Merge branch 'upstream' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireless-2.6 into upstream
diff --git a/Documentation/HOWTO b/Documentation/HOWTO
index 8d51c14..48123db 100644
--- a/Documentation/HOWTO
+++ b/Documentation/HOWTO
@@ -30,6 +30,7 @@
 experience, the following books are good for, if anything, reference:
  - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall]
  - "Practical C Programming" by Steve Oualline [O'Reilly]
+ - "C:  A Reference Manual" by Harbison and Steele [Prentice Hall]
 
 The kernel is written using GNU C and the GNU toolchain.  While it
 adheres to the ISO C89 standard, it uses a number of extensions that are
diff --git a/Documentation/crypto/api-intro.txt b/Documentation/crypto/api-intro.txt
index 5a03a28..e41a79a 100644
--- a/Documentation/crypto/api-intro.txt
+++ b/Documentation/crypto/api-intro.txt
@@ -193,6 +193,7 @@
   Kartikey Mahendra Bhatt (CAST6)
   Jon Oberheide (ARC4)
   Jouni Malinen (Michael MIC)
+  NTT(Nippon Telegraph and Telephone Corporation) (Camellia)
 
 SHA1 algorithm contributors:
   Jean-Francois Dive
@@ -246,6 +247,9 @@
 VIA PadLock contributors:
   Michal Ludvig
 
+Camellia algorithm contributors:
+  NTT(Nippon Telegraph and Telephone Corporation) (Camellia)
+
 Generic scatterwalk code by Adam J. Richter <adam@yggdrasil.com>
 
 Please send any credits updates or corrections to:
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 0ba6af0..fa844fd 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -50,22 +50,6 @@
 
 ---------------------------
 
-What:	ieee1394 core's unused exports (CONFIG_IEEE1394_EXPORT_FULL_API)
-When:	January 2007
-Why:	There are no projects known to use these exported symbols, except
-	dfg1394 (uses one symbol whose functionality is core-internal now).
-Who:	Stefan Richter <stefanr@s5r6.in-berlin.de>
-
----------------------------
-
-What:	ieee1394's *_oui sysfs attributes (CONFIG_IEEE1394_OUI_DB)
-When:	January 2007
-Files:	drivers/ieee1394/: oui.db, oui2c.sh
-Why:	big size, little value
-Who:	Stefan Richter <stefanr@s5r6.in-berlin.de>
-
----------------------------
-
 What:	Video4Linux API 1 ioctls and video_decoder.h from Video devices.
 When:	December 2006
 Why:	V4L1 AP1 was replaced by V4L2 API. during migration from 2.4 to 2.6
@@ -186,18 +170,6 @@
 
 ---------------------------
 
-What:	find_trylock_page
-When:	January 2007
-Why:	The interface no longer has any callers left in the kernel. It
-	is an odd interface (compared with other find_*_page functions), in
-	that it does not take a refcount to the page, only the page lock.
-	It should be replaced with find_get_page or find_lock_page if possible.
-	This feature removal can be reevaluated if users of the interface
-	cannot cleanly use something else.
-Who:	Nick Piggin <npiggin@suse.de>
-
----------------------------
-
 What:	Interrupt only SA_* flags
 When:	Januar 2007
 Why:	The interrupt related SA_* flags are replaced by IRQF_* to move them
@@ -274,6 +246,7 @@
 
 ---------------------------
 
+<<<<<<< test:Documentation/feature-removal-schedule.txt
 What:	ACPI hotkey driver (CONFIG_ACPI_HOTKEY)
 When:	2.6.21
 Why:	hotkey.c was an attempt to consolidate multiple drivers that use
@@ -306,11 +279,18 @@
 	the BIOS can be extracted and disassembled with acpidump
 	and iasl as documented in the pmtools package here:
 	http://ftp.kernel.org/pub/linux/kernel/people/lenb/acpi/utils
-
 Who:	Len Brown <len.brown@intel.com>
 
 ---------------------------
 
+What:	ACPI procfs interface
+When:	July 2007
+Why:	After ACPI sysfs conversion, ACPI attributes will be duplicated
+	in sysfs and the ACPI procfs interface should be removed.
+Who:	Zhang Rui <rui.zhang@intel.com>
+
+---------------------------
+
 What:	/proc/acpi/button
 When:	August 2007
 Why:	/proc/acpi/button has been replaced by events to the input layer
@@ -325,3 +305,10 @@
 Who:	Jeff Garzik <jeff@garzik.org>
 
 ---------------------------
+
+What:   sk98lin network driver
+When:   July 2007
+Why:    In kernel tree version of driver is unmaintained. Sk98lin driver
+	replaced by the skge driver. 
+Who:    Stephen Hemminger <shemminger@osdl.org>
+
diff --git a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt
index 3f9ddbc..09939696 100644
--- a/Documentation/s390/Debugging390.txt
+++ b/Documentation/s390/Debugging390.txt
@@ -480,7 +480,7 @@
 r3       argument 1 / return value 1 (if long long) call-clobbered
 r4       argument 2                                 call-clobbered
 r5       argument 3                                 call-clobbered
-r6	 argument 5                                 saved
+r6	 argument 4				    saved
 r7       pointer-to arguments 5 to ...              saved      
 r8       this & that                                saved
 r9       this & that                                saved
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 9fef210..c30ff1b 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -242,6 +242,12 @@
     ac97_clock		- AC'97 clock (default = 48000)
     ac97_quirk		- AC'97 workaround for strange hardware
 			  See "AC97 Quirk Option" section below.
+    ac97_codec		- Workaround to specify which AC'97 codec 
+			  instead of probing.  If this works for you
+			  file a bug with your `lspci -vn` output.
+			  -2  -- Force probing.
+			  -1  -- Default behavior.
+			  0-2 -- Use the specified codec.
     spdif_aclink	- S/PDIF transfer over AC-link (default = 1)
 
     This module supports one card and autoprobe.
@@ -779,6 +785,7 @@
 	  asus-dig	ASUS with SPDIF out
 	  asus-dig2	ASUS with SPDIF out (using GPIO2)
 	  uniwill	3-jack
+	  fujitsu	Fujitsu Laptops (Pi1536)
 	  F1734		2-jack
 	  lg		LG laptop (m1 express dual)
 	  lg-lw		LG LW20/LW25 laptop
@@ -800,14 +807,18 @@
 	ALC262
 	  fujitsu	Fujitsu Laptop
 	  hp-bpc	HP xw4400/6400/8400/9400 laptops
+	  hp-bpc-d7000	HP BPC D7000
 	  benq		Benq ED8
+	  hippo		Hippo (ATI) with jack detection, Sony UX-90s
+	  hippo_1	Hippo (Benq) with jack detection
 	  basic		fixed pin assignment w/o SPDIF
 	  auto		auto-config reading BIOS (default)
 
 	ALC882/885
 	  3stack-dig	3-jack with SPDIF I/O
-	  6stck-dig	6-jack digital with SPDIF I/O
+	  6stack-dig	6-jack digital with SPDIF I/O
 	  arima		Arima W820Di1
+	  macpro	MacPro support
 	  auto		auto-config reading BIOS (default)
 
 	ALC883/888
@@ -817,6 +828,10 @@
 	  3stack-6ch-dig 3-jack 6-channel with SPDIF I/O
 	  6stack-dig-demo  6-jack digital for Intel demo board
 	  acer		Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
+	  medion	Medion Laptops
+	  targa-dig	Targa/MSI
+	  targa-2ch-dig	Targs/MSI with 2-channel
+	  laptop-eapd   3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE)
 	  auto		auto-config reading BIOS (default)
 
 	ALC861/660
@@ -825,6 +840,16 @@
 	  6stack-dig	6-jack with SPDIF I/O
 	  3stack-660	3-jack (for ALC660)
 	  uniwill-m31	Uniwill M31 laptop
+	  toshiba	Toshiba laptop support
+	  asus		Asus laptop support
+	  asus-laptop	ASUS F2/F3 laptops
+	  auto		auto-config reading BIOS (default)
+
+	ALC861VD/660VD
+	  3stack	3-jack
+	  3stack-dig	3-jack with SPDIF OUT
+	  6stack-dig	6-jack with SPDIF OUT
+	  3stack-660	3-jack (for ALC660VD)
 	  auto		auto-config reading BIOS (default)
 
 	CMI9880
@@ -845,6 +870,7 @@
 	  3stack	3-stack, shared surrounds
 	  laptop	2-channel only (FSC V2060, Samsung M50)
 	  laptop-eapd	2-channel with EAPD (Samsung R65, ASUS A6J)
+	  ultra		2-channel with EAPD (Samsung Ultra tablet PC)
 
 	AD1988
 	  6stack	6-jack
@@ -854,12 +880,31 @@
 	  laptop	3-jack with hp-jack automute
 	  laptop-dig	ditto with SPDIF
 	  auto		auto-config reading BIOS (default)
+	
+	Conexant 5045
+	  laptop	Laptop config 
+	  test		for testing/debugging purpose, almost all controls
+			can be adjusted.  Appearing only when compiled with
+			$CONFIG_SND_DEBUG=y
+
+	Conexant 5047
+	  laptop	Basic Laptop config 
+	  laptop-hp	Laptop config for some HP models (subdevice 30A5)
+	  laptop-eapd	Laptop config with EAPD support
+	  test		for testing/debugging purpose, almost all controls
+			can be adjusted.  Appearing only when compiled with
+			$CONFIG_SND_DEBUG=y
 
 	STAC9200/9205/9220/9221/9254
 	  ref		Reference board
 	  3stack	D945 3stack
 	  5stack	D945 5stack + SPDIF
 
+	STAC9202/9250/9251
+	  ref		Reference board, base config
+	  m2-2		Some Gateway MX series laptops
+	  m6		Some Gateway NX series laptops
+
 	STAC9227/9228/9229/927x
 	  ref		Reference board
 	  3stack	D965 3stack
@@ -974,6 +1019,7 @@
     Module for Envy24HT (VT/ICE1724), Envy24PT (VT1720) based PCI sound cards.
 			* MidiMan M Audio Revolution 5.1
 			* MidiMan M Audio Revolution 7.1
+			* MidiMan M Audio Audiophile 192
 			* AMP Ltd AUDIO2000
 			* TerraTec Aureon 5.1 Sky
 			* TerraTec Aureon 7.1 Space
@@ -993,7 +1039,7 @@
 
     model       - Use the given board model, one of the following:
 		  revo51, revo71, amp2000, prodigy71, prodigy71lt,
-		  prodigy192, aureon51, aureon71, universe,
+		  prodigy192, aureon51, aureon71, universe, ap192,
 		  k8x800, phase22, phase28, ms300, av710
 
     This module supports multiple cards and autoprobe.
@@ -1049,6 +1095,9 @@
     buggy_semaphore - Enable workaround for hardwares with buggy
 		    semaphores (e.g. on some ASUS laptops)
 		    (default off)
+    spdif_aclink  - Use S/PDIF over AC-link instead of direct connection
+		    from the controller chip
+		    (0 = off, 1 = on, -1 = default)
 
     This module supports one chip and autoprobe.
 
@@ -1371,6 +1420,13 @@
 
     This module supports multiple cards.
 
+  Module snd-portman2x4
+  ---------------------
+
+    Module for Midiman Portman 2x4 parallel port MIDI interface
+
+    This module supports multiple cards.
+
   Module snd-powermac (on ppc only)
   ---------------------------------
 
diff --git a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl
index 1f3ae3e..c4d2e35 100644
--- a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl
+++ b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl
@@ -36,7 +36,7 @@
   </bookinfo>
 
   <chapter><title>Management of Cards and Devices</title>
-     <sect1><title>Card Managment</title>
+     <sect1><title>Card Management</title>
 !Esound/core/init.c
      </sect1>
      <sect1><title>Device Components</title>
@@ -59,7 +59,7 @@
      <sect1><title>PCM Format Helpers</title>
 !Esound/core/pcm_misc.c
      </sect1>
-     <sect1><title>PCM Memory Managment</title>
+     <sect1><title>PCM Memory Management</title>
 !Esound/core/pcm_memory.c
      </sect1>
   </chapter>
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
index ccd0a95..74d3a35 100644
--- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
@@ -1360,8 +1360,7 @@
         <informalexample>
           <programlisting>
 <![CDATA[
-  static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id,
-                                          struct pt_regs *regs)
+  static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id)
   {
           struct mychip *chip = dev_id;
           ....
@@ -2127,7 +2126,7 @@
 	accessible via <constant>substream-&gt;runtime</constant>.
 	This runtime pointer holds the various information; it holds
 	the copy of hw_params and sw_params configurations, the buffer
-	pointers, mmap records, spinlocks, etc.  Almost everyhing you
+	pointers, mmap records, spinlocks, etc.  Almost everything you
 	need for controlling the PCM can be found there.
 	</para>
 
@@ -2340,7 +2339,7 @@
 
 	<para>
 	  When the PCM substreams can be synchronized (typically,
-	synchorinized start/stop of a playback and a capture streams),
+	synchronized start/stop of a playback and a capture streams),
 	you can give <constant>SNDRV_PCM_INFO_SYNC_START</constant>,
 	too.  In this case, you'll need to check the linked-list of
 	PCM substreams in the trigger callback.  This will be
@@ -3062,8 +3061,7 @@
 	    <title>Interrupt Handler Case #1</title>
             <programlisting>
 <![CDATA[
-  static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id,
-                                          struct pt_regs *regs)
+  static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id)
   {
           struct mychip *chip = dev_id;
           spin_lock(&chip->lock);
@@ -3106,8 +3104,7 @@
 	    <title>Interrupt Handler Case #2</title>
             <programlisting>
 <![CDATA[
-  static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id,
-                                          struct pt_regs *regs)
+  static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id)
   {
           struct mychip *chip = dev_id;
           spin_lock(&chip->lock);
@@ -3247,7 +3244,7 @@
         You can even define your own constraint rules.
         For example, let's suppose my_chip can manage a substream of 1 channel
         if and only if the format is S16_LE, otherwise it supports any format
-        specified in the <structname>snd_pcm_hardware</structname> stucture (or in any
+        specified in the <structname>snd_pcm_hardware</structname> structure (or in any
         other constraint_list). You can build a rule like this:
 
         <example>
@@ -3691,16 +3688,6 @@
         </para>
 
         <para>
-          Here, the chip instance is retrieved via
-        <function>snd_kcontrol_chip()</function> macro.  This macro
-        just accesses to kcontrol-&gt;private_data. The
-        kcontrol-&gt;private_data field is 
-        given as the argument of <function>snd_ctl_new()</function>
-        (see the later subsection
-        <link linkend="control-interface-constructor"><citetitle>Constructor</citetitle></link>).
-        </para>
-
-        <para>
 	The <structfield>value</structfield> field is depending on
         the type of control as well as on info callback.  For example,
 	the sb driver uses this field to store the register offset,
@@ -3780,7 +3767,7 @@
         <para>
 	Like <structfield>get</structfield> callback,
 	when the control has more than one elements,
-	all elemehts must be evaluated in this callback, too.
+	all elements must be evaluated in this callback, too.
         </para>
       </section>
 
@@ -5541,12 +5528,12 @@
   #ifdef CONFIG_PM
   static int snd_my_suspend(struct pci_dev *pci, pm_message_t state)
   {
-          .... /* do things for suspsend */
+          .... /* do things for suspend */
           return 0;
   }
   static int snd_my_resume(struct pci_dev *pci)
   {
-          .... /* do things for suspsend */
+          .... /* do things for suspend */
           return 0;
   }
   #endif
@@ -6111,7 +6098,7 @@
 <!-- ****************************************************** -->
 <!-- Acknowledgments  -->
 <!-- ****************************************************** -->
-  <chapter id="acknowledments">
+  <chapter id="acknowledgments">
     <title>Acknowledgments</title>
     <para>
       I would like to thank Phil Kerr for his help for improvement and
diff --git a/Documentation/sound/alsa/hda_codec.txt b/Documentation/sound/alsa/hda_codec.txt
index 0be57ed..4eaae2a 100644
--- a/Documentation/sound/alsa/hda_codec.txt
+++ b/Documentation/sound/alsa/hda_codec.txt
@@ -277,11 +277,11 @@
 snd_hda_get_codec_name() stores the codec name on the given string.
 
 snd_hda_check_board_config() can be used to obtain the configuration
-information matching with the device.  Define the table with struct
-hda_board_config entries (zero-terminated), and pass it to the
-function.  The function checks the modelname given as a module
-parameter, and PCI subsystem IDs.  If the matching entry is found, it
-returns the config field value.
+information matching with the device.  Define the model string table
+and the table with struct snd_pci_quirk entries (zero-terminated),
+and pass it to the function.  The function checks the modelname given
+as a module parameter, and PCI subsystem IDs.  If the matching entry
+is found, it returns the config field value.
 
 snd_hda_add_new_ctls() can be used to create and add control entries.
 Pass the zero-terminated array of struct snd_kcontrol_new.  The same array
diff --git a/Documentation/sound/alsa/soc/DAI.txt b/Documentation/sound/alsa/soc/DAI.txt
new file mode 100644
index 0000000..58cbfd0
--- /dev/null
+++ b/Documentation/sound/alsa/soc/DAI.txt
@@ -0,0 +1,56 @@
+ASoC currently supports the three main Digital Audio Interfaces (DAI) found on
+SoC controllers and portable audio CODECS today, namely AC97, I2S and PCM.
+
+
+AC97
+====
+
+  AC97 is a five wire interface commonly found on many PC sound cards. It is
+now also popular in many portable devices. This DAI has a reset line and time
+multiplexes its data on its SDATA_OUT (playback) and SDATA_IN (capture) lines.
+The bit clock (BCLK) is always driven by the CODEC (usually 12.288MHz) and the
+frame (FRAME) (usually 48kHz) is always driven by the controller. Each AC97
+frame is 21uS long and is divided into 13 time slots.
+
+The AC97 specification can be found at :-
+http://www.intel.com/design/chipsets/audio/ac97_r23.pdf
+
+
+I2S
+===
+
+ I2S is a common 4 wire DAI used in HiFi, STB and portable devices. The Tx and
+Rx lines are used for audio transmision, whilst the bit clock (BCLK) and
+left/right clock (LRC) synchronise the link. I2S is flexible in that either the
+controller or CODEC can drive (master) the BCLK and LRC clock lines. Bit clock
+usually varies depending on the sample rate and the master system clock
+(SYSCLK). LRCLK is the same as the sample rate. A few devices support separate
+ADC and DAC LRCLK's, this allows for similtanious capture and playback at
+different sample rates.
+
+I2S has several different operating modes:-
+
+ o I2S - MSB is transmitted on the falling edge of the first BCLK after LRC
+         transition.
+
+ o Left Justified - MSB is transmitted on transition of LRC.
+
+ o Right Justified - MSB is transmitted sample size BCLK's before LRC
+                     transition.
+
+PCM
+===
+
+PCM is another 4 wire interface, very similar to I2S, that can support a more
+flexible protocol. It has bit clock (BCLK) and sync (SYNC) lines that are used
+to synchronise the link whilst the Tx and Rx lines are used to transmit and
+receive the audio data. Bit clock usually varies depending on sample rate
+whilst sync runs at the sample rate. PCM also supports Time Division
+Multiplexing (TDM) in that several devices can use the bus similtaniuosly (This
+is sometimes referred to as network mode).
+
+Common PCM operating modes:-
+
+ o Mode A - MSB is transmitted on falling edge of first BCLK after FRAME/SYNC.
+
+ o Mode B - MSB is transmitted on rising edge of FRAME/SYNC.
diff --git a/Documentation/sound/alsa/soc/clocking.txt b/Documentation/sound/alsa/soc/clocking.txt
new file mode 100644
index 0000000..e93960d
--- /dev/null
+++ b/Documentation/sound/alsa/soc/clocking.txt
@@ -0,0 +1,51 @@
+Audio Clocking
+==============
+
+This text describes the audio clocking terms in ASoC and digital audio in
+general. Note: Audio clocking can be complex !
+
+
+Master Clock
+------------
+
+Every audio subsystem is driven by a master clock (sometimes refered to as MCLK
+or SYSCLK). This audio master clock can be derived from a number of sources
+(e.g. crystal, PLL, CPU clock) and is responsible for producing the correct
+audio playback and capture sample rates.
+
+Some master clocks (e.g. PLL's and CPU based clocks) are configuarble in that
+their speed can be altered by software (depending on the system use and to save
+power). Other master clocks are fixed at at set frequency (i.e. crystals).
+
+
+DAI Clocks
+----------
+The Digital Audio Interface is usually driven by a Bit Clock (often referred to
+as BCLK). This clock is used to drive the digital audio data across the link
+between the codec and CPU.
+
+The DAI also has a frame clock to signal the start of each audio frame. This
+clock is sometimes referred to as LRC (left right clock) or FRAME. This clock
+runs at exactly the sample rate (LRC = Rate).
+
+Bit Clock can be generated as follows:-
+
+BCLK = MCLK / x
+
+ or
+
+BCLK = LRC * x
+
+ or
+
+BCLK = LRC * Channels * Word Size
+
+This relationship depends on the codec or SoC CPU in particular. In general
+it's best to configure BCLK to the lowest possible speed (depending on your
+rate, number of channels and wordsize) to save on power.
+
+It's also desireable to use the codec (if possible) to drive (or master) the
+audio clocks as it's usually gives more accurate sample rates than the CPU.
+
+
+
diff --git a/Documentation/sound/alsa/soc/codec.txt b/Documentation/sound/alsa/soc/codec.txt
new file mode 100644
index 0000000..48983c7
--- /dev/null
+++ b/Documentation/sound/alsa/soc/codec.txt
@@ -0,0 +1,197 @@
+ASoC Codec Driver
+=================
+
+The codec driver is generic and hardware independent code that configures the
+codec to provide audio capture and playback. It should contain no code that is
+specific to the target platform or machine. All platform and machine specific
+code should be added to the platform and machine drivers respectively.
+
+Each codec driver *must* provide the following features:-
+
+ 1) Codec DAI and PCM configuration
+ 2) Codec control IO - using I2C, 3 Wire(SPI) or both API's
+ 3) Mixers and audio controls
+ 4) Codec audio operations
+
+Optionally, codec drivers can also provide:-
+
+ 5) DAPM description.
+ 6) DAPM event handler.
+ 7) DAC Digital mute control.
+
+It's probably best to use this guide in conjuction with the existing codec
+driver code in sound/soc/codecs/
+
+ASoC Codec driver breakdown
+===========================
+
+1 - Codec DAI and PCM configuration
+-----------------------------------
+Each codec driver must have a struct snd_soc_codec_dai to define it's DAI and
+PCM's capablities and operations. This struct is exported so that it can be
+registered with the core by your machine driver.
+
+e.g.
+
+struct snd_soc_codec_dai wm8731_dai = {
+	.name = "WM8731",
+	/* playback capabilities */
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8731_RATES,
+		.formats = WM8731_FORMATS,},
+	/* capture capabilities */
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8731_RATES,
+		.formats = WM8731_FORMATS,},
+	/* pcm operations - see section 4 below */
+	.ops = {
+		.prepare = wm8731_pcm_prepare,
+		.hw_params = wm8731_hw_params,
+		.shutdown = wm8731_shutdown,
+	},
+	/* DAI operations - see DAI.txt */
+	.dai_ops = {
+		.digital_mute = wm8731_mute,
+		.set_sysclk = wm8731_set_dai_sysclk,
+		.set_fmt = wm8731_set_dai_fmt,
+	}
+};
+EXPORT_SYMBOL_GPL(wm8731_dai);
+
+
+2 - Codec control IO
+--------------------
+The codec can ususally be controlled via an I2C or SPI style interface (AC97
+combines control with data in the DAI). The codec drivers will have to provide
+functions to read and write the codec registers along with supplying a register
+cache:-
+
+	/* IO control data and register cache */
+    void *control_data; /* codec control (i2c/3wire) data */
+    void *reg_cache;
+
+Codec read/write should do any data formatting and call the hardware read write
+below to perform the IO. These functions are called by the core and alsa when
+performing DAPM or changing the mixer:-
+
+    unsigned int (*read)(struct snd_soc_codec *, unsigned int);
+    int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
+
+Codec hardware IO functions - usually points to either the I2C, SPI or AC97
+read/write:-
+
+	hw_write_t hw_write;
+	hw_read_t hw_read;
+
+
+3 - Mixers and audio controls
+-----------------------------
+All the codec mixers and audio controls can be defined using the convenience
+macros defined in soc.h.
+
+    #define SOC_SINGLE(xname, reg, shift, mask, invert)
+
+Defines a single control as follows:-
+
+  xname = Control name e.g. "Playback Volume"
+  reg = codec register
+  shift = control bit(s) offset in register
+  mask = control bit size(s) e.g. mask of 7 = 3 bits
+  invert = the control is inverted
+
+Other macros include:-
+
+    #define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert)
+
+A stereo control
+
+    #define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert)
+
+A stereo control spanning 2 registers
+
+    #define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts)
+
+Defines an single enumerated control as follows:-
+
+   xreg = register
+   xshift = control bit(s) offset in register
+   xmask = control bit(s) size
+   xtexts = pointer to array of strings that describe each setting
+
+   #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts)
+
+Defines a stereo enumerated control
+
+
+4 - Codec Audio Operations
+--------------------------
+The codec driver also supports the following alsa operations:-
+
+/* SoC audio ops */
+struct snd_soc_ops {
+	int (*startup)(struct snd_pcm_substream *);
+	void (*shutdown)(struct snd_pcm_substream *);
+	int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
+	int (*hw_free)(struct snd_pcm_substream *);
+	int (*prepare)(struct snd_pcm_substream *);
+};
+
+Please refer to the alsa driver PCM documentation for details.
+http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm
+
+
+5 - DAPM description.
+---------------------
+The Dynamic Audio Power Management description describes the codec's power
+components, their relationships and registers to the ASoC core. Please read
+dapm.txt for details of building the description.
+
+Please also see the examples in other codec drivers.
+
+
+6 - DAPM event handler
+----------------------
+This function is a callback that handles codec domain PM calls and system
+domain PM calls (e.g. suspend and resume). It's used to put the codec to sleep
+when not in use.
+
+Power states:-
+
+	SNDRV_CTL_POWER_D0: /* full On */
+	/* vref/mid, clk and osc on, active */
+
+	SNDRV_CTL_POWER_D1: /* partial On */
+	SNDRV_CTL_POWER_D2: /* partial On */
+
+	SNDRV_CTL_POWER_D3hot: /* Off, with power */
+	/* everything off except vref/vmid, inactive */
+
+	SNDRV_CTL_POWER_D3cold: /* Everything Off, without power */
+
+
+7 - Codec DAC digital mute control.
+------------------------------------
+Most codecs have a digital mute before the DAC's that can be used to minimise
+any system noise.  The mute stops any digital data from entering the DAC.
+
+A callback can be created that is called by the core for each codec DAI when the
+mute is applied or freed.
+
+i.e.
+
+static int wm8974_mute(struct snd_soc_codec *codec,
+	struct snd_soc_codec_dai *dai, int mute)
+{
+	u16 mute_reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0xffbf;
+	if(mute)
+		wm8974_write(codec, WM8974_DAC, mute_reg | 0x40);
+	else
+		wm8974_write(codec, WM8974_DAC, mute_reg);
+	return 0;
+}
diff --git a/Documentation/sound/alsa/soc/dapm.txt b/Documentation/sound/alsa/soc/dapm.txt
new file mode 100644
index 0000000..c11877f
--- /dev/null
+++ b/Documentation/sound/alsa/soc/dapm.txt
@@ -0,0 +1,297 @@
+Dynamic Audio Power Management for Portable Devices
+===================================================
+
+1. Description
+==============
+
+Dynamic Audio Power Management (DAPM) is designed to allow portable Linux devices
+to use the minimum amount of power within the audio subsystem at all times. It
+is independent of other kernel PM and as such, can easily co-exist with the
+other PM systems.
+
+DAPM is also completely transparent to all user space applications as all power
+switching is done within the ASoC core. No code changes or recompiling are
+required for user space applications. DAPM makes power switching descisions based
+upon any audio stream (capture/playback) activity and audio mixer settings
+within the device.
+
+DAPM spans the whole machine. It covers power control within the entire audio
+subsystem, this includes internal codec power blocks and machine level power
+systems.
+
+There are 4 power domains within DAPM
+
+   1. Codec domain - VREF, VMID (core codec and audio power)
+      Usually controlled at codec probe/remove and suspend/resume, although
+      can be set at stream time if power is not needed for sidetone, etc.
+
+   2. Platform/Machine domain - physically connected inputs and outputs
+      Is platform/machine and user action specific, is configured by the
+      machine driver and responds to asynchronous events e.g when HP
+      are inserted
+
+   3. Path domain - audio susbsystem signal paths
+      Automatically set when mixer and mux settings are changed by the user.
+      e.g. alsamixer, amixer.
+
+   4. Stream domain - DAC's and ADC's.
+      Enabled and disabled when stream playback/capture is started and
+      stopped respectively. e.g. aplay, arecord.
+
+All DAPM power switching descisons are made automatically by consulting an audio
+routing map of the whole machine. This map is specific to each machine and
+consists of the interconnections between every audio component (including
+internal codec components). All audio components that effect power are called
+widgets hereafter.
+
+
+2. DAPM Widgets
+===============
+
+Audio DAPM widgets fall into a number of types:-
+
+ o Mixer      - Mixes several analog signals into a single analog signal.
+ o Mux        - An analog switch that outputs only 1 of it's inputs.
+ o PGA        - A programmable gain amplifier or attenuation widget.
+ o ADC        - Analog to Digital Converter
+ o DAC        - Digital to Analog Converter
+ o Switch     - An analog switch
+ o Input      - A codec input pin
+ o Output     - A codec output pin
+ o Headphone  - Headphone (and optional Jack)
+ o Mic        - Mic (and optional Jack)
+ o Line       - Line Input/Output (and optional Jack)
+ o Speaker    - Speaker
+ o Pre        - Special PRE widget (exec before all others)
+ o Post       - Special POST widget (exec after all others)
+
+(Widgets are defined in include/sound/soc-dapm.h)
+
+Widgets are usually added in the codec driver and the machine driver. There are
+convience macros defined in soc-dapm.h that can be used to quickly build a
+list of widgets of the codecs and machines DAPM widgets.
+
+Most widgets have a name, register, shift and invert. Some widgets have extra
+parameters for stream name and kcontrols.
+
+
+2.1 Stream Domain Widgets
+-------------------------
+
+Stream Widgets relate to the stream power domain and only consist of ADC's
+(analog to digital converters) and DAC's (digital to analog converters).
+
+Stream widgets have the following format:-
+
+SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert),
+
+NOTE: the stream name must match the corresponding stream name in your codecs
+snd_soc_codec_dai.
+
+e.g. stream widgets for HiFi playback and capture
+
+SND_SOC_DAPM_DAC("HiFi DAC", "HiFi Playback", REG, 3, 1),
+SND_SOC_DAPM_ADC("HiFi ADC", "HiFi Capture", REG, 2, 1),
+
+
+2.2 Path Domain Widgets
+-----------------------
+
+Path domain widgets have a ability to control or effect the audio signal or
+audio paths within the audio subsystem. They have the following form:-
+
+SND_SOC_DAPM_PGA(name, reg, shift, invert, controls, num_controls)
+
+Any widget kcontrols can be set using the controls and num_controls members.
+
+e.g. Mixer widget (the kcontrols are declared first)
+
+/* Output Mixer */
+static const snd_kcontrol_new_t wm8731_output_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0),
+SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0),
+SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0),
+};
+
+SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, wm8731_output_mixer_controls,
+	ARRAY_SIZE(wm8731_output_mixer_controls)),
+
+
+2.3 Platform/Machine domain Widgets
+-----------------------------------
+
+Machine widgets are different from codec widgets in that they don't have a
+codec register bit associated with them. A machine widget is assigned to each
+machine audio component (non codec) that can be independently powered. e.g.
+
+ o Speaker Amp
+ o Microphone Bias
+ o Jack connectors
+
+A machine widget can have an optional call back.
+
+e.g. Jack connector widget for an external Mic that enables Mic Bias
+when the Mic is inserted:-
+
+static int spitz_mic_bias(struct snd_soc_dapm_widget* w, int event)
+{
+	if(SND_SOC_DAPM_EVENT_ON(event))
+		set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS);
+	else
+		reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS);
+
+	return 0;
+}
+
+SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias),
+
+
+2.4 Codec Domain
+----------------
+
+The Codec power domain has no widgets and is handled by the codecs DAPM event
+handler. This handler is called when the codec powerstate is changed wrt to any
+stream event or by kernel PM events.
+
+
+2.5 Virtual Widgets
+-------------------
+
+Sometimes widgets exist in the codec or machine audio map that don't have any
+corresponding register bit for power control. In this case it's necessary to
+create a virtual widget - a widget with no control bits e.g.
+
+SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0),
+
+This can be used to merge to signal paths together in software.
+
+After all the widgets have been defined, they can then be added to the DAPM
+subsystem individually with a call to snd_soc_dapm_new_control().
+
+
+3. Codec Widget Interconnections
+================================
+
+Widgets are connected to each other within the codec and machine by audio
+paths (called interconnections). Each interconnection must be defined in order
+to create a map of all audio paths between widgets.
+This is easiest with a diagram of the codec (and schematic of the machine audio
+system), as it requires joining widgets together via their audio signal paths.
+
+i.e. from the WM8731 codec's output mixer (wm8731.c)
+
+The WM8731 output mixer has 3 inputs (sources)
+
+ 1. Line Bypass Input
+ 2. DAC (HiFi playback)
+ 3. Mic Sidetone Input
+
+Each input in this example has a kcontrol associated with it (defined in example
+above) and is connected to the output mixer via it's kcontrol name. We can now
+connect the destination widget (wrt audio signal) with it's source widgets.
+
+	/* output mixer */
+	{"Output Mixer", "Line Bypass Switch", "Line Input"},
+	{"Output Mixer", "HiFi Playback Switch", "DAC"},
+	{"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
+
+So we have :-
+
+	Destination Widget  <=== Path Name <=== Source Widget
+
+Or:-
+
+	Sink, Path, Source
+
+Or :-
+
+	"Output Mixer" is connected to the "DAC" via the "HiFi Playback Switch".
+
+When there is no path name connecting widgets (e.g. a direct connection) we
+pass NULL for the path name.
+
+Interconnections are created with a call to:-
+
+snd_soc_dapm_connect_input(codec, sink, path, source);
+
+Finally, snd_soc_dapm_new_widgets(codec) must be called after all widgets and
+interconnections have been registered with the core. This causes the core to
+scan the codec and machine so that the internal DAPM state matches the
+physical state of the machine.
+
+
+3.1 Machine Widget Interconnections
+-----------------------------------
+Machine widget interconnections are created in the same way as codec ones and
+directly connect the codec pins to machine level widgets.
+
+e.g. connects the speaker out codec pins to the internal speaker.
+
+	/* ext speaker connected to codec pins LOUT2, ROUT2  */
+	{"Ext Spk", NULL , "ROUT2"},
+	{"Ext Spk", NULL , "LOUT2"},
+
+This allows the DAPM to power on and off pins that are connected (and in use)
+and pins that are NC respectively.
+
+
+4 Endpoint Widgets
+===================
+An endpoint is a start or end point (widget) of an audio signal within the
+machine and includes the codec. e.g.
+
+ o Headphone Jack
+ o Internal Speaker
+ o Internal Mic
+ o Mic Jack
+ o Codec Pins
+
+When a codec pin is NC it can be marked as not used with a call to
+
+snd_soc_dapm_set_endpoint(codec, "Widget Name", 0);
+
+The last argument is 0 for inactive and 1 for active. This way the pin and its
+input widget will never be powered up and consume power.
+
+This also applies to machine widgets. e.g. if a headphone is connected to a
+jack then the jack can be marked active. If the headphone is removed, then
+the headphone jack can be marked inactive.
+
+
+5 DAPM Widget Events
+====================
+
+Some widgets can register their interest with the DAPM core in PM events.
+e.g. A Speaker with an amplifier registers a widget so the amplifier can be
+powered only when the spk is in use.
+
+/* turn speaker amplifier on/off depending on use */
+static int corgi_amp_event(struct snd_soc_dapm_widget *w, int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
+	else
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
+
+	return 0;
+}
+
+/* corgi machine dapm widgets */
+static const struct snd_soc_dapm_widget wm8731_dapm_widgets =
+	SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event);
+
+Please see soc-dapm.h for all other widgets that support events.
+
+
+5.1 Event types
+---------------
+
+The following event types are supported by event widgets.
+
+/* dapm event types */
+#define SND_SOC_DAPM_PRE_PMU	0x1 	/* before widget power up */
+#define SND_SOC_DAPM_POST_PMU	0x2		/* after widget power up */
+#define SND_SOC_DAPM_PRE_PMD	0x4 	/* before widget power down */
+#define SND_SOC_DAPM_POST_PMD	0x8		/* after widget power down */
+#define SND_SOC_DAPM_PRE_REG	0x10	/* before audio path setup */
+#define SND_SOC_DAPM_POST_REG	0x20	/* after audio path setup */
diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt
new file mode 100644
index 0000000..72bd222
--- /dev/null
+++ b/Documentation/sound/alsa/soc/machine.txt
@@ -0,0 +1,113 @@
+ASoC Machine Driver
+===================
+
+The ASoC machine (or board) driver is the code that glues together the platform
+and codec drivers.
+
+The machine driver can contain codec and platform specific code. It registers
+the audio subsystem with the kernel as a platform device and is represented by
+the following struct:-
+
+/* SoC machine */
+struct snd_soc_machine {
+	char *name;
+
+	int (*probe)(struct platform_device *pdev);
+	int (*remove)(struct platform_device *pdev);
+
+	/* the pre and post PM functions are used to do any PM work before and
+	 * after the codec and DAI's do any PM work. */
+	int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);
+	int (*suspend_post)(struct platform_device *pdev, pm_message_t state);
+	int (*resume_pre)(struct platform_device *pdev);
+	int (*resume_post)(struct platform_device *pdev);
+
+	/* machine stream operations */
+	struct snd_soc_ops *ops;
+
+	/* CPU <--> Codec DAI links  */
+	struct snd_soc_dai_link *dai_link;
+	int num_links;
+};
+
+probe()/remove()
+----------------
+probe/remove are optional. Do any machine specific probe here.
+
+
+suspend()/resume()
+------------------
+The machine driver has pre and post versions of suspend and resume to take care
+of any machine audio tasks that have to be done before or after the codec, DAI's
+and DMA is suspended and resumed. Optional.
+
+
+Machine operations
+------------------
+The machine specific audio operations can be set here. Again this is optional.
+
+
+Machine DAI Configuration
+-------------------------
+The machine DAI configuration glues all the codec and CPU DAI's together. It can
+also be used to set up the DAI system clock and for any machine related DAI
+initialisation e.g. the machine audio map can be connected to the codec audio
+map, unconnnected codec pins can be set as such. Please see corgi.c, spitz.c
+for examples.
+
+struct snd_soc_dai_link is used to set up each DAI in your machine. e.g.
+
+/* corgi digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link corgi_dai = {
+	.name = "WM8731",
+	.stream_name = "WM8731",
+	.cpu_dai = &pxa_i2s_dai,
+	.codec_dai = &wm8731_dai,
+	.init = corgi_wm8731_init,
+	.ops = &corgi_ops,
+};
+
+struct snd_soc_machine then sets up the machine with it's DAI's. e.g.
+
+/* corgi audio machine driver */
+static struct snd_soc_machine snd_soc_machine_corgi = {
+	.name = "Corgi",
+	.dai_link = &corgi_dai,
+	.num_links = 1,
+};
+
+
+Machine Audio Subsystem
+-----------------------
+
+The machine soc device glues the platform, machine and codec driver together.
+Private data can also be set here. e.g.
+
+/* corgi audio private data */
+static struct wm8731_setup_data corgi_wm8731_setup = {
+	.i2c_address = 0x1b,
+};
+
+/* corgi audio subsystem */
+static struct snd_soc_device corgi_snd_devdata = {
+	.machine = &snd_soc_machine_corgi,
+	.platform = &pxa2xx_soc_platform,
+	.codec_dev = &soc_codec_dev_wm8731,
+	.codec_data = &corgi_wm8731_setup,
+};
+
+
+Machine Power Map
+-----------------
+
+The machine driver can optionally extend the codec power map and to become an
+audio power map of the audio subsystem. This allows for automatic power up/down
+of speaker/HP amplifiers, etc. Codec pins can be connected to the machines jack
+sockets in the machine init function. See soc/pxa/spitz.c and dapm.txt for
+details.
+
+
+Machine Controls
+----------------
+
+Machine specific audio mixer controls can be added in the dai init function.
\ No newline at end of file
diff --git a/Documentation/sound/alsa/soc/overview.txt b/Documentation/sound/alsa/soc/overview.txt
new file mode 100644
index 0000000..753c5cc
--- /dev/null
+++ b/Documentation/sound/alsa/soc/overview.txt
@@ -0,0 +1,83 @@
+ALSA SoC Layer
+==============
+
+The overall project goal of the ALSA System on Chip (ASoC) layer is to provide
+better ALSA support for embedded system on chip procesors (e.g. pxa2xx, au1x00,
+iMX, etc) and portable audio codecs. Currently there is some support in the
+kernel for SoC audio, however it has some limitations:-
+
+  * Currently, codec drivers are often tightly coupled to the underlying SoC
+    cpu. This is not ideal and leads to code duplication i.e. Linux now has 4
+    different wm8731 drivers for 4 different SoC platforms.
+
+  * There is no standard method to signal user initiated audio events.
+    e.g. Headphone/Mic insertion, Headphone/Mic detection after an insertion
+    event. These are quite common events on portable devices and ofter require
+    machine specific code to re route audio, enable amps etc after such an event.
+
+  * Current drivers tend to power up the entire codec when playing
+    (or recording) audio. This is fine for a PC, but tends to waste a lot of
+    power on portable devices. There is also no support for saving power via
+    changing codec oversampling rates, bias currents, etc.
+
+
+ASoC Design
+===========
+
+The ASoC layer is designed to address these issues and provide the following
+features :-
+
+  * Codec independence. Allows reuse of codec drivers on other platforms
+    and machines.
+
+  * Easy I2S/PCM audio interface setup between codec and SoC. Each SoC interface
+    and codec registers it's audio interface capabilities with the core and are
+    subsequently matched and configured when the application hw params are known.
+
+  * Dynamic Audio Power Management (DAPM). DAPM automatically sets the codec to
+    it's minimum power state at all times. This includes powering up/down
+    internal power blocks depending on the internal codec audio routing and any
+    active streams.
+
+  * Pop and click reduction. Pops and clicks can be reduced by powering the
+    codec up/down in the correct sequence (including using digital mute). ASoC
+    signals the codec when to change power states.
+
+  * Machine specific controls: Allow machines to add controls to the sound card
+    e.g. volume control for speaker amp.
+
+To achieve all this, ASoC basically splits an embedded audio system into 3
+components :-
+
+  * Codec driver: The codec driver is platform independent and contains audio
+    controls, audio interface capabilities, codec dapm definition and codec IO
+    functions.
+
+  * Platform driver: The platform driver contains the audio dma engine and audio
+    interface drivers (e.g. I2S, AC97, PCM) for that platform.
+
+  * Machine driver: The machine driver handles any machine specific controls and
+    audio events. i.e. turing on an amp at start of playback.
+
+
+Documentation
+=============
+
+The documentation is spilt into the following sections:-
+
+overview.txt: This file.
+
+codec.txt: Codec driver internals.
+
+DAI.txt: Description of Digital Audio Interface standards and how to configure
+a DAI within your codec and CPU DAI drivers.
+
+dapm.txt: Dynamic Audio Power Management
+
+platform.txt: Platform audio DMA and DAI.
+
+machine.txt: Machine driver internals.
+
+pop_clicks.txt: How to minimise audio artifacts.
+
+clocking.txt: ASoC clocking for best power performance.
\ No newline at end of file
diff --git a/Documentation/sound/alsa/soc/platform.txt b/Documentation/sound/alsa/soc/platform.txt
new file mode 100644
index 0000000..e95b16d
--- /dev/null
+++ b/Documentation/sound/alsa/soc/platform.txt
@@ -0,0 +1,58 @@
+ASoC Platform Driver
+====================
+
+An ASoC platform driver can be divided into audio DMA and SoC DAI configuration
+and control. The platform drivers only target the SoC CPU and must have no board
+specific code.
+
+Audio DMA
+=========
+
+The platform DMA driver optionally supports the following alsa operations:-
+
+/* SoC audio ops */
+struct snd_soc_ops {
+	int (*startup)(struct snd_pcm_substream *);
+	void (*shutdown)(struct snd_pcm_substream *);
+	int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
+	int (*hw_free)(struct snd_pcm_substream *);
+	int (*prepare)(struct snd_pcm_substream *);
+	int (*trigger)(struct snd_pcm_substream *, int);
+};
+
+The platform driver exports it's DMA functionailty via struct snd_soc_platform:-
+
+struct snd_soc_platform {
+	char *name;
+
+	int (*probe)(struct platform_device *pdev);
+	int (*remove)(struct platform_device *pdev);
+	int (*suspend)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai);
+	int (*resume)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai);
+
+	/* pcm creation and destruction */
+	int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *, struct snd_pcm *);
+	void (*pcm_free)(struct snd_pcm *);
+
+	/* platform stream ops */
+	struct snd_pcm_ops *pcm_ops;
+};
+
+Please refer to the alsa driver documentation for details of audio DMA.
+http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm
+
+An example DMA driver is soc/pxa/pxa2xx-pcm.c
+
+
+SoC DAI Drivers
+===============
+
+Each SoC DAI driver must provide the following features:-
+
+ 1) Digital audio interface (DAI) description
+ 2) Digital audio interface configuration
+ 3) PCM's description
+ 4) Sysclk configuration
+ 5) Suspend and resume (optional)
+
+Please see codec.txt for a description of items 1 - 4.
diff --git a/Documentation/sound/alsa/soc/pops_clicks.txt b/Documentation/sound/alsa/soc/pops_clicks.txt
new file mode 100644
index 0000000..2cf7ee5
--- /dev/null
+++ b/Documentation/sound/alsa/soc/pops_clicks.txt
@@ -0,0 +1,52 @@
+Audio Pops and Clicks
+=====================
+
+Pops and clicks are unwanted audio artifacts caused by the powering up and down
+of components within the audio subsystem. This is noticable on PC's when an
+audio module is either loaded or unloaded (at module load time the sound card is
+powered up and causes a popping noise on the speakers).
+
+Pops and clicks can be more frequent on portable systems with DAPM. This is
+because the components within the subsystem are being dynamically powered
+depending on the audio usage and this can subsequently cause a small pop or
+click every time a component power state is changed.
+
+
+Minimising Playback Pops and Clicks
+===================================
+
+Playback pops in portable audio subsystems cannot be completely eliminated atm,
+however future audio codec hardware will have better pop and click supression.
+Pops can be reduced within playback by powering the audio components in a
+specific order. This order is different for startup and shutdown and follows
+some basic rules:-
+
+ Startup Order :- DAC --> Mixers --> Output PGA --> Digital Unmute
+
+ Shutdown Order :- Digital Mute --> Output PGA --> Mixers --> DAC
+
+This assumes that the codec PCM output path from the DAC is via a mixer and then
+a PGA (programmable gain amplifier) before being output to the speakers.
+
+
+Minimising Capture Pops and Clicks
+==================================
+
+Capture artifacts are somewhat easier to get rid as we can delay activating the
+ADC until all the pops have occured. This follows similar power rules to
+playback in that components are powered in a sequence depending upon stream
+startup or shutdown.
+
+ Startup Order - Input PGA --> Mixers --> ADC
+
+ Shutdown Order - ADC --> Mixers --> Input PGA
+
+
+Zipper Noise
+============
+An unwanted zipper noise can occur within the audio playback or capture stream
+when a volume control is changed near its maximum gain value. The zipper noise
+is heard when the gain increase or decrease changes the mean audio signal
+amplitude too quickly. It can be minimised by enabling the zero cross setting
+for each volume control. The ZC forces the gain change to occur when the signal
+crosses the zero amplitude line.
diff --git a/Documentation/usb/proc_usb_info.txt b/Documentation/usb/proc_usb_info.txt
index 22c5331..077e903 100644
--- a/Documentation/usb/proc_usb_info.txt
+++ b/Documentation/usb/proc_usb_info.txt
@@ -213,15 +213,16 @@
 
 Interface descriptor info (can be multiple per Config):
 
-I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
-|   |      |      |       |             |      |       |__Driver name
-|   |      |      |       |             |      |          or "(none)"
-|   |      |      |       |             |      |__InterfaceProtocol
-|   |      |      |       |             |__InterfaceSubClass
-|   |      |      |       |__InterfaceClass
-|   |      |      |__NumberOfEndpoints
-|   |      |__AlternateSettingNumber
-|   |__InterfaceNumber
+I:* If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
+| | |      |      |       |             |      |       |__Driver name
+| | |      |      |       |             |      |          or "(none)"
+| | |      |      |       |             |      |__InterfaceProtocol
+| | |      |      |       |             |__InterfaceSubClass
+| | |      |      |       |__InterfaceClass
+| | |      |      |__NumberOfEndpoints
+| | |      |__AlternateSettingNumber
+| | |__InterfaceNumber
+| |__ "*" indicates the active altsetting (others are " ")
 |__Interface info tag
 
     A given interface may have one or more "alternate" settings.
@@ -277,7 +278,7 @@
 on how to do this.)
 
 The Interface lines can be used to determine what driver is
-being used for each device.
+being used for each device, and which altsetting it activated.
 
 The Configuration lines could be used to list maximum power
 (in milliamps) that a system's USB devices are using.
diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt
index e65ec82..0f6808a 100644
--- a/Documentation/usb/usbmon.txt
+++ b/Documentation/usb/usbmon.txt
@@ -77,7 +77,7 @@
 
 The '1t' type data consists of a stream of events, such as URB submission,
 URB callback, submission error. Every event is a text line, which consists
-of whitespace separated words. The number of position of words may depend
+of whitespace separated words. The number or position of words may depend
 on the event type, but there is a set of words, common for all types.
 
 Here is the list of words, from left to right:
@@ -170,4 +170,152 @@
 
 * Raw binary format and API
 
-TBD
+The overall architecture of the API is about the same as the one above,
+only the events are delivered in binary format. Each event is sent in
+the following structure (its name is made up, so that we can refer to it):
+
+struct usbmon_packet {
+	u64 id;			/*  0: URB ID - from submission to callback */
+	unsigned char type;	/*  8: Same as text; extensible. */
+	unsigned char xfer_type; /*    ISO (0), Intr, Control, Bulk (3) */
+	unsigned char epnum;	/*     Endpoint number and transfer direction */
+	unsigned char devnum;	/*     Device address */
+	u16 busnum;		/* 12: Bus number */
+	char flag_setup;	/* 14: Same as text */
+	char flag_data;		/* 15: Same as text; Binary zero is OK. */
+	s64 ts_sec;		/* 16: gettimeofday */
+	s32 ts_usec;		/* 24: gettimeofday */
+	int status;		/* 28: */
+	unsigned int length;	/* 32: Length of data (submitted or actual) */
+	unsigned int len_cap;	/* 36: Delivered length */
+	unsigned char setup[8];	/* 40: Only for Control 'S' */
+};				/* 48 bytes total */
+
+These events can be received from a character device by reading with read(2),
+with an ioctl(2), or by accessing the buffer with mmap.
+
+The character device is usually called /dev/usbmonN, where N is the USB bus
+number. Number zero (/dev/usbmon0) is special and means "all buses".
+However, this feature is not implemented yet. Note that specific naming
+policy is set by your Linux distribution.
+
+If you create /dev/usbmon0 by hand, make sure that it is owned by root
+and has mode 0600. Otherwise, unpriviledged users will be able to snoop
+keyboard traffic.
+
+The following ioctl calls are available, with MON_IOC_MAGIC 0x92:
+
+ MON_IOCQ_URB_LEN, defined as _IO(MON_IOC_MAGIC, 1)
+
+This call returns the length of data in the next event. Note that majority of
+events contain no data, so if this call returns zero, it does not mean that
+no events are available.
+
+ MON_IOCG_STATS, defined as _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
+
+The argument is a pointer to the following structure:
+
+struct mon_bin_stats {
+	u32 queued;
+	u32 dropped;
+};
+
+The member "queued" refers to the number of events currently queued in the
+buffer (and not to the number of events processed since the last reset).
+
+The member "dropped" is the number of events lost since the last call
+to MON_IOCG_STATS.
+
+ MON_IOCT_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 4)
+
+This call sets the buffer size. The argument is the size in bytes.
+The size may be rounded down to the next chunk (or page). If the requested
+size is out of [unspecified] bounds for this kernel, the call fails with
+-EINVAL.
+
+ MON_IOCQ_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 5)
+
+This call returns the current size of the buffer in bytes.
+
+ MON_IOCX_GET, defined as _IOW(MON_IOC_MAGIC, 6, struct mon_get_arg)
+
+This call waits for events to arrive if none were in the kernel buffer,
+then returns the first event. Its argument is a pointer to the following
+structure:
+
+struct mon_get_arg {
+	struct usbmon_packet *hdr;
+	void *data;
+	size_t alloc;		/* Length of data (can be zero) */
+};
+
+Before the call, hdr, data, and alloc should be filled. Upon return, the area
+pointed by hdr contains the next event structure, and the data buffer contains
+the data, if any. The event is removed from the kernel buffer.
+
+ MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg)
+
+This ioctl is primarily used when the application accesses the buffer
+with mmap(2). Its argument is a pointer to the following structure:
+
+struct mon_mfetch_arg {
+	uint32_t *offvec;	/* Vector of events fetched */
+	uint32_t nfetch;	/* Number of events to fetch (out: fetched) */
+	uint32_t nflush;	/* Number of events to flush */
+};
+
+The ioctl operates in 3 stages.
+
+First, it removes and discards up to nflush events from the kernel buffer.
+The actual number of events discarded is returned in nflush.
+
+Second, it waits for an event to be present in the buffer, unless the pseudo-
+device is open with O_NONBLOCK.
+
+Third, it extracts up to nfetch offsets into the mmap buffer, and stores
+them into the offvec. The actual number of event offsets is stored into
+the nfetch.
+
+ MON_IOCH_MFLUSH, defined as _IO(MON_IOC_MAGIC, 8)
+
+This call removes a number of events from the kernel buffer. Its argument
+is the number of events to remove. If the buffer contains fewer events
+than requested, all events present are removed, and no error is reported.
+This works when no events are available too.
+
+ FIONBIO
+
+The ioctl FIONBIO may be implemented in the future, if there's a need.
+
+In addition to ioctl(2) and read(2), the special file of binary API can
+be polled with select(2) and poll(2). But lseek(2) does not work.
+
+* Memory-mapped access of the kernel buffer for the binary API
+
+The basic idea is simple:
+
+To prepare, map the buffer by getting the current size, then using mmap(2).
+Then, execute a loop similar to the one written in pseudo-code below:
+
+   struct mon_mfetch_arg fetch;
+   struct usbmon_packet *hdr;
+   int nflush = 0;
+   for (;;) {
+      fetch.offvec = vec; // Has N 32-bit words
+      fetch.nfetch = N;   // Or less than N
+      fetch.nflush = nflush;
+      ioctl(fd, MON_IOCX_MFETCH, &fetch);   // Process errors, too
+      nflush = fetch.nfetch;       // This many packets to flush when done
+      for (i = 0; i < nflush; i++) {
+         hdr = (struct ubsmon_packet *) &mmap_area[vec[i]];
+         if (hdr->type == '@')     // Filler packet
+            continue;
+         caddr_t data = &mmap_area[vec[i]] + 64;
+         process_packet(hdr, data);
+      }
+   }
+
+Thus, the main idea is to execute only one ioctl per N events.
+
+Although the buffer is circular, the returned headers and data do not cross
+the end of the buffer, so the above pseudo-code does not need any gathering.
diff --git a/Documentation/video-output.txt b/Documentation/video-output.txt
new file mode 100644
index 0000000..e517011
--- /dev/null
+++ b/Documentation/video-output.txt
@@ -0,0 +1,34 @@
+
+		Video Output Switcher Control
+		~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		2006 luming.yu@intel.com
+
+The output sysfs class driver provides an abstract video output layer that
+can be used to hook platform specific methods to enable/disable video output
+device through common sysfs interface. For example, on my IBM ThinkPad T42
+laptop, The ACPI video driver registered its output devices and read/write
+method for 'state' with output sysfs class. The user interface under sysfs is:
+
+linux:/sys/class/video_output # tree .
+.
+|-- CRT0
+|   |-- device -> ../../../devices/pci0000:00/0000:00:01.0
+|   |-- state
+|   |-- subsystem -> ../../../class/video_output
+|   `-- uevent
+|-- DVI0
+|   |-- device -> ../../../devices/pci0000:00/0000:00:01.0
+|   |-- state
+|   |-- subsystem -> ../../../class/video_output
+|   `-- uevent
+|-- LCD0
+|   |-- device -> ../../../devices/pci0000:00/0000:00:01.0
+|   |-- state
+|   |-- subsystem -> ../../../class/video_output
+|   `-- uevent
+`-- TV0
+   |-- device -> ../../../devices/pci0000:00/0000:00:01.0
+   |-- state
+   |-- subsystem -> ../../../class/video_output
+   `-- uevent
+
diff --git a/MAINTAINERS b/MAINTAINERS
index 0ad8803..a6c1ebd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -584,12 +584,30 @@
 W:	http://xf.iksaif.net/acpi4asus
 S:	Maintained
 
+ASUS LAPTOP EXTRAS DRIVER
+P:	Corentin Chary
+M:	corentincj@iksaif.net
+L:	acpi4asus-user@lists.sourceforge.net
+W:	http://sourceforge.net/projects/acpi4asus
+W:	http://xf.iksaif.net/acpi4asus
+S:	Maintained
+
 ATA OVER ETHERNET DRIVER
 P:	Ed L. Cashin
 M:	ecashin@coraid.com
 W:	http://www.coraid.com/support/linux
 S:	Supported
 
+ATL1 ETHERNET DRIVER
+P:	Jay Cliburn
+M:	jcliburn@gmail.com
+P:	Chris Snook
+M:	csnook@redhat.com
+L:	atl1-devel@lists.sourceforge.net
+W:	http://sourceforge.net/projects/atl1
+W:	http://atl1.sourceforge.net
+S:	Maintained
+
 ATM
 P:	Chas Williams
 M:	chas@cmf.nrl.navy.mil
@@ -1096,7 +1114,7 @@
 DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
 P:	Tobias Ringstrom
 M:	tori@unhappy.mine.nu
-L:	linux-kernel@vger.kernel.org
+L:	netdev@vger.kernel.org
 S:	Maintained
 
 DOCBOOK FOR DOCUMENTATION
@@ -2343,7 +2361,7 @@
 NETWORKING [WIRELESS]
 P:	John W. Linville
 M:	linville@tuxdriver.com
-L:	netdev@vger.kernel.org
+L:	linux-wireless@vger.kernel.org
 T:	git kernel.org:/pub/scm/linux/kernel/git/linville/wireless-2.6.git
 S:	Maintained
 
@@ -2477,6 +2495,12 @@
 W:	http://www.nongnu.org/orinoco/
 S:	Maintained
 
+PA SEMI ETHERNET DRIVER
+P:	Olof Johansson
+M:	olof@lixom.net
+L:	netdev@vger.kernel.org
+S:	Maintained
+
 PARALLEL PORT SUPPORT
 P:	Phil Blundell
 M:	philb@gnu.org
@@ -2646,7 +2670,7 @@
 
 PRISM54 WIRELESS DRIVER
 P:	Prism54 Development Team
-M:	prism54-private@prism54.org
+M:	developers@islsm.org
 L:	netdev@vger.kernel.org
 W:	http://prism54.org
 S:	Maintained
@@ -2791,7 +2815,7 @@
 P:	Heiko Carstens
 M:	heiko.carstens@de.ibm.com
 M:	linux390@de.ibm.com
-L:	linux-390@vm.marist.edu
+L:	linux-s390@vger.kernel.org
 W:	http://www.ibm.com/developerworks/linux/linux390/
 S:	Supported
 
@@ -2799,7 +2823,7 @@
 P:	Frank Pavlic
 M:	fpavlic@de.ibm.com
 M:	linux390@de.ibm.com
-L:	linux-390@vm.marist.edu
+L:	linux-s390@vger.kernel.org
 W:	http://www.ibm.com/developerworks/linux/linux390/
 S:	Supported
 
@@ -2807,7 +2831,7 @@
 P:	Swen Schillig
 M:	swen@vnet.ibm.com
 M:	linux390@de.ibm.com
-L:	linux-390@vm.marist.edu
+L:	linux-s390@vger.kernel.org
 W:	http://www.ibm.com/developerworks/linux/linux390/
 S:	Supported
 
@@ -3013,6 +3037,12 @@
 L:	alsa-devel@alsa-project.org
 S:	Maintained
 
+SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT
+P:	Liam Girdwood
+M:	liam.girdwood@wolfsonmicro.com
+L:	alsa-devel@alsa-project.org
+S:	Supported
+
 SPI SUBSYSTEM
 P:	David Brownell
 M:	dbrownell@users.sourceforge.net
@@ -3263,6 +3293,11 @@
 W:	http://vtun.sourceforge.net/tun
 S:	Maintained
 
+TURBOCHANNEL SUBSYSTEM
+P:	Maciej W. Rozycki
+M:	macro@linux-mips.org
+S:	Maintained
+
 U14-34F SCSI DRIVER
 P:	Dario Ballabio
 M:	ballabio_dario@emc.com
@@ -3647,7 +3682,7 @@
 W83L51xD SD/MMC CARD INTERFACE DRIVER
 P:	Pierre Ossman
 M:	drzeus-wbsd@drzeus.cx
-L:	wbsd-devel@list.drzeus.cx
+L:	linux-kernel@vger.kernel.org
 W:	http://projects.drzeus.cx/wbsd
 S:	Maintained
 
diff --git a/Makefile b/Makefile
index 7e2750f..cdeda68 100644
--- a/Makefile
+++ b/Makefile
@@ -776,7 +776,7 @@
 #	  $(EXTRAVERSION)		eg, -rc6
 #	$(localver-full)
 #	  $(localver)
-#	    localversion*		(all localversion* files)
+#	    localversion*		(files without backups, containing '~')
 #	    $(CONFIG_LOCALVERSION)	(from kernel config setting)
 #	  $(localver-auto)		(only if CONFIG_LOCALVERSION_AUTO is set)
 #	    ./scripts/setlocalversion	(SCM tag, if one exists)
@@ -787,17 +787,12 @@
 # moment, only git is supported but other SCMs can edit the script
 # scripts/setlocalversion and add the appropriate checks as needed.
 
-nullstring :=
-space      := $(nullstring) # end of line
+pattern = ".*/localversion[^~]*"
+string  = $(shell cat /dev/null \
+	   `find $(objtree) $(srctree) -maxdepth 1 -regex $(pattern) | sort`)
 
-___localver = $(objtree)/localversion* $(srctree)/localversion*
-__localver  = $(sort $(wildcard $(___localver)))
-# skip backup files (containing '~')
-_localver = $(foreach f, $(__localver), $(if $(findstring ~, $(f)),,$(f)))
-
-localver = $(subst $(space),, \
-	   $(shell cat /dev/null $(_localver)) \
-	   $(patsubst "%",%,$(CONFIG_LOCALVERSION)))
+localver = $(subst $(space),, $(string) \
+			      $(patsubst "%",%,$(CONFIG_LOCALVERSION)))
 
 # If CONFIG_LOCALVERSION_AUTO is set scripts/setlocalversion is called
 # and if the SCM is know a tag from the SCM is appended.
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 3c10b9a..ab642a4 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -575,3 +575,7 @@
 
 EXPORT_SYMBOL(pci_iomap);
 EXPORT_SYMBOL(pci_iounmap);
+
+/* FIXME: Some boxes have multiple ISA bridges! */
+struct pci_dev *isa_bridge;
+EXPORT_SYMBOL(isa_bridge);
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 6783c2e..1523046e 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -9,6 +9,7 @@
 	bool
 	default y
 	select RTC_LIB
+	select SYS_SUPPORTS_APM_EMULATION
 	help
 	  The ARM series is a line of low-power-consumption RISC chip designs
 	  licensed by ARM Ltd and targeted at embedded applications and
@@ -17,6 +18,9 @@
 	  Europe.  There is an ARM Linux project with a web page at
 	  <http://www.arm.linux.org.uk/>.
 
+config SYS_SUPPORTS_APM_EMULATION
+	bool
+
 config GENERIC_TIME
 	bool
 	default n
@@ -856,31 +860,6 @@
 
 source "kernel/power/Kconfig"
 
-config APM
-	tristate "Advanced Power Management Emulation"
-	---help---
-	  APM is a BIOS specification for saving power using several different
-	  techniques. This is mostly useful for battery powered laptops with
-	  APM compliant BIOSes. If you say Y here, the system time will be
-	  reset after a RESUME operation, the /proc/apm device will provide
-	  battery status information, and user-space programs will receive
-	  notification of APM "events" (e.g. battery status change).
-
-	  In order to use APM, you will need supporting software. For location
-	  and more information, read <file:Documentation/pm.txt> and the
-	  Battery Powered Linux mini-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  This driver does not spin down disk drives (see the hdparm(8)
-	  manpage ("man 8 hdparm") for that), and it doesn't turn off
-	  VESA-compliant "green" monitors.
-
-	  Generally, if you don't have a battery in your machine, there isn't
-	  much point in using this driver and you should say N. If you get
-	  random kernel OOPSes or reboots that don't seem to be related to
-	  anything, try disabling/enabling this option (or disabling/enabling
-	  APM in your BIOS).
-
 endmenu
 
 source "net/Kconfig"
diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c
index b359974..a3b450f 100644
--- a/arch/arm/common/sharpsl_pm.c
+++ b/arch/arm/common/sharpsl_pm.c
@@ -27,7 +27,7 @@
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
-#include <asm/apm.h>
+#include <asm/apm-emulation.h>
 #include <asm/arch/pm.h>
 #include <asm/arch/pxa-regs.h>
 #include <asm/arch/sharpsl.h>
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index ab06a86..1b935fb 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -10,7 +10,6 @@
 		   process.o ptrace.o semaphore.o setup.o signal.o sys_arm.o \
 		   time.o traps.o
 
-obj-$(CONFIG_APM)		+= apm.o
 obj-$(CONFIG_ISA_DMA_API)	+= dma.o
 obj-$(CONFIG_ARCH_ACORN)	+= ecard.o 
 obj-$(CONFIG_FIQ)		+= fiq.o
diff --git a/arch/arm/mach-pxa/corgi_pm.c b/arch/arm/mach-pxa/corgi_pm.c
index 4c3de40..165017d 100644
--- a/arch/arm/mach-pxa/corgi_pm.c
+++ b/arch/arm/mach-pxa/corgi_pm.c
@@ -16,7 +16,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
-#include <asm/apm.h>
+#include <asm/apm-emulation.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 #include <asm/hardware.h>
diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c
index db6e8f5..b1d8cfc 100644
--- a/arch/arm/mach-pxa/sharpsl_pm.c
+++ b/arch/arm/mach-pxa/sharpsl_pm.c
@@ -23,7 +23,7 @@
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
-#include <asm/apm.h>
+#include <asm/apm-emulation.h>
 #include <asm/arch/pm.h>
 #include <asm/arch/pxa-regs.h>
 #include <asm/arch/sharpsl.h>
diff --git a/arch/arm/mach-pxa/spitz_pm.c b/arch/arm/mach-pxa/spitz_pm.c
index 40be833..b97d543 100644
--- a/arch/arm/mach-pxa/spitz_pm.c
+++ b/arch/arm/mach-pxa/spitz_pm.c
@@ -16,7 +16,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
-#include <asm/apm.h>
+#include <asm/apm-emulation.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 #include <asm/hardware.h>
diff --git a/arch/avr32/boards/atstk1000/Makefile b/arch/avr32/boards/atstk1000/Makefile
index df94994..8e09922 100644
--- a/arch/avr32/boards/atstk1000/Makefile
+++ b/arch/avr32/boards/atstk1000/Makefile
@@ -1,2 +1,2 @@
-obj-y				+= setup.o spi.o flash.o
+obj-y				+= setup.o flash.o
 obj-$(CONFIG_BOARD_ATSTK1002)	+= atstk1002.o
diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
index 32b361f..d47e39f 100644
--- a/arch/avr32/boards/atstk1000/atstk1002.c
+++ b/arch/avr32/boards/atstk1000/atstk1002.c
@@ -8,17 +8,24 @@
  * published by the Free Software Foundation.
  */
 #include <linux/clk.h>
+#include <linux/device.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/spi/spi.h>
 
 #include <asm/io.h>
 #include <asm/setup.h>
+#include <asm/arch/at32ap7000.h>
 #include <asm/arch/board.h>
 #include <asm/arch/init.h>
+#include <asm/arch/portmux.h>
+
+
+#define	SW2_DEFAULT		/* MMCI and UART_A available */
 
 struct eth_addr {
 	u8 addr[6];
@@ -29,6 +36,16 @@
 static struct eth_platform_data __initdata eth_data[2];
 extern struct lcdc_platform_data atstk1000_fb0_data;
 
+static struct spi_board_info spi_board_info[] __initdata = {
+	{
+		.modalias	= "ltv350qv",
+		.controller_data = (void *)GPIO_PIN_PA(4),
+		.max_speed_hz	= 16000000,
+		.bus_num	= 0,
+		.chip_select	= 1,
+	},
+};
+
 /*
  * The next two functions should go away as the boot loader is
  * supposed to initialize the macb address registers with a valid
@@ -86,23 +103,53 @@
 
 void __init setup_board(void)
 {
-	at32_map_usart(1, 0);	/* /dev/ttyS0 */
-	at32_map_usart(2, 1);	/* /dev/ttyS1 */
-	at32_map_usart(3, 2);	/* /dev/ttyS2 */
+#ifdef	SW2_DEFAULT
+	at32_map_usart(1, 0);	/* USART 1/A: /dev/ttyS0, DB9 */
+#else
+	at32_map_usart(0, 1);	/* USART 0/B: /dev/ttyS1, IRDA */
+#endif
+	/* USART 2/unused: expansion connector */
+	at32_map_usart(3, 2);	/* USART 3/C: /dev/ttyS2, DB9 */
 
 	at32_setup_serial_console(0);
 }
 
 static int __init atstk1002_init(void)
 {
+	/*
+	 * ATSTK1000 uses 32-bit SDRAM interface. Reserve the
+	 * SDRAM-specific pins so that nobody messes with them.
+	 */
+	at32_reserve_pin(GPIO_PIN_PE(0));	/* DATA[16]	*/
+	at32_reserve_pin(GPIO_PIN_PE(1));	/* DATA[17]	*/
+	at32_reserve_pin(GPIO_PIN_PE(2));	/* DATA[18]	*/
+	at32_reserve_pin(GPIO_PIN_PE(3));	/* DATA[19]	*/
+	at32_reserve_pin(GPIO_PIN_PE(4));	/* DATA[20]	*/
+	at32_reserve_pin(GPIO_PIN_PE(5));	/* DATA[21]	*/
+	at32_reserve_pin(GPIO_PIN_PE(6));	/* DATA[22]	*/
+	at32_reserve_pin(GPIO_PIN_PE(7));	/* DATA[23]	*/
+	at32_reserve_pin(GPIO_PIN_PE(8));	/* DATA[24]	*/
+	at32_reserve_pin(GPIO_PIN_PE(9));	/* DATA[25]	*/
+	at32_reserve_pin(GPIO_PIN_PE(10));	/* DATA[26]	*/
+	at32_reserve_pin(GPIO_PIN_PE(11));	/* DATA[27]	*/
+	at32_reserve_pin(GPIO_PIN_PE(12));	/* DATA[28]	*/
+	at32_reserve_pin(GPIO_PIN_PE(13));	/* DATA[29]	*/
+	at32_reserve_pin(GPIO_PIN_PE(14));	/* DATA[30]	*/
+	at32_reserve_pin(GPIO_PIN_PE(15));	/* DATA[31]	*/
+	at32_reserve_pin(GPIO_PIN_PE(26));	/* SDCS		*/
+
 	at32_add_system_devices();
 
+#ifdef	SW2_DEFAULT
 	at32_add_device_usart(0);
+#else
 	at32_add_device_usart(1);
+#endif
 	at32_add_device_usart(2);
 
 	set_hw_addr(at32_add_device_eth(0, &eth_data[0]));
 
+	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
 	at32_add_device_spi(0);
 	at32_add_device_lcdc(0, &atstk1000_fb0_data);
 
diff --git a/arch/avr32/boards/atstk1000/spi.c b/arch/avr32/boards/atstk1000/spi.c
deleted file mode 100644
index 567726c..0000000
--- a/arch/avr32/boards/atstk1000/spi.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * ATSTK1000 SPI devices
- *
- * Copyright (C) 2005 Atmel Norway
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-
-static struct spi_board_info spi_board_info[] __initdata = {
-	{
-		.modalias	= "ltv350qv",
-		.max_speed_hz	= 16000000,
-		.bus_num	= 0,
-		.chip_select	= 1,
-	},
-};
-
-static int board_init_spi(void)
-{
-	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
-	return 0;
-}
-arch_initcall(board_init_spi);
diff --git a/arch/avr32/kernel/cpu.c b/arch/avr32/kernel/cpu.c
index 342452b..2e72fd2 100644
--- a/arch/avr32/kernel/cpu.c
+++ b/arch/avr32/kernel/cpu.c
@@ -9,6 +9,7 @@
 #include <linux/sysdev.h>
 #include <linux/seq_file.h>
 #include <linux/cpu.h>
+#include <linux/module.h>
 #include <linux/percpu.h>
 #include <linux/param.h>
 #include <linux/errno.h>
diff --git a/arch/avr32/kernel/irq.c b/arch/avr32/kernel/irq.c
index 856f354..fd31124 100644
--- a/arch/avr32/kernel/irq.c
+++ b/arch/avr32/kernel/irq.c
@@ -57,6 +57,7 @@
 		seq_printf(p, "%3d: ", i);
 		for_each_online_cpu(cpu)
 			seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]);
+		seq_printf(p, " %8s", irq_desc[i].chip->name ? : "-");
 		seq_printf(p, "  %s", action->name);
 		for (action = action->next; action; action = action->next)
 			seq_printf(p, ", %s", action->name);
diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c
index a342116..c6734ae 100644
--- a/arch/avr32/kernel/setup.c
+++ b/arch/avr32/kernel/setup.c
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/root_dev.h>
 #include <linux/cpu.h>
+#include <linux/kernel.h>
 
 #include <asm/sections.h>
 #include <asm/processor.h>
@@ -174,8 +175,7 @@
 	 * Copy the data so the bootmem init code doesn't need to care
 	 * about it.
 	 */
-	if (mem_range_next_free >=
-	    (sizeof(mem_range_cache) / sizeof(mem_range_cache[0])))
+	if (mem_range_next_free >= ARRAY_SIZE(mem_range_cache))
 		panic("Physical memory map too complex!\n");
 
 	new = &mem_range_cache[mem_range_next_free++];
diff --git a/arch/avr32/lib/libgcc.h b/arch/avr32/lib/libgcc.h
deleted file mode 100644
index 5a091b5..0000000
--- a/arch/avr32/lib/libgcc.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Definitions for various functions 'borrowed' from gcc-3.4.3 */
-
-#define BITS_PER_UNIT	8
-
-typedef		 int QItype	__attribute__ ((mode (QI)));
-typedef unsigned int UQItype	__attribute__ ((mode (QI)));
-typedef		 int HItype	__attribute__ ((mode (HI)));
-typedef unsigned int UHItype	__attribute__ ((mode (HI)));
-typedef 	 int SItype	__attribute__ ((mode (SI)));
-typedef unsigned int USItype	__attribute__ ((mode (SI)));
-typedef		 int DItype	__attribute__ ((mode (DI)));
-typedef unsigned int UDItype	__attribute__ ((mode (DI)));
-typedef 	float SFtype	__attribute__ ((mode (SF)));
-typedef		float DFtype	__attribute__ ((mode (DF)));
-typedef int word_type __attribute__ ((mode (__word__)));
-
-#define W_TYPE_SIZE (4 * BITS_PER_UNIT)
-#define Wtype	SItype
-#define UWtype	USItype
-#define HWtype	SItype
-#define UHWtype	USItype
-#define DWtype	DItype
-#define UDWtype	UDItype
-#define __NW(a,b)	__ ## a ## si ## b
-#define __NDW(a,b)	__ ## a ## di ## b
-
-struct DWstruct {Wtype high, low;};
-
-typedef union
-{
-  struct DWstruct s;
-  DWtype ll;
-} DWunion;
diff --git a/arch/avr32/lib/longlong.h b/arch/avr32/lib/longlong.h
deleted file mode 100644
index cd5e369..0000000
--- a/arch/avr32/lib/longlong.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/* longlong.h -- definitions for mixed size 32/64 bit arithmetic.
-   Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000
-   Free Software Foundation, Inc.
-
-   This definition file 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 definition file 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.  */
-
-/* Borrowed from gcc-3.4.3 */
-
-#define __BITS4 (W_TYPE_SIZE / 4)
-#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2))
-#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1))
-#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2))
-
-#define count_leading_zeros(count, x) ((count) = __builtin_clz(x))
-
-#define __udiv_qrnnd_c(q, r, n1, n0, d) \
-  do {									\
-    UWtype __d1, __d0, __q1, __q0;					\
-    UWtype __r1, __r0, __m;						\
-    __d1 = __ll_highpart (d);						\
-    __d0 = __ll_lowpart (d);						\
-									\
-    __r1 = (n1) % __d1;							\
-    __q1 = (n1) / __d1;							\
-    __m = (UWtype) __q1 * __d0;						\
-    __r1 = __r1 * __ll_B | __ll_highpart (n0);				\
-    if (__r1 < __m)							\
-      {									\
-	__q1--, __r1 += (d);						\
-	if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\
-	  if (__r1 < __m)						\
-	    __q1--, __r1 += (d);					\
-      }									\
-    __r1 -= __m;							\
-									\
-    __r0 = __r1 % __d1;							\
-    __q0 = __r1 / __d1;							\
-    __m = (UWtype) __q0 * __d0;						\
-    __r0 = __r0 * __ll_B | __ll_lowpart (n0);				\
-    if (__r0 < __m)							\
-      {									\
-	__q0--, __r0 += (d);						\
-	if (__r0 >= (d))						\
-	  if (__r0 < __m)						\
-	    __q0--, __r0 += (d);					\
-      }									\
-    __r0 -= __m;							\
-									\
-    (q) = (UWtype) __q1 * __ll_B | __q0;				\
-    (r) = __r0;								\
-  } while (0)
-
-#define udiv_qrnnd __udiv_qrnnd_c
-
-#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
-  do {									\
-    UWtype __x;								\
-    __x = (al) - (bl);							\
-    (sh) = (ah) - (bh) - (__x > (al));					\
-    (sl) = __x;								\
-  } while (0)
-
-#define umul_ppmm(w1, w0, u, v)						\
-  do {									\
-    UWtype __x0, __x1, __x2, __x3;					\
-    UHWtype __ul, __vl, __uh, __vh;					\
-									\
-    __ul = __ll_lowpart (u);						\
-    __uh = __ll_highpart (u);						\
-    __vl = __ll_lowpart (v);						\
-    __vh = __ll_highpart (v);						\
-									\
-    __x0 = (UWtype) __ul * __vl;					\
-    __x1 = (UWtype) __ul * __vh;					\
-    __x2 = (UWtype) __uh * __vl;					\
-    __x3 = (UWtype) __uh * __vh;					\
-									\
-    __x1 += __ll_highpart (__x0);/* this can't give carry */		\
-    __x1 += __x2;		/* but this indeed can */		\
-    if (__x1 < __x2)		/* did we get it? */			\
-      __x3 += __ll_B;		/* yes, add it in the proper pos.  */	\
-									\
-    (w1) = __x3 + __ll_highpart (__x1);					\
-    (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0);		\
-  } while (0)
diff --git a/arch/avr32/mach-at32ap/Makefile b/arch/avr32/mach-at32ap/Makefile
index f62eb69..b21bea9 100644
--- a/arch/avr32/mach-at32ap/Makefile
+++ b/arch/avr32/mach-at32ap/Makefile
@@ -1,2 +1,2 @@
-obj-y				+= at32ap.o clock.o pio.o intc.o extint.o hsmc.o
+obj-y				+= at32ap.o clock.o intc.o extint.o pio.o hsmc.o
 obj-$(CONFIG_CPU_AT32AP7000)	+= at32ap7000.o
diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c
index 48f4ef3..c1e477e 100644
--- a/arch/avr32/mach-at32ap/at32ap7000.c
+++ b/arch/avr32/mach-at32ap/at32ap7000.c
@@ -496,9 +496,16 @@
 DEFINE_DEV(pio, 3);
 DEV_CLK(mck, pio3, pba, 13);
 
+static struct resource pio4_resource[] = {
+	PBMEM(0xffe03800),
+	IRQ(17),
+};
+DEFINE_DEV(pio, 4);
+DEV_CLK(mck, pio4, pba, 14);
+
 void __init at32_add_system_devices(void)
 {
-	system_manager.eim_first_irq = NR_INTERNAL_IRQS;
+	system_manager.eim_first_irq = EIM_IRQ_BASE;
 
 	platform_device_register(&at32_sm_device);
 	platform_device_register(&at32_intc0_device);
@@ -509,6 +516,7 @@
 	platform_device_register(&pio1_device);
 	platform_device_register(&pio2_device);
 	platform_device_register(&pio3_device);
+	platform_device_register(&pio4_device);
 }
 
 /* --------------------------------------------------------------------
@@ -521,7 +529,7 @@
 };
 static struct resource atmel_usart0_resource[] = {
 	PBMEM(0xffe00c00),
-	IRQ(7),
+	IRQ(6),
 };
 DEFINE_DEV_DATA(atmel_usart, 0);
 DEV_CLK(usart, atmel_usart0, pba, 4);
@@ -583,7 +591,7 @@
 	select_peripheral(PB(17), PERIPH_B, 0);	/* TXD	*/
 }
 
-static struct platform_device *at32_usarts[4];
+static struct platform_device *__initdata at32_usarts[4];
 
 void __init at32_map_usart(unsigned int hw_id, unsigned int line)
 {
@@ -728,12 +736,19 @@
 /* --------------------------------------------------------------------
  *  SPI
  * -------------------------------------------------------------------- */
-static struct resource spi0_resource[] = {
+static struct resource atmel_spi0_resource[] = {
 	PBMEM(0xffe00000),
 	IRQ(3),
 };
-DEFINE_DEV(spi, 0);
-DEV_CLK(mck, spi0, pba, 0);
+DEFINE_DEV(atmel_spi, 0);
+DEV_CLK(spi_clk, atmel_spi0, pba, 0);
+
+static struct resource atmel_spi1_resource[] = {
+	PBMEM(0xffe00400),
+	IRQ(4),
+};
+DEFINE_DEV(atmel_spi, 1);
+DEV_CLK(spi_clk, atmel_spi1, pba, 1);
 
 struct platform_device *__init at32_add_device_spi(unsigned int id)
 {
@@ -741,13 +756,33 @@
 
 	switch (id) {
 	case 0:
-		pdev = &spi0_device;
+		pdev = &atmel_spi0_device;
 		select_peripheral(PA(0),  PERIPH_A, 0);	/* MISO	 */
 		select_peripheral(PA(1),  PERIPH_A, 0);	/* MOSI	 */
 		select_peripheral(PA(2),  PERIPH_A, 0);	/* SCK	 */
-		select_peripheral(PA(3),  PERIPH_A, 0);	/* NPCS0 */
-		select_peripheral(PA(4),  PERIPH_A, 0);	/* NPCS1 */
-		select_peripheral(PA(5),  PERIPH_A, 0);	/* NPCS2 */
+
+		/* NPCS[2:0] */
+		at32_select_gpio(GPIO_PIN_PA(3),
+				 AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
+		at32_select_gpio(GPIO_PIN_PA(4),
+				 AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
+		at32_select_gpio(GPIO_PIN_PA(5),
+				 AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
+		break;
+
+	case 1:
+		pdev = &atmel_spi1_device;
+		select_peripheral(PB(0),  PERIPH_B, 0);	/* MISO  */
+		select_peripheral(PB(1),  PERIPH_B, 0);	/* MOSI  */
+		select_peripheral(PB(5),  PERIPH_B, 0);	/* SCK   */
+
+		/* NPCS[2:0] */
+		at32_select_gpio(GPIO_PIN_PB(2),
+				 AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
+		at32_select_gpio(GPIO_PIN_PB(3),
+				 AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
+		at32_select_gpio(GPIO_PIN_PB(4),
+				 AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
 		break;
 
 	default:
@@ -860,6 +895,7 @@
 	&pio1_mck,
 	&pio2_mck,
 	&pio3_mck,
+	&pio4_mck,
 	&atmel_usart0_usart,
 	&atmel_usart1_usart,
 	&atmel_usart2_usart,
@@ -868,7 +904,8 @@
 	&macb0_pclk,
 	&macb1_hclk,
 	&macb1_pclk,
-	&spi0_mck,
+	&atmel_spi0_spi_clk,
+	&atmel_spi1_spi_clk,
 	&lcdc0_hclk,
 	&lcdc0_pixclk,
 };
@@ -880,6 +917,7 @@
 	at32_init_pio(&pio1_device);
 	at32_init_pio(&pio2_device);
 	at32_init_pio(&pio3_device);
+	at32_init_pio(&pio4_device);
 }
 
 void __init at32_clock_init(void)
diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c
index b59272e..4a60ecc 100644
--- a/arch/avr32/mach-at32ap/extint.c
+++ b/arch/avr32/mach-at32ap/extint.c
@@ -55,20 +55,11 @@
 	unsigned long flags;
 	int ret = 0;
 
+	flow_type &= IRQ_TYPE_SENSE_MASK;
 	if (flow_type == IRQ_TYPE_NONE)
 		flow_type = IRQ_TYPE_LEVEL_LOW;
 
 	desc = &irq_desc[irq];
-	desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
-	desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
-
-	if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) {
-		desc->status |= IRQ_LEVEL;
-		set_irq_handler(irq, handle_level_irq);
-	} else {
-		set_irq_handler(irq, handle_edge_irq);
-	}
-
 	spin_lock_irqsave(&sm->lock, flags);
 
 	mode = sm_readl(sm, EIM_MODE);
@@ -97,9 +88,16 @@
 		break;
 	}
 
-	sm_writel(sm, EIM_MODE, mode);
-	sm_writel(sm, EIM_EDGE, edge);
-	sm_writel(sm, EIM_LEVEL, level);
+	if (ret == 0) {
+		sm_writel(sm, EIM_MODE, mode);
+		sm_writel(sm, EIM_EDGE, edge);
+		sm_writel(sm, EIM_LEVEL, level);
+
+		if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+			flow_type |= IRQ_LEVEL;
+		desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
+		desc->status |= flow_type;
+	}
 
 	spin_unlock_irqrestore(&sm->lock, flags);
 
@@ -122,8 +120,6 @@
 	unsigned long status, pending;
 	unsigned int i, ext_irq;
 
-	spin_lock(&sm->lock);
-
 	status = sm_readl(sm, EIM_ISR);
 	pending = status & sm_readl(sm, EIM_IMR);
 
@@ -133,10 +129,11 @@
 
 		ext_irq = i + sm->eim_first_irq;
 		ext_desc = irq_desc + ext_irq;
-		ext_desc->handle_irq(ext_irq, ext_desc);
+		if (ext_desc->status & IRQ_LEVEL)
+			handle_level_irq(ext_irq, ext_desc);
+		else
+			handle_edge_irq(ext_irq, ext_desc);
 	}
-
-	spin_unlock(&sm->lock);
 }
 
 static int __init eim_init(void)
@@ -168,8 +165,9 @@
 	sm->eim_chip = &eim_chip;
 
 	for (i = 0; i < nr_irqs; i++) {
+		/* NOTE the handler we set here is ignored by the demux */
 		set_irq_chip_and_handler(sm->eim_first_irq + i, &eim_chip,
-					 handle_edge_irq);
+					 handle_level_irq);
 		set_irq_chip_data(sm->eim_first_irq + i, sm);
 	}
 
diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c
index f1280ed..9ba5654 100644
--- a/arch/avr32/mach-at32ap/pio.c
+++ b/arch/avr32/mach-at32ap/pio.c
@@ -12,7 +12,9 @@
 #include <linux/debugfs.h>
 #include <linux/fs.h>
 #include <linux/platform_device.h>
+#include <linux/irq.h>
 
+#include <asm/gpio.h>
 #include <asm/io.h>
 
 #include <asm/arch/portmux.h>
@@ -26,7 +28,8 @@
 	const struct platform_device *pdev;
 	struct clk *clk;
 	u32 pinmux_mask;
-	char name[32];
+	u32 gpio_mask;
+	char name[8];
 };
 
 static struct pio_device pio_dev[MAX_NR_PIO_DEVICES];
@@ -76,6 +79,9 @@
 	if (!(flags & AT32_GPIOF_PULLUP))
 		pio_writel(pio, PUDR, mask);
 
+	/* gpio_request NOT allowed */
+	set_bit(pin_index, &pio->gpio_mask);
+
 	return;
 
 fail:
@@ -99,19 +105,29 @@
 		goto fail;
 	}
 
-	pio_writel(pio, PUER, mask);
-	if (flags & AT32_GPIOF_HIGH)
-		pio_writel(pio, SODR, mask);
-	else
-		pio_writel(pio, CODR, mask);
-	if (flags & AT32_GPIOF_OUTPUT)
+	if (flags & AT32_GPIOF_OUTPUT) {
+		if (flags & AT32_GPIOF_HIGH)
+			pio_writel(pio, SODR, mask);
+		else
+			pio_writel(pio, CODR, mask);
+		pio_writel(pio, PUDR, mask);
 		pio_writel(pio, OER, mask);
-	else
+	} else {
+		if (flags & AT32_GPIOF_PULLUP)
+			pio_writel(pio, PUER, mask);
+		else
+			pio_writel(pio, PUDR, mask);
+		if (flags & AT32_GPIOF_DEGLITCH)
+			pio_writel(pio, IFER, mask);
+		else
+			pio_writel(pio, IFDR, mask);
 		pio_writel(pio, ODR, mask);
+	}
 
 	pio_writel(pio, PER, mask);
-	if (!(flags & AT32_GPIOF_PULLUP))
-		pio_writel(pio, PUDR, mask);
+
+	/* gpio_request now allowed */
+	clear_bit(pin_index, &pio->gpio_mask);
 
 	return;
 
@@ -119,20 +135,220 @@
 	dump_stack();
 }
 
+/* Reserve a pin, preventing anyone else from changing its configuration. */
+void __init at32_reserve_pin(unsigned int pin)
+{
+	struct pio_device *pio;
+	unsigned int pin_index = pin & 0x1f;
+
+	pio = gpio_to_pio(pin);
+	if (unlikely(!pio)) {
+		printk("pio: invalid pin %u\n", pin);
+		goto fail;
+	}
+
+	if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) {
+		printk("%s: pin %u is busy\n", pio->name, pin_index);
+		goto fail;
+	}
+
+	return;
+
+fail:
+	dump_stack();
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* GPIO API */
+
+int gpio_request(unsigned int gpio, const char *label)
+{
+	struct pio_device *pio;
+	unsigned int pin;
+
+	pio = gpio_to_pio(gpio);
+	if (!pio)
+		return -ENODEV;
+
+	pin = gpio & 0x1f;
+	if (test_and_set_bit(pin, &pio->gpio_mask))
+		return -EBUSY;
+
+	return 0;
+}
+EXPORT_SYMBOL(gpio_request);
+
+void gpio_free(unsigned int gpio)
+{
+	struct pio_device *pio;
+	unsigned int pin;
+
+	pio = gpio_to_pio(gpio);
+	if (!pio) {
+		printk(KERN_ERR
+		       "gpio: attempted to free invalid pin %u\n", gpio);
+		return;
+	}
+
+	pin = gpio & 0x1f;
+	if (!test_and_clear_bit(pin, &pio->gpio_mask))
+		printk(KERN_ERR "gpio: freeing free or non-gpio pin %s-%u\n",
+		       pio->name, pin);
+}
+EXPORT_SYMBOL(gpio_free);
+
+int gpio_direction_input(unsigned int gpio)
+{
+	struct pio_device *pio;
+	unsigned int pin;
+
+	pio = gpio_to_pio(gpio);
+	if (!pio)
+		return -ENODEV;
+
+	pin = gpio & 0x1f;
+	pio_writel(pio, ODR, 1 << pin);
+
+	return 0;
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+int gpio_direction_output(unsigned int gpio)
+{
+	struct pio_device *pio;
+	unsigned int pin;
+
+	pio = gpio_to_pio(gpio);
+	if (!pio)
+		return -ENODEV;
+
+	pin = gpio & 0x1f;
+	pio_writel(pio, OER, 1 << pin);
+
+	return 0;
+}
+EXPORT_SYMBOL(gpio_direction_output);
+
+int gpio_get_value(unsigned int gpio)
+{
+	struct pio_device *pio = &pio_dev[gpio >> 5];
+
+	return (pio_readl(pio, PDSR) >> (gpio & 0x1f)) & 1;
+}
+EXPORT_SYMBOL(gpio_get_value);
+
+void gpio_set_value(unsigned int gpio, int value)
+{
+	struct pio_device *pio = &pio_dev[gpio >> 5];
+	u32 mask;
+
+	mask = 1 << (gpio & 0x1f);
+	if (value)
+		pio_writel(pio, SODR, mask);
+	else
+		pio_writel(pio, CODR, mask);
+}
+EXPORT_SYMBOL(gpio_set_value);
+
+/*--------------------------------------------------------------------------*/
+
+/* GPIO IRQ support */
+
+static void gpio_irq_mask(unsigned irq)
+{
+	unsigned		gpio = irq_to_gpio(irq);
+	struct pio_device	*pio = &pio_dev[gpio >> 5];
+
+	pio_writel(pio, IDR, 1 << (gpio & 0x1f));
+}
+
+static void gpio_irq_unmask(unsigned irq)
+{
+	unsigned		gpio = irq_to_gpio(irq);
+	struct pio_device	*pio = &pio_dev[gpio >> 5];
+
+	pio_writel(pio, IER, 1 << (gpio & 0x1f));
+}
+
+static int gpio_irq_type(unsigned irq, unsigned type)
+{
+	if (type != IRQ_TYPE_EDGE_BOTH && type != IRQ_TYPE_NONE)
+		return -EINVAL;
+
+	return 0;
+}
+
+static struct irq_chip gpio_irqchip = {
+	.name		= "gpio",
+	.mask		= gpio_irq_mask,
+	.unmask		= gpio_irq_unmask,
+	.set_type	= gpio_irq_type,
+};
+
+static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+	struct pio_device	*pio = get_irq_chip_data(irq);
+	unsigned		gpio_irq;
+
+	gpio_irq = (unsigned) get_irq_data(irq);
+	for (;;) {
+		u32		isr;
+		struct irq_desc	*d;
+
+		/* ack pending GPIO interrupts */
+		isr = pio_readl(pio, ISR) & pio_readl(pio, IMR);
+		if (!isr)
+			break;
+		do {
+			int i;
+
+			i = ffs(isr) - 1;
+			isr &= ~(1 << i);
+
+			i += gpio_irq;
+			d = &irq_desc[i];
+
+			d->handle_irq(i, d);
+		} while (isr);
+	}
+}
+
+static void __init
+gpio_irq_setup(struct pio_device *pio, int irq, int gpio_irq)
+{
+	unsigned	i;
+
+	set_irq_chip_data(irq, pio);
+	set_irq_data(irq, (void *) gpio_irq);
+
+	for (i = 0; i < 32; i++, gpio_irq++) {
+		set_irq_chip_data(gpio_irq, pio);
+		set_irq_chip_and_handler(gpio_irq, &gpio_irqchip,
+				handle_simple_irq);
+	}
+
+	set_irq_chained_handler(irq, gpio_irq_handler);
+}
+
+/*--------------------------------------------------------------------------*/
+
 static int __init pio_probe(struct platform_device *pdev)
 {
 	struct pio_device *pio = NULL;
+	int irq = platform_get_irq(pdev, 0);
+	int gpio_irq_base = GPIO_IRQ_BASE + pdev->id * 32;
 
 	BUG_ON(pdev->id >= MAX_NR_PIO_DEVICES);
 	pio = &pio_dev[pdev->id];
 	BUG_ON(!pio->regs);
 
-	/* TODO: Interrupts */
+	gpio_irq_setup(pio, irq, gpio_irq_base);
 
 	platform_set_drvdata(pdev, pio);
 
-	printk(KERN_INFO "%s: Atmel Port Multiplexer at 0x%p (irq %d)\n",
-	       pio->name, pio->regs, platform_get_irq(pdev, 0));
+	printk(KERN_DEBUG "%s: base 0x%p, irq %d chains %d..%d\n",
+	       pio->name, pio->regs, irq, gpio_irq_base, gpio_irq_base + 31);
 
 	return 0;
 }
@@ -148,7 +364,7 @@
 {
 	return platform_driver_register(&pio_driver);
 }
-subsys_initcall(pio_init);
+postcore_initcall(pio_init);
 
 void __init at32_init_pio(struct platform_device *pdev)
 {
@@ -184,6 +400,13 @@
 	pio->pdev = pdev;
 	pio->regs = ioremap(regs->start, regs->end - regs->start + 1);
 
-	pio_writel(pio, ODR, ~0UL);
-	pio_writel(pio, PER, ~0UL);
+	/*
+	 * request_gpio() is only valid for pins that have been
+	 * explicitly configured as GPIO and not previously requested
+	 */
+	pio->gpio_mask = ~0UL;
+
+	/* start with irqs disabled and acked */
+	pio_writel(pio, IDR, ~0UL);
+	(void) pio_readl(pio, ISR);
 }
diff --git a/arch/avr32/mm/cache.c b/arch/avr32/mm/cache.c
index 450515b..fb13f72 100644
--- a/arch/avr32/mm/cache.c
+++ b/arch/avr32/mm/cache.c
@@ -22,18 +22,34 @@
 
 void invalidate_dcache_region(void *start, size_t size)
 {
-	unsigned long v, begin, end, linesz;
+	unsigned long v, begin, end, linesz, mask;
+	int flush = 0;
 
 	linesz = boot_cpu_data.dcache.linesz;
+	mask = linesz - 1;
 
-	//printk("invalidate dcache: %p + %u\n", start, size);
+	/* when first and/or last cachelines are shared, flush them
+	 * instead of invalidating ... never discard valid data!
+	 */
+	begin = (unsigned long)start;
+	end = begin + size - 1;
 
-	/* You asked for it, you got it */
-	begin = (unsigned long)start & ~(linesz - 1);
-	end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);
+	if (begin & mask) {
+		flush_dcache_line(start);
+		begin += linesz;
+		flush = 1;
+	}
+	if ((end & mask) != mask) {
+		flush_dcache_line((void *)end);
+		end -= linesz;
+		flush = 1;
+	}
 
-	for (v = begin; v < end; v += linesz)
+	/* remaining cachelines only need invalidation */
+	for (v = begin; v <= end; v += linesz)
 		invalidate_dcache_line((void *)v);
+	if (flush)
+		flush_write_buffer();
 }
 
 void clean_dcache_region(void *start, size_t size)
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 5d80edf..bb0c376 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -466,7 +466,8 @@
 #
 # Plug and Play support
 #
-# CONFIG_PNP is not set
+CONFIG_PNP=y
+CONFIG_PNPACPI=y
 
 #
 # Block devices
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index cbcb2c2..e94aff6 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -66,7 +66,7 @@
 
 #define BAD_MADT_ENTRY(entry, end) (					    \
 		(!entry) || (unsigned long)entry + sizeof(*entry) > end ||  \
-		((acpi_table_entry_header *)entry)->length < sizeof(*entry))
+		((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
 
 #define PREFIX			"ACPI: "
 
@@ -79,7 +79,7 @@
 int acpi_strict;
 EXPORT_SYMBOL(acpi_strict);
 
-acpi_interrupt_flags acpi_sci_flags __initdata;
+u8 acpi_sci_flags __initdata;
 int acpi_sci_override_gsi __initdata;
 int acpi_skip_timer_override __initdata;
 int acpi_use_timer_override __initdata;
@@ -92,11 +92,6 @@
 #warning ACPI uses CMPXCHG, i486 and later hardware
 #endif
 
-#define MAX_MADT_ENTRIES	256
-u8 x86_acpiid_to_apicid[MAX_MADT_ENTRIES] =
-    {[0 ... MAX_MADT_ENTRIES - 1] = 0xff };
-EXPORT_SYMBOL(x86_acpiid_to_apicid);
-
 /* --------------------------------------------------------------------------
                               Boot-time Configuration
    -------------------------------------------------------------------------- */
@@ -166,30 +161,26 @@
 
 #ifdef CONFIG_PCI_MMCONFIG
 /* The physical address of the MMCONFIG aperture.  Set from ACPI tables. */
-struct acpi_table_mcfg_config *pci_mmcfg_config;
+struct acpi_mcfg_allocation *pci_mmcfg_config;
 int pci_mmcfg_config_num;
 
-int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
+int __init acpi_parse_mcfg(struct acpi_table_header *header)
 {
 	struct acpi_table_mcfg *mcfg;
 	unsigned long i;
 	int config_size;
 
-	if (!phys_addr || !size)
+	if (!header)
 		return -EINVAL;
 
-	mcfg = (struct acpi_table_mcfg *)__acpi_map_table(phys_addr, size);
-	if (!mcfg) {
-		printk(KERN_WARNING PREFIX "Unable to map MCFG\n");
-		return -ENODEV;
-	}
+	mcfg = (struct acpi_table_mcfg *)header;
 
 	/* how many config structures do we have */
 	pci_mmcfg_config_num = 0;
-	i = size - sizeof(struct acpi_table_mcfg);
-	while (i >= sizeof(struct acpi_table_mcfg_config)) {
+	i = header->length - sizeof(struct acpi_table_mcfg);
+	while (i >= sizeof(struct acpi_mcfg_allocation)) {
 		++pci_mmcfg_config_num;
-		i -= sizeof(struct acpi_table_mcfg_config);
+		i -= sizeof(struct acpi_mcfg_allocation);
 	};
 	if (pci_mmcfg_config_num == 0) {
 		printk(KERN_ERR PREFIX "MMCONFIG has no entries\n");
@@ -204,9 +195,9 @@
 		return -ENOMEM;
 	}
 
-	memcpy(pci_mmcfg_config, &mcfg->config, config_size);
+	memcpy(pci_mmcfg_config, &mcfg[1], config_size);
 	for (i = 0; i < pci_mmcfg_config_num; ++i) {
-		if (mcfg->config[i].base_reserved) {
+		if (pci_mmcfg_config[i].address > 0xFFFFFFFF) {
 			printk(KERN_ERR PREFIX
 			       "MMCONFIG not in low 4GB of memory\n");
 			kfree(pci_mmcfg_config);
@@ -220,24 +211,24 @@
 #endif				/* CONFIG_PCI_MMCONFIG */
 
 #ifdef CONFIG_X86_LOCAL_APIC
-static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_madt(struct acpi_table_header *table)
 {
 	struct acpi_table_madt *madt = NULL;
 
-	if (!phys_addr || !size || !cpu_has_apic)
+	if (!cpu_has_apic)
 		return -EINVAL;
 
-	madt = (struct acpi_table_madt *)__acpi_map_table(phys_addr, size);
+	madt = (struct acpi_table_madt *)table;
 	if (!madt) {
 		printk(KERN_WARNING PREFIX "Unable to map MADT\n");
 		return -ENODEV;
 	}
 
-	if (madt->lapic_address) {
-		acpi_lapic_addr = (u64) madt->lapic_address;
+	if (madt->address) {
+		acpi_lapic_addr = (u64) madt->address;
 
 		printk(KERN_DEBUG PREFIX "Local APIC address 0x%08x\n",
-		       madt->lapic_address);
+		       madt->address);
 	}
 
 	acpi_madt_oem_check(madt->header.oem_id, madt->header.oem_table_id);
@@ -246,21 +237,17 @@
 }
 
 static int __init
-acpi_parse_lapic(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_lapic(struct acpi_subtable_header * header, const unsigned long end)
 {
-	struct acpi_table_lapic *processor = NULL;
+	struct acpi_madt_local_apic *processor = NULL;
 
-	processor = (struct acpi_table_lapic *)header;
+	processor = (struct acpi_madt_local_apic *)header;
 
 	if (BAD_MADT_ENTRY(processor, end))
 		return -EINVAL;
 
 	acpi_table_print_madt_entry(header);
 
-	/* Record local apic id only when enabled */
-	if (processor->flags.enabled)
-		x86_acpiid_to_apicid[processor->acpi_id] = processor->id;
-
 	/*
 	 * We need to register disabled CPU as well to permit
 	 * counting disabled CPUs. This allows us to size
@@ -269,18 +256,18 @@
 	 * when we use CPU hotplug.
 	 */
 	mp_register_lapic(processor->id,	/* APIC ID */
-			  processor->flags.enabled);	/* Enabled? */
+			  processor->lapic_flags & ACPI_MADT_ENABLED);	/* Enabled? */
 
 	return 0;
 }
 
 static int __init
-acpi_parse_lapic_addr_ovr(acpi_table_entry_header * header,
+acpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header,
 			  const unsigned long end)
 {
-	struct acpi_table_lapic_addr_ovr *lapic_addr_ovr = NULL;
+	struct acpi_madt_local_apic_override *lapic_addr_ovr = NULL;
 
-	lapic_addr_ovr = (struct acpi_table_lapic_addr_ovr *)header;
+	lapic_addr_ovr = (struct acpi_madt_local_apic_override *)header;
 
 	if (BAD_MADT_ENTRY(lapic_addr_ovr, end))
 		return -EINVAL;
@@ -291,11 +278,11 @@
 }
 
 static int __init
-acpi_parse_lapic_nmi(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end)
 {
-	struct acpi_table_lapic_nmi *lapic_nmi = NULL;
+	struct acpi_madt_local_apic_nmi *lapic_nmi = NULL;
 
-	lapic_nmi = (struct acpi_table_lapic_nmi *)header;
+	lapic_nmi = (struct acpi_madt_local_apic_nmi *)header;
 
 	if (BAD_MADT_ENTRY(lapic_nmi, end))
 		return -EINVAL;
@@ -313,11 +300,11 @@
 #ifdef CONFIG_X86_IO_APIC
 
 static int __init
-acpi_parse_ioapic(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end)
 {
-	struct acpi_table_ioapic *ioapic = NULL;
+	struct acpi_madt_io_apic *ioapic = NULL;
 
-	ioapic = (struct acpi_table_ioapic *)header;
+	ioapic = (struct acpi_madt_io_apic *)header;
 
 	if (BAD_MADT_ENTRY(ioapic, end))
 		return -EINVAL;
@@ -342,11 +329,11 @@
 		polarity = 3;
 
 	/* Command-line over-ride via acpi_sci= */
-	if (acpi_sci_flags.trigger)
-		trigger = acpi_sci_flags.trigger;
+	if (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)
+		trigger = (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2;
 
-	if (acpi_sci_flags.polarity)
-		polarity = acpi_sci_flags.polarity;
+	if (acpi_sci_flags & ACPI_MADT_POLARITY_MASK)
+		polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK;
 
 	/*
 	 * mp_config_acpi_legacy_irqs() already setup IRQs < 16
@@ -357,51 +344,52 @@
 
 	/*
 	 * stash over-ride to indicate we've been here
-	 * and for later update of acpi_fadt
+	 * and for later update of acpi_gbl_FADT
 	 */
 	acpi_sci_override_gsi = gsi;
 	return;
 }
 
 static int __init
-acpi_parse_int_src_ovr(acpi_table_entry_header * header,
+acpi_parse_int_src_ovr(struct acpi_subtable_header * header,
 		       const unsigned long end)
 {
-	struct acpi_table_int_src_ovr *intsrc = NULL;
+	struct acpi_madt_interrupt_override *intsrc = NULL;
 
-	intsrc = (struct acpi_table_int_src_ovr *)header;
+	intsrc = (struct acpi_madt_interrupt_override *)header;
 
 	if (BAD_MADT_ENTRY(intsrc, end))
 		return -EINVAL;
 
 	acpi_table_print_madt_entry(header);
 
-	if (intsrc->bus_irq == acpi_fadt.sci_int) {
+	if (intsrc->source_irq == acpi_gbl_FADT.sci_interrupt) {
 		acpi_sci_ioapic_setup(intsrc->global_irq,
-				      intsrc->flags.polarity,
-				      intsrc->flags.trigger);
+				      intsrc->inti_flags & ACPI_MADT_POLARITY_MASK,
+				      (intsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2);
 		return 0;
 	}
 
 	if (acpi_skip_timer_override &&
-	    intsrc->bus_irq == 0 && intsrc->global_irq == 2) {
+	    intsrc->source_irq == 0 && intsrc->global_irq == 2) {
 		printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n");
 		return 0;
 	}
 
-	mp_override_legacy_irq(intsrc->bus_irq,
-			       intsrc->flags.polarity,
-			       intsrc->flags.trigger, intsrc->global_irq);
+	mp_override_legacy_irq(intsrc->source_irq,
+				intsrc->inti_flags & ACPI_MADT_POLARITY_MASK,
+				(intsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2,
+				intsrc->global_irq);
 
 	return 0;
 }
 
 static int __init
-acpi_parse_nmi_src(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_nmi_src(struct acpi_subtable_header * header, const unsigned long end)
 {
-	struct acpi_table_nmi_src *nmi_src = NULL;
+	struct acpi_madt_nmi_source *nmi_src = NULL;
 
-	nmi_src = (struct acpi_table_nmi_src *)header;
+	nmi_src = (struct acpi_madt_nmi_source *)header;
 
 	if (BAD_MADT_ENTRY(nmi_src, end))
 		return -EINVAL;
@@ -417,7 +405,7 @@
 
 /*
  * acpi_pic_sci_set_trigger()
- * 
+ *
  * use ELCR to set PIC-mode trigger type for SCI
  *
  * If a PIC-mode SCI is not recognized or gives spurious IRQ7's
@@ -511,7 +499,7 @@
 {
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 	union acpi_object *obj;
-	struct acpi_table_lapic *lapic;
+	struct acpi_madt_local_apic *lapic;
 	cpumask_t tmp_map, new_map;
 	u8 physid;
 	int cpu;
@@ -529,10 +517,10 @@
 		return -EINVAL;
 	}
 
-	lapic = (struct acpi_table_lapic *)obj->buffer.pointer;
+	lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer;
 
-	if ((lapic->header.type != ACPI_MADT_LAPIC) ||
-	    (!lapic->flags.enabled)) {
+	if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC ||
+	    !(lapic->lapic_flags & ACPI_MADT_ENABLED)) {
 		kfree(buffer.pointer);
 		return -EINVAL;
 	}
@@ -544,7 +532,7 @@
 	buffer.pointer = NULL;
 
 	tmp_map = cpu_present_map;
-	mp_register_lapic(physid, lapic->flags.enabled);
+	mp_register_lapic(physid, lapic->lapic_flags & ACPI_MADT_ENABLED);
 
 	/*
 	 * If mp_register_lapic successfully generates a new logical cpu
@@ -566,14 +554,6 @@
 
 int acpi_unmap_lsapic(int cpu)
 {
-	int i;
-
-	for_each_possible_cpu(i) {
-		if (x86_acpiid_to_apicid[i] == x86_cpu_to_apicid[cpu]) {
-			x86_acpiid_to_apicid[i] = -1;
-			break;
-		}
-	}
 	x86_cpu_to_apicid[cpu] = -1;
 	cpu_clear(cpu, cpu_present_map);
 	num_processors--;
@@ -619,42 +599,36 @@
 	return 0;
 }
 
-static int __init acpi_parse_sbf(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_sbf(struct acpi_table_header *table)
 {
-	struct acpi_table_sbf *sb;
+	struct acpi_table_boot *sb;
 
-	if (!phys_addr || !size)
-		return -EINVAL;
-
-	sb = (struct acpi_table_sbf *)__acpi_map_table(phys_addr, size);
+	sb = (struct acpi_table_boot *)table;
 	if (!sb) {
 		printk(KERN_WARNING PREFIX "Unable to map SBF\n");
 		return -ENODEV;
 	}
 
-	sbf_port = sb->sbf_cmos;	/* Save CMOS port */
+	sbf_port = sb->cmos_index;	/* Save CMOS port */
 
 	return 0;
 }
 
 #ifdef CONFIG_HPET_TIMER
 
-static int __init acpi_parse_hpet(unsigned long phys, unsigned long size)
+static int __init acpi_parse_hpet(struct acpi_table_header *table)
 {
 	struct acpi_table_hpet *hpet_tbl;
 	struct resource *hpet_res;
 	resource_size_t res_start;
 
-	if (!phys || !size)
-		return -EINVAL;
-
-	hpet_tbl = (struct acpi_table_hpet *)__acpi_map_table(phys, size);
+	hpet_tbl = (struct acpi_table_hpet *)table;
 	if (!hpet_tbl) {
 		printk(KERN_WARNING PREFIX "Unable to map HPET\n");
 		return -ENODEV;
 	}
 
-	if (hpet_tbl->addr.space_id != ACPI_SPACE_MEM) {
+	if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) {
 		printk(KERN_WARNING PREFIX "HPET timers must be located in "
 		       "memory.\n");
 		return -1;
@@ -667,29 +641,28 @@
 		hpet_res->name = (void *)&hpet_res[1];
 		hpet_res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
 		snprintf((char *)hpet_res->name, HPET_RESOURCE_NAME_SIZE,
-			 "HPET %u", hpet_tbl->number);
+			 "HPET %u", hpet_tbl->sequence);
 		hpet_res->end = (1 * 1024) - 1;
 	}
 
-#ifdef	CONFIG_X86_64
-	vxtime.hpet_address = hpet_tbl->addr.addrl |
-	    ((long)hpet_tbl->addr.addrh << 32);
+#ifdef CONFIG_X86_64
+	vxtime.hpet_address = hpet_tbl->address.address;
 
 	printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
-	       hpet_tbl->id, vxtime.hpet_address);
+		hpet_tbl->id, vxtime.hpet_address);
 
 	res_start = vxtime.hpet_address;
-#else				/* X86 */
+#else                          /* X86 */
 	{
 		extern unsigned long hpet_address;
 
-		hpet_address = hpet_tbl->addr.addrl;
+		hpet_address = hpet_tbl->address.address;
 		printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
-		       hpet_tbl->id, hpet_address);
+			hpet_tbl->id, hpet_address);
 
 		res_start = hpet_address;
 	}
-#endif				/* X86 */
+#endif                         /* X86 */
 
 	if (hpet_res) {
 		hpet_res->start = res_start;
@@ -707,42 +680,28 @@
 extern u32 pmtmr_ioport;
 #endif
 
-static int __init acpi_parse_fadt(unsigned long phys, unsigned long size)
+static int __init acpi_parse_fadt(struct acpi_table_header *table)
 {
-	struct fadt_descriptor *fadt = NULL;
-
-	fadt = (struct fadt_descriptor *)__acpi_map_table(phys, size);
-	if (!fadt) {
-		printk(KERN_WARNING PREFIX "Unable to map FADT\n");
-		return 0;
-	}
-	/* initialize sci_int early for INT_SRC_OVR MADT parsing */
-	acpi_fadt.sci_int = fadt->sci_int;
-
-	/* initialize rev and apic_phys_dest_mode for x86_64 genapic */
-	acpi_fadt.revision = fadt->revision;
-	acpi_fadt.force_apic_physical_destination_mode =
-	    fadt->force_apic_physical_destination_mode;
 
 #ifdef CONFIG_X86_PM_TIMER
 	/* detect the location of the ACPI PM Timer */
-	if (fadt->revision >= FADT2_REVISION_ID) {
+	if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) {
 		/* FADT rev. 2 */
-		if (fadt->xpm_tmr_blk.address_space_id !=
+		if (acpi_gbl_FADT.xpm_timer_block.space_id !=
 		    ACPI_ADR_SPACE_SYSTEM_IO)
 			return 0;
 
-		pmtmr_ioport = fadt->xpm_tmr_blk.address;
+		pmtmr_ioport = acpi_gbl_FADT.xpm_timer_block.address;
 		/*
 		 * "X" fields are optional extensions to the original V1.0
 		 * fields, so we must selectively expand V1.0 fields if the
 		 * corresponding X field is zero.
 	 	 */
 		if (!pmtmr_ioport)
-			pmtmr_ioport = fadt->V1_pm_tmr_blk;
+			pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
 	} else {
 		/* FADT rev. 1 */
-		pmtmr_ioport = fadt->V1_pm_tmr_blk;
+		pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
 	}
 	if (pmtmr_ioport)
 		printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n",
@@ -784,13 +743,13 @@
 	if (!cpu_has_apic)
 		return -ENODEV;
 
-	/* 
+	/*
 	 * Note that the LAPIC address is obtained from the MADT (32-bit value)
 	 * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
 	 */
 
 	count =
-	    acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR,
+	    acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE,
 				  acpi_parse_lapic_addr_ovr, 0);
 	if (count < 0) {
 		printk(KERN_ERR PREFIX
@@ -800,7 +759,7 @@
 
 	mp_register_lapic_address(acpi_lapic_addr);
 
-	count = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic,
+	count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC, acpi_parse_lapic,
 				      MAX_APICS);
 	if (!count) {
 		printk(KERN_ERR PREFIX "No LAPIC entries present\n");
@@ -813,7 +772,7 @@
 	}
 
 	count =
-	    acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0);
+	    acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0);
 	if (count < 0) {
 		printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
 		/* TBD: Cleanup to allow fallback to MPS */
@@ -842,7 +801,7 @@
 		return -ENODEV;
 	}
 
-	if (!cpu_has_apic) 
+	if (!cpu_has_apic)
 		return -ENODEV;
 
 	/*
@@ -855,7 +814,7 @@
 	}
 
 	count =
-	    acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic,
+	    acpi_table_parse_madt(ACPI_MADT_TYPE_IO_APIC, acpi_parse_ioapic,
 				  MAX_IO_APICS);
 	if (!count) {
 		printk(KERN_ERR PREFIX "No IOAPIC entries present\n");
@@ -866,7 +825,7 @@
 	}
 
 	count =
-	    acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr,
+	    acpi_table_parse_madt(ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, acpi_parse_int_src_ovr,
 				  NR_IRQ_VECTORS);
 	if (count < 0) {
 		printk(KERN_ERR PREFIX
@@ -880,13 +839,13 @@
 	 * pretend we got one so we can set the SCI flags.
 	 */
 	if (!acpi_sci_override_gsi)
-		acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0);
+		acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0);
 
 	/* Fill in identity legacy mapings where no override */
 	mp_config_acpi_legacy_irqs();
 
 	count =
-	    acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src,
+	    acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_parse_nmi_src,
 				  NR_IRQ_VECTORS);
 	if (count < 0) {
 		printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
@@ -908,7 +867,7 @@
 #ifdef CONFIG_X86_LOCAL_APIC
 	int count, error;
 
-	count = acpi_table_parse(ACPI_APIC, acpi_parse_madt);
+	count = acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt);
 	if (count >= 1) {
 
 		/*
@@ -1195,7 +1154,7 @@
 	if (acpi_disabled && !acpi_ht)
 		return 1;
 
-	/* 
+	/*
 	 * Initialize the ACPI boot-time table parser.
 	 */
 	error = acpi_table_init();
@@ -1204,7 +1163,7 @@
 		return error;
 	}
 
-	acpi_table_parse(ACPI_BOOT, acpi_parse_sbf);
+	acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
 
 	/*
 	 * blacklist may disable ACPI entirely
@@ -1232,19 +1191,19 @@
 	if (acpi_disabled && !acpi_ht)
 		return 1;
 
-	acpi_table_parse(ACPI_BOOT, acpi_parse_sbf);
+	acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
 
 	/*
 	 * set sci_int and PM timer address
 	 */
-	acpi_table_parse(ACPI_FADT, acpi_parse_fadt);
+	acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt);
 
 	/*
 	 * Process the Multiple APIC Description Table (MADT), if present
 	 */
 	acpi_process_madt();
 
-	acpi_table_parse(ACPI_HPET, acpi_parse_hpet);
+	acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet);
 
 	return 0;
 }
@@ -1315,13 +1274,17 @@
 	if (!s)
 		return -EINVAL;
 	if (!strcmp(s, "edge"))
-		acpi_sci_flags.trigger = 1;
+		acpi_sci_flags =  ACPI_MADT_TRIGGER_EDGE |
+			(acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK);
 	else if (!strcmp(s, "level"))
-		acpi_sci_flags.trigger = 3;
+		acpi_sci_flags = ACPI_MADT_TRIGGER_LEVEL |
+			(acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK);
 	else if (!strcmp(s, "high"))
-		acpi_sci_flags.polarity = 1;
+		acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_HIGH |
+			(acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK);
 	else if (!strcmp(s, "low"))
-		acpi_sci_flags.polarity = 3;
+		acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_LOW |
+			(acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK);
 	else
 		return -EINVAL;
 	return 0;
diff --git a/arch/i386/kernel/acpi/earlyquirk.c b/arch/i386/kernel/acpi/earlyquirk.c
index 4b60af7..bf86f76 100644
--- a/arch/i386/kernel/acpi/earlyquirk.c
+++ b/arch/i386/kernel/acpi/earlyquirk.c
@@ -16,7 +16,7 @@
 
 static int nvidia_hpet_detected __initdata;
 
-static int __init nvidia_hpet_check(unsigned long phys, unsigned long size)
+static int __init nvidia_hpet_check(struct acpi_table_header *header)
 {
 	nvidia_hpet_detected = 1;
 	return 0;
@@ -30,7 +30,7 @@
 	   is enabled. */
 	if (!acpi_use_timer_override && vendor == PCI_VENDOR_ID_NVIDIA) {
 		nvidia_hpet_detected = 0;
-		acpi_table_parse(ACPI_HPET, nvidia_hpet_check);
+		acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check);
 		if (nvidia_hpet_detected == 0) {
 			acpi_skip_timer_override = 1;
 			  printk(KERN_INFO "Nvidia board "
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
index e940e00..a3db933 100644
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
@@ -190,7 +190,7 @@
 		/* Invoke C3 */
 		inb(cx_address);
 		/* Dummy op - must do something useless after P_LVL3 read */
-		t = inl(acpi_fadt.xpm_tmr_blk.address);
+		t = inl(acpi_gbl_FADT.xpm_timer_block.address);
 	}
 	/* Disable bus ratio bit */
 	local_irq_disable();
@@ -250,8 +250,7 @@
 		outb(3, 0x22);
 	} else if ((pr != NULL) && pr->flags.bm_control) {
  		/* Disable bus master arbitration */
-		acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1,
-				  ACPI_MTX_DO_NOT_LOCK);
+		acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
 	}
 	switch (longhaul_version) {
 
@@ -281,8 +280,7 @@
 	case TYPE_POWERSAVER:
 		if (longhaul_flags & USE_ACPI_C3) {
 			/* Don't allow wakeup */
-			acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0,
-					  ACPI_MTX_DO_NOT_LOCK);
+			acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
 			do_powersaver(cx->address, clock_ratio_index);
 		} else {
 			do_powersaver(0, clock_ratio_index);
@@ -295,8 +293,7 @@
 		outb(0, 0x22);
 	} else if ((pr != NULL) && pr->flags.bm_control) {
 		/* Enable bus master arbitration */
-		acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0,
-				  ACPI_MTX_DO_NOT_LOCK);
+		acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
 	}
 	outb(pic2_mask,0xA1);	/* restore mask */
 	outb(pic1_mask,0x21);
@@ -414,7 +411,7 @@
 	highest_speed = calc_speed(maxmult);
 	lowest_speed = calc_speed(minmult);
 	dprintk ("FSB:%dMHz  Lowest speed: %s   Highest speed:%s\n", fsb,
-		 print_speed(lowest_speed/1000), 
+		 print_speed(lowest_speed/1000),
 		 print_speed(highest_speed/1000));
 
 	if (lowest_speed == highest_speed) {
@@ -498,7 +495,7 @@
 		maxvid.mV/1000, maxvid.mV%1000,
 		minvid.mV/1000, minvid.mV%1000,
 		numvscales);
-	
+
 	j = 0;
 	while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {
 		speed = longhaul_table[j].frequency;
diff --git a/arch/i386/kernel/hpet.c b/arch/i386/kernel/hpet.c
index 45a8685..0b29d41 100644
--- a/arch/i386/kernel/hpet.c
+++ b/arch/i386/kernel/hpet.c
@@ -12,7 +12,7 @@
 /* FSEC = 10^-15 NSEC = 10^-9 */
 #define FSEC_PER_NSEC	1000000
 
-static void *hpet_ptr;
+static void __iomem *hpet_ptr;
 
 static cycle_t read_hpet(void)
 {
@@ -40,8 +40,7 @@
 		return -ENODEV;
 
 	/* calculate the hpet address: */
-	hpet_base =
-		(void __iomem*)ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
+	hpet_base = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
 	hpet_ptr = hpet_base + HPET_COUNTER;
 
 	/* calculate the frequency: */
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index 6a3875f..ba8d302 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -126,7 +126,7 @@
  */
 static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
 {
-	volatile struct io_apic *io_apic = io_apic_base(apic);
+	volatile struct io_apic __iomem *io_apic = io_apic_base(apic);
 	if (sis_apic_bug)
 		writel(reg, &io_apic->index);
 	writel(value, &io_apic->data);
@@ -2606,25 +2606,32 @@
 	.retrigger	= ioapic_retrigger_irq,
 };
 
-int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
+int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
 {
 	struct msi_msg msg;
-	int ret;
+	int irq, ret;
+	irq = create_irq();
+	if (irq < 0)
+		return irq;
+
+	set_irq_msi(irq, desc);
 	ret = msi_compose_msg(dev, irq, &msg);
-	if (ret < 0)
+	if (ret < 0) {
+		destroy_irq(irq);
 		return ret;
+	}
 
 	write_msi_msg(irq, &msg);
 
 	set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq,
 				      "edge");
 
-	return 0;
+	return irq;
 }
 
 void arch_teardown_msi_irq(unsigned int irq)
 {
-	return;
+	destroy_irq(irq);
 }
 
 #endif /* CONFIG_PCI_MSI */
diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
index 49bff35..4f5983c 100644
--- a/arch/i386/kernel/mpparse.c
+++ b/arch/i386/kernel/mpparse.c
@@ -1057,7 +1057,7 @@
 	static int		gsi_to_irq[MAX_GSI_NUM];
 
 	/* Don't set up the ACPI SCI because it's already set up */
-	if (acpi_fadt.sci_int == gsi)
+	if (acpi_gbl_FADT.sci_interrupt == gsi)
 		return gsi;
 
 	ioapic = mp_find_ioapic(gsi);
@@ -1114,7 +1114,7 @@
 			/*
 			 * Don't assign IRQ used by ACPI SCI
 			 */
-			if (gsi == acpi_fadt.sci_int)
+			if (gsi == acpi_gbl_FADT.sci_interrupt)
 				gsi = pci_irq++;
 			gsi_to_irq[irq] = gsi;
 		} else {
diff --git a/arch/i386/kernel/srat.c b/arch/i386/kernel/srat.c
index f7e735c..2a8713e 100644
--- a/arch/i386/kernel/srat.c
+++ b/arch/i386/kernel/srat.c
@@ -62,19 +62,19 @@
 /* Identify CPU proximity domains */
 static void __init parse_cpu_affinity_structure(char *p)
 {
-	struct acpi_table_processor_affinity *cpu_affinity = 
-				(struct acpi_table_processor_affinity *) p;
+	struct acpi_srat_cpu_affinity *cpu_affinity =
+				(struct acpi_srat_cpu_affinity *) p;
 
-	if (!cpu_affinity->flags.enabled)
+	if ((cpu_affinity->flags & ACPI_SRAT_CPU_ENABLED) == 0)
 		return;		/* empty entry */
 
 	/* mark this node as "seen" in node bitmap */
-	BMAP_SET(pxm_bitmap, cpu_affinity->proximity_domain);
+	BMAP_SET(pxm_bitmap, cpu_affinity->proximity_domain_lo);
 
-	apicid_to_pxm[cpu_affinity->apic_id] = cpu_affinity->proximity_domain;
+	apicid_to_pxm[cpu_affinity->apic_id] = cpu_affinity->proximity_domain_lo;
 
 	printk("CPU 0x%02X in proximity domain 0x%02X\n",
-		cpu_affinity->apic_id, cpu_affinity->proximity_domain);
+		cpu_affinity->apic_id, cpu_affinity->proximity_domain_lo);
 }
 
 /*
@@ -84,28 +84,27 @@
 static void __init parse_memory_affinity_structure (char *sratp)
 {
 	unsigned long long paddr, size;
-	unsigned long start_pfn, end_pfn; 
+	unsigned long start_pfn, end_pfn;
 	u8 pxm;
 	struct node_memory_chunk_s *p, *q, *pend;
-	struct acpi_table_memory_affinity *memory_affinity =
-			(struct acpi_table_memory_affinity *) sratp;
+	struct acpi_srat_mem_affinity *memory_affinity =
+			(struct acpi_srat_mem_affinity *) sratp;
 
-	if (!memory_affinity->flags.enabled)
+	if ((memory_affinity->flags & ACPI_SRAT_MEM_ENABLED) == 0)
 		return;		/* empty entry */
 
+	pxm = memory_affinity->proximity_domain & 0xff;
+
 	/* mark this node as "seen" in node bitmap */
-	BMAP_SET(pxm_bitmap, memory_affinity->proximity_domain);
+	BMAP_SET(pxm_bitmap, pxm);
 
 	/* calculate info for memory chunk structure */
-	paddr = memory_affinity->base_addr_hi;
-	paddr = (paddr << 32) | memory_affinity->base_addr_lo;
-	size = memory_affinity->length_hi;
-	size = (size << 32) | memory_affinity->length_lo;
-	
+	paddr = memory_affinity->base_address;
+	size = memory_affinity->length;
+
 	start_pfn = paddr >> PAGE_SHIFT;
 	end_pfn = (paddr + size) >> PAGE_SHIFT;
-	
-	pxm = memory_affinity->proximity_domain;
+
 
 	if (num_memory_chunks >= MAXCHUNKS) {
 		printk("Too many mem chunks in SRAT. Ignoring %lld MBytes at %llx\n",
@@ -132,8 +131,8 @@
 	printk("Memory range 0x%lX to 0x%lX (type 0x%X) in proximity domain 0x%02X %s\n",
 		start_pfn, end_pfn,
 		memory_affinity->memory_type,
-		memory_affinity->proximity_domain,
-		(memory_affinity->flags.hot_pluggable ?
+		pxm,
+		((memory_affinity->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) ?
 		 "enabled and removable" : "enabled" ) );
 }
 
@@ -185,10 +184,10 @@
 	num_memory_chunks = 0;
 	while (p < end) {
 		switch (*p) {
-		case ACPI_SRAT_PROCESSOR_AFFINITY:
+		case ACPI_SRAT_TYPE_CPU_AFFINITY:
 			parse_cpu_affinity_structure(p);
 			break;
-		case ACPI_SRAT_MEMORY_AFFINITY:
+		case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
 			parse_memory_affinity_structure(p);
 			break;
 		default:
@@ -262,31 +261,30 @@
 	return 0;
 }
 
+struct acpi_static_rsdt {
+	struct acpi_table_rsdt table;
+	u32 padding[7]; /* Allow for 7 more table entries */
+};
+
 int __init get_memcfg_from_srat(void)
 {
 	struct acpi_table_header *header = NULL;
 	struct acpi_table_rsdp *rsdp = NULL;
 	struct acpi_table_rsdt *rsdt = NULL;
-	struct acpi_pointer *rsdp_address = NULL;
-	struct acpi_table_rsdt saved_rsdt;
+	acpi_native_uint rsdp_address = 0;
+	struct acpi_static_rsdt saved_rsdt;
 	int tables = 0;
 	int i = 0;
 
-	if (ACPI_FAILURE(acpi_find_root_pointer(ACPI_PHYSICAL_ADDRESSING,
-						rsdp_address))) {
+	rsdp_address = acpi_find_rsdp();
+	if (!rsdp_address) {
 		printk("%s: System description tables not found\n",
 		       __FUNCTION__);
 		goto out_err;
 	}
 
-	if (rsdp_address->pointer_type == ACPI_PHYSICAL_POINTER) {
-		printk("%s: assigning address to rsdp\n", __FUNCTION__);
-		rsdp = (struct acpi_table_rsdp *)
-				(u32)rsdp_address->pointer.physical;
-	} else {
-		printk("%s: rsdp_address is not a physical pointer\n", __FUNCTION__);
-		goto out_err;
-	}
+	printk("%s: assigning address to rsdp\n", __FUNCTION__);
+	rsdp = (struct acpi_table_rsdp *)(u32)rsdp_address;
 	if (!rsdp) {
 		printk("%s: Didn't find ACPI root!\n", __FUNCTION__);
 		goto out_err;
@@ -295,13 +293,13 @@
 	printk(KERN_INFO "%.8s v%d [%.6s]\n", rsdp->signature, rsdp->revision,
 		rsdp->oem_id);
 
-	if (strncmp(rsdp->signature, RSDP_SIG,strlen(RSDP_SIG))) {
+	if (strncmp(rsdp->signature, ACPI_SIG_RSDP,strlen(ACPI_SIG_RSDP))) {
 		printk(KERN_WARNING "%s: RSDP table signature incorrect\n", __FUNCTION__);
 		goto out_err;
 	}
 
 	rsdt = (struct acpi_table_rsdt *)
-	    boot_ioremap(rsdp->rsdt_address, sizeof(struct acpi_table_rsdt));
+	    boot_ioremap(rsdp->rsdt_physical_address, sizeof(struct acpi_table_rsdt));
 
 	if (!rsdt) {
 		printk(KERN_WARNING
@@ -310,9 +308,9 @@
 		goto out_err;
 	}
 
-	header = & rsdt->header;
+	header = &rsdt->header;
 
-	if (strncmp(header->signature, RSDT_SIG, strlen(RSDT_SIG))) {
+	if (strncmp(header->signature, ACPI_SIG_RSDT, strlen(ACPI_SIG_RSDT))) {
 		printk(KERN_WARNING "ACPI: RSDT signature incorrect\n");
 		goto out_err;
 	}
@@ -330,9 +328,9 @@
 
 	memcpy(&saved_rsdt, rsdt, sizeof(saved_rsdt));
 
-	if (saved_rsdt.header.length > sizeof(saved_rsdt)) {
+	if (saved_rsdt.table.header.length > sizeof(saved_rsdt)) {
 		printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n",
-		       saved_rsdt.header.length);
+		       saved_rsdt.table.header.length);
 		goto out_err;
 	}
 
@@ -341,15 +339,15 @@
 	for (i = 0; i < tables; i++) {
 		/* Map in header, then map in full table length. */
 		header = (struct acpi_table_header *)
-			boot_ioremap(saved_rsdt.entry[i], sizeof(struct acpi_table_header));
+			boot_ioremap(saved_rsdt.table.table_offset_entry[i], sizeof(struct acpi_table_header));
 		if (!header)
 			break;
 		header = (struct acpi_table_header *)
-			boot_ioremap(saved_rsdt.entry[i], header->length);
+			boot_ioremap(saved_rsdt.table.table_offset_entry[i], header->length);
 		if (!header)
 			break;
 
-		if (strncmp((char *) &header->signature, "SRAT", 4))
+		if (strncmp((char *) &header->signature, ACPI_SIG_SRAT, 4))
 			continue;
 
 		/* we've found the srat table. don't need to look at any more tables */
diff --git a/arch/i386/kernel/sysenter.c b/arch/i386/kernel/sysenter.c
index 5da7442..bc882a2 100644
--- a/arch/i386/kernel/sysenter.c
+++ b/arch/i386/kernel/sysenter.c
@@ -70,11 +70,12 @@
  */
 extern const char vsyscall_int80_start, vsyscall_int80_end;
 extern const char vsyscall_sysenter_start, vsyscall_sysenter_end;
-static void *syscall_page;
+static struct page *syscall_pages[1];
 
 int __init sysenter_setup(void)
 {
-	syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
+	void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
+	syscall_pages[0] = virt_to_page(syscall_page);
 
 #ifdef CONFIG_COMPAT_VDSO
 	__set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_READONLY);
@@ -96,31 +97,12 @@
 }
 
 #ifndef CONFIG_COMPAT_VDSO
-static struct page *syscall_nopage(struct vm_area_struct *vma,
-				unsigned long adr, int *type)
-{
-	struct page *p = virt_to_page(adr - vma->vm_start + syscall_page);
-	get_page(p);
-	return p;
-}
-
-/* Prevent VMA merging */
-static void syscall_vma_close(struct vm_area_struct *vma)
-{
-}
-
-static struct vm_operations_struct syscall_vm_ops = {
-	.close = syscall_vma_close,
-	.nopage = syscall_nopage,
-};
-
 /* Defined in vsyscall-sysenter.S */
 extern void SYSENTER_RETURN;
 
 /* Setup a VMA at program startup for the vsyscall page */
 int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack)
 {
-	struct vm_area_struct *vma;
 	struct mm_struct *mm = current->mm;
 	unsigned long addr;
 	int ret;
@@ -132,38 +114,25 @@
 		goto up_fail;
 	}
 
-	vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
-	if (!vma) {
-		ret = -ENOMEM;
-		goto up_fail;
-	}
-
-	vma->vm_start = addr;
-	vma->vm_end = addr + PAGE_SIZE;
-	/* MAYWRITE to allow gdb to COW and set breakpoints */
-	vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE;
 	/*
+	 * MAYWRITE to allow gdb to COW and set breakpoints
+	 *
 	 * Make sure the vDSO gets into every core dump.
 	 * Dumping its contents makes post-mortem fully interpretable later
 	 * without matching up the same kernel and hardware config to see
 	 * what PC values meant.
 	 */
-	vma->vm_flags |= VM_ALWAYSDUMP;
-	vma->vm_flags |= mm->def_flags;
-	vma->vm_page_prot = protection_map[vma->vm_flags & 7];
-	vma->vm_ops = &syscall_vm_ops;
-	vma->vm_mm = mm;
-
-	ret = insert_vm_struct(mm, vma);
-	if (unlikely(ret)) {
-		kmem_cache_free(vm_area_cachep, vma);
+	ret = install_special_mapping(mm, addr, PAGE_SIZE,
+				      VM_READ|VM_EXEC|
+				      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
+				      VM_ALWAYSDUMP,
+				      syscall_pages);
+	if (ret)
 		goto up_fail;
-	}
 
 	current->mm->context.vdso = (void *)addr;
 	current_thread_info()->sysenter_return =
 				    (void *)VDSO_SYM(&SYSENTER_RETURN);
-	mm->total_vm++;
 up_fail:
 	up_write(&mm->mmap_sem);
 	return ret;
diff --git a/arch/i386/mach-es7000/es7000.h b/arch/i386/mach-es7000/es7000.h
index 80566ca..c8d5aa1 100644
--- a/arch/i386/mach-es7000/es7000.h
+++ b/arch/i386/mach-es7000/es7000.h
@@ -84,15 +84,6 @@
 };
 
 #ifdef CONFIG_ACPI
-struct acpi_table_sdt {
-	unsigned long pa;
-	unsigned long count;
-	struct {
-		unsigned long pa;
-		enum acpi_table_id id;
-		unsigned long size;
-	}	entry[50];
-};
 
 struct oem_table {
 	struct acpi_table_header Header;
diff --git a/arch/i386/mach-es7000/es7000plat.c b/arch/i386/mach-es7000/es7000plat.c
index 3d0fc85..9be6cea 100644
--- a/arch/i386/mach-es7000/es7000plat.c
+++ b/arch/i386/mach-es7000/es7000plat.c
@@ -160,51 +160,14 @@
 int __init
 find_unisys_acpi_oem_table(unsigned long *oem_addr)
 {
-	struct acpi_table_rsdp		*rsdp = NULL;
-	unsigned long			rsdp_phys = 0;
-	struct acpi_table_header 	*header = NULL;
-	int				i;
-	struct acpi_table_sdt		sdt;
-
-	rsdp_phys = acpi_find_rsdp();
-	rsdp = __va(rsdp_phys);
-	if (rsdp->rsdt_address) {
-		struct acpi_table_rsdt	*mapped_rsdt = NULL;
-		sdt.pa = rsdp->rsdt_address;
-
-		header = (struct acpi_table_header *)
-			__acpi_map_table(sdt.pa, sizeof(struct acpi_table_header));
-		if (!header)
-			return -ENODEV;
-
-		sdt.count = (header->length - sizeof(struct acpi_table_header)) >> 3;
-		mapped_rsdt = (struct acpi_table_rsdt *)
-			__acpi_map_table(sdt.pa, header->length);
-		if (!mapped_rsdt)
-			return -ENODEV;
-
-		header = &mapped_rsdt->header;
-
-		for (i = 0; i < sdt.count; i++)
-			sdt.entry[i].pa = (unsigned long) mapped_rsdt->entry[i];
-	};
-	for (i = 0; i < sdt.count; i++) {
-
-		header = (struct acpi_table_header *)
-			__acpi_map_table(sdt.entry[i].pa,
-				sizeof(struct acpi_table_header));
-		if (!header)
-			continue;
-		if (!strncmp((char *) &header->signature, "OEM1", 4)) {
-			if (!strncmp((char *) &header->oem_id, "UNISYS", 6)) {
-				void *addr;
-				struct oem_table *t;
-				acpi_table_print(header, sdt.entry[i].pa);
-				t = (struct oem_table *) __acpi_map_table(sdt.entry[i].pa, header->length);
-				addr = (void *) __acpi_map_table(t->OEMTableAddr, t->OEMTableSize);
-				*oem_addr = (unsigned long) addr;
-				return 0;
-			}
+	struct acpi_table_header *header = NULL;
+	int i = 0;
+	while (ACPI_SUCCESS(acpi_get_table("OEM1", i++, &header))) {
+		if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) {
+			struct oem_table *t = (struct oem_table *)header;
+			*oem_addr = (unsigned long)__acpi_map_table(t->OEMTableAddr,
+								    t->OEMTableSize);
+			return 0;
 		}
 	}
 	return -1;
diff --git a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr.c
index ad91528..e223b1d 100644
--- a/arch/i386/mm/pageattr.c
+++ b/arch/i386/mm/pageattr.c
@@ -224,7 +224,7 @@
 	list_replace_init(&df_list, &l);
 	spin_unlock_irq(&cpa_lock);
 	if (!cpu_has_clflush)
-		flush_map(0);
+		flush_map(NULL);
 	list_for_each_entry_safe(pg, next, &l, lru) {
 		if (cpu_has_clflush)
 			flush_map(page_address(pg));
diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c
index e2616a2..5700220 100644
--- a/arch/i386/pci/mmconfig.c
+++ b/arch/i386/pci/mmconfig.c
@@ -36,7 +36,7 @@
 static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
 {
 	int cfg_num = -1;
-	struct acpi_table_mcfg_config *cfg;
+	struct acpi_mcfg_allocation *cfg;
 
 	if (seg == 0 && bus < MAX_CHECK_BUS &&
 	    test_bit(PCI_SLOT(devfn) + 32*bus, fallback_slots))
@@ -48,11 +48,11 @@
 			break;
 		}
 		cfg = &pci_mmcfg_config[cfg_num];
-		if (cfg->pci_segment_group_number != seg)
+		if (cfg->pci_segment != seg)
 			continue;
 		if ((cfg->start_bus_number <= bus) &&
 		    (cfg->end_bus_number >= bus))
-			return cfg->base_address;
+			return cfg->address;
 	}
 
 	/* Handle more broken MCFG tables on Asus etc.
@@ -60,9 +60,9 @@
  	   this applies to all busses. */
 	cfg = &pci_mmcfg_config[0];
 	if (pci_mmcfg_config_num == 1 &&
-		cfg->pci_segment_group_number == 0 &&
+		cfg->pci_segment == 0 &&
 		(cfg->start_bus_number | cfg->end_bus_number) == 0)
-		return cfg->base_address;
+		return cfg->address;
 
 	/* Fall back to type 0 */
 	return 0;
@@ -125,7 +125,7 @@
 	unsigned long flags;
 	u32 base;
 
-	if ((bus > 255) || (devfn > 255) || (reg > 4095)) 
+	if ((bus > 255) || (devfn > 255) || (reg > 4095))
 		return -EINVAL;
 
 	base = get_base_addr(seg, bus, devfn);
@@ -199,19 +199,19 @@
 	if ((pci_probe & PCI_PROBE_MMCONF) == 0)
 		return;
 
-	acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+	acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
 	if ((pci_mmcfg_config_num == 0) ||
 	    (pci_mmcfg_config == NULL) ||
-	    (pci_mmcfg_config[0].base_address == 0))
+	    (pci_mmcfg_config[0].address == 0))
 		return;
 
 	/* Only do this check when type 1 works. If it doesn't work
 	   assume we run on a Mac and always use MCFG */
-	if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].base_address,
-			pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
+	if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].address,
+			pci_mmcfg_config[0].address + MMCONFIG_APER_MIN,
 			E820_RESERVED)) {
-		printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n",
-				pci_mmcfg_config[0].base_address);
+		printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %lx is not E820-reserved\n",
+				(unsigned long)pci_mmcfg_config[0].address);
 		printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
 		return;
 	}
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index fcacfe2..f1d2899 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -11,6 +11,8 @@
 
 config IA64
 	bool
+	select PCI if (!IA64_HP_SIM)
+	select ACPI if (!IA64_HP_SIM)
 	default y
 	help
 	  The Itanium Processor Family is Intel's 64-bit successor to
@@ -28,7 +30,6 @@
 
 config SWIOTLB
        bool
-       default y
 
 config RWSEM_XCHGADD_ALGORITHM
 	bool
@@ -84,10 +85,9 @@
 
 config IA64_GENERIC
 	bool "generic"
-	select ACPI
-	select PCI
 	select NUMA
 	select ACPI_NUMA
+	select SWIOTLB
 	help
 	  This selects the system type of your hardware.  A "generic" kernel
 	  will run on any supported IA-64 system.  However, if you configure
@@ -104,6 +104,7 @@
 
 config IA64_DIG
 	bool "DIG-compliant"
+	select SWIOTLB
 
 config IA64_HP_ZX1
 	bool "HP-zx1/sx1000"
@@ -113,6 +114,7 @@
 
 config IA64_HP_ZX1_SWIOTLB
 	bool "HP-zx1/sx1000 with software I/O TLB"
+	select SWIOTLB
 	help
 	  Build a kernel that runs on HP zx1 and sx1000 systems even when they
 	  have broken PCI devices which cannot DMA to full 32 bits.  Apart
@@ -131,6 +133,7 @@
 
 config IA64_HP_SIM
 	bool "Ski-simulator"
+	select SWIOTLB
 
 endchoice
 
diff --git a/arch/ia64/hp/common/hwsw_iommu.c b/arch/ia64/hp/common/hwsw_iommu.c
index a5a5637..2153bca 100644
--- a/arch/ia64/hp/common/hwsw_iommu.c
+++ b/arch/ia64/hp/common/hwsw_iommu.c
@@ -192,3 +192,7 @@
 EXPORT_SYMBOL(hwsw_dma_supported);
 EXPORT_SYMBOL(hwsw_alloc_coherent);
 EXPORT_SYMBOL(hwsw_free_coherent);
+EXPORT_SYMBOL(hwsw_sync_single_for_cpu);
+EXPORT_SYMBOL(hwsw_sync_single_for_device);
+EXPORT_SYMBOL(hwsw_sync_sg_for_cpu);
+EXPORT_SYMBOL(hwsw_sync_sg_for_device);
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index 29f05d4..9197d7b 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -55,7 +55,7 @@
 
 #define BAD_MADT_ENTRY(entry, end) (                                        \
 		(!entry) || (unsigned long)entry + sizeof(*entry) > end ||  \
-		((acpi_table_entry_header *)entry)->length < sizeof(*entry))
+		((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
 
 #define PREFIX			"ACPI: "
 
@@ -67,16 +67,11 @@
 unsigned int acpi_cpei_override;
 unsigned int acpi_cpei_phys_cpuid;
 
-#define MAX_SAPICS 256
-u16 ia64_acpiid_to_sapicid[MAX_SAPICS] = {[0 ... MAX_SAPICS - 1] = -1 };
-
-EXPORT_SYMBOL(ia64_acpiid_to_sapicid);
-
 const char *acpi_get_sysname(void)
 {
 #ifdef CONFIG_IA64_GENERIC
 	unsigned long rsdp_phys;
-	struct acpi20_table_rsdp *rsdp;
+	struct acpi_table_rsdp *rsdp;
 	struct acpi_table_xsdt *xsdt;
 	struct acpi_table_header *hdr;
 
@@ -87,16 +82,16 @@
 		return "dig";
 	}
 
-	rsdp = (struct acpi20_table_rsdp *)__va(rsdp_phys);
-	if (strncmp(rsdp->signature, RSDP_SIG, sizeof(RSDP_SIG) - 1)) {
+	rsdp = (struct acpi_table_rsdp *)__va(rsdp_phys);
+	if (strncmp(rsdp->signature, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1)) {
 		printk(KERN_ERR
 		       "ACPI 2.0 RSDP signature incorrect, default to \"dig\"\n");
 		return "dig";
 	}
 
-	xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_address);
+	xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_physical_address);
 	hdr = &xsdt->header;
-	if (strncmp(hdr->signature, XSDT_SIG, sizeof(XSDT_SIG) - 1)) {
+	if (strncmp(hdr->signature, ACPI_SIG_XSDT, sizeof(ACPI_SIG_XSDT) - 1)) {
 		printk(KERN_ERR
 		       "ACPI 2.0 XSDT signature incorrect, default to \"dig\"\n");
 		return "dig";
@@ -169,12 +164,12 @@
 static u8 has_8259;
 
 static int __init
-acpi_parse_lapic_addr_ovr(acpi_table_entry_header * header,
+acpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header,
 			  const unsigned long end)
 {
-	struct acpi_table_lapic_addr_ovr *lapic;
+	struct acpi_madt_local_apic_override *lapic;
 
-	lapic = (struct acpi_table_lapic_addr_ovr *)header;
+	lapic = (struct acpi_madt_local_apic_override *)header;
 
 	if (BAD_MADT_ENTRY(lapic, end))
 		return -EINVAL;
@@ -187,22 +182,19 @@
 }
 
 static int __init
-acpi_parse_lsapic(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_lsapic(struct acpi_subtable_header * header, const unsigned long end)
 {
-	struct acpi_table_lsapic *lsapic;
+	struct acpi_madt_local_sapic *lsapic;
 
-	lsapic = (struct acpi_table_lsapic *)header;
+	lsapic = (struct acpi_madt_local_sapic *)header;
 
-	if (BAD_MADT_ENTRY(lsapic, end))
-		return -EINVAL;
+	/*Skip BAD_MADT_ENTRY check, as lsapic size could vary */
 
-	if (lsapic->flags.enabled) {
+	if (lsapic->lapic_flags & ACPI_MADT_ENABLED) {
 #ifdef CONFIG_SMP
 		smp_boot_data.cpu_phys_id[available_cpus] =
 		    (lsapic->id << 8) | lsapic->eid;
 #endif
-		ia64_acpiid_to_sapicid[lsapic->acpi_id] =
-		    (lsapic->id << 8) | lsapic->eid;
 		++available_cpus;
 	}
 
@@ -211,11 +203,11 @@
 }
 
 static int __init
-acpi_parse_lapic_nmi(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end)
 {
-	struct acpi_table_lapic_nmi *lacpi_nmi;
+	struct acpi_madt_local_apic_nmi *lacpi_nmi;
 
-	lacpi_nmi = (struct acpi_table_lapic_nmi *)header;
+	lacpi_nmi = (struct acpi_madt_local_apic_nmi *)header;
 
 	if (BAD_MADT_ENTRY(lacpi_nmi, end))
 		return -EINVAL;
@@ -225,11 +217,11 @@
 }
 
 static int __init
-acpi_parse_iosapic(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_iosapic(struct acpi_subtable_header * header, const unsigned long end)
 {
-	struct acpi_table_iosapic *iosapic;
+	struct acpi_madt_io_sapic *iosapic;
 
-	iosapic = (struct acpi_table_iosapic *)header;
+	iosapic = (struct acpi_madt_io_sapic *)header;
 
 	if (BAD_MADT_ENTRY(iosapic, end))
 		return -EINVAL;
@@ -240,13 +232,13 @@
 static unsigned int __initdata acpi_madt_rev;
 
 static int __init
-acpi_parse_plat_int_src(acpi_table_entry_header * header,
+acpi_parse_plat_int_src(struct acpi_subtable_header * header,
 			const unsigned long end)
 {
-	struct acpi_table_plat_int_src *plintsrc;
+	struct acpi_madt_interrupt_source *plintsrc;
 	int vector;
 
-	plintsrc = (struct acpi_table_plat_int_src *)header;
+	plintsrc = (struct acpi_madt_interrupt_source *)header;
 
 	if (BAD_MADT_ENTRY(plintsrc, end))
 		return -EINVAL;
@@ -257,19 +249,19 @@
 	 */
 	vector = iosapic_register_platform_intr(plintsrc->type,
 						plintsrc->global_irq,
-						plintsrc->iosapic_vector,
+						plintsrc->io_sapic_vector,
 						plintsrc->eid,
 						plintsrc->id,
-						(plintsrc->flags.polarity ==
-						 1) ? IOSAPIC_POL_HIGH :
-						IOSAPIC_POL_LOW,
-						(plintsrc->flags.trigger ==
-						 1) ? IOSAPIC_EDGE :
-						IOSAPIC_LEVEL);
+						((plintsrc->inti_flags & ACPI_MADT_POLARITY_MASK) ==
+						 ACPI_MADT_POLARITY_ACTIVE_HIGH) ?
+						IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
+						((plintsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) ==
+						 ACPI_MADT_TRIGGER_EDGE) ?
+						IOSAPIC_EDGE : IOSAPIC_LEVEL);
 
 	platform_intr_list[plintsrc->type] = vector;
 	if (acpi_madt_rev > 1) {
-		acpi_cpei_override = plintsrc->plint_flags.cpei_override_flag;
+		acpi_cpei_override = plintsrc->flags & ACPI_MADT_CPEI_OVERRIDE;
 	}
 
 	/*
@@ -324,30 +316,32 @@
 }
 
 static int __init
-acpi_parse_int_src_ovr(acpi_table_entry_header * header,
+acpi_parse_int_src_ovr(struct acpi_subtable_header * header,
 		       const unsigned long end)
 {
-	struct acpi_table_int_src_ovr *p;
+	struct acpi_madt_interrupt_override *p;
 
-	p = (struct acpi_table_int_src_ovr *)header;
+	p = (struct acpi_madt_interrupt_override *)header;
 
 	if (BAD_MADT_ENTRY(p, end))
 		return -EINVAL;
 
-	iosapic_override_isa_irq(p->bus_irq, p->global_irq,
-				 (p->flags.polarity ==
-				  1) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
-				 (p->flags.trigger ==
-				  1) ? IOSAPIC_EDGE : IOSAPIC_LEVEL);
+	iosapic_override_isa_irq(p->source_irq, p->global_irq,
+				 ((p->inti_flags & ACPI_MADT_POLARITY_MASK) ==
+				  ACPI_MADT_POLARITY_ACTIVE_HIGH) ?
+				 IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
+				 ((p->inti_flags & ACPI_MADT_TRIGGER_MASK) ==
+				 ACPI_MADT_TRIGGER_EDGE) ?
+				 IOSAPIC_EDGE : IOSAPIC_LEVEL);
 	return 0;
 }
 
 static int __init
-acpi_parse_nmi_src(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_nmi_src(struct acpi_subtable_header * header, const unsigned long end)
 {
-	struct acpi_table_nmi_src *nmi_src;
+	struct acpi_madt_nmi_source *nmi_src;
 
-	nmi_src = (struct acpi_table_nmi_src *)header;
+	nmi_src = (struct acpi_madt_nmi_source *)header;
 
 	if (BAD_MADT_ENTRY(nmi_src, end))
 		return -EINVAL;
@@ -371,12 +365,12 @@
 	}
 }
 
-static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_madt(struct acpi_table_header *table)
 {
-	if (!phys_addr || !size)
+	if (!table)
 		return -EINVAL;
 
-	acpi_madt = (struct acpi_table_madt *)__va(phys_addr);
+	acpi_madt = (struct acpi_table_madt *)table;
 
 	acpi_madt_rev = acpi_madt->header.revision;
 
@@ -384,14 +378,14 @@
 #ifdef CONFIG_ITANIUM
 	has_8259 = 1;		/* Firmware on old Itanium systems is broken */
 #else
-	has_8259 = acpi_madt->flags.pcat_compat;
+	has_8259 = acpi_madt->flags & ACPI_MADT_PCAT_COMPAT;
 #endif
 	iosapic_system_init(has_8259);
 
 	/* Get base address of IPI Message Block */
 
-	if (acpi_madt->lapic_address)
-		ipi_base_addr = ioremap(acpi_madt->lapic_address, 0);
+	if (acpi_madt->address)
+		ipi_base_addr = ioremap(acpi_madt->address, 0);
 
 	printk(KERN_INFO PREFIX "Local APIC address %p\n", ipi_base_addr);
 
@@ -413,23 +407,24 @@
 #define pxm_bit_test(bit)	(test_bit(bit,(void *)pxm_flag))
 static struct acpi_table_slit __initdata *slit_table;
 
-static int get_processor_proximity_domain(struct acpi_table_processor_affinity *pa)
+static int get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa)
 {
 	int pxm;
 
-	pxm = pa->proximity_domain;
+	pxm = pa->proximity_domain_lo;
 	if (ia64_platform_is("sn2"))
-		pxm += pa->reserved[0] << 8;
+		pxm += pa->proximity_domain_hi[0] << 8;
 	return pxm;
 }
 
-static int get_memory_proximity_domain(struct acpi_table_memory_affinity *ma)
+static int get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma)
 {
 	int pxm;
 
 	pxm = ma->proximity_domain;
-	if (ia64_platform_is("sn2"))
-		pxm += ma->reserved1[0] << 8;
+	if (!ia64_platform_is("sn2"))
+		pxm &= 0xff;
+
 	return pxm;
 }
 
@@ -442,7 +437,7 @@
 	u32 len;
 
 	len = sizeof(struct acpi_table_header) + 8
-	    + slit->localities * slit->localities;
+	    + slit->locality_count * slit->locality_count;
 	if (slit->header.length != len) {
 		printk(KERN_ERR
 		       "ACPI 2.0 SLIT: size mismatch: %d expected, %d actual\n",
@@ -454,11 +449,11 @@
 }
 
 void __init
-acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa)
+acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
 {
 	int pxm;
 
-	if (!pa->flags.enabled)
+	if (!(pa->flags & ACPI_SRAT_CPU_ENABLED))
 		return;
 
 	pxm = get_processor_proximity_domain(pa);
@@ -467,14 +462,14 @@
 	pxm_bit_set(pxm);
 
 	node_cpuid[srat_num_cpus].phys_id =
-	    (pa->apic_id << 8) | (pa->lsapic_eid);
+	    (pa->apic_id << 8) | (pa->local_sapic_eid);
 	/* nid should be overridden as logical node id later */
 	node_cpuid[srat_num_cpus].nid = pxm;
 	srat_num_cpus++;
 }
 
 void __init
-acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
+acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
 {
 	unsigned long paddr, size;
 	int pxm;
@@ -483,13 +478,11 @@
 	pxm = get_memory_proximity_domain(ma);
 
 	/* fill node memory chunk structure */
-	paddr = ma->base_addr_hi;
-	paddr = (paddr << 32) | ma->base_addr_lo;
-	size = ma->length_hi;
-	size = (size << 32) | ma->length_lo;
+	paddr = ma->base_address;
+	size = ma->length;
 
 	/* Ignore disabled entries */
-	if (!ma->flags.enabled)
+	if (!(ma->flags & ACPI_SRAT_MEM_ENABLED))
 		return;
 
 	/* record this node in proximity bitmap */
@@ -560,16 +553,16 @@
 	if (!slit_table)
 		return;
 	memset(numa_slit, -1, sizeof(numa_slit));
-	for (i = 0; i < slit_table->localities; i++) {
+	for (i = 0; i < slit_table->locality_count; i++) {
 		if (!pxm_bit_test(i))
 			continue;
 		node_from = pxm_to_node(i);
-		for (j = 0; j < slit_table->localities; j++) {
+		for (j = 0; j < slit_table->locality_count; j++) {
 			if (!pxm_bit_test(j))
 				continue;
 			node_to = pxm_to_node(j);
 			node_distance(node_from, node_to) =
-			    slit_table->entry[i * slit_table->localities + j];
+			    slit_table->entry[i * slit_table->locality_count + j];
 		}
 	}
 
@@ -617,21 +610,21 @@
 
 EXPORT_SYMBOL(acpi_unregister_gsi);
 
-static int __init acpi_parse_fadt(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_fadt(struct acpi_table_header *table)
 {
 	struct acpi_table_header *fadt_header;
-	struct fadt_descriptor *fadt;
+	struct acpi_table_fadt *fadt;
 
-	if (!phys_addr || !size)
+	if (!table)
 		return -EINVAL;
 
-	fadt_header = (struct acpi_table_header *)__va(phys_addr);
+	fadt_header = (struct acpi_table_header *)table;
 	if (fadt_header->revision != 3)
 		return -ENODEV;	/* Only deal with ACPI 2.0 FADT */
 
-	fadt = (struct fadt_descriptor *)fadt_header;
+	fadt = (struct acpi_table_fadt *)fadt_header;
 
-	acpi_register_gsi(fadt->sci_int, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
+	acpi_register_gsi(fadt->sci_interrupt, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
 	return 0;
 }
 
@@ -658,7 +651,7 @@
 	 * information -- the successor to MPS tables.
 	 */
 
-	if (acpi_table_parse(ACPI_APIC, acpi_parse_madt) < 1) {
+	if (acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt) < 1) {
 		printk(KERN_ERR PREFIX "Can't find MADT\n");
 		goto skip_madt;
 	}
@@ -666,40 +659,40 @@
 	/* Local APIC */
 
 	if (acpi_table_parse_madt
-	    (ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0) < 0)
+	    (ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE, acpi_parse_lapic_addr_ovr, 0) < 0)
 		printk(KERN_ERR PREFIX
 		       "Error parsing LAPIC address override entry\n");
 
-	if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_parse_lsapic, NR_CPUS)
+	if (acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_SAPIC, acpi_parse_lsapic, NR_CPUS)
 	    < 1)
 		printk(KERN_ERR PREFIX
 		       "Error parsing MADT - no LAPIC entries\n");
 
-	if (acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0)
+	if (acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0)
 	    < 0)
 		printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
 
 	/* I/O APIC */
 
 	if (acpi_table_parse_madt
-	    (ACPI_MADT_IOSAPIC, acpi_parse_iosapic, NR_IOSAPICS) < 1)
+	    (ACPI_MADT_TYPE_IO_SAPIC, acpi_parse_iosapic, NR_IOSAPICS) < 1)
 		printk(KERN_ERR PREFIX
 		       "Error parsing MADT - no IOSAPIC entries\n");
 
 	/* System-Level Interrupt Routing */
 
 	if (acpi_table_parse_madt
-	    (ACPI_MADT_PLAT_INT_SRC, acpi_parse_plat_int_src,
+	    (ACPI_MADT_TYPE_INTERRUPT_SOURCE, acpi_parse_plat_int_src,
 	     ACPI_MAX_PLATFORM_INTERRUPTS) < 0)
 		printk(KERN_ERR PREFIX
 		       "Error parsing platform interrupt source entry\n");
 
 	if (acpi_table_parse_madt
-	    (ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, 0) < 0)
+	    (ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, acpi_parse_int_src_ovr, 0) < 0)
 		printk(KERN_ERR PREFIX
 		       "Error parsing interrupt source overrides entry\n");
 
-	if (acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, 0) < 0)
+	if (acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_parse_nmi_src, 0) < 0)
 		printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
       skip_madt:
 
@@ -709,7 +702,7 @@
 	 * gets interrupts such as power and sleep buttons.  If it's not
 	 * on a Legacy interrupt, it needs to be setup.
 	 */
-	if (acpi_table_parse(ACPI_FADT, acpi_parse_fadt) < 1)
+	if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt) < 1)
 		printk(KERN_ERR PREFIX "Can't find FADT\n");
 
 #ifdef CONFIG_SMP
@@ -842,7 +835,7 @@
 {
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 	union acpi_object *obj;
-	struct acpi_table_lsapic *lsapic;
+	struct acpi_madt_local_sapic *lsapic;
 	cpumask_t tmp_map;
 	long physid;
 	int cpu;
@@ -854,16 +847,16 @@
 		return -EINVAL;
 
 	obj = buffer.pointer;
-	if (obj->type != ACPI_TYPE_BUFFER ||
-	    obj->buffer.length < sizeof(*lsapic)) {
+	if (obj->type != ACPI_TYPE_BUFFER)
+	{
 		kfree(buffer.pointer);
 		return -EINVAL;
 	}
 
-	lsapic = (struct acpi_table_lsapic *)obj->buffer.pointer;
+	lsapic = (struct acpi_madt_local_sapic *)obj->buffer.pointer;
 
-	if ((lsapic->header.type != ACPI_MADT_LSAPIC) ||
-	    (!lsapic->flags.enabled)) {
+	if ((lsapic->header.type != ACPI_MADT_TYPE_LOCAL_SAPIC) ||
+	    (!lsapic->lapic_flags & ACPI_MADT_ENABLED)) {
 		kfree(buffer.pointer);
 		return -EINVAL;
 	}
@@ -883,7 +876,6 @@
 
 	cpu_set(cpu, cpu_present_map);
 	ia64_cpu_to_sapicid[cpu] = physid;
-	ia64_acpiid_to_sapicid[lsapic->acpi_id] = ia64_cpu_to_sapicid[cpu];
 
 	*pcpu = cpu;
 	return (0);
@@ -893,14 +885,6 @@
 
 int acpi_unmap_lsapic(int cpu)
 {
-	int i;
-
-	for (i = 0; i < MAX_SAPICS; i++) {
-		if (ia64_acpiid_to_sapicid[i] == ia64_cpu_to_sapicid[cpu]) {
-			ia64_acpiid_to_sapicid[i] = -1;
-			break;
-		}
-	}
 	ia64_cpu_to_sapicid[cpu] = -1;
 	cpu_clear(cpu, cpu_present_map);
 
@@ -920,7 +904,7 @@
 {
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 	union acpi_object *obj;
-	struct acpi_table_iosapic *iosapic;
+	struct acpi_madt_io_sapic *iosapic;
 	unsigned int gsi_base;
 	int pxm, node;
 
@@ -938,9 +922,9 @@
 		return AE_OK;
 	}
 
-	iosapic = (struct acpi_table_iosapic *)obj->buffer.pointer;
+	iosapic = (struct acpi_madt_io_sapic *)obj->buffer.pointer;
 
-	if (iosapic->header.type != ACPI_MADT_IOSAPIC) {
+	if (iosapic->header.type != ACPI_MADT_TYPE_IO_SAPIC) {
 		kfree(buffer.pointer);
 		return AE_OK;
 	}
diff --git a/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c
index bc2f64d..37bb16f 100644
--- a/arch/ia64/kernel/crash.c
+++ b/arch/ia64/kernel/crash.c
@@ -52,7 +52,7 @@
 static DEFINE_PER_CPU(struct elf_prstatus, elf_prstatus);
 
 void
-crash_save_this_cpu()
+crash_save_this_cpu(void)
 {
 	void *buf;
 	unsigned long cfm, sof, sol;
@@ -79,6 +79,7 @@
 	final_note(buf);
 }
 
+#ifdef CONFIG_SMP
 static int
 kdump_wait_cpu_freeze(void)
 {
@@ -91,6 +92,7 @@
 	}
 	return 1;
 }
+#endif
 
 void
 machine_crash_shutdown(struct pt_regs *pt)
@@ -116,6 +118,11 @@
 static void
 machine_kdump_on_init(void)
 {
+	if (!ia64_kimage) {
+		printk(KERN_NOTICE "machine_kdump_on_init(): "
+				"kdump not configured\n");
+		return;
+	}
 	local_irq_disable();
 	kexec_disable_iosapic();
 	machine_kexec(ia64_kimage);
@@ -132,11 +139,12 @@
 	atomic_inc(&kdump_cpu_freezed);
 	kdump_status[cpuid] = 1;
 	mb();
-	if (cpuid == 0) {
-		for (;;)
-			cpu_relax();
-	} else
+#ifdef CONFIG_HOTPLUG_CPU
+	if (cpuid != 0)
 		ia64_jump_to_sal(&sal_boot_rendez_state[cpuid]);
+#endif
+	for (;;)
+		cpu_relax();
 }
 
 static int
diff --git a/arch/ia64/kernel/crash_dump.c b/arch/ia64/kernel/crash_dump.c
index 83b8c91..da60e90 100644
--- a/arch/ia64/kernel/crash_dump.c
+++ b/arch/ia64/kernel/crash_dump.c
@@ -9,7 +9,8 @@
 #include <linux/errno.h>
 #include <linux/types.h>
 
-#include <linux/uaccess.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
 
 /**
  * copy_oldmem_page - copy one page from "oldmem"
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index 0b25a7d..6c03928 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -380,7 +380,7 @@
 #endif
 		return __va(md->phys_addr);
 	}
-	printk(KERN_WARNING "%s: no PAL-code memory-descriptor found",
+	printk(KERN_WARNING "%s: no PAL-code memory-descriptor found\n",
 	       __FUNCTION__);
 	return NULL;
 }
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index 15234ed..e7873ee 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1610,5 +1610,7 @@
 	data8 sys_sync_file_range		// 1300
 	data8 sys_tee
 	data8 sys_vmsplice
+	data8 sys_ni_syscall			// reserved for move_pages
+	data8 sys_getcpu
 
 	.org sys_call_table + 8*NR_syscalls	// guard against failures to increase NR_syscalls
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index 0fc5fb7..d6aab40 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -925,6 +925,11 @@
 			/* Clear the interrupt controller descriptor */
 			idesc->chip = &no_irq_type;
 
+#ifdef CONFIG_SMP
+			/* Clear affinity */
+			cpus_setall(idesc->affinity);
+#endif
+
 			/* Clear the interrupt information */
 			memset(&iosapic_intr_info[vector], 0,
 			       sizeof(struct iosapic_intr_info));
diff --git a/arch/ia64/kernel/machine_kexec.c b/arch/ia64/kernel/machine_kexec.c
index e2ccc9f..4f0f3b8 100644
--- a/arch/ia64/kernel/machine_kexec.c
+++ b/arch/ia64/kernel/machine_kexec.c
@@ -14,6 +14,7 @@
 #include <linux/kexec.h>
 #include <linux/cpu.h>
 #include <linux/irq.h>
+#include <linux/efi.h>
 #include <asm/mmu_context.h>
 #include <asm/setup.h>
 #include <asm/delay.h>
@@ -68,22 +69,10 @@
 {
 }
 
-void machine_shutdown(void)
-{
-	int cpu;
-
-	for_each_online_cpu(cpu) {
-		if (cpu != smp_processor_id())
-			cpu_down(cpu);
-	}
-	kexec_disable_iosapic();
-}
-
 /*
  * Do not allocate memory (or fail in any way) in machine_kexec().
  * We are past the point of no return, committed to rebooting now.
  */
-extern void *efi_get_pal_addr(void);
 static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
 {
 	struct kimage *image = arg;
@@ -93,6 +82,7 @@
 	unsigned long vector;
 	int ii;
 
+	BUG_ON(!image);
 	if (image->type == KEXEC_TYPE_CRASH) {
 		crash_save_this_cpu();
 		current->thread.ksp = (__u64)info->sw - 16;
@@ -131,6 +121,7 @@
 
 void machine_kexec(struct kimage *image)
 {
+	BUG_ON(!image);
 	unw_init_running(ia64_machine_kexec, image);
 	for(;;);
 }
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c
index 822e59a..0d05450 100644
--- a/arch/ia64/kernel/msi_ia64.c
+++ b/arch/ia64/kernel/msi_ia64.c
@@ -64,12 +64,17 @@
 }
 #endif /* CONFIG_SMP */
 
-int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
 {
 	struct msi_msg	msg;
 	unsigned long	dest_phys_id;
-	unsigned int	vector;
+	unsigned int	irq, vector;
 
+	irq = create_irq();
+	if (irq < 0)
+		return irq;
+
+	set_irq_msi(irq, desc);
 	dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
 	vector = irq;
 
@@ -89,12 +94,12 @@
 	write_msi_msg(irq, &msg);
 	set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);
 
-	return 0;
+	return irq;
 }
 
 void ia64_teardown_msi_irq(unsigned int irq)
 {
-	return;		/* no-op */
+	destroy_irq(irq);
 }
 
 static void ia64_ack_msi_irq(unsigned int irq)
@@ -126,12 +131,12 @@
 };
 
 
-int arch_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
 {
 	if (platform_setup_msi_irq)
-		return platform_setup_msi_irq(irq, pdev);
+		return platform_setup_msi_irq(pdev, desc);
 
-	return ia64_setup_msi_irq(irq, pdev);
+	return ia64_setup_msi_irq(pdev, desc);
 }
 
 void arch_teardown_msi_irq(unsigned int irq)
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 17685ab..ae96d41 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -34,6 +34,7 @@
 #include <asm/ia32.h>
 #include <asm/irq.h>
 #include <asm/kdebug.h>
+#include <asm/kexec.h>
 #include <asm/pgalloc.h>
 #include <asm/processor.h>
 #include <asm/sal.h>
@@ -803,6 +804,21 @@
 		ia64_pal_halt(min_power_state);
 }
 
+void machine_shutdown(void)
+{
+#ifdef CONFIG_HOTPLUG_CPU
+	int cpu;
+
+	for_each_online_cpu(cpu) {
+		if (cpu != smp_processor_id())
+			cpu_down(cpu);
+	}
+#endif
+#ifdef CONFIG_KEXEC
+	kexec_disable_iosapic();
+#endif
+}
+
 void
 machine_restart (char *restart_cmd)
 {
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index aa705e4..3f89187 100644
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -607,7 +607,7 @@
 	 */
  	list_for_each_safe(this, next, &current->children) {
 		p = list_entry(this, struct task_struct, sibling);
-		if (p->mm != mm)
+		if (p->tgid != child->tgid)
 			continue;
 		if (thread_matches(p, addr)) {
 			child = p;
@@ -1405,6 +1405,7 @@
 	struct ia64_psr *child_psr = ia64_psr(task_pt_regs(child));
 
 	/* make sure the single step/taken-branch trap bits are not set: */
+	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
 	child_psr->ss = 0;
 	child_psr->tb = 0;
 }
@@ -1525,6 +1526,7 @@
 		 * Make sure the single step/taken-branch trap bits
 		 * are not set:
 		 */
+		clear_tsk_thread_flag(child, TIF_SINGLESTEP);
 		ia64_psr(pt)->ss = 0;
 		ia64_psr(pt)->tb = 0;
 
@@ -1556,6 +1558,7 @@
 			goto out_tsk;
 
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		set_tsk_thread_flag(child, TIF_SINGLESTEP);
 		if (request == PTRACE_SINGLESTEP) {
 			ia64_psr(pt)->ss = 1;
 		} else {
@@ -1595,13 +1598,9 @@
 }
 
 
-void
+static void
 syscall_trace (void)
 {
-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
-		return;
-	if (!(current->ptrace & PT_PTRACED))
-		return;
 	/*
 	 * The 0x80 provides a way for the tracing parent to
 	 * distinguish between a syscall stop and SIGTRAP delivery.
@@ -1664,7 +1663,8 @@
 		audit_syscall_exit(success, result);
 	}
 
-	if (test_thread_flag(TIF_SYSCALL_TRACE)
+	if ((test_thread_flag(TIF_SYSCALL_TRACE)
+	    || test_thread_flag(TIF_SINGLESTEP))
 	    && (current->ptrace & PT_PTRACED))
 		syscall_trace();
 }
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index ad567b8d..83c2629 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -569,34 +569,31 @@
 		{ 1UL << 1, "spontaneous deferral"},
 		{ 1UL << 2, "16-byte atomic ops" }
 	};
-	char features[128], *cp, sep;
+	char features[128], *cp, *sep;
 	struct cpuinfo_ia64 *c = v;
 	unsigned long mask;
 	unsigned long proc_freq;
-	int i;
+	int i, size;
 
 	mask = c->features;
 
 	/* build the feature string: */
-	memcpy(features, " standard", 10);
+	memcpy(features, "standard", 9);
 	cp = features;
-	sep = 0;
-	for (i = 0; i < (int) ARRAY_SIZE(feature_bits); ++i) {
+	size = sizeof(features);
+	sep = "";
+	for (i = 0; i < ARRAY_SIZE(feature_bits) && size > 1; ++i) {
 		if (mask & feature_bits[i].mask) {
-			if (sep)
-				*cp++ = sep;
-			sep = ',';
-			*cp++ = ' ';
-			strcpy(cp, feature_bits[i].feature_name);
-			cp += strlen(feature_bits[i].feature_name);
+			cp += snprintf(cp, size, "%s%s", sep,
+				       feature_bits[i].feature_name),
+			sep = ", ";
 			mask &= ~feature_bits[i].mask;
+			size = sizeof(features) - (cp - features);
 		}
 	}
-	if (mask) {
-		/* print unknown features as a hex value: */
-		if (sep)
-			*cp++ = sep;
-		sprintf(cp, " 0x%lx", mask);
+	if (mask && size > 1) {
+		/* print unknown features as a hex value */
+		snprintf(cp, size, "%s0x%lx", sep, mask);
 	}
 
 	proc_freq = cpufreq_quick_get(cpunum);
@@ -612,7 +609,7 @@
 		   "model name : %s\n"
 		   "revision   : %u\n"
 		   "archrev    : %u\n"
-		   "features   :%s\n"	/* don't change this---it _is_ right! */
+		   "features   : %s\n"
 		   "cpu number : %lu\n"
 		   "cpu regs   : %u\n"
 		   "cpu MHz    : %lu.%06lu\n"
diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c
index f4c7f77..55ddd80 100644
--- a/arch/ia64/kernel/smp.c
+++ b/arch/ia64/kernel/smp.c
@@ -221,13 +221,13 @@
 
 #ifdef CONFIG_KEXEC
 void
-kdump_smp_send_stop()
+kdump_smp_send_stop(void)
 {
  	send_IPI_allbutself(IPI_KDUMP_CPU_STOP);
 }
 
 void
-kdump_smp_send_init()
+kdump_smp_send_init(void)
 {
 	unsigned int cpu, self_cpu;
 	self_cpu = smp_processor_id();
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index d6083a0..8f3d006 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -157,6 +157,7 @@
 	}
 #endif
 
+  . = ALIGN(8);
    __con_initcall_start = .;
   .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET)
 	{ *(.con_initcall.init) }
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
index 1e79551..63e6d49 100644
--- a/arch/ia64/mm/contig.c
+++ b/arch/ia64/mm/contig.c
@@ -30,47 +30,69 @@
 #endif
 
 /**
- * show_mem - display a memory statistics summary
+ * show_mem - give short summary of memory stats
  *
- * Just walks the pages in the system and describes where they're allocated.
+ * Shows a simple page count of reserved and used pages in the system.
+ * For discontig machines, it does this on a per-pgdat basis.
  */
-void
-show_mem (void)
+void show_mem(void)
 {
-	int i, total = 0, reserved = 0;
-	int shared = 0, cached = 0;
+	int i, total_reserved = 0;
+	int total_shared = 0, total_cached = 0;
+	unsigned long total_present = 0;
+	pg_data_t *pgdat;
 
 	printk(KERN_INFO "Mem-info:\n");
 	show_free_areas();
-
 	printk(KERN_INFO "Free swap:       %6ldkB\n",
 	       nr_swap_pages<<(PAGE_SHIFT-10));
-	i = max_mapnr;
-	for (i = 0; i < max_mapnr; i++) {
-		if (!pfn_valid(i)) {
+	printk(KERN_INFO "Node memory in pages:\n");
+	for_each_online_pgdat(pgdat) {
+		unsigned long present;
+		unsigned long flags;
+		int shared = 0, cached = 0, reserved = 0;
+
+		pgdat_resize_lock(pgdat, &flags);
+		present = pgdat->node_present_pages;
+		for(i = 0; i < pgdat->node_spanned_pages; i++) {
+			struct page *page;
+			if (pfn_valid(pgdat->node_start_pfn + i))
+				page = pfn_to_page(pgdat->node_start_pfn + i);
+			else {
 #ifdef CONFIG_VIRTUAL_MEM_MAP
-			if (max_gap < LARGE_GAP)
-				continue;
-			i = vmemmap_find_next_valid_pfn(0, i) - 1;
+				if (max_gap < LARGE_GAP)
+					continue;
 #endif
-			continue;
+				i = vmemmap_find_next_valid_pfn(pgdat->node_id,
+					 i) - 1;
+				continue;
+			}
+			if (PageReserved(page))
+				reserved++;
+			else if (PageSwapCache(page))
+				cached++;
+			else if (page_count(page))
+				shared += page_count(page)-1;
 		}
-		total++;
-		if (PageReserved(mem_map+i))
-			reserved++;
-		else if (PageSwapCache(mem_map+i))
-			cached++;
-		else if (page_count(mem_map + i))
-			shared += page_count(mem_map + i) - 1;
+		pgdat_resize_unlock(pgdat, &flags);
+		total_present += present;
+		total_reserved += reserved;
+		total_cached += cached;
+		total_shared += shared;
+		printk(KERN_INFO "Node %4d:  RAM: %11ld, rsvd: %8d, "
+		       "shrd: %10d, swpd: %10d\n", pgdat->node_id,
+		       present, reserved, shared, cached);
 	}
-	printk(KERN_INFO "%d pages of RAM\n", total);
-	printk(KERN_INFO "%d reserved pages\n", reserved);
-	printk(KERN_INFO "%d pages shared\n", shared);
-	printk(KERN_INFO "%d pages swap cached\n", cached);
-	printk(KERN_INFO "%ld pages in page table cache\n",
+	printk(KERN_INFO "%ld pages of RAM\n", total_present);
+	printk(KERN_INFO "%d reserved pages\n", total_reserved);
+	printk(KERN_INFO "%d pages shared\n", total_shared);
+	printk(KERN_INFO "%d pages swap cached\n", total_cached);
+	printk(KERN_INFO "Total of %ld pages in page table cache\n",
 	       pgtable_quicklist_total_size());
+	printk(KERN_INFO "%d free buffer pages\n", nr_free_buffer_pages());
 }
 
+
 /* physical address where the bootmem map is located */
 unsigned long bootmap_start;
 
@@ -177,7 +199,7 @@
 
 #ifdef CONFIG_CRASH_DUMP
 	/* If we are doing a crash dump, we still need to know the real mem
-	 * size before original memory map is * reset. */
+	 * size before original memory map is reset. */
 	saved_max_pfn = max_pfn;
 #endif
 }
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index 96722cb..6eae596 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -412,37 +412,6 @@
 	return;
 }
 
-#ifdef CONFIG_SPARSEMEM
-/**
- * register_sparse_mem - notify SPARSEMEM that this memory range exists.
- * @start: physical start of range
- * @end: physical end of range
- * @arg: unused
- *
- * Simply calls SPARSEMEM to register memory section(s).
- */
-static int __init register_sparse_mem(unsigned long start, unsigned long end,
-	void *arg)
-{
-	int nid;
-
-	start = __pa(start) >> PAGE_SHIFT;
-	end = __pa(end) >> PAGE_SHIFT;
-	nid = early_pfn_to_nid(start);
-	memory_present(nid, start, end);
-
-	return 0;
-}
-
-static void __init arch_sparse_init(void)
-{
-	efi_memmap_walk(register_sparse_mem, NULL);
-	sparse_init();
-}
-#else
-#define arch_sparse_init() do {} while (0)
-#endif
-
 /**
  * find_memory - walk the EFI memory map and setup the bootmem allocator
  *
@@ -473,6 +442,9 @@
 			node_clear(node, memory_less_mask);
 			mem_data[node].min_pfn = ~0UL;
 		}
+
+	efi_memmap_walk(register_active_ranges, NULL);
+
 	/*
 	 * Initialize the boot memory maps in reverse order since that's
 	 * what the bootmem allocator expects
@@ -506,6 +478,12 @@
 	max_pfn = max_low_pfn;
 
 	find_initrd();
+
+#ifdef CONFIG_CRASH_DUMP
+	/* If we are doing a crash dump, we still need to know the real mem
+	 * size before original memory map is reset. */
+        saved_max_pfn = max_pfn;
+#endif
 }
 
 #ifdef CONFIG_SMP
@@ -654,7 +632,6 @@
 {
 	unsigned long end = start + len;
 
-	add_active_range(node, start >> PAGE_SHIFT, end >> PAGE_SHIFT);
 	mem_data[node].num_physpages += len >> PAGE_SHIFT;
 	if (start <= __pa(MAX_DMA_ADDRESS))
 		mem_data[node].num_dma_physpages +=
@@ -686,10 +663,11 @@
 
 	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
 
-	arch_sparse_init();
-
 	efi_memmap_walk(filter_rsvd_memory, count_node_pages);
 
+	sparse_memory_present_with_active_regions(MAX_NUMNODES);
+	sparse_init();
+
 #ifdef CONFIG_VIRTUAL_MEM_MAP
 	vmalloc_end -= PAGE_ALIGN(ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) *
 		sizeof(struct page));
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 1373fae..faaca21 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -19,6 +19,7 @@
 #include <linux/swap.h>
 #include <linux/proc_fs.h>
 #include <linux/bitops.h>
+#include <linux/kexec.h>
 
 #include <asm/a.out.h>
 #include <asm/dma.h>
@@ -128,6 +129,25 @@
 	set_bit(PG_arch_1, &page->flags);	/* mark page as clean */
 }
 
+/*
+ * Since DMA is i-cache coherent, any (complete) pages that were written via
+ * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to
+ * flush them when they get mapped into an executable vm-area.
+ */
+void
+dma_mark_clean(void *addr, size_t size)
+{
+	unsigned long pg_addr, end;
+
+	pg_addr = PAGE_ALIGN((unsigned long) addr);
+	end = (unsigned long) addr + size;
+	while (pg_addr + PAGE_SIZE <= end) {
+		struct page *page = virt_to_page(pg_addr);
+		set_bit(PG_arch_1, &page->flags);
+		pg_addr += PAGE_SIZE;
+	}
+}
+
 inline void
 ia64_set_rbs_bot (void)
 {
@@ -595,13 +615,27 @@
 	return 0;
 }
 
+#endif /* CONFIG_VIRTUAL_MEM_MAP */
+
 int __init
 register_active_ranges(u64 start, u64 end, void *arg)
 {
-	add_active_range(0, __pa(start) >> PAGE_SHIFT, __pa(end) >> PAGE_SHIFT);
+	int nid = paddr_to_nid(__pa(start));
+
+	if (nid < 0)
+		nid = 0;
+#ifdef CONFIG_KEXEC
+	if (start > crashk_res.start && start < crashk_res.end)
+		start = crashk_res.end;
+	if (end > crashk_res.start && end < crashk_res.end)
+		end = crashk_res.start;
+#endif
+
+	if (start < end)
+		add_active_range(nid, __pa(start) >> PAGE_SHIFT,
+			__pa(end) >> PAGE_SHIFT);
 	return 0;
 }
-#endif /* CONFIG_VIRTUAL_MEM_MAP */
 
 static int __init
 count_reserved_pages (u64 start, u64 end, void *arg)
diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c
index abca6bd..fcf7f93 100644
--- a/arch/ia64/sn/kernel/huberror.c
+++ b/arch/ia64/sn/kernel/huberror.c
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000,2002-2005 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992 - 1997, 2000,2002-2007 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/types.h>
@@ -38,12 +38,20 @@
 			(u64) nasid, 0, 0, 0, 0, 0, 0);
 
 		if ((int)ret_stuff.v0)
-			panic("hubii_eint_handler(): Fatal TIO Error");
+			panic("%s: Fatal %s Error", __FUNCTION__,
+				((nasid & 1) ? "TIO" : "HUBII"));
 
 		if (!(nasid & 1)) /* Not a TIO, handle CRB errors */
 			(void)hubiio_crb_error_handler(hubdev_info);
-	} else 
-		bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid)));
+	} else
+		if (nasid & 1) {	/* TIO errors */
+			SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT,
+				(u64) nasid, 0, 0, 0, 0, 0, 0);
+
+			if ((int)ret_stuff.v0)
+				panic("%s: Fatal TIO Error", __FUNCTION__);
+		} else
+			bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid)));
 
 	return IRQ_HANDLED;
 }
diff --git a/arch/ia64/sn/kernel/io_acpi_init.c b/arch/ia64/sn/kernel/io_acpi_init.c
index cb96b4e..8c331ca 100644
--- a/arch/ia64/sn/kernel/io_acpi_init.c
+++ b/arch/ia64/sn/kernel/io_acpi_init.c
@@ -13,6 +13,7 @@
 #include <asm/sn/sn_sal.h>
 #include "xtalk/hubdev.h"
 #include <linux/acpi.h>
+#include <acpi/acnamesp.h>
 
 
 /*
@@ -31,6 +32,12 @@
 		    0xa2, 0x7c, 0x08, 0x00, 0x69, 0x13, 0xea, 0x51 },
 };
 
+struct sn_pcidev_match {
+	u8 bus;
+	unsigned int devfn;
+	acpi_handle handle;
+};
+
 /*
  * Perform the early IO init in PROM.
  */
@@ -119,9 +126,11 @@
 	status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS,
 					  &sn_uuid, &buffer);
 	if (ACPI_FAILURE(status)) {
-		printk(KERN_ERR "get_acpi_pcibus_ptr: "
-		       "get_acpi_bussoft_info() failed: %d\n",
-		       status);
+		printk(KERN_ERR "%s: "
+		       "acpi_get_vendor_resource() failed (0x%x) for: ",
+		       __FUNCTION__, status);
+		acpi_ns_print_node_pathname(handle, NULL);
+		printk("\n");
 		return NULL;
 	}
 	resource = buffer.pointer;
@@ -130,8 +139,8 @@
 	if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) !=
 	     sizeof(struct pcibus_bussoft *)) {
 		printk(KERN_ERR
-		       "get_acpi_bussoft_ptr: Invalid vendor data "
-		       "length %d\n", vendor->byte_length);
+		       "%s: Invalid vendor data length %d\n",
+			__FUNCTION__, vendor->byte_length);
 		kfree(buffer.pointer);
 		return NULL;
 	}
@@ -143,34 +152,254 @@
 }
 
 /*
- * sn_acpi_bus_fixup
+ * sn_extract_device_info - Extract the pcidev_info and the sn_irq_info
+ *			    pointers from the vendor resource using the
+ *			    provided acpi handle, and copy the structures
+ *			    into the argument buffers.
  */
-void
-sn_acpi_bus_fixup(struct pci_bus *bus)
+static int
+sn_extract_device_info(acpi_handle handle, struct pcidev_info **pcidev_info,
+		    struct sn_irq_info **sn_irq_info)
 {
-	struct pci_dev *pci_dev = NULL;
-	struct pcibus_bussoft *prom_bussoft_ptr;
-	extern void sn_common_bus_fixup(struct pci_bus *,
-					struct pcibus_bussoft *);
+	u64 addr;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	struct sn_irq_info *irq_info, *irq_info_prom;
+	struct pcidev_info *pcidev_ptr, *pcidev_prom_ptr;
+	struct acpi_resource *resource;
+	int ret = 0;
+	acpi_status status;
+	struct acpi_resource_vendor_typed *vendor;
 
-	if (!bus->parent) {	/* If root bus */
-		prom_bussoft_ptr = sn_get_bussoft_ptr(bus);
-		if (prom_bussoft_ptr == NULL) {
-			printk(KERN_ERR
-			       "sn_pci_fixup_bus: 0x%04x:0x%02x Unable to "
-			       "obtain prom_bussoft_ptr\n",
-			       pci_domain_nr(bus), bus->number);
-			return;
+	/*
+	 * The pointer to this device's pcidev_info structure in
+	 * the PROM, is in the vendor resource.
+	 */
+	status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS,
+					  &sn_uuid, &buffer);
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_ERR
+		       "%s: acpi_get_vendor_resource() failed (0x%x) for: ",
+		        __FUNCTION__, status);
+		acpi_ns_print_node_pathname(handle, NULL);
+		printk("\n");
+		return 1;
+	}
+
+	resource = buffer.pointer;
+	vendor = &resource->data.vendor_typed;
+	if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) !=
+	    sizeof(struct pci_devdev_info *)) {
+		printk(KERN_ERR
+		       "%s: Invalid vendor data length: %d for: ",
+		        __FUNCTION__, vendor->byte_length);
+		acpi_ns_print_node_pathname(handle, NULL);
+		printk("\n");
+		ret = 1;
+		goto exit;
+	}
+
+	pcidev_ptr = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
+	if (!pcidev_ptr)
+		panic("%s: Unable to alloc memory for pcidev_info", __FUNCTION__);
+
+	memcpy(&addr, vendor->byte_data, sizeof(struct pcidev_info *));
+	pcidev_prom_ptr = __va(addr);
+	memcpy(pcidev_ptr, pcidev_prom_ptr, sizeof(struct pcidev_info));
+
+	/* Get the IRQ info */
+	irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
+	if (!irq_info)
+		 panic("%s: Unable to alloc memory for sn_irq_info", __FUNCTION__);
+
+	if (pcidev_ptr->pdi_sn_irq_info) {
+		irq_info_prom = __va(pcidev_ptr->pdi_sn_irq_info);
+		memcpy(irq_info, irq_info_prom, sizeof(struct sn_irq_info));
+	}
+
+	*pcidev_info = pcidev_ptr;
+	*sn_irq_info = irq_info;
+
+exit:
+	kfree(buffer.pointer);
+	return ret;
+}
+
+static unsigned int
+get_host_devfn(acpi_handle device_handle, acpi_handle rootbus_handle)
+{
+	unsigned long adr;
+	acpi_handle child;
+	unsigned int devfn;
+	int function;
+	acpi_handle parent;
+	int slot;
+	acpi_status status;
+
+	/*
+	 * Do an upward search to find the root bus device, and
+	 * obtain the host devfn from the previous child device.
+	 */
+	child = device_handle;
+	while (child) {
+		status = acpi_get_parent(child, &parent);
+		if (ACPI_FAILURE(status)) {
+			printk(KERN_ERR "%s: acpi_get_parent() failed "
+			       "(0x%x) for: ", __FUNCTION__, status);
+			acpi_ns_print_node_pathname(child, NULL);
+			printk("\n");
+			panic("%s: Unable to find host devfn\n", __FUNCTION__);
 		}
-		sn_common_bus_fixup(bus, prom_bussoft_ptr);
+		if (parent == rootbus_handle)
+			break;
+		child = parent;
 	}
-	list_for_each_entry(pci_dev, &bus->devices, bus_list) {
-		sn_pci_fixup_slot(pci_dev);
+	if (!child) {
+		printk(KERN_ERR "%s: Unable to find root bus for: ",
+		       __FUNCTION__);
+		acpi_ns_print_node_pathname(device_handle, NULL);
+		printk("\n");
+		BUG();
 	}
+
+	status = acpi_evaluate_integer(child, METHOD_NAME__ADR, NULL, &adr);
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_ERR "%s: Unable to get _ADR (0x%x) for: ",
+		       __FUNCTION__, status);
+		acpi_ns_print_node_pathname(child, NULL);
+		printk("\n");
+		panic("%s: Unable to find host devfn\n", __FUNCTION__);
+	}
+
+	slot = (adr >> 16) & 0xffff;
+	function = adr & 0xffff;
+	devfn = PCI_DEVFN(slot, function);
+	return devfn;
 }
 
 /*
- * sn_acpi_slot_fixup - Perform any SN specific slot fixup.
+ * find_matching_device - Callback routine to find the ACPI device
+ *			  that matches up with our pci_dev device.
+ *			  Matching is done on bus number and devfn.
+ *			  To find the bus number for a particular
+ *			  ACPI device, we must look at the _BBN method
+ *			  of its parent.
+ */
+static acpi_status
+find_matching_device(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+	unsigned long bbn = -1;
+	unsigned long adr;
+	acpi_handle parent = NULL;
+	acpi_status status;
+	unsigned int devfn;
+	int function;
+	int slot;
+	struct sn_pcidev_match *info = context;
+
+        status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
+                                       &adr);
+        if (ACPI_SUCCESS(status)) {
+		status = acpi_get_parent(handle, &parent);
+		if (ACPI_FAILURE(status)) {
+			printk(KERN_ERR
+			       "%s: acpi_get_parent() failed (0x%x) for: ",
+					__FUNCTION__, status);
+			acpi_ns_print_node_pathname(handle, NULL);
+			printk("\n");
+			return AE_OK;
+		}
+		status = acpi_evaluate_integer(parent, METHOD_NAME__BBN,
+					       NULL, &bbn);
+		if (ACPI_FAILURE(status)) {
+			printk(KERN_ERR
+			  "%s: Failed to find _BBN in parent of: ",
+					__FUNCTION__);
+			acpi_ns_print_node_pathname(handle, NULL);
+			printk("\n");
+			return AE_OK;
+		}
+
+                slot = (adr >> 16) & 0xffff;
+                function = adr & 0xffff;
+                devfn = PCI_DEVFN(slot, function);
+                if ((info->devfn == devfn) && (info->bus == bbn)) {
+			/* We have a match! */
+			info->handle = handle;
+			return 1;
+		}
+	}
+	return AE_OK;
+}
+
+/*
+ * sn_acpi_get_pcidev_info - Search ACPI namespace for the acpi
+ *			     device matching the specified pci_dev,
+ *			     and return the pcidev info and irq info.
+ */
+int
+sn_acpi_get_pcidev_info(struct pci_dev *dev, struct pcidev_info **pcidev_info,
+			struct sn_irq_info **sn_irq_info)
+{
+	unsigned int host_devfn;
+	struct sn_pcidev_match pcidev_match;
+	acpi_handle rootbus_handle;
+	unsigned long segment;
+	acpi_status status;
+
+	rootbus_handle = PCI_CONTROLLER(dev)->acpi_handle;
+        status = acpi_evaluate_integer(rootbus_handle, METHOD_NAME__SEG, NULL,
+                                       &segment);
+        if (ACPI_SUCCESS(status)) {
+		if (segment != pci_domain_nr(dev)) {
+			printk(KERN_ERR
+			       "%s: Segment number mismatch, 0x%lx vs 0x%x for: ",
+			       __FUNCTION__, segment, pci_domain_nr(dev));
+			acpi_ns_print_node_pathname(rootbus_handle, NULL);
+			printk("\n");
+			return 1;
+		}
+	} else {
+		printk(KERN_ERR "%s: Unable to get __SEG from: ",
+		       __FUNCTION__);
+		acpi_ns_print_node_pathname(rootbus_handle, NULL);
+		printk("\n");
+		return 1;
+	}
+
+	/*
+	 * We want to search all devices in this segment/domain
+	 * of the ACPI namespace for the matching ACPI device,
+	 * which holds the pcidev_info pointer in its vendor resource.
+	 */
+	pcidev_match.bus = dev->bus->number;
+	pcidev_match.devfn = dev->devfn;
+	pcidev_match.handle = NULL;
+
+	acpi_walk_namespace(ACPI_TYPE_DEVICE, rootbus_handle, ACPI_UINT32_MAX,
+			    find_matching_device, &pcidev_match, NULL);
+
+	if (!pcidev_match.handle) {
+		printk(KERN_ERR
+		       "%s: Could not find matching ACPI device for %s.\n",
+		       __FUNCTION__, pci_name(dev));
+		return 1;
+	}
+
+	if (sn_extract_device_info(pcidev_match.handle, pcidev_info, sn_irq_info))
+		return 1;
+
+	/* Build up the pcidev_info.pdi_slot_host_handle */
+	host_devfn = get_host_devfn(pcidev_match.handle, rootbus_handle);
+	(*pcidev_info)->pdi_slot_host_handle =
+			((unsigned long) pci_domain_nr(dev) << 40) |
+					/* bus == 0 */
+					host_devfn;
+	return 0;
+}
+
+/*
+ * sn_acpi_slot_fixup - Obtain the pcidev_info and sn_irq_info.
+ *			Perform any SN specific slot fixup.
  *			At present there does not appear to be
  *			any generic way to handle a ROM image
  *			that has been shadowed by the PROM, so
@@ -179,11 +408,18 @@
  */
 
 void
-sn_acpi_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info)
+sn_acpi_slot_fixup(struct pci_dev *dev)
 {
 	void __iomem *addr;
+	struct pcidev_info *pcidev_info = NULL;
+	struct sn_irq_info *sn_irq_info = NULL;
 	size_t size;
 
+	if (sn_acpi_get_pcidev_info(dev, &pcidev_info, &sn_irq_info)) {
+		panic("%s:  Failure obtaining pcidev_info for %s\n",
+		      __FUNCTION__, pci_name(dev));
+	}
+
 	if (pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE]) {
 		/*
 		 * A valid ROM image exists and has been shadowed by the
@@ -200,8 +436,11 @@
 						(unsigned long) addr + size;
 		dev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_BIOS_COPY;
 	}
+	sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info);
 }
 
+EXPORT_SYMBOL(sn_acpi_slot_fixup);
+
 static struct acpi_driver acpi_sn_hubdev_driver = {
 	.name = "SGI HUBDEV Driver",
 	.ids = "SGIHUB,SGITIO",
@@ -212,6 +451,33 @@
 
 
 /*
+ * sn_acpi_bus_fixup -  Perform SN specific setup of software structs
+ *			(pcibus_bussoft, pcidev_info) and hardware
+ *			registers, for the specified bus and devices under it.
+ */
+void
+sn_acpi_bus_fixup(struct pci_bus *bus)
+{
+	struct pci_dev *pci_dev = NULL;
+	struct pcibus_bussoft *prom_bussoft_ptr;
+
+	if (!bus->parent) {	/* If root bus */
+		prom_bussoft_ptr = sn_get_bussoft_ptr(bus);
+		if (prom_bussoft_ptr == NULL) {
+			printk(KERN_ERR
+			       "%s: 0x%04x:0x%02x Unable to "
+			       "obtain prom_bussoft_ptr\n",
+			       __FUNCTION__, pci_domain_nr(bus), bus->number);
+			return;
+		}
+		sn_common_bus_fixup(bus, prom_bussoft_ptr);
+	}
+	list_for_each_entry(pci_dev, &bus->devices, bus_list) {
+		sn_acpi_slot_fixup(pci_dev);
+	}
+}
+
+/*
  * sn_io_acpi_init - PROM has ACPI support for IO, defining at a minimum the
  *		     nodes and root buses in the DSDT. As a result, bus scanning
  *		     will be initiated by the Linux ACPI code.
diff --git a/arch/ia64/sn/kernel/io_common.c b/arch/ia64/sn/kernel/io_common.c
index d4dd8f4..d48bcd8 100644
--- a/arch/ia64/sn/kernel/io_common.c
+++ b/arch/ia64/sn/kernel/io_common.c
@@ -26,14 +26,10 @@
 #include <linux/acpi.h>
 #include <asm/sn/sn2/sn_hwperf.h>
 #include <asm/sn/acpi.h>
+#include "acpi/acglobal.h"
 
 extern void sn_init_cpei_timer(void);
 extern void register_sn_procfs(void);
-extern void sn_acpi_bus_fixup(struct pci_bus *);
-extern void sn_bus_fixup(struct pci_bus *);
-extern void sn_acpi_slot_fixup(struct pci_dev *, struct pcidev_info *);
-extern void sn_more_slot_fixup(struct pci_dev *, struct pcidev_info *);
-extern void sn_legacy_pci_window_fixup(struct pci_controller *, u64, u64);
 extern void sn_io_acpi_init(void);
 extern void sn_io_init(void);
 
@@ -48,6 +44,9 @@
 
 int sn_ioif_inited;		/* SN I/O infrastructure initialized? */
 
+int sn_acpi_rev;		/* SN ACPI revision */
+EXPORT_SYMBOL_GPL(sn_acpi_rev);
+
 struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES];	/* indexed by asic type */
 
 /*
@@ -99,25 +98,6 @@
 }
 
 /*
- * Retrieve the pci device information given the bus and device|function number.
- */
-static inline u64
-sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev,
-		    u64 sn_irq_info)
-{
-	struct ia64_sal_retval ret_stuff;
-	ret_stuff.status = 0;
-	ret_stuff.v0 = 0;
-
-	SAL_CALL_NOLOCK(ret_stuff,
-			(u64) SN_SAL_IOIF_GET_PCIDEV_INFO,
-			(u64) segment, (u64) bus_number, (u64) devfn,
-			(u64) pci_dev,
-			sn_irq_info, 0, 0);
-	return ret_stuff.v0;
-}
-
-/*
  * sn_pcidev_info_get() - Retrieve the pcidev_info struct for the specified
  *			  device.
  */
@@ -249,50 +229,25 @@
 }
 
 /*
- * sn_pci_fixup_slot() - This routine sets up a slot's resources consistent
- *			 with the Linux PCI abstraction layer. Resources
- *			 acquired from our PCI provider include PIO maps
- *			 to BAR space and interrupt objects.
+ * sn_pci_fixup_slot()
  */
-void sn_pci_fixup_slot(struct pci_dev *dev)
+void sn_pci_fixup_slot(struct pci_dev *dev, struct pcidev_info *pcidev_info,
+		       struct sn_irq_info *sn_irq_info)
 {
 	int segment = pci_domain_nr(dev->bus);
-	int status = 0;
 	struct pcibus_bussoft *bs;
- 	struct pci_bus *host_pci_bus;
- 	struct pci_dev *host_pci_dev;
-	struct pcidev_info *pcidev_info;
- 	struct sn_irq_info *sn_irq_info;
- 	unsigned int bus_no, devfn;
+	struct pci_bus *host_pci_bus;
+	struct pci_dev *host_pci_dev;
+	unsigned int bus_no, devfn;
 
 	pci_dev_get(dev); /* for the sysdata pointer */
-	pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
-	if (!pcidev_info)
-		BUG();		/* Cannot afford to run out of memory */
-
-	sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
-	if (!sn_irq_info)
-		BUG();		/* Cannot afford to run out of memory */
-
-	/* Call to retrieve pci device information needed by kernel. */
-	status = sal_get_pcidev_info((u64) segment, (u64) dev->bus->number,
-				     dev->devfn,
-				     (u64) __pa(pcidev_info),
-				     (u64) __pa(sn_irq_info));
-	if (status)
-		BUG(); /* Cannot get platform pci device information */
 
 	/* Add pcidev_info to list in pci_controller.platform_data */
 	list_add_tail(&pcidev_info->pdi_list,
 		      &(SN_PLATFORM_DATA(dev->bus)->pcidev_info));
-
-	if (SN_ACPI_BASE_SUPPORT())
-		sn_acpi_slot_fixup(dev, pcidev_info);
-	else
-		sn_more_slot_fixup(dev, pcidev_info);
 	/*
 	 * Using the PROMs values for the PCI host bus, get the Linux
- 	 * PCI host_pci_dev struct and set up host bus linkages
+	 * PCI host_pci_dev struct and set up host bus linkages
  	 */
 
 	bus_no = (pcidev_info->pdi_slot_host_handle >> 32) & 0xff;
@@ -489,11 +444,6 @@
 			sprintf(address, "%s^%d", address, geo_slot(geoid));
 }
 
-/*
- * sn_pci_fixup_bus() - Perform SN specific setup of software structs
- *			(pcibus_bussoft, pcidev_info) and hardware
- *			registers, for the specified bus and devices under it.
- */
 void __devinit
 sn_pci_fixup_bus(struct pci_bus *bus)
 {
@@ -519,6 +469,15 @@
 	if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM())
 		return 0;
 
+	/* we set the acpi revision to that of the DSDT table OEM rev. */
+	{
+		struct acpi_table_header *header = NULL;
+
+		acpi_get_table_by_index(ACPI_TABLE_INDEX_DSDT, &header);
+		BUG_ON(header == NULL);
+		sn_acpi_rev = header->oem_revision;
+	}
+
 	/*
 	 * prime sn_pci_provider[].  Individial provider init routines will
 	 * override their respective default entries.
@@ -544,8 +503,12 @@
 	register_sn_procfs();
 #endif
 
-	printk(KERN_INFO "ACPI  DSDT OEM Rev 0x%x\n",
-	       acpi_gbl_DSDT->oem_revision);
+	{
+		struct acpi_table_header *header;
+		(void)acpi_get_table_by_index(ACPI_TABLE_INDEX_DSDT, &header);
+		printk(KERN_INFO "ACPI  DSDT OEM Rev 0x%x\n",
+			header->oem_revision);
+	}
 	if (SN_ACPI_BASE_SUPPORT())
 		sn_io_acpi_init();
 	else
@@ -605,7 +568,6 @@
 
 fs_initcall(sn_io_late_init);
 
-EXPORT_SYMBOL(sn_pci_fixup_slot);
 EXPORT_SYMBOL(sn_pci_unfixup_slot);
 EXPORT_SYMBOL(sn_bus_store_sysdata);
 EXPORT_SYMBOL(sn_bus_free_sysdata);
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index 9ad843e..600be3e 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -56,6 +56,25 @@
 	return ret_stuff.v0;
 }
 
+/*
+ * Retrieve the pci device information given the bus and device|function number.
+ */
+static inline u64
+sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev,
+		    u64 sn_irq_info)
+{
+	struct ia64_sal_retval ret_stuff;
+	ret_stuff.status = 0;
+	ret_stuff.v0 = 0;
+
+	SAL_CALL_NOLOCK(ret_stuff,
+			(u64) SN_SAL_IOIF_GET_PCIDEV_INFO,
+			(u64) segment, (u64) bus_number, (u64) devfn,
+			(u64) pci_dev,
+			sn_irq_info, 0, 0);
+	return ret_stuff.v0;
+}
+
 
 /*
  * sn_fixup_ionodes() - This routine initializes the HUB data structure for
@@ -172,18 +191,40 @@
 }
 
 /*
- * sn_more_slot_fixup() - We are not running with an ACPI capable PROM,
+ * sn_io_slot_fixup() -   We are not running with an ACPI capable PROM,
  *			  and need to convert the pci_dev->resource
  *			  'start' and 'end' addresses to mapped addresses,
  *			  and setup the pci_controller->window array entries.
  */
 void
-sn_more_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info)
+sn_io_slot_fixup(struct pci_dev *dev)
 {
 	unsigned int count = 0;
 	int idx;
 	s64 pci_addrs[PCI_ROM_RESOURCE + 1];
 	unsigned long addr, end, size, start;
+	struct pcidev_info *pcidev_info;
+	struct sn_irq_info *sn_irq_info;
+	int status;
+
+	pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
+	if (!pcidev_info)
+		panic("%s: Unable to alloc memory for pcidev_info", __FUNCTION__);
+
+	sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
+	if (!sn_irq_info)
+		panic("%s: Unable to alloc memory for sn_irq_info", __FUNCTION__);
+
+	/* Call to retrieve pci device information needed by kernel. */
+	status = sal_get_pcidev_info((u64) pci_domain_nr(dev),
+		(u64) dev->bus->number,
+		dev->devfn,
+		(u64) __pa(pcidev_info),
+		(u64) __pa(sn_irq_info));
+
+	if (status)
+		BUG(); /* Cannot get platform pci device information */
+
 
 	/* Copy over PIO Mapped Addresses */
 	for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
@@ -219,8 +260,12 @@
 	 */
 	if (count > 0)
 		sn_pci_window_fixup(dev, count, pci_addrs);
+
+	sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info);
 }
 
+EXPORT_SYMBOL(sn_io_slot_fixup);
+
 /*
  * sn_pci_controller_fixup() - This routine sets up a bus's resources
  *			       consistent with the Linux PCI abstraction layer.
@@ -272,9 +317,6 @@
 {
 	struct pci_dev *pci_dev = NULL;
 	struct pcibus_bussoft *prom_bussoft_ptr;
-	extern void sn_common_bus_fixup(struct pci_bus *,
-					struct pcibus_bussoft *);
-
 
 	if (!bus->parent) {  /* If root bus */
 		prom_bussoft_ptr = PCI_CONTROLLER(bus)->platform_data;
@@ -291,7 +333,7 @@
 					   prom_bussoft_ptr->bs_legacy_mem);
         }
         list_for_each_entry(pci_dev, &bus->devices, bus_list) {
-                sn_pci_fixup_slot(pci_dev);
+                sn_io_slot_fixup(pci_dev);
         }
 
 }
diff --git a/arch/ia64/sn/kernel/iomv.c b/arch/ia64/sn/kernel/iomv.c
index 4aa4f30..ab7e2fd 100644
--- a/arch/ia64/sn/kernel/iomv.c
+++ b/arch/ia64/sn/kernel/iomv.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * 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.
@@ -26,9 +26,10 @@
  * @port: port to convert
  *
  * Legacy in/out instructions are converted to ld/st instructions
- * on IA64.  This routine will convert a port number into a valid 
+ * on IA64.  This routine will convert a port number into a valid
  * SN i/o address.  Used by sn_in*() and sn_out*().
  */
+
 void *sn_io_addr(unsigned long port)
 {
 	if (!IS_RUNNING_ON_SIMULATOR()) {
diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c
index b3a435f..ea3dc38 100644
--- a/arch/ia64/sn/kernel/msi_sn.c
+++ b/arch/ia64/sn/kernel/msi_sn.c
@@ -59,13 +59,12 @@
 	sn_intr_free(nasid, widget, sn_irq_info);
 	sn_msi_info[irq].sn_irq_info = NULL;
 
-	return;
+	destroy_irq(irq);
 }
 
-int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+int sn_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *entry)
 {
 	struct msi_msg msg;
-	struct msi_desc *entry;
 	int widget;
 	int status;
 	nasid_t nasid;
@@ -73,8 +72,8 @@
 	struct sn_irq_info *sn_irq_info;
 	struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev);
 	struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
+	int irq;
 
-	entry = get_irq_data(irq);
 	if (!entry->msi_attrib.is_64)
 		return -EINVAL;
 
@@ -84,6 +83,11 @@
 	if (provider == NULL || provider->dma_map_consistent == NULL)
 		return -EINVAL;
 
+	irq = create_irq();
+	if (irq < 0)
+		return irq;
+
+	set_irq_msi(irq, entry);
 	/*
 	 * Set up the vector plumbing.  Let the prom (via sn_intr_alloc)
 	 * decide which cpu to direct this msi at by default.
@@ -95,12 +99,15 @@
 			SWIN_WIDGETNUM(bussoft->bs_base);
 
 	sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
-	if (! sn_irq_info)
+	if (! sn_irq_info) {
+		destroy_irq(irq);
 		return -ENOMEM;
+	}
 
 	status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1);
 	if (status) {
 		kfree(sn_irq_info);
+		destroy_irq(irq);
 		return -ENOMEM;
 	}
 
@@ -121,6 +128,7 @@
 	if (! bus_addr) {
 		sn_intr_free(nasid, widget, sn_irq_info);
 		kfree(sn_irq_info);
+		destroy_irq(irq);
 		return -ENOMEM;
 	}
 
@@ -139,7 +147,7 @@
 	write_msi_msg(irq, &msg);
 	set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq);
 
-	return 0;
+	return irq;
 }
 
 #ifdef CONFIG_SMP
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
index 6846dc9..04a82560 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
@@ -20,7 +20,8 @@
 #include "xtalk/hubdev.h"
 
 int
-sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp)
+sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp,
+                      char **ssdt)
 {
 	struct ia64_sal_retval ret_stuff;
 	u64 busnum;
@@ -32,7 +33,8 @@
 	segment = soft->pbi_buscommon.bs_persist_segment;
 	busnum = soft->pbi_buscommon.bs_persist_busnum;
 	SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_ENABLE, segment,
-			busnum, (u64) device, (u64) resp, 0, 0, 0);
+			busnum, (u64) device, (u64) resp, (u64)ia64_tpa(ssdt),
+			0, 0);
 
 	return (int)ret_stuff.v0;
 }
diff --git a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c
index 9226264..11ea217 100644
--- a/arch/m68knommu/kernel/time.c
+++ b/arch/m68knommu/kernel/time.c
@@ -23,6 +23,7 @@
 
 #include <asm/machdep.h>
 #include <asm/io.h>
+#include <asm/irq_regs.h>
 
 #define	TICK_SIZE (tick_nsec / 1000)
 
@@ -38,7 +39,7 @@
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
-static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
+static irqreturn_t timer_interrupt(int irq, void *dummy)
 {
 	/* last time the cmos clock got updated */
 	static long last_rtc_update=0;
@@ -51,7 +52,7 @@
 
 	do_timer(1);
 #ifndef CONFIG_SMP
-	update_process_times(user_mode(regs));
+	update_process_times(user_mode(get_irq_regs()));
 #endif
 	if (current->pid)
 		profile_tick(CPU_PROFILING);
diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S
index 2b2a10d..bfade20 100644
--- a/arch/m68knommu/kernel/vmlinux.lds.S
+++ b/arch/m68knommu/kernel/vmlinux.lds.S
@@ -87,6 +87,16 @@
 		*(__ksymtab_gpl)
 		__stop___ksymtab_gpl = .;
 
+		/* Kernel symbol table: Normal unused symbols */
+		__start___ksymtab_unused = .;
+		*(__ksymtab_unused)
+		__stop___ksymtab_unused = .;
+
+		/* Kernel symbol table: GPL-only unused symbols */
+		__start___ksymtab_unused_gpl = .;
+		*(__ksymtab_unused_gpl)
+		__stop___ksymtab_unused_gpl = .;
+
 		/* Kernel symbol table: GPL-future symbols */
 		__start___ksymtab_gpl_future = .;
 		*(__ksymtab_gpl_future)
diff --git a/arch/m68knommu/platform/5206/config.c b/arch/m68knommu/platform/5206/config.c
index 34657f8..3343830 100644
--- a/arch/m68knommu/platform/5206/config.c
+++ b/arch/m68knommu/platform/5206/config.c
@@ -26,7 +26,7 @@
 /***************************************************************************/
 
 void coldfire_tick(void);
-void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_timer_init(irq_handler_t handler);
 unsigned long coldfire_timer_offset(void);
 void coldfire_trap_init(void);
 void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/5206e/config.c b/arch/m68knommu/platform/5206e/config.c
index 48e4d62..0f67320 100644
--- a/arch/m68knommu/platform/5206e/config.c
+++ b/arch/m68knommu/platform/5206e/config.c
@@ -25,7 +25,7 @@
 /***************************************************************************/
 
 void coldfire_tick(void);
-void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_timer_init(irq_handler_t handler);
 unsigned long coldfire_timer_offset(void);
 void coldfire_trap_init(void);
 void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/520x/config.c b/arch/m68knommu/platform/520x/config.c
index 823f561..58b2878 100644
--- a/arch/m68knommu/platform/520x/config.c
+++ b/arch/m68knommu/platform/520x/config.c
@@ -13,6 +13,7 @@
 
 #include <linux/kernel.h>
 #include <linux/param.h>
+#include <linux/interrupt.h>
 #include <asm/machdep.h>
 #include <asm/dma.h>
 
@@ -27,7 +28,7 @@
 /***************************************************************************/
 
 void coldfire_pit_tick(void);
-void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_pit_init(irq_handler_t handler);
 unsigned long coldfire_pit_offset(void);
 void coldfire_trap_init(void);
 void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/523x/config.c b/arch/m68knommu/platform/523x/config.c
index 85de817..9b054e6 100644
--- a/arch/m68knommu/platform/523x/config.c
+++ b/arch/m68knommu/platform/523x/config.c
@@ -27,7 +27,7 @@
 /***************************************************************************/
 
 void coldfire_pit_tick(void);
-void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_pit_init(irq_handler_t handler);
 unsigned long coldfire_pit_offset(void);
 void coldfire_trap_init(void);
 void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/5249/config.c b/arch/m68knommu/platform/5249/config.c
index 9d19d5b..d670607 100644
--- a/arch/m68knommu/platform/5249/config.c
+++ b/arch/m68knommu/platform/5249/config.c
@@ -12,6 +12,7 @@
 #include <linux/sched.h>
 #include <linux/param.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <asm/irq.h>
 #include <asm/dma.h>
 #include <asm/traps.h>
@@ -24,7 +25,7 @@
 /***************************************************************************/
 
 void coldfire_tick(void);
-void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_timer_init(irq_handler_t handler);
 unsigned long coldfire_timer_offset(void);
 void coldfire_trap_init(void);
 void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/5272/config.c b/arch/m68knommu/platform/5272/config.c
index d500e27..6b437cc 100644
--- a/arch/m68knommu/platform/5272/config.c
+++ b/arch/m68knommu/platform/5272/config.c
@@ -26,7 +26,7 @@
 /***************************************************************************/
 
 void coldfire_tick(void);
-void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_timer_init(irq_handler_t handler);
 unsigned long coldfire_timer_offset(void);
 void coldfire_trap_init(void);
 void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/527x/config.c b/arch/m68knommu/platform/527x/config.c
index bbae515..28e7d96 100644
--- a/arch/m68knommu/platform/527x/config.c
+++ b/arch/m68knommu/platform/527x/config.c
@@ -27,7 +27,7 @@
 /***************************************************************************/
 
 void coldfire_pit_tick(void);
-void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_pit_init(irq_handler_t handler);
 unsigned long coldfire_pit_offset(void);
 void coldfire_trap_init(void);
 void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/528x/config.c b/arch/m68knommu/platform/528x/config.c
index 18dad90..805b4f7 100644
--- a/arch/m68knommu/platform/528x/config.c
+++ b/arch/m68knommu/platform/528x/config.c
@@ -27,7 +27,7 @@
 /***************************************************************************/
 
 void coldfire_pit_tick(void);
-void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_pit_init(irq_handler_t handler);
 unsigned long coldfire_pit_offset(void);
 void coldfire_trap_init(void);
 void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/5307/config.c b/arch/m68knommu/platform/5307/config.c
index 8074ac5..e04b84d 100644
--- a/arch/m68knommu/platform/5307/config.c
+++ b/arch/m68knommu/platform/5307/config.c
@@ -27,7 +27,7 @@
 /***************************************************************************/
 
 void coldfire_tick(void);
-void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_timer_init(irq_handler_t handler);
 unsigned long coldfire_timer_offset(void);
 void coldfire_trap_init(void);
 void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/5307/pit.c b/arch/m68knommu/platform/5307/pit.c
index 9dc5688..aa15bee 100644
--- a/arch/m68knommu/platform/5307/pit.c
+++ b/arch/m68knommu/platform/5307/pit.c
@@ -43,7 +43,7 @@
 
 /***************************************************************************/
 
-void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *))
+void coldfire_pit_init(irq_handler_t handler)
 {
 	volatile unsigned char *icrp;
 	volatile unsigned long *imrp;
diff --git a/arch/m68knommu/platform/5307/timers.c b/arch/m68knommu/platform/5307/timers.c
index e5668af..87b112b 100644
--- a/arch/m68knommu/platform/5307/timers.c
+++ b/arch/m68knommu/platform/5307/timers.c
@@ -62,7 +62,7 @@
 
 /***************************************************************************/
 
-void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *))
+void coldfire_timer_init(irq_handler_t handler)
 {
 	__raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
 	__raw_writetrr(((MCF_BUSCLK / 16) / HZ), TA(MCFTIMER_TRR));
@@ -111,12 +111,13 @@
 /*
  *	Use the other timer to provide high accuracy profiling info.
  */
-void coldfire_profile_tick(int irq, void *dummy, struct pt_regs *regs)
+irqreturn_t coldfire_profile_tick(int irq, void *dummy)
 {
 	/* Reset ColdFire timer2 */
 	__raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER));
 	if (current->pid)
 		profile_tick(CPU_PROFILING, regs);
+	return IRQ_HANDLED;
 }
 
 /***************************************************************************/
diff --git a/arch/m68knommu/platform/532x/config.c b/arch/m68knommu/platform/532x/config.c
index c7d6ad5..664c3a12 100644
--- a/arch/m68knommu/platform/532x/config.c
+++ b/arch/m68knommu/platform/532x/config.c
@@ -35,7 +35,7 @@
 /***************************************************************************/
 
 void coldfire_tick(void);
-void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_timer_init(irq_handler_t handler);
 unsigned long coldfire_timer_offset(void);
 void coldfire_trap_init(void);
 void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/5407/config.c b/arch/m68knommu/platform/5407/config.c
index 5aad264..036f628 100644
--- a/arch/m68knommu/platform/5407/config.c
+++ b/arch/m68knommu/platform/5407/config.c
@@ -26,7 +26,7 @@
 /***************************************************************************/
 
 void coldfire_tick(void);
-void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_timer_init(irq_handler_t handler);
 unsigned long coldfire_timer_offset(void);
 void coldfire_trap_init(void);
 void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/68328/config.c b/arch/m68knommu/platform/68328/config.c
index 26ffeba..e5c537d 100644
--- a/arch/m68knommu/platform/68328/config.c
+++ b/arch/m68knommu/platform/68328/config.c
@@ -34,7 +34,7 @@
 
 /***************************************************************************/
 
-void m68328_timer_init(irqreturn_t (*timer_routine) (int, void *, struct pt_regs *));
+void m68328_timer_init(irq_handler_t timer_routine);
 void m68328_timer_tick(void);
 unsigned long m68328_timer_gettimeoffset(void);
 void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec);
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index bbd386f..9d839a9 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -575,6 +575,7 @@
 	select DMA_IP27
 	select EARLY_PRINTK
 	select HW_HAS_PCI
+	select NR_CPUS_DEFAULT_64
 	select PCI_DOMAINS
 	select SYS_HAS_CPU_R10000
 	select SYS_SUPPORTS_64BIT_KERNEL
@@ -612,6 +613,7 @@
 	bool "Sibyte BCM91480B-BigSur"
 	select BOOT_ELF32
 	select DMA_COHERENT
+	select NR_CPUS_DEFAULT_4
 	select PCI_DOMAINS
 	select SIBYTE_BCM1x80
 	select SWAP_IO_SPACE
@@ -623,6 +625,7 @@
 	bool "Sibyte BCM91250A-SWARM"
 	select BOOT_ELF32
 	select DMA_COHERENT
+	select NR_CPUS_DEFAULT_2
 	select SIBYTE_SB1250
 	select SWAP_IO_SPACE
 	select SYS_HAS_CPU_SB1
@@ -635,6 +638,7 @@
 	depends on EXPERIMENTAL
 	select BOOT_ELF32
 	select DMA_COHERENT
+	select NR_CPUS_DEFAULT_2
 	select SIBYTE_SB1250
 	select SWAP_IO_SPACE
 	select SYS_HAS_CPU_SB1
@@ -668,6 +672,7 @@
 	depends on EXPERIMENTAL
 	select BOOT_ELF32
 	select DMA_COHERENT
+	select NR_CPUS_DEFAULT_2
 	select SIBYTE_SB1250
 	select SWAP_IO_SPACE
 	select SYS_HAS_CPU_SB1
@@ -680,6 +685,7 @@
 	depends on EXPERIMENTAL
 	select BOOT_ELF32
 	select DMA_COHERENT
+	select NR_CPUS_DEFAULT_2
 	select SIBYTE_SB1250
 	select SWAP_IO_SPACE
 	select SYS_HAS_CPU_SB1
@@ -790,23 +796,6 @@
 
 endchoice
 
-config KEXEC
- 	bool "Kexec system call (EXPERIMENTAL)"
- 	depends on EXPERIMENTAL
- 	help
- 	  kexec is a system call that implements the ability to shutdown your
- 	  current kernel, and to start another kernel.  It is like a reboot
- 	  but it is indepedent of the system firmware.   And like a reboot
- 	  you can start any kernel with it, not just Linux.
-
- 	  The name comes from the similiarity to the exec system call.
-
- 	  It is an ongoing process to be certain the hardware in a machine
- 	  is properly shutdown, so do not be surprised if this code does not
- 	  initially work for you.  It may help to enable device hotplugging
- 	  support.  As of this writing the exact hardware interface is
- 	  strongly in flux, so no good recommendation can be made.
-
 source "arch/mips/ddb5xxx/Kconfig"
 source "arch/mips/gt64120/ev64120/Kconfig"
 source "arch/mips/jazz/Kconfig"
@@ -945,6 +934,9 @@
 
 endchoice
 
+config SYS_SUPPORTS_APM_EMULATION
+	bool
+
 config SYS_SUPPORTS_BIG_ENDIAN
 	bool
 
@@ -1012,6 +1004,7 @@
 	bool
 	select SYS_HAS_CPU_MIPS32_R1
 	select SYS_SUPPORTS_32BIT_KERNEL
+	select SYS_SUPPORTS_APM_EMULATION
 
 config PNX8550
 	bool
@@ -1541,6 +1534,8 @@
 	select CPU_MIPSR2_IRQ_VI
 	select CPU_MIPSR2_SRS
 	select MIPS_MT
+	select NR_CPUS_DEFAULT_2
+	select NR_CPUS_DEFAULT_8
 	select SMP
 	select SYS_SUPPORTS_SMP
 	help
@@ -1756,13 +1751,34 @@
 config SYS_SUPPORTS_SMP
 	bool
 
+config NR_CPUS_DEFAULT_2
+	bool
+
+config NR_CPUS_DEFAULT_4
+	bool
+
+config NR_CPUS_DEFAULT_8
+	bool
+
+config NR_CPUS_DEFAULT_16
+	bool
+
+config NR_CPUS_DEFAULT_32
+	bool
+
+config NR_CPUS_DEFAULT_64
+	bool
+
 config NR_CPUS
 	int "Maximum number of CPUs (2-64)"
 	range 2 64
 	depends on SMP
-	default "64" if SGI_IP27
-	default "2"
-	default "8" if MIPS_MT_SMTC
+	default "2" if NR_CPUS_DEFAULT_2
+	default "4" if NR_CPUS_DEFAULT_4
+	default "8" if NR_CPUS_DEFAULT_8
+	default "16" if NR_CPUS_DEFAULT_16
+	default "32" if NR_CPUS_DEFAULT_32
+	default "64" if NR_CPUS_DEFAULT_64
 	help
 	  This allows you to specify the maximum number of CPUs which this
 	  kernel will support.  The maximum supported value is 32 for 32-bit
@@ -1859,6 +1875,40 @@
 	  This will result in additional memory usage, so it is not
 	  recommended for normal users.
 
+config KEXEC
+	bool "Kexec system call (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	help
+	  kexec is a system call that implements the ability to shutdown your
+	  current kernel, and to start another kernel.  It is like a reboot
+	  but it is indepedent of the system firmware.   And like a reboot
+	  you can start any kernel with it, not just Linux.
+
+	  The name comes from the similiarity to the exec system call.
+
+	  It is an ongoing process to be certain the hardware in a machine
+	  is properly shutdown, so do not be surprised if this code does not
+	  initially work for you.  It may help to enable device hotplugging
+	  support.  As of this writing the exact hardware interface is
+	  strongly in flux, so no good recommendation can be made.
+
+config SECCOMP
+	bool "Enable seccomp to safely compute untrusted bytecode"
+	depends on PROC_FS && BROKEN
+	default y
+	help
+	  This kernel feature is useful for number crunching applications
+	  that may need to compute untrusted bytecode during their
+	  execution. By using pipes or other transports made available to
+	  the process as file descriptors supporting the read/write
+	  syscalls, it's possible to isolate those applications in
+	  their own address space using seccomp. Once seccomp is
+	  enabled via /proc/<pid>/seccomp, it cannot be disabled
+	  and the task is only allowed to execute a few safe syscalls
+	  defined by each seccomp mode.
+
+	  If unsure, say Y. Only embedded should say N here.
+
 endmenu
 
 config RWSEM_GENERIC_SPINLOCK
@@ -2025,52 +2075,11 @@
 	bool
 	default y if MIPS32_O32 || MIPS32_N32
 
-config SECCOMP
-	bool "Enable seccomp to safely compute untrusted bytecode"
-	depends on PROC_FS && BROKEN
-	default y
-	help
-	  This kernel feature is useful for number crunching applications
-	  that may need to compute untrusted bytecode during their
-	  execution. By using pipes or other transports made available to
-	  the process as file descriptors supporting the read/write
-	  syscalls, it's possible to isolate those applications in
-	  their own address space using seccomp. Once seccomp is
-	  enabled via /proc/<pid>/seccomp, it cannot be disabled
-	  and the task is only allowed to execute a few safe syscalls
-	  defined by each seccomp mode.
+endmenu
 
-	  If unsure, say Y. Only embedded should say N here.
+menu "Power management options"
 
-config PM
-	bool "Power Management support (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && SOC_AU1X00
-
-config APM
-        tristate "Advanced Power Management Emulation"
-	depends on PM
-        ---help---
-	  APM is a BIOS specification for saving power using several different
-	  techniques. This is mostly useful for battery powered systems with
-	  APM compliant BIOSes. If you say Y here, the system time will be
-	  reset after a RESUME operation, the /proc/apm device will provide
-	  battery status information, and user-space programs will receive
-	  notification of APM "events" (e.g. battery status change).
-
-	  In order to use APM, you will need supporting software. For location
-	  and more information, read <file:Documentation/pm.txt> and the
-	  Battery Powered Linux mini-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  This driver does not spin down disk drives (see the hdparm(8)
-	  manpage ("man 8 hdparm") for that), and it doesn't turn off
-	  VESA-compliant "green" monitors.
-
-	  Generally, if you don't have a battery in your machine, there isn't
-	  much point in using this driver and you should say N. If you get
-	  random kernel OOPSes or reboots that don't seem to be related to
-	  anything, try disabling/enabling this option (or disabling/enabling
-	  APM in your BIOS).
+source "kernel/power/Kconfig"
 
 endmenu
 
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug
index 5d6afb5..9351f1c 100644
--- a/arch/mips/Kconfig.debug
+++ b/arch/mips/Kconfig.debug
@@ -22,10 +22,10 @@
 	string "Default kernel command string"
 	default ""
 	help
-          On some platforms, there is currently no way for the boot loader to
-          pass arguments to the kernel. For these platforms, you can supply
-          some command-line options at build time by entering them here.  In
-          other cases you can specify kernel args so that you don't have
+	  On some platforms, there is currently no way for the boot loader to
+	  pass arguments to the kernel. For these platforms, you can supply
+	  some command-line options at build time by entering them here.  In
+	  other cases you can specify kernel args so that you don't have
 	  to set them up in board prom initialization routines.
 
 config DEBUG_STACK_USAGE
diff --git a/arch/mips/arc/identify.c b/arch/mips/arc/identify.c
index 3ba7c47..4b90736 100644
--- a/arch/mips/arc/identify.c
+++ b/arch/mips/arc/identify.c
@@ -77,7 +77,7 @@
 {
 	int i;
 
-	for (i = 0; i < (sizeof(mach_table) / sizeof (mach_table[0])); i++) {
+	for (i = 0; i < ARRAY_SIZE(mach_table); i++) {
 		if (!strcmp(s, mach_table[i].arcname))
 			return &mach_table[i];
 	}
diff --git a/arch/mips/arc/memory.c b/arch/mips/arc/memory.c
index 8a9ef58..456cb81a 100644
--- a/arch/mips/arc/memory.c
+++ b/arch/mips/arc/memory.c
@@ -141,30 +141,20 @@
 	}
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	unsigned long freed = 0;
 	unsigned long addr;
 	int i;
 
 	if (prom_flags & PROM_FLAG_DONT_FREE_TEMP)
-		return 0;
+		return;
 
 	for (i = 0; i < boot_mem_map.nr_map; i++) {
 		if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
 			continue;
 
 		addr = boot_mem_map.map[i].addr;
-		while (addr < boot_mem_map.map[i].addr
-			      + boot_mem_map.map[i].size) {
-			ClearPageReserved(virt_to_page(__va(addr)));
-			init_page_count(virt_to_page(__va(addr)));
-			free_page((unsigned long)__va(addr));
-			addr += PAGE_SIZE;
-			freed += PAGE_SIZE;
-		}
+		free_init_pages("prom memory",
+				addr, addr + boot_mem_map.map[i].size);
 	}
-	printk(KERN_INFO "Freeing prom memory: %ldkb freed\n", freed >> 10);
-
-	return freed;
 }
diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c
index 9cf7b671..ea6e99f 100644
--- a/arch/mips/au1000/common/irq.c
+++ b/arch/mips/au1000/common/irq.c
@@ -233,7 +233,7 @@
 
 
 static struct irq_chip rise_edge_irq_type = {
-	.typename = "Au1000 Rise Edge",
+	.name = "Au1000 Rise Edge",
 	.ack = mask_and_ack_rise_edge_irq,
 	.mask = local_disable_irq,
 	.mask_ack = mask_and_ack_rise_edge_irq,
@@ -242,7 +242,7 @@
 };
 
 static struct irq_chip fall_edge_irq_type = {
-	.typename = "Au1000 Fall Edge",
+	.name = "Au1000 Fall Edge",
 	.ack = mask_and_ack_fall_edge_irq,
 	.mask = local_disable_irq,
 	.mask_ack = mask_and_ack_fall_edge_irq,
@@ -251,7 +251,7 @@
 };
 
 static struct irq_chip either_edge_irq_type = {
-	.typename = "Au1000 Rise or Fall Edge",
+	.name = "Au1000 Rise or Fall Edge",
 	.ack = mask_and_ack_either_edge_irq,
 	.mask = local_disable_irq,
 	.mask_ack = mask_and_ack_either_edge_irq,
@@ -260,7 +260,7 @@
 };
 
 static struct irq_chip level_irq_type = {
-	.typename = "Au1000 Level",
+	.name = "Au1000 Level",
 	.ack = mask_and_ack_level_irq,
 	.mask = local_disable_irq,
 	.mask_ack = mask_and_ack_level_irq,
diff --git a/arch/mips/au1000/common/pci.c b/arch/mips/au1000/common/pci.c
index 9f8ce08..6c25e6c 100644
--- a/arch/mips/au1000/common/pci.c
+++ b/arch/mips/au1000/common/pci.c
@@ -76,13 +76,17 @@
 	}
 
 #ifdef CONFIG_DMA_NONCOHERENT
-	/*
-         *  Set the NC bit in controller for Au1500 pre-AC silicon
-	 */
-	u32 prid = read_c0_prid();
-	if ( (prid & 0xFF000000) == 0x01000000 && prid < 0x01030202) {
-	       au_writel( 1<<16 | au_readl(Au1500_PCI_CFG), Au1500_PCI_CFG);
-	       printk("Non-coherent PCI accesses enabled\n");
+	{
+		/*
+		 *  Set the NC bit in controller for Au1500 pre-AC silicon
+		 */
+		u32 prid = read_c0_prid();
+
+		if ((prid & 0xFF000000) == 0x01000000 && prid < 0x01030202) {
+		       au_writel((1 << 16) | au_readl(Au1500_PCI_CFG),
+			         Au1500_PCI_CFG);
+		       printk("Non-coherent PCI accesses enabled\n");
+		}
 	}
 #endif
 
diff --git a/arch/mips/au1000/common/prom.c b/arch/mips/au1000/common/prom.c
index 6fce60a..a8637cd 100644
--- a/arch/mips/au1000/common/prom.c
+++ b/arch/mips/au1000/common/prom.c
@@ -149,9 +149,8 @@
 	return 0;
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	return 0;
 }
 
 EXPORT_SYMBOL(prom_getcmdline);
diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c
index 919172db..13fe187 100644
--- a/arch/mips/au1000/common/setup.c
+++ b/arch/mips/au1000/common/setup.c
@@ -141,17 +141,20 @@
 /* This routine should be valid for all Au1x based boards */
 phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size)
 {
-	u32 start, end;
-
 	/* Don't fixup 36 bit addresses */
-	if ((phys_addr >> 32) != 0) return phys_addr;
+	if ((phys_addr >> 32) != 0)
+		return phys_addr;
 
 #ifdef CONFIG_PCI
-	start = (u32)Au1500_PCI_MEM_START;
-	end = (u32)Au1500_PCI_MEM_END;
-	/* check for pci memory window */
-	if ((phys_addr >= start) && ((phys_addr + size) < end)) {
-		return (phys_t)((phys_addr - start) + Au1500_PCI_MEM_START);
+	{
+		u32 start, end;
+
+		start = (u32)Au1500_PCI_MEM_START;
+		end = (u32)Au1500_PCI_MEM_END;
+		/* check for pci memory window */
+		if ((phys_addr >= start) && ((phys_addr + size) < end))
+			return (phys_t)
+			       ((phys_addr - start) + Au1500_PCI_MEM_START);
 	}
 #endif
 
diff --git a/arch/mips/au1000/pb1100/board_setup.c b/arch/mips/au1000/pb1100/board_setup.c
index 2d1533f..6bc1f8e 100644
--- a/arch/mips/au1000/pb1100/board_setup.c
+++ b/arch/mips/au1000/pb1100/board_setup.c
@@ -47,8 +47,7 @@
 
 void __init board_setup(void)
 {
-	u32 pin_func;
-	u32 sys_freqctrl, sys_clksrc;
+	volatile void __iomem * base = (volatile void __iomem *) 0xac000000UL;
 
 	// set AUX clock to 12MHz * 8 = 96 MHz
 	au_writel(8, SYS_AUXPLL);
@@ -56,58 +55,62 @@
 	udelay(100);
 
 #ifdef CONFIG_USB_OHCI
-	// configure pins GPIO[14:9] as GPIO
-	pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x80);
+	{
+		u32 pin_func, sys_freqctrl, sys_clksrc;
 
-	/* zero and disable FREQ2 */
-	sys_freqctrl = au_readl(SYS_FREQCTRL0);
-	sys_freqctrl &= ~0xFFF00000;
-	au_writel(sys_freqctrl, SYS_FREQCTRL0);
+		// configure pins GPIO[14:9] as GPIO
+		pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x80);
 
-	/* zero and disable USBH/USBD/IrDA clock */
-	sys_clksrc = au_readl(SYS_CLKSRC);
-	sys_clksrc &= ~0x0000001F;
-	au_writel(sys_clksrc, SYS_CLKSRC);
+		/* zero and disable FREQ2 */
+		sys_freqctrl = au_readl(SYS_FREQCTRL0);
+		sys_freqctrl &= ~0xFFF00000;
+		au_writel(sys_freqctrl, SYS_FREQCTRL0);
 
-	sys_freqctrl = au_readl(SYS_FREQCTRL0);
-	sys_freqctrl &= ~0xFFF00000;
+		/* zero and disable USBH/USBD/IrDA clock */
+		sys_clksrc = au_readl(SYS_CLKSRC);
+		sys_clksrc &= ~0x0000001F;
+		au_writel(sys_clksrc, SYS_CLKSRC);
 
-	sys_clksrc = au_readl(SYS_CLKSRC);
-	sys_clksrc &= ~0x0000001F;
+		sys_freqctrl = au_readl(SYS_FREQCTRL0);
+		sys_freqctrl &= ~0xFFF00000;
 
-	// FREQ2 = aux/2 = 48 MHz
-	sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20));
-	au_writel(sys_freqctrl, SYS_FREQCTRL0);
+		sys_clksrc = au_readl(SYS_CLKSRC);
+		sys_clksrc &= ~0x0000001F;
 
-	/*
-	 * Route 48MHz FREQ2 into USBH/USBD/IrDA
-	 */
-	sys_clksrc |= ((4<<2) | (0<<1) | 0 );
-	au_writel(sys_clksrc, SYS_CLKSRC);
+		// FREQ2 = aux/2 = 48 MHz
+		sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20));
+		au_writel(sys_freqctrl, SYS_FREQCTRL0);
 
-	/* setup the static bus controller */
-	au_writel(0x00000002, MEM_STCFG3);  /* type = PCMCIA */
-	au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */
-	au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */
+		/*
+		 * Route 48MHz FREQ2 into USBH/USBD/IrDA
+		 */
+		sys_clksrc |= ((4<<2) | (0<<1) | 0 );
+		au_writel(sys_clksrc, SYS_CLKSRC);
 
-	// get USB Functionality pin state (device vs host drive pins)
-	pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
-	// 2nd USB port is USB host
-	pin_func |= 0x8000;
-	au_writel(pin_func, SYS_PINFUNC);
+		/* setup the static bus controller */
+		au_writel(0x00000002, MEM_STCFG3);  /* type = PCMCIA */
+		au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */
+		au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */
+
+		// get USB Functionality pin state (device vs host drive pins)
+		pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
+		// 2nd USB port is USB host
+		pin_func |= 0x8000;
+		au_writel(pin_func, SYS_PINFUNC);
+	}
 #endif // defined (CONFIG_USB_OHCI)
 
 	/* Enable sys bus clock divider when IDLE state or no bus activity. */
 	au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL);
 
 	// Enable the RTC if not already enabled
-	if (!(readb(0xac000028) & 0x20)) {
-		writeb(readb(0xac000028) | 0x20, 0xac000028);
+	if (!(readb(base + 0x28) & 0x20)) {
+		writeb(readb(base + 0x28) | 0x20, base + 0x28);
 		au_sync();
 	}
 	// Put the clock in BCD mode
-	if (readb(0xac00002C) & 0x4) { /* reg B */
-		writeb(readb(0xac00002c) & ~0x4, 0xac00002c);
+	if (readb(base + 0x2C) & 0x4) { /* reg B */
+		writeb(readb(base + 0x2c) & ~0x4, base + 0x2c);
 		au_sync();
 	}
 }
diff --git a/arch/mips/au1000/pb1200/irqmap.c b/arch/mips/au1000/pb1200/irqmap.c
index 91983ba..b73b2d1 100644
--- a/arch/mips/au1000/pb1200/irqmap.c
+++ b/arch/mips/au1000/pb1200/irqmap.c
@@ -137,33 +137,20 @@
 	return;
 }
 
-static inline void pb1200_mask_and_ack_irq(unsigned int irq_nr)
-{
-	pb1200_disable_irq( irq_nr );
-}
-
-static void pb1200_end_irq(unsigned int irq_nr)
-{
-	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
-		pb1200_enable_irq(irq_nr);
-	}
-}
-
 static struct irq_chip external_irq_type =
 {
 #ifdef CONFIG_MIPS_PB1200
-	"Pb1200 Ext",
+	.name = "Pb1200 Ext",
 #endif
 #ifdef CONFIG_MIPS_DB1200
-	"Db1200 Ext",
+	.name = "Db1200 Ext",
 #endif
-	pb1200_startup_irq,
-	pb1200_shutdown_irq,
-	pb1200_enable_irq,
-	pb1200_disable_irq,
-	pb1200_mask_and_ack_irq,
-	pb1200_end_irq,
-	NULL
+	.startup  = pb1200_startup_irq,
+	.shutdown = pb1200_shutdown_irq,
+	.ack      = pb1200_disable_irq,
+	.mask     = pb1200_disable_irq,
+	.mask_ack = pb1200_disable_irq,
+	.unmask   = pb1200_enable_irq,
 };
 
 void _board_init_irq(void)
@@ -172,7 +159,8 @@
 
 	for (irq_nr = PB1200_INT_BEGIN; irq_nr <= PB1200_INT_END; irq_nr++)
 	{
-		irq_desc[irq_nr].chip = &external_irq_type;
+		set_irq_chip_and_handler(irq_nr, &external_irq_type,
+					 handle_level_irq);
 		pb1200_disable_irq(irq_nr);
 	}
 
diff --git a/arch/mips/basler/excite/excite_irq.c b/arch/mips/basler/excite/excite_irq.c
index 2e2061a..1ecab63 100644
--- a/arch/mips/basler/excite/excite_irq.c
+++ b/arch/mips/basler/excite/excite_irq.c
@@ -47,9 +47,9 @@
  */
 void __init arch_init_irq(void)
 {
-	mips_cpu_irq_init(0);
-	rm7k_cpu_irq_init(8);
-	rm9k_cpu_irq_init(12);
+	mips_cpu_irq_init();
+	rm7k_cpu_irq_init();
+	rm9k_cpu_irq_init();
 
 #ifdef CONFIG_KGDB
 	excite_kgdb_init();
diff --git a/arch/mips/cobalt/irq.c b/arch/mips/cobalt/irq.c
index 4c46f0e..fe93b84 100644
--- a/arch/mips/cobalt/irq.c
+++ b/arch/mips/cobalt/irq.c
@@ -104,7 +104,7 @@
 	GT_WRITE(GT_INTRMASK_OFS, 0);
 
 	init_i8259_irqs();				/*  0 ... 15 */
-	mips_cpu_irq_init(COBALT_CPU_IRQ);		/* 16 ... 23 */
+	mips_cpu_irq_init();		/* 16 ... 23 */
 
 	/*
 	 * Mask all cpu interrupts
diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c
index e8f0f20..a4b69b5 100644
--- a/arch/mips/cobalt/setup.c
+++ b/arch/mips/cobalt/setup.c
@@ -204,8 +204,7 @@
 	add_memory_region(0x0, memsz, BOOT_MEM_RAM);
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
 	/* Nothing to do! */
-	return 0;
 }
diff --git a/arch/mips/ddb5xxx/common/prom.c b/arch/mips/ddb5xxx/common/prom.c
index efef0f5..54a857b 100644
--- a/arch/mips/ddb5xxx/common/prom.c
+++ b/arch/mips/ddb5xxx/common/prom.c
@@ -59,9 +59,8 @@
 #endif
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	return 0;
 }
 
 #if defined(CONFIG_DDB5477)
diff --git a/arch/mips/ddb5xxx/ddb5477/irq.c b/arch/mips/ddb5xxx/ddb5477/irq.c
index a8bd2e6..2b23234 100644
--- a/arch/mips/ddb5xxx/ddb5477/irq.c
+++ b/arch/mips/ddb5xxx/ddb5477/irq.c
@@ -17,6 +17,7 @@
 #include <linux/ptrace.h>
 
 #include <asm/i8259.h>
+#include <asm/irq_cpu.h>
 #include <asm/system.h>
 #include <asm/mipsregs.h>
 #include <asm/debug.h>
@@ -73,7 +74,6 @@
 }
 
 extern void vrc5477_irq_init(u32 base);
-extern void mips_cpu_irq_init(u32 base);
 static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL };
 
 void __init arch_init_irq(void)
@@ -125,7 +125,7 @@
 
 	/* init all controllers */
 	init_i8259_irqs();
-	mips_cpu_irq_init(CPU_IRQ_BASE);
+	mips_cpu_irq_init();
 	vrc5477_irq_init(VRC5477_IRQ_BASE);
 
 
@@ -146,8 +146,7 @@
 	irq = *(volatile u8 *) KSEG1ADDR(DDB_PCI_IACK_BASE);
 	ddb_out32(DDB_PCIINIT10, reg);
 
-	/* i8259.c set the base vector to be 0x0 */
-	return irq + I8259_IRQ_BASE;
+	return irq;
 }
 /*
  * the first level int-handler will jump here if it is a vrc5477 irq
@@ -177,7 +176,7 @@
 		/* check for i8259 interrupts */
 		if (intStatus & (1 << VRC5477_I8259_CASCADE)) {
 			int i8259_irq = i8259_interrupt_ack();
-			do_IRQ(I8259_IRQ_BASE + i8259_irq);
+			do_IRQ(i8259_irq);
 			return;
 		}
 	}
diff --git a/arch/mips/ddb5xxx/ddb5477/irq_5477.c b/arch/mips/ddb5xxx/ddb5477/irq_5477.c
index 96249aa..98c3b15 100644
--- a/arch/mips/ddb5xxx/ddb5477/irq_5477.c
+++ b/arch/mips/ddb5xxx/ddb5477/irq_5477.c
@@ -82,7 +82,7 @@
 }
 
 struct irq_chip vrc5477_irq_controller = {
-	.typename = "vrc5477_irq",
+	.name = "vrc5477_irq",
 	.ack = vrc5477_irq_ack,
 	.mask = vrc5477_irq_disable,
 	.mask_ack = vrc5477_irq_ack,
diff --git a/arch/mips/dec/Makefile b/arch/mips/dec/Makefile
index ed181fd..8b790c2 100644
--- a/arch/mips/dec/Makefile
+++ b/arch/mips/dec/Makefile
@@ -6,6 +6,7 @@
 		   kn02-irq.o kn02xa-berr.o reset.o setup.o time.o
 
 obj-$(CONFIG_PROM_CONSOLE)	+= promcon.o
+obj-$(CONFIG_TC)		+= tc.o
 obj-$(CONFIG_CPU_HAS_WB)	+= wbflush.o
 
 EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/dec/ioasic-irq.c b/arch/mips/dec/ioasic-irq.c
index 4c7cb40..3acb133 100644
--- a/arch/mips/dec/ioasic-irq.c
+++ b/arch/mips/dec/ioasic-irq.c
@@ -62,7 +62,7 @@
 }
 
 static struct irq_chip ioasic_irq_type = {
-	.typename = "IO-ASIC",
+	.name = "IO-ASIC",
 	.ack = ack_ioasic_irq,
 	.mask = mask_ioasic_irq,
 	.mask_ack = ack_ioasic_irq,
@@ -84,7 +84,7 @@
 }
 
 static struct irq_chip ioasic_dma_irq_type = {
-	.typename = "IO-ASIC-DMA",
+	.name = "IO-ASIC-DMA",
 	.ack = ack_ioasic_dma_irq,
 	.mask = mask_ioasic_dma_irq,
 	.mask_ack = ack_ioasic_dma_irq,
diff --git a/arch/mips/dec/kn02-irq.c b/arch/mips/dec/kn02-irq.c
index 916e46b..02439dc 100644
--- a/arch/mips/dec/kn02-irq.c
+++ b/arch/mips/dec/kn02-irq.c
@@ -58,7 +58,7 @@
 }
 
 static struct irq_chip kn02_irq_type = {
-	.typename = "KN02-CSR",
+	.name = "KN02-CSR",
 	.ack = ack_kn02_irq,
 	.mask = mask_kn02_irq,
 	.mask_ack = ack_kn02_irq,
diff --git a/arch/mips/dec/prom/identify.c b/arch/mips/dec/prom/identify.c
index 81d5e87..c4e3c1e 100644
--- a/arch/mips/dec/prom/identify.c
+++ b/arch/mips/dec/prom/identify.c
@@ -88,6 +88,7 @@
 {
 	dec_kn_slot_base = KN02_SLOT_BASE;
 	dec_kn_slot_size = KN02_SLOT_SIZE;
+	dec_tc_bus = 1;
 
 	dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + KN02_RTC);
 }
@@ -96,6 +97,7 @@
 {
 	dec_kn_slot_base = KN02XA_SLOT_BASE;
 	dec_kn_slot_size = IOASIC_SLOT_SIZE;
+	dec_tc_bus = 1;
 
 	ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL);
 	dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY);
@@ -105,6 +107,7 @@
 {
 	dec_kn_slot_base = KN03_SLOT_BASE;
 	dec_kn_slot_size = IOASIC_SLOT_SIZE;
+	dec_tc_bus = 1;
 
 	ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL);
 	dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY);
diff --git a/arch/mips/dec/prom/memory.c b/arch/mips/dec/prom/memory.c
index 3aa01d2..5a557e2 100644
--- a/arch/mips/dec/prom/memory.c
+++ b/arch/mips/dec/prom/memory.c
@@ -92,9 +92,9 @@
 		rex_setup_memory_region();
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	unsigned long addr, end;
+	unsigned long end;
 
 	/*
 	 * Free everything below the kernel itself but leave
@@ -114,16 +114,5 @@
 #endif
 		end = __pa(&_text);
 
-	addr = PAGE_SIZE;
-	while (addr < end) {
-		ClearPageReserved(virt_to_page(__va(addr)));
-		init_page_count(virt_to_page(__va(addr)));
-		free_page((unsigned long)__va(addr));
-		addr += PAGE_SIZE;
-	}
-
-	printk("Freeing unused PROM memory: %ldkb freed\n",
-	       (end - PAGE_SIZE) >> 10);
-
-	return end - PAGE_SIZE;
+	free_init_pages("unused PROM memory", PAGE_SIZE, end);
 }
diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c
index d34032a..b8a5e75 100644
--- a/arch/mips/dec/setup.c
+++ b/arch/mips/dec/setup.c
@@ -53,6 +53,8 @@
 EXPORT_SYMBOL(dec_kn_slot_base);
 EXPORT_SYMBOL(dec_kn_slot_size);
 
+int dec_tc_bus;
+
 spinlock_t ioasic_ssr_lock;
 
 volatile u32 *ioasic_base;
@@ -234,7 +236,7 @@
 	memcpy(&cpu_mask_nr_tbl, &kn01_cpu_mask_nr_tbl,
 		sizeof(kn01_cpu_mask_nr_tbl));
 
-	mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
+	mips_cpu_irq_init();
 
 }				/* dec_init_kn01 */
 
@@ -309,7 +311,7 @@
 	memcpy(&cpu_mask_nr_tbl, &kn230_cpu_mask_nr_tbl,
 		sizeof(kn230_cpu_mask_nr_tbl));
 
-	mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
+	mips_cpu_irq_init();
 
 }				/* dec_init_kn230 */
 
@@ -403,7 +405,7 @@
 	memcpy(&asic_mask_nr_tbl, &kn02_asic_mask_nr_tbl,
 		sizeof(kn02_asic_mask_nr_tbl));
 
-	mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
+	mips_cpu_irq_init();
 	init_kn02_irqs(KN02_IRQ_BASE);
 
 }				/* dec_init_kn02 */
@@ -504,7 +506,7 @@
 	memcpy(&asic_mask_nr_tbl, &kn02ba_asic_mask_nr_tbl,
 		sizeof(kn02ba_asic_mask_nr_tbl));
 
-	mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
+	mips_cpu_irq_init();
 	init_ioasic_irqs(IO_IRQ_BASE);
 
 }				/* dec_init_kn02ba */
@@ -601,7 +603,7 @@
 	memcpy(&asic_mask_nr_tbl, &kn02ca_asic_mask_nr_tbl,
 		sizeof(kn02ca_asic_mask_nr_tbl));
 
-	mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
+	mips_cpu_irq_init();
 	init_ioasic_irqs(IO_IRQ_BASE);
 
 }				/* dec_init_kn02ca */
@@ -702,7 +704,7 @@
 	memcpy(&asic_mask_nr_tbl, &kn03_asic_mask_nr_tbl,
 		sizeof(kn03_asic_mask_nr_tbl));
 
-	mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
+	mips_cpu_irq_init();
 	init_ioasic_irqs(IO_IRQ_BASE);
 
 }				/* dec_init_kn03 */
diff --git a/arch/mips/dec/tc.c b/arch/mips/dec/tc.c
new file mode 100644
index 0000000..732027c
--- /dev/null
+++ b/arch/mips/dec/tc.c
@@ -0,0 +1,95 @@
+/*
+ *	TURBOchannel architecture calls.
+ *
+ *	Copyright (c) Harald Koerfgen, 1998
+ *	Copyright (c) 2001, 2003, 2005, 2006  Maciej W. Rozycki
+ *	Copyright (c) 2005  James Simmons
+ *
+ *	This file is subject to the terms and conditions of the GNU
+ *	General Public License.  See the file "COPYING" in the main
+ *	directory of this archive for more details.
+ */
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/tc.h>
+#include <linux/types.h>
+
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+#include <asm/paccess.h>
+
+#include <asm/dec/interrupts.h>
+#include <asm/dec/prom.h>
+#include <asm/dec/system.h>
+
+/*
+ * Protected read byte from TURBOchannel slot space.
+ */
+int tc_preadb(u8 *valp, void __iomem *addr)
+{
+	return get_dbe(*valp, (u8 *)addr);
+}
+
+/*
+ * Get TURBOchannel bus information as specified by the spec, plus
+ * the slot space base address and the number of slots.
+ */
+int __init tc_bus_get_info(struct tc_bus *tbus)
+{
+	if (!dec_tc_bus)
+		return -ENXIO;
+
+	memcpy(&tbus->info, rex_gettcinfo(), sizeof(tbus->info));
+	tbus->slot_base = CPHYSADDR((long)rex_slot_address(0));
+
+	switch (mips_machtype) {
+	case MACH_DS5000_200:
+		tbus->num_tcslots = 7;
+		break;
+	case MACH_DS5000_2X0:
+	case MACH_DS5900:
+		tbus->ext_slot_base = 0x20000000;
+		tbus->ext_slot_size = 0x20000000;
+		/* fall through */
+	case MACH_DS5000_1XX:
+		tbus->num_tcslots = 3;
+		break;
+	case MACH_DS5000_XX:
+		tbus->num_tcslots = 2;
+	default:
+		break;
+	}
+	return 0;
+}
+
+/*
+ * Get the IRQ for the specified slot.
+ */
+void __init tc_device_get_irq(struct tc_dev *tdev)
+{
+	switch (tdev->slot) {
+	case 0:
+		tdev->interrupt = dec_interrupt[DEC_IRQ_TC0];
+		break;
+	case 1:
+		tdev->interrupt = dec_interrupt[DEC_IRQ_TC1];
+		break;
+	case 2:
+		tdev->interrupt = dec_interrupt[DEC_IRQ_TC2];
+		break;
+	/*
+	 * Yuck! DS5000/200 onboard devices
+	 */
+	case 5:
+		tdev->interrupt = dec_interrupt[DEC_IRQ_TC5];
+		break;
+	case 6:
+		tdev->interrupt = dec_interrupt[DEC_IRQ_TC6];
+		break;
+	default:
+		tdev->interrupt = -1;
+		break;
+	}
+}
diff --git a/arch/mips/emma2rh/common/irq_emma2rh.c b/arch/mips/emma2rh/common/irq_emma2rh.c
index 8d880f0..96df37b 100644
--- a/arch/mips/emma2rh/common/irq_emma2rh.c
+++ b/arch/mips/emma2rh/common/irq_emma2rh.c
@@ -57,7 +57,7 @@
 }
 
 struct irq_chip emma2rh_irq_controller = {
-	.typename = "emma2rh_irq",
+	.name = "emma2rh_irq",
 	.ack = emma2rh_irq_disable,
 	.mask = emma2rh_irq_disable,
 	.mask_ack = emma2rh_irq_disable,
diff --git a/arch/mips/emma2rh/markeins/irq.c b/arch/mips/emma2rh/markeins/irq.c
index c93369c..3299b6d 100644
--- a/arch/mips/emma2rh/markeins/irq.c
+++ b/arch/mips/emma2rh/markeins/irq.c
@@ -106,7 +106,7 @@
 	emma2rh_irq_init(EMMA2RH_IRQ_BASE);
 	emma2rh_sw_irq_init(EMMA2RH_SW_IRQ_BASE);
 	emma2rh_gpio_irq_init(EMMA2RH_GPIO_IRQ_BASE);
-	mips_cpu_irq_init(CPU_IRQ_BASE);
+	mips_cpu_irq_init();
 
 	/* setup cascade interrupts */
 	setup_irq(EMMA2RH_IRQ_BASE + EMMA2RH_SW_CASCADE, &irq_cascade);
diff --git a/arch/mips/emma2rh/markeins/irq_markeins.c b/arch/mips/emma2rh/markeins/irq_markeins.c
index 2116d9b..fba5c15 100644
--- a/arch/mips/emma2rh/markeins/irq_markeins.c
+++ b/arch/mips/emma2rh/markeins/irq_markeins.c
@@ -49,7 +49,7 @@
 }
 
 struct irq_chip emma2rh_sw_irq_controller = {
-	.typename = "emma2rh_sw_irq",
+	.name = "emma2rh_sw_irq",
 	.ack = emma2rh_sw_irq_disable,
 	.mask = emma2rh_sw_irq_disable,
 	.mask_ack = emma2rh_sw_irq_disable,
@@ -115,7 +115,7 @@
 }
 
 struct irq_chip emma2rh_gpio_irq_controller = {
-	.typename = "emma2rh_gpio_irq",
+	.name = "emma2rh_gpio_irq",
 	.ack = emma2rh_gpio_irq_ack,
 	.mask = emma2rh_gpio_irq_disable,
 	.mask_ack = emma2rh_gpio_irq_ack,
diff --git a/arch/mips/gt64120/ev64120/irq.c b/arch/mips/gt64120/ev64120/irq.c
index b3e5796..04572b9 100644
--- a/arch/mips/gt64120/ev64120/irq.c
+++ b/arch/mips/gt64120/ev64120/irq.c
@@ -88,7 +88,7 @@
 }
 
 static struct irq_chip ev64120_irq_type = {
-	.typename	= "EV64120",
+	.name		= "EV64120",
 	.ack		= disable_ev64120_irq,
 	.mask		= disable_ev64120_irq,
 	.mask_ack	= disable_ev64120_irq,
diff --git a/arch/mips/gt64120/ev64120/setup.c b/arch/mips/gt64120/ev64120/setup.c
index 99c8d42..477848c 100644
--- a/arch/mips/gt64120/ev64120/setup.c
+++ b/arch/mips/gt64120/ev64120/setup.c
@@ -59,9 +59,8 @@
  */
 extern struct pci_ops galileo_pci_ops;
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	return 0;
 }
 
 /*
diff --git a/arch/mips/gt64120/momenco_ocelot/dbg_io.c b/arch/mips/gt64120/momenco_ocelot/dbg_io.c
index 2128684..32d6fb4 100644
--- a/arch/mips/gt64120/momenco_ocelot/dbg_io.c
+++ b/arch/mips/gt64120/momenco_ocelot/dbg_io.c
@@ -1,6 +1,4 @@
 
-#ifdef CONFIG_KGDB
-
 #include <asm/serial.h> /* For the serial port location and base baud */
 
 /* --- CONFIG --- */
@@ -121,5 +119,3 @@
 	UART16550_WRITE(OFS_SEND_BUFFER, byte);
 	return 1;
 }
-
-#endif
diff --git a/arch/mips/gt64120/momenco_ocelot/irq.c b/arch/mips/gt64120/momenco_ocelot/irq.c
index d929440..2585d9d 100644
--- a/arch/mips/gt64120/momenco_ocelot/irq.c
+++ b/arch/mips/gt64120/momenco_ocelot/irq.c
@@ -90,6 +90,6 @@
 	clear_c0_status(ST0_IM);
 	local_irq_disable();
 
-	mips_cpu_irq_init(0);
-	rm7k_cpu_irq_init(8);
+	mips_cpu_irq_init();
+	rm7k_cpu_irq_init();
 }
diff --git a/arch/mips/gt64120/momenco_ocelot/prom.c b/arch/mips/gt64120/momenco_ocelot/prom.c
index 8677b6d..78f393b 100644
--- a/arch/mips/gt64120/momenco_ocelot/prom.c
+++ b/arch/mips/gt64120/momenco_ocelot/prom.c
@@ -67,7 +67,6 @@
 	add_memory_region(0, 64 << 20, BOOT_MEM_RAM);
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	return 0;
 }
diff --git a/arch/mips/gt64120/wrppmc/irq.c b/arch/mips/gt64120/wrppmc/irq.c
index eedfc24..d3d9659 100644
--- a/arch/mips/gt64120/wrppmc/irq.c
+++ b/arch/mips/gt64120/wrppmc/irq.c
@@ -63,7 +63,7 @@
 void __init arch_init_irq(void)
 {
 	/* IRQ 0 - 7 are for MIPS common irq_cpu controller */
-	mips_cpu_irq_init(0);
+	mips_cpu_irq_init();
 
 	gt64120_init_pic();
 }
diff --git a/arch/mips/gt64120/wrppmc/setup.c b/arch/mips/gt64120/wrppmc/setup.c
index 429afc4..121188d 100644
--- a/arch/mips/gt64120/wrppmc/setup.c
+++ b/arch/mips/gt64120/wrppmc/setup.c
@@ -93,9 +93,8 @@
 }
 #endif /* WRPPMC_EARLY_DEBUG */
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	return 0;
 }
 
 #ifdef CONFIG_SERIAL_8250
diff --git a/arch/mips/jazz/irq.c b/arch/mips/jazz/irq.c
index f8d417b..295892e 100644
--- a/arch/mips/jazz/irq.c
+++ b/arch/mips/jazz/irq.c
@@ -40,7 +40,7 @@
 }
 
 static struct irq_chip r4030_irq_type = {
-	.typename = "R4030",
+	.name = "R4030",
 	.ack = disable_r4030_irq,
 	.mask = disable_r4030_irq,
 	.mask_ack = disable_r4030_irq,
diff --git a/arch/mips/jmr3927/common/prom.c b/arch/mips/jmr3927/common/prom.c
index 5d5838f..aa481b7 100644
--- a/arch/mips/jmr3927/common/prom.c
+++ b/arch/mips/jmr3927/common/prom.c
@@ -75,7 +75,6 @@
 	*cp = '\0';
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	return 0;
 }
diff --git a/arch/mips/jmr3927/rbhma3100/irq.c b/arch/mips/jmr3927/rbhma3100/irq.c
index 3da49c5..7d2c203 100644
--- a/arch/mips/jmr3927/rbhma3100/irq.c
+++ b/arch/mips/jmr3927/rbhma3100/irq.c
@@ -439,7 +439,7 @@
 }
 
 static struct irq_chip jmr3927_irq_controller = {
-	.typename = "jmr3927_irq",
+	.name = "jmr3927_irq",
 	.ack = jmr3927_irq_ack,
 	.mask = jmr3927_irq_disable,
 	.mask_ack = jmr3927_irq_ack,
diff --git a/arch/mips/jmr3927/rbhma3100/setup.c b/arch/mips/jmr3927/rbhma3100/setup.c
index 138f25e..7ca3d6d 100644
--- a/arch/mips/jmr3927/rbhma3100/setup.c
+++ b/arch/mips/jmr3927/rbhma3100/setup.c
@@ -434,7 +434,7 @@
 
 	/* DMA */
 	tx3927_dmaptr->mcr = 0;
-	for (i = 0; i < sizeof(tx3927_dmaptr->ch) / sizeof(tx3927_dmaptr->ch[0]); i++) {
+	for (i = 0; i < ARRAY_SIZE(tx3927_dmaptr->ch); i++) {
 		/* reset channel */
 		tx3927_dmaptr->ch[i].ccr = TX3927_DMA_CCR_CHRST;
 		tx3927_dmaptr->ch[i].ccr = 0;
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index bbbb8d7..1bf2c84 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -14,8 +14,6 @@
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-$(CONFIG_MODULES)		+= mips_ksyms.o module.o
 
-obj-$(CONFIG_APM)		+= apm.o
-
 obj-$(CONFIG_CPU_R3000)		+= r2300_fpu.o r2300_switch.o
 obj-$(CONFIG_CPU_TX39XX)	+= r2300_fpu.o r2300_switch.o
 obj-$(CONFIG_CPU_TX49XX)	+= r4k_fpu.o r4k_switch.o
diff --git a/arch/mips/kernel/apm.c b/arch/mips/kernel/apm.c
deleted file mode 100644
index ba16d07..0000000
--- a/arch/mips/kernel/apm.c
+++ /dev/null
@@ -1,604 +0,0 @@
-/*
- * bios-less APM driver for MIPS Linux
- *  Jamey Hicks <jamey@crl.dec.com>
- *  adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com)
- *
- * APM 1.2 Reference:
- *   Intel Corporation, Microsoft Corporation. Advanced Power Management
- *   (APM) BIOS Interface Specification, Revision 1.2, February 1996.
- *
- * [This document is available from Microsoft at:
- *    http://www.microsoft.com/hwdev/busbios/amp_12.htm]
- */
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/timer.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include <linux/miscdevice.h>
-#include <linux/apm_bios.h>
-#include <linux/capability.h>
-#include <linux/sched.h>
-#include <linux/pm.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/init.h>
-#include <linux/completion.h>
-
-#include <asm/apm.h> /* apm_power_info */
-#include <asm/system.h>
-
-/*
- * The apm_bios device is one of the misc char devices.
- * This is its minor number.
- */
-#define APM_MINOR_DEV	134
-
-/*
- * See Documentation/Config.help for the configuration options.
- *
- * Various options can be changed at boot time as follows:
- * (We allow underscores for compatibility with the modules code)
- *	apm=on/off			enable/disable APM
- */
-
-/*
- * Maximum number of events stored
- */
-#define APM_MAX_EVENTS		16
-
-struct apm_queue {
-	unsigned int		event_head;
-	unsigned int		event_tail;
-	apm_event_t		events[APM_MAX_EVENTS];
-};
-
-/*
- * The per-file APM data
- */
-struct apm_user {
-	struct list_head	list;
-
-	unsigned int		suser: 1;
-	unsigned int		writer: 1;
-	unsigned int		reader: 1;
-
-	int			suspend_result;
-	unsigned int		suspend_state;
-#define SUSPEND_NONE	0		/* no suspend pending */
-#define SUSPEND_PENDING	1		/* suspend pending read */
-#define SUSPEND_READ	2		/* suspend read, pending ack */
-#define SUSPEND_ACKED	3		/* suspend acked */
-#define SUSPEND_DONE	4		/* suspend completed */
-
-	struct apm_queue	queue;
-};
-
-/*
- * Local variables
- */
-static int suspends_pending;
-static int apm_disabled;
-static int mips_apm_active;
-
-static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
-static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
-
-/*
- * This is a list of everyone who has opened /dev/apm_bios
- */
-static DECLARE_RWSEM(user_list_lock);
-static LIST_HEAD(apm_user_list);
-
-/*
- * kapmd info.  kapmd provides us a process context to handle
- * "APM" events within - specifically necessary if we're going
- * to be suspending the system.
- */
-static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait);
-static DECLARE_COMPLETION(kapmd_exit);
-static DEFINE_SPINLOCK(kapmd_queue_lock);
-static struct apm_queue kapmd_queue;
-
-
-static const char driver_version[] = "1.13";	/* no spaces */
-
-
-
-/*
- * Compatibility cruft until the IPAQ people move over to the new
- * interface.
- */
-static void __apm_get_power_status(struct apm_power_info *info)
-{
-}
-
-/*
- * This allows machines to provide their own "apm get power status" function.
- */
-void (*apm_get_power_status)(struct apm_power_info *) = __apm_get_power_status;
-EXPORT_SYMBOL(apm_get_power_status);
-
-
-/*
- * APM event queue management.
- */
-static inline int queue_empty(struct apm_queue *q)
-{
-	return q->event_head == q->event_tail;
-}
-
-static inline apm_event_t queue_get_event(struct apm_queue *q)
-{
-	q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
-	return q->events[q->event_tail];
-}
-
-static void queue_add_event(struct apm_queue *q, apm_event_t event)
-{
-	q->event_head = (q->event_head + 1) % APM_MAX_EVENTS;
-	if (q->event_head == q->event_tail) {
-		static int notified;
-
-		if (notified++ == 0)
-		    printk(KERN_ERR "apm: an event queue overflowed\n");
-		q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
-	}
-	q->events[q->event_head] = event;
-}
-
-static void queue_event_one_user(struct apm_user *as, apm_event_t event)
-{
-	if (as->suser && as->writer) {
-		switch (event) {
-		case APM_SYS_SUSPEND:
-		case APM_USER_SUSPEND:
-			/*
-			 * If this user already has a suspend pending,
-			 * don't queue another one.
-			 */
-			if (as->suspend_state != SUSPEND_NONE)
-				return;
-
-			as->suspend_state = SUSPEND_PENDING;
-			suspends_pending++;
-			break;
-		}
-	}
-	queue_add_event(&as->queue, event);
-}
-
-static void queue_event(apm_event_t event, struct apm_user *sender)
-{
-	struct apm_user *as;
-
-	down_read(&user_list_lock);
-	list_for_each_entry(as, &apm_user_list, list) {
-		if (as != sender && as->reader)
-			queue_event_one_user(as, event);
-	}
-	up_read(&user_list_lock);
-	wake_up_interruptible(&apm_waitqueue);
-}
-
-static void apm_suspend(void)
-{
-	struct apm_user *as;
-	int err = pm_suspend(PM_SUSPEND_MEM);
-
-	/*
-	 * Anyone on the APM queues will think we're still suspended.
-	 * Send a message so everyone knows we're now awake again.
-	 */
-	queue_event(APM_NORMAL_RESUME, NULL);
-
-	/*
-	 * Finally, wake up anyone who is sleeping on the suspend.
-	 */
-	down_read(&user_list_lock);
-	list_for_each_entry(as, &apm_user_list, list) {
-		as->suspend_result = err;
-		as->suspend_state = SUSPEND_DONE;
-	}
-	up_read(&user_list_lock);
-
-	wake_up(&apm_suspend_waitqueue);
-}
-
-static ssize_t apm_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos)
-{
-	struct apm_user *as = fp->private_data;
-	apm_event_t event;
-	int i = count, ret = 0;
-
-	if (count < sizeof(apm_event_t))
-		return -EINVAL;
-
-	if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK)
-		return -EAGAIN;
-
-	wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue));
-
-	while ((i >= sizeof(event)) && !queue_empty(&as->queue)) {
-		event = queue_get_event(&as->queue);
-
-		ret = -EFAULT;
-		if (copy_to_user(buf, &event, sizeof(event)))
-			break;
-
-		if (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND)
-			as->suspend_state = SUSPEND_READ;
-
-		buf += sizeof(event);
-		i -= sizeof(event);
-	}
-
-	if (i < count)
-		ret = count - i;
-
-	return ret;
-}
-
-static unsigned int apm_poll(struct file *fp, poll_table * wait)
-{
-	struct apm_user *as = fp->private_data;
-
-	poll_wait(fp, &apm_waitqueue, wait);
-	return queue_empty(&as->queue) ? 0 : POLLIN | POLLRDNORM;
-}
-
-/*
- * apm_ioctl - handle APM ioctl
- *
- * APM_IOC_SUSPEND
- *   This IOCTL is overloaded, and performs two functions.  It is used to:
- *     - initiate a suspend
- *     - acknowledge a suspend read from /dev/apm_bios.
- *   Only when everyone who has opened /dev/apm_bios with write permission
- *   has acknowledge does the actual suspend happen.
- */
-static int
-apm_ioctl(struct inode * inode, struct file *filp, unsigned int cmd, unsigned long arg)
-{
-	struct apm_user *as = filp->private_data;
-	unsigned long flags;
-	int err = -EINVAL;
-
-	if (!as->suser || !as->writer)
-		return -EPERM;
-
-	switch (cmd) {
-	case APM_IOC_SUSPEND:
-		as->suspend_result = -EINTR;
-
-		if (as->suspend_state == SUSPEND_READ) {
-			/*
-			 * If we read a suspend command from /dev/apm_bios,
-			 * then the corresponding APM_IOC_SUSPEND ioctl is
-			 * interpreted as an acknowledge.
-			 */
-			as->suspend_state = SUSPEND_ACKED;
-			suspends_pending--;
-		} else {
-			/*
-			 * Otherwise it is a request to suspend the system.
-			 * Queue an event for all readers, and expect an
-			 * acknowledge from all writers who haven't already
-			 * acknowledged.
-			 */
-			queue_event(APM_USER_SUSPEND, as);
-		}
-
-		/*
-		 * If there are no further acknowledges required, suspend
-		 * the system.
-		 */
-		if (suspends_pending == 0)
-			apm_suspend();
-
-		/*
-		 * Wait for the suspend/resume to complete.  If there are
-		 * pending acknowledges, we wait here for them.
-		 *
-		 * Note that we need to ensure that the PM subsystem does
-		 * not kick us out of the wait when it suspends the threads.
-		 */
-		flags = current->flags;
-		current->flags |= PF_NOFREEZE;
-
-		/*
-		 * Note: do not allow a thread which is acking the suspend
-		 * to escape until the resume is complete.
-		 */
-		if (as->suspend_state == SUSPEND_ACKED)
-			wait_event(apm_suspend_waitqueue,
-					 as->suspend_state == SUSPEND_DONE);
-		else
-			wait_event_interruptible(apm_suspend_waitqueue,
-					 as->suspend_state == SUSPEND_DONE);
-
-		current->flags = flags;
-		err = as->suspend_result;
-		as->suspend_state = SUSPEND_NONE;
-		break;
-	}
-
-	return err;
-}
-
-static int apm_release(struct inode * inode, struct file * filp)
-{
-	struct apm_user *as = filp->private_data;
-	filp->private_data = NULL;
-
-	down_write(&user_list_lock);
-	list_del(&as->list);
-	up_write(&user_list_lock);
-
-	/*
-	 * We are now unhooked from the chain.  As far as new
-	 * events are concerned, we no longer exist.  However, we
-	 * need to balance suspends_pending, which means the
-	 * possibility of sleeping.
-	 */
-	if (as->suspend_state != SUSPEND_NONE) {
-		suspends_pending -= 1;
-		if (suspends_pending == 0)
-			apm_suspend();
-	}
-
-	kfree(as);
-	return 0;
-}
-
-static int apm_open(struct inode * inode, struct file * filp)
-{
-	struct apm_user *as;
-
-	as = kzalloc(sizeof(*as), GFP_KERNEL);
-	if (as) {
-		/*
-		 * XXX - this is a tiny bit broken, when we consider BSD
-		 * process accounting. If the device is opened by root, we
-		 * instantly flag that we used superuser privs. Who knows,
-		 * we might close the device immediately without doing a
-		 * privileged operation -- cevans
-		 */
-		as->suser = capable(CAP_SYS_ADMIN);
-		as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
-		as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
-
-		down_write(&user_list_lock);
-		list_add(&as->list, &apm_user_list);
-		up_write(&user_list_lock);
-
-		filp->private_data = as;
-	}
-
-	return as ? 0 : -ENOMEM;
-}
-
-static struct file_operations apm_bios_fops = {
-	.owner		= THIS_MODULE,
-	.read		= apm_read,
-	.poll		= apm_poll,
-	.ioctl		= apm_ioctl,
-	.open		= apm_open,
-	.release	= apm_release,
-};
-
-static struct miscdevice apm_device = {
-	.minor		= APM_MINOR_DEV,
-	.name		= "apm_bios",
-	.fops		= &apm_bios_fops
-};
-
-
-#ifdef CONFIG_PROC_FS
-/*
- * Arguments, with symbols from linux/apm_bios.h.
- *
- *   0) Linux driver version (this will change if format changes)
- *   1) APM BIOS Version.  Usually 1.0, 1.1 or 1.2.
- *   2) APM flags from APM Installation Check (0x00):
- *	bit 0: APM_16_BIT_SUPPORT
- *	bit 1: APM_32_BIT_SUPPORT
- *	bit 2: APM_IDLE_SLOWS_CLOCK
- *	bit 3: APM_BIOS_DISABLED
- *	bit 4: APM_BIOS_DISENGAGED
- *   3) AC line status
- *	0x00: Off-line
- *	0x01: On-line
- *	0x02: On backup power (BIOS >= 1.1 only)
- *	0xff: Unknown
- *   4) Battery status
- *	0x00: High
- *	0x01: Low
- *	0x02: Critical
- *	0x03: Charging
- *	0x04: Selected battery not present (BIOS >= 1.2 only)
- *	0xff: Unknown
- *   5) Battery flag
- *	bit 0: High
- *	bit 1: Low
- *	bit 2: Critical
- *	bit 3: Charging
- *	bit 7: No system battery
- *	0xff: Unknown
- *   6) Remaining battery life (percentage of charge):
- *	0-100: valid
- *	-1: Unknown
- *   7) Remaining battery life (time units):
- *	Number of remaining minutes or seconds
- *	-1: Unknown
- *   8) min = minutes; sec = seconds
- */
-static int apm_get_info(char *buf, char **start, off_t fpos, int length)
-{
-	struct apm_power_info info;
-	char *units;
-	int ret;
-
-	info.ac_line_status = 0xff;
-	info.battery_status = 0xff;
-	info.battery_flag   = 0xff;
-	info.battery_life   = -1;
-	info.time	    = -1;
-	info.units	    = -1;
-
-	if (apm_get_power_status)
-		apm_get_power_status(&info);
-
-	switch (info.units) {
-	default:	units = "?";	break;
-	case 0: 	units = "min";	break;
-	case 1: 	units = "sec";	break;
-	}
-
-	ret = sprintf(buf, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
-		     driver_version, APM_32_BIT_SUPPORT,
-		     info.ac_line_status, info.battery_status,
-		     info.battery_flag, info.battery_life,
-		     info.time, units);
-
- 	return ret;
-}
-#endif
-
-static int kapmd(void *arg)
-{
-	daemonize("kapmd");
-	current->flags |= PF_NOFREEZE;
-
-	do {
-		apm_event_t event;
-
-		wait_event_interruptible(kapmd_wait,
-				!queue_empty(&kapmd_queue) || !mips_apm_active);
-
-		if (!mips_apm_active)
-			break;
-
-		spin_lock_irq(&kapmd_queue_lock);
-		event = 0;
-		if (!queue_empty(&kapmd_queue))
-			event = queue_get_event(&kapmd_queue);
-		spin_unlock_irq(&kapmd_queue_lock);
-
-		switch (event) {
-		case 0:
-			break;
-
-		case APM_LOW_BATTERY:
-		case APM_POWER_STATUS_CHANGE:
-			queue_event(event, NULL);
-			break;
-
-		case APM_USER_SUSPEND:
-		case APM_SYS_SUSPEND:
-			queue_event(event, NULL);
-			if (suspends_pending == 0)
-				apm_suspend();
-			break;
-
-		case APM_CRITICAL_SUSPEND:
-			apm_suspend();
-			break;
-		}
-	} while (1);
-
-	complete_and_exit(&kapmd_exit, 0);
-}
-
-static int __init apm_init(void)
-{
-	int ret;
-
-	if (apm_disabled) {
-		printk(KERN_NOTICE "apm: disabled on user request.\n");
-		return -ENODEV;
-	}
-
-	mips_apm_active = 1;
-
-	ret = kernel_thread(kapmd, NULL, CLONE_KERNEL);
-	if (ret < 0) {
-		mips_apm_active = 0;
-		return ret;
-	}
-
-#ifdef CONFIG_PROC_FS
-	create_proc_info_entry("apm", 0, NULL, apm_get_info);
-#endif
-
-	ret = misc_register(&apm_device);
-	if (ret != 0) {
-		remove_proc_entry("apm", NULL);
-
-		mips_apm_active = 0;
-		wake_up(&kapmd_wait);
-		wait_for_completion(&kapmd_exit);
-	}
-
-	return ret;
-}
-
-static void __exit apm_exit(void)
-{
-	misc_deregister(&apm_device);
-	remove_proc_entry("apm", NULL);
-
-	mips_apm_active = 0;
-	wake_up(&kapmd_wait);
-	wait_for_completion(&kapmd_exit);
-}
-
-module_init(apm_init);
-module_exit(apm_exit);
-
-MODULE_AUTHOR("Stephen Rothwell");
-MODULE_DESCRIPTION("Advanced Power Management");
-MODULE_LICENSE("GPL");
-
-#ifndef MODULE
-static int __init apm_setup(char *str)
-{
-	while ((str != NULL) && (*str != '\0')) {
-		if (strncmp(str, "off", 3) == 0)
-			apm_disabled = 1;
-		if (strncmp(str, "on", 2) == 0)
-			apm_disabled = 0;
-		str = strchr(str, ',');
-		if (str != NULL)
-			str += strspn(str, ", \t");
-	}
-	return 1;
-}
-
-__setup("apm=", apm_setup);
-#endif
-
-/**
- * apm_queue_event - queue an APM event for kapmd
- * @event: APM event
- *
- * Queue an APM event for kapmd to process and ultimately take the
- * appropriate action.  Only a subset of events are handled:
- *   %APM_LOW_BATTERY
- *   %APM_POWER_STATUS_CHANGE
- *   %APM_USER_SUSPEND
- *   %APM_SYS_SUSPEND
- *   %APM_CRITICAL_SUSPEND
- */
-void apm_queue_event(apm_event_t event)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&kapmd_queue_lock, flags);
-	queue_add_event(&kapmd_queue, event);
-	spin_unlock_irqrestore(&kapmd_queue_lock, flags);
-
-	wake_up_interruptible(&kapmd_wait);
-}
-EXPORT_SYMBOL(apm_queue_event);
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index ff88b06..ea7df4b 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -234,10 +234,6 @@
 	constant("#define _PMD_SHIFT     ", PMD_SHIFT);
 	constant("#define _PGDIR_SHIFT   ", PGDIR_SHIFT);
 	linefeed;
-	constant("#define _PGD_ORDER     ", PGD_ORDER);
-	constant("#define _PMD_ORDER     ", PMD_ORDER);
-	constant("#define _PTE_ORDER     ", PTE_ORDER);
-	linefeed;
 	constant("#define _PTRS_PER_PGD  ", PTRS_PER_PGD);
 	constant("#define _PTRS_PER_PMD  ", PTRS_PER_PMD);
 	constant("#define _PTRS_PER_PTE  ", PTRS_PER_PTE);
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 442839e..f59ef27 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -565,7 +565,7 @@
 	if (config3 & MIPS_CONF3_VEIC)
 		c->options |= MIPS_CPU_VEIC;
 	if (config3 & MIPS_CONF3_MT)
-                c->ases |= MIPS_ASE_MIPSMT;
+	        c->ases |= MIPS_ASE_MIPSMT;
 
 	return config3 & MIPS_CONF_M;
 }
diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c
index 719d269..7bc8820 100644
--- a/arch/mips/kernel/gdb-stub.c
+++ b/arch/mips/kernel/gdb-stub.c
@@ -505,13 +505,13 @@
 	 */
 	printk("$0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
 	       regs->reg0, regs->reg1, regs->reg2, regs->reg3,
-               regs->reg4, regs->reg5, regs->reg6, regs->reg7);
+	       regs->reg4, regs->reg5, regs->reg6, regs->reg7);
 	printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
 	       regs->reg8, regs->reg9, regs->reg10, regs->reg11,
-               regs->reg12, regs->reg13, regs->reg14, regs->reg15);
+	       regs->reg12, regs->reg13, regs->reg14, regs->reg15);
 	printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
 	       regs->reg16, regs->reg17, regs->reg18, regs->reg19,
-               regs->reg20, regs->reg21, regs->reg22, regs->reg23);
+	       regs->reg20, regs->reg21, regs->reg22, regs->reg23);
 	printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
 	       regs->reg24, regs->reg25, regs->reg26, regs->reg27,
 	       regs->reg28, regs->reg29, regs->reg30, regs->reg31);
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index 9a7811d..6f57ca4 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -231,28 +231,3 @@
 #endif /* CONFIG_SMP */
 
 	__FINIT
-
-	.comm	kernelsp,    NR_CPUS * 8, 8
-	.comm	pgd_current, NR_CPUS * 8, 8
-
-	.comm	fw_arg0, SZREG, SZREG		# firmware arguments
-	.comm	fw_arg1, SZREG, SZREG
-	.comm	fw_arg2, SZREG, SZREG
-	.comm	fw_arg3, SZREG, SZREG
-
-	.macro page name, order
-	.comm	\name, (_PAGE_SIZE << \order), (_PAGE_SIZE << \order)
-	.endm
-
-	/*
-	 * On 64-bit we've got three-level pagetables with a slightly
-	 * different layout ...
-	 */
-	page	swapper_pg_dir, _PGD_ORDER
-#ifdef CONFIG_64BIT
-#if defined(CONFIG_MODULES) && !defined(CONFIG_BUILD_ELF64)
-	page	module_pg_dir, _PGD_ORDER
-#endif
-	page	invalid_pmd_table, _PMD_ORDER
-#endif
-	page	invalid_pte_table, _PTE_ORDER
diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c
index b59a676..b33ba6c 100644
--- a/arch/mips/kernel/i8259.c
+++ b/arch/mips/kernel/i8259.c
@@ -54,9 +54,11 @@
 
 void disable_8259A_irq(unsigned int irq)
 {
-	unsigned int mask = 1 << irq;
+	unsigned int mask;
 	unsigned long flags;
 
+	irq -= I8259A_IRQ_BASE;
+	mask = 1 << irq;
 	spin_lock_irqsave(&i8259A_lock, flags);
 	cached_irq_mask |= mask;
 	if (irq & 8)
@@ -68,9 +70,11 @@
 
 void enable_8259A_irq(unsigned int irq)
 {
-	unsigned int mask = ~(1 << irq);
+	unsigned int mask;
 	unsigned long flags;
 
+	irq -= I8259A_IRQ_BASE;
+	mask = ~(1 << irq);
 	spin_lock_irqsave(&i8259A_lock, flags);
 	cached_irq_mask &= mask;
 	if (irq & 8)
@@ -82,10 +86,12 @@
 
 int i8259A_irq_pending(unsigned int irq)
 {
-	unsigned int mask = 1 << irq;
+	unsigned int mask;
 	unsigned long flags;
 	int ret;
 
+	irq -= I8259A_IRQ_BASE;
+	mask = 1 << irq;
 	spin_lock_irqsave(&i8259A_lock, flags);
 	if (irq < 8)
 		ret = inb(PIC_MASTER_CMD) & mask;
@@ -134,9 +140,11 @@
  */
 void mask_and_ack_8259A(unsigned int irq)
 {
-	unsigned int irqmask = 1 << irq;
+	unsigned int irqmask;
 	unsigned long flags;
 
+	irq -= I8259A_IRQ_BASE;
+	irqmask = 1 << irq;
 	spin_lock_irqsave(&i8259A_lock, flags);
 	/*
 	 * Lightweight spurious IRQ detection. We do not want
@@ -169,8 +177,8 @@
 		outb(0x60+irq,PIC_MASTER_CMD);	/* 'Specific EOI to master */
 	}
 #ifdef CONFIG_MIPS_MT_SMTC
-        if (irq_hwmask[irq] & ST0_IM)
-        	set_c0_status(irq_hwmask[irq] & ST0_IM);
+	if (irq_hwmask[irq] & ST0_IM)
+		set_c0_status(irq_hwmask[irq] & ST0_IM);
 #endif /* CONFIG_MIPS_MT_SMTC */
 	spin_unlock_irqrestore(&i8259A_lock, flags);
 	return;
@@ -322,8 +330,8 @@
 
 	init_8259A(0);
 
-	for (i = 0; i < 16; i++)
+	for (i = I8259A_IRQ_BASE; i < I8259A_IRQ_BASE + 16; i++)
 		set_irq_chip_and_handler(i, &i8259A_chip, handle_level_irq);
 
-	setup_irq(PIC_CASCADE_IR, &irq2);
+	setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2);
 }
diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
index 37cad5d..3cc25c0 100644
--- a/arch/mips/kernel/irixelf.c
+++ b/arch/mips/kernel/irixelf.c
@@ -10,6 +10,8 @@
  * Copyright (C) 1996 - 2004 David S. Miller <dm@engr.sgi.com>
  * Copyright (C) 2004 - 2005 Steven J. Hill <sjhill@realitydiluted.com>
  */
+#undef DEBUG
+
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/stat.h>
@@ -40,8 +42,6 @@
 
 #include <linux/elf.h>
 
-#undef DEBUG
-
 static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs);
 static int load_irix_library(struct file *);
 static int irix_core_dump(long signr, struct pt_regs * regs,
@@ -52,72 +52,102 @@
 	irix_core_dump, PAGE_SIZE
 };
 
-#ifdef DEBUG
 /* Debugging routines. */
 static char *get_elf_p_type(Elf32_Word p_type)
 {
-	int i = (int) p_type;
+#ifdef DEBUG
+	switch (p_type) {
+	case PT_NULL:
+		return "PT_NULL";
+		break;
 
-	switch(i) {
-	case PT_NULL: return("PT_NULL"); break;
-	case PT_LOAD: return("PT_LOAD"); break;
-	case PT_DYNAMIC: return("PT_DYNAMIC"); break;
-	case PT_INTERP: return("PT_INTERP"); break;
-	case PT_NOTE: return("PT_NOTE"); break;
-	case PT_SHLIB: return("PT_SHLIB"); break;
-	case PT_PHDR: return("PT_PHDR"); break;
-	case PT_LOPROC: return("PT_LOPROC/REGINFO"); break;
-	case PT_HIPROC: return("PT_HIPROC"); break;
-	default: return("PT_BOGUS"); break;
+	case PT_LOAD:
+		return "PT_LOAD";
+		break;
+
+	case PT_DYNAMIC:
+		return "PT_DYNAMIC";
+		break;
+
+	case PT_INTERP:
+		return "PT_INTERP";
+		break;
+
+	case PT_NOTE:
+		return "PT_NOTE";
+		break;
+
+	case PT_SHLIB:
+		return "PT_SHLIB";
+		break;
+
+	case PT_PHDR:
+		return "PT_PHDR";
+		break;
+
+	case PT_LOPROC:
+		return "PT_LOPROC/REGINFO";
+		break;
+
+	case PT_HIPROC:
+		return "PT_HIPROC";
+		break;
+
+	default:
+		return "PT_BOGUS";
+		break;
 	}
+#endif
 }
 
 static void print_elfhdr(struct elfhdr *ehp)
 {
 	int i;
 
-	printk("ELFHDR: e_ident<");
-	for(i = 0; i < (EI_NIDENT - 1); i++) printk("%x ", ehp->e_ident[i]);
-	printk("%x>\n", ehp->e_ident[i]);
-	printk("        e_type[%04x] e_machine[%04x] e_version[%08lx]\n",
-	       (unsigned short) ehp->e_type, (unsigned short) ehp->e_machine,
-	       (unsigned long) ehp->e_version);
-	printk("        e_entry[%08lx] e_phoff[%08lx] e_shoff[%08lx] "
-	       "e_flags[%08lx]\n",
-	       (unsigned long) ehp->e_entry, (unsigned long) ehp->e_phoff,
-	       (unsigned long) ehp->e_shoff, (unsigned long) ehp->e_flags);
-	printk("        e_ehsize[%04x] e_phentsize[%04x] e_phnum[%04x]\n",
-	       (unsigned short) ehp->e_ehsize, (unsigned short) ehp->e_phentsize,
-	       (unsigned short) ehp->e_phnum);
-	printk("        e_shentsize[%04x] e_shnum[%04x] e_shstrndx[%04x]\n",
-	       (unsigned short) ehp->e_shentsize, (unsigned short) ehp->e_shnum,
-	       (unsigned short) ehp->e_shstrndx);
+	pr_debug("ELFHDR: e_ident<");
+	for (i = 0; i < (EI_NIDENT - 1); i++)
+		pr_debug("%x ", ehp->e_ident[i]);
+	pr_debug("%x>\n", ehp->e_ident[i]);
+	pr_debug("        e_type[%04x] e_machine[%04x] e_version[%08lx]\n",
+	         (unsigned short) ehp->e_type, (unsigned short) ehp->e_machine,
+	         (unsigned long) ehp->e_version);
+	pr_debug("        e_entry[%08lx] e_phoff[%08lx] e_shoff[%08lx] "
+	         "e_flags[%08lx]\n",
+	         (unsigned long) ehp->e_entry, (unsigned long) ehp->e_phoff,
+	         (unsigned long) ehp->e_shoff, (unsigned long) ehp->e_flags);
+	pr_debug("        e_ehsize[%04x] e_phentsize[%04x] e_phnum[%04x]\n",
+	         (unsigned short) ehp->e_ehsize,
+	         (unsigned short) ehp->e_phentsize,
+	         (unsigned short) ehp->e_phnum);
+	pr_debug("        e_shentsize[%04x] e_shnum[%04x] e_shstrndx[%04x]\n",
+	         (unsigned short) ehp->e_shentsize,
+	         (unsigned short) ehp->e_shnum,
+	         (unsigned short) ehp->e_shstrndx);
 }
 
 static void print_phdr(int i, struct elf_phdr *ep)
 {
-	printk("PHDR[%d]: p_type[%s] p_offset[%08lx] p_vaddr[%08lx] "
-	       "p_paddr[%08lx]\n", i, get_elf_p_type(ep->p_type),
-	       (unsigned long) ep->p_offset, (unsigned long) ep->p_vaddr,
-	       (unsigned long) ep->p_paddr);
-	printk("         p_filesz[%08lx] p_memsz[%08lx] p_flags[%08lx] "
-	       "p_align[%08lx]\n", (unsigned long) ep->p_filesz,
-	       (unsigned long) ep->p_memsz, (unsigned long) ep->p_flags,
-	       (unsigned long) ep->p_align);
+	pr_debug("PHDR[%d]: p_type[%s] p_offset[%08lx] p_vaddr[%08lx] "
+	         "p_paddr[%08lx]\n", i, get_elf_p_type(ep->p_type),
+	         (unsigned long) ep->p_offset, (unsigned long) ep->p_vaddr,
+	         (unsigned long) ep->p_paddr);
+	pr_debug("         p_filesz[%08lx] p_memsz[%08lx] p_flags[%08lx] "
+	         "p_align[%08lx]\n", (unsigned long) ep->p_filesz,
+	         (unsigned long) ep->p_memsz, (unsigned long) ep->p_flags,
+	         (unsigned long) ep->p_align);
 }
 
 static void dump_phdrs(struct elf_phdr *ep, int pnum)
 {
 	int i;
 
-	for(i = 0; i < pnum; i++, ep++) {
-		if((ep->p_type == PT_LOAD) ||
-		   (ep->p_type == PT_INTERP) ||
-		   (ep->p_type == PT_PHDR))
+	for (i = 0; i < pnum; i++, ep++) {
+		if ((ep->p_type == PT_LOAD) ||
+		    (ep->p_type == PT_INTERP) ||
+		    (ep->p_type == PT_PHDR))
 			print_phdr(i, ep);
 	}
 }
-#endif /* DEBUG */
 
 static void set_brk(unsigned long start, unsigned long end)
 {
@@ -156,11 +186,10 @@
 	elf_addr_t *envp;
 	elf_addr_t *sp, *csp;
 
-#ifdef DEBUG
-	printk("create_irix_tables: p[%p] argc[%d] envc[%d] "
-	       "load_addr[%08x] interp_load_addr[%08x]\n",
-	       p, argc, envc, load_addr, interp_load_addr);
-#endif
+	pr_debug("create_irix_tables: p[%p] argc[%d] envc[%d] "
+	         "load_addr[%08x] interp_load_addr[%08x]\n",
+	         p, argc, envc, load_addr, interp_load_addr);
+
 	sp = (elf_addr_t *) (~15UL & (unsigned long) p);
 	csp = sp;
 	csp -= exec ? DLINFO_ITEMS*2 : 2;
@@ -181,7 +210,7 @@
 	sp -= 2;
 	NEW_AUX_ENT(0, AT_NULL, 0);
 
-	if(exec) {
+	if (exec) {
 		sp -= 11*2;
 
 		NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff);
@@ -245,9 +274,7 @@
 	last_bss = 0;
 	error = load_addr = 0;
 
-#ifdef DEBUG
 	print_elfhdr(interp_elf_ex);
-#endif
 
 	/* First of all, some simple consistency checks */
 	if ((interp_elf_ex->e_type != ET_EXEC &&
@@ -258,7 +285,7 @@
 	}
 
 	/* Now read in all of the header information */
-	if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) {
+	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) {
 	    printk("IRIX interp header bigger than a page (%d)\n",
 		   (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum));
 	    return 0xffffffff;
@@ -267,15 +294,15 @@
 	elf_phdata = kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum,
 			     GFP_KERNEL);
 
-	if(!elf_phdata) {
-          printk("Cannot kmalloc phdata for IRIX interp.\n");
-	  return 0xffffffff;
+	if (!elf_phdata) {
+		printk("Cannot kmalloc phdata for IRIX interp.\n");
+		return 0xffffffff;
 	}
 
 	/* If the size of this structure has changed, then punt, since
 	 * we will be doing the wrong thing.
 	 */
-	if(interp_elf_ex->e_phentsize != 32) {
+	if (interp_elf_ex->e_phentsize != 32) {
 		printk("IRIX interp e_phentsize == %d != 32 ",
 		       interp_elf_ex->e_phentsize);
 		kfree(elf_phdata);
@@ -286,61 +313,71 @@
 			   (char *) elf_phdata,
 			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
 
-#ifdef DEBUG
 	dump_phdrs(elf_phdata, interp_elf_ex->e_phnum);
-#endif
 
 	eppnt = elf_phdata;
-	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
-	  if(eppnt->p_type == PT_LOAD) {
-	    int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
-	    int elf_prot = 0;
-	    unsigned long vaddr = 0;
-	    if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
-	    if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
-	    if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
-	    elf_type |= MAP_FIXED;
-	    vaddr = eppnt->p_vaddr;
+	for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) {
+		if (eppnt->p_type == PT_LOAD) {
+			int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+			int elf_prot = 0;
+			unsigned long vaddr = 0;
+			if (eppnt->p_flags & PF_R)
+				elf_prot =  PROT_READ;
+			if (eppnt->p_flags & PF_W)
+				elf_prot |= PROT_WRITE;
+			if (eppnt->p_flags & PF_X)
+				elf_prot |= PROT_EXEC;
+			elf_type |= MAP_FIXED;
+			vaddr = eppnt->p_vaddr;
 
-	    pr_debug("INTERP do_mmap(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ",
-		   interpreter, vaddr,
-		   (unsigned long) (eppnt->p_filesz + (eppnt->p_vaddr & 0xfff)),
-		   (unsigned long) elf_prot, (unsigned long) elf_type,
-		   (unsigned long) (eppnt->p_offset & 0xfffff000));
-	    down_write(&current->mm->mmap_sem);
-	    error = do_mmap(interpreter, vaddr,
-			    eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
-			    elf_prot, elf_type,
-			    eppnt->p_offset & 0xfffff000);
-	    up_write(&current->mm->mmap_sem);
+			pr_debug("INTERP do_mmap"
+			         "(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ",
+			         interpreter, vaddr,
+			         (unsigned long)
+			         (eppnt->p_filesz + (eppnt->p_vaddr & 0xfff)),
+			         (unsigned long)
+			         elf_prot, (unsigned long) elf_type,
+			         (unsigned long)
+			         (eppnt->p_offset & 0xfffff000));
 
-	    if(error < 0 && error > -1024) {
-		    printk("Aieee IRIX interp mmap error=%d\n", error);
-		    break;  /* Real error */
-	    }
-	    pr_debug("error=%08lx ", (unsigned long) error);
-	    if(!load_addr && interp_elf_ex->e_type == ET_DYN) {
-	      load_addr = error;
-              pr_debug("load_addr = error ");
-	    }
+			down_write(&current->mm->mmap_sem);
+			error = do_mmap(interpreter, vaddr,
+			eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
+			elf_prot, elf_type,
+			eppnt->p_offset & 0xfffff000);
+			up_write(&current->mm->mmap_sem);
 
-	    /* Find the end of the file  mapping for this phdr, and keep
-	     * track of the largest address we see for this.
-	     */
-	    k = eppnt->p_vaddr + eppnt->p_filesz;
-	    if(k > elf_bss) elf_bss = k;
+			if (error < 0 && error > -1024) {
+				printk("Aieee IRIX interp mmap error=%d\n",
+				       error);
+				break;  /* Real error */
+			}
+			pr_debug("error=%08lx ", (unsigned long) error);
+			if (!load_addr && interp_elf_ex->e_type == ET_DYN) {
+				load_addr = error;
+				pr_debug("load_addr = error ");
+			}
 
-	    /* Do the same thing for the memory mapping - between
-	     * elf_bss and last_bss is the bss section.
-	     */
-	    k = eppnt->p_memsz + eppnt->p_vaddr;
-	    if(k > last_bss) last_bss = k;
-	    pr_debug("\n");
-	  }
+			/*
+			 * Find the end of the file  mapping for this phdr, and
+			 * keep track of the largest address we see for this.
+			 */
+			k = eppnt->p_vaddr + eppnt->p_filesz;
+			if (k > elf_bss)
+				elf_bss = k;
+
+			/* Do the same thing for the memory mapping - between
+			 * elf_bss and last_bss is the bss section.
+			 */
+			k = eppnt->p_memsz + eppnt->p_vaddr;
+			if (k > last_bss)
+				last_bss = k;
+			pr_debug("\n");
+		}
 	}
 
 	/* Now use mmap to map the library into memory. */
-	if(error < 0 && error > -1024) {
+	if (error < 0 && error > -1024) {
 		pr_debug("got error %d\n", error);
 		kfree(elf_phdata);
 		return 0xffffffff;
@@ -377,7 +414,7 @@
 		return -ENOEXEC;
 
 	/* First of all, some simple consistency checks */
-	if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) ||
+	if ((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) ||
 	    !bprm->file->f_op->mmap) {
 		return -ENOEXEC;
 	}
@@ -388,7 +425,7 @@
 	 * XXX all registers as 64bits on cpu's capable of this at
 	 * XXX exception time plus frob the XTLB exception vector.
 	 */
-	if((ehp->e_flags & EF_MIPS_ABI2))
+	if ((ehp->e_flags & EF_MIPS_ABI2))
 		return -ENOEXEC;
 
 	return 0;
@@ -410,7 +447,7 @@
 	struct file *file = NULL;
 
 	*name = NULL;
-	for(i = 0; i < pnum; i++, epp++) {
+	for (i = 0; i < pnum; i++, epp++) {
 		if (epp->p_type != PT_INTERP)
 			continue;
 
@@ -467,8 +504,8 @@
 	unsigned int tmp;
 	int i, prot;
 
-	for(i = 0; i < pnum; i++, epp++) {
-		if(epp->p_type != PT_LOAD)
+	for (i = 0; i < pnum; i++, epp++) {
+		if (epp->p_type != PT_LOAD)
 			continue;
 
 		/* Map it. */
@@ -483,23 +520,23 @@
 	        up_write(&current->mm->mmap_sem);
 
 		/* Fixup location tracking vars. */
-		if((epp->p_vaddr & 0xfffff000) < *estack)
+		if ((epp->p_vaddr & 0xfffff000) < *estack)
 			*estack = (epp->p_vaddr & 0xfffff000);
-		if(!*laddr)
+		if (!*laddr)
 			*laddr = epp->p_vaddr - epp->p_offset;
-		if(epp->p_vaddr < *scode)
+		if (epp->p_vaddr < *scode)
 			*scode = epp->p_vaddr;
 
 		tmp = epp->p_vaddr + epp->p_filesz;
-		if(tmp > *ebss)
+		if (tmp > *ebss)
 			*ebss = tmp;
-		if((epp->p_flags & PF_X) && *ecode < tmp)
+		if ((epp->p_flags & PF_X) && *ecode < tmp)
 			*ecode = tmp;
-		if(*edata < tmp)
+		if (*edata < tmp)
 			*edata = tmp;
 
 		tmp = epp->p_vaddr + epp->p_memsz;
-		if(tmp > *ebrk)
+		if (tmp > *ebrk)
 			*ebrk = tmp;
 	}
 
@@ -513,12 +550,12 @@
 	int i;
 
 	*eentry = 0xffffffff;
-	for(i = 0; i < pnum; i++, epp++) {
-		if(epp->p_type != PT_INTERP)
+	for (i = 0; i < pnum; i++, epp++) {
+		if (epp->p_type != PT_INTERP)
 			continue;
 
 		/* We should have fielded this error elsewhere... */
-		if(*eentry != 0xffffffff)
+		if (*eentry != 0xffffffff)
 			return -1;
 
 		set_fs(old_fs);
@@ -604,9 +641,7 @@
 	if (elf_ex.e_shnum > 20)
 		goto out;
 
-#ifdef DEBUG
 	print_elfhdr(&elf_ex);
-#endif
 
 	/* Now read in all of the header information */
 	size = elf_ex.e_phentsize * elf_ex.e_phnum;
@@ -622,13 +657,11 @@
 	if (retval < 0)
 		goto out_free_ph;
 
-#ifdef DEBUG
 	dump_phdrs(elf_phdata, elf_ex.e_phnum);
-#endif
 
 	/* Set some things for later. */
-	for(i = 0; i < elf_ex.e_phnum; i++) {
-		switch(elf_phdata[i].p_type) {
+	for (i = 0; i < elf_ex.e_phnum; i++) {
+		switch (elf_phdata[i].p_type) {
 		case PT_INTERP:
 			has_interp = 1;
 			elf_ihdr = &elf_phdata[i];
@@ -667,7 +700,7 @@
 
 	if (elf_interpreter) {
 		retval = verify_irix_interpreter(&interp_elf_ex);
-		if(retval)
+		if (retval)
 			goto out_free_interp;
 	}
 
@@ -706,12 +739,12 @@
 	               &load_addr, &start_code, &elf_bss, &end_code,
 	               &end_data, &elf_brk);
 
-	if(elf_interpreter) {
+	if (elf_interpreter) {
 		retval = map_interpreter(elf_phdata, &interp_elf_ex,
 					 interpreter, &interp_load_addr,
 					 elf_ex.e_phnum, old_fs, &elf_entry);
 		kfree(elf_interpreter);
-		if(retval) {
+		if (retval) {
 			set_fs(old_fs);
 			printk("Unable to load IRIX ELF interpreter\n");
 			send_sig(SIGSEGV, current, 0);
@@ -809,12 +842,12 @@
 		return -ENOEXEC;
 
 	/* First of all, some simple consistency checks. */
-	if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
+	if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
 	   !file->f_op->mmap)
 		return -ENOEXEC;
 
 	/* Now read in all of the header information. */
-	if(sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
+	if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
 		return -ENOEXEC;
 
 	elf_phdata = kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
@@ -825,15 +858,15 @@
 			   sizeof(struct elf_phdr) * elf_ex.e_phnum);
 
 	j = 0;
-	for(i=0; i<elf_ex.e_phnum; i++)
-		if((elf_phdata + i)->p_type == PT_LOAD) j++;
+	for (i=0; i<elf_ex.e_phnum; i++)
+		if ((elf_phdata + i)->p_type == PT_LOAD) j++;
 
-	if(j != 1)  {
+	if (j != 1)  {
 		kfree(elf_phdata);
 		return -ENOEXEC;
 	}
 
-	while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
+	while (elf_phdata->p_type != PT_LOAD) elf_phdata++;
 
 	/* Now use mmap to map the library into memory. */
 	down_write(&current->mm->mmap_sem);
@@ -889,9 +922,7 @@
 		return -EFAULT;
 	}
 
-#ifdef DEBUG
 	dump_phdrs(user_phdrp, cnt);
-#endif
 
 	for (i = 0; i < cnt; i++, hp++) {
 		if (__get_user(type, &hp->p_type))
@@ -905,14 +936,14 @@
 	filp = fget(fd);
 	if (!filp)
 		return -EACCES;
-	if(!filp->f_op) {
+	if (!filp->f_op) {
 		printk("irix_mapelf: Bogon filp!\n");
 		fput(filp);
 		return -EACCES;
 	}
 
 	hp = user_phdrp;
-	for(i = 0; i < cnt; i++, hp++) {
+	for (i = 0; i < cnt; i++, hp++) {
 		int prot;
 
 		retval = __get_user(vaddr, &hp->p_vaddr);
@@ -1015,8 +1046,6 @@
 	return sz;
 }
 
-/* #define DEBUG */
-
 #define DUMP_WRITE(addr, nr)	\
 	if (!dump_write(file, (addr), (nr))) \
 		goto end_coredump;
@@ -1093,9 +1122,7 @@
 
 		segs++;
 	}
-#ifdef DEBUG
-	printk("irix_core_dump: %d segs taking %d bytes\n", segs, size);
-#endif
+	pr_debug("irix_core_dump: %d segs taking %d bytes\n", segs, size);
 
 	/* Set up header. */
 	memcpy(elf.e_ident, ELFMAG, SELFMAG);
@@ -1221,7 +1248,7 @@
 		struct elf_phdr phdr;
 		int sz = 0;
 
-		for(i = 0; i < numnote; i++)
+		for (i = 0; i < numnote; i++)
 			sz += notesize(&notes[i]);
 
 		phdr.p_type = PT_NOTE;
@@ -1241,7 +1268,7 @@
 	dataoff = offset = roundup(offset, PAGE_SIZE);
 
 	/* Write program headers for segments dump. */
-	for(vma = current->mm->mmap, i = 0;
+	for (vma = current->mm->mmap, i = 0;
 		i < segs && vma != NULL; vma = vma->vm_next) {
 		struct elf_phdr phdr;
 		size_t sz;
@@ -1267,7 +1294,7 @@
 		DUMP_WRITE(&phdr, sizeof(phdr));
 	}
 
-	for(i = 0; i < numnote; i++)
+	for (i = 0; i < numnote; i++)
 		if (!writenote(&notes[i], file))
 			goto end_coredump;
 
@@ -1275,7 +1302,7 @@
 
 	DUMP_SEEK(dataoff);
 
-	for(i = 0, vma = current->mm->mmap;
+	for (i = 0, vma = current->mm->mmap;
 	    i < segs && vma != NULL;
 	    vma = vma->vm_next) {
 		unsigned long addr = vma->vm_start;
@@ -1284,9 +1311,7 @@
 		if (!maydump(vma))
 			continue;
 		i++;
-#ifdef DEBUG
-		printk("elf_core_dump: writing %08lx %lx\n", addr, len);
-#endif
+		pr_debug("elf_core_dump: writing %08lx %lx\n", addr, len);
 		DUMP_WRITE((void __user *)addr, len);
 	}
 
diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c
index bcaad66..2967537 100644
--- a/arch/mips/kernel/irq-msc01.c
+++ b/arch/mips/kernel/irq-msc01.c
@@ -112,7 +112,7 @@
 }
 
 struct irq_chip msc_levelirq_type = {
-	.typename = "SOC-it-Level",
+	.name = "SOC-it-Level",
 	.ack = level_mask_and_ack_msc_irq,
 	.mask = mask_msc_irq,
 	.mask_ack = level_mask_and_ack_msc_irq,
@@ -122,7 +122,7 @@
 };
 
 struct irq_chip msc_edgeirq_type = {
-	.typename = "SOC-it-Edge",
+	.name = "SOC-it-Edge",
 	.ack = edge_mask_and_ack_msc_irq,
 	.mask = mask_msc_irq,
 	.mask_ack = edge_mask_and_ack_msc_irq,
diff --git a/arch/mips/kernel/irq-mv6434x.c b/arch/mips/kernel/irq-mv6434x.c
index efbd219..3dd5618 100644
--- a/arch/mips/kernel/irq-mv6434x.c
+++ b/arch/mips/kernel/irq-mv6434x.c
@@ -23,13 +23,13 @@
 
 static inline int ls1bit32(unsigned int x)
 {
-        int b = 31, s;
+	int b = 31, s;
 
-        s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s;
-        s =  8; if (x <<  8 == 0) s = 0; b -= s; x <<= s;
-        s =  4; if (x <<  4 == 0) s = 0; b -= s; x <<= s;
-        s =  2; if (x <<  2 == 0) s = 0; b -= s; x <<= s;
-        s =  1; if (x <<  1 == 0) s = 0; b -= s;
+	s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s;
+	s =  8; if (x <<  8 == 0) s = 0; b -= s; x <<= s;
+	s =  4; if (x <<  4 == 0) s = 0; b -= s; x <<= s;
+	s =  2; if (x <<  2 == 0) s = 0; b -= s; x <<= s;
+	s =  1; if (x <<  1 == 0) s = 0; b -= s;
 
         return b;
 }
@@ -92,7 +92,7 @@
 }
 
 struct irq_chip mv64340_irq_type = {
-	.typename = "MV-64340",
+	.name = "MV-64340",
 	.ack = mask_mv64340_irq,
 	.mask = mask_mv64340_irq,
 	.mask_ack = mask_mv64340_irq,
diff --git a/arch/mips/kernel/irq-rm7000.c b/arch/mips/kernel/irq-rm7000.c
index 123324b..2507328 100644
--- a/arch/mips/kernel/irq-rm7000.c
+++ b/arch/mips/kernel/irq-rm7000.c
@@ -17,28 +17,27 @@
 #include <asm/mipsregs.h>
 #include <asm/system.h>
 
-static int irq_base;
-
 static inline void unmask_rm7k_irq(unsigned int irq)
 {
-	set_c0_intcontrol(0x100 << (irq - irq_base));
+	set_c0_intcontrol(0x100 << (irq - RM7K_CPU_IRQ_BASE));
 }
 
 static inline void mask_rm7k_irq(unsigned int irq)
 {
-	clear_c0_intcontrol(0x100 << (irq - irq_base));
+	clear_c0_intcontrol(0x100 << (irq - RM7K_CPU_IRQ_BASE));
 }
 
 static struct irq_chip rm7k_irq_controller = {
-	.typename = "RM7000",
+	.name = "RM7000",
 	.ack = mask_rm7k_irq,
 	.mask = mask_rm7k_irq,
 	.mask_ack = mask_rm7k_irq,
 	.unmask = unmask_rm7k_irq,
 };
 
-void __init rm7k_cpu_irq_init(int base)
+void __init rm7k_cpu_irq_init(void)
 {
+	int base = RM7K_CPU_IRQ_BASE;
 	int i;
 
 	clear_c0_intcontrol(0x00000f00);		/* Mask all */
@@ -46,6 +45,4 @@
 	for (i = base; i < base + 4; i++)
 		set_irq_chip_and_handler(i, &rm7k_irq_controller,
 					 handle_level_irq);
-
-	irq_base = base;
 }
diff --git a/arch/mips/kernel/irq-rm9000.c b/arch/mips/kernel/irq-rm9000.c
index 0e6f4c5..ae83d2d 100644
--- a/arch/mips/kernel/irq-rm9000.c
+++ b/arch/mips/kernel/irq-rm9000.c
@@ -18,16 +18,14 @@
 #include <asm/mipsregs.h>
 #include <asm/system.h>
 
-static int irq_base;
-
 static inline void unmask_rm9k_irq(unsigned int irq)
 {
-	set_c0_intcontrol(0x1000 << (irq - irq_base));
+	set_c0_intcontrol(0x1000 << (irq - RM9K_CPU_IRQ_BASE));
 }
 
 static inline void mask_rm9k_irq(unsigned int irq)
 {
-	clear_c0_intcontrol(0x1000 << (irq - irq_base));
+	clear_c0_intcontrol(0x1000 << (irq - RM9K_CPU_IRQ_BASE));
 }
 
 static inline void rm9k_cpu_irq_enable(unsigned int irq)
@@ -39,15 +37,6 @@
 	local_irq_restore(flags);
 }
 
-static void rm9k_cpu_irq_disable(unsigned int irq)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	mask_rm9k_irq(irq);
-	local_irq_restore(flags);
-}
-
 /*
  * Performance counter interrupts are global on all processors.
  */
@@ -81,7 +70,7 @@
 }
 
 static struct irq_chip rm9k_irq_controller = {
-	.typename = "RM9000",
+	.name = "RM9000",
 	.ack = mask_rm9k_irq,
 	.mask = mask_rm9k_irq,
 	.mask_ack = mask_rm9k_irq,
@@ -89,7 +78,7 @@
 };
 
 static struct irq_chip rm9k_perfcounter_irq = {
-	.typename = "RM9000",
+	.name = "RM9000",
 	.startup = rm9k_perfcounter_irq_startup,
 	.shutdown = rm9k_perfcounter_irq_shutdown,
 	.ack = mask_rm9k_irq,
@@ -102,8 +91,9 @@
 
 EXPORT_SYMBOL(rm9000_perfcount_irq);
 
-void __init rm9k_cpu_irq_init(int base)
+void __init rm9k_cpu_irq_init(void)
 {
+	int base = RM9K_CPU_IRQ_BASE;
 	int i;
 
 	clear_c0_intcontrol(0x0000f000);		/* Mask all */
@@ -115,6 +105,4 @@
 	rm9000_perfcount_irq = base + 1;
 	set_irq_chip_and_handler(rm9000_perfcount_irq, &rm9k_perfcounter_irq,
 				 handle_level_irq);
-
-	irq_base = base;
 }
diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c
index fcc86b9..7b66e03 100644
--- a/arch/mips/kernel/irq_cpu.c
+++ b/arch/mips/kernel/irq_cpu.c
@@ -25,7 +25,7 @@
  * Don't even think about using this on SMP.  You have been warned.
  *
  * This file exports one global function:
- *	void mips_cpu_irq_init(int irq_base);
+ *	void mips_cpu_irq_init(void);
  */
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -36,22 +36,20 @@
 #include <asm/mipsmtregs.h>
 #include <asm/system.h>
 
-static int mips_cpu_irq_base;
-
 static inline void unmask_mips_irq(unsigned int irq)
 {
-	set_c0_status(0x100 << (irq - mips_cpu_irq_base));
+	set_c0_status(0x100 << (irq - MIPS_CPU_IRQ_BASE));
 	irq_enable_hazard();
 }
 
 static inline void mask_mips_irq(unsigned int irq)
 {
-	clear_c0_status(0x100 << (irq - mips_cpu_irq_base));
+	clear_c0_status(0x100 << (irq - MIPS_CPU_IRQ_BASE));
 	irq_disable_hazard();
 }
 
 static struct irq_chip mips_cpu_irq_controller = {
-	.typename	= "MIPS",
+	.name		= "MIPS",
 	.ack		= mask_mips_irq,
 	.mask		= mask_mips_irq,
 	.mask_ack	= mask_mips_irq,
@@ -70,7 +68,7 @@
 {
 	unsigned int vpflags = dvpe();
 
-	clear_c0_cause(0x100 << (irq - mips_cpu_irq_base));
+	clear_c0_cause(0x100 << (irq - MIPS_CPU_IRQ_BASE));
 	evpe(vpflags);
 	unmask_mips_mt_irq(irq);
 
@@ -84,13 +82,13 @@
 static void mips_mt_cpu_irq_ack(unsigned int irq)
 {
 	unsigned int vpflags = dvpe();
-	clear_c0_cause(0x100 << (irq - mips_cpu_irq_base));
+	clear_c0_cause(0x100 << (irq - MIPS_CPU_IRQ_BASE));
 	evpe(vpflags);
 	mask_mips_mt_irq(irq);
 }
 
 static struct irq_chip mips_mt_cpu_irq_controller = {
-	.typename	= "MIPS",
+	.name		= "MIPS",
 	.startup	= mips_mt_cpu_irq_startup,
 	.ack		= mips_mt_cpu_irq_ack,
 	.mask		= mask_mips_mt_irq,
@@ -99,8 +97,9 @@
 	.eoi		= unmask_mips_mt_irq,
 };
 
-void __init mips_cpu_irq_init(int irq_base)
+void __init mips_cpu_irq_init(void)
 {
+	int irq_base = MIPS_CPU_IRQ_BASE;
 	int i;
 
 	/* Mask interrupts. */
@@ -118,6 +117,4 @@
 	for (i = irq_base + 2; i < irq_base + 8; i++)
 		set_irq_chip_and_handler(i, &mips_cpu_irq_controller,
 					 handle_level_irq);
-
-	mips_cpu_irq_base = irq_base;
 }
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index de3fae2..0b8ce59 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -194,15 +194,15 @@
 }
 
 struct sysinfo32 {
-        s32 uptime;
-        u32 loads[3];
-        u32 totalram;
-        u32 freeram;
-        u32 sharedram;
-        u32 bufferram;
-        u32 totalswap;
-        u32 freeswap;
-        u16 procs;
+	s32 uptime;
+	u32 loads[3];
+	u32 totalram;
+	u32 freeram;
+	u32 sharedram;
+	u32 bufferram;
+	u32 totalswap;
+	u32 freeswap;
+	u16 procs;
 	u32 totalhigh;
 	u32 freehigh;
 	u32 mem_unit;
@@ -558,7 +558,7 @@
 asmlinkage int sys32_ustat(dev_t dev, struct ustat32 __user * ubuf32)
 {
 	int err;
-        struct ustat tmp;
+	struct ustat tmp;
 	struct ustat32 tmp32;
 	mm_segment_t old_fs = get_fs();
 
@@ -569,11 +569,11 @@
 	if (err)
 		goto out;
 
-        memset(&tmp32,0,sizeof(struct ustat32));
-        tmp32.f_tfree = tmp.f_tfree;
-        tmp32.f_tinode = tmp.f_tinode;
+	memset(&tmp32,0,sizeof(struct ustat32));
+	tmp32.f_tfree = tmp.f_tfree;
+	tmp32.f_tinode = tmp.f_tinode;
 
-        err = copy_to_user(ubuf32,&tmp32,sizeof(struct ustat32)) ? -EFAULT : 0;
+	err = copy_to_user(ubuf32,&tmp32,sizeof(struct ustat32)) ? -EFAULT : 0;
 
 out:
 	return err;
diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c
index c1373a6..a32f679 100644
--- a/arch/mips/kernel/mips-mt.c
+++ b/arch/mips/kernel/mips-mt.c
@@ -96,6 +96,10 @@
 		goto out_unlock;
 	}
 
+	retval = security_task_setscheduler(p, 0, NULL);
+	if (retval)
+		goto out_unlock;
+
 	/* Record new user-specified CPU set for future reference */
 	p->thread.user_cpus_allowed = new_mask;
 
@@ -141,8 +145,9 @@
 	p = find_process_by_pid(pid);
 	if (!p)
 		goto out_unlock;
-
-	retval = 0;
+	retval = security_task_getscheduler(p);
+	if (retval)
+		goto out_unlock;
 
 	cpus_and(mask, p->thread.user_cpus_allowed, cpu_possible_map);
 
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
index 4ed37ba..5ddc2e9 100644
--- a/arch/mips/kernel/proc.c
+++ b/arch/mips/kernel/proc.c
@@ -31,13 +31,13 @@
 	[CPU_R4000PC]	= "R4000PC",
 	[CPU_R4000SC]	= "R4000SC",
 	[CPU_R4000MC]	= "R4000MC",
-        [CPU_R4200]	= "R4200",
+	[CPU_R4200]	= "R4200",
 	[CPU_R4400PC]	= "R4400PC",
 	[CPU_R4400SC]	= "R4400SC",
 	[CPU_R4400MC]	= "R4400MC",
 	[CPU_R4600]	= "R4600",
 	[CPU_R6000]	= "R6000",
-        [CPU_R6000A]	= "R6000A",
+	[CPU_R6000A]	= "R6000A",
 	[CPU_R8000]	= "R8000",
 	[CPU_R10000]	= "R10000",
 	[CPU_R12000]	= "R12000",
@@ -46,14 +46,14 @@
 	[CPU_R4650]	= "R4650",
 	[CPU_R4700]	= "R4700",
 	[CPU_R5000]	= "R5000",
-        [CPU_R5000A]	= "R5000A",
+	[CPU_R5000A]	= "R5000A",
 	[CPU_R4640]	= "R4640",
 	[CPU_NEVADA]	= "Nevada",
 	[CPU_RM7000]	= "RM7000",
 	[CPU_RM9000]	= "RM9000",
 	[CPU_R5432]	= "R5432",
 	[CPU_4KC]	= "MIPS 4Kc",
-        [CPU_5KC]	= "MIPS 5Kc",
+	[CPU_5KC]	= "MIPS 5Kc",
 	[CPU_R4310]	= "R4310",
 	[CPU_SB1]	= "SiByte SB1",
 	[CPU_SB1A]	= "SiByte SB1A",
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index ec8209f..04e5b38 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -41,10 +41,6 @@
 #include <asm/isadep.h>
 #include <asm/inst.h>
 #include <asm/stacktrace.h>
-#ifdef CONFIG_MIPS_MT_SMTC
-#include <asm/mipsmtregs.h>
-extern void smtc_idle_loop_hook(void);
-#endif /* CONFIG_MIPS_MT_SMTC */
 
 /*
  * The idle thread. There's no useful work to be done, so just try to conserve
@@ -57,6 +53,8 @@
 	while (1) {
 		while (!need_resched()) {
 #ifdef CONFIG_MIPS_MT_SMTC
+			extern void smtc_idle_loop_hook(void);
+
 			smtc_idle_loop_hook();
 #endif /* CONFIG_MIPS_MT_SMTC */
 			if (cpu_wait)
diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S
index 880fa6e..59c1577 100644
--- a/arch/mips/kernel/r4k_fpu.S
+++ b/arch/mips/kernel/r4k_fpu.S
@@ -114,6 +114,14 @@
  */
 LEAF(_restore_fp_context)
 	EX	lw t0, SC_FPC_CSR(a0)
+
+	/* Fail if the CSR has exceptions pending */
+	srl	t1, t0, 5
+	and	t1, t0
+	andi	t1, 0x1f << 7
+	bnez	t1, fault
+	 nop
+
 #ifdef CONFIG_64BIT
 	EX	ldc1 $f1, SC_FPREGS+8(a0)
 	EX	ldc1 $f3, SC_FPREGS+24(a0)
@@ -157,6 +165,14 @@
 LEAF(_restore_fp_context32)
 	/* Restore an o32 sigcontext.  */
 	EX	lw t0, SC32_FPC_CSR(a0)
+
+	/* Fail if the CSR has exceptions pending */
+	srl	t1, t0, 5
+	and	t1, t0
+	andi	t1, 0x1f << 7
+	bnez	t1, fault
+	 nop
+
 	EX	ldc1 $f0, SC32_FPREGS+0(a0)
 	EX	ldc1 $f2, SC32_FPREGS+16(a0)
 	EX	ldc1 $f4, SC32_FPREGS+32(a0)
@@ -177,9 +193,10 @@
 	jr	ra
 	 li	v0, 0					# success
 	END(_restore_fp_context32)
-	.set	reorder
 #endif
 
+	.set	reorder
+
 	.type	fault@function
 	.ent	fault
 fault:	li	v0, -EFAULT				# failure
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c
index 5a99e3e..8610f4a 100644
--- a/arch/mips/kernel/rtlx.c
+++ b/arch/mips/kernel/rtlx.c
@@ -63,7 +63,7 @@
 
 static void rtlx_dispatch(void)
 {
-	do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ);
+	do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ);
 }
 
 
@@ -491,7 +491,7 @@
 	.name		= "RTLX",
 };
 
-static int rtlx_irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ;
+static int rtlx_irq_num = MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ;
 
 static char register_chrdev_failed[] __initdata =
 	KERN_ERR "rtlx_module_init: unable to register device\n";
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index a7bff2a..39add23 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -384,7 +384,7 @@
 	PTR	sys_readlinkat
 	PTR	sys_fchmodat
 	PTR	sys_faccessat
-	PTR	sys_pselect6
+	PTR	compat_sys_pselect6
 	PTR	sys_ppoll			/* 6265 */
 	PTR	sys_unshare
 	PTR	sys_splice
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index e91379c..c58b8e0 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -506,7 +506,7 @@
 	PTR	sys_readlinkat
 	PTR	sys_fchmodat
 	PTR	sys_faccessat			/* 4300 */
-	PTR	sys_pselect6
+	PTR	compat_sys_pselect6
 	PTR	sys_ppoll
 	PTR	sys_unshare
 	PTR	sys_splice
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 89440a0..d2e01e7 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -271,8 +271,7 @@
 static void __init bootmem_init(void)
 {
 	unsigned long reserved_end;
-	unsigned long highest = 0;
-	unsigned long mapstart = -1UL;
+	unsigned long mapstart = ~0UL;
 	unsigned long bootmap_size;
 	int i;
 
@@ -284,6 +283,13 @@
 	reserved_end = max(init_initrd(), PFN_UP(__pa_symbol(&_end)));
 
 	/*
+	 * max_low_pfn is not a number of pages. The number of pages
+	 * of the system is given by 'max_low_pfn - min_low_pfn'.
+	 */
+	min_low_pfn = ~0UL;
+	max_low_pfn = 0;
+
+	/*
 	 * Find the highest page frame number we have available.
 	 */
 	for (i = 0; i < boot_mem_map.nr_map; i++) {
@@ -296,8 +302,10 @@
 		end = PFN_DOWN(boot_mem_map.map[i].addr
 				+ boot_mem_map.map[i].size);
 
-		if (end > highest)
-			highest = end;
+		if (end > max_low_pfn)
+			max_low_pfn = end;
+		if (start < min_low_pfn)
+			min_low_pfn = start;
 		if (end <= reserved_end)
 			continue;
 		if (start >= mapstart)
@@ -305,22 +313,36 @@
 		mapstart = max(reserved_end, start);
 	}
 
+	if (min_low_pfn >= max_low_pfn)
+		panic("Incorrect memory mapping !!!");
+	if (min_low_pfn > ARCH_PFN_OFFSET) {
+		printk(KERN_INFO
+		       "Wasting %lu bytes for tracking %lu unused pages\n",
+		       (min_low_pfn - ARCH_PFN_OFFSET) * sizeof(struct page),
+		       min_low_pfn - ARCH_PFN_OFFSET);
+	} else if (min_low_pfn < ARCH_PFN_OFFSET) {
+		printk(KERN_INFO
+		       "%lu free pages won't be used\n",
+		       ARCH_PFN_OFFSET - min_low_pfn);
+	}
+	min_low_pfn = ARCH_PFN_OFFSET;
+
 	/*
 	 * Determine low and high memory ranges
 	 */
-	if (highest > PFN_DOWN(HIGHMEM_START)) {
+	if (max_low_pfn > PFN_DOWN(HIGHMEM_START)) {
 #ifdef CONFIG_HIGHMEM
 		highstart_pfn = PFN_DOWN(HIGHMEM_START);
-		highend_pfn = highest;
+		highend_pfn = max_low_pfn;
 #endif
-		highest = PFN_DOWN(HIGHMEM_START);
+		max_low_pfn = PFN_DOWN(HIGHMEM_START);
 	}
 
 	/*
 	 * Initialize the boot-time allocator with low memory only.
 	 */
-	bootmap_size = init_bootmem(mapstart, highest);
-
+	bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart,
+					 min_low_pfn, max_low_pfn);
 	/*
 	 * Register fully available low RAM pages with the bootmem allocator.
 	 */
@@ -507,9 +529,9 @@
 
 #if defined(CONFIG_VT)
 #if defined(CONFIG_VGA_CONSOLE)
-        conswitchp = &vga_con;
+	conswitchp = &vga_con;
 #elif defined(CONFIG_DUMMY_CONSOLE)
-        conswitchp = &dummy_con;
+	conswitchp = &dummy_con;
 #endif
 #endif
 
@@ -541,3 +563,6 @@
 }
 
 __setup("nodsp", dsp_disable);
+
+unsigned long kernelsp[NR_CPUS];
+unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3;
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index b9d358e..9a44053 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -89,7 +89,7 @@
 	spin_lock_irq(&current->sighand->siglock);
 	current->saved_sigmask = current->blocked;
 	current->blocked = newset;
-        recalc_sigpending();
+	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
 	current->state = TASK_INTERRUPTIBLE;
@@ -124,7 +124,7 @@
 
 	if (!ret && oact) {
 		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
-                        return -EFAULT;
+			return -EFAULT;
 		err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
 		err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler);
 		err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
@@ -304,7 +304,7 @@
 	       current->comm, current->pid,
 	       frame, regs->cp0_epc, frame->regs[31]);
 #endif
-        return 0;
+	return 0;
 
 give_sigsegv:
 	force_sigsegv(signr, current);
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c
index a67c185..b28646b 100644
--- a/arch/mips/kernel/signal_n32.c
+++ b/arch/mips/kernel/signal_n32.c
@@ -105,7 +105,7 @@
 	spin_lock_irq(&current->sighand->siglock);
 	current->saved_sigmask = current->blocked;
 	current->blocked = newset;
-        recalc_sigpending();
+	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
 	current->state = TASK_INTERRUPTIBLE;
@@ -184,7 +184,7 @@
 	/* Create the ucontext.  */
 	err |= __put_user(0, &frame->rs_uc.uc_flags);
 	err |= __put_user(0, &frame->rs_uc.uc_link);
-        sp = (int) (long) current->sas_ss_sp;
+	sp = (int) (long) current->sas_ss_sp;
 	err |= __put_user(sp,
 	                  &frame->rs_uc.uc_stack.ss_sp);
 	err |= __put_user(sas_ss_flags(regs->regs[29]),
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c
index 1ee689c..64b62bd 100644
--- a/arch/mips/kernel/smp-mt.c
+++ b/arch/mips/kernel/smp-mt.c
@@ -35,7 +35,6 @@
 #include <asm/mipsregs.h>
 #include <asm/mipsmtregs.h>
 #include <asm/mips_mt.h>
-#include <asm/mips-boards/maltaint.h>  /* This is f*cking wrong */
 
 #define MIPS_CPU_IPI_RESCHED_IRQ 0
 #define MIPS_CPU_IPI_CALL_IRQ 1
@@ -108,12 +107,12 @@
 
 static void ipi_resched_dispatch(void)
 {
-	do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
+	do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
 }
 
 static void ipi_call_dispatch(void)
 {
-	do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ);
+	do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
 }
 
 static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
@@ -270,8 +269,8 @@
 		set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
 	}
 
-	cpu_ipi_resched_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
-	cpu_ipi_call_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ;
+	cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
+	cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ;
 
 	setup_irq(cpu_ipi_resched_irq, &irq_resched);
 	setup_irq(cpu_ipi_call_irq, &irq_call);
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index 6a857bf..9251ea8 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -26,16 +26,6 @@
  * This file should be built into the kernel only if CONFIG_MIPS_MT_SMTC is set.
  */
 
-/*
- * MIPSCPU_INT_BASE is identically defined in both
- * asm-mips/mips-boards/maltaint.h and asm-mips/mips-boards/simint.h,
- * but as yet there's no properly organized include structure that
- * will ensure that the right *int.h file will be included for a
- * given platform build.
- */
-
-#define MIPSCPU_INT_BASE	16
-
 #define MIPS_CPU_IPI_IRQ	1
 
 #define LOCK_MT_PRA() \
@@ -77,15 +67,15 @@
 
 #define IPIBUF_PER_CPU 4
 
-struct smtc_ipi_q IPIQ[NR_CPUS];
-struct smtc_ipi_q freeIPIq;
+static struct smtc_ipi_q IPIQ[NR_CPUS];
+static struct smtc_ipi_q freeIPIq;
 
 
 /* Forward declarations */
 
 void ipi_decode(struct smtc_ipi *);
-void post_direct_ipi(int cpu, struct smtc_ipi *pipi);
-void setup_cross_vpe_interrupts(void);
+static void post_direct_ipi(int cpu, struct smtc_ipi *pipi);
+static void setup_cross_vpe_interrupts(void);
 void init_smtc_stats(void);
 
 /* Global SMTC Status */
@@ -200,7 +190,7 @@
  * Configure shared TLB - VPC configuration bit must be set by caller
  */
 
-void smtc_configure_tlb(void)
+static void smtc_configure_tlb(void)
 {
 	int i,tlbsiz,vpes;
 	unsigned long mvpconf0;
@@ -648,7 +638,7 @@
  * the VPE.
  */
 
-void smtc_ipi_qdump(void)
+static void smtc_ipi_qdump(void)
 {
 	int i;
 
@@ -686,28 +676,6 @@
 	return result;
 }
 
-/* No longer used in IPI dispatch, but retained for future recycling */
-
-static __inline__ int atomic_postclear(unsigned int *pv)
-{
-	unsigned long result;
-
-	unsigned long temp;
-
-	__asm__ __volatile__(
-	"1:	ll	%0, %2					\n"
-	"	or	%1, $0, $0				\n"
-	"	sc	%1, %2					\n"
-	"	beqz	%1, 1b					\n"
-	"	sync						\n"
-	: "=&r" (result), "=&r" (temp), "=m" (*pv)
-	: "m" (*pv)
-	: "memory");
-
-	return result;
-}
-
-
 void smtc_send_ipi(int cpu, int type, unsigned int action)
 {
 	int tcstatus;
@@ -781,7 +749,7 @@
 /*
  * Send IPI message to Halted TC, TargTC/TargVPE already having been set
  */
-void post_direct_ipi(int cpu, struct smtc_ipi *pipi)
+static void post_direct_ipi(int cpu, struct smtc_ipi *pipi)
 {
 	struct pt_regs *kstack;
 	unsigned long tcstatus;
@@ -921,7 +889,7 @@
  * interrupts.
  */
 
-static int cpu_ipi_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_IRQ;
+static int cpu_ipi_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_IRQ;
 
 static irqreturn_t ipi_interrupt(int irq, void *dev_idm)
 {
@@ -1000,7 +968,7 @@
 
 static struct irqaction irq_ipi;
 
-void setup_cross_vpe_interrupts(void)
+static void setup_cross_vpe_interrupts(void)
 {
 	if (!cpu_has_vint)
 		panic("SMTC Kernel requires Vectored Interupt support");
@@ -1191,7 +1159,7 @@
 	 * It would be nice to be able to use a spinlock here,
 	 * but this is invoked from within TLB flush routines
 	 * that protect themselves with DVPE, so if a lock is
-         * held by another TC, it'll never be freed.
+	 * held by another TC, it'll never be freed.
 	 *
 	 * DVPE/DMT must not be done with interrupts enabled,
 	 * so even so most callers will already have disabled
@@ -1296,7 +1264,7 @@
  * Support for single-threading cache flush operations.
  */
 
-int halt_state_save[NR_CPUS];
+static int halt_state_save[NR_CPUS];
 
 /*
  * To really, really be sure that nothing is being done
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
index 6c2406a..93a1484 100644
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -669,7 +669,7 @@
 
 struct irix_statfs {
 	short f_type;
-        long  f_bsize, f_frsize, f_blocks, f_bfree, f_files, f_ffree;
+	long  f_bsize, f_frsize, f_blocks, f_bfree, f_files, f_ffree;
 	char  f_fname[6], f_fpack[6];
 };
 
@@ -959,7 +959,7 @@
 
 	fn = default_llseek;
 	if (file->f_op && file->f_op->llseek)
-        fn = file->f_op->llseek;
+	fn = file->f_op->llseek;
 	lock_kernel();
 	retval = fn(file, offset, origin);
 	unlock_kernel();
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
index 458fccf..4596249 100644
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -522,7 +522,7 @@
 };
 
 static char *rstrs[] = {
-    	[R_MIPS_NONE]	= "MIPS_NONE",
+	[R_MIPS_NONE]	= "MIPS_NONE",
 	[R_MIPS_32]	= "MIPS_32",
 	[R_MIPS_26]	= "MIPS_26",
 	[R_MIPS_HI16]	= "MIPS_HI16",
@@ -695,7 +695,7 @@
 }
 
 /* We are prepared so configure and start the VPE... */
-int vpe_run(struct vpe * v)
+static int vpe_run(struct vpe * v)
 {
 	struct vpe_notifications *n;
 	unsigned long val, dmt_flag;
@@ -713,16 +713,16 @@
 	dvpe();
 
 	if (!list_empty(&v->tc)) {
-                if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
-                        printk(KERN_WARNING "VPE loader: TC %d is already in use.\n",
-                               t->index);
-                        return -ENOEXEC;
-                }
-        } else {
-                printk(KERN_WARNING "VPE loader: No TC's associated with VPE %d\n",
-                       v->minor);
-                return -ENOEXEC;
-        }
+		if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
+			printk(KERN_WARNING "VPE loader: TC %d is already in use.\n",
+			       t->index);
+			return -ENOEXEC;
+		}
+	} else {
+		printk(KERN_WARNING "VPE loader: No TC's associated with VPE %d\n",
+		       v->minor);
+		return -ENOEXEC;
+	}
 
 	/* Put MVPE's into 'configuration state' */
 	set_c0_mvpcontrol(MVPCONTROL_VPC);
@@ -775,14 +775,14 @@
 
 	back_to_back_c0_hazard();
 
-        /* Set up the XTC bit in vpeconf0 to point at our tc */
-        write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC))
-                               | (t->index << VPECONF0_XTC_SHIFT));
+	/* Set up the XTC bit in vpeconf0 to point at our tc */
+	write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC))
+	                      | (t->index << VPECONF0_XTC_SHIFT));
 
 	back_to_back_c0_hazard();
 
-        /* enable this VPE */
-        write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
+	/* enable this VPE */
+	write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
 
 	/* clear out any left overs from a previous program */
 	write_vpe_c0_status(0);
@@ -832,7 +832,7 @@
  * contents of the program (p)buffer performing relocatations/etc, free's it
  * when finished.
  */
-int vpe_elfload(struct vpe * v)
+static int vpe_elfload(struct vpe * v)
 {
 	Elf_Ehdr *hdr;
 	Elf_Shdr *sechdrs;
diff --git a/arch/mips/lasat/interrupt.c b/arch/mips/lasat/interrupt.c
index 2affa5f..9a622b9 100644
--- a/arch/mips/lasat/interrupt.c
+++ b/arch/mips/lasat/interrupt.c
@@ -45,7 +45,7 @@
 }
 
 static struct irq_chip lasat_irq_type = {
-	.typename = "Lasat",
+	.name = "Lasat",
 	.ack = disable_lasat_irq,
 	.mask = disable_lasat_irq,
 	.mask_ack = disable_lasat_irq,
diff --git a/arch/mips/lasat/prom.c b/arch/mips/lasat/prom.c
index 88c7ab8..d47692f 100644
--- a/arch/mips/lasat/prom.c
+++ b/arch/mips/lasat/prom.c
@@ -132,9 +132,8 @@
 	add_memory_region(0, lasat_board_info.li_memsize, BOOT_MEM_RAM);
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	return 0;
 }
 
 const char *get_system_type(void)
diff --git a/arch/mips/lib-32/Makefile b/arch/mips/lib-32/Makefile
index dcd4d2e..2036cf5 100644
--- a/arch/mips/lib-32/Makefile
+++ b/arch/mips/lib-32/Makefile
@@ -2,7 +2,7 @@
 # Makefile for MIPS-specific library files..
 #
 
-lib-y	+= memset.o watch.o
+lib-y	+= watch.o
 
 obj-$(CONFIG_CPU_MIPS32)	+= dump_tlb.o
 obj-$(CONFIG_CPU_MIPS64)	+= dump_tlb.o
diff --git a/arch/mips/lib-64/Makefile b/arch/mips/lib-64/Makefile
index dcd4d2e..2036cf5 100644
--- a/arch/mips/lib-64/Makefile
+++ b/arch/mips/lib-64/Makefile
@@ -2,7 +2,7 @@
 # Makefile for MIPS-specific library files..
 #
 
-lib-y	+= memset.o watch.o
+lib-y	+= watch.o
 
 obj-$(CONFIG_CPU_MIPS32)	+= dump_tlb.o
 obj-$(CONFIG_CPU_MIPS64)	+= dump_tlb.o
diff --git a/arch/mips/lib-64/memset.S b/arch/mips/lib-64/memset.S
deleted file mode 100644
index e2c42c8..0000000
--- a/arch/mips/lib-64/memset.S
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * 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.
- *
- * Copyright (C) 1998, 1999, 2000 by Ralf Baechle
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- */
-#include <asm/asm.h>
-#include <asm/asm-offsets.h>
-#include <asm/regdef.h>
-
-#define EX(insn,reg,addr,handler)			\
-9:	insn	reg, addr;				\
-	.section __ex_table,"a"; 			\
-	PTR	9b, handler; 				\
-	.previous
-
-	.macro	f_fill64 dst, offset, val, fixup
-	EX(LONG_S, \val, (\offset +  0 * LONGSIZE)(\dst), \fixup)
-	EX(LONG_S, \val, (\offset +  1 * LONGSIZE)(\dst), \fixup)
-	EX(LONG_S, \val, (\offset +  2 * LONGSIZE)(\dst), \fixup)
-	EX(LONG_S, \val, (\offset +  3 * LONGSIZE)(\dst), \fixup)
-	EX(LONG_S, \val, (\offset +  4 * LONGSIZE)(\dst), \fixup)
-	EX(LONG_S, \val, (\offset +  5 * LONGSIZE)(\dst), \fixup)
-	EX(LONG_S, \val, (\offset +  6 * LONGSIZE)(\dst), \fixup)
-	EX(LONG_S, \val, (\offset +  7 * LONGSIZE)(\dst), \fixup)
-	.endm
-
-/*
- * memset(void *s, int c, size_t n)
- *
- * a0: start of area to clear
- * a1: char to fill with
- * a2: size of area to clear
- */
-	.set	noreorder
-	.align	5
-LEAF(memset)
-	beqz		a1, 1f
-	 move		v0, a0			/* result */
-
-	andi		a1, 0xff		/* spread fillword */
-	dsll		t1, a1, 8
-	or		a1, t1
-	dsll		t1, a1, 16
-	or		a1, t1
-	dsll		t1, a1, 32
-	or		a1, t1
-1:
-
-FEXPORT(__bzero)
-	sltiu		t0, a2, LONGSIZE	/* very small region? */
-	bnez		t0, small_memset
-	 andi		t0, a0, LONGMASK	/* aligned? */
-
-	beqz		t0, 1f
-	 PTR_SUBU	t0, LONGSIZE		/* alignment in bytes */
-
-#ifdef __MIPSEB__
-	EX(sdl, a1, (a0), first_fixup)		/* make dword aligned */
-#endif
-#ifdef __MIPSEL__
-	EX(sdr, a1, (a0), first_fixup)		/* make dword aligned */
-#endif
-	PTR_SUBU	a0, t0			/* long align ptr */
-	PTR_ADDU	a2, t0			/* correct size */
-
-1:	ori		t1, a2, 0x3f		/* # of full blocks */
-	xori		t1, 0x3f
-	beqz		t1, memset_partial	/* no block to fill */
-	 andi		t0, a2, 0x38
-
-	PTR_ADDU	t1, a0			/* end address */
-	.set		reorder
-1:	PTR_ADDIU	a0, 64
-	f_fill64 a0, -64, a1, fwd_fixup
-	bne		t1, a0, 1b
-	.set		noreorder
-
-memset_partial:
-	PTR_LA		t1, 2f			/* where to start */
-	.set		noat
-	dsrl		AT, t0, 1
-	PTR_SUBU	t1, AT
-	.set		noat
-	jr		t1
-	 PTR_ADDU	a0, t0			/* dest ptr */
-
-	.set		push
-	.set		noreorder
-	.set		nomacro
-	f_fill64 a0, -64, a1, partial_fixup	/* ... but first do longs ... */
-2:	.set		pop
-	andi		a2, LONGMASK		/* At most one long to go */
-
-	beqz		a2, 1f
-	 PTR_ADDU	a0, a2			/* What's left */
-#ifdef __MIPSEB__
-	EX(sdr, a1, -1(a0), last_fixup)
-#endif
-#ifdef __MIPSEL__
-	EX(sdl, a1, -1(a0), last_fixup)
-#endif
-1:	jr		ra
-	 move		a2, zero
-
-small_memset:
-	beqz		a2, 2f
-	 PTR_ADDU	t1, a0, a2
-
-1:	PTR_ADDIU	a0, 1			/* fill bytewise */
-	bne		t1, a0, 1b
-	 sb		a1, -1(a0)
-
-2:	jr		ra			/* done */
-	 move		a2, zero
-	END(memset)
-
-first_fixup:
-	jr	ra
-	 nop
-
-fwd_fixup:
-	PTR_L		t0, TI_TASK($28)
-	LONG_L		t0, THREAD_BUADDR(t0)
-	andi		a2, 0x3f
-	LONG_ADDU	a2, t1
-	jr		ra
-	 LONG_SUBU	a2, t0
-
-partial_fixup:
-	PTR_L		t0, TI_TASK($28)
-	LONG_L		t0, THREAD_BUADDR(t0)
-	andi		a2, LONGMASK
-	LONG_ADDU	a2, t1
-	jr		ra
-	 LONG_SUBU	a2, t0
-
-last_fixup:
-	jr		ra
-	 andi		v1, a2, LONGMASK
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index 989c900..5ad501b 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -2,7 +2,7 @@
 # Makefile for MIPS-specific library files..
 #
 
-lib-y	+= csum_partial.o memcpy.o promlib.o \
+lib-y	+= csum_partial.o memcpy.o memset.o promlib.o \
 	   strlen_user.o strncpy_user.o strnlen_user.o uncached.o
 
 obj-y	+= iomap.o
diff --git a/arch/mips/lib-32/memset.S b/arch/mips/lib/memset.S
similarity index 84%
rename from arch/mips/lib-32/memset.S
rename to arch/mips/lib/memset.S
index 1981485..3f8b8b3 100644
--- a/arch/mips/lib-32/memset.S
+++ b/arch/mips/lib/memset.S
@@ -10,6 +10,14 @@
 #include <asm/asm-offsets.h>
 #include <asm/regdef.h>
 
+#if LONGSIZE == 4
+#define LONG_S_L swl
+#define LONG_S_R swr
+#else
+#define LONG_S_L sdl
+#define LONG_S_R sdr
+#endif
+
 #define EX(insn,reg,addr,handler)			\
 9:	insn	reg, addr;				\
 	.section __ex_table,"a"; 			\
@@ -25,6 +33,7 @@
 	EX(LONG_S, \val, (\offset +  5 * LONGSIZE)(\dst), \fixup)
 	EX(LONG_S, \val, (\offset +  6 * LONGSIZE)(\dst), \fixup)
 	EX(LONG_S, \val, (\offset +  7 * LONGSIZE)(\dst), \fixup)
+#if LONGSIZE == 4
 	EX(LONG_S, \val, (\offset +  8 * LONGSIZE)(\dst), \fixup)
 	EX(LONG_S, \val, (\offset +  9 * LONGSIZE)(\dst), \fixup)
 	EX(LONG_S, \val, (\offset + 10 * LONGSIZE)(\dst), \fixup)
@@ -33,6 +42,7 @@
 	EX(LONG_S, \val, (\offset + 13 * LONGSIZE)(\dst), \fixup)
 	EX(LONG_S, \val, (\offset + 14 * LONGSIZE)(\dst), \fixup)
 	EX(LONG_S, \val, (\offset + 15 * LONGSIZE)(\dst), \fixup)
+#endif
 	.endm
 
 /*
@@ -49,9 +59,13 @@
 	 move		v0, a0			/* result */
 
 	andi		a1, 0xff		/* spread fillword */
-	sll		t1, a1, 8
+	LONG_SLL		t1, a1, 8
 	or		a1, t1
-	sll		t1, a1, 16
+	LONG_SLL		t1, a1, 16
+#if LONGSIZE == 8
+	or		a1, t1
+	LONG_SLL		t1, a1, 32
+#endif
 	or		a1, t1
 1:
 
@@ -64,10 +78,10 @@
 	 PTR_SUBU	t0, LONGSIZE		/* alignment in bytes */
 
 #ifdef __MIPSEB__
-	EX(swl, a1, (a0), first_fixup)		/* make word aligned */
+	EX(LONG_S_L, a1, (a0), first_fixup)	/* make word/dword aligned */
 #endif
 #ifdef __MIPSEL__
-	EX(swr, a1, (a0), first_fixup)		/* make word aligned */
+	EX(LONG_S_R, a1, (a0), first_fixup)	/* make word/dword aligned */
 #endif
 	PTR_SUBU	a0, t0			/* long align ptr */
 	PTR_ADDU	a2, t0			/* correct size */
@@ -75,7 +89,7 @@
 1:	ori		t1, a2, 0x3f		/* # of full blocks */
 	xori		t1, 0x3f
 	beqz		t1, memset_partial	/* no block to fill */
-	 andi		t0, a2, 0x3c
+	 andi		t0, a2, 0x40-LONGSIZE
 
 	PTR_ADDU	t1, a0			/* end address */
 	.set		reorder
@@ -86,7 +100,14 @@
 
 memset_partial:
 	PTR_LA		t1, 2f			/* where to start */
+#if LONGSIZE == 4
 	PTR_SUBU	t1, t0
+#else
+	.set		noat
+	LONG_SRL		AT, t0, 1
+	PTR_SUBU	t1, AT
+	.set		noat
+#endif
 	jr		t1
 	 PTR_ADDU	a0, t0			/* dest ptr */
 
@@ -100,10 +121,10 @@
 	beqz		a2, 1f
 	 PTR_ADDU	a0, a2			/* What's left */
 #ifdef __MIPSEB__
-	EX(swr, a1, -1(a0), last_fixup)
+	EX(LONG_S_R, a1, -1(a0), last_fixup)
 #endif
 #ifdef __MIPSEL__
-	EX(swl, a1, -1(a0), last_fixup)
+	EX(LONG_S_L, a1, -1(a0), last_fixup)
 #endif
 1:	jr		ra
 	 move		a2, zero
diff --git a/arch/mips/lib/uncached.c b/arch/mips/lib/uncached.c
index 98ce89f..2388f7f 100644
--- a/arch/mips/lib/uncached.c
+++ b/arch/mips/lib/uncached.c
@@ -44,20 +44,24 @@
 
 	if (sp >= (long)CKSEG0 && sp < (long)CKSEG2)
 		usp = CKSEG1ADDR(sp);
+#ifdef CONFIG_64BIT
 	else if ((long long)sp >= (long long)PHYS_TO_XKPHYS(0LL, 0) &&
 		 (long long)sp < (long long)PHYS_TO_XKPHYS(8LL, 0))
 		usp = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED,
 				     XKPHYS_TO_PHYS((long long)sp));
+#endif
 	else {
 		BUG();
 		usp = sp;
 	}
 	if (lfunc >= (long)CKSEG0 && lfunc < (long)CKSEG2)
 		ufunc = CKSEG1ADDR(lfunc);
+#ifdef CONFIG_64BIT
 	else if ((long long)lfunc >= (long long)PHYS_TO_XKPHYS(0LL, 0) &&
 		 (long long)lfunc < (long long)PHYS_TO_XKPHYS(8LL, 0))
 		ufunc = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED,
 				       XKPHYS_TO_PHYS((long long)lfunc));
+#endif
 	else {
 		BUG();
 		ufunc = lfunc;
diff --git a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c
index 43dba6c..dfa0acb 100644
--- a/arch/mips/mips-boards/atlas/atlas_int.c
+++ b/arch/mips/mips-boards/atlas/atlas_int.c
@@ -32,6 +32,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
+#include <linux/kernel.h>
 
 #include <asm/gdb-stub.h>
 #include <asm/io.h>
@@ -69,7 +70,7 @@
 }
 
 static struct irq_chip atlas_irq_type = {
-	.typename = "Atlas",
+	.name = "Atlas",
 	.ack = disable_atlas_irq,
 	.mask = disable_atlas_irq,
 	.mask_ack = disable_atlas_irq,
@@ -220,7 +221,7 @@
 	{MSC01C_INT_TMR,		MSC01_IRQ_EDGE, 0},
 	{MSC01C_INT_PCI,		MSC01_IRQ_LEVEL, 0},
 };
-int __initdata msc_nr_irqs = sizeof(msc_irqmap) / sizeof(*msc_irqmap);
+int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap);
 
 msc_irqmap_t __initdata msc_eicirqmap[] = {
 	{MSC01E_INT_SW0,		MSC01_IRQ_LEVEL, 0},
@@ -231,14 +232,14 @@
 	{MSC01E_INT_PERFCTR,		MSC01_IRQ_LEVEL, 0},
 	{MSC01E_INT_CPUCTR,		MSC01_IRQ_LEVEL, 0}
 };
-int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap) / sizeof(*msc_eicirqmap);
+int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap);
 
 void __init arch_init_irq(void)
 {
 	init_atlas_irqs(ATLAS_INT_BASE);
 
 	if (!cpu_has_veic)
-		mips_cpu_irq_init(MIPSCPU_INT_BASE);
+		mips_cpu_irq_init();
 
 	switch(mips_revision_corid) {
 	case MIPS_REVISION_CORID_CORE_MSC:
diff --git a/arch/mips/mips-boards/generic/memory.c b/arch/mips/mips-boards/generic/memory.c
index eeed944..ebf0e16 100644
--- a/arch/mips/mips-boards/generic/memory.c
+++ b/arch/mips/mips-boards/generic/memory.c
@@ -166,9 +166,8 @@
 	}
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	unsigned long freed = 0;
 	unsigned long addr;
 	int i;
 
@@ -176,17 +175,8 @@
 		if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
 			continue;
 
-		addr = PAGE_ALIGN(boot_mem_map.map[i].addr);
-		while (addr < boot_mem_map.map[i].addr
-			      + boot_mem_map.map[i].size) {
-			ClearPageReserved(virt_to_page(__va(addr)));
-			init_page_count(virt_to_page(__va(addr)));
-			free_page((unsigned long)__va(addr));
-			addr += PAGE_SIZE;
-			freed += PAGE_SIZE;
-		}
+		addr = boot_mem_map.map[i].addr;
+		free_init_pages("prom memory",
+				addr, addr + boot_mem_map.map[i].size);
 	}
-	printk("Freeing prom memory: %ldkb freed\n", freed >> 10);
-
-	return freed;
 }
diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c
index 90ad5bf..3c206bb 100644
--- a/arch/mips/mips-boards/malta/malta_int.c
+++ b/arch/mips/mips-boards/malta/malta_int.c
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
+#include <linux/kernel.h>
 #include <linux/random.h>
 
 #include <asm/i8259.h>
@@ -289,7 +290,7 @@
 	{MSC01C_INT_TMR,		MSC01_IRQ_EDGE, 0},
 	{MSC01C_INT_PCI,		MSC01_IRQ_LEVEL, 0},
 };
-int __initdata msc_nr_irqs = sizeof(msc_irqmap)/sizeof(msc_irqmap_t);
+int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap);
 
 msc_irqmap_t __initdata msc_eicirqmap[] = {
 	{MSC01E_INT_SW0,		MSC01_IRQ_LEVEL, 0},
@@ -303,14 +304,14 @@
 	{MSC01E_INT_PERFCTR,		MSC01_IRQ_LEVEL, 0},
 	{MSC01E_INT_CPUCTR,		MSC01_IRQ_LEVEL, 0}
 };
-int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap)/sizeof(msc_irqmap_t);
+int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap);
 
 void __init arch_init_irq(void)
 {
 	init_i8259_irqs();
 
 	if (!cpu_has_veic)
-		mips_cpu_irq_init (MIPSCPU_INT_BASE);
+		mips_cpu_irq_init();
 
         switch(mips_revision_corid) {
         case MIPS_REVISION_CORID_CORE_MSC:
diff --git a/arch/mips/mips-boards/sead/sead_int.c b/arch/mips/mips-boards/sead/sead_int.c
index 874ccb0..c4b9de3 100644
--- a/arch/mips/mips-boards/sead/sead_int.c
+++ b/arch/mips/mips-boards/sead/sead_int.c
@@ -113,5 +113,5 @@
 
 void __init arch_init_irq(void)
 {
-	mips_cpu_irq_init(MIPSCPU_INT_BASE);
+	mips_cpu_irq_init();
 }
diff --git a/arch/mips/mips-boards/sim/sim_int.c b/arch/mips/mips-boards/sim/sim_int.c
index 2ce449d..15ac065 100644
--- a/arch/mips/mips-boards/sim/sim_int.c
+++ b/arch/mips/mips-boards/sim/sim_int.c
@@ -21,9 +21,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <asm/mips-boards/simint.h>
-
-
-extern void mips_cpu_irq_init(int);
+#include <asm/irq_cpu.h>
 
 static inline int clz(unsigned long x)
 {
@@ -86,5 +84,5 @@
 
 void __init arch_init_irq(void)
 {
-	mips_cpu_irq_init(MIPSCPU_INT_BASE);
+	mips_cpu_irq_init();
 }
diff --git a/arch/mips/mips-boards/sim/sim_mem.c b/arch/mips/mips-boards/sim/sim_mem.c
index f7ce769..46bc16f 100644
--- a/arch/mips/mips-boards/sim/sim_mem.c
+++ b/arch/mips/mips-boards/sim/sim_mem.c
@@ -99,10 +99,9 @@
 	}
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
 	int i;
-	unsigned long freed = 0;
 	unsigned long addr;
 
 	for (i = 0; i < boot_mem_map.nr_map; i++) {
@@ -110,16 +109,7 @@
 			continue;
 
 		addr = boot_mem_map.map[i].addr;
-		while (addr < boot_mem_map.map[i].addr
-			      + boot_mem_map.map[i].size) {
-			ClearPageReserved(virt_to_page(__va(addr)));
-			init_page_count(virt_to_page(__va(addr)));
-			free_page((unsigned long)__va(addr));
-			addr += PAGE_SIZE;
-			freed += PAGE_SIZE;
-		}
+		free_init_pages("prom memory",
+				addr, addr + boot_mem_map.map[i].size);
 	}
-	printk("Freeing prom memory: %ldkb freed\n", freed >> 10);
-
-	return freed;
 }
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 49065c1..125a4a8 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -341,7 +341,6 @@
 void __init paging_init(void)
 {
 	unsigned long zones_size[MAX_NR_ZONES] = { 0, };
-	unsigned long max_dma, low;
 #ifndef CONFIG_FLATMEM
 	unsigned long zholes_size[MAX_NR_ZONES] = { 0, };
 	unsigned long i, j, pfn;
@@ -354,19 +353,19 @@
 #endif
 	kmap_coherent_init();
 
-	max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
-	low = max_low_pfn;
-
 #ifdef CONFIG_ISA
-	if (low < max_dma)
-		zones_size[ZONE_DMA] = low;
-	else {
-		zones_size[ZONE_DMA] = max_dma;
-		zones_size[ZONE_NORMAL] = low - max_dma;
-	}
-#else
-	zones_size[ZONE_DMA] = low;
+	if (max_low_pfn >= MAX_DMA_PFN)
+		if (min_low_pfn >= MAX_DMA_PFN) {
+			zones_size[ZONE_DMA] = 0;
+			zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn;
+		} else {
+			zones_size[ZONE_DMA] = MAX_DMA_PFN - min_low_pfn;
+			zones_size[ZONE_NORMAL] = max_low_pfn - MAX_DMA_PFN;
+		}
+	else
 #endif
+	zones_size[ZONE_DMA] = max_low_pfn - min_low_pfn;
+
 #ifdef CONFIG_HIGHMEM
 	zones_size[ZONE_HIGHMEM] = highend_pfn - highstart_pfn;
 
@@ -467,7 +466,7 @@
 }
 #endif /* !CONFIG_NEED_MULTIPLE_NODES */
 
-static void free_init_pages(char *what, unsigned long begin, unsigned long end)
+void free_init_pages(const char *what, unsigned long begin, unsigned long end)
 {
 	unsigned long pfn;
 
@@ -493,18 +492,25 @@
 }
 #endif
 
-extern unsigned long prom_free_prom_memory(void);
-
 void free_initmem(void)
 {
-	unsigned long freed;
-
-	freed = prom_free_prom_memory();
-	if (freed)
-		printk(KERN_INFO "Freeing firmware memory: %ldkb freed\n",
-		       freed >> 10);
-
+	prom_free_prom_memory();
 	free_init_pages("unused kernel memory",
 			__pa_symbol(&__init_begin),
 			__pa_symbol(&__init_end));
 }
+
+unsigned long pgd_current[NR_CPUS];
+/*
+ * On 64-bit we've got three-level pagetables with a slightly
+ * different layout ...
+ */
+#define __page_aligned(order) __attribute__((__aligned__(PAGE_SIZE<<order)))
+pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned(PGD_ORDER);
+#ifdef CONFIG_64BIT
+#ifdef MODULE_START
+pgd_t module_pg_dir[PTRS_PER_PGD] __page_aligned(PGD_ORDER);
+#endif
+pmd_t invalid_pmd_table[PTRS_PER_PMD] __page_aligned(PMD_ORDER);
+#endif
+pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned(PTE_ORDER);
diff --git a/arch/mips/momentum/jaguar_atx/Makefile b/arch/mips/momentum/jaguar_atx/Makefile
index 67372f3..2e8cebd 100644
--- a/arch/mips/momentum/jaguar_atx/Makefile
+++ b/arch/mips/momentum/jaguar_atx/Makefile
@@ -6,7 +6,7 @@
 # unless it's something special (ie not a .c file).
 #
 
-obj-y += irq.o prom.o reset.o setup.o
+obj-y += irq.o platform.o prom.o reset.o setup.o
 
 obj-$(CONFIG_SERIAL_8250_CONSOLE) += ja-console.o
 obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o
diff --git a/arch/mips/momentum/jaguar_atx/irq.c b/arch/mips/momentum/jaguar_atx/irq.c
index 2efb25a..f2b4325 100644
--- a/arch/mips/momentum/jaguar_atx/irq.c
+++ b/arch/mips/momentum/jaguar_atx/irq.c
@@ -82,8 +82,8 @@
 	 */
 	clear_c0_status(ST0_IM);
 
-	mips_cpu_irq_init(0);
-	rm7k_cpu_irq_init(8);
+	mips_cpu_irq_init();
+	rm7k_cpu_irq_init();
 
 	/* set up the cascading interrupts */
 	setup_irq(8, &cascade_mv64340);
diff --git a/arch/mips/momentum/jaguar_atx/jaguar_atx_fpga.h b/arch/mips/momentum/jaguar_atx/jaguar_atx_fpga.h
index 6978654..022f697 100644
--- a/arch/mips/momentum/jaguar_atx/jaguar_atx_fpga.h
+++ b/arch/mips/momentum/jaguar_atx/jaguar_atx_fpga.h
@@ -46,7 +46,9 @@
 
 extern unsigned long ja_fpga_base;
 
-#define JAGUAR_FPGA_WRITE(x,y) writeb(x, ja_fpga_base + JAGUAR_ATX_REG_##y)
-#define JAGUAR_FPGA_READ(x) readb(ja_fpga_base + JAGUAR_ATX_REG_##x)
+#define __FPGA_REG_TO_ADDR(reg)						\
+	((void *) ja_fpga_base + JAGUAR_ATX_REG_##reg)
+#define JAGUAR_FPGA_WRITE(x, reg) writeb(x, __FPGA_REG_TO_ADDR(reg))
+#define JAGUAR_FPGA_READ(reg) readb(__FPGA_REG_TO_ADDR(reg))
 
 #endif
diff --git a/arch/mips/momentum/jaguar_atx/platform.c b/arch/mips/momentum/jaguar_atx/platform.c
new file mode 100644
index 0000000..035ea51
--- /dev/null
+++ b/arch/mips/momentum/jaguar_atx/platform.c
@@ -0,0 +1,235 @@
+#include <linux/delay.h>
+#include <linux/if_ether.h>
+#include <linux/ioport.h>
+#include <linux/mv643xx.h>
+#include <linux/platform_device.h>
+
+#include "jaguar_atx_fpga.h"
+
+#if defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE)
+
+static struct resource mv643xx_eth_shared_resources[] = {
+	[0] = {
+		.name   = "ethernet shared base",
+		.start  = 0xf1000000 + MV643XX_ETH_SHARED_REGS,
+		.end    = 0xf1000000 + MV643XX_ETH_SHARED_REGS +
+		                       MV643XX_ETH_SHARED_REGS_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device mv643xx_eth_shared_device = {
+	.name		= MV643XX_ETH_SHARED_NAME,
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(mv643xx_eth_shared_resources),
+	.resource	= mv643xx_eth_shared_resources,
+};
+
+#define MV_SRAM_BASE			0xfe000000UL
+#define MV_SRAM_SIZE			(256 * 1024)
+
+#define MV_SRAM_RXRING_SIZE		(MV_SRAM_SIZE / 4)
+#define MV_SRAM_TXRING_SIZE		(MV_SRAM_SIZE / 4)
+
+#define MV_SRAM_BASE_ETH0		MV_SRAM_BASE
+#define MV_SRAM_BASE_ETH1		(MV_SRAM_BASE + (MV_SRAM_SIZE / 2))
+
+#define MV64x60_IRQ_ETH_0 48
+#define MV64x60_IRQ_ETH_1 49
+#define MV64x60_IRQ_ETH_2 50
+
+#ifdef CONFIG_MV643XX_ETH_0
+
+static struct resource mv64x60_eth0_resources[] = {
+	[0] = {
+		.name	= "eth0 irq",
+		.start	= MV64x60_IRQ_ETH_0,
+		.end	= MV64x60_IRQ_ETH_0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static char eth0_mac_addr[ETH_ALEN];
+
+static struct mv643xx_eth_platform_data eth0_pd = {
+	.mac_addr	= eth0_mac_addr,
+
+	.tx_sram_addr	= MV_SRAM_BASE_ETH0,
+	.tx_sram_size	= MV_SRAM_TXRING_SIZE,
+	.tx_queue_size	= MV_SRAM_TXRING_SIZE / 16,
+
+	.rx_sram_addr	= MV_SRAM_BASE_ETH0 + MV_SRAM_TXRING_SIZE,
+	.rx_sram_size	= MV_SRAM_RXRING_SIZE,
+	.rx_queue_size	= MV_SRAM_RXRING_SIZE / 16,
+};
+
+static struct platform_device eth0_device = {
+	.name		= MV643XX_ETH_NAME,
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(mv64x60_eth0_resources),
+	.resource	= mv64x60_eth0_resources,
+	.dev = {
+		.platform_data = &eth0_pd,
+	},
+};
+#endif /* CONFIG_MV643XX_ETH_0 */
+
+#ifdef CONFIG_MV643XX_ETH_1
+
+static struct resource mv64x60_eth1_resources[] = {
+	[0] = {
+		.name	= "eth1 irq",
+		.start	= MV64x60_IRQ_ETH_1,
+		.end	= MV64x60_IRQ_ETH_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static char eth1_mac_addr[ETH_ALEN];
+
+static struct mv643xx_eth_platform_data eth1_pd = {
+	.mac_addr	= eth1_mac_addr,
+
+	.tx_sram_addr	= MV_SRAM_BASE_ETH1,
+	.tx_sram_size	= MV_SRAM_TXRING_SIZE,
+	.tx_queue_size	= MV_SRAM_TXRING_SIZE / 16,
+
+	.rx_sram_addr	= MV_SRAM_BASE_ETH1 + MV_SRAM_TXRING_SIZE,
+	.rx_sram_size	= MV_SRAM_RXRING_SIZE,
+	.rx_queue_size	= MV_SRAM_RXRING_SIZE / 16,
+};
+
+static struct platform_device eth1_device = {
+	.name		= MV643XX_ETH_NAME,
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(mv64x60_eth1_resources),
+	.resource	= mv64x60_eth1_resources,
+	.dev = {
+		.platform_data = &eth1_pd,
+	},
+};
+#endif /* CONFIG_MV643XX_ETH_1 */
+
+#ifdef CONFIG_MV643XX_ETH_2
+
+static struct resource mv64x60_eth2_resources[] = {
+	[0] = {
+		.name	= "eth2 irq",
+		.start	= MV64x60_IRQ_ETH_2,
+		.end	= MV64x60_IRQ_ETH_2,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static char eth2_mac_addr[ETH_ALEN];
+
+static struct mv643xx_eth_platform_data eth2_pd = {
+	.mac_addr	= eth2_mac_addr,
+};
+
+static struct platform_device eth2_device = {
+	.name		= MV643XX_ETH_NAME,
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(mv64x60_eth2_resources),
+	.resource	= mv64x60_eth2_resources,
+	.dev = {
+		.platform_data = &eth2_pd,
+	},
+};
+#endif /* CONFIG_MV643XX_ETH_2 */
+
+static struct platform_device *mv643xx_eth_pd_devs[] __initdata = {
+	&mv643xx_eth_shared_device,
+#ifdef CONFIG_MV643XX_ETH_0
+	&eth0_device,
+#endif
+#ifdef CONFIG_MV643XX_ETH_1
+	&eth1_device,
+#endif
+#ifdef CONFIG_MV643XX_ETH_2
+	&eth2_device,
+#endif
+};
+
+static u8 __init exchange_bit(u8 val, u8 cs)
+{
+	/* place the data */
+	JAGUAR_FPGA_WRITE((val << 2) | cs, EEPROM_MODE);
+	udelay(1);
+
+	/* turn the clock on */
+	JAGUAR_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE);
+	udelay(1);
+
+	/* turn the clock off and read-strobe */
+	JAGUAR_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);
+
+	/* return the data */
+	return (JAGUAR_FPGA_READ(EEPROM_MODE) >> 3) & 0x1;
+}
+
+static void __init get_mac(char dest[6])
+{
+	u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+	int i,j;
+
+	for (i = 0; i < 12; i++)
+		exchange_bit(read_opcode[i], 1);
+
+	for (j = 0; j < 6; j++) {
+		dest[j] = 0;
+		for (i = 0; i < 8; i++) {
+			dest[j] <<= 1;
+			dest[j] |= exchange_bit(0, 1);
+		}
+	}
+
+	/* turn off CS */
+	exchange_bit(0,0);
+}
+
+/*
+ * Copy and increment ethernet MAC address by a small value.
+ *
+ * This is useful for systems where the only one MAC address is stored in
+ * non-volatile memory for multiple ports.
+ */
+static inline void eth_mac_add(unsigned char *dst, unsigned char *src,
+	unsigned int add)
+{
+	int i;
+
+	BUG_ON(add >= 256);
+
+	for (i = ETH_ALEN; i >= 0; i--) {
+		dst[i] = src[i] + add;
+		add = dst[i] < src[i];		/* compute carry */
+	}
+
+	WARN_ON(add);
+}
+
+static int __init mv643xx_eth_add_pds(void)
+{
+	unsigned char mac[ETH_ALEN];
+	int ret;
+
+	get_mac(mac);
+#ifdef CONFIG_MV643XX_ETH_0
+	eth_mac_add(eth1_mac_addr, mac, 0);
+#endif
+#ifdef CONFIG_MV643XX_ETH_1
+	eth_mac_add(eth1_mac_addr, mac, 1);
+#endif
+#ifdef CONFIG_MV643XX_ETH_2
+	eth_mac_add(eth2_mac_addr, mac, 2);
+#endif
+	ret = platform_add_devices(mv643xx_eth_pd_devs,
+			ARRAY_SIZE(mv643xx_eth_pd_devs));
+
+	return ret;
+}
+
+device_initcall(mv643xx_eth_add_pds);
+
+#endif /* defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE) */
diff --git a/arch/mips/momentum/jaguar_atx/prom.c b/arch/mips/momentum/jaguar_atx/prom.c
index 3d27129..5dd154e 100644
--- a/arch/mips/momentum/jaguar_atx/prom.c
+++ b/arch/mips/momentum/jaguar_atx/prom.c
@@ -39,56 +39,6 @@
 	return "Momentum Jaguar-ATX";
 }
 
-#ifdef CONFIG_MV643XX_ETH
-extern unsigned char prom_mac_addr_base[6];
-
-static void burn_clocks(void)
-{
-	int i;
-
-	/* this loop should burn at least 1us -- this should be plenty */
-	for (i = 0; i < 0x10000; i++)
-		;
-}
-
-static u8 exchange_bit(u8 val, u8 cs)
-{
-	/* place the data */
-	JAGUAR_FPGA_WRITE((val << 2) | cs, EEPROM_MODE);
-	burn_clocks();
-
-	/* turn the clock on */
-	JAGUAR_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE);
-	burn_clocks();
-
-	/* turn the clock off and read-strobe */
-	JAGUAR_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);
-
-	/* return the data */
-	return ((JAGUAR_FPGA_READ(EEPROM_MODE) >> 3) & 0x1);
-}
-
-void get_mac(char dest[6])
-{
-	u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-	int i,j;
-
-	for (i = 0; i < 12; i++)
-		exchange_bit(read_opcode[i], 1);
-
-	for (j = 0; j < 6; j++) {
-		dest[j] = 0;
-		for (i = 0; i < 8; i++) {
-			dest[j] <<= 1;
-			dest[j] |= exchange_bit(0, 1);
-		}
-	}
-
-	/* turn off CS */
-	exchange_bit(0,0);
-}
-#endif
-
 #ifdef CONFIG_64BIT
 
 unsigned long signext(unsigned long addr)
@@ -228,16 +178,10 @@
 #endif /* CONFIG_64BIT */
 	mips_machgroup = MACH_GROUP_MOMENCO;
 	mips_machtype = MACH_MOMENCO_JAGUAR_ATX;
-
-#ifdef CONFIG_MV643XX_ETH
-	/* get the base MAC address for on-board ethernet ports */
-	get_mac(prom_mac_addr_base);
-#endif
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	return 0;
 }
 
 void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
diff --git a/arch/mips/momentum/ocelot_3/irq.c b/arch/mips/momentum/ocelot_3/irq.c
index cea0e5d..3862d1d 100644
--- a/arch/mips/momentum/ocelot_3/irq.c
+++ b/arch/mips/momentum/ocelot_3/irq.c
@@ -65,7 +65,7 @@
 	 */
 	clear_c0_status(ST0_IM | ST0_BEV);
 
-	rm7k_cpu_irq_init(8);
+	rm7k_cpu_irq_init();
 
 	/* set up the cascading interrupts */
 	setup_irq(8, &cascade_mv64340);		/* unmask intControl IM8, IRQ 9 */
diff --git a/arch/mips/momentum/ocelot_3/prom.c b/arch/mips/momentum/ocelot_3/prom.c
index 6ce9b7f..8e02df6 100644
--- a/arch/mips/momentum/ocelot_3/prom.c
+++ b/arch/mips/momentum/ocelot_3/prom.c
@@ -180,9 +180,8 @@
 #endif
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	return 0;
 }
 
 void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
diff --git a/arch/mips/momentum/ocelot_c/cpci-irq.c b/arch/mips/momentum/ocelot_c/cpci-irq.c
index bb11fef..186a140 100644
--- a/arch/mips/momentum/ocelot_c/cpci-irq.c
+++ b/arch/mips/momentum/ocelot_c/cpci-irq.c
@@ -84,7 +84,7 @@
 }
 
 struct irq_chip cpci_irq_type = {
-	.typename = "CPCI/FPGA",
+	.name = "CPCI/FPGA",
 	.ack = mask_cpci_irq,
 	.mask = mask_cpci_irq,
 	.mask_ack = mask_cpci_irq,
diff --git a/arch/mips/momentum/ocelot_c/dbg_io.c b/arch/mips/momentum/ocelot_c/dbg_io.c
index 2128684..32d6fb4 100644
--- a/arch/mips/momentum/ocelot_c/dbg_io.c
+++ b/arch/mips/momentum/ocelot_c/dbg_io.c
@@ -1,6 +1,4 @@
 
-#ifdef CONFIG_KGDB
-
 #include <asm/serial.h> /* For the serial port location and base baud */
 
 /* --- CONFIG --- */
@@ -121,5 +119,3 @@
 	UART16550_WRITE(OFS_SEND_BUFFER, byte);
 	return 1;
 }
-
-#endif
diff --git a/arch/mips/momentum/ocelot_c/irq.c b/arch/mips/momentum/ocelot_c/irq.c
index ea65223..40472f7 100644
--- a/arch/mips/momentum/ocelot_c/irq.c
+++ b/arch/mips/momentum/ocelot_c/irq.c
@@ -94,7 +94,7 @@
 	 */
 	clear_c0_status(ST0_IM);
 
-	mips_cpu_irq_init(0);
+	mips_cpu_irq_init();
 
 	/* set up the cascading interrupts */
 	setup_irq(3, &cascade_fpga);
diff --git a/arch/mips/momentum/ocelot_c/prom.c b/arch/mips/momentum/ocelot_c/prom.c
index d0b77e1..b689cee 100644
--- a/arch/mips/momentum/ocelot_c/prom.c
+++ b/arch/mips/momentum/ocelot_c/prom.c
@@ -178,7 +178,6 @@
 #endif
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	return 0;
 }
diff --git a/arch/mips/momentum/ocelot_c/uart-irq.c b/arch/mips/momentum/ocelot_c/uart-irq.c
index a7a80c0..de1a31e 100644
--- a/arch/mips/momentum/ocelot_c/uart-irq.c
+++ b/arch/mips/momentum/ocelot_c/uart-irq.c
@@ -77,7 +77,7 @@
 }
 
 struct irq_chip uart_irq_type = {
-	.typename = "UART/FPGA",
+	.name = "UART/FPGA",
 	.ack = mask_uart_irq,
 	.mask = mask_uart_irq,
 	.mask_ack = mask_uart_irq,
diff --git a/arch/mips/momentum/ocelot_g/dbg_io.c b/arch/mips/momentum/ocelot_g/dbg_io.c
index 2128684..32d6fb4 100644
--- a/arch/mips/momentum/ocelot_g/dbg_io.c
+++ b/arch/mips/momentum/ocelot_g/dbg_io.c
@@ -1,6 +1,4 @@
 
-#ifdef CONFIG_KGDB
-
 #include <asm/serial.h> /* For the serial port location and base baud */
 
 /* --- CONFIG --- */
@@ -121,5 +119,3 @@
 	UART16550_WRITE(OFS_SEND_BUFFER, byte);
 	return 1;
 }
-
-#endif
diff --git a/arch/mips/momentum/ocelot_g/irq.c b/arch/mips/momentum/ocelot_g/irq.c
index da46524..273541f 100644
--- a/arch/mips/momentum/ocelot_g/irq.c
+++ b/arch/mips/momentum/ocelot_g/irq.c
@@ -94,8 +94,8 @@
 	clear_c0_status(ST0_IM);
 	local_irq_disable();
 
-	mips_cpu_irq_init(0);
-	rm7k_cpu_irq_init(8);
+	mips_cpu_irq_init();
+	rm7k_cpu_irq_init();
 
 	gt64240_irq_init();
 }
diff --git a/arch/mips/momentum/ocelot_g/prom.c b/arch/mips/momentum/ocelot_g/prom.c
index 2f75c6b..836d083 100644
--- a/arch/mips/momentum/ocelot_g/prom.c
+++ b/arch/mips/momentum/ocelot_g/prom.c
@@ -79,7 +79,6 @@
 	}
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	return 0;
 }
diff --git a/arch/mips/oprofile/Kconfig b/arch/mips/oprofile/Kconfig
index 55feaf7..ca395ef 100644
--- a/arch/mips/oprofile/Kconfig
+++ b/arch/mips/oprofile/Kconfig
@@ -11,7 +11,7 @@
 
 config OPROFILE
 	tristate "OProfile system profiling (EXPERIMENTAL)"
-	depends on PROFILING && EXPERIMENTAL
+	depends on PROFILING && !!MIPS_MT_SMTC && EXPERIMENTAL
 	help
 	  OProfile is a profiling system capable of profiling the
 	  whole system, include the kernel, kernel modules, libraries,
diff --git a/arch/mips/pci/fixup-vr4133.c b/arch/mips/pci/fixup-vr4133.c
index 597b897..a8d9d22 100644
--- a/arch/mips/pci/fixup-vr4133.c
+++ b/arch/mips/pci/fixup-vr4133.c
@@ -17,8 +17,10 @@
  */
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/kernel.h>
 
 #include <asm/io.h>
+#include <asm/i8259.h>
 #include <asm/vr41xx/cmbvr4133.h>
 
 extern int vr4133_rockhopper;
@@ -142,7 +144,7 @@
 	if (bus == NULL)
 		return -1;
 
-	for (i = 0; i < sizeof (int_map) / sizeof (int_map[0]); i++) {
+	for (i = 0; i < ARRAY_SIZE(int_map); i++) {
 		if (int_map[i].bus == bus->number && int_map[i].slot == slot) {
 			int line;
 			for (line = 0; line < 4; line++)
@@ -160,17 +162,7 @@
 #ifdef CONFIG_ROCKHOPPER
 void i8259_init(void)
 {
-	outb(0x11, 0x20);		/* Master ICW1 */
-	outb(I8259_IRQ_BASE, 0x21);	/* Master ICW2 */
-	outb(0x04, 0x21);		/* Master ICW3 */
-	outb(0x01, 0x21);		/* Master ICW4 */
-	outb(0xff, 0x21);		/* Master IMW */
-
-	outb(0x11, 0xa0);		/* Slave ICW1 */
-	outb(I8259_IRQ_BASE + 8, 0xa1);	/* Slave ICW2 */
-	outb(0x02, 0xa1);		/* Slave ICW3 */
-	outb(0x01, 0xa1);		/* Slave ICW4 */
-	outb(0xff, 0xa1);		/* Slave IMW */
+	init_i8259_irqs();
 
 	outb(0x00, 0x4d0);
 	outb(0x02, 0x4d1);	/* USB IRQ9 is level */
diff --git a/arch/mips/philips/pnx8550/common/int.c b/arch/mips/philips/pnx8550/common/int.c
index 2c36c10..d48665e 100644
--- a/arch/mips/philips/pnx8550/common/int.c
+++ b/arch/mips/philips/pnx8550/common/int.c
@@ -159,7 +159,7 @@
 }
 
 static struct irq_chip level_irq_type = {
-	.typename =	"PNX Level IRQ",
+	.name =		"PNX Level IRQ",
 	.ack =		mask_irq,
 	.mask =		mask_irq,
 	.mask_ack =	mask_irq,
diff --git a/arch/mips/philips/pnx8550/common/prom.c b/arch/mips/philips/pnx8550/common/prom.c
index eb6ec11..8aeed6c 100644
--- a/arch/mips/philips/pnx8550/common/prom.c
+++ b/arch/mips/philips/pnx8550/common/prom.c
@@ -106,9 +106,8 @@
 	return 0;
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	return 0;
 }
 
 extern int pnx8550_console_port;
diff --git a/arch/mips/pmc-sierra/yosemite/dbg_io.c b/arch/mips/pmc-sierra/yosemite/dbg_io.c
index 0f659c9..6362c70 100644
--- a/arch/mips/pmc-sierra/yosemite/dbg_io.c
+++ b/arch/mips/pmc-sierra/yosemite/dbg_io.c
@@ -93,7 +93,7 @@
  * Functions to READ and WRITE to serial port 1
  */
 #define	SERIAL_READ_1(ofs)		(*((volatile unsigned char*)	\
-					(TITAN_SERIAL_BASE_1 + ofs)
+					(TITAN_SERIAL_BASE_1 + ofs)))
 
 #define	SERIAL_WRITE_1(ofs, val)	((*((volatile unsigned char*)	\
 					(TITAN_SERIAL_BASE_1 + ofs))) = val)
diff --git a/arch/mips/pmc-sierra/yosemite/irq.c b/arch/mips/pmc-sierra/yosemite/irq.c
index adb0485..428d1f4 100644
--- a/arch/mips/pmc-sierra/yosemite/irq.c
+++ b/arch/mips/pmc-sierra/yosemite/irq.c
@@ -148,9 +148,9 @@
 {
 	clear_c0_status(ST0_IM);
 
-	mips_cpu_irq_init(0);
-	rm7k_cpu_irq_init(8);
-	rm9k_cpu_irq_init(12);
+	mips_cpu_irq_init();
+	rm7k_cpu_irq_init();
+	rm9k_cpu_irq_init();
 
 #ifdef CONFIG_KGDB
 	/* At this point, initialize the second serial port */
diff --git a/arch/mips/pmc-sierra/yosemite/prom.c b/arch/mips/pmc-sierra/yosemite/prom.c
index 9fe4973..1e1685e 100644
--- a/arch/mips/pmc-sierra/yosemite/prom.c
+++ b/arch/mips/pmc-sierra/yosemite/prom.c
@@ -132,9 +132,8 @@
 	prom_grab_secondary();
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	return 0;
 }
 
 void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c
index 1b9b0d3..6a6e15e 100644
--- a/arch/mips/pmc-sierra/yosemite/setup.c
+++ b/arch/mips/pmc-sierra/yosemite/setup.c
@@ -171,6 +171,7 @@
 
 static void __init py_uart_setup(void)
 {
+#ifdef CONFIG_SERIAL_8250
 	struct uart_port up;
 
 	/*
@@ -188,6 +189,7 @@
 
 	if (early_serial_setup(&up))
 		printk(KERN_ERR "Early serial init of port 0 failed\n");
+#endif /* CONFIG_SERIAL_8250 */
 }
 
 static void __init py_rtc_setup(void)
diff --git a/arch/mips/qemu/q-mem.c b/arch/mips/qemu/q-mem.c
index d174fac..dae39b5 100644
--- a/arch/mips/qemu/q-mem.c
+++ b/arch/mips/qemu/q-mem.c
@@ -1,6 +1,5 @@
 #include <linux/init.h>
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	return 0UL;
 }
diff --git a/arch/mips/sgi-ip22/ip22-eisa.c b/arch/mips/sgi-ip22/ip22-eisa.c
index a1a9af6..6b6e97b 100644
--- a/arch/mips/sgi-ip22/ip22-eisa.c
+++ b/arch/mips/sgi-ip22/ip22-eisa.c
@@ -139,7 +139,7 @@
 }
 
 static struct irq_chip ip22_eisa1_irq_type = {
-	.typename	= "IP22 EISA",
+	.name		= "IP22 EISA",
 	.startup	= startup_eisa1_irq,
 	.ack		= mask_and_ack_eisa1_irq,
 	.mask		= disable_eisa1_irq,
@@ -194,7 +194,7 @@
 }
 
 static struct irq_chip ip22_eisa2_irq_type = {
-	.typename	= "IP22 EISA",
+	.name		= "IP22 EISA",
 	.startup	= startup_eisa2_irq,
 	.ack		= mask_and_ack_eisa2_irq,
 	.mask		= disable_eisa2_irq,
diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c
index c44f8be..b454924 100644
--- a/arch/mips/sgi-ip22/ip22-int.c
+++ b/arch/mips/sgi-ip22/ip22-int.c
@@ -19,6 +19,7 @@
 
 #include <asm/mipsregs.h>
 #include <asm/addrspace.h>
+#include <asm/irq_cpu.h>
 
 #include <asm/sgi/ioc.h>
 #include <asm/sgi/hpc3.h>
@@ -52,7 +53,7 @@
 }
 
 static struct irq_chip ip22_local0_irq_type = {
-	.typename	= "IP22 local 0",
+	.name		= "IP22 local 0",
 	.ack		= disable_local0_irq,
 	.mask		= disable_local0_irq,
 	.mask_ack	= disable_local0_irq,
@@ -73,7 +74,7 @@
 }
 
 static struct irq_chip ip22_local1_irq_type = {
-	.typename	= "IP22 local 1",
+	.name		= "IP22 local 1",
 	.ack		= disable_local1_irq,
 	.mask		= disable_local1_irq,
 	.mask_ack	= disable_local1_irq,
@@ -94,7 +95,7 @@
 }
 
 static struct irq_chip ip22_local2_irq_type = {
-	.typename	= "IP22 local 2",
+	.name		= "IP22 local 2",
 	.ack		= disable_local2_irq,
 	.mask		= disable_local2_irq,
 	.mask_ack	= disable_local2_irq,
@@ -115,7 +116,7 @@
 }
 
 static struct irq_chip ip22_local3_irq_type = {
-	.typename	= "IP22 local 3",
+	.name		= "IP22 local 3",
 	.ack		= disable_local3_irq,
 	.mask		= disable_local3_irq,
 	.mask_ack	= disable_local3_irq,
@@ -253,8 +254,6 @@
 		indy_8254timer_irq();
 }
 
-extern void mips_cpu_irq_init(unsigned int irq_base);
-
 void __init arch_init_irq(void)
 {
 	int i;
@@ -316,7 +315,7 @@
 	sgint->cmeimask1 = 0;
 
 	/* init CPU irqs */
-	mips_cpu_irq_init(SGINT_CPU);
+	mips_cpu_irq_init();
 
 	for (i = SGINT_LOCAL0; i < SGI_INTERRUPTS; i++) {
 		struct irq_chip *handler;
diff --git a/arch/mips/sgi-ip22/ip22-mc.c b/arch/mips/sgi-ip22/ip22-mc.c
index b58bd52..ddb6506 100644
--- a/arch/mips/sgi-ip22/ip22-mc.c
+++ b/arch/mips/sgi-ip22/ip22-mc.c
@@ -202,7 +202,6 @@
 }
 
 void __init prom_meminit(void) {}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	return 0;
 }
diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c
index 319f880..60ade76 100644
--- a/arch/mips/sgi-ip27/ip27-irq.c
+++ b/arch/mips/sgi-ip27/ip27-irq.c
@@ -333,7 +333,7 @@
 }
 
 static struct irq_chip bridge_irq_type = {
-	.typename	= "bridge",
+	.name		= "bridge",
 	.startup	= startup_bridge_irq,
 	.shutdown	= shutdown_bridge_irq,
 	.ack		= disable_bridge_irq,
diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c
index 16e5682..0e3d535 100644
--- a/arch/mips/sgi-ip27/ip27-memory.c
+++ b/arch/mips/sgi-ip27/ip27-memory.c
@@ -498,10 +498,9 @@
 	}
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
 	/* We got nothing to free here ...  */
-	return 0;
 }
 
 extern void pagetable_init(void);
diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c
index c20e989..9ce5136 100644
--- a/arch/mips/sgi-ip27/ip27-timer.c
+++ b/arch/mips/sgi-ip27/ip27-timer.c
@@ -181,7 +181,7 @@
 }
 
 static struct irq_chip rt_irq_type = {
-	.typename	= "SN HUB RT timer",
+	.name		= "SN HUB RT timer",
 	.ack		= disable_rt_irq,
 	.mask		= disable_rt_irq,
 	.mask_ack	= disable_rt_irq,
diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c
index ae06386..8c450d9 100644
--- a/arch/mips/sgi-ip32/ip32-irq.c
+++ b/arch/mips/sgi-ip32/ip32-irq.c
@@ -144,7 +144,7 @@
 }
 
 static struct irq_chip ip32_cpu_interrupt = {
-	.typename = "IP32 CPU",
+	.name = "IP32 CPU",
 	.ack = disable_cpu_irq,
 	.mask = disable_cpu_irq,
 	.mask_ack = disable_cpu_irq,
@@ -193,7 +193,7 @@
 }
 
 static struct irq_chip ip32_crime_interrupt = {
-	.typename = "IP32 CRIME",
+	.name = "IP32 CRIME",
 	.ack = mask_and_ack_crime_irq,
 	.mask = disable_crime_irq,
 	.mask_ack = mask_and_ack_crime_irq,
@@ -234,7 +234,7 @@
 }
 
 static struct irq_chip ip32_macepci_interrupt = {
-	.typename = "IP32 MACE PCI",
+	.name = "IP32 MACE PCI",
 	.ack = disable_macepci_irq,
 	.mask = disable_macepci_irq,
 	.mask_ack = disable_macepci_irq,
@@ -347,7 +347,7 @@
 }
 
 static struct irq_chip ip32_maceisa_interrupt = {
-	.typename = "IP32 MACE ISA",
+	.name = "IP32 MACE ISA",
 	.ack = mask_and_ack_maceisa_irq,
 	.mask = disable_maceisa_irq,
 	.mask_ack = mask_and_ack_maceisa_irq,
@@ -379,7 +379,7 @@
 }
 
 static struct irq_chip ip32_mace_interrupt = {
-	.typename = "IP32 MACE",
+	.name = "IP32 MACE",
 	.ack = disable_mace_irq,
 	.mask = disable_mace_irq,
 	.mask_ack = disable_mace_irq,
diff --git a/arch/mips/sgi-ip32/ip32-memory.c b/arch/mips/sgi-ip32/ip32-memory.c
index d37d40a..849d392 100644
--- a/arch/mips/sgi-ip32/ip32-memory.c
+++ b/arch/mips/sgi-ip32/ip32-memory.c
@@ -43,7 +43,6 @@
 }
 
 
-unsigned long __init prom_free_prom_memory (void)
+void __init prom_free_prom_memory(void)
 {
-	return 0;
 }
diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c
index 2e8f6b2..1dc5d05 100644
--- a/arch/mips/sibyte/bcm1480/irq.c
+++ b/arch/mips/sibyte/bcm1480/irq.c
@@ -82,7 +82,7 @@
 #endif
 
 static struct irq_chip bcm1480_irq_type = {
-	.typename = "BCM1480-IMR",
+	.name = "BCM1480-IMR",
 	.ack = ack_bcm1480_irq,
 	.mask = disable_bcm1480_irq,
 	.mask_ack = ack_bcm1480_irq,
diff --git a/arch/mips/sibyte/cfe/setup.c b/arch/mips/sibyte/cfe/setup.c
index 6e8952d..9e6099e 100644
--- a/arch/mips/sibyte/cfe/setup.c
+++ b/arch/mips/sibyte/cfe/setup.c
@@ -343,10 +343,9 @@
 	prom_meminit();
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
 	/* Not sure what I'm supposed to do here.  Nothing, I think */
-	return 0;
 }
 
 void prom_putchar(char c)
diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c
index 82ce753..1482394 100644
--- a/arch/mips/sibyte/sb1250/irq.c
+++ b/arch/mips/sibyte/sb1250/irq.c
@@ -67,7 +67,7 @@
 #endif
 
 static struct irq_chip sb1250_irq_type = {
-	.typename = "SB1250-IMR",
+	.name = "SB1250-IMR",
 	.ack = ack_sb1250_irq,
 	.mask = disable_sb1250_irq,
 	.mask_ack = ack_sb1250_irq,
diff --git a/arch/mips/sibyte/sb1250/prom.c b/arch/mips/sibyte/sb1250/prom.c
index 3c33a45..257c4e6 100644
--- a/arch/mips/sibyte/sb1250/prom.c
+++ b/arch/mips/sibyte/sb1250/prom.c
@@ -87,10 +87,9 @@
 	prom_meminit();
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
 	/* Not sure what I'm supposed to do here.  Nothing, I think */
-	return 0;
 }
 
 void prom_putchar(char c)
diff --git a/arch/mips/sni/irq.c b/arch/mips/sni/irq.c
index 8511bcc..039e8e5 100644
--- a/arch/mips/sni/irq.c
+++ b/arch/mips/sni/irq.c
@@ -37,7 +37,7 @@
 }
 
 static struct irq_chip pciasic_irq_type = {
-	.typename = "ASIC-PCI",
+	.name = "ASIC-PCI",
 	.ack = disable_pciasic_irq,
 	.mask = disable_pciasic_irq,
 	.mask_ack = disable_pciasic_irq,
diff --git a/arch/mips/sni/sniprom.c b/arch/mips/sni/sniprom.c
index d1d0f1f..1213d16 100644
--- a/arch/mips/sni/sniprom.c
+++ b/arch/mips/sni/sniprom.c
@@ -67,9 +67,8 @@
 	va_end(args);
 }
 
-unsigned long prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	return 0;
 }
 
 /*
diff --git a/arch/mips/tx4927/common/tx4927_irq.c b/arch/mips/tx4927/common/tx4927_irq.c
index ed4a19a..e7f3e5b 100644
--- a/arch/mips/tx4927/common/tx4927_irq.c
+++ b/arch/mips/tx4927/common/tx4927_irq.c
@@ -120,7 +120,7 @@
 
 #define TX4927_CP0_NAME "TX4927-CP0"
 static struct irq_chip tx4927_irq_cp0_type = {
-	.typename	= TX4927_CP0_NAME,
+	.name		= TX4927_CP0_NAME,
 	.ack		= tx4927_irq_cp0_disable,
 	.mask		= tx4927_irq_cp0_disable,
 	.mask_ack	= tx4927_irq_cp0_disable,
@@ -129,7 +129,7 @@
 
 #define TX4927_PIC_NAME "TX4927-PIC"
 static struct irq_chip tx4927_irq_pic_type = {
-	.typename	= TX4927_PIC_NAME,
+	.name		= TX4927_PIC_NAME,
 	.ack		= tx4927_irq_pic_disable,
 	.mask		= tx4927_irq_pic_disable,
 	.mask_ack	= tx4927_irq_pic_disable,
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
index b54b529..dcce88f 100644
--- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
+++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
@@ -228,7 +228,7 @@
 
 #define TOSHIBA_RBTX4927_IOC_NAME "RBTX4927-IOC"
 static struct irq_chip toshiba_rbtx4927_irq_ioc_type = {
-	.typename = TOSHIBA_RBTX4927_IOC_NAME,
+	.name = TOSHIBA_RBTX4927_IOC_NAME,
 	.ack = toshiba_rbtx4927_irq_ioc_disable,
 	.mask = toshiba_rbtx4927_irq_ioc_disable,
 	.mask_ack = toshiba_rbtx4927_irq_ioc_disable,
@@ -241,7 +241,7 @@
 #ifdef CONFIG_TOSHIBA_FPCIB0
 #define TOSHIBA_RBTX4927_ISA_NAME "RBTX4927-ISA"
 static struct irq_chip toshiba_rbtx4927_irq_isa_type = {
-	.typename = TOSHIBA_RBTX4927_ISA_NAME,
+	.name = TOSHIBA_RBTX4927_ISA_NAME,
 	.ack = toshiba_rbtx4927_irq_isa_mask_and_ack,
 	.mask = toshiba_rbtx4927_irq_isa_disable,
 	.mask_ack = toshiba_rbtx4927_irq_isa_mask_and_ack,
@@ -490,13 +490,13 @@
 	{
 		u32 i, j = 0;
 		for (i = 0; i < NR_IRQS; i++) {
-			if (strcmp(irq_desc[i].chip->typename, "none")
+			if (strcmp(irq_desc[i].chip->name, "none")
 			    == 0)
 				continue;
 
 			if ((i >= 1)
-			    && (irq_desc[i - 1].chip->typename ==
-				irq_desc[i].chip->typename)) {
+			    && (irq_desc[i - 1].chip->name ==
+				irq_desc[i].chip->name)) {
 				j++;
 			} else {
 				j = 0;
@@ -510,7 +510,7 @@
 			     (u32) (irq_desc[i].action ? irq_desc[i].
 				    action->handler : 0),
 			     irq_desc[i].depth,
-			     irq_desc[i].chip->typename, j);
+			     irq_desc[i].chip->name, j);
 		}
 	}
 #endif
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c
index efe5056..9a3a5ba 100644
--- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c
+++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c
@@ -80,9 +80,8 @@
 	add_memory_region(0, msize << 20, BOOT_MEM_RAM);
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	return 0;
 }
 
 const char *get_system_type(void)
diff --git a/arch/mips/tx4938/common/irq.c b/arch/mips/tx4938/common/irq.c
index a347b42..3a2dbfc 100644
--- a/arch/mips/tx4938/common/irq.c
+++ b/arch/mips/tx4938/common/irq.c
@@ -49,7 +49,7 @@
 
 #define TX4938_CP0_NAME "TX4938-CP0"
 static struct irq_chip tx4938_irq_cp0_type = {
-	.typename = TX4938_CP0_NAME,
+	.name = TX4938_CP0_NAME,
 	.ack = tx4938_irq_cp0_disable,
 	.mask = tx4938_irq_cp0_disable,
 	.mask_ack = tx4938_irq_cp0_disable,
@@ -58,7 +58,7 @@
 
 #define TX4938_PIC_NAME "TX4938-PIC"
 static struct irq_chip tx4938_irq_pic_type = {
-	.typename = TX4938_PIC_NAME,
+	.name = TX4938_PIC_NAME,
 	.ack = tx4938_irq_pic_disable,
 	.mask = tx4938_irq_pic_disable,
 	.mask_ack = tx4938_irq_pic_disable,
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/irq.c b/arch/mips/tx4938/toshiba_rbtx4938/irq.c
index b6f363d..2e96dbb 100644
--- a/arch/mips/tx4938/toshiba_rbtx4938/irq.c
+++ b/arch/mips/tx4938/toshiba_rbtx4938/irq.c
@@ -92,7 +92,7 @@
 
 #define TOSHIBA_RBTX4938_IOC_NAME "RBTX4938-IOC"
 static struct irq_chip toshiba_rbtx4938_irq_ioc_type = {
-	.typename = TOSHIBA_RBTX4938_IOC_NAME,
+	.name = TOSHIBA_RBTX4938_IOC_NAME,
 	.ack = toshiba_rbtx4938_irq_ioc_disable,
 	.mask = toshiba_rbtx4938_irq_ioc_disable,
 	.mask_ack = toshiba_rbtx4938_irq_ioc_disable,
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/prom.c b/arch/mips/tx4938/toshiba_rbtx4938/prom.c
index e44daf3..7dc6a0a 100644
--- a/arch/mips/tx4938/toshiba_rbtx4938/prom.c
+++ b/arch/mips/tx4938/toshiba_rbtx4938/prom.c
@@ -56,9 +56,8 @@
 	return;
 }
 
-unsigned long  __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-	return 0;
 }
 
 void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
diff --git a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c
index c075261..adabc6b 100644
--- a/arch/mips/vr41xx/common/icu.c
+++ b/arch/mips/vr41xx/common/icu.c
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2001-2002  MontaVista Software Inc.
  *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copyright (C) 2003-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2003-2006  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
  *
  *  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
@@ -68,6 +68,7 @@
 #define MPIUINTREG	0x0e
 #define MAIUINTREG	0x10
 #define MKIUINTREG	0x12
+#define MMACINTREG	0x12
 #define MGIUINTLREG	0x14
 #define MDSIUINTREG	0x16
 #define NMIREG		0x18
@@ -241,6 +242,30 @@
 
 EXPORT_SYMBOL(vr41xx_disable_kiuint);
 
+void vr41xx_enable_macint(uint16_t mask)
+{
+	struct irq_desc *desc = irq_desc + ETHERNET_IRQ;
+	unsigned long flags;
+
+	spin_lock_irqsave(&desc->lock, flags);
+	icu1_set(MMACINTREG, mask);
+	spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+EXPORT_SYMBOL(vr41xx_enable_macint);
+
+void vr41xx_disable_macint(uint16_t mask)
+{
+	struct irq_desc *desc = irq_desc + ETHERNET_IRQ;
+	unsigned long flags;
+
+	spin_lock_irqsave(&desc->lock, flags);
+	icu1_clear(MMACINTREG, mask);
+	spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+EXPORT_SYMBOL(vr41xx_disable_macint);
+
 void vr41xx_enable_dsiuint(uint16_t mask)
 {
 	struct irq_desc *desc = irq_desc + DSIU_IRQ;
@@ -428,7 +453,7 @@
 }
 
 static struct irq_chip sysint1_irq_type = {
-	.typename	= "SYSINT1",
+	.name		= "SYSINT1",
 	.ack		= disable_sysint1_irq,
 	.mask		= disable_sysint1_irq,
 	.mask_ack	= disable_sysint1_irq,
@@ -446,7 +471,7 @@
 }
 
 static struct irq_chip sysint2_irq_type = {
-	.typename	= "SYSINT2",
+	.name		= "SYSINT2",
 	.ack		= disable_sysint2_irq,
 	.mask		= disable_sysint2_irq,
 	.mask_ack	= disable_sysint2_irq,
diff --git a/arch/mips/vr41xx/common/init.c b/arch/mips/vr41xx/common/init.c
index a2e285c..4f97e0b 100644
--- a/arch/mips/vr41xx/common/init.c
+++ b/arch/mips/vr41xx/common/init.c
@@ -81,7 +81,6 @@
 	}
 }
 
-unsigned long __init prom_free_prom_memory (void)
+void __init prom_free_prom_memory(void)
 {
-	return 0UL;
 }
diff --git a/arch/mips/vr41xx/common/irq.c b/arch/mips/vr41xx/common/irq.c
index 16decf4..cba36a2 100644
--- a/arch/mips/vr41xx/common/irq.c
+++ b/arch/mips/vr41xx/common/irq.c
@@ -95,27 +95,27 @@
 	unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
 
 	if (pending & CAUSEF_IP7)
-		do_IRQ(7);
+		do_IRQ(TIMER_IRQ);
 	else if (pending & 0x7800) {
 		if (pending & CAUSEF_IP3)
-			irq_dispatch(3);
+			irq_dispatch(INT1_IRQ);
 		else if (pending & CAUSEF_IP4)
-			irq_dispatch(4);
+			irq_dispatch(INT2_IRQ);
 		else if (pending & CAUSEF_IP5)
-			irq_dispatch(5);
+			irq_dispatch(INT3_IRQ);
 		else if (pending & CAUSEF_IP6)
-			irq_dispatch(6);
+			irq_dispatch(INT4_IRQ);
 	} else if (pending & CAUSEF_IP2)
-		irq_dispatch(2);
+		irq_dispatch(INT0_IRQ);
 	else if (pending & CAUSEF_IP0)
-		do_IRQ(0);
+		do_IRQ(MIPS_SOFTINT0_IRQ);
 	else if (pending & CAUSEF_IP1)
-		do_IRQ(1);
+		do_IRQ(MIPS_SOFTINT1_IRQ);
 	else
 		spurious_interrupt();
 }
 
 void __init arch_init_irq(void)
 {
-	mips_cpu_irq_init(MIPS_CPU_IRQ_BASE);
+	mips_cpu_irq_init();
 }
diff --git a/arch/mips/vr41xx/nec-cmbvr4133/irq.c b/arch/mips/vr41xx/nec-cmbvr4133/irq.c
index 128ed8d..7d2d076 100644
--- a/arch/mips/vr41xx/nec-cmbvr4133/irq.c
+++ b/arch/mips/vr41xx/nec-cmbvr4133/irq.c
@@ -21,60 +21,16 @@
 #include <linux/interrupt.h>
 
 #include <asm/io.h>
+#include <asm/i8259.h>
 #include <asm/vr41xx/cmbvr4133.h>
 
-extern void enable_8259A_irq(unsigned int irq);
-extern void disable_8259A_irq(unsigned int irq);
-extern void mask_and_ack_8259A(unsigned int irq);
-extern void init_8259A(int hoge);
-
 extern int vr4133_rockhopper;
 
-static void enable_i8259_irq(unsigned int irq)
-{
-	enable_8259A_irq(irq - I8259_IRQ_BASE);
-}
-
-static void disable_i8259_irq(unsigned int irq)
-{
-	disable_8259A_irq(irq - I8259_IRQ_BASE);
-}
-
-static void ack_i8259_irq(unsigned int irq)
-{
-	mask_and_ack_8259A(irq - I8259_IRQ_BASE);
-}
-
-static struct irq_chip i8259_irq_type = {
-	.typename       = "XT-PIC",
-	.ack            = ack_i8259_irq,
-	.mask		= disable_i8259_irq,
-	.mask_ack	= ack_i8259_irq,
-	.unmask		= enable_i8259_irq,
-};
-
 static int i8259_get_irq_number(int irq)
 {
-	unsigned long isr;
-
-	isr = inb(0x20);
-	irq = ffz(~isr);
-	if (irq == 2) {
-		isr = inb(0xa0);
-		irq = 8 + ffz(~isr);
-	}
-
-	if (irq < 0 || irq > 15)
-		return -EINVAL;
-
-	return I8259_IRQ_BASE + irq;
+	return i8259_irq();
 }
 
-static struct irqaction i8259_slave_cascade = {
-	.handler        = &no_action,
-	.name           = "cascade",
-};
-
 void __init rockhopper_init_irq(void)
 {
 	int i;
@@ -84,11 +40,6 @@
 		return;
 	}
 
-	for (i = I8259_IRQ_BASE; i <= I8259_IRQ_LAST; i++)
-		set_irq_chip_and_handler(i, &i8259_irq_type, handle_level_irq);
-
-	setup_irq(I8259_SLAVE_IRQ, &i8259_slave_cascade);
-
 	vr41xx_set_irq_trigger(CMBVR41XX_INTC_PIN, TRIGGER_LEVEL, SIGNAL_THROUGH);
 	vr41xx_set_irq_level(CMBVR41XX_INTC_PIN, LEVEL_HIGH);
 	vr41xx_cascade_irq(CMBVR41XX_INTC_IRQ, i8259_get_irq_number);
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index d6abe49..f08e80a 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -173,6 +173,11 @@
 	help
 	  The Freescale E600 SoCs have 74xx cores.
 
+config PPC_8xx
+	bool "Freescale 8xx"
+	select FSL_SOC
+	select 8xx
+
 config 40x
 	bool "AMCC 40x"
 	select PPC_DCR_NATIVE
@@ -181,8 +186,6 @@
 	bool "AMCC 44x"
 	select PPC_DCR_NATIVE
 
-config 8xx
-	bool "Freescale 8xx"
 
 config E200
 	bool "Freescale e200"
@@ -211,6 +214,10 @@
 	bool
 
 # this is temp to handle compat with arch=ppc
+config 8xx
+	bool
+
+# this is temp to handle compat with arch=ppc
 config 83xx
 	bool
 
@@ -429,6 +436,21 @@
 	bool
 	default n
 
+config PPC_MPC5200
+	bool
+	select PPC_MPC52xx
+	default n
+
+config PPC_MPC5200_BUGFIX
+	bool "MPC5200 (L25R) bugfix support"
+	depends on PPC_MPC5200
+	default n
+	help
+	  Enable workarounds for original MPC5200 errata.  This is not required
+	  for MPC5200B based boards.
+
+	  It is safe to say 'Y' here
+
 config PPC_EFIKA
 	bool "bPlan Efika 5k2. MPC5200B based computer"
 	depends on PPC_MULTIPLATFORM && PPC32
@@ -441,7 +463,7 @@
 config PPC_LITE5200
 	bool "Freescale Lite5200 Eval Board"
 	depends on PPC_MULTIPLATFORM && PPC32
-	select PPC_MPC52xx
+	select PPC_MPC5200
 	default n
 
 config PPC_PMAC
@@ -484,6 +506,7 @@
 	select PPC_970_NAP
 	select PPC_NATIVE
 	select PPC_RTAS
+	select MMIO_NVRAM
 	select ATA_NONSTANDARD if ATA
 	default n
 	help
@@ -529,6 +552,11 @@
 	bool "Sony PS3 (incomplete)"
 	depends on PPC_MULTIPLATFORM && PPC64
 	select PPC_CELL
+	select USB_ARCH_HAS_OHCI
+	select USB_OHCI_LITTLE_ENDIAN
+	select USB_OHCI_BIG_ENDIAN_MMIO
+	select USB_ARCH_HAS_EHCI
+	select USB_EHCI_BIG_ENDIAN_MMIO
 	help
 	  This option enables support for the Sony PS3 game console
 	  and other platforms using the PS3 hypervisor.
@@ -536,6 +564,16 @@
 	  enabling this will not result in a bootable kernel on a
 	  PS3 system.
 
+config PPC_CELLEB
+	bool "Toshiba's Cell Reference Set 'Celleb' Architecture"
+	depends on PPC_MULTIPLATFORM && PPC64
+	select PPC_CELL
+	select PPC_OF_PLATFORM_PCI
+	select HAS_TXX9_SERIAL
+	select PPC_UDBG_BEAT
+	select USB_OHCI_BIG_ENDIAN_MMIO
+	select USB_EHCI_BIG_ENDIAN_MMIO
+
 config PPC_NATIVE
 	bool
 	depends on PPC_MULTIPLATFORM
@@ -549,6 +587,11 @@
 	depends on PPC_RTAS
 	default n
 
+config PPC_UDBG_BEAT
+	bool "BEAT based debug console"
+	depends on PPC_CELLEB
+	default n
+
 config XICS
 	depends on PPC_PSERIES
 	bool
@@ -702,6 +745,7 @@
 source arch/powerpc/platforms/8xx/Kconfig
 source arch/powerpc/platforms/cell/Kconfig
 source arch/powerpc/platforms/ps3/Kconfig
+source arch/powerpc/platforms/pasemi/Kconfig
 
 menu "Kernel options"
 
@@ -724,7 +768,7 @@
 
 config MATH_EMULATION
 	bool "Math emulation"
-	depends on 4xx || 8xx || E200 || PPC_83xx || E500
+	depends on 4xx || 8xx || E200 || PPC_MPC832x || E500
 	---help---
 	  Some PowerPC chips designed for embedded applications do not have
 	  a floating-point unit and therefore do not implement the
@@ -1182,7 +1226,7 @@
 
 config KPROBES
 	bool "Kprobes (EXPERIMENTAL)"
-	depends on PPC64 && KALLSYMS && EXPERIMENTAL && MODULES
+	depends on !BOOKE && !4xx && KALLSYMS && EXPERIMENTAL && MODULES
 	help
 	  Kprobes allows you to trap at almost any kernel address and
 	  execute a callback function.  register_kprobe() establishes
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index f0e51ed..d39d133 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -4,14 +4,14 @@
 
 config DEBUG_STACKOVERFLOW
 	bool "Check for stack overflows"
-	depends on DEBUG_KERNEL && PPC64
+	depends on DEBUG_KERNEL
 	help
 	  This option will cause messages to be printed if free stack space
 	  drops below a certain limit.
 
 config DEBUG_STACK_USAGE
 	bool "Stack utilization instrumentation"
-	depends on DEBUG_KERNEL && PPC64
+	depends on DEBUG_KERNEL
 	help
 	  Enables the display of the minimum amount of free stack which each
 	  task has ever had available in the sysrq-T and sysrq-P debug output.
@@ -185,6 +185,20 @@
 	  Select this to enable early debugging for legacy iSeries. You need
 	  to hit "Ctrl-x Ctrl-x" to see the messages on the console.
 
+config PPC_EARLY_DEBUG_PAS_REALMODE
+	bool "PA Semi real mode"
+	depends on PPC_PASEMI
+	help
+	  Select this to enable early debugging for PA Semi.
+	  Output will be on UART0.
+
+config PPC_EARLY_DEBUG_BEAT
+	bool "Beat HV Console"
+	depends on PPC_CELLEB
+	select PPC_UDBG_BEAT
+	help
+	  Select this to enable early debugging for Celleb with Beat.
+
 endchoice
 
 endmenu
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 98392fb..dc77940 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -162,6 +162,7 @@
 image-$(CONFIG_PPC_MAPLE)		+= zImage.pseries
 image-$(CONFIG_PPC_IBM_CELL_BLADE)	+= zImage.pseries
 image-$(CONFIG_PPC_PS3)			+= zImage.ps3
+image-$(CONFIG_PPC_CELLEB)		+= zImage.pseries
 image-$(CONFIG_PPC_CHRP)		+= zImage.chrp
 image-$(CONFIG_PPC_EFIKA)		+= zImage.chrp
 image-$(CONFIG_PPC_PMAC)		+= zImage.pmac
diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts
index 34efdd0..26b44f7 100644
--- a/arch/powerpc/boot/dts/mpc8272ads.dts
+++ b/arch/powerpc/boot/dts/mpc8272ads.dts
@@ -53,13 +53,20 @@
                reg = <00000000 4000000 f4500000 00000020>;
        };
 
+       chosen {
+               name = "chosen";
+               linux,platform = <0>;
+               interrupt-controller = <10c00>;
+               linux,phandle = <400>;
+       };
+
        soc8272@f0000000 {
                #address-cells = <1>;
                #size-cells = <1>;
                #interrupt-cells = <2>;
                device_type = "soc";
-               ranges = < 0 0 2 00000000 f0000000 00053000>;
-               reg = <f0000000 0>;
+               ranges = <00000000 f0000000 00053000>;
+               reg = <f0000000 10000>;
 
                mdio@0 {
                        device_type = "mdio";
@@ -71,7 +78,7 @@
                        ethernet-phy@0 {
                                linux,phandle = <2452000>;
                                interrupt-parent = <10c00>;
-                               interrupts = <19 1>;
+                               interrupts = <17 4>;
                                reg = <0>;
                                bitbang = [ 12 12 13 02 02 01 ];
                                device_type = "ethernet-phy";
@@ -79,7 +86,7 @@
                        ethernet-phy@1 {
                                linux,phandle = <2452001>;
                                interrupt-parent = <10c00>;
-                               interrupts = <19 1>;
+                               interrupts = <17 4>;
                                bitbang = [ 12 12 13 02 02 01 ];
                                reg = <3>;
                                device_type = "ethernet-phy";
@@ -90,7 +97,7 @@
                        #address-cells = <1>;
                        #size-cells = <0>;
                        device_type = "network";
-                       device-id = <2>;
+                       device-id = <1>;
                        compatible = "fs_enet";
                        model = "FCC";
                        reg = <11300 20 8400 100 11380 30>;
@@ -104,7 +111,7 @@
 
                ethernet@25000 {
                        device_type = "network";
-                       device-id = <3>;
+                       device-id = <2>;
                        compatible = "fs_enet";
                        model = "FCC";
                        reg = <11320 20 8500 100 113b0 30>;
@@ -123,8 +130,8 @@
                        #interrupt-cells = <2>;
                        device_type = "cpm";
                        model = "CPM2";
-                       ranges = <00000000 00000000 3ffff>;
-                       reg = <10d80 3280>;
+                       ranges = <00000000 00000000 20000>;
+                       reg = <0 20000>;
                        command-proc = <119c0>;
                        brg-frequency = <17D7840>;
                        cpm_clk = <BEBC200>;
@@ -133,7 +140,7 @@
                                device_type = "serial";
                                compatible = "cpm_uart";
                                model = "SCC";
-                               device-id = <2>;
+                               device-id = <1>;
                                reg = <11a00 20 8000 100>;
                                current-speed = <1c200>;
                                interrupts = <28 2>;
@@ -147,7 +154,7 @@
                                device_type = "serial";
                                compatible = "cpm_uart";
                                model = "SCC";
-                               device-id = <5>;
+                               device-id = <4>;
                                reg = <11a60 20 8300 100>;
                                current-speed = <1c200>;
                                interrupts = <2b 2>;
@@ -181,24 +188,24 @@
                        interrupt-map = <
 
                                        /* IDSEL 0x16 */
-                                        b000 0 0 1 f8200000 40 0
-                                        b000 0 0 2 f8200000 41 0
-                                        b000 0 0 3 f8200000 42 0
-                                        b000 0 0 4 f8200000 43 0
+                                        b000 0 0 1 f8200000 40 8
+                                        b000 0 0 2 f8200000 41 8
+                                        b000 0 0 3 f8200000 42 8
+                                        b000 0 0 4 f8200000 43 8
 
                                        /* IDSEL 0x17 */
-                                        b800 0 0 1 f8200000 43 0
-                                        b800 0 0 2 f8200000 40 0
-                                        b800 0 0 3 f8200000 41 0
-                                        b800 0 0 4 f8200000 42 0
+                                        b800 0 0 1 f8200000 43 8
+                                        b800 0 0 2 f8200000 40 8
+                                        b800 0 0 3 f8200000 41 8
+                                        b800 0 0 4 f8200000 42 8
 
                                        /* IDSEL 0x18 */
-                                        c000 0 0 1 f8200000 42 0
-                                        c000 0 0 2 f8200000 43 0
-                                        c000 0 0 3 f8200000 40 0
-                                        c000 0 0 4 f8200000 41 0>;
+                                        c000 0 0 1 f8200000 42 8
+                                        c000 0 0 2 f8200000 43 8
+                                        c000 0 0 3 f8200000 40 8
+                                        c000 0 0 4 f8200000 41 8>;
                        interrupt-parent = <10c00>;
-                       interrupts = <14 3>;
+                       interrupts = <14 8>;
                        bus-range = <0 0>;
                        ranges = <02000000 0 80000000 80000000 0 40000000
                                  01000000 0 00000000 f6000000 0 02000000>;
@@ -210,7 +217,7 @@
                        model = "SEC2";
                        compatible = "talitos";
                        reg = <30000 10000>;
-                       interrupts = <b 0>;
+                       interrupts = <b 2>;
                        interrupt-parent = <10c00>;
                        num-channels = <4>;
                        channel-fifo-len = <18>;
diff --git a/arch/powerpc/boot/dts/mpc8323emds.dts b/arch/powerpc/boot/dts/mpc8323emds.dts
new file mode 100644
index 0000000..fa7ef24
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8323emds.dts
@@ -0,0 +1,345 @@
+/*
+ * MPC8323E EMDS Device Tree Source
+ *
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+/ {
+	model = "MPC8323EMDS";
+	compatible = "MPC83xx";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	linux,phandle = <100>;
+
+	cpus {
+		#cpus = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		linux,phandle = <200>;
+
+		PowerPC,8323@0 {
+			device_type = "cpu";
+			reg = <0>;
+			d-cache-line-size = <20>;	// 32 bytes
+			i-cache-line-size = <20>;	// 32 bytes
+			d-cache-size = <4000>;		// L1, 16K
+			i-cache-size = <4000>;		// L1, 16K
+			timebase-frequency = <0>;
+			bus-frequency = <0>;
+			clock-frequency = <0>;
+			32-bit;
+			linux,phandle = <201>;
+			linux,boot-cpu;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		linux,phandle = <300>;
+		reg = <00000000 08000000>;
+	};
+
+	bcsr@f8000000 {
+		device_type = "board-control";
+		reg = <f8000000 8000>;
+	};
+
+	soc8323@e0000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <2>;
+		device_type = "soc";
+		ranges = <0 e0000000 00100000>;
+		reg = <e0000000 00000200>;
+		bus-frequency = <7DE2900>;
+
+		wdt@200 {
+			device_type = "watchdog";
+			compatible = "mpc83xx_wdt";
+			reg = <200 100>;
+		};
+
+		i2c@3000 {
+			device_type = "i2c";
+			compatible = "fsl-i2c";
+			reg = <3000 100>;
+			interrupts = <e 8>;
+			interrupt-parent = <700>;
+			dfsrr;
+		};
+
+		serial@4500 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <4500 100>;
+			clock-frequency = <0>;
+			interrupts = <9 8>;
+			interrupt-parent = <700>;
+		};
+
+		serial@4600 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <4600 100>;
+			clock-frequency = <0>;
+			interrupts = <a 8>;
+			interrupt-parent = <700>;
+		};
+
+		crypto@30000 {
+			device_type = "crypto";
+			model = "SEC2";
+			compatible = "talitos";
+			reg = <30000 7000>;
+			interrupts = <b 8>;
+			interrupt-parent = <700>;
+			/* Rev. 2.2 */
+			num-channels = <1>;
+			channel-fifo-len = <18>;
+			exec-units-mask = <0000004c>;
+			descriptor-types-mask = <0122003f>;
+		};
+
+		pci@8500 {
+			linux,phandle = <8500>;
+			interrupt-map-mask = <f800 0 0 7>;
+			interrupt-map = <
+					/* IDSEL 0x11 AD17 */
+					 8800 0 0 1 700 14 8
+					 8800 0 0 2 700 15 8
+					 8800 0 0 3 700 16 8
+					 8800 0 0 4 700 17 8
+
+					/* IDSEL 0x12 AD18 */
+					 9000 0 0 1 700 16 8
+					 9000 0 0 2 700 17 8
+					 9000 0 0 3 700 14 8
+					 9000 0 0 4 700 15 8
+
+					/* IDSEL 0x13 AD19 */
+					 9800 0 0 1 700 17 8
+					 9800 0 0 2 700 14 8
+					 9800 0 0 3 700 15 8
+					 9800 0 0 4 700 16 8
+
+					/* IDSEL 0x15 AD21*/
+					 a800 0 0 1 700 14 8
+					 a800 0 0 2 700 15 8
+					 a800 0 0 3 700 16 8
+					 a800 0 0 4 700 17 8
+
+					/* IDSEL 0x16 AD22*/
+					 b000 0 0 1 700 17 8
+					 b000 0 0 2 700 14 8
+					 b000 0 0 3 700 15 8
+					 b000 0 0 4 700 16 8
+
+					/* IDSEL 0x17 AD23*/
+					 b800 0 0 1 700 16 8
+					 b800 0 0 2 700 17 8
+					 b800 0 0 3 700 14 8
+					 b800 0 0 4 700 15 8
+
+					/* IDSEL 0x18 AD24*/
+					 c000 0 0 1 700 15 8
+					 c000 0 0 2 700 16 8
+					 c000 0 0 3 700 17 8
+					 c000 0 0 4 700 14 8>;
+			interrupt-parent = <700>;
+			interrupts = <42 8>;
+			bus-range = <0 0>;
+			ranges = <02000000 0 a0000000 90000000 0 10000000
+			          42000000 0 80000000 80000000 0 10000000
+			          01000000 0 00000000 d0000000 0 00100000>;
+			clock-frequency = <0>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg = <8500 100>;
+			compatible = "83xx";
+			device_type = "pci";
+		};
+
+		pic@700 {
+			linux,phandle = <700>;
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <700 100>;
+			built-in;
+			device_type = "ipic";
+		};
+		
+		par_io@1400 {
+			reg = <1400 100>;
+			device_type = "par_io";
+			num-ports = <7>;
+
+			ucc_pin@03 {
+				linux,phandle = <140003>;
+				pio-map = <
+			/* port  pin  dir  open_drain  assignment  has_irq */
+					3  4  3  0  2  0  /* MDIO */
+					3  5  1  0  2  0  /* MDC */
+					0  d  2  0  1  0 	/* RX_CLK (CLK9) */
+					3 18  2  0  1  0 	/* TX_CLK (CLK10) */
+					1  1  1  0  1  0 	/* TxD1 */
+					1  0  1  0  1  0 	/* TxD0 */
+					1  1  1  0  1  0 	/* TxD1 */
+					1  2  1  0  1  0 	/* TxD2 */
+					1  3  1  0  1  0 	/* TxD3 */
+					1  4  2  0  1  0 	/* RxD0 */
+					1  5  2  0  1  0 	/* RxD1 */
+					1  6  2  0  1  0 	/* RxD2 */
+					1  7  2  0  1  0 	/* RxD3 */
+					1  8  2  0  1  0 	/* RX_ER */
+					1  9  1  0  1  0 	/* TX_ER */
+					1  a  2  0  1  0 	/* RX_DV */
+					1  b  2  0  1  0 	/* COL */
+					1  c  1  0  1  0 	/* TX_EN */
+					1  d  2  0  1  0>;/* CRS */
+			};
+			ucc_pin@04 {
+				linux,phandle = <140004>;
+				pio-map = <
+			/* port  pin  dir  open_drain  assignment  has_irq */
+					3 1f  2  0  1  0 	/* RX_CLK (CLK7) */
+					3  6  2  0  1  0 	/* TX_CLK (CLK8) */
+					1 12  1  0  1  0 	/* TxD0 */
+					1 13  1  0  1  0 	/* TxD1 */
+					1 14  1  0  1  0 	/* TxD2 */
+					1 15  1  0  1  0 	/* TxD3 */
+					1 16  2  0  1  0 	/* RxD0 */
+					1 17  2  0  1  0 	/* RxD1 */
+					1 18  2  0  1  0 	/* RxD2 */
+					1 19  2  0  1  0 	/* RxD3 */
+					1 1a  2  0  1  0 	/* RX_ER */
+					1 1b  1  0  1  0 	/* TX_ER */
+					1 1c  2  0  1  0 	/* RX_DV */
+					1 1d  2  0  1  0 	/* COL */
+					1 1e  1  0  1  0 	/* TX_EN */
+					1 1f  2  0  1  0>;/* CRS */
+			};
+		};
+	};
+
+	qe@e0100000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		device_type = "qe";
+		model = "QE";
+		ranges = <0 e0100000 00100000>;
+		reg = <e0100000 480>;
+		brg-frequency = <0>;
+		bus-frequency = <BCD3D80>;
+		
+		muram@10000 {
+			device_type = "muram";
+			ranges = <0 00010000 00004000>;
+	
+			data-only@0 {
+				reg = <0 4000>;
+			};
+		};
+
+		spi@4c0 {
+			device_type = "spi";
+			compatible = "fsl_spi";
+			reg = <4c0 40>;
+			interrupts = <2>;
+			interrupt-parent = <80>;
+			mode = "cpu";
+		};
+
+		spi@500 {
+			device_type = "spi";
+			compatible = "fsl_spi";
+			reg = <500 40>;
+			interrupts = <1>;
+			interrupt-parent = <80>;
+			mode = "cpu";
+		};
+
+		usb@6c0 {
+			device_type = "usb";
+			compatible = "qe_udc";
+			reg = <6c0 40 8B00 100>;
+			interrupts = <b>;
+			interrupt-parent = <80>;
+			mode = "slave";
+		};
+
+		ucc@2200 {
+			device_type = "network";
+			compatible = "ucc_geth";
+			model = "UCC";
+			device-id = <3>;
+			reg = <2200 200>;
+			interrupts = <22>;
+			interrupt-parent = <80>;
+			mac-address = [ 00 04 9f 00 23 23 ];
+			rx-clock = <19>;
+			tx-clock = <1a>;
+			phy-handle = <212003>;
+			pio-handle = <140003>;
+		};
+
+		ucc@3200 {
+			device_type = "network";
+			compatible = "ucc_geth";
+			model = "UCC";
+			device-id = <4>;
+			reg = <3000 200>;
+			interrupts = <23>;
+			interrupt-parent = <80>;
+			mac-address = [ 00 11 22 33 44 55 ];
+			rx-clock = <17>;
+			tx-clock = <18>;
+			phy-handle = <212004>;
+			pio-handle = <140004>;
+		};
+
+		mdio@2320 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2320 18>;
+			device_type = "mdio";
+			compatible = "ucc_geth_phy";
+
+			ethernet-phy@03 {
+				linux,phandle = <212003>;
+				interrupt-parent = <700>;
+				interrupts = <11 2>;
+				reg = <3>;
+				device_type = "ethernet-phy";
+				interface = <3>; //ENET_100_MII
+			};
+			ethernet-phy@04 {
+				linux,phandle = <212004>;
+				interrupt-parent = <700>;
+				interrupts = <12 2>;
+				reg = <4>;
+				device_type = "ethernet-phy";
+				interface = <3>;
+			};
+		};
+
+		qeic@80 {
+			linux,phandle = <80>;
+			interrupt-controller;
+			device_type = "qeic";
+			#address-cells = <0>;
+			#interrupt-cells = <1>;
+			reg = <80 80>;
+			built-in;
+			big-endian;
+			interrupts = <20 8 21 8>; //high:32 low:33
+			interrupt-parent = <700>;
+		};
+	};
+};
diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts
index 2b16848..119bd5d 100644
--- a/arch/powerpc/boot/dts/mpc8560ads.dts
+++ b/arch/powerpc/boot/dts/mpc8560ads.dts
@@ -200,7 +200,7 @@
 					 a800 0 0 4 40000 31 1>;
 
 			interrupt-parent = <40000>;
-			interrupts = <42 0>;
+			interrupts = <8 0>;
 			bus-range = <0 0>;
 			ranges = <02000000 0 80000000 80000000 0 20000000
 				  01000000 0 00000000 e2000000 0 01000000>;
@@ -250,7 +250,7 @@
 				rx-clock = <1>;
 				tx-clock = <1>;
 				current-speed = <1c200>;
-				interrupts = <64 1>;
+				interrupts = <28 8>;
 				interrupt-parent = <90c00>;
 			};
 
@@ -264,7 +264,7 @@
 				rx-clock = <2>;
 				tx-clock = <2>;
 				current-speed = <1c200>;
-				interrupts = <65 1>;
+				interrupts = <29 8>;
 				interrupt-parent = <90c00>;
 			};
 
@@ -278,7 +278,7 @@
 				clock-setup = <ff00ffff 250000>;
 				rx-clock = <15>;
 				tx-clock = <16>;
-				interrupts = <5d 1>;
+				interrupts = <21 8>;
 				interrupt-parent = <90c00>;
 				phy-handle = <2452002>;
 			};
@@ -293,7 +293,7 @@
 				clock-setup = <ffff00ff 3700>;
 				rx-clock = <17>;
 				tx-clock = <18>;
-				interrupts = <5e 1>;
+				interrupts = <22 8>;
 				interrupt-parent = <90c00>;
 				phy-handle = <2452003>;
 			};
diff --git a/arch/powerpc/boot/dts/mpc866ads.dts b/arch/powerpc/boot/dts/mpc866ads.dts
new file mode 100644
index 0000000..5d40052
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc866ads.dts
@@ -0,0 +1,162 @@
+/*
+ * MPC866 ADS Device Tree Source
+ *
+ * Copyright 2006 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+
+/ {
+	model = "MPC866ADS";
+	compatible = "mpc8xx";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	linux,phandle = <100>;
+
+	cpus {
+		#cpus = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		linux,phandle = <200>;
+
+		PowerPC,866@0 {
+			device_type = "cpu";
+			reg = <0>;
+			d-cache-line-size = <20>;	// 32 bytes
+			i-cache-line-size = <20>;	// 32 bytes
+			d-cache-size = <2000>;		// L1, 8K
+			i-cache-size = <4000>;		// L1, 16K
+			timebase-frequency = <0>;
+			bus-frequency = <0>;
+			clock-frequency = <0>;
+			32-bit;
+			interrupts = <f 2>;	// decrementer interrupt
+			interrupt-parent = <ff000000>;
+			linux,phandle = <201>;
+			linux,boot-cpu;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		linux,phandle = <300>;
+		reg = <00000000 800000>;
+	};
+
+	soc866@ff000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <2>;
+		device_type = "soc";
+		ranges = <0 ff000000 00100000>;
+		reg = <ff000000 00000200>;
+		bus-frequency = <0>;
+		mdio@e80 {
+			device_type = "mdio";
+			compatible = "fs_enet";
+			reg = <e80 8>;
+			linux,phandle = <e80>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			ethernet-phy@f {
+				linux,phandle = <e800f>;
+				reg = <f>;
+				device_type = "ethernet-phy";
+			};
+		};
+
+		fec@e00 {
+			device_type = "network";
+			compatible = "fs_enet";
+			model = "FEC";
+			device-id = <1>;
+			reg = <e00 188>;
+			mac-address = [ 00 00 0C 00 01 FD ];
+			interrupts = <3 1>;
+			interrupt-parent = <ff000000>;
+			phy-handle = <e800f>;
+		};
+
+		pic@ff000000 {
+			linux,phandle = <ff000000>;
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <0 24>;
+			built-in;
+			device_type = "mpc8xx-pic";
+			compatible = "CPM";
+		};
+
+		cpm@ff000000 {
+			linux,phandle = <ff000000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#interrupt-cells = <2>;
+			device_type = "cpm";
+			model = "CPM";
+			ranges = <0 0 4000>;
+			reg = <860 f0>;
+			command-proc = <9c0>;
+			brg-frequency = <0>;
+			interrupts = <0 2>;	// cpm error interrupt
+			interrupt-parent = <930>;
+
+			pic@930 {
+				linux,phandle = <930>;
+				interrupt-controller;
+				#address-cells = <0>;
+				#interrupt-cells = <2>;
+				interrupts = <5 2 0 2>;
+				interrupt-parent = <ff000000>;
+				reg = <930 20>;
+				built-in;
+				device_type = "cpm-pic";
+				compatible = "CPM";
+			};
+
+			smc@a80 {
+				device_type = "serial";
+				compatible = "cpm_uart";
+				model = "SMC";
+				device-id = <1>;
+				reg = <a80 10 3e80 40>;
+				clock-setup = <00ffffff 0>;
+				rx-clock = <1>;
+				tx-clock = <1>;
+				current-speed = <0>;
+				interrupts = <4 3>;
+				interrupt-parent = <930>;
+			};
+
+			smc@a90 {
+				device_type = "serial";
+				compatible = "cpm_uart";
+				model = "SMC";
+				device-id = <2>;
+				reg = <a90 20 3f80 40>;
+				clock-setup = <ff00ffff 90000>;
+				rx-clock = <2>;
+				tx-clock = <2>;
+				current-speed = <0>;
+				interrupts = <3 3>;
+				interrupt-parent = <930>;
+			};
+
+			scc@a00 {
+				device_type = "network";
+				compatible = "fs_enet";
+				model = "SCC";
+				device-id = <1>;
+				reg = <a00 18 3c00 80>;
+				mac-address = [ 00 00 0C 00 03 FD ];
+				interrupts = <1e 3>;
+				interrupt-parent = <930>;
+			};
+		};
+	};
+};
diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts
new file mode 100644
index 0000000..cf1a19f
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc885ads.dts
@@ -0,0 +1,185 @@
+/*
+ * MPC885 ADS Device Tree Source
+ *
+ * Copyright 2006 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+
+/ {
+	model = "MPC885ADS";
+	compatible = "mpc8xx";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	linux,phandle = <100>;
+
+	cpus {
+		#cpus = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		linux,phandle = <200>;
+
+		PowerPC,885@0 {
+			device_type = "cpu";
+			reg = <0>;
+			d-cache-line-size = <20>;	// 32 bytes
+			i-cache-line-size = <20>;	// 32 bytes
+			d-cache-size = <2000>;		// L1, 8K
+			i-cache-size = <2000>;		// L1, 8K
+			timebase-frequency = <0>;
+			bus-frequency = <0>;
+			clock-frequency = <0>;
+			32-bit;
+			interrupts = <f 2>;	// decrementer interrupt
+			interrupt-parent = <ff000000>;
+			linux,phandle = <201>;
+			linux,boot-cpu;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		linux,phandle = <300>;
+		reg = <00000000 800000>;
+	};
+
+	soc885@ff000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <2>;
+		device_type = "soc";
+		ranges = <0 ff000000 00100000>;
+		reg = <ff000000 00000200>;
+		bus-frequency = <0>;
+		mdio@e80 {
+			device_type = "mdio";
+			compatible = "fs_enet";
+			reg = <e80 8>;
+			linux,phandle = <e80>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			ethernet-phy@0 {
+				linux,phandle = <e8000>;
+				reg = <0>;
+				device_type = "ethernet-phy";
+			};
+			ethernet-phy@1 {
+				linux,phandle = <e8001>;
+				reg = <1>;
+				device_type = "ethernet-phy";
+			};
+			ethernet-phy@2 {
+				linux,phandle = <e8002>;
+				reg = <2>;
+				device_type = "ethernet-phy";
+			};
+		};
+
+		fec@e00 {
+			device_type = "network";
+			compatible = "fs_enet";
+			model = "FEC";
+			device-id = <1>;
+			reg = <e00 188>;
+			mac-address = [ 00 00 0C 00 01 FD ];
+			interrupts = <3 1>;
+			interrupt-parent = <ff000000>;
+			phy-handle = <e8000>;
+		};
+
+		fec@1e00 {
+			device_type = "network";
+			compatible = "fs_enet";
+			model = "FEC";
+			device-id = <2>;
+			reg = <1e00 188>;
+			mac-address = [ 00 00 0C 00 02 FD ];
+			interrupts = <7 1>;
+			interrupt-parent = <ff000000>;
+			phy-handle = <e8001>;
+		};
+
+		pic@ff000000 {
+			linux,phandle = <ff000000>;
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <0 24>;
+			built-in;
+			device_type = "mpc8xx-pic";
+			compatible = "CPM";
+		};
+
+		cpm@ff000000 {
+			linux,phandle = <ff000000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#interrupt-cells = <2>;
+			device_type = "cpm";
+			model = "CPM";
+			ranges = <0 0 4000>;
+			reg = <860 f0>;
+			command-proc = <9c0>;
+			brg-frequency = <0>;
+			interrupts = <0 2>;	// cpm error interrupt
+			interrupt-parent = <930>;
+
+			pic@930 {
+				linux,phandle = <930>;
+				interrupt-controller;
+				#address-cells = <0>;
+				#interrupt-cells = <2>;
+				interrupts = <5 2 0 2>;
+				interrupt-parent = <ff000000>;
+				reg = <930 20>;
+				built-in;
+				device_type = "cpm-pic";
+				compatible = "CPM";
+			};
+
+			smc@a80 {
+				device_type = "serial";
+				compatible = "cpm_uart";
+				model = "SMC";
+				device-id = <1>;
+				reg = <a80 10 3e80 40>;
+				clock-setup = <00ffffff 0>;
+				rx-clock = <1>;
+				tx-clock = <1>;
+				current-speed = <0>;
+				interrupts = <4 3>;
+				interrupt-parent = <930>;
+			};
+
+			smc@a90 {
+				device_type = "serial";
+				compatible = "cpm_uart";
+				model = "SMC";
+				device-id = <2>;
+				reg = <a90 20 3f80 40>;
+				clock-setup = <ff00ffff 90000>;
+				rx-clock = <2>;
+				tx-clock = <2>;
+				current-speed = <0>;
+				interrupts = <3 3>;
+				interrupt-parent = <930>;
+			};
+
+			scc@a40 {
+				device_type = "network";
+				compatible = "fs_enet";
+				model = "SCC";
+				device-id = <3>;
+				reg = <a40 18 3e00 80>;
+				mac-address = [ 00 00 0C 00 03 FD ];
+				interrupts = <1c 3>;
+				interrupt-parent = <930>;
+				phy-handle = <e8002>;
+			};
+		};
+	};
+};
diff --git a/arch/powerpc/configs/celleb_defconfig b/arch/powerpc/configs/celleb_defconfig
new file mode 100644
index 0000000..a1fe971
--- /dev/null
+++ b/arch/powerpc/configs/celleb_defconfig
@@ -0,0 +1,1408 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.20-rc4
+# Thu Jan 11 20:55:33 2007
+#
+CONFIG_PPC64=y
+CONFIG_64BIT=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_ARCH_HAS_ILOG2_U64=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_COMPAT=y
+CONFIG_SYSVIPC_COMPAT=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+# CONFIG_PPC_UDBG_16550 is not set
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+# CONFIG_DEFAULT_UIMAGE is not set
+
+#
+# Processor support
+#
+# CONFIG_POWER4_ONLY is not set
+CONFIG_POWER3=y
+CONFIG_POWER4=y
+CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_PPC_OF_PLATFORM_PCI=y
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_VIRT_CPU_ACCOUNTING=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_CPUSETS is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Platform support
+#
+CONFIG_PPC_MULTIPLATFORM=y
+# CONFIG_EMBEDDED6xx is not set
+# CONFIG_APUS is not set
+# CONFIG_PPC_PSERIES is not set
+# CONFIG_PPC_ISERIES is not set
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_PMAC is not set
+# CONFIG_PPC_MAPLE is not set
+# CONFIG_PPC_PASEMI is not set
+CONFIG_PPC_CELL=y
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PPC_IBM_CELL_BLADE is not set
+# CONFIG_PPC_PS3 is not set
+CONFIG_PPC_CELLEB=y
+CONFIG_PPC_UDBG_BEAT=y
+# CONFIG_U3_DART is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+# CONFIG_MPIC is not set
+
+#
+# Cell Broadband Engine options
+#
+CONFIG_SPU_FS=y
+CONFIG_SPU_BASE=y
+# CONFIG_CBE_RAS is not set
+
+#
+# Kernel options
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_BKL=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_FORCE_MAX_ZONEORDER=13
+# CONFIG_IOMMU_VMERGE is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_KEXEC=y
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_IRQ_ALL_CPUS is not set
+CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=4
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_NEED_MULTIPLE_NODES=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPARSEMEM_EXTREME=y
+CONFIG_MEMORY_HOTPLUG=y
+CONFIG_MEMORY_HOTPLUG_SPARSE=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+CONFIG_RESOURCES_64BIT=y
+CONFIG_ARCH_MEMORY_PROBE=y
+CONFIG_NODES_SPAN_OTHER_NODES=y
+# CONFIG_PPC_64K_PAGES is not set
+# CONFIG_SCHED_SMT is not set
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_INDIRECT_PCI is not set
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCIEPORTBUS is not set
+# CONFIG_PCI_DEBUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+CONFIG_KERNEL_START=0xc000000000000000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+# CONFIG_IPV6_MIP6 is not set
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NF_CONNTRACK_ENABLED is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_QUEUE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP6_NF_QUEUE is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=131072
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_IDE_CELLEB=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+# CONFIG_MD_RAID456 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=m
+# CONFIG_DM_DEBUG is not set
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_EMC is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_MAC_EMUMOUSEBTN is not set
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_SPIDER_NET=y
+# CONFIG_QLA3XXX is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_MOXA_SMARTIO_NEW is not set
+# CONFIG_ISI is not set
+# CONFIG_SYNCLINK is not set
+# CONFIG_SYNCLINKMP is not set
+# CONFIG_SYNCLINK_GT is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_RIO is not set
+# CONFIG_STALDRV is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_TXX9=y
+CONFIG_HAS_TXX9_SERIAL=y
+CONFIG_SERIAL_TXX9_CONSOLE=y
+# CONFIG_SERIAL_TXX9_STDSERIAL is not set
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_HVC_DRIVER=y
+CONFIG_HVC_BEAT=y
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_MULTITHREAD_PROBE is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT2_FS_XIP=y
+CONFIG_FS_XIP=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+# CONFIG_NFSD_V4 is not set
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_ACL_SUPPORT=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+# CONFIG_KPROBES is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=15
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_RWSEMS is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_FORCED_INLINING is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUGGER=y
+CONFIG_XMON=y
+CONFIG_XMON_DEFAULT=y
+CONFIG_XMON_DISASSEMBLY=y
+CONFIG_IRQSTACKS=y
+# CONFIG_BOOTX_TEXT is not set
+CONFIG_PPC_EARLY_DEBUG=y
+# CONFIG_PPC_EARLY_DEBUG_LPAR is not set
+# CONFIG_PPC_EARLY_DEBUG_G5 is not set
+# CONFIG_PPC_EARLY_DEBUG_RTAS_PANEL is not set
+# CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE is not set
+# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set
+# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set
+CONFIG_PPC_EARLY_DEBUG_BEAT=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/configs/mpc8272_ads_defconfig b/arch/powerpc/configs/mpc8272_ads_defconfig
new file mode 100644
index 0000000..2af4502
--- /dev/null
+++ b/arch/powerpc/configs/mpc8272_ads_defconfig
@@ -0,0 +1,848 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.17-rc5
+# Fri Jul 14 20:36:35 2006
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+# CONFIG_PPC_UDBG_16550 is not set
+# CONFIG_GENERIC_TBSYNC is not set
+# CONFIG_DEFAULT_UIMAGE is not set
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_52xx is not set
+CONFIG_PPC_82xx=y
+# CONFIG_PPC_83xx is not set
+# CONFIG_PPC_85xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_6xx=y
+CONFIG_PPC_FPU=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_SMP is not set
+
+#
+# Code maturity level options
+#
+# CONFIG_EXPERIMENTAL is not set
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION="powerpc8272"
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_PQ2ADS=y
+CONFIG_8260=y
+CONFIG_8272=y
+CONFIG_CPM2=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_EMBEDDEDBOOT=y
+
+#
+# Platform support
+#
+CONFIG_ADS8272=y
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+# CONFIG_PC_KEYBOARD is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+# CONFIG_PPC_I8259 is not set
+CONFIG_FSL_SOC=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00400000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_IPV6_TUNNEL is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_CONNTRACK is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_IDE_GENERIC is not set
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+CONFIG_DAVICOM_PHY=y
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_FIXED_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_FS_ENET=y
+# CONFIG_FS_ENET_HAS_SCC is not set
+CONFIG_FS_ENET_HAS_FCC=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPP_DEFLATE=y
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+CONFIG_SERIAL_CPM_SCC1=y
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+CONFIG_SERIAL_CPM_SCC4=y
+# CONFIG_SERIAL_CPM_SMC1 is not set
+# CONFIG_SERIAL_CPM_SMC2 is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=y
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_HFSPLUS_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SMB_FS=y
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_UNWIND_INFO is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUGGER is not set
+# CONFIG_KGDB_CONSOLE is not set
+CONFIG_BDI_SWITCH=y
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/configs/mpc832xemds_defconfig b/arch/powerpc/configs/mpc832xemds_defconfig
new file mode 100644
index 0000000..e1b36de
--- /dev/null
+++ b/arch/powerpc/configs/mpc832xemds_defconfig
@@ -0,0 +1,1083 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.20-rc5
+# Tue Jan 30 14:27:25 2007
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFAULT_UIMAGE=y
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_82xx is not set
+CONFIG_PPC_83xx=y
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_86xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_6xx=y
+CONFIG_83xx=y
+CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_SMP is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_QUICC_ENGINE=y
+CONFIG_PPC_GEN550=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Platform support
+#
+CONFIG_MPC832x_MDS=y
+# CONFIG_MPC834x_SYS is not set
+# CONFIG_MPC834x_ITX is not set
+# CONFIG_MPC8360E_PB is not set
+CONFIG_PPC_MPC832x=y
+# CONFIG_MPIC is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_MATH_EMULATION=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCIEPORTBUS is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+# CONFIG_BLK_DEV_SD is not set
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_MAC_EMUMOUSEBTN is not set
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_GIANFAR is not set
+CONFIG_UCC_GETH=y
+# CONFIG_UGETH_NAPI is not set
+# CONFIG_UGETH_MAGIC_PACKET is not set
+# CONFIG_UGETH_FILTERING is not set
+# CONFIG_UGETH_TX_ON_DEMOND is not set
+# CONFIG_QLA3XXX is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_83xx_WDT=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# QE Options
+#
+CONFIG_UCC_SLOW=y
+CONFIG_UCC_FAST=y
+CONFIG_UCC=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/configs/mpc834x_itx_defconfig b/arch/powerpc/configs/mpc834x_itx_defconfig
index 45757b6..7902806 100644
--- a/arch/powerpc/configs/mpc834x_itx_defconfig
+++ b/arch/powerpc/configs/mpc834x_itx_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20-rc5
-# Mon Jan 22 22:23:43 2007
+# Fri Jan 26 00:19:02 2007
 #
 # CONFIG_PPC64 is not set
 CONFIG_PPC32=y
@@ -149,7 +149,6 @@
 # CONFIG_PREEMPT is not set
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_MATH_EMULATION=y
 CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
 CONFIG_ARCH_POPULATES_NODE_MAP=y
@@ -324,6 +323,7 @@
 # User Modules And Translation Layers
 #
 CONFIG_MTD_CHAR=y
+# CONFIG_MTD_BLKDEVS is not set
 # CONFIG_MTD_BLOCK is not set
 # CONFIG_MTD_BLOCK_RO is not set
 # CONFIG_FTL is not set
@@ -366,6 +366,7 @@
 CONFIG_MTD_PHYSMAP_START=0xfe000000
 CONFIG_MTD_PHYSMAP_LEN=0x1000000
 CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PHYSMAP_OF is not set
 # CONFIG_MTD_PLATRAM is not set
 
 #
@@ -390,6 +391,7 @@
 # NAND Flash Device Drivers
 #
 # CONFIG_MTD_NAND is not set
+# CONFIG_MTD_NAND_CAFE is not set
 
 #
 # OneNAND Flash Device Drivers
@@ -1011,7 +1013,6 @@
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_MULTITHREAD_PROBE is not set
 # CONFIG_USB_OTG is not set
 
 #
diff --git a/arch/powerpc/configs/mpc834x_mds_defconfig b/arch/powerpc/configs/mpc834x_mds_defconfig
index c24db58..9eaed3a 100644
--- a/arch/powerpc/configs/mpc834x_mds_defconfig
+++ b/arch/powerpc/configs/mpc834x_mds_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20-rc5
-# Mon Jan 22 22:24:10 2007
+# Fri Jan 26 00:19:27 2007
 #
 # CONFIG_PPC64 is not set
 CONFIG_PPC32=y
@@ -149,7 +149,6 @@
 # CONFIG_PREEMPT is not set
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_MATH_EMULATION=y
 CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
 CONFIG_ARCH_POPULATES_NODE_MAP=y
diff --git a/arch/powerpc/configs/mpc8360emds_defconfig b/arch/powerpc/configs/mpc8360emds_defconfig
index 58e6795..bbe38cc 100644
--- a/arch/powerpc/configs/mpc8360emds_defconfig
+++ b/arch/powerpc/configs/mpc8360emds_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20-rc5
-# Mon Jan 22 22:24:40 2007
+# Fri Jan 26 00:19:45 2007
 #
 # CONFIG_PPC64 is not set
 CONFIG_PPC32=y
@@ -150,7 +150,6 @@
 # CONFIG_PREEMPT is not set
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_MATH_EMULATION=y
 CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
 CONFIG_ARCH_POPULATES_NODE_MAP=y
diff --git a/arch/powerpc/configs/mpc866_ads_defconfig b/arch/powerpc/configs/mpc866_ads_defconfig
new file mode 100644
index 0000000..539d9e3
--- /dev/null
+++ b/arch/powerpc/configs/mpc866_ads_defconfig
@@ -0,0 +1,829 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.19-rc6
+# Fri Nov 24 21:13:55 2006
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+# CONFIG_PPC_UDBG_16550 is not set
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+# CONFIG_DEFAULT_UIMAGE is not set
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_52xx is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_86xx is not set
+CONFIG_PPC_8xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_8xx=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+# CONFIG_BUG is not set
+CONFIG_ELF_CORE=y
+# CONFIG_BASE_FULL is not set
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=1
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_EMBEDDEDBOOT=y
+# CONFIG_MPIC is not set
+
+#
+# Platform support
+#
+CONFIG_CPM1=y
+# CONFIG_MPC8XXFADS is not set
+CONFIG_MPC86XADS=y
+# CONFIG_MPC885ADS is not set
+
+#
+# MPC8xx CPM Options
+#
+
+#
+# Generic MPC8xx Options
+#
+CONFIG_8xx_COPYBACK=y
+CONFIG_8xx_CPU6=y
+CONFIG_NO_UCODE_PATCH=y
+# CONFIG_USB_SOF_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_SMC1_UCODE_PATCH is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_MATH_EMULATION=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_PROC_DEVICETREE is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+CONFIG_FSL_SOC=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+# CONFIG_PCI_QSPAN is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_START=0xff100000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_BOOT_LOAD=0x00400000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_TIFM_CORE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+CONFIG_FIXED_PHY=y
+CONFIG_FIXED_MII_10_FDX=y
+CONFIG_FIXED_MII_100_FDX=y
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_FEC_8XX is not set
+CONFIG_FS_ENET=y
+CONFIG_FS_ENET_HAS_SCC=y
+CONFIG_FS_ENET_HAS_FEC=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+CONFIG_SERIAL_CPM_SMC2=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_FS is not set
+# CONFIG_UNWIND_INFO is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
diff --git a/arch/powerpc/configs/mpc885_ads_defconfig b/arch/powerpc/configs/mpc885_ads_defconfig
new file mode 100644
index 0000000..e2c17d8
--- /dev/null
+++ b/arch/powerpc/configs/mpc885_ads_defconfig
@@ -0,0 +1,827 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.19-rc4
+# Fri Nov 10 21:30:40 2006
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+# CONFIG_PPC_UDBG_16550 is not set
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+# CONFIG_DEFAULT_UIMAGE is not set
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_52xx is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_86xx is not set
+CONFIG_PPC_8xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_8xx=y
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+# CONFIG_BUG is not set
+CONFIG_ELF_CORE=y
+# CONFIG_BASE_FULL is not set
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=1
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_EMBEDDEDBOOT=y
+# CONFIG_MPIC is not set
+
+#
+# Platform support
+#
+CONFIG_CPM1=y
+# CONFIG_MPC8XXFADS is not set
+# CONFIG_MPC86XADS is not set
+CONFIG_MPC885ADS=y
+
+#
+# MPC8xx CPM Options
+#
+
+#
+# Generic MPC8xx Options
+#
+CONFIG_8xx_COPYBACK=y
+# CONFIG_8xx_CPU6 is not set
+CONFIG_NO_UCODE_PATCH=y
+# CONFIG_USB_SOF_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_SMC1_UCODE_PATCH is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_MATH_EMULATION=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_PROC_DEVICETREE is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+CONFIG_FSL_SOC=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+# CONFIG_PCI_QSPAN is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_START=0xff100000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_BOOT_LOAD=0x00400000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_TIFM_CORE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+CONFIG_DAVICOM_PHY=y
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+CONFIG_FIXED_PHY=y
+CONFIG_FIXED_MII_10_FDX=y
+# CONFIG_FIXED_MII_100_FDX is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_FEC_8XX is not set
+CONFIG_FS_ENET=y
+CONFIG_FS_ENET_HAS_SCC=y
+CONFIG_FS_ENET_HAS_FEC=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+CONFIG_SERIAL_CPM_SMC2=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_FS is not set
+# CONFIG_UNWIND_INFO is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
diff --git a/arch/powerpc/configs/pasemi_defconfig b/arch/powerpc/configs/pasemi_defconfig
new file mode 100644
index 0000000..97a57e9
--- /dev/null
+++ b/arch/powerpc/configs/pasemi_defconfig
@@ -0,0 +1,1722 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.20-rc6
+# Thu Feb  1 22:54:15 2007
+#
+CONFIG_PPC64=y
+CONFIG_64BIT=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_ARCH_HAS_ILOG2_U64=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_COMPAT=y
+CONFIG_SYSVIPC_COMPAT=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_PPC_UDBG_16550=y
+CONFIG_GENERIC_TBSYNC=y
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+# CONFIG_DEFAULT_UIMAGE is not set
+
+#
+# Processor support
+#
+CONFIG_POWER4_ONLY=y
+CONFIG_POWER4=y
+CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+# CONFIG_PPC_OF_PLATFORM_PCI is not set
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+# CONFIG_VIRT_CPU_ACCOUNTING is not set
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_CPUSETS is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+CONFIG_STOP_MACHINE=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Platform support
+#
+CONFIG_PPC_MULTIPLATFORM=y
+# CONFIG_EMBEDDED6xx is not set
+# CONFIG_APUS is not set
+CONFIG_PPC_PSERIES=y
+# CONFIG_PPC_ISERIES is not set
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_PMAC is not set
+# CONFIG_PPC_MAPLE is not set
+CONFIG_PPC_PASEMI=y
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PPC_IBM_CELL_BLADE is not set
+# CONFIG_PPC_PS3 is not set
+CONFIG_PPC_NATIVE=y
+# CONFIG_UDBG_RTAS_CONSOLE is not set
+CONFIG_XICS=y
+# CONFIG_U3_DART is not set
+CONFIG_PPC_RTAS=y
+CONFIG_RTAS_ERROR_LOGGING=y
+CONFIG_RTAS_PROC=y
+# CONFIG_RTAS_FLASH is not set
+# CONFIG_MMIO_NVRAM is not set
+CONFIG_IBMVIO=y
+# CONFIG_IBMEBUS is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_MPIC=y
+
+#
+# PA Semi PWRficient options
+#
+CONFIG_PPC_PASEMI_IOMMU=y
+
+#
+# Kernel options
+#
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_BKL=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_FORCE_MAX_ZONEORDER=13
+CONFIG_IOMMU_VMERGE=y
+# CONFIG_HOTPLUG_CPU is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_IRQ_ALL_CPUS is not set
+# CONFIG_PPC_SPLPAR is not set
+CONFIG_EEH=y
+# CONFIG_SCANLOG is not set
+# CONFIG_LPARCFG is not set
+# CONFIG_NUMA is not set
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_RESOURCES_64BIT=y
+# CONFIG_PPC_64K_PAGES is not set
+# CONFIG_SCHED_SMT is not set
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_MPIC_WEIRD is not set
+CONFIG_PPC_I8259=y
+# CONFIG_PPC_INDIRECT_PCI is not set
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCIEPORTBUS is not set
+# CONFIG_PCI_DEBUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=y
+CONFIG_PCMCIA_DEBUG=y
+CONFIG_PCMCIA=y
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
+CONFIG_CARDBUS=y
+
+#
+# PC-card bridges
+#
+# CONFIG_YENTA is not set
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+CONFIG_KERNEL_START=0xc000000000000000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=y
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+# CONFIG_MTD_PARTITIONS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+CONFIG_MTD_SLRAM=y
+CONFIG_MTD_PHRAM=y
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_NAND_CAFE is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+CONFIG_BLK_DEV_IDESCSI=y
+CONFIG_IDE_TASK_IOCTL=y
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_IDE_GENERIC is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_CHR_DEV_OSST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+CONFIG_BLK_DEV_3W_XXXX_RAID=y
+CONFIG_SCSI_3W_9XXX=y
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_IBMVSCSI is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_SYM53C500 is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_AHCI is not set
+CONFIG_SATA_SVW=y
+# CONFIG_ATA_PIIX is not set
+CONFIG_SATA_MV=y
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+CONFIG_SATA_SIL=y
+CONFIG_SATA_SIL24=y
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+CONFIG_ATA_GENERIC=y
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PCMCIA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+CONFIG_IEEE1394=y
+
+#
+# Subsystem Options
+#
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+# CONFIG_IEEE1394_OUI_DB is not set
+# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set
+# CONFIG_IEEE1394_EXPORT_FULL_API is not set
+
+#
+# Device Drivers
+#
+CONFIG_IEEE1394_PCILYNX=y
+CONFIG_IEEE1394_OHCI1394=y
+
+#
+# Protocol Drivers
+#
+# CONFIG_IEEE1394_VIDEO1394 is not set
+CONFIG_IEEE1394_SBP2=y
+# CONFIG_IEEE1394_ETH1394 is not set
+# CONFIG_IEEE1394_DV1394 is not set
+CONFIG_IEEE1394_RAWIO=y
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_MAC_EMUMOUSEBTN is not set
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_IBMVETH=y
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+CONFIG_EEPRO100=y
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+CONFIG_E1000_NAPI=y
+# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+CONFIG_TIGON3=y
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=y
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
+# CONFIG_SERIAL_8250_CS is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_ICOM is not set
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=4
+CONFIG_HVC_DRIVER=y
+CONFIG_HVC_CONSOLE=y
+CONFIG_HVC_RTAS=y
+# CONFIG_HVCS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+CONFIG_GEN_RTC=y
+CONFIG_GEN_RTC_X=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+CONFIG_RAW_DRIVER=y
+CONFIG_MAX_RAW_DEVS=256
+# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+CONFIG_I2C_ALGOPCF=y
+CONFIG_I2C_ALGOPCA=y
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+CONFIG_SENSORS_EEPROM=y
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+CONFIG_I2C_DEBUG_BUS=y
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+CONFIG_HWMON_VID=y
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+CONFIG_SENSORS_LM85=y
+# CONFIG_SENSORS_LM87 is not set
+CONFIG_SENSORS_LM90=y
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB=y
+CONFIG_FB_DDC=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_MACMODES=y
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_OF is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+CONFIG_FB_VGA16=y
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_NVIDIA=y
+CONFIG_FB_NVIDIA_I2C=y
+CONFIG_FB_RIVA=y
+CONFIG_FB_RIVA_I2C=y
+# CONFIG_FB_RIVA_DEBUG is not set
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G=y
+CONFIG_FB_MATROX_I2C=y
+CONFIG_FB_MATROX_MAVEN=y
+CONFIG_FB_MATROX_MULTIHEAD=y
+CONFIG_FB_RADEON=y
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+CONFIG_VGACON_SOFT_SCROLLBACK=y
+CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_HWDEP=y
+CONFIG_SND_RAWMIDI=y
+CONFIG_SND_SEQUENCER=y
+# CONFIG_SND_SEQ_DUMMY is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+
+#
+# ALSA PowerMac devices
+#
+
+#
+# USB devices
+#
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_USB_USX2Y=y
+
+#
+# PCMCIA devices
+#
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_PDAUDIOCF is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=y
+CONFIG_USB_SL811_HCD=y
+# CONFIG_USB_SL811_CS is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+CONFIG_USB_LIBUSUAL=y
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+
+#
+# RTC drivers
+#
+# CONFIG_RTC_DRV_X1205 is not set
+CONFIG_RTC_DRV_DS1307=y
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+CONFIG_CONFIGFS_FS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
+
+#
+# Instrumentation Support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+# CONFIG_KPROBES is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUGGER=y
+CONFIG_XMON=y
+CONFIG_XMON_DEFAULT=y
+CONFIG_XMON_DISASSEMBLY=y
+# CONFIG_IRQSTACKS is not set
+CONFIG_BOOTX_TEXT=y
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig
index 3256087..ec644b3 100644
--- a/arch/powerpc/configs/ps3_defconfig
+++ b/arch/powerpc/configs/ps3_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20-rc5
-# Mon Jan 22 22:29:11 2007
+# Linux kernel version: 2.6.20-rc6
+# Thu Jan 25 13:35:34 2007
 #
 CONFIG_PPC64=y
 CONFIG_64BIT=y
@@ -70,10 +70,10 @@
 CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
 CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
-CONFIG_EMBEDDED=y
-# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
@@ -160,7 +160,7 @@
 # PS3 Platform Options
 #
 CONFIG_PS3_HTAB_SIZE=20
-CONFIG_PS3_DYNAMIC_DMA=y
+# CONFIG_PS3_DYNAMIC_DMA is not set
 CONFIG_PS3_USE_LPAR_ADDR=y
 CONFIG_PS3_VUART=y
 
@@ -207,7 +207,7 @@
 # CONFIG_SCHED_SMT is not set
 CONFIG_PROC_DEVICETREE=y
 CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="root=/dev/nfs rw ip=dhcp"
+CONFIG_CMDLINE="root=/dev/sda1 ip=dhcp"
 # CONFIG_PM is not set
 # CONFIG_SECCOMP is not set
 CONFIG_ISA_DMA_API=y
@@ -240,7 +240,8 @@
 # Networking options
 #
 # CONFIG_NETDEBUG is not set
-# CONFIG_PACKET is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
@@ -353,6 +354,7 @@
 # CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
 # CONFIG_CDROM_PKTCDVD is not set
@@ -380,10 +382,11 @@
 #
 # SCSI support type (disk, tape, CD-ROM)
 #
-# CONFIG_BLK_DEV_SD is not set
+CONFIG_BLK_DEV_SD=y
 # CONFIG_CHR_DEV_ST is not set
 # CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
 # CONFIG_CHR_DEV_SG is not set
 # CONFIG_CHR_DEV_SCH is not set
 
@@ -456,6 +459,7 @@
 # Ethernet (10 or 100Mbit)
 #
 # CONFIG_NET_ETHERNET is not set
+CONFIG_MII=y
 
 #
 # Ethernet (1000 Mbit)
@@ -504,10 +508,13 @@
 #
 # Userland interfaces
 #
-# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
 # CONFIG_INPUT_TSDEV is not set
-CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
 
 #
@@ -598,6 +605,7 @@
 # Digital Video Broadcasting Devices
 #
 # CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
 
 #
 # Graphics support
@@ -626,15 +634,142 @@
 #
 # USB support
 #
-# CONFIG_USB_ARCH_HAS_HCD is not set
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
 
 #
 # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
 #
 
 #
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET_MII=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_GL620A is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_PLUSB is not set
+CONFIG_USB_NET_MCS7830=y
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_ZAURUS is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+
+#
+# USB DSL modem support
+#
+
+#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
@@ -691,8 +826,14 @@
 # File systems
 #
 # CONFIG_EXT2_FS is not set
-# CONFIG_EXT3_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
 # CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
@@ -712,14 +853,20 @@
 #
 # CD-ROM/DVD Filesystems
 #
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
 
 #
 # DOS/FAT/NT Filesystems
 #
+CONFIG_FAT_FS=y
 # CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
@@ -785,7 +932,46 @@
 #
 # Native Language Support
 #
-# CONFIG_NLS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
 
 #
 # Distributed Lock Manager
@@ -795,9 +981,10 @@
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
-# CONFIG_CRC32 is not set
+CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_PLIST=y
 CONFIG_IOMAP_COPY=y
@@ -821,22 +1008,23 @@
 CONFIG_LOG_BUF_SHIFT=17
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_SLAB=y
+# CONFIG_DEBUG_SLAB_LEAK is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
 CONFIG_DEBUG_SPINLOCK=y
-# CONFIG_DEBUG_MUTEXES is not set
-# CONFIG_DEBUG_RWSEMS is not set
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_RWSEMS=y
 CONFIG_DEBUG_SPINLOCK_SLEEP=y
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_VM is not set
 CONFIG_DEBUG_LIST=y
 CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
-# CONFIG_DEBUG_STACKOVERFLOW is not set
+CONFIG_DEBUG_STACKOVERFLOW=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 # CONFIG_DEBUGGER is not set
 CONFIG_IRQSTACKS=y
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index d2ded19..8120d42 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -17,6 +17,7 @@
 obj-$(CONFIG_PPC64)		+= setup_64.o binfmt_elf32.o sys_ppc32.o \
 				   signal_64.o ptrace32.o \
 				   paca.o cpu_setup_ppc970.o \
+				   cpu_setup_pa6t.o \
 				   firmware.o sysfs.o nvram_64.o
 obj-$(CONFIG_PPC64)		+= vdso64/
 obj-$(CONFIG_ALTIVEC)		+= vecemu.o vector.o
diff --git a/arch/powerpc/kernel/cpu_setup_pa6t.S b/arch/powerpc/kernel/cpu_setup_pa6t.S
new file mode 100644
index 0000000..4047be2
--- /dev/null
+++ b/arch/powerpc/kernel/cpu_setup_pa6t.S
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/cache.h>
+
+/* Right now, restore and setup are the same thing */
+_GLOBAL(__restore_cpu_pa6t)
+_GLOBAL(__setup_cpu_pa6t)
+	/* Do nothing if not running in HV mode */
+	mfmsr	r0
+	rldicl.	r0,r0,4,63
+	beqlr
+
+	mfspr	r0,SPRN_HID5
+	ori	r0,r0,0x30
+	mtspr	SPRN_HID5,r0
+
+	mfspr	r0,SPRN_LPCR
+	ori	r0,r0,0x7000
+	mtspr	SPRN_LPCR,r0
+
+	blr
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index b742013..dd17dff 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -43,6 +43,8 @@
 #ifdef CONFIG_PPC64
 extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_ppc970MP(unsigned long offset, struct cpu_spec* spec);
+extern void __setup_cpu_pa6t(unsigned long offset, struct cpu_spec* spec);
+extern void __restore_cpu_pa6t(unsigned long offset, struct cpu_spec* spec);
 extern void __restore_cpu_ppc970(void);
 #endif /* CONFIG_PPC64 */
 
@@ -86,6 +88,7 @@
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
+		.pmc_type		= PPC_PMC_IBM,
 		.oprofile_cpu_type	= "ppc64/power3",
 		.oprofile_type		= PPC_OPROFILE_RS64,
 		.platform		= "power3",
@@ -99,6 +102,7 @@
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
+		.pmc_type		= PPC_PMC_IBM,
 		.oprofile_cpu_type	= "ppc64/power3",
 		.oprofile_type		= PPC_OPROFILE_RS64,
 		.platform		= "power3",
@@ -112,6 +116,7 @@
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
+		.pmc_type		= PPC_PMC_IBM,
 		.oprofile_cpu_type	= "ppc64/rs64",
 		.oprofile_type		= PPC_OPROFILE_RS64,
 		.platform		= "rs64",
@@ -125,6 +130,7 @@
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
+		.pmc_type		= PPC_PMC_IBM,
 		.oprofile_cpu_type	= "ppc64/rs64",
 		.oprofile_type		= PPC_OPROFILE_RS64,
 		.platform		= "rs64",
@@ -138,6 +144,7 @@
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
+		.pmc_type		= PPC_PMC_IBM,
 		.oprofile_cpu_type	= "ppc64/rs64",
 		.oprofile_type		= PPC_OPROFILE_RS64,
 		.platform		= "rs64",
@@ -151,6 +158,7 @@
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
+		.pmc_type		= PPC_PMC_IBM,
 		.oprofile_cpu_type	= "ppc64/rs64",
 		.oprofile_type		= PPC_OPROFILE_RS64,
 		.platform		= "rs64",
@@ -164,6 +172,7 @@
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
+		.pmc_type		= PPC_PMC_IBM,
 		.oprofile_cpu_type	= "ppc64/power4",
 		.oprofile_type		= PPC_OPROFILE_POWER4,
 		.platform		= "power4",
@@ -177,6 +186,7 @@
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
+		.pmc_type		= PPC_PMC_IBM,
 		.oprofile_cpu_type	= "ppc64/power4",
 		.oprofile_type		= PPC_OPROFILE_POWER4,
 		.platform		= "power4",
@@ -191,6 +201,7 @@
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
+		.pmc_type		= PPC_PMC_IBM,
 		.cpu_setup		= __setup_cpu_ppc970,
 		.cpu_restore		= __restore_cpu_ppc970,
 		.oprofile_cpu_type	= "ppc64/970",
@@ -207,6 +218,7 @@
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
+		.pmc_type		= PPC_PMC_IBM,
 		.cpu_setup		= __setup_cpu_ppc970,
 		.cpu_restore		= __restore_cpu_ppc970,
 		.oprofile_cpu_type	= "ppc64/970",
@@ -239,6 +251,7 @@
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
+		.pmc_type		= PPC_PMC_IBM,
 		.cpu_setup		= __setup_cpu_ppc970,
 		.oprofile_cpu_type	= "ppc64/970",
 		.oprofile_type		= PPC_OPROFILE_POWER4,
@@ -253,6 +266,7 @@
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 6,
+		.pmc_type		= PPC_PMC_IBM,
 		.oprofile_cpu_type	= "ppc64/power5",
 		.oprofile_type		= PPC_OPROFILE_POWER4,
 		/* SIHV / SIPR bits are implemented on POWER4+ (GQ)
@@ -271,6 +285,7 @@
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 6,
+		.pmc_type		= PPC_PMC_IBM,
 		.oprofile_cpu_type	= "ppc64/power5+",
 		.oprofile_type		= PPC_OPROFILE_POWER4,
 		.oprofile_mmcra_sihv	= MMCRA_SIHV,
@@ -321,6 +336,7 @@
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 6,
+		.pmc_type		= PPC_PMC_IBM,
 		.oprofile_cpu_type	= "ppc64/power6",
 		.oprofile_type		= PPC_OPROFILE_POWER4,
  		.oprofile_mmcra_sihv	= POWER6_MMCRA_SIHV,
@@ -340,6 +356,7 @@
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 4,
+		.pmc_type		= PPC_PMC_IBM,
 		.oprofile_cpu_type	= "ppc64/cell-be",
 		.oprofile_type		= PPC_OPROFILE_CELL,
 		.platform		= "ppc-cell-be",
@@ -353,6 +370,9 @@
 		.icache_bsize		= 64,
 		.dcache_bsize		= 64,
 		.num_pmcs		= 6,
+		.pmc_type		= PPC_PMC_PA6T,
+		.cpu_setup		= __setup_cpu_pa6t,
+		.cpu_restore		= __restore_cpu_pa6t,
 		.platform		= "pa6t",
 	},
 	{	/* default match */
@@ -364,6 +384,7 @@
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 6,
+		.pmc_type		= PPC_PMC_IBM,
 		.platform		= "power4",
 	}
 #endif	/* CONFIG_PPC64 */
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 2551c08..2b66d53 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -172,13 +172,18 @@
 	stdcx.	r0,0,r1			/* to clear the reservation */
 	andi.	r6,r8,MSR_PR
 	ld	r4,_LINK(r1)
+	/*
+	 * Clear RI before restoring r13.  If we are returning to
+	 * userspace and we take an exception after restoring r13,
+	 * we end up corrupting the userspace r13 value.
+	 */
+	li	r12,MSR_RI
+	andc	r11,r10,r12
+	mtmsrd	r11,1			/* clear MSR.RI */
 	beq-	1f
 	ACCOUNT_CPU_USER_EXIT(r11, r12)
 	ld	r13,GPR13(r1)	/* only restore r13 if returning to usermode */
 1:	ld	r2,GPR2(r1)
-	li	r12,MSR_RI
-	andc	r11,r10,r12
-	mtmsrd	r11,1			/* clear MSR.RI */
 	ld	r1,GPR1(r1)
 	mtlr	r4
 	mtcr	r5
@@ -488,42 +493,44 @@
 #endif
 	stb	r5,PACASOFTIRQEN(r13)
 
-	ld	r3,_MSR(r1)
-	andi.	r0,r3,MSR_RI
-	beq-	unrecov_restore
-
 	/* extract EE bit and use it to restore paca->hard_enabled */
+	ld	r3,_MSR(r1)
 	rldicl	r4,r3,49,63		/* r0 = (r3 >> 15) & 1 */
 	stb	r4,PACAHARDIRQEN(r13)
 
-	andi.	r0,r3,MSR_PR
+	ld	r4,_CTR(r1)
+	ld	r0,_LINK(r1)
+	mtctr	r4
+	mtlr	r0
+	ld	r4,_XER(r1)
+	mtspr	SPRN_XER,r4
+
+	REST_8GPRS(5, r1)
+
+	andi.	r0,r3,MSR_RI
+	beq-	unrecov_restore
+
+	stdcx.	r0,0,r1		/* to clear the reservation */
+
+	/*
+	 * Clear RI before restoring r13.  If we are returning to
+	 * userspace and we take an exception after restoring r13,
+	 * we end up corrupting the userspace r13 value.
+	 */
+	mfmsr	r4
+	andc	r4,r4,r0	/* r0 contains MSR_RI here */
+	mtmsrd	r4,1
 
 	/*
 	 * r13 is our per cpu area, only restore it if we are returning to
 	 * userspace
 	 */
+	andi.	r0,r3,MSR_PR
 	beq	1f
-	ACCOUNT_CPU_USER_EXIT(r3, r4)
+	ACCOUNT_CPU_USER_EXIT(r2, r4)
 	REST_GPR(13, r1)
 1:
-	ld	r3,_CTR(r1)
-	ld	r0,_LINK(r1)
-	mtctr	r3
-	mtlr	r0
-	ld	r3,_XER(r1)
-	mtspr	SPRN_XER,r3
-
-	REST_8GPRS(5, r1)
-
-	stdcx.	r0,0,r1		/* to clear the reservation */
-
-	mfmsr	r0
-	li	r2, MSR_RI
-	andc	r0,r0,r2
-	mtmsrd	r0,1
-
-	ld	r0,_MSR(r1)
-	mtspr	SPRN_SRR1,r0
+	mtspr	SPRN_SRR1,r3
 
 	ld	r2,_CCR(r1)
 	mtcrf	0xFF,r2
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index 9417cf5..c897203 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -344,12 +344,7 @@
 /* System reset */
 /* core99 pmac starts the seconary here by changing the vector, and
    putting it back to what it was (unknown_exception) when done.  */
-#if defined(CONFIG_GEMINI) && defined(CONFIG_SMP)
-	. = 0x100
-	b	__secondary_start_gemini
-#else
 	EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD)
-#endif
 
 /* Machine check */
 /*
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 71b1fe5..97cedcd6 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -613,7 +613,7 @@
 /*** pSeries interrupt support ***/
 
 	/* moved from 0xf00 */
-	MASKABLE_EXCEPTION_PSERIES(., performance_monitor)
+	STD_EXCEPTION_PSERIES(., performance_monitor)
 
 /*
  * An interrupt came in while soft-disabled; clear EE in SRR1,
diff --git a/arch/powerpc/kernel/iomap.c b/arch/powerpc/kernel/iomap.c
index c681133..601ef79 100644
--- a/arch/powerpc/kernel/iomap.c
+++ b/arch/powerpc/kernel/iomap.c
@@ -12,23 +12,23 @@
  * Here comes the ppc64 implementation of the IOMAP 
  * interfaces.
  */
-unsigned int fastcall ioread8(void __iomem *addr)
+unsigned int ioread8(void __iomem *addr)
 {
 	return readb(addr);
 }
-unsigned int fastcall ioread16(void __iomem *addr)
+unsigned int ioread16(void __iomem *addr)
 {
 	return readw(addr);
 }
-unsigned int fastcall ioread16be(void __iomem *addr)
+unsigned int ioread16be(void __iomem *addr)
 {
 	return in_be16(addr);
 }
-unsigned int fastcall ioread32(void __iomem *addr)
+unsigned int ioread32(void __iomem *addr)
 {
 	return readl(addr);
 }
-unsigned int fastcall ioread32be(void __iomem *addr)
+unsigned int ioread32be(void __iomem *addr)
 {
 	return in_be32(addr);
 }
@@ -38,23 +38,23 @@
 EXPORT_SYMBOL(ioread32);
 EXPORT_SYMBOL(ioread32be);
 
-void fastcall iowrite8(u8 val, void __iomem *addr)
+void iowrite8(u8 val, void __iomem *addr)
 {
 	writeb(val, addr);
 }
-void fastcall iowrite16(u16 val, void __iomem *addr)
+void iowrite16(u16 val, void __iomem *addr)
 {
 	writew(val, addr);
 }
-void fastcall iowrite16be(u16 val, void __iomem *addr)
+void iowrite16be(u16 val, void __iomem *addr)
 {
 	out_be16(addr, val);
 }
-void fastcall iowrite32(u32 val, void __iomem *addr)
+void iowrite32(u32 val, void __iomem *addr)
 {
 	writel(val, addr);
 }
-void fastcall iowrite32be(u32 val, void __iomem *addr)
+void iowrite32be(u32 val, void __iomem *addr)
 {
 	out_be32(addr, val);
 }
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 0bd8c76..919fbf5 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -281,10 +281,10 @@
 
 	/*
 	 * Every platform is required to implement ppc_md.get_irq.
-	 * This function will either return an irq number or -1 to
+	 * This function will either return an irq number or NO_IRQ to
 	 * indicate there are no more pending.
-	 * The value -2 is for buggy hardware and means that this IRQ
-	 * has already been handled. -- Tom
+	 * The value NO_IRQ_IGNORE is for buggy hardware and means that this
+	 * IRQ has already been handled. -- Tom
 	 */
 	irq = ppc_md.get_irq();
 
@@ -604,6 +604,8 @@
 	 */
 	virq = irq_find_mapping(host, hwirq);
 	if (virq != IRQ_NONE) {
+		if (host->ops->remap)
+			host->ops->remap(host, virq, hwirq);
 		pr_debug("irq: -> existing mapping on virq %d\n", virq);
 		return virq;
 	}
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index 4657563..dd2886f 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -46,8 +46,8 @@
 	if ((unsigned long)p->addr & 0x03) {
 		printk("Attempt to register kprobe at an unaligned address\n");
 		ret = -EINVAL;
-	} else if (IS_MTMSRD(insn) || IS_RFID(insn)) {
-		printk("Cannot register a kprobe on rfid or mtmsrd\n");
+	} else if (IS_MTMSRD(insn) || IS_RFID(insn) || IS_RFI(insn)) {
+		printk("Cannot register a kprobe on rfi/rfid or mtmsr[d]\n");
 		ret = -EINVAL;
 	}
 
@@ -483,8 +483,12 @@
 	memcpy(&kcb->jprobe_saved_regs, regs, sizeof(struct pt_regs));
 
 	/* setup return addr to the jprobe handler routine */
+#ifdef CONFIG_PPC64
 	regs->nip = (unsigned long)(((func_descr_t *)jp->entry)->entry);
 	regs->gpr[2] = (unsigned long)(((func_descr_t *)jp->entry)->toc);
+#else
+	regs->nip = (unsigned long)jp->entry;
+#endif
 
 	return 1;
 }
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index 41c05dc..0de5a08 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -439,6 +439,10 @@
 
 	ssize_t retval = -ENOMEM;
 
+	if (!firmware_has_feature(FW_FEATURE_SPLPAR) ||
+			firmware_has_feature(FW_FEATURE_ISERIES))
+		return -EINVAL;
+
 	kbuf = kmalloc(count, GFP_KERNEL);
 	if (!kbuf)
 		goto out;
@@ -517,7 +521,7 @@
 static ssize_t lparcfg_write(struct file *file, const char __user * buf,
 			     size_t count, loff_t * off)
 {
-	return count;
+	return -EINVAL;
 }
 
 #endif				/* CONFIG_PPC_PSERIES */
@@ -570,6 +574,7 @@
 struct file_operations lparcfg_fops = {
 	.owner		= THIS_MODULE,
 	.read		= seq_read,
+	.write		= lparcfg_write,
 	.open		= lparcfg_open,
 	.release	= single_release,
 };
@@ -581,10 +586,8 @@
 
 	/* Allow writing if we have FW_FEATURE_SPLPAR */
 	if (firmware_has_feature(FW_FEATURE_SPLPAR) &&
-			!firmware_has_feature(FW_FEATURE_ISERIES)) {
-		lparcfg_fops.write = lparcfg_write;
+			!firmware_has_feature(FW_FEATURE_ISERIES))
 		mode |= S_IWUSR;
-	}
 
 	ent = create_proc_entry("ppc64/lparcfg", mode, NULL);
 	if (ent) {
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index 21fd2c6..519861d 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -311,6 +311,46 @@
 	blr
 #endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */
 
+#ifdef CONFIG_PPC_PASEMI
+
+/* No support in all binutils for these yet, so use defines */
+#define LBZCIX(RT,RA,RB)  .long (0x7c0006aa|(RT<<21)|(RA<<16)|(RB << 11))
+#define STBCIX(RS,RA,RB)  .long (0x7c0007aa|(RS<<21)|(RA<<16)|(RB << 11))
+
+
+_GLOBAL(real_205_readb)
+	mfmsr	r7
+	ori	r0,r7,MSR_DR
+	xori	r0,r0,MSR_DR
+	sync
+	mtmsrd	r0
+	sync
+	isync
+	LBZCIX(r3,0,r3)
+	isync
+	mtmsrd	r7
+	sync
+	isync
+	blr
+
+_GLOBAL(real_205_writeb)
+	mfmsr	r7
+	ori	r0,r7,MSR_DR
+	xori	r0,r0,MSR_DR
+	sync
+	mtmsrd	r0
+	sync
+	isync
+	STBCIX(r3,0,r4)
+	isync
+	mtmsrd	r7
+	sync
+	isync
+	blr
+
+#endif /* CONFIG_PPC_PASEMI */
+
+
 #ifdef CONFIG_CPU_FREQ_PMAC64
 /*
  * SCOM access functions for 970 (FX only for now)
diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c
index 8339fd6..07a89a3 100644
--- a/arch/powerpc/kernel/module_32.c
+++ b/arch/powerpc/kernel/module_32.c
@@ -224,7 +224,12 @@
 			/* Low half of the symbol */
 			*(uint16_t *)location = value;
 			break;
-		
+
+		case R_PPC_ADDR16_HI:
+			/* Higher half of the symbol */
+			*(uint16_t *)location = (value >> 16);
+			break;
+
 		case R_PPC_ADDR16_HA:
 			/* Sign-adjusted lower 16 bits: PPC ELF ABI says:
 			   (((x >> 16) + ((x & 0x8000) ? 1 : 0))) & 0xFFFF.
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index c54f363..d8ef2e1 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -1450,7 +1450,6 @@
 		return -1;
 	}
 	pci_dev->irq = virq;
-	pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, virq);
 
 	return 0;
 }
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 01f18c6..7e97d71 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -381,8 +381,6 @@
 
 	pci_device_add(dev, bus);
 
-	/* XXX pci_scan_msi_device(dev); */
-
 	return dev;
 }
 EXPORT_SYMBOL(of_create_pci_dev);
@@ -1325,7 +1323,6 @@
 	DBG(" -> mapped to linux irq %d\n", virq);
 
 	pci_dev->irq = virq;
-	pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, virq);
 
 	return 0;
 }
diff --git a/arch/powerpc/kernel/pmc.c b/arch/powerpc/kernel/pmc.c
index 3d8f6f4..24d7b7c 100644
--- a/arch/powerpc/kernel/pmc.c
+++ b/arch/powerpc/kernel/pmc.c
@@ -17,40 +17,25 @@
 #include <linux/module.h>
 
 #include <asm/processor.h>
+#include <asm/cputable.h>
 #include <asm/pmc.h>
 
+#ifndef MMCR0_PMA0
+#define MMCR0_PMA0	0
+#endif
+
+static void dummy_perf(struct pt_regs *regs)
+{
 #if defined(CONFIG_FSL_BOOKE) && !defined(CONFIG_E200)
-static void dummy_perf(struct pt_regs *regs)
-{
-	unsigned int pmgc0 = mfpmr(PMRN_PMGC0);
-
-	pmgc0 &= ~PMGC0_PMIE;
-	mtpmr(PMRN_PMGC0, pmgc0);
-}
+	mtpmr(PMRN_PMGC0, mfpmr(PMRN_PMGC0) & ~PMGC0_PMIE);
 #elif defined(CONFIG_PPC64) || defined(CONFIG_6xx)
-
-#ifndef MMCR0_PMAO
-#define MMCR0_PMAO	0
-#endif
-
-/* Ensure exceptions are disabled */
-static void dummy_perf(struct pt_regs *regs)
-{
-	unsigned int mmcr0 = mfspr(SPRN_MMCR0);
-
-	mmcr0 &= ~(MMCR0_PMXE|MMCR0_PMAO);
-	mtspr(SPRN_MMCR0, mmcr0);
-}
+	if (cur_cpu_spec->pmc_type == PPC_PMC_IBM)
+		mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~(MMCR0_PMXE|MMCR0_PMA0));
 #else
-/* Ensure exceptions are disabled */
-static void dummy_perf(struct pt_regs *regs)
-{
-	unsigned int mmcr0 = mfspr(SPRN_MMCR0);
-
-	mmcr0 &= ~(MMCR0_PMXE);
-	mtspr(SPRN_MMCR0, mmcr0);
-}
+	mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_PMXE);
 #endif
+}
+
 
 static DEFINE_SPINLOCK(pmc_owner_lock);
 static void *pmc_owner_caller; /* mostly for debugging */
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 95776b6..ecee596 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -44,6 +44,7 @@
 #include <asm/btext.h>
 #include <asm/div64.h>
 #include <asm/signal.h>
+#include <asm/dcr.h>
 
 #ifdef  CONFIG_8xx
 #include <asm/commproc.h>
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 1fc732a..3be52d6 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -1221,8 +1221,7 @@
 		if (np->name != NULL && strcasecmp(np->name, name) == 0
 		    && of_node_get(np))
 			break;
-	if (from)
-		of_node_put(from);
+	of_node_put(from);
 	read_unlock(&devtree_lock);
 	return np;
 }
@@ -1250,8 +1249,7 @@
 		if (np->type != 0 && strcasecmp(np->type, type) == 0
 		    && of_node_get(np))
 			break;
-	if (from)
-		of_node_put(from);
+	of_node_put(from);
 	read_unlock(&devtree_lock);
 	return np;
 }
@@ -1285,8 +1283,7 @@
 		if (device_is_compatible(np, compatible) && of_node_get(np))
 			break;
 	}
-	if (from)
-		of_node_put(from);
+	of_node_put(from);
 	read_unlock(&devtree_lock);
 	return np;
 }
@@ -1329,8 +1326,7 @@
 	for (np = allnodes; np != 0; np = np->allnext)
 		if (np->linux_phandle == handle)
 			break;
-	if (np)
-		of_node_get(np);
+	of_node_get(np);
 	read_unlock(&devtree_lock);
 	return np;
 }
@@ -1353,8 +1349,7 @@
 	for (; np != 0; np = np->allnext)
 		if (of_node_get(np))
 			break;
-	if (prev)
-		of_node_put(prev);
+	of_node_put(prev);
 	read_unlock(&devtree_lock);
 	return np;
 }
@@ -1399,8 +1394,7 @@
 	for (; next != 0; next = next->sibling)
 		if (of_node_get(next))
 			break;
-	if (prev)
-		of_node_put(prev);
+	of_node_put(prev);
 	read_unlock(&devtree_lock);
 	return next;
 }
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 975102a..cc44c7b 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -532,16 +532,22 @@
 	    && (current->ptrace & PT_PTRACED))
 		do_syscall_trace();
 
-	if (unlikely(current->audit_context))
-		audit_syscall_entry(
-#ifdef CONFIG_PPC32
-				    AUDIT_ARCH_PPC,
-#else
-				    test_thread_flag(TIF_32BIT)?AUDIT_ARCH_PPC:AUDIT_ARCH_PPC64,
+	if (unlikely(current->audit_context)) {
+#ifdef CONFIG_PPC64
+		if (!test_thread_flag(TIF_32BIT))
+			audit_syscall_entry(AUDIT_ARCH_PPC64,
+					    regs->gpr[0],
+					    regs->gpr[3], regs->gpr[4],
+					    regs->gpr[5], regs->gpr[6]);
+		else
 #endif
-				    regs->gpr[0],
-				    regs->gpr[3], regs->gpr[4],
-				    regs->gpr[5], regs->gpr[6]);
+			audit_syscall_entry(AUDIT_ARCH_PPC,
+					    regs->gpr[0],
+					    regs->gpr[3] & 0xffffffff,
+					    regs->gpr[4] & 0xffffffff,
+					    regs->gpr[5] & 0xffffffff,
+					    regs->gpr[6] & 0xffffffff);
+	}
 }
 
 void do_syscall_trace_leave(struct pt_regs *regs)
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 61c65d1..6a19fa4 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -65,6 +65,7 @@
 
 #ifdef CONFIG_VGA_CONSOLE
 unsigned long vgacon_remap_base;
+EXPORT_SYMBOL(vgacon_remap_base);
 #endif
 
 /*
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index 400ab2b..d57818a 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -169,6 +169,11 @@
 	return count; \
 }
 
+
+/* Let's define all possible registers, we'll only hook up the ones
+ * that are implemented on the current processor
+ */
+
 SYSFS_PMCSETUP(mmcr0, SPRN_MMCR0);
 SYSFS_PMCSETUP(mmcr1, SPRN_MMCR1);
 SYSFS_PMCSETUP(mmcra, SPRN_MMCRA);
@@ -184,55 +189,87 @@
 SYSFS_PMCSETUP(spurr, SPRN_SPURR);
 SYSFS_PMCSETUP(dscr, SPRN_DSCR);
 
-static SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0);
-static SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1);
+SYSFS_PMCSETUP(pa6t_pmc0, PA6T_SPRN_PMC0);
+SYSFS_PMCSETUP(pa6t_pmc1, PA6T_SPRN_PMC1);
+SYSFS_PMCSETUP(pa6t_pmc2, PA6T_SPRN_PMC2);
+SYSFS_PMCSETUP(pa6t_pmc3, PA6T_SPRN_PMC3);
+SYSFS_PMCSETUP(pa6t_pmc4, PA6T_SPRN_PMC4);
+SYSFS_PMCSETUP(pa6t_pmc5, PA6T_SPRN_PMC5);
+
+
 static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
-static SYSDEV_ATTR(pmc1, 0600, show_pmc1, store_pmc1);
-static SYSDEV_ATTR(pmc2, 0600, show_pmc2, store_pmc2);
-static SYSDEV_ATTR(pmc3, 0600, show_pmc3, store_pmc3);
-static SYSDEV_ATTR(pmc4, 0600, show_pmc4, store_pmc4);
-static SYSDEV_ATTR(pmc5, 0600, show_pmc5, store_pmc5);
-static SYSDEV_ATTR(pmc6, 0600, show_pmc6, store_pmc6);
-static SYSDEV_ATTR(pmc7, 0600, show_pmc7, store_pmc7);
-static SYSDEV_ATTR(pmc8, 0600, show_pmc8, store_pmc8);
-static SYSDEV_ATTR(purr, 0600, show_purr, NULL);
 static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL);
 static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr);
+static SYSDEV_ATTR(purr, 0600, show_purr, store_purr);
+
+static struct sysdev_attribute ibm_common_attrs[] = {
+	_SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0),
+	_SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1),
+};
+
+static struct sysdev_attribute ibm_pmc_attrs[] = {
+	_SYSDEV_ATTR(pmc1, 0600, show_pmc1, store_pmc1),
+	_SYSDEV_ATTR(pmc2, 0600, show_pmc2, store_pmc2),
+	_SYSDEV_ATTR(pmc3, 0600, show_pmc3, store_pmc3),
+	_SYSDEV_ATTR(pmc4, 0600, show_pmc4, store_pmc4),
+	_SYSDEV_ATTR(pmc5, 0600, show_pmc5, store_pmc5),
+	_SYSDEV_ATTR(pmc6, 0600, show_pmc6, store_pmc6),
+	_SYSDEV_ATTR(pmc7, 0600, show_pmc7, store_pmc7),
+	_SYSDEV_ATTR(pmc8, 0600, show_pmc8, store_pmc8),
+};
+
+static struct sysdev_attribute pa6t_attrs[] = {
+	_SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0),
+	_SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1),
+	_SYSDEV_ATTR(pmc0, 0600, show_pa6t_pmc0, store_pa6t_pmc0),
+	_SYSDEV_ATTR(pmc1, 0600, show_pa6t_pmc1, store_pa6t_pmc1),
+	_SYSDEV_ATTR(pmc2, 0600, show_pa6t_pmc2, store_pa6t_pmc2),
+	_SYSDEV_ATTR(pmc3, 0600, show_pa6t_pmc3, store_pa6t_pmc3),
+	_SYSDEV_ATTR(pmc4, 0600, show_pa6t_pmc4, store_pa6t_pmc4),
+	_SYSDEV_ATTR(pmc5, 0600, show_pa6t_pmc5, store_pa6t_pmc5),
+};
+
 
 static void register_cpu_online(unsigned int cpu)
 {
 	struct cpu *c = &per_cpu(cpu_devices, cpu);
 	struct sys_device *s = &c->sysdev;
+	struct sysdev_attribute *attrs, *pmc_attrs;
+	int i, nattrs;
 
 	if (!firmware_has_feature(FW_FEATURE_ISERIES) &&
 			cpu_has_feature(CPU_FTR_SMT))
 		sysdev_create_file(s, &attr_smt_snooze_delay);
 
 	/* PMC stuff */
+	switch (cur_cpu_spec->pmc_type) {
+	case PPC_PMC_IBM:
+		attrs = ibm_common_attrs;
+		nattrs = sizeof(ibm_common_attrs) / sizeof(struct sysdev_attribute);
+		pmc_attrs = ibm_pmc_attrs;
+		break;
+	case PPC_PMC_PA6T:
+		/* PA Semi starts counting at PMC0 */
+		attrs = pa6t_attrs;
+		nattrs = sizeof(pa6t_attrs) / sizeof(struct sysdev_attribute);
+		pmc_attrs = NULL;
+		break;
+	default:
+		attrs = NULL;
+		nattrs = 0;
+		pmc_attrs = NULL;
+	}
 
-	sysdev_create_file(s, &attr_mmcr0);
-	sysdev_create_file(s, &attr_mmcr1);
+	for (i = 0; i < nattrs; i++)
+		sysdev_create_file(s, &attrs[i]);
+
+	if (pmc_attrs)
+		for (i = 0; i < cur_cpu_spec->num_pmcs; i++)
+			sysdev_create_file(s, &pmc_attrs[i]);
 
 	if (cpu_has_feature(CPU_FTR_MMCRA))
 		sysdev_create_file(s, &attr_mmcra);
 
-	if (cur_cpu_spec->num_pmcs >= 1)
-		sysdev_create_file(s, &attr_pmc1);
-	if (cur_cpu_spec->num_pmcs >= 2)
-		sysdev_create_file(s, &attr_pmc2);
-	if (cur_cpu_spec->num_pmcs >= 3)
-		sysdev_create_file(s, &attr_pmc3);
-	if (cur_cpu_spec->num_pmcs >= 4)
-		sysdev_create_file(s, &attr_pmc4);
-	if (cur_cpu_spec->num_pmcs >= 5)
-		sysdev_create_file(s, &attr_pmc5);
-	if (cur_cpu_spec->num_pmcs >= 6)
-		sysdev_create_file(s, &attr_pmc6);
-	if (cur_cpu_spec->num_pmcs >= 7)
-		sysdev_create_file(s, &attr_pmc7);
-	if (cur_cpu_spec->num_pmcs >= 8)
-		sysdev_create_file(s, &attr_pmc8);
-
 	if (cpu_has_feature(CPU_FTR_PURR))
 		sysdev_create_file(s, &attr_purr);
 
@@ -248,6 +285,8 @@
 {
 	struct cpu *c = &per_cpu(cpu_devices, cpu);
 	struct sys_device *s = &c->sysdev;
+	struct sysdev_attribute *attrs, *pmc_attrs;
+	int i, nattrs;
 
 	BUG_ON(!c->hotpluggable);
 
@@ -256,30 +295,34 @@
 		sysdev_remove_file(s, &attr_smt_snooze_delay);
 
 	/* PMC stuff */
+	switch (cur_cpu_spec->pmc_type) {
+	case PPC_PMC_IBM:
+		attrs = ibm_common_attrs;
+		nattrs = sizeof(ibm_common_attrs) / sizeof(struct sysdev_attribute);
+		pmc_attrs = ibm_pmc_attrs;
+		break;
+	case PPC_PMC_PA6T:
+		/* PA Semi starts counting at PMC0 */
+		attrs = pa6t_attrs;
+		nattrs = sizeof(pa6t_attrs) / sizeof(struct sysdev_attribute);
+		pmc_attrs = NULL;
+		break;
+	default:
+		attrs = NULL;
+		nattrs = 0;
+		pmc_attrs = NULL;
+	}
 
-	sysdev_remove_file(s, &attr_mmcr0);
-	sysdev_remove_file(s, &attr_mmcr1);
+	for (i = 0; i < nattrs; i++)
+		sysdev_remove_file(s, &attrs[i]);
+
+	if (pmc_attrs)
+		for (i = 0; i < cur_cpu_spec->num_pmcs; i++)
+			sysdev_remove_file(s, &pmc_attrs[i]);
 
 	if (cpu_has_feature(CPU_FTR_MMCRA))
 		sysdev_remove_file(s, &attr_mmcra);
 
-	if (cur_cpu_spec->num_pmcs >= 1)
-		sysdev_remove_file(s, &attr_pmc1);
-	if (cur_cpu_spec->num_pmcs >= 2)
-		sysdev_remove_file(s, &attr_pmc2);
-	if (cur_cpu_spec->num_pmcs >= 3)
-		sysdev_remove_file(s, &attr_pmc3);
-	if (cur_cpu_spec->num_pmcs >= 4)
-		sysdev_remove_file(s, &attr_pmc4);
-	if (cur_cpu_spec->num_pmcs >= 5)
-		sysdev_remove_file(s, &attr_pmc5);
-	if (cur_cpu_spec->num_pmcs >= 6)
-		sysdev_remove_file(s, &attr_pmc6);
-	if (cur_cpu_spec->num_pmcs >= 7)
-		sysdev_remove_file(s, &attr_pmc7);
-	if (cur_cpu_spec->num_pmcs >= 8)
-		sysdev_remove_file(s, &attr_pmc8);
-
 	if (cpu_has_feature(CPU_FTR_PURR))
 		sysdev_remove_file(s, &attr_purr);
 
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 535f506..dcc6f15 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -174,7 +174,7 @@
 	 * generate the same exception over and over again and we get
 	 * nowhere.  Better to kill it and let the kernel panic.
 	 */
-	if (current->pid == 1) {
+	if (is_init(current)) {
 		__sighandler_t handler;
 
 		spin_lock_irq(&current->sighand->siglock);
@@ -535,34 +535,40 @@
 	}
 }
 
-static void parse_fpe(struct pt_regs *regs)
+static inline int __parse_fpscr(unsigned long fpscr)
 {
-	int code = 0;
-	unsigned long fpscr;
-
-	flush_fp_to_thread(current);
-
-	fpscr = current->thread.fpscr.val;
+	int ret = 0;
 
 	/* Invalid operation */
 	if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX))
-		code = FPE_FLTINV;
+		ret = FPE_FLTINV;
 
 	/* Overflow */
 	else if ((fpscr & FPSCR_OE) && (fpscr & FPSCR_OX))
-		code = FPE_FLTOVF;
+		ret = FPE_FLTOVF;
 
 	/* Underflow */
 	else if ((fpscr & FPSCR_UE) && (fpscr & FPSCR_UX))
-		code = FPE_FLTUND;
+		ret = FPE_FLTUND;
 
 	/* Divide by zero */
 	else if ((fpscr & FPSCR_ZE) && (fpscr & FPSCR_ZX))
-		code = FPE_FLTDIV;
+		ret = FPE_FLTDIV;
 
 	/* Inexact result */
 	else if ((fpscr & FPSCR_XE) && (fpscr & FPSCR_XX))
-		code = FPE_FLTRES;
+		ret = FPE_FLTRES;
+
+	return ret;
+}
+
+static void parse_fpe(struct pt_regs *regs)
+{
+	int code = 0;
+
+	flush_fp_to_thread(current);
+
+	code = __parse_fpscr(current->thread.fpscr.val);
 
 	_exception(SIGFPE, regs, code, regs->nip);
 }
@@ -739,20 +745,7 @@
 	extern int do_mathemu(struct pt_regs *regs);
 
 	/* We can now get here via a FP Unavailable exception if the core
-	 * has no FPU, in that case no reason flags will be set */
-#ifdef CONFIG_MATH_EMULATION
-	/* (reason & REASON_ILLEGAL) would be the obvious thing here,
-	 * but there seems to be a hardware bug on the 405GP (RevD)
-	 * that means ESR is sometimes set incorrectly - either to
-	 * ESR_DST (!?) or 0.  In the process of chasing this with the
-	 * hardware people - not sure if it can happen on any illegal
-	 * instruction or only on FP instructions, whether there is a
-	 * pattern to occurences etc. -dgibson 31/Mar/2003 */
-	if (!(reason & REASON_TRAP) && do_mathemu(regs) == 0) {
-		emulate_single_step(regs);
-		return;
-	}
-#endif /* CONFIG_MATH_EMULATION */
+	 * has no FPU, in that case the reason flags will be 0 */
 
 	if (reason & REASON_FP) {
 		/* IEEE FP exception */
@@ -778,6 +771,31 @@
 
 	local_irq_enable();
 
+#ifdef CONFIG_MATH_EMULATION
+	/* (reason & REASON_ILLEGAL) would be the obvious thing here,
+	 * but there seems to be a hardware bug on the 405GP (RevD)
+	 * that means ESR is sometimes set incorrectly - either to
+	 * ESR_DST (!?) or 0.  In the process of chasing this with the
+	 * hardware people - not sure if it can happen on any illegal
+	 * instruction or only on FP instructions, whether there is a
+	 * pattern to occurences etc. -dgibson 31/Mar/2003 */
+	switch (do_mathemu(regs)) {
+	case 0:
+		emulate_single_step(regs);
+		return;
+	case 1: {
+			int code = 0;
+			code = __parse_fpscr(current->thread.fpscr.val);
+			_exception(SIGFPE, regs, code, regs->nip);
+			return;
+		}
+	case -EFAULT:
+		_exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip);
+		return;
+	}
+	/* fall through on any other errors */
+#endif /* CONFIG_MATH_EMULATION */
+
 	/* Try to emulate it if we should. */
 	if (reason & (REASON_ILLEGAL | REASON_PRIVILEGED)) {
 		switch (emulate_instruction(regs)) {
@@ -891,18 +909,39 @@
 
 #ifdef CONFIG_MATH_EMULATION
 	errcode = do_mathemu(regs);
+
+	switch (errcode) {
+	case 0:
+		emulate_single_step(regs);
+		return;
+	case 1: {
+			int code = 0;
+			code = __parse_fpscr(current->thread.fpscr.val);
+			_exception(SIGFPE, regs, code, regs->nip);
+			return;
+		}
+	case -EFAULT:
+		_exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip);
+		return;
+	default:
+		_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
+		return;
+	}
+
 #else
 	errcode = Soft_emulate_8xx(regs);
-#endif
-	if (errcode) {
-		if (errcode > 0)
-			_exception(SIGFPE, regs, 0, 0);
-		else if (errcode == -EFAULT)
-			_exception(SIGSEGV, regs, 0, 0);
-		else
-			_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
-	} else
+	switch (errcode) {
+	case 0:
 		emulate_single_step(regs);
+		return;
+	case 1:
+		_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
+		return;
+	case -EFAULT:
+		_exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip);
+		return;
+	}
+#endif
 }
 #endif /* CONFIG_8xx */
 
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c
index 5730906..8f5afdb 100644
--- a/arch/powerpc/kernel/udbg.c
+++ b/arch/powerpc/kernel/udbg.c
@@ -45,6 +45,10 @@
 #elif defined(CONFIG_PPC_EARLY_DEBUG_ISERIES)
 	/* For iSeries - hit Ctrl-x Ctrl-x to see the output */
 	udbg_init_iseries();
+#elif defined(CONFIG_PPC_EARLY_DEBUG_BEAT)
+	udbg_init_debug_beat();
+#elif defined(CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE)
+	udbg_init_pas_realmode();
 #endif
 }
 
diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c
index 2d17f2b..e738f93 100644
--- a/arch/powerpc/kernel/udbg_16550.c
+++ b/arch/powerpc/kernel/udbg_16550.c
@@ -14,6 +14,8 @@
 
 extern u8 real_readb(volatile u8 __iomem  *addr);
 extern void real_writeb(u8 data, volatile u8 __iomem *addr);
+extern u8 real_205_readb(volatile u8 __iomem  *addr);
+extern void real_205_writeb(u8 data, volatile u8 __iomem *addr);
 
 struct NS16550 {
 	/* this struct must be packed */
@@ -167,3 +169,25 @@
 	udbg_getc_poll = NULL;
 }
 #endif /* CONFIG_PPC_MAPLE */
+
+#ifdef CONFIG_PPC_PASEMI
+void udbg_pas_real_putc(char c)
+{
+	if (udbg_comport) {
+		while ((real_205_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
+			/* wait for idle */;
+		real_205_writeb(c, &udbg_comport->thr); eieio();
+		if (c == '\n')
+			udbg_pas_real_putc('\r');
+	}
+}
+
+void udbg_init_pas_realmode(void)
+{
+	udbg_comport = (volatile struct NS16550 __iomem *)0xfcff03f8;
+
+	udbg_putc = udbg_pas_real_putc;
+	udbg_getc = NULL;
+	udbg_getc_poll = NULL;
+}
+#endif /* CONFIG_PPC_MAPLE */
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index ae0ede1..50149ec 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -49,9 +49,13 @@
 /* Max supported size for symbol names */
 #define MAX_SYMNAME	64
 
+#define VDSO32_MAXPAGES	(((0x3000 + PAGE_MASK) >> PAGE_SHIFT) + 2)
+#define VDSO64_MAXPAGES	(((0x3000 + PAGE_MASK) >> PAGE_SHIFT) + 2)
+
 extern char vdso32_start, vdso32_end;
 static void *vdso32_kbase = &vdso32_start;
 unsigned int vdso32_pages;
+static struct page *vdso32_pagelist[VDSO32_MAXPAGES];
 unsigned long vdso32_sigtramp;
 unsigned long vdso32_rt_sigtramp;
 
@@ -59,6 +63,7 @@
 extern char vdso64_start, vdso64_end;
 static void *vdso64_kbase = &vdso64_start;
 unsigned int vdso64_pages;
+static struct page *vdso64_pagelist[VDSO64_MAXPAGES];
 unsigned long vdso64_rt_sigtramp;
 #endif /* CONFIG_PPC64 */
 
@@ -165,55 +170,6 @@
 #endif /* DEBUG */
 
 /*
- * Keep a dummy vma_close for now, it will prevent VMA merging.
- */
-static void vdso_vma_close(struct vm_area_struct * vma)
-{
-}
-
-/*
- * Our nopage() function, maps in the actual vDSO kernel pages, they will
- * be mapped read-only by do_no_page(), and eventually COW'ed, either
- * right away for an initial write access, or by do_wp_page().
- */
-static struct page * vdso_vma_nopage(struct vm_area_struct * vma,
-				     unsigned long address, int *type)
-{
-	unsigned long offset = address - vma->vm_start;
-	struct page *pg;
-#ifdef CONFIG_PPC64
-	void *vbase = (vma->vm_mm->task_size > TASK_SIZE_USER32) ?
-		vdso64_kbase : vdso32_kbase;
-#else
-	void *vbase = vdso32_kbase;
-#endif
-
-	DBG("vdso_vma_nopage(current: %s, address: %016lx, off: %lx)\n",
-	    current->comm, address, offset);
-
-	if (address < vma->vm_start || address > vma->vm_end)
-		return NOPAGE_SIGBUS;
-
-	/*
-	 * Last page is systemcfg.
-	 */
-	if ((vma->vm_end - address) <= PAGE_SIZE)
-		pg = virt_to_page(vdso_data);
-	else
-		pg = virt_to_page(vbase + offset);
-
-	get_page(pg);
-	DBG(" ->page count: %d\n", page_count(pg));
-
-	return pg;
-}
-
-static struct vm_operations_struct vdso_vmops = {
-	.close	= vdso_vma_close,
-	.nopage	= vdso_vma_nopage,
-};
-
-/*
  * This is called from binfmt_elf, we create the special vma for the
  * vDSO and insert it into the mm struct tree
  */
@@ -221,20 +177,23 @@
 				int executable_stack)
 {
 	struct mm_struct *mm = current->mm;
-	struct vm_area_struct *vma;
+	struct page **vdso_pagelist;
 	unsigned long vdso_pages;
 	unsigned long vdso_base;
 	int rc;
 
 #ifdef CONFIG_PPC64
 	if (test_thread_flag(TIF_32BIT)) {
+		vdso_pagelist = vdso32_pagelist;
 		vdso_pages = vdso32_pages;
 		vdso_base = VDSO32_MBASE;
 	} else {
+		vdso_pagelist = vdso64_pagelist;
 		vdso_pages = vdso64_pages;
 		vdso_base = VDSO64_MBASE;
 	}
 #else
+	vdso_pagelist = vdso32_pagelist;
 	vdso_pages = vdso32_pages;
 	vdso_base = VDSO32_MBASE;
 #endif
@@ -262,17 +221,6 @@
 		goto fail_mmapsem;
 	}
 
-
-	/* Allocate a VMA structure and fill it up */
-	vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
-	if (vma == NULL) {
-		rc = -ENOMEM;
-		goto fail_mmapsem;
-	}
-	vma->vm_mm = mm;
-	vma->vm_start = vdso_base;
-	vma->vm_end = vma->vm_start + (vdso_pages << PAGE_SHIFT);
-
 	/*
 	 * our vma flags don't have VM_WRITE so by default, the process isn't
 	 * allowed to write those pages.
@@ -282,32 +230,26 @@
 	 * and your nice userland gettimeofday will be totally dead.
 	 * It's fine to use that for setting breakpoints in the vDSO code
 	 * pages though
-	 */
-	vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC;
-	/*
+	 *
 	 * Make sure the vDSO gets into every core dump.
 	 * Dumping its contents makes post-mortem fully interpretable later
 	 * without matching up the same kernel and hardware config to see
 	 * what PC values meant.
 	 */
-	vma->vm_flags |= VM_ALWAYSDUMP;
-	vma->vm_flags |= mm->def_flags;
-	vma->vm_page_prot = protection_map[vma->vm_flags & 0x7];
-	vma->vm_ops = &vdso_vmops;
-
-	/* Insert new VMA */
-	rc = insert_vm_struct(mm, vma);
+	rc = install_special_mapping(mm, vdso_base, vdso_pages << PAGE_SHIFT,
+				     VM_READ|VM_EXEC|
+				     VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
+				     VM_ALWAYSDUMP,
+				     vdso_pagelist);
 	if (rc)
-		goto fail_vma;
+		goto fail_mmapsem;
 
-	/* Put vDSO base into mm struct and account for memory usage */
+	/* Put vDSO base into mm struct */
 	current->mm->context.vdso_base = vdso_base;
-	mm->total_vm += (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+
 	up_write(&mm->mmap_sem);
 	return 0;
 
- fail_vma:
-	kmem_cache_free(vm_area_cachep, vma);
  fail_mmapsem:
 	up_write(&mm->mmap_sem);
 	return rc;
@@ -778,18 +720,26 @@
 	}
 
 	/* Make sure pages are in the correct state */
+	BUG_ON(vdso32_pages + 2 > VDSO32_MAXPAGES);
 	for (i = 0; i < vdso32_pages; i++) {
 		struct page *pg = virt_to_page(vdso32_kbase + i*PAGE_SIZE);
 		ClearPageReserved(pg);
 		get_page(pg);
-
+		vdso32_pagelist[i] = pg;
 	}
+	vdso32_pagelist[i++] = virt_to_page(vdso_data);
+	vdso32_pagelist[i] = NULL;
+
 #ifdef CONFIG_PPC64
+	BUG_ON(vdso64_pages + 2 > VDSO64_MAXPAGES);
 	for (i = 0; i < vdso64_pages; i++) {
 		struct page *pg = virt_to_page(vdso64_kbase + i*PAGE_SIZE);
 		ClearPageReserved(pg);
 		get_page(pg);
+		vdso64_pagelist[i] = pg;
 	}
+	vdso64_pagelist[i++] = virt_to_page(vdso_data);
+	vdso64_pagelist[i] = NULL;
 #endif /* CONFIG_PPC64 */
 
 	get_page(virt_to_page(vdso_data));
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index a80f8f1..2968ffe 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -199,10 +199,8 @@
 /* vio_dev refcount hit 0 */
 static void __devinit vio_dev_release(struct device *dev)
 {
-	if (dev->archdata.of_node) {
-		/* XXX should free TCE table */
-		of_node_put(dev->archdata.of_node);
-	}
+	/* XXX should free TCE table */
+	of_node_put(dev->archdata.of_node);
 	kfree(to_vio_dev(dev));
 }
 
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index a0360ae..4b1ba49 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -16,13 +16,15 @@
 			   strcase.o
 obj-$(CONFIG_QUICC_ENGINE) += rheap.o
 obj-$(CONFIG_XMON)	+= sstep.o
+obj-$(CONFIG_KPROBES)	+= sstep.o
+obj-$(CONFIG_NOT_COHERENT_CACHE)	+= dma-noncoherent.o
 
 ifeq ($(CONFIG_PPC64),y)
 obj-$(CONFIG_SMP)	+= locks.o
-obj-$(CONFIG_DEBUG_KERNEL) += sstep.o
 endif
 
 # Temporary hack until we have migrated to asm-powerpc
 ifeq ($(CONFIG_PPC_MERGE),y)
+obj-$(CONFIG_8xx)	+= rheap.o
 obj-$(CONFIG_CPM2)	+= rheap.o
 endif
diff --git a/arch/ppc/kernel/dma-mapping.c b/arch/powerpc/lib/dma-noncoherent.c
similarity index 93%
rename from arch/ppc/kernel/dma-mapping.c
rename to arch/powerpc/lib/dma-noncoherent.c
index 10fec73..48f3d13 100644
--- a/arch/ppc/kernel/dma-mapping.c
+++ b/arch/powerpc/lib/dma-noncoherent.c
@@ -22,37 +22,13 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/module.h>
-#include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/stddef.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/bootmem.h>
 #include <linux/highmem.h>
 #include <linux/dma-mapping.h>
-#include <linux/hardirq.h>
-
-#include <asm/pgalloc.h>
-#include <asm/prom.h>
-#include <asm/io.h>
-#include <asm/mmu_context.h>
-#include <asm/pgtable.h>
-#include <asm/mmu.h>
-#include <asm/uaccess.h>
-#include <asm/smp.h>
-#include <asm/machdep.h>
-
-int map_page(unsigned long va, phys_addr_t pa, int flags);
 
 #include <asm/tlbflush.h>
 
diff --git a/arch/powerpc/lib/rheap.c b/arch/powerpc/lib/rheap.c
index 57bf991..6c5c5dd 100644
--- a/arch/powerpc/lib/rheap.c
+++ b/arch/powerpc/lib/rheap.c
@@ -14,6 +14,7 @@
  */
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 
@@ -85,7 +86,8 @@
 	info->flags &= ~RHIF_STATIC_BLOCK;
 
 	/* add all new blocks to the free list */
-	for (i = 0, blk = block + info->max_blocks; i < new_blocks; i++, blk++)
+	blk = block + info->max_blocks - new_blocks;
+	for (i = 0; i < new_blocks; i++, blk++)
 		list_add(&blk->list, &info->empty_list);
 
 	return 0;
@@ -670,7 +672,7 @@
 	int maxnr;
 	int i, nr;
 
-	maxnr = sizeof(st) / sizeof(st[0]);
+	maxnr = ARRAY_SIZE(st);
 
 	printk(KERN_INFO
 	       "info @0x%p (%d slots empty / %d max)\n",
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 1bb20d8..8c77c79 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -1014,7 +1014,6 @@
 
 		/* Primary is full, try the secondary */
 		if (unlikely(slot == -1)) {
-			new_pte |= _PAGE_F_SECOND;
 			hpte_group = ((~hash & htab_hash_mask) *
 				      HPTES_PER_GROUP) & ~0x7UL; 
 			slot = ppc_md.hpte_insert(hpte_group, va, pa, rflags,
@@ -1033,7 +1032,7 @@
 		if (unlikely(slot == -2))
 			panic("hash_huge_page: pte_insert failed\n");
 
-		new_pte |= (slot << 12) & _PAGE_F_GIX;
+		new_pte |= (slot << 12) & (_PAGE_F_SECOND | _PAGE_F_GIX);
 	}
 
 	/*
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index d1c0758..77b4637 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -61,10 +61,6 @@
 extern void hash_preload(struct mm_struct *mm, unsigned long ea,
 			 unsigned long access, unsigned long trap);
 
-/*
- * This is called by /dev/mem to know if a given address has to
- * be mapped non-cacheable or not
- */
 int page_is_ram(unsigned long pfn)
 {
 	unsigned long paddr = (pfn << PAGE_SHIFT);
@@ -490,19 +486,19 @@
 	    !cpu_has_feature(CPU_FTR_NOEXECUTE) &&
 	    pfn_valid(pfn)) {
 		struct page *page = pfn_to_page(pfn);
+#ifdef CONFIG_8xx
+		/* On 8xx, cache control instructions (particularly
+		 * "dcbst" from flush_dcache_icache) fault as write
+		 * operation if there is an unpopulated TLB entry
+		 * for the address in question. To workaround that,
+		 * we invalidate the TLB here, thus avoiding dcbst
+		 * misbehaviour.
+		 */
+		_tlbie(address);
+#endif
 		if (!PageReserved(page)
 		    && !test_bit(PG_arch_1, &page->flags)) {
 			if (vma->vm_mm == current->active_mm) {
-#ifdef CONFIG_8xx
-			/* On 8xx, cache control instructions (particularly 
-		 	 * "dcbst" from flush_dcache_icache) fault as write 
-			 * operation if there is an unpopulated TLB entry 
-			 * for the address in question. To workaround that, 
-			 * we invalidate the TLB here, thus avoiding dcbst 
-			 * misbehaviour.
-			 */
-				_tlbie(address);
-#endif
 				__flush_dcache_icache((void *) address);
 			} else
 				flush_dcache_icache_page(page);
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 1891dbe..bd02272 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -294,11 +294,8 @@
 	}
 }
 
-/* is x a power of 2? */
-#define is_power_of_2(x)	((x) != 0 && (((x) & ((x) - 1)) == 0))
-
 /* is x a power of 4? */
-#define is_power_of_4(x)	((x) != 0 && (((x) & (x-1)) == 0) && (ffs(x) & 1))
+#define is_power_of_4(x)	is_power_of_2(x) && (ffs(x) & 1))
 
 /*
  * Set up a mapping for a block of I/O.
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
index b6d8239..fbd62ea 100644
--- a/arch/powerpc/oprofile/common.c
+++ b/arch/powerpc/oprofile/common.c
@@ -149,6 +149,8 @@
 #ifdef CONFIG_PPC64
 #ifdef CONFIG_PPC_CELL_NATIVE
 		case PPC_OPROFILE_CELL:
+			if (firmware_has_feature(FW_FEATURE_LPAR))
+				return -ENODEV;
 			model = &op_model_cell;
 			break;
 #endif
diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c
index f481c0e..5d1bbaf 100644
--- a/arch/powerpc/oprofile/op_model_7450.c
+++ b/arch/powerpc/oprofile/op_model_7450.c
@@ -137,9 +137,9 @@
 
 	for (i = 0; i < NUM_CTRS; ++i) {
 		if (ctr[i].enabled)
-			ctr_write(i, reset_value[i]);
+			classic_ctr_write(i, reset_value[i]);
 		else
-			ctr_write(i, 0);
+			classic_ctr_write(i, 0);
 	}
 
 	/* Clear the freeze bit, and enable the interrupt.
@@ -179,13 +179,13 @@
 	is_kernel = is_kernel_addr(pc);
 
 	for (i = 0; i < NUM_CTRS; ++i) {
-		val = ctr_read(i);
+		val = classic_ctr_read(i);
 		if (val < 0) {
 			if (oprofile_running && ctr[i].enabled) {
 				oprofile_add_ext_sample(pc, regs, i, is_kernel);
-				ctr_write(i, reset_value[i]);
+				classic_ctr_write(i, reset_value[i]);
 			} else {
-				ctr_write(i, 0);
+				classic_ctr_write(i, 0);
 			}
 		}
 	}
diff --git a/arch/powerpc/oprofile/op_model_fsl_booke.c b/arch/powerpc/oprofile/op_model_fsl_booke.c
index 0b3c31f..2267eb8 100644
--- a/arch/powerpc/oprofile/op_model_fsl_booke.c
+++ b/arch/powerpc/oprofile/op_model_fsl_booke.c
@@ -32,6 +32,87 @@
 static int num_counters;
 static int oprofile_running;
 
+static inline u32 get_pmlca(int ctr)
+{
+	u32 pmlca;
+
+	switch (ctr) {
+		case 0:
+			pmlca = mfpmr(PMRN_PMLCA0);
+			break;
+		case 1:
+			pmlca = mfpmr(PMRN_PMLCA1);
+			break;
+		case 2:
+			pmlca = mfpmr(PMRN_PMLCA2);
+			break;
+		case 3:
+			pmlca = mfpmr(PMRN_PMLCA3);
+			break;
+		default:
+			panic("Bad ctr number\n");
+	}
+
+	return pmlca;
+}
+
+static inline void set_pmlca(int ctr, u32 pmlca)
+{
+	switch (ctr) {
+		case 0:
+			mtpmr(PMRN_PMLCA0, pmlca);
+			break;
+		case 1:
+			mtpmr(PMRN_PMLCA1, pmlca);
+			break;
+		case 2:
+			mtpmr(PMRN_PMLCA2, pmlca);
+			break;
+		case 3:
+			mtpmr(PMRN_PMLCA3, pmlca);
+			break;
+		default:
+			panic("Bad ctr number\n");
+	}
+}
+
+static inline unsigned int ctr_read(unsigned int i)
+{
+	switch(i) {
+		case 0:
+			return mfpmr(PMRN_PMC0);
+		case 1:
+			return mfpmr(PMRN_PMC1);
+		case 2:
+			return mfpmr(PMRN_PMC2);
+		case 3:
+			return mfpmr(PMRN_PMC3);
+		default:
+			return 0;
+	}
+}
+
+static inline void ctr_write(unsigned int i, unsigned int val)
+{
+	switch(i) {
+		case 0:
+			mtpmr(PMRN_PMC0, val);
+			break;
+		case 1:
+			mtpmr(PMRN_PMC1, val);
+			break;
+		case 2:
+			mtpmr(PMRN_PMC2, val);
+			break;
+		case 3:
+			mtpmr(PMRN_PMC3, val);
+			break;
+		default:
+			break;
+	}
+}
+
+
 static void init_pmc_stop(int ctr)
 {
 	u32 pmlca = (PMLCA_FC | PMLCA_FCS | PMLCA_FCU |
diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c
index 356709d..fe597a1 100644
--- a/arch/powerpc/oprofile/op_model_power4.c
+++ b/arch/powerpc/oprofile/op_model_power4.c
@@ -121,9 +121,9 @@
 
 	for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) {
 		if (ctr[i].enabled) {
-			ctr_write(i, reset_value[i]);
+			classic_ctr_write(i, reset_value[i]);
 		} else {
-			ctr_write(i, 0);
+			classic_ctr_write(i, 0);
 		}
 	}
 
@@ -254,13 +254,13 @@
 	mtmsrd(mfmsr() | MSR_PMM);
 
 	for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) {
-		val = ctr_read(i);
+		val = classic_ctr_read(i);
 		if (val < 0) {
 			if (oprofile_running && ctr[i].enabled) {
 				oprofile_add_ext_sample(pc, regs, i, is_kernel);
-				ctr_write(i, reset_value[i]);
+				classic_ctr_write(i, reset_value[i]);
 			} else {
-				ctr_write(i, 0);
+				classic_ctr_write(i, 0);
 			}
 		}
 	}
diff --git a/arch/powerpc/oprofile/op_model_rs64.c b/arch/powerpc/oprofile/op_model_rs64.c
index 19c5ee0..c731acb 100644
--- a/arch/powerpc/oprofile/op_model_rs64.c
+++ b/arch/powerpc/oprofile/op_model_rs64.c
@@ -137,10 +137,10 @@
 
 	for (i = 0; i < num_counters; ++i) {
 		if (ctr[i].enabled) {
-			ctr_write(i, reset_value[i]);
+			classic_ctr_write(i, reset_value[i]);
 			ctrl_write(i, ctr[i].event);
 		} else {
-			ctr_write(i, 0);
+			classic_ctr_write(i, 0);
 		}
 	}
 
@@ -186,13 +186,13 @@
 	mtmsrd(mfmsr() | MSR_PMM);
 
 	for (i = 0; i < num_counters; ++i) {
-		val = ctr_read(i);
+		val = classic_ctr_read(i);
 		if (val < 0) {
 			if (ctr[i].enabled) {
 				oprofile_add_ext_sample(pc, regs, i, is_kernel);
-				ctr_write(i, reset_value[i]);
+				classic_ctr_write(i, reset_value[i]);
 			} else {
-				ctr_write(i, 0);
+				classic_ctr_write(i, 0);
 			}
 		}
 	}
diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile
index a46184a..795b713 100644
--- a/arch/powerpc/platforms/52xx/Makefile
+++ b/arch/powerpc/platforms/52xx/Makefile
@@ -3,6 +3,7 @@
 #
 ifeq ($(CONFIG_PPC_MERGE),y)
 obj-y				+= mpc52xx_pic.o mpc52xx_common.o
+obj-$(CONFIG_PCI)		+= mpc52xx_pci.o
 endif
 
 obj-$(CONFIG_PPC_EFIKA)		+= efika-setup.o efika-pci.o
diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c
index 0f21bab..cdb16bf 100644
--- a/arch/powerpc/platforms/52xx/lite5200.c
+++ b/arch/powerpc/platforms/52xx/lite5200.c
@@ -107,6 +107,12 @@
 	mpc52xx_setup_cpu();	/* Generic */
 	lite52xx_setup_cpu();	/* Platorm specific */
 
+#ifdef CONFIG_PCI
+	np = of_find_node_by_type(np, "pci");
+	if (np)
+		mpc52xx_add_bridge(np);
+#endif
+
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (initrd_start)
 		ROOT_DEV = Root_RAM0;
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
new file mode 100644
index 0000000..faf161b
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
@@ -0,0 +1,412 @@
+/*
+ * PCI code for the Freescale MPC52xx embedded CPU.
+ *
+ * Copyright (C) 2006 Secret Lab Technologies Ltd.
+ *                        Grant Likely <grant.likely@secretlab.ca>
+ * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#undef DEBUG
+
+#include <asm/pci.h>
+#include <asm/mpc52xx.h>
+#include <asm/delay.h>
+#include <asm/machdep.h>
+#include <linux/kernel.h>
+
+
+/* ======================================================================== */
+/* PCI windows config                                                       */
+/* ======================================================================== */
+
+#define MPC52xx_PCI_TARGET_IO	0xf0000000
+#define MPC52xx_PCI_TARGET_MEM	0x00000000
+
+
+/* ======================================================================== */
+/* Structures mapping & Defines for PCI Unit                                */
+/* ======================================================================== */
+
+#define MPC52xx_PCI_GSCR_BM		0x40000000
+#define MPC52xx_PCI_GSCR_PE		0x20000000
+#define MPC52xx_PCI_GSCR_SE		0x10000000
+#define MPC52xx_PCI_GSCR_XLB2PCI_MASK	0x07000000
+#define MPC52xx_PCI_GSCR_XLB2PCI_SHIFT	24
+#define MPC52xx_PCI_GSCR_IPG2PCI_MASK	0x00070000
+#define MPC52xx_PCI_GSCR_IPG2PCI_SHIFT	16
+#define MPC52xx_PCI_GSCR_BME		0x00004000
+#define MPC52xx_PCI_GSCR_PEE		0x00002000
+#define MPC52xx_PCI_GSCR_SEE		0x00001000
+#define MPC52xx_PCI_GSCR_PR		0x00000001
+
+
+#define MPC52xx_PCI_IWBTAR_TRANSLATION(proc_ad,pci_ad,size)	  \
+		( ( (proc_ad) & 0xff000000 )			| \
+		  ( (((size) - 1) >> 8) & 0x00ff0000 )		| \
+		  ( ((pci_ad) >> 16) & 0x0000ff00 ) )
+
+#define MPC52xx_PCI_IWCR_PACK(win0,win1,win2)	(((win0) << 24) | \
+						 ((win1) << 16) | \
+						 ((win2) <<  8))
+
+#define MPC52xx_PCI_IWCR_DISABLE	0x0
+#define MPC52xx_PCI_IWCR_ENABLE		0x1
+#define MPC52xx_PCI_IWCR_READ		0x0
+#define MPC52xx_PCI_IWCR_READ_LINE	0x2
+#define MPC52xx_PCI_IWCR_READ_MULTI	0x4
+#define MPC52xx_PCI_IWCR_MEM		0x0
+#define MPC52xx_PCI_IWCR_IO		0x8
+
+#define MPC52xx_PCI_TCR_P		0x01000000
+#define MPC52xx_PCI_TCR_LD		0x00010000
+
+#define MPC52xx_PCI_TBATR_DISABLE	0x0
+#define MPC52xx_PCI_TBATR_ENABLE	0x1
+
+struct mpc52xx_pci {
+	u32	idr;		/* PCI + 0x00 */
+	u32	scr;		/* PCI + 0x04 */
+	u32	ccrir;		/* PCI + 0x08 */
+	u32	cr1;		/* PCI + 0x0C */
+	u32	bar0;		/* PCI + 0x10 */
+	u32	bar1;		/* PCI + 0x14 */
+	u8	reserved1[16];	/* PCI + 0x18 */
+	u32	ccpr;		/* PCI + 0x28 */
+	u32	sid;		/* PCI + 0x2C */
+	u32	erbar;		/* PCI + 0x30 */
+	u32	cpr;		/* PCI + 0x34 */
+	u8	reserved2[4];	/* PCI + 0x38 */
+	u32	cr2;		/* PCI + 0x3C */
+	u8	reserved3[32];	/* PCI + 0x40 */
+	u32	gscr;		/* PCI + 0x60 */
+	u32	tbatr0;		/* PCI + 0x64 */
+	u32	tbatr1;		/* PCI + 0x68 */
+	u32	tcr;		/* PCI + 0x6C */
+	u32	iw0btar;	/* PCI + 0x70 */
+	u32	iw1btar;	/* PCI + 0x74 */
+	u32	iw2btar;	/* PCI + 0x78 */
+	u8	reserved4[4];	/* PCI + 0x7C */
+	u32	iwcr;		/* PCI + 0x80 */
+	u32	icr;		/* PCI + 0x84 */
+	u32	isr;		/* PCI + 0x88 */
+	u32	arb;		/* PCI + 0x8C */
+	u8	reserved5[104];	/* PCI + 0x90 */
+	u32	car;		/* PCI + 0xF8 */
+	u8	reserved6[4];	/* PCI + 0xFC */
+};
+
+
+/* ======================================================================== */
+/* PCI configuration acess                                                  */
+/* ======================================================================== */
+
+static int
+mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+				int offset, int len, u32 *val)
+{
+	struct pci_controller *hose = bus->sysdata;
+	u32 value;
+
+	if (ppc_md.pci_exclude_device)
+		if (ppc_md.pci_exclude_device(bus->number, devfn))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+
+	out_be32(hose->cfg_addr,
+		(1 << 31) |
+		((bus->number - hose->bus_offset) << 16) |
+		(devfn << 8) |
+		(offset & 0xfc));
+	mb();
+
+#if defined(CONFIG_PPC_MPC5200_BUGFIX)
+	if (bus->number != hose->bus_offset) {
+		/* workaround for the bug 435 of the MPC5200 (L25R);
+		 * Don't do 32 bits config access during type-1 cycles */
+		switch (len) {
+		      case 1:
+			value = in_8(((u8 __iomem *)hose->cfg_data) +
+			             (offset & 3));
+			break;
+		      case 2:
+			value = in_le16(((u16 __iomem *)hose->cfg_data) +
+			                ((offset>>1) & 1));
+			break;
+
+		      default:
+			value = in_le16((u16 __iomem *)hose->cfg_data) |
+				(in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16);
+			break;
+		}
+	}
+	else
+#endif
+	{
+		value = in_le32(hose->cfg_data);
+
+		if (len != 4) {
+			value >>= ((offset & 0x3) << 3);
+			value &= 0xffffffff >> (32 - (len << 3));
+		}
+	}
+
+	*val = value;
+
+	out_be32(hose->cfg_addr, 0);
+	mb();
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+				int offset, int len, u32 val)
+{
+	struct pci_controller *hose = bus->sysdata;
+	u32 value, mask;
+
+	if (ppc_md.pci_exclude_device)
+		if (ppc_md.pci_exclude_device(bus->number, devfn))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+
+	out_be32(hose->cfg_addr,
+		(1 << 31) |
+		((bus->number - hose->bus_offset) << 16) |
+		(devfn << 8) |
+		(offset & 0xfc));
+	mb();
+
+#if defined(CONFIG_PPC_MPC5200_BUGFIX)
+	if (bus->number != hose->bus_offset) {
+		/* workaround for the bug 435 of the MPC5200 (L25R);
+		 * Don't do 32 bits config access during type-1 cycles */
+		switch (len) {
+		      case 1:
+			out_8(((u8 __iomem *)hose->cfg_data) +
+				(offset & 3), val);
+			break;
+		      case 2:
+			out_le16(((u16 __iomem *)hose->cfg_data) +
+				((offset>>1) & 1), val);
+			break;
+
+		      default:
+			out_le16((u16 __iomem *)hose->cfg_data,
+				(u16)val);
+			out_le16(((u16 __iomem *)hose->cfg_data) + 1,
+				(u16)(val>>16));
+			break;
+		}
+	}
+	else
+#endif
+	{
+		if (len != 4) {
+			value = in_le32(hose->cfg_data);
+
+			offset = (offset & 0x3) << 3;
+			mask = (0xffffffff >> (32 - (len << 3)));
+			mask <<= offset;
+
+			value &= ~mask;
+			val = value | ((val << offset) & mask);
+		}
+
+		out_le32(hose->cfg_data, val);
+	}
+	mb();
+
+	out_be32(hose->cfg_addr, 0);
+	mb();
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops mpc52xx_pci_ops = {
+	.read  = mpc52xx_pci_read_config,
+	.write = mpc52xx_pci_write_config
+};
+
+
+/* ======================================================================== */
+/* PCI setup                                                                */
+/* ======================================================================== */
+
+static void __init
+mpc52xx_pci_setup(struct pci_controller *hose,
+                  struct mpc52xx_pci __iomem *pci_regs)
+{
+	struct resource *res;
+	u32 tmp;
+	int iwcr0 = 0, iwcr1 = 0, iwcr2 = 0;
+
+	pr_debug("mpc52xx_pci_setup(hose=%p, pci_regs=%p)\n", hose, pci_regs);
+
+	/* pci_process_bridge_OF_ranges() found all our addresses for us;
+	 * now store them in the right places */
+	hose->cfg_addr = &pci_regs->car;
+	hose->cfg_data = hose->io_base_virt;
+
+	/* Control regs */
+	tmp = in_be32(&pci_regs->scr);
+	tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+	out_be32(&pci_regs->scr, tmp);
+
+	/* Memory windows */
+	res = &hose->mem_resources[0];
+	if (res->flags) {
+		pr_debug("mem_resource[0] = {.start=%x, .end=%x, .flags=%lx}\n",
+		         res->start, res->end, res->flags);
+		out_be32(&pci_regs->iw0btar,
+		         MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
+		                  res->end - res->start + 1));
+		iwcr0 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM;
+		if (res->flags & IORESOURCE_PREFETCH)
+			iwcr0 |= MPC52xx_PCI_IWCR_READ_MULTI;
+		else
+			iwcr0 |= MPC52xx_PCI_IWCR_READ;
+	}
+
+	res = &hose->mem_resources[1];
+	if (res->flags) {
+		pr_debug("mem_resource[1] = {.start=%x, .end=%x, .flags=%lx}\n",
+		         res->start, res->end, res->flags);
+		out_be32(&pci_regs->iw1btar,
+		         MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
+		                  res->end - res->start + 1));
+		iwcr1 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM;
+		if (res->flags & IORESOURCE_PREFETCH)
+			iwcr1 |= MPC52xx_PCI_IWCR_READ_MULTI;
+		else
+			iwcr1 |= MPC52xx_PCI_IWCR_READ;
+	}
+
+	/* IO resources */
+	res = &hose->io_resource;
+	if (!res) {
+		printk(KERN_ERR "%s: Didn't find IO resources\n", __FILE__);
+		return;
+	}
+	pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} "
+	         ".io_base_phys=0x%p\n",
+	         res->start, res->end, res->flags, (void*)hose->io_base_phys);
+	out_be32(&pci_regs->iw2btar,
+	         MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys,
+	                                        res->start,
+	                                        res->end - res->start + 1));
+	iwcr2 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_IO;
+
+	/* Set all the IWCR fields at once; they're in the same reg */
+	out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2));
+
+	out_be32(&pci_regs->tbatr0,
+		MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO );
+	out_be32(&pci_regs->tbatr1,
+		MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM );
+
+	out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD);
+
+	tmp = in_be32(&pci_regs->gscr);
+#if 0
+	/* Reset the exteral bus ( internal PCI controller is NOT resetted ) */
+	/* Not necessary and can be a bad thing if for example the bootloader
+	   is displaying a splash screen or ... Just left here for
+	   documentation purpose if anyone need it */
+	out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR);
+	udelay(50);
+#endif
+
+	/* Make sure the PCI bridge is out of reset */
+	out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR);
+}
+
+static void
+mpc52xx_pci_fixup_resources(struct pci_dev *dev)
+{
+	int i;
+
+	pr_debug("mpc52xx_pci_fixup_resources() %.4x:%.4x\n",
+	         dev->vendor, dev->device);
+
+	/* We don't rely on boot loader for PCI and resets all
+	   devices */
+	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+		struct resource *res = &dev->resource[i];
+		if (res->end > res->start) {	/* Only valid resources */
+			res->end -= res->start;
+			res->start = 0;
+			res->flags |= IORESOURCE_UNSET;
+		}
+	}
+
+	/* The PCI Host bridge of MPC52xx has a prefetch memory resource
+	   fixed to 1Gb. Doesn't fit in the resource system so we remove it */
+	if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
+	     (   dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200
+	      || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) {
+		struct resource *res = &dev->resource[1];
+		res->start = res->end = res->flags = 0;
+	}
+}
+
+int __init
+mpc52xx_add_bridge(struct device_node *node)
+{
+	int len;
+	struct mpc52xx_pci __iomem *pci_regs;
+	struct pci_controller *hose;
+	const int *bus_range;
+	struct resource rsrc;
+
+	pr_debug("Adding MPC52xx PCI host bridge %s\n", node->full_name);
+
+	pci_assign_all_buses = 1;
+
+	if (of_address_to_resource(node, 0, &rsrc) != 0) {
+		printk(KERN_ERR "Can't get %s resources\n", node->full_name);
+		return -EINVAL;
+	}
+
+	bus_range = get_property(node, "bus-range", &len);
+	if (bus_range == NULL || len < 2 * sizeof(int)) {
+		printk(KERN_WARNING "Can't get %s bus-range, assume bus 0\n",
+		       node->full_name);
+		bus_range = NULL;
+	}
+
+	/* There are some PCI quirks on the 52xx, register the hook to
+	 * fix them. */
+	ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources;
+
+	/* Alloc and initialize the pci controller.  Values in the device
+	 * tree are needed to configure the 52xx PCI controller.  Rather
+	 * than parse the tree here, let pci_process_bridge_OF_ranges()
+	 * do it for us and extract the values after the fact */
+	hose = pcibios_alloc_controller();
+	if (!hose)
+		return -ENOMEM;
+
+	hose->arch_data = node;
+	hose->set_cfg_type = 1;
+
+	hose->first_busno = bus_range ? bus_range[0] : 0;
+	hose->last_busno = bus_range ? bus_range[1] : 0xff;
+
+	hose->bus_offset = 0;
+	hose->ops = &mpc52xx_pci_ops;
+
+	pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
+	if (!pci_regs)
+		return -ENOMEM;
+
+	pci_process_bridge_OF_ranges(hose, node, 1);
+
+	/* Finish setting up PCI using values obtained by
+	 * pci_proces_bridge_OF_ranges */
+	mpc52xx_pci_setup(hose, pci_regs);
+
+	return 0;
+}
diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c
index 0f5b30d..74e7892 100644
--- a/arch/powerpc/platforms/82xx/mpc82xx.c
+++ b/arch/powerpc/platforms/82xx/mpc82xx.c
@@ -50,7 +50,7 @@
 #include <sysdev/fsl_soc.h>
 #include <sysdev/cpm2_pic.h>
 
-#include "pq2ads_pd.h"
+#include "pq2ads.h"
 
 static int __init get_freq(char *name, unsigned long *val)
 {
diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
index ea880f1..7334c1a 100644
--- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c
+++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
@@ -51,7 +51,7 @@
 #include <sysdev/fsl_soc.h>
 #include <../sysdev/cpm2_pic.h>
 
-#include "pq2ads_pd.h"
+#include "pq2ads.h"
 
 #ifdef CONFIG_PCI
 static uint pci_clk_frq;
diff --git a/arch/powerpc/platforms/82xx/pq2ads.h b/arch/powerpc/platforms/82xx/pq2ads.h
index fb2f92b..5b5cca6 100644
--- a/arch/powerpc/platforms/82xx/pq2ads.h
+++ b/arch/powerpc/platforms/82xx/pq2ads.h
@@ -22,6 +22,7 @@
 #ifndef __MACH_ADS8260_DEFS
 #define __MACH_ADS8260_DEFS
 
+#include <linux/seq_file.h>
 #include <asm/ppcboot.h>
 
 /* For our show_cpuinfo hooks. */
@@ -46,12 +47,12 @@
 #define BCSR1_RS232_EN1		((uint)0x02000000)      /* 0 ==enable */
 #define BCSR1_RS232_EN2		((uint)0x01000000)      /* 0 ==enable */
 #define BCSR3_FETHIEN2		((uint)0x10000000)      /* 0 == enable*/
-#define BCSR3_FETH2_RS		((uint)0x80000000)      /* 0 == reset */
+#define BCSR3_FETH2_RST		((uint)0x80000000)      /* 0 == reset */
 
 /* cpm serial driver works with constants below */
 
 #define SIU_INT_SMC1		((uint)0x04+CPM_IRQ_OFFSET)
-#define SIU_INT_SMC2i		((uint)0x05+CPM_IRQ_OFFSET)
+#define SIU_INT_SMC2		((uint)0x05+CPM_IRQ_OFFSET)
 #define SIU_INT_SCC1		((uint)0x28+CPM_IRQ_OFFSET)
 #define SIU_INT_SCC2		((uint)0x29+CPM_IRQ_OFFSET)
 #define SIU_INT_SCC3		((uint)0x2a+CPM_IRQ_OFFSET)
diff --git a/arch/powerpc/platforms/83xx/misc.c b/arch/powerpc/platforms/83xx/misc.c
index f0c6df6..f01806c 100644
--- a/arch/powerpc/platforms/83xx/misc.c
+++ b/arch/powerpc/platforms/83xx/misc.c
@@ -18,23 +18,36 @@
 
 #include "mpc83xx.h"
 
+static __be32 __iomem *restart_reg_base;
+
+static int __init mpc83xx_restart_init(void)
+{
+	/* map reset restart_reg_baseister space */
+	restart_reg_base = ioremap(get_immrbase() + 0x900, 0xff);
+
+	return 0;
+}
+
+arch_initcall(mpc83xx_restart_init);
+
 void mpc83xx_restart(char *cmd)
 {
 #define RST_OFFSET	0x00000900
 #define RST_PROT_REG	0x00000018
 #define RST_CTRL_REG	0x0000001c
-	__be32 __iomem *reg;
-
-	/* map reset register space */
-	reg = ioremap(get_immrbase() + 0x900, 0xff);
 
 	local_irq_disable();
 
-	/* enable software reset "RSTE" */
-	out_be32(reg + (RST_PROT_REG >> 2), 0x52535445);
+	if (restart_reg_base) {
+		/* enable software reset "RSTE" */
+		out_be32(restart_reg_base + (RST_PROT_REG >> 2), 0x52535445);
 
-	/* set software hard reset */
-	out_be32(reg + (RST_CTRL_REG >> 2), 0x2);
+		/* set software hard reset */
+		out_be32(restart_reg_base + (RST_CTRL_REG >> 2), 0x2);
+	} else {
+		printk (KERN_EMERG "Error: Restart registers not mapped, spinning!\n");
+	}
+
 	for (;;) ;
 }
 
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c
index 4d47119..3ecb55f 100644
--- a/arch/powerpc/platforms/83xx/mpc832x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c
@@ -25,6 +25,7 @@
 #include <linux/initrd.h>
 
 #include <asm/of_device.h>
+#include <asm/of_platform.h>
 #include <asm/system.h>
 #include <asm/atomic.h>
 #include <asm/time.h>
@@ -153,7 +154,7 @@
 }
 device_initcall(mpc832x_declare_of_platform_devices);
 
-void __init mpc832x_sys_init_IRQ(void)
+static void __init mpc832x_sys_init_IRQ(void)
 {
 
 	struct device_node *np;
diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c
index 314c42a..2446dea 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_itx.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c
@@ -81,7 +81,7 @@
 #endif
 }
 
-void __init mpc834x_itx_init_IRQ(void)
+static void __init mpc834x_itx_init_IRQ(void)
 {
 	struct device_node *np;
 
diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.c b/arch/powerpc/platforms/83xx/mpc834x_sys.c
index 80b735a..f30393f 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_sys.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_sys.c
@@ -79,7 +79,7 @@
 #endif
 }
 
-void __init mpc834x_sys_init_IRQ(void)
+static void __init mpc834x_sys_init_IRQ(void)
 {
 	struct device_node *np;
 
diff --git a/arch/powerpc/platforms/83xx/mpc8360e_pb.c b/arch/powerpc/platforms/83xx/mpc8360e_pb.c
index 53b92a9..ccce2f9 100644
--- a/arch/powerpc/platforms/83xx/mpc8360e_pb.c
+++ b/arch/powerpc/platforms/83xx/mpc8360e_pb.c
@@ -31,6 +31,7 @@
 #include <linux/initrd.h>
 
 #include <asm/of_device.h>
+#include <asm/of_platform.h>
 #include <asm/system.h>
 #include <asm/atomic.h>
 #include <asm/time.h>
@@ -158,7 +159,7 @@
 }
 device_initcall(mpc8360_declare_of_platform_devices);
 
-void __init mpc8360_sys_init_IRQ(void)
+static void __init mpc8360_sys_init_IRQ(void)
 {
 
 	struct device_node *np;
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig
index d1ecc0f..0c70944 100644
--- a/arch/powerpc/platforms/86xx/Kconfig
+++ b/arch/powerpc/platforms/86xx/Kconfig
@@ -8,6 +8,7 @@
 config MPC8641_HPCN
 	bool "Freescale MPC8641 HPCN"
 	select PPC_I8259
+	select DEFAULT_UIMAGE
 	help
 	  This option enables support for the MPC8641 HPCN board.
 
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
index bb7fb41..7ef0c68 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_smp.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
@@ -65,7 +65,6 @@
 	pr_debug("smp_86xx_kick_cpu: kick CPU #%d\n", nr);
 
 	local_irq_save(flags);
-	local_irq_disable();
 
 	/* Save reset vector */
 	save_vector = *vector;
diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig
index c8c0ba3..beea683 100644
--- a/arch/powerpc/platforms/8xx/Kconfig
+++ b/arch/powerpc/platforms/8xx/Kconfig
@@ -1,105 +1,16 @@
+menu "Platform support"
+        depends on PPC_8xx
+
 config FADS
 	bool
 
+config CPM1
+	bool
+
 choice
 	prompt "8xx Machine Type"
 	depends on 8xx
-	default RPXLITE
-
-config RPXLITE
-	bool "RPX-Lite"
-	---help---
-	  Single-board computers based around the PowerPC MPC8xx chips and
-	  intended for embedded applications.  The following types are
-	  supported:
-
-	  RPX-Lite:
-	  Embedded Planet RPX Lite. PC104 form-factor SBC based on the MPC823.
-
-	  RPX-Classic:
-	  Embedded Planet RPX Classic Low-fat. Credit-card-size SBC based on
-	  the MPC 860
-
-	  BSE-IP:
-	  Bright Star Engineering ip-Engine.
-
-	  TQM823L:
-	  TQM850L:
-	  TQM855L:
-	  TQM860L:
-	  MPC8xx based family of mini modules, half credit card size,
-	  up to 64 MB of RAM, 8 MB Flash, (Fast) Ethernet, 2 x serial ports,
-	  2 x CAN bus interface, ...
-	  Manufacturer: TQ Components, www.tq-group.de
-	  Date of Release: October (?) 1999
-	  End of Life: not yet :-)
-	  URL:
-	  - module: <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>
-	  - starter kit: <http://www.denx.de/PDF/STK8xxLHWM201.pdf>
-	  - images: <http://www.denx.de/embedded-ppc-en.html>
-
-	  FPS850L:
-	  FingerPrint Sensor System (based on TQM850L)
-	  Manufacturer: IKENDI AG, <http://www.ikendi.com/>
-	  Date of Release: November 1999
-	  End of life: end 2000 ?
-	  URL: see TQM850L
-
-	  IVMS8:
-	  MPC860 based board used in the "Integrated Voice Mail System",
-	  Small Version (8 voice channels)
-	  Manufacturer: Speech Design, <http://www.speech-design.de/>
-	  Date of Release: December 2000 (?)
-	  End of life: -
-	  URL: <http://www.speech-design.de/>
-
-	  IVML24:
-	  MPC860 based board used in the "Integrated Voice Mail System",
-	  Large Version (24 voice channels)
-	  Manufacturer: Speech Design, <http://www.speech-design.de/>
-	  Date of Release: March 2001  (?)
-	  End of life: -
-	  URL: <http://www.speech-design.de/>
-
-	  HERMES:
-	  Hermes-Pro ISDN/LAN router with integrated 8 x hub
-	  Manufacturer: Multidata Gesellschaft fur Datentechnik und Informatik
-	  <http://www.multidata.de/>
-	  Date of Release: 2000 (?)
-	  End of life: -
-	  URL: <http://www.multidata.de/english/products/hpro.htm>
-
-	  IP860:
-	  VMEBus IP (Industry Pack) carrier board with MPC860
-	  Manufacturer: MicroSys GmbH, <http://www.microsys.de/>
-	  Date of Release: ?
-	  End of life: -
-	  URL: <http://www.microsys.de/html/ip860.html>
-
-	  PCU_E:
-	  PCU = Peripheral Controller Unit, Extended
-	  Manufacturer: Siemens AG, ICN (Information and Communication Networks)
-	  	<http://www.siemens.de/page/1,3771,224315-1-999_2_226207-0,00.html>
-	  Date of Release: April 2001
-	  End of life: August 2001
-	  URL: n. a.
-
-config RPXCLASSIC
-	bool "RPX-Classic"
-	help
-	  The RPX-Classic is a single-board computer based on the Motorola
-	  MPC860.  It features 16MB of DRAM and a variable amount of flash,
-	  I2C EEPROM, thermal monitoring, a PCMCIA slot, a DIP switch and two
-	  LEDs.  Variants with Ethernet ports exist.  Say Y here to support it
-	  directly.
-
-config BSEIP
-	bool "BSE-IP"
-	help
-	  Say Y here to support the Bright Star Engineering ipEngine SBC.
-	  This is a credit-card-sized device featuring a MPC823 processor,
-	  26MB DRAM, 4MB flash, Ethernet, a 16K-gate FPGA, USB, an LCD/video
-	  controller, and two RS232 ports.
+	default MPC885ADS
 
 config MPC8XXFADS
 	bool "FADS"
@@ -107,111 +18,59 @@
 
 config MPC86XADS
 	bool "MPC86XADS"
+	select CPM1
 	help
 	  MPC86x Application Development System by Freescale Semiconductor.
 	  The MPC86xADS is meant to serve as a platform for s/w and h/w
 	  development around the MPC86X processor families.
-	select FADS
 
 config MPC885ADS
 	bool "MPC885ADS"
+	select CPM1
 	help
 	  Freescale Semiconductor MPC885 Application Development System (ADS).
 	  Also known as DUET.
 	  The MPC885ADS is meant to serve as a platform for s/w and h/w
 	  development around the MPC885 processor family.
 
-config TQM823L
-	bool "TQM823L"
-	help
-	  Say Y here to support the TQM823L, one of an MPC8xx-based family of
-	  mini SBCs (half credit-card size) from TQ Components first released
-	  in late 1999.  Technical references are at
-	  <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
-	  <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
-	  <http://www.denx.de/embedded-ppc-en.html>.
-
-config TQM850L
-	bool "TQM850L"
-	help
-	  Say Y here to support the TQM850L, one of an MPC8xx-based family of
-	  mini SBCs (half credit-card size) from TQ Components first released
-	  in late 1999.  Technical references are at
-	  <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
-	  <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
-	  <http://www.denx.de/embedded-ppc-en.html>.
-
-config TQM855L
-	bool "TQM855L"
-	help
-	  Say Y here to support the TQM855L, one of an MPC8xx-based family of
-	  mini SBCs (half credit-card size) from TQ Components first released
-	  in late 1999.  Technical references are at
-	  <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
-	  <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
-	  <http://www.denx.de/embedded-ppc-en.html>.
-
-config TQM860L
-	bool "TQM860L"
-	help
-	  Say Y here to support the TQM860L, one of an MPC8xx-based family of
-	  mini SBCs (half credit-card size) from TQ Components first released
-	  in late 1999.  Technical references are at
-	  <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
-	  <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
-	  <http://www.denx.de/embedded-ppc-en.html>.
-
-config FPS850L
-	bool "FPS850L"
-
-config IVMS8
-	bool "IVMS8"
-	help
-	  Say Y here to support the Integrated Voice-Mail Small 8-channel SBC
-	  from Speech Design, released March 2001.  The manufacturer's website
-	  is at <http://www.speech-design.de/>.
-
-config IVML24
-	bool "IVML24"
-	help
-	  Say Y here to support the Integrated Voice-Mail Large 24-channel SBC
-	  from Speech Design, released March 2001.  The manufacturer's website
-	  is at <http://www.speech-design.de/>.
-
-config HERMES_PRO
-	bool "HERMES"
-
-config IP860
-	bool "IP860"
-
-config LWMON
-	bool "LWMON"
-
-config PCU_E
-	bool "PCU_E"
-
-config CCM
-	bool "CCM"
-
-config LANTEC
-	bool "LANTEC"
-
-config MBX
-	bool "MBX"
-	help
-	  MBX is a line of Motorola single-board computer based around the
-	  MPC821 and MPC860 processors, and intended for embedded-controller
-	  applications.  Say Y here to support these boards directly.
-
-config WINCEPT
-	bool "WinCept"
-	help
-	  The Wincept 100/110 is a Motorola single-board computer based on the
-	  MPC821 PowerPC, introduced in 1998 and designed to be used in
-	  thin-client machines.  Say Y to support it directly.
-
 endchoice
 
+menu "Freescale Ethernet driver platform-specific options"
+        depends on (FS_ENET && MPC885ADS)
+
+        config MPC8xx_SECOND_ETH
+        bool "Second Ethernet channel"
+        depends on MPC885ADS
+        default y
+        help
+          This enables support for second Ethernet on MPC885ADS and MPC86xADS boards.
+          The latter will use SCC1, for 885ADS you can select it below.
+
+        choice
+                prompt "Second Ethernet channel"
+                depends on MPC8xx_SECOND_ETH
+                default MPC8xx_SECOND_ETH_FEC2
+
+                config MPC8xx_SECOND_ETH_FEC2
+                bool "FEC2"
+                depends on MPC885ADS
+                help
+                  Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2
+                  (often 2-nd UART) will not work if this is enabled.
+
+                config MPC8xx_SECOND_ETH_SCC3
+                bool "SCC3"
+                depends on MPC885ADS
+                help
+                  Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1
+                  (often 1-nd UART) will not work if this is enabled.
+
+        endchoice
+
+endmenu
+
+endmenu
+
 #
 # MPC8xx Communication options
 #
@@ -219,79 +78,6 @@
 menu "MPC8xx CPM Options"
 	depends on 8xx
 
-config SCC_ENET
-	bool "CPM SCC Ethernet"
-	depends on NET_ETHERNET
-	help
-	  Enable Ethernet support via the Motorola MPC8xx serial
-	  communications controller.
-
-choice
-	prompt "SCC used for Ethernet"
-	depends on SCC_ENET
-	default SCC1_ENET
-
-config SCC1_ENET
-	bool "SCC1"
-	help
-	  Use MPC8xx serial communications controller 1 to drive Ethernet
-	  (default).
-
-config SCC2_ENET
-	bool "SCC2"
-	help
-	  Use MPC8xx serial communications controller 2 to drive Ethernet.
-
-config SCC3_ENET
-	bool "SCC3"
-	help
-	  Use MPC8xx serial communications controller 3 to drive Ethernet.
-
-endchoice
-
-config FEC_ENET
-	bool "860T FEC Ethernet"
-	depends on NET_ETHERNET
-	help
-	  Enable Ethernet support via the Fast Ethernet Controller (FCC) on
-	  the Motorola MPC8260.
-
-config USE_MDIO
-	bool "Use MDIO for PHY configuration"
-	depends on FEC_ENET
-	help
-	  On some boards the hardware configuration of the ethernet PHY can be
-	  used without any software interaction over the MDIO interface, so
-	  all MII code can be omitted. Say N here if unsure or if you don't
-	  need link status reports.
-
-config  FEC_AM79C874
-	bool "Support AMD79C874 PHY"
-	depends on USE_MDIO
-
-config FEC_LXT970
-	bool "Support LXT970 PHY"
-	depends on USE_MDIO
-
-config FEC_LXT971
-	bool "Support LXT971 PHY"
-	depends on USE_MDIO
-	
-config FEC_QS6612
-	bool "Support QS6612 PHY"
-	depends on USE_MDIO
-	
-config ENET_BIG_BUFFERS
-	bool "Use Big CPM Ethernet Buffers"
-	depends on SCC_ENET || FEC_ENET
-	help
-	  Allocate large buffers for MPC8xx Ethernet. Increases throughput
-	  and decreases the likelihood of dropped packets, but costs memory.
-
-config HTDMSOUND
-	bool "Embedded Planet HIOX Audio"
-	depends on SOUND=y
-
 # This doesn't really belong here, but it is convenient to ask
 # 8xx specific questions.
 comment "Generic MPC8xx Options"
diff --git a/arch/powerpc/platforms/8xx/Makefile b/arch/powerpc/platforms/8xx/Makefile
new file mode 100644
index 0000000..5e2dae3
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the PowerPC 8xx linux kernel.
+#
+obj-$(CONFIG_PPC_8xx)	  += m8xx_setup.o
+obj-$(CONFIG_MPC885ADS)   += mpc885ads_setup.o
+obj-$(CONFIG_MPC86XADS)   += mpc86xads_setup.o
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
new file mode 100644
index 0000000..9ed7125
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
@@ -0,0 +1,303 @@
+/*
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net)
+ *  Further modified for generic 8xx by Dan.
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/initrd.h>
+#include <linux/ioport.h>
+#include <linux/bootmem.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+
+#include <asm/mmu.h>
+#include <asm/reg.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/mpc8xx.h>
+#include <asm/8xx_immap.h>
+#include <asm/machdep.h>
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+#include <asm/prom.h>
+#include <asm/fs_pd.h>
+#include <mm/mmu_decl.h>
+
+#include "sysdev/mpc8xx_pic.h"
+
+void m8xx_calibrate_decr(void);
+extern void m8xx_wdt_handler_install(bd_t *bp);
+extern int cpm_pic_init(void);
+extern int cpm_get_irq(void);
+
+/* A place holder for time base interrupts, if they are ever enabled. */
+irqreturn_t timebase_interrupt(int irq, void * dev)
+{
+	printk ("timebase_interrupt()\n");
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction tbint_irqaction = {
+	.handler = timebase_interrupt,
+	.mask = CPU_MASK_NONE,
+	.name = "tbint",
+};
+
+/* per-board overridable init_internal_rtc() function. */
+void __init __attribute__ ((weak))
+init_internal_rtc(void)
+{
+	sit8xx_t *sys_tmr = (sit8xx_t *) immr_map(im_sit);
+
+	/* Disable the RTC one second and alarm interrupts. */
+	clrbits16(&sys_tmr->sit_rtcsc, (RTCSC_SIE | RTCSC_ALE));
+
+	/* Enable the RTC */
+	setbits16(&sys_tmr->sit_rtcsc, (RTCSC_RTF | RTCSC_RTE));
+	immr_unmap(sys_tmr);
+}
+
+static int __init get_freq(char *name, unsigned long *val)
+{
+        struct device_node *cpu;
+        unsigned int *fp;
+        int found = 0;
+
+        /* The cpu node should have timebase and clock frequency properties */
+        cpu = of_find_node_by_type(NULL, "cpu");
+
+        if (cpu) {
+                fp = (unsigned int *)get_property(cpu, name, NULL);
+                if (fp) {
+                        found = 1;
+                        *val = *fp++;
+                }
+
+                of_node_put(cpu);
+        }
+
+        return found;
+}
+
+/* The decrementer counts at the system (internal) clock frequency divided by
+ * sixteen, or external oscillator divided by four.  We force the processor
+ * to use system clock divided by sixteen.
+ */
+void __init mpc8xx_calibrate_decr(void)
+{
+	struct device_node *cpu;
+	cark8xx_t *clk_r1;
+	car8xx_t *clk_r2;
+	sitk8xx_t *sys_tmr1;
+	sit8xx_t *sys_tmr2;
+	int irq, virq;
+
+        clk_r1 = (cark8xx_t *) immr_map(im_clkrstk);
+
+	/* Unlock the SCCR. */
+	out_be32(&clk_r1->cark_sccrk, ~KAPWR_KEY);
+	out_be32(&clk_r1->cark_sccrk, KAPWR_KEY);
+	immr_unmap(clk_r1);
+
+	/* Force all 8xx processors to use divide by 16 processor clock. */
+        clk_r2 = (car8xx_t *) immr_map(im_clkrst);
+	setbits32(&clk_r2->car_sccr, 0x02000000);
+	immr_unmap(clk_r2);
+
+	/* Processor frequency is MHz.
+	 */
+        ppc_tb_freq = 50000000;
+        if (!get_freq("bus-frequency", &ppc_tb_freq)) {
+                printk(KERN_ERR "WARNING: Estimating decrementer frequency "
+                                "(not found)\n");
+        }
+        ppc_tb_freq /= 16;
+        ppc_proc_freq = 50000000;
+        if (!get_freq("clock-frequency", &ppc_proc_freq))
+                printk(KERN_ERR "WARNING: Estimating processor frequency"
+                                "(not found)\n");
+
+        printk("Decrementer Frequency = 0x%lx\n", ppc_tb_freq);
+
+	/* Perform some more timer/timebase initialization.  This used
+	 * to be done elsewhere, but other changes caused it to get
+	 * called more than once....that is a bad thing.
+	 *
+	 * First, unlock all of the registers we are going to modify.
+	 * To protect them from corruption during power down, registers
+	 * that are maintained by keep alive power are "locked".  To
+	 * modify these registers we have to write the key value to
+	 * the key location associated with the register.
+	 * Some boards power up with these unlocked, while others
+	 * are locked.  Writing anything (including the unlock code?)
+	 * to the unlocked registers will lock them again.  So, here
+	 * we guarantee the registers are locked, then we unlock them
+	 * for our use.
+	 */
+        sys_tmr1 = (sitk8xx_t *) immr_map(im_sitk);
+	out_be32(&sys_tmr1->sitk_tbscrk, ~KAPWR_KEY);
+	out_be32(&sys_tmr1->sitk_rtcsck, ~KAPWR_KEY);
+	out_be32(&sys_tmr1->sitk_tbk, ~KAPWR_KEY);
+	out_be32(&sys_tmr1->sitk_tbscrk, KAPWR_KEY);
+	out_be32(&sys_tmr1->sitk_rtcsck, KAPWR_KEY);
+	out_be32(&sys_tmr1->sitk_tbk, KAPWR_KEY);
+	immr_unmap(sys_tmr1);
+
+	init_internal_rtc();
+
+	/* Enabling the decrementer also enables the timebase interrupts
+	 * (or from the other point of view, to get decrementer interrupts
+	 * we have to enable the timebase).  The decrementer interrupt
+	 * is wired into the vector table, nothing to do here for that.
+	 */
+        cpu = of_find_node_by_type(NULL, "cpu");
+        virq= irq_of_parse_and_map(cpu, 0);
+	irq = irq_map[virq].hwirq;
+
+	sys_tmr2 = (sit8xx_t *) immr_map(im_sit);
+	out_be16(&sys_tmr2->sit_tbscr, ((1 << (7 - (irq/2))) << 8) |
+					(TBSCR_TBF | TBSCR_TBE));
+	immr_unmap(sys_tmr2);
+
+	if (setup_irq(virq, &tbint_irqaction))
+		panic("Could not allocate timer IRQ!");
+
+#ifdef CONFIG_8xx_WDT
+	/* Install watchdog timer handler early because it might be
+	 * already enabled by the bootloader
+	 */
+	m8xx_wdt_handler_install(binfo);
+#endif
+}
+
+/* The RTC on the MPC8xx is an internal register.
+ * We want to protect this during power down, so we need to unlock,
+ * modify, and re-lock.
+ */
+
+int mpc8xx_set_rtc_time(struct rtc_time *tm)
+{
+	sitk8xx_t *sys_tmr1;
+	sit8xx_t *sys_tmr2;
+	int time;
+
+        sys_tmr1 = (sitk8xx_t *) immr_map(im_sitk);
+	sys_tmr2 = (sit8xx_t *) immr_map(im_sit);
+	time = mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
+                      tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+	out_be32(&sys_tmr1->sitk_rtck, KAPWR_KEY);
+	out_be32(&sys_tmr2->sit_rtc, time);
+	out_be32(&sys_tmr1->sitk_rtck, ~KAPWR_KEY);
+
+	immr_unmap(sys_tmr2);
+	immr_unmap(sys_tmr1);
+	return 0;
+}
+
+void mpc8xx_get_rtc_time(struct rtc_time *tm)
+{
+	unsigned long data;
+	sit8xx_t *sys_tmr = (sit8xx_t *) immr_map(im_sit);
+
+	/* Get time from the RTC. */
+	data = in_be32(&sys_tmr->sit_rtc);
+	to_tm(data, tm);
+        tm->tm_year -= 1900;
+        tm->tm_mon -= 1;
+	immr_unmap(sys_tmr);
+	return;
+}
+
+void mpc8xx_restart(char *cmd)
+{
+	__volatile__ unsigned char dummy;
+	car8xx_t * clk_r = (car8xx_t *) immr_map(im_clkrst);
+
+
+	local_irq_disable();
+
+	setbits32(&clk_r->car_plprcr, 0x00000080);
+	/* Clear the ME bit in MSR to cause checkstop on machine check
+	*/
+	mtmsr(mfmsr() & ~0x1000);
+
+	dummy = in_8(&clk_r->res[0]);
+	printk("Restart failed\n");
+	while(1);
+}
+
+void mpc8xx_show_cpuinfo(struct seq_file *m)
+{
+	struct device_node *root;
+	uint memsize = total_memory;
+	const char *model = "";
+
+	seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
+
+	root = of_find_node_by_path("/");
+	if (root)
+		model = get_property(root, "model", NULL);
+	seq_printf(m, "Machine\t\t: %s\n", model);
+	of_node_put(root);
+
+	seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
+}
+
+static void cpm_cascade(unsigned int irq, struct irq_desc *desc)
+{
+	int cascade_irq;
+
+	if ((cascade_irq = cpm_get_irq()) >= 0) {
+		struct irq_desc *cdesc = irq_desc + cascade_irq;
+
+		generic_handle_irq(cascade_irq);
+		cdesc->chip->eoi(cascade_irq);
+	}
+	desc->chip->eoi(irq);
+}
+
+/* Initialize the internal interrupt controller.  The number of
+ * interrupts supported can vary with the processor type, and the
+ * 82xx family can have up to 64.
+ * External interrupts can be either edge or level triggered, and
+ * need to be initialized by the appropriate driver.
+ */
+void __init m8xx_pic_init(void)
+{
+	int irq;
+
+	if (mpc8xx_pic_init()) {
+                printk(KERN_ERR "Failed interrupt 8xx controller  initialization\n");
+		return;
+	}
+
+	irq = cpm_pic_init();
+	if (irq != NO_IRQ)
+		set_irq_chained_handler(irq, cpm_cascade);
+}
diff --git a/arch/powerpc/platforms/8xx/mpc86xads.h b/arch/powerpc/platforms/8xx/mpc86xads.h
new file mode 100644
index 0000000..b5d19dd
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/mpc86xads.h
@@ -0,0 +1,95 @@
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Freescale MPC86xADS board.
+ * Copied from the FADS stuff.
+ *
+ * Author: MontaVista Software, Inc.
+ *         source@mvista.com
+ *
+ * 2005 (c) MontaVista Software, Inc.  This file is licensed under the
+ * terms of the GNU General Public License version 2.  This program is licensed
+ * "as is" without any warranty of any kind, whether express or implied.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_MPC86XADS_H__
+#define __ASM_MPC86XADS_H__
+
+#include <asm/ppcboot.h>
+#include <sysdev/fsl_soc.h>
+
+/* U-Boot maps BCSR to 0xff080000 */
+#define BCSR_ADDR		((uint)0xff080000)
+#define BCSR_SIZE		((uint)32)
+#define BCSR0			((uint)(BCSR_ADDR + 0x00))
+#define BCSR1			((uint)(BCSR_ADDR + 0x04))
+#define BCSR2			((uint)(BCSR_ADDR + 0x08))
+#define BCSR3			((uint)(BCSR_ADDR + 0x0c))
+#define BCSR4			((uint)(BCSR_ADDR + 0x10))
+
+#define CFG_PHYDEV_ADDR		((uint)0xff0a0000)
+#define BCSR5			((uint)(CFG_PHYDEV_ADDR + 0x300))
+
+#define IMAP_ADDR		(get_immrbase())
+#define IMAP_SIZE		((uint)(64 * 1024))
+
+#define MPC8xx_CPM_OFFSET	(0x9c0)
+#define CPM_MAP_ADDR		(get_immrbase() + MPC8xx_CPM_OFFSET)
+#define CPM_IRQ_OFFSET		16     // for compability with cpm_uart driver
+
+#define PCMCIA_MEM_ADDR		(uint)0xff020000)
+#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
+
+/* Bits of interest in the BCSRs.
+ */
+#define BCSR1_ETHEN		((uint)0x20000000)
+#define BCSR1_IRDAEN		((uint)0x10000000)
+#define BCSR1_RS232EN_1		((uint)0x01000000)
+#define BCSR1_PCCEN		((uint)0x00800000)
+#define BCSR1_PCCVCC0		((uint)0x00400000)
+#define BCSR1_PCCVPP0		((uint)0x00200000)
+#define BCSR1_PCCVPP1		((uint)0x00100000)
+#define BCSR1_PCCVPP_MASK	(BCSR1_PCCVPP0 | BCSR1_PCCVPP1)
+#define BCSR1_RS232EN_2		((uint)0x00040000)
+#define BCSR1_PCCVCC1		((uint)0x00010000)
+#define BCSR1_PCCVCC_MASK	(BCSR1_PCCVCC0 | BCSR1_PCCVCC1)
+
+#define BCSR4_ETH10_RST		((uint)0x80000000)	/* 10Base-T PHY reset*/
+#define BCSR4_USB_LO_SPD	((uint)0x04000000)
+#define BCSR4_USB_VCC		((uint)0x02000000)
+#define BCSR4_USB_FULL_SPD	((uint)0x00040000)
+#define BCSR4_USB_EN		((uint)0x00020000)
+
+#define BCSR5_MII2_EN		0x40
+#define BCSR5_MII2_RST		0x20
+#define BCSR5_T1_RST		0x10
+#define BCSR5_ATM155_RST	0x08
+#define BCSR5_ATM25_RST		0x04
+#define BCSR5_MII1_EN		0x02
+#define BCSR5_MII1_RST		0x01
+
+/* Interrupt level assignments */
+#define PHY_INTERRUPT	SIU_IRQ7	/* PHY link change interrupt */
+#define SIU_INT_FEC1	SIU_LEVEL1	/* FEC1 interrupt */
+#define FEC_INTERRUPT	SIU_INT_FEC1	/* FEC interrupt */
+
+/* We don't use the 8259 */
+#define NR_8259_INTS	0
+
+/* CPM Ethernet through SCC1 */
+#define PA_ENET_RXD     ((ushort)0x0001)
+#define PA_ENET_TXD     ((ushort)0x0002)
+#define PA_ENET_TCLK    ((ushort)0x0100)
+#define PA_ENET_RCLK    ((ushort)0x0200)
+#define PB_ENET_TENA    ((uint)0x00001000)
+#define PC_ENET_CLSN    ((ushort)0x0010)
+#define PC_ENET_RENA    ((ushort)0x0020)
+
+/* Control bits in the SICR to route TCLK (CLK1) and RCLK (CLK2) to
+ * SCC1.  Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
+ */
+#define SICR_ENET_MASK  ((uint)0x000000ff)
+#define SICR_ENET_CLKRT ((uint)0x0000002c)
+
+#endif /* __ASM_MPC86XADS_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c
new file mode 100644
index 0000000..ef52ce7
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c
@@ -0,0 +1,301 @@
+/*arch/ppc/platforms/mpc86xads-setup.c
+ *
+ * Platform setup for the Freescale mpc86xads board
+ *
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * Copyright 2005 MontaVista Software Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/root_dev.h>
+
+#include <linux/fs_enet_pd.h>
+#include <linux/fs_uart_pd.h>
+#include <linux/mii.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/ppcboot.h>
+#include <asm/mpc8xx.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+#include <asm/fs_pd.h>
+#include <asm/prom.h>
+
+extern void cpm_reset(void);
+extern void mpc8xx_show_cpuinfo(struct seq_file*);
+extern void mpc8xx_restart(char *cmd);
+extern void mpc8xx_calibrate_decr(void);
+extern int mpc8xx_set_rtc_time(struct rtc_time *tm);
+extern void mpc8xx_get_rtc_time(struct rtc_time *tm);
+extern void m8xx_pic_init(void);
+extern unsigned int mpc8xx_get_irq(void);
+
+static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi);
+static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi);
+static void init_scc1_ioports(struct fs_platform_info* ptr);
+
+void __init mpc86xads_board_setup(void)
+{
+	cpm8xx_t *cp;
+ 	unsigned int *bcsr_io;
+	u8 tmpval8;
+
+	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+	cp = (cpm8xx_t *)immr_map(im_cpm);
+
+	if (bcsr_io == NULL) {
+		printk(KERN_CRIT "Could not remap BCSR\n");
+		return;
+	}
+#ifdef CONFIG_SERIAL_CPM_SMC1
+	clrbits32(bcsr_io, BCSR1_RS232EN_1);
+	clrbits32(&cp->cp_simode, 0xe0000000 >> 17);	/* brg1 */
+	tmpval8 = in_8(&(cp->cp_smc[0].smc_smcm)) | (SMCM_RX | SMCM_TX);
+	out_8(&(cp->cp_smc[0].smc_smcm), tmpval8);
+	clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN);
+#else
+	setbits32(bcsr_io,BCSR1_RS232EN_1);
+	out_be16(&cp->cp_smc[0].smc_smcmr, 0);
+	out_8(&cp->cp_smc[0].smc_smce, 0);
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SMC2
+	clrbits32(bcsr_io,BCSR1_RS232EN_2);
+	clrbits32(&cp->cp_simode, 0xe0000000 >> 1);
+	setbits32(&cp->cp_simode, 0x20000000 >> 1);	/* brg2 */
+	tmpval8 = in_8(&(cp->cp_smc[1].smc_smcm)) | (SMCM_RX | SMCM_TX);
+	out_8(&(cp->cp_smc[1].smc_smcm), tmpval8);
+	clrbits16(&cp->cp_smc[1].smc_smcmr, SMCMR_REN | SMCMR_TEN);
+
+	init_smc2_uart_ioports(0);
+#else
+	setbits32(bcsr_io,BCSR1_RS232EN_2);
+	out_be16(&cp->cp_smc[1].smc_smcmr, 0);
+	out_8(&cp->cp_smc[1].smc_smce, 0);
+#endif
+	immr_unmap(cp);
+	iounmap(bcsr_io);
+}
+
+
+static void init_fec1_ioports(struct fs_platform_info* ptr)
+{
+	iop8xx_t *io_port = (iop8xx_t *)immr_map(im_ioport);
+
+	/* configure FEC1 pins  */
+
+	setbits16(&io_port->iop_pdpar, 0x1fff);
+	setbits16(&io_port->iop_pddir, 0x1fff);
+
+	immr_unmap(io_port);
+}
+
+void init_fec_ioports(struct fs_platform_info *fpi)
+{
+	int fec_no = fs_get_fec_index(fpi->fs_no);
+
+	switch (fec_no) {
+	case 0:
+		init_fec1_ioports(fpi);
+		break;
+	default:
+		printk(KERN_ERR "init_fec_ioports: invalid FEC number\n");
+		return;
+	}
+}
+
+static void init_scc1_ioports(struct fs_platform_info* fpi)
+{
+	unsigned *bcsr_io;
+	iop8xx_t *io_port;
+	cpm8xx_t *cp;
+
+	bcsr_io = ioremap(BCSR_ADDR, BCSR_SIZE);
+	io_port = (iop8xx_t *)immr_map(im_ioport);
+	cp = (cpm8xx_t *)immr_map(im_cpm);
+
+	if (bcsr_io == NULL) {
+		printk(KERN_CRIT "Could not remap BCSR\n");
+		return;
+	}
+
+	/* Configure port A pins for Txd and Rxd.
+	 */
+	setbits16(&io_port->iop_papar, PA_ENET_RXD | PA_ENET_TXD);
+	clrbits16(&io_port->iop_padir, PA_ENET_RXD | PA_ENET_TXD);
+	clrbits16(&io_port->iop_paodr, PA_ENET_TXD);
+
+	/* Configure port C pins to enable CLSN and RENA.
+	 */
+	clrbits16(&io_port->iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA);
+	clrbits16(&io_port->iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA);
+	setbits16(&io_port->iop_pcso, PC_ENET_CLSN | PC_ENET_RENA);
+
+	/* Configure port A for TCLK and RCLK.
+	 */
+	setbits16(&io_port->iop_papar, PA_ENET_TCLK | PA_ENET_RCLK);
+        clrbits16(&io_port->iop_padir, PA_ENET_TCLK | PA_ENET_RCLK);
+        clrbits32(&cp->cp_pbpar, PB_ENET_TENA);
+        clrbits32(&cp->cp_pbdir, PB_ENET_TENA);
+
+	/* Configure Serial Interface clock routing.
+	 * First, clear all SCC bits to zero, then set the ones we want.
+	 */
+	clrbits32(&cp->cp_sicr, SICR_ENET_MASK);
+	setbits32(&cp->cp_sicr, SICR_ENET_CLKRT);
+
+	/* In the original SCC enet driver the following code is placed at
+	   the end of the initialization */
+        setbits32(&cp->cp_pbpar, PB_ENET_TENA);
+        setbits32(&cp->cp_pbdir, PB_ENET_TENA);
+
+	clrbits32(bcsr_io+1, BCSR1_ETHEN);
+	iounmap(bcsr_io);
+	immr_unmap(cp);
+	immr_unmap(io_port);
+}
+
+void init_scc_ioports(struct fs_platform_info *fpi)
+{
+	int scc_no = fs_get_scc_index(fpi->fs_no);
+
+	switch (scc_no) {
+	case 0:
+		init_scc1_ioports(fpi);
+		break;
+	default:
+		printk(KERN_ERR "init_scc_ioports: invalid SCC number\n");
+		return;
+	}
+}
+
+
+
+static void init_smc1_uart_ioports(struct fs_uart_platform_info* ptr)
+{
+        unsigned *bcsr_io;
+	cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm);
+
+	setbits32(&cp->cp_pbpar, 0x000000c0);
+	clrbits32(&cp->cp_pbdir, 0x000000c0);
+	clrbits16(&cp->cp_pbodr, 0x00c0);
+	immr_unmap(cp);
+
+        bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+        if (bcsr_io == NULL) {
+                printk(KERN_CRIT "Could not remap BCSR1\n");
+                return;
+        }
+        clrbits32(bcsr_io,BCSR1_RS232EN_1);
+        iounmap(bcsr_io);
+}
+
+static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi)
+{
+        unsigned *bcsr_io;
+	cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm);
+
+	setbits32(&cp->cp_pbpar, 0x00000c00);
+	clrbits32(&cp->cp_pbdir, 0x00000c00);
+	clrbits16(&cp->cp_pbodr, 0x0c00);
+	immr_unmap(cp);
+
+        bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+        if (bcsr_io == NULL) {
+                printk(KERN_CRIT "Could not remap BCSR1\n");
+                return;
+        }
+        clrbits32(bcsr_io,BCSR1_RS232EN_2);
+        iounmap(bcsr_io);
+}
+
+void init_smc_ioports(struct fs_uart_platform_info *data)
+{
+	int smc_no = fs_uart_id_fsid2smc(data->fs_no);
+
+	switch (smc_no) {
+	case 0:
+		init_smc1_uart_ioports(data);
+		data->brg = data->clk_rx;
+		break;
+	case 1:
+		init_smc2_uart_ioports(data);
+		data->brg = data->clk_rx;
+		break;
+	default:
+		printk(KERN_ERR "init_scc_ioports: invalid SCC number\n");
+		return;
+	}
+}
+
+int platform_device_skip(char *model, int id)
+{
+	return 0;
+}
+
+static void __init mpc86xads_setup_arch(void)
+{
+	struct device_node *cpu;
+
+	cpu = of_find_node_by_type(NULL, "cpu");
+	if (cpu != 0) {
+		const unsigned int *fp;
+
+		fp = get_property(cpu, "clock-frequency", NULL);
+		if (fp != 0)
+			loops_per_jiffy = *fp / HZ;
+		else
+			loops_per_jiffy = 50000000 / HZ;
+		of_node_put(cpu);
+	}
+
+	cpm_reset();
+
+	mpc86xads_board_setup();
+
+	ROOT_DEV = Root_NFS;
+}
+
+static int __init mpc86xads_probe(void)
+{
+	char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
+					  "model", NULL);
+	if (model == NULL)
+		return 0;
+	if (strcmp(model, "MPC866ADS"))
+		return 0;
+
+	return 1;
+}
+
+define_machine(mpc86x_ads) {
+	.name			= "MPC86x ADS",
+	.probe			= mpc86xads_probe,
+	.setup_arch		= mpc86xads_setup_arch,
+	.init_IRQ		= m8xx_pic_init,
+	.show_cpuinfo		= mpc8xx_show_cpuinfo,
+	.get_irq		= mpc8xx_get_irq,
+	.restart		= mpc8xx_restart,
+	.calibrate_decr		= mpc8xx_calibrate_decr,
+	.set_rtc_time		= mpc8xx_set_rtc_time,
+	.get_rtc_time		= mpc8xx_get_rtc_time,
+};
diff --git a/arch/powerpc/platforms/8xx/mpc885ads.h b/arch/powerpc/platforms/8xx/mpc885ads.h
new file mode 100644
index 0000000..30cbebf
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/mpc885ads.h
@@ -0,0 +1,95 @@
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Freescale MPC885ADS board.
+ * Copied from the FADS stuff.
+ *
+ * Author: MontaVista Software, Inc.
+ *         source@mvista.com
+ *
+ * 2005 (c) MontaVista Software, Inc.  This file is licensed under the
+ * terms of the GNU General Public License version 2.  This program is licensed
+ * "as is" without any warranty of any kind, whether express or implied.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_MPC885ADS_H__
+#define __ASM_MPC885ADS_H__
+
+#include <asm/ppcboot.h>
+#include <sysdev/fsl_soc.h>
+
+/* U-Boot maps BCSR to 0xff080000 */
+#define BCSR_ADDR		((uint)0xff080000)
+#define BCSR_SIZE		((uint)32)
+#define BCSR0			((uint)(BCSR_ADDR + 0x00))
+#define BCSR1			((uint)(BCSR_ADDR + 0x04))
+#define BCSR2			((uint)(BCSR_ADDR + 0x08))
+#define BCSR3			((uint)(BCSR_ADDR + 0x0c))
+#define BCSR4			((uint)(BCSR_ADDR + 0x10))
+
+#define CFG_PHYDEV_ADDR		((uint)0xff0a0000)
+#define BCSR5			((uint)(CFG_PHYDEV_ADDR + 0x300))
+
+#define IMAP_ADDR		(get_immrbase())
+#define IMAP_SIZE		((uint)(64 * 1024))
+
+#define MPC8xx_CPM_OFFSET	(0x9c0)
+#define CPM_MAP_ADDR		(get_immrbase() + MPC8xx_CPM_OFFSET)
+#define CPM_IRQ_OFFSET		16     // for compability with cpm_uart driver
+
+#define PCMCIA_MEM_ADDR		(uint)0xff020000)
+#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
+
+/* Bits of interest in the BCSRs.
+ */
+#define BCSR1_ETHEN		((uint)0x20000000)
+#define BCSR1_IRDAEN		((uint)0x10000000)
+#define BCSR1_RS232EN_1		((uint)0x01000000)
+#define BCSR1_PCCEN		((uint)0x00800000)
+#define BCSR1_PCCVCC0		((uint)0x00400000)
+#define BCSR1_PCCVPP0		((uint)0x00200000)
+#define BCSR1_PCCVPP1		((uint)0x00100000)
+#define BCSR1_PCCVPP_MASK	(BCSR1_PCCVPP0 | BCSR1_PCCVPP1)
+#define BCSR1_RS232EN_2		((uint)0x00040000)
+#define BCSR1_PCCVCC1		((uint)0x00010000)
+#define BCSR1_PCCVCC_MASK	(BCSR1_PCCVCC0 | BCSR1_PCCVCC1)
+
+#define BCSR4_ETH10_RST		((uint)0x80000000)	/* 10Base-T PHY reset*/
+#define BCSR4_USB_LO_SPD	((uint)0x04000000)
+#define BCSR4_USB_VCC		((uint)0x02000000)
+#define BCSR4_USB_FULL_SPD	((uint)0x00040000)
+#define BCSR4_USB_EN		((uint)0x00020000)
+
+#define BCSR5_MII2_EN		0x40
+#define BCSR5_MII2_RST		0x20
+#define BCSR5_T1_RST		0x10
+#define BCSR5_ATM155_RST	0x08
+#define BCSR5_ATM25_RST		0x04
+#define BCSR5_MII1_EN		0x02
+#define BCSR5_MII1_RST		0x01
+
+/* Interrupt level assignments */
+#define PHY_INTERRUPT	SIU_IRQ7	/* PHY link change interrupt */
+#define SIU_INT_FEC1	SIU_LEVEL1	/* FEC1 interrupt */
+#define SIU_INT_FEC2	SIU_LEVEL3	/* FEC2 interrupt */
+#define FEC_INTERRUPT	SIU_INT_FEC1	/* FEC interrupt */
+
+/* We don't use the 8259 */
+#define NR_8259_INTS	0
+
+/* CPM Ethernet through SCC3 */
+#define PA_ENET_RXD	((ushort)0x0040)
+#define PA_ENET_TXD	((ushort)0x0080)
+#define PE_ENET_TCLK	((uint)0x00004000)
+#define PE_ENET_RCLK	((uint)0x00008000)
+#define PE_ENET_TENA	((uint)0x00000010)
+#define PC_ENET_CLSN	((ushort)0x0400)
+#define PC_ENET_RENA	((ushort)0x0800)
+
+/* Control bits in the SICR to route TCLK (CLK5) and RCLK (CLK6) to
+ * SCC3.  Also, make sure GR3 (bit 8) and SC3 (bit 9) are zero */
+#define SICR_ENET_MASK	((uint)0x00ff0000)
+#define SICR_ENET_CLKRT	((uint)0x002c0000)
+
+#endif /* __ASM_MPC885ADS_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
new file mode 100644
index 0000000..c5fefdf6
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -0,0 +1,387 @@
+/*arch/ppc/platforms/mpc885ads-setup.c
+ *
+ * Platform setup for the Freescale mpc885ads board
+ *
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * Copyright 2005 MontaVista Software Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/root_dev.h>
+
+#include <linux/fs_enet_pd.h>
+#include <linux/fs_uart_pd.h>
+#include <linux/mii.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/ppcboot.h>
+#include <asm/mpc8xx.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+#include <asm/fs_pd.h>
+#include <asm/prom.h>
+
+extern void cpm_reset(void);
+extern void mpc8xx_show_cpuinfo(struct seq_file*);
+extern void mpc8xx_restart(char *cmd);
+extern void mpc8xx_calibrate_decr(void);
+extern int mpc8xx_set_rtc_time(struct rtc_time *tm);
+extern void mpc8xx_get_rtc_time(struct rtc_time *tm);
+extern void m8xx_pic_init(void);
+extern unsigned int mpc8xx_get_irq(void);
+
+static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi);
+static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi);
+static void init_scc3_ioports(struct fs_platform_info* ptr);
+
+void __init mpc885ads_board_setup(void)
+{
+	cpm8xx_t *cp;
+	unsigned int *bcsr_io;
+	u8 tmpval8;
+
+#ifdef CONFIG_FS_ENET
+	iop8xx_t *io_port;
+#endif
+
+	bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+	cp = (cpm8xx_t *)immr_map(im_cpm);
+
+	if (bcsr_io == NULL) {
+		printk(KERN_CRIT "Could not remap BCSR\n");
+		return;
+	}
+#ifdef CONFIG_SERIAL_CPM_SMC1
+	clrbits32(bcsr_io, BCSR1_RS232EN_1);
+	clrbits32(&cp->cp_simode, 0xe0000000 >> 17);	/* brg1 */
+	tmpval8 = in_8(&(cp->cp_smc[0].smc_smcm)) | (SMCM_RX | SMCM_TX);
+	out_8(&(cp->cp_smc[0].smc_smcm), tmpval8);
+	clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN);	/* brg1 */
+#else
+	setbits32(bcsr_io,BCSR1_RS232EN_1);
+	out_be16(&cp->cp_smc[0].smc_smcmr, 0);
+	out_8(&cp->cp_smc[0].smc_smce, 0);
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SMC2
+	clrbits32(bcsr_io,BCSR1_RS232EN_2);
+	clrbits32(&cp->cp_simode, 0xe0000000 >> 1);
+	setbits32(&cp->cp_simode, 0x20000000 >> 1);	/* brg2 */
+	tmpval8 = in_8(&(cp->cp_smc[1].smc_smcm)) | (SMCM_RX | SMCM_TX);
+	out_8(&(cp->cp_smc[1].smc_smcm), tmpval8);
+	clrbits16(&cp->cp_smc[1].smc_smcmr, SMCMR_REN | SMCMR_TEN);
+
+	init_smc2_uart_ioports(0);
+#else
+	setbits32(bcsr_io,BCSR1_RS232EN_2);
+	out_be16(&cp->cp_smc[1].smc_smcmr, 0);
+	out_8(&cp->cp_smc[1].smc_smce, 0);
+#endif
+	immr_unmap(cp);
+	iounmap(bcsr_io);
+
+#ifdef CONFIG_FS_ENET
+	/* use MDC for MII (common) */
+	io_port = (iop8xx_t*)immr_map(im_ioport);
+	setbits16(&io_port->iop_pdpar, 0x0080);
+	clrbits16(&io_port->iop_pddir, 0x0080);
+
+	bcsr_io = ioremap(BCSR5, sizeof(unsigned long));
+	clrbits32(bcsr_io,BCSR5_MII1_EN);
+	clrbits32(bcsr_io,BCSR5_MII1_RST);
+#ifndef CONFIG_FC_ENET_HAS_SCC
+	clrbits32(bcsr_io,BCSR5_MII2_EN);
+	clrbits32(bcsr_io,BCSR5_MII2_RST);
+
+#endif
+	iounmap(bcsr_io);
+	immr_unmap(io_port);
+
+#endif
+}
+
+
+static void init_fec1_ioports(struct fs_platform_info* ptr)
+{
+	cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm);
+	iop8xx_t *io_port = (iop8xx_t *)immr_map(im_ioport);
+
+	/* configure FEC1 pins  */
+	setbits16(&io_port->iop_papar, 0xf830);
+	setbits16(&io_port->iop_padir, 0x0830);
+	clrbits16(&io_port->iop_padir, 0xf000);
+
+	setbits32(&cp->cp_pbpar, 0x00001001);
+	clrbits32(&cp->cp_pbdir, 0x00001001);
+
+	setbits16(&io_port->iop_pcpar, 0x000c);
+	clrbits16(&io_port->iop_pcdir, 0x000c);
+
+	setbits32(&cp->cp_pepar, 0x00000003);
+	setbits32(&cp->cp_pedir, 0x00000003);
+	clrbits32(&cp->cp_peso, 0x00000003);
+	clrbits32(&cp->cp_cptr, 0x00000100);
+
+	immr_unmap(io_port);
+	immr_unmap(cp);
+}
+
+
+static void init_fec2_ioports(struct fs_platform_info* ptr)
+{
+	cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm);
+	iop8xx_t *io_port = (iop8xx_t *)immr_map(im_ioport);
+
+	/* configure FEC2 pins */
+	setbits32(&cp->cp_pepar, 0x0003fffc);
+	setbits32(&cp->cp_pedir, 0x0003fffc);
+	clrbits32(&cp->cp_peso, 0x000087fc);
+	setbits32(&cp->cp_peso, 0x00037800);
+	clrbits32(&cp->cp_cptr, 0x00000080);
+
+	immr_unmap(io_port);
+	immr_unmap(cp);
+}
+
+void init_fec_ioports(struct fs_platform_info *fpi)
+{
+	int fec_no = fs_get_fec_index(fpi->fs_no);
+
+	switch (fec_no) {
+	case 0:
+		init_fec1_ioports(fpi);
+		break;
+	case 1:
+		init_fec2_ioports(fpi);
+		break;
+	default:
+		printk(KERN_ERR "init_fec_ioports: invalid FEC number\n");
+		return;
+	}
+}
+
+static void init_scc3_ioports(struct fs_platform_info* fpi)
+{
+	unsigned *bcsr_io;
+	iop8xx_t *io_port;
+	cpm8xx_t *cp;
+
+	bcsr_io = ioremap(BCSR_ADDR, BCSR_SIZE);
+	io_port = (iop8xx_t *)immr_map(im_ioport);
+	cp = (cpm8xx_t *)immr_map(im_cpm);
+
+	if (bcsr_io == NULL) {
+		printk(KERN_CRIT "Could not remap BCSR\n");
+		return;
+	}
+
+	/* Enable the PHY.
+	 */
+	clrbits32(bcsr_io+4, BCSR4_ETH10_RST);
+	udelay(1000);
+	setbits32(bcsr_io+4, BCSR4_ETH10_RST);
+	/* Configure port A pins for Txd and Rxd.
+	 */
+	setbits16(&io_port->iop_papar, PA_ENET_RXD | PA_ENET_TXD);
+	clrbits16(&io_port->iop_padir, PA_ENET_RXD | PA_ENET_TXD);
+
+	/* Configure port C pins to enable CLSN and RENA.
+	 */
+	clrbits16(&io_port->iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA);
+	clrbits16(&io_port->iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA);
+	setbits16(&io_port->iop_pcso, PC_ENET_CLSN | PC_ENET_RENA);
+
+	/* Configure port E for TCLK and RCLK.
+	 */
+	setbits32(&cp->cp_pepar, PE_ENET_TCLK | PE_ENET_RCLK);
+	clrbits32(&cp->cp_pepar, PE_ENET_TENA);
+	clrbits32(&cp->cp_pedir,
+		  PE_ENET_TCLK | PE_ENET_RCLK | PE_ENET_TENA);
+	clrbits32(&cp->cp_peso, PE_ENET_TCLK | PE_ENET_RCLK);
+	setbits32(&cp->cp_peso, PE_ENET_TENA);
+
+	/* Configure Serial Interface clock routing.
+	 * First, clear all SCC bits to zero, then set the ones we want.
+	 */
+	clrbits32(&cp->cp_sicr, SICR_ENET_MASK);
+	setbits32(&cp->cp_sicr, SICR_ENET_CLKRT);
+
+	/* Disable Rx and Tx. SMC1 sshould be stopped if SCC3 eternet are used.
+	 */
+	clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN);
+	/* On the MPC885ADS SCC ethernet PHY is initialized in the full duplex mode
+	 * by H/W setting after reset. SCC ethernet controller support only half duplex.
+	 * This discrepancy of modes causes a lot of carrier lost errors.
+	 */
+
+	/* In the original SCC enet driver the following code is placed at
+	   the end of the initialization */
+	setbits32(&cp->cp_pepar, PE_ENET_TENA);
+	clrbits32(&cp->cp_pedir, PE_ENET_TENA);
+	setbits32(&cp->cp_peso, PE_ENET_TENA);
+
+	setbits32(bcsr_io+4, BCSR1_ETHEN);
+	iounmap(bcsr_io);
+	immr_unmap(io_port);
+	immr_unmap(cp);
+}
+
+void init_scc_ioports(struct fs_platform_info *fpi)
+{
+	int scc_no = fs_get_scc_index(fpi->fs_no);
+
+	switch (scc_no) {
+	case 2:
+		init_scc3_ioports(fpi);
+		break;
+	default:
+		printk(KERN_ERR "init_scc_ioports: invalid SCC number\n");
+		return;
+	}
+}
+
+
+
+static void init_smc1_uart_ioports(struct fs_uart_platform_info* ptr)
+{
+        unsigned *bcsr_io;
+	cpm8xx_t *cp;
+
+	cp = (cpm8xx_t *)immr_map(im_cpm);
+	setbits32(&cp->cp_pepar, 0x000000c0);
+	clrbits32(&cp->cp_pedir, 0x000000c0);
+	clrbits32(&cp->cp_peso, 0x00000040);
+	setbits32(&cp->cp_peso, 0x00000080);
+	immr_unmap(cp);
+
+        bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+        if (bcsr_io == NULL) {
+                printk(KERN_CRIT "Could not remap BCSR1\n");
+                return;
+        }
+        clrbits32(bcsr_io,BCSR1_RS232EN_1);
+        iounmap(bcsr_io);
+}
+
+static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi)
+{
+        unsigned *bcsr_io;
+	cpm8xx_t *cp;
+
+	cp = (cpm8xx_t *)immr_map(im_cpm);
+	setbits32(&cp->cp_pepar, 0x00000c00);
+	clrbits32(&cp->cp_pedir, 0x00000c00);
+	clrbits32(&cp->cp_peso, 0x00000400);
+	setbits32(&cp->cp_peso, 0x00000800);
+	immr_unmap(cp);
+
+        bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+        if (bcsr_io == NULL) {
+                printk(KERN_CRIT "Could not remap BCSR1\n");
+                return;
+        }
+        clrbits32(bcsr_io,BCSR1_RS232EN_2);
+        iounmap(bcsr_io);
+}
+
+void init_smc_ioports(struct fs_uart_platform_info *data)
+{
+	int smc_no = fs_uart_id_fsid2smc(data->fs_no);
+
+	switch (smc_no) {
+	case 0:
+		init_smc1_uart_ioports(data);
+		data->brg = data->clk_rx;
+		break;
+	case 1:
+		init_smc2_uart_ioports(data);
+		data->brg = data->clk_rx;
+		break;
+	default:
+		printk(KERN_ERR "init_scc_ioports: invalid SCC number\n");
+		return;
+	}
+}
+
+int platform_device_skip(char *model, int id)
+{
+#ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3
+	const char *dev = "FEC";
+	int n = 2;
+#else
+	const char *dev = "SCC";
+	int n = 3;
+#endif
+
+	if (!strcmp(model, dev) && n == id)
+		return 1;
+
+	return 0;
+}
+
+static void __init mpc885ads_setup_arch(void)
+{
+	struct device_node *cpu;
+
+	cpu = of_find_node_by_type(NULL, "cpu");
+	if (cpu != 0) {
+		const unsigned int *fp;
+
+		fp = get_property(cpu, "clock-frequency", NULL);
+		if (fp != 0)
+			loops_per_jiffy = *fp / HZ;
+		else
+			loops_per_jiffy = 50000000 / HZ;
+		of_node_put(cpu);
+	}
+
+	cpm_reset();
+
+	mpc885ads_board_setup();
+
+	ROOT_DEV = Root_NFS;
+}
+
+static int __init mpc885ads_probe(void)
+{
+	char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
+					  "model", NULL);
+	if (model == NULL)
+		return 0;
+	if (strcmp(model, "MPC885ADS"))
+		return 0;
+
+	return 1;
+}
+
+define_machine(mpc885_ads) {
+	.name			= "MPC885 ADS",
+	.probe			= mpc885ads_probe,
+	.setup_arch		= mpc885ads_setup_arch,
+	.init_IRQ		= m8xx_pic_init,
+	.show_cpuinfo		= mpc8xx_show_cpuinfo,
+	.get_irq		= mpc8xx_get_irq,
+	.restart		= mpc8xx_restart,
+	.calibrate_decr		= mpc8xx_calibrate_decr,
+	.set_rtc_time		= mpc8xx_set_rtc_time,
+	.get_rtc_time		= mpc8xx_get_rtc_time,
+};
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
index 507d1b9..65e6123 100644
--- a/arch/powerpc/platforms/Makefile
+++ b/arch/powerpc/platforms/Makefile
@@ -8,6 +8,8 @@
 obj-$(CONFIG_PPC_MPC52xx)	+= 52xx/
 obj-$(CONFIG_PPC_CHRP)		+= chrp/
 obj-$(CONFIG_4xx)		+= 4xx/
+obj-$(CONFIG_PPC_8xx)		+= 8xx/
+obj-$(CONFIG_PPC_82xx)		+= 82xx/
 obj-$(CONFIG_PPC_83xx)		+= 83xx/
 obj-$(CONFIG_PPC_85xx)		+= 85xx/
 obj-$(CONFIG_PPC_86xx)		+= 86xx/
@@ -17,4 +19,5 @@
 obj-$(CONFIG_PPC_PASEMI)	+= pasemi/
 obj-$(CONFIG_PPC_CELL)		+= cell/
 obj-$(CONFIG_PPC_PS3)		+= ps3/
+obj-$(CONFIG_PPC_CELLEB)	+= celleb/
 obj-$(CONFIG_EMBEDDED6xx)	+= embedded6xx/
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index f90e833..869af89 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -14,7 +14,12 @@
 spufs-modular-$(CONFIG_SPU_FS)		+= spu_syscalls.o
 spu-priv1-$(CONFIG_PPC_CELL_NATIVE)	+= spu_priv1_mmio.o
 
+spu-manage-$(CONFIG_PPC_CELLEB)		+= spu_manage.o
+spu-manage-$(CONFIG_PPC_CELL_NATIVE)	+= spu_manage.o
+
 obj-$(CONFIG_SPU_BASE)			+= spu_callbacks.o spu_base.o \
 					   spu_coredump.o \
 					   $(spufs-modular-m) \
-					   $(spu-priv1-y) spufs/
+					   $(spu-priv1-y) \
+					   $(spu-manage-y) \
+					   spufs/
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index b43466b..67d617b 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -149,7 +149,8 @@
 static void invalidate_tce_cache(struct cbe_iommu *iommu, unsigned long *pte,
 		long n_ptes)
 {
-	unsigned long *reg, val;
+	unsigned long __iomem *reg;
+	unsigned long val;
 	long n;
 
 	reg = iommu->xlate_regs + IOC_IOPT_CacheInvd;
@@ -592,7 +593,7 @@
 	/* Init base fields */
 	i = cbe_nr_iommus++;
 	iommu = &iommus[i];
-	iommu->stab = 0;
+	iommu->stab = NULL;
 	iommu->nid = nid;
 	snprintf(iommu->name, sizeof(iommu->name), "iommu%d", i);
 	INIT_LIST_HEAD(&iommu->windows);
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index bd7bffc..c43999a 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -170,9 +170,11 @@
 spu_irq_class_0_bottom(struct spu *spu)
 {
 	unsigned long stat, mask;
+	unsigned long flags;
 
 	spu->class_0_pending = 0;
 
+	spin_lock_irqsave(&spu->register_lock, flags);
 	mask = spu_int_mask_get(spu, 0);
 	stat = spu_int_stat_get(spu, 0);
 
@@ -188,6 +190,7 @@
 		__spu_trap_error(spu);
 
 	spu_int_stat_clear(spu, 0, stat);
+	spin_unlock_irqrestore(&spu->register_lock, flags);
 
 	return (stat & 0x7) ? -EIO : 0;
 }
diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c
new file mode 100644
index 0000000..d8b39fe
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spu_manage.c
@@ -0,0 +1,420 @@
+/*
+ * spu management operations for of based platforms
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ * Copyright 2006 Sony Corp.
+ * (C) Copyright 2007 TOSHIBA 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.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+
+#include <asm/spu.h>
+#include <asm/spu_priv1.h>
+#include <asm/firmware.h>
+#include <asm/prom.h>
+
+#include "interrupt.h"
+
+struct device_node *spu_devnode(struct spu *spu)
+{
+	return spu->devnode;
+}
+
+EXPORT_SYMBOL_GPL(spu_devnode);
+
+static u64 __init find_spu_unit_number(struct device_node *spe)
+{
+	const unsigned int *prop;
+	int proplen;
+	prop = get_property(spe, "unit-id", &proplen);
+	if (proplen == 4)
+		return (u64)*prop;
+
+	prop = get_property(spe, "reg", &proplen);
+	if (proplen == 4)
+		return (u64)*prop;
+
+	return 0;
+}
+
+static int __init cell_spuprop_present(struct spu *spu, struct device_node *spe,
+		const char *prop)
+{
+	const struct address_prop {
+		unsigned long address;
+		unsigned int len;
+	} __attribute__((packed)) *p;
+	int proplen;
+
+	unsigned long start_pfn, nr_pages;
+	struct pglist_data *pgdata;
+	struct zone *zone;
+	int ret;
+
+	p = get_property(spe, prop, &proplen);
+	WARN_ON(proplen != sizeof (*p));
+
+	start_pfn = p->address >> PAGE_SHIFT;
+	nr_pages = ((unsigned long)p->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+	pgdata = NODE_DATA(spu->node);
+	zone = pgdata->node_zones;
+
+	ret = __add_pages(zone, start_pfn, nr_pages);
+
+	return ret;
+}
+
+static void __iomem * __init map_spe_prop(struct spu *spu,
+		struct device_node *n, const char *name)
+{
+	const struct address_prop {
+		unsigned long address;
+		unsigned int len;
+	} __attribute__((packed)) *prop;
+
+	const void *p;
+	int proplen;
+	void __iomem *ret = NULL;
+	int err = 0;
+
+	p = get_property(n, name, &proplen);
+	if (proplen != sizeof (struct address_prop))
+		return NULL;
+
+	prop = p;
+
+	err = cell_spuprop_present(spu, n, name);
+	if (err && (err != -EEXIST))
+		goto out;
+
+	ret = ioremap(prop->address, prop->len);
+
+ out:
+	return ret;
+}
+
+static void spu_unmap(struct spu *spu)
+{
+	if (!firmware_has_feature(FW_FEATURE_LPAR))
+		iounmap(spu->priv1);
+	iounmap(spu->priv2);
+	iounmap(spu->problem);
+	iounmap((__force u8 __iomem *)spu->local_store);
+}
+
+static int __init spu_map_interrupts_old(struct spu *spu,
+	struct device_node *np)
+{
+	unsigned int isrc;
+	const u32 *tmp;
+	int nid;
+
+	/* Get the interrupt source unit from the device-tree */
+	tmp = get_property(np, "isrc", NULL);
+	if (!tmp)
+		return -ENODEV;
+	isrc = tmp[0];
+
+	tmp = get_property(np->parent->parent, "node-id", NULL);
+	if (!tmp) {
+		printk(KERN_WARNING "%s: can't find node-id\n", __FUNCTION__);
+		nid = spu->node;
+	} else
+		nid = tmp[0];
+
+	/* Add the node number */
+	isrc |= nid << IIC_IRQ_NODE_SHIFT;
+
+	/* Now map interrupts of all 3 classes */
+	spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc);
+	spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc);
+	spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc);
+
+	/* Right now, we only fail if class 2 failed */
+	return spu->irqs[2] == NO_IRQ ? -EINVAL : 0;
+}
+
+static int __init spu_map_device_old(struct spu *spu)
+{
+	struct device_node *node = spu->devnode;
+	const char *prop;
+	int ret;
+
+	ret = -ENODEV;
+	spu->name = get_property(node, "name", NULL);
+	if (!spu->name)
+		goto out;
+
+	prop = get_property(node, "local-store", NULL);
+	if (!prop)
+		goto out;
+	spu->local_store_phys = *(unsigned long *)prop;
+
+	/* we use local store as ram, not io memory */
+	spu->local_store = (void __force *)
+		map_spe_prop(spu, node, "local-store");
+	if (!spu->local_store)
+		goto out;
+
+	prop = get_property(node, "problem", NULL);
+	if (!prop)
+		goto out_unmap;
+	spu->problem_phys = *(unsigned long *)prop;
+
+	spu->problem = map_spe_prop(spu, node, "problem");
+	if (!spu->problem)
+		goto out_unmap;
+
+	spu->priv2 = map_spe_prop(spu, node, "priv2");
+	if (!spu->priv2)
+		goto out_unmap;
+
+	if (!firmware_has_feature(FW_FEATURE_LPAR)) {
+		spu->priv1 = map_spe_prop(spu, node, "priv1");
+		if (!spu->priv1)
+			goto out_unmap;
+	}
+
+	ret = 0;
+	goto out;
+
+out_unmap:
+	spu_unmap(spu);
+out:
+	return ret;
+}
+
+static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
+{
+	struct of_irq oirq;
+	int ret;
+	int i;
+
+	for (i=0; i < 3; i++) {
+		ret = of_irq_map_one(np, i, &oirq);
+		if (ret) {
+			pr_debug("spu_new: failed to get irq %d\n", i);
+			goto err;
+		}
+		ret = -EINVAL;
+		pr_debug("  irq %d no 0x%x on %s\n", i, oirq.specifier[0],
+			 oirq.controller->full_name);
+		spu->irqs[i] = irq_create_of_mapping(oirq.controller,
+					oirq.specifier, oirq.size);
+		if (spu->irqs[i] == NO_IRQ) {
+			pr_debug("spu_new: failed to map it !\n");
+			goto err;
+		}
+	}
+	return 0;
+
+err:
+	pr_debug("failed to map irq %x for spu %s\n", *oirq.specifier,
+		spu->name);
+	for (; i >= 0; i--) {
+		if (spu->irqs[i] != NO_IRQ)
+			irq_dispose_mapping(spu->irqs[i]);
+	}
+	return ret;
+}
+
+static int spu_map_resource(struct spu *spu, int nr,
+			    void __iomem** virt, unsigned long *phys)
+{
+	struct device_node *np = spu->devnode;
+	unsigned long start_pfn, nr_pages;
+	struct pglist_data *pgdata;
+	struct zone *zone;
+	struct resource resource = { };
+	unsigned long len;
+	int ret;
+
+	ret = of_address_to_resource(np, nr, &resource);
+	if (ret)
+		goto out;
+
+	if (phys)
+		*phys = resource.start;
+	len = resource.end - resource.start + 1;
+	*virt = ioremap(resource.start, len);
+	if (!*virt)
+		ret = -EINVAL;
+
+	start_pfn = resource.start >> PAGE_SHIFT;
+	nr_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+	pgdata = NODE_DATA(spu->node);
+	zone = pgdata->node_zones;
+
+	ret = __add_pages(zone, start_pfn, nr_pages);
+
+out:
+	return ret;
+}
+
+static int __init spu_map_device(struct spu *spu)
+{
+	struct device_node *np = spu->devnode;
+	int ret = -ENODEV;
+
+	spu->name = get_property(np, "name", NULL);
+	if (!spu->name)
+		goto out;
+
+	ret = spu_map_resource(spu, 0, (void __iomem**)&spu->local_store,
+			       &spu->local_store_phys);
+	if (ret) {
+		pr_debug("spu_new: failed to map %s resource 0\n",
+			 np->full_name);
+		goto out;
+	}
+	ret = spu_map_resource(spu, 1, (void __iomem**)&spu->problem,
+			       &spu->problem_phys);
+	if (ret) {
+		pr_debug("spu_new: failed to map %s resource 1\n",
+			 np->full_name);
+		goto out_unmap;
+	}
+	ret = spu_map_resource(spu, 2, (void __iomem**)&spu->priv2, NULL);
+	if (ret) {
+		pr_debug("spu_new: failed to map %s resource 2\n",
+			 np->full_name);
+		goto out_unmap;
+	}
+	if (!firmware_has_feature(FW_FEATURE_LPAR))
+		ret = spu_map_resource(spu, 3,
+			       (void __iomem**)&spu->priv1, NULL);
+	if (ret) {
+		pr_debug("spu_new: failed to map %s resource 3\n",
+			 np->full_name);
+		goto out_unmap;
+	}
+	pr_debug("spu_new: %s maps:\n", np->full_name);
+	pr_debug("  local store   : 0x%016lx -> 0x%p\n",
+		 spu->local_store_phys, spu->local_store);
+	pr_debug("  problem state : 0x%016lx -> 0x%p\n",
+		 spu->problem_phys, spu->problem);
+	pr_debug("  priv2         :                       0x%p\n", spu->priv2);
+	pr_debug("  priv1         :                       0x%p\n", spu->priv1);
+
+	return 0;
+
+out_unmap:
+	spu_unmap(spu);
+out:
+	pr_debug("failed to map spe %s: %d\n", spu->name, ret);
+	return ret;
+}
+
+static int __init of_enumerate_spus(int (*fn)(void *data))
+{
+	int ret;
+	struct device_node *node;
+
+	ret = -ENODEV;
+	for (node = of_find_node_by_type(NULL, "spe");
+			node; node = of_find_node_by_type(node, "spe")) {
+		ret = fn(node);
+		if (ret) {
+			printk(KERN_WARNING "%s: Error initializing %s\n",
+				__FUNCTION__, node->name);
+			break;
+		}
+	}
+	return ret;
+}
+
+static int __init of_create_spu(struct spu *spu, void *data)
+{
+	int ret;
+	struct device_node *spe = (struct device_node *)data;
+	static int legacy_map = 0, legacy_irq = 0;
+
+	spu->devnode = of_node_get(spe);
+	spu->spe_id = find_spu_unit_number(spe);
+
+	spu->node = of_node_to_nid(spe);
+	if (spu->node >= MAX_NUMNODES) {
+		printk(KERN_WARNING "SPE %s on node %d ignored,"
+		       " node number too big\n", spe->full_name, spu->node);
+		printk(KERN_WARNING "Check if CONFIG_NUMA is enabled.\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	ret = spu_map_device(spu);
+	if (ret) {
+		if (!legacy_map) {
+			legacy_map = 1;
+			printk(KERN_WARNING "%s: Legacy device tree found, "
+				"trying to map old style\n", __FUNCTION__);
+		}
+		ret = spu_map_device_old(spu);
+		if (ret) {
+			printk(KERN_ERR "Unable to map %s\n",
+				spu->name);
+			goto out;
+		}
+	}
+
+	ret = spu_map_interrupts(spu, spe);
+	if (ret) {
+		if (!legacy_irq) {
+			legacy_irq = 1;
+			printk(KERN_WARNING "%s: Legacy device tree found, "
+				"trying old style irq\n", __FUNCTION__);
+		}
+		ret = spu_map_interrupts_old(spu, spe);
+		if (ret) {
+			printk(KERN_ERR "%s: could not map interrupts",
+				spu->name);
+			goto out_unmap;
+		}
+	}
+
+	pr_debug("Using SPE %s %p %p %p %p %d\n", spu->name,
+		spu->local_store, spu->problem, spu->priv1,
+		spu->priv2, spu->number);
+	goto out;
+
+out_unmap:
+	spu_unmap(spu);
+out:
+	return ret;
+}
+
+static int of_destroy_spu(struct spu *spu)
+{
+	spu_unmap(spu);
+	of_node_put(spu->devnode);
+	return 0;
+}
+
+const struct spu_management_ops spu_management_of_ops = {
+	.enumerate_spus = of_enumerate_spus,
+	.create_spu = of_create_spu,
+	.destroy_spu = of_destroy_spu,
+};
diff --git a/arch/powerpc/platforms/cell/spu_priv1_mmio.c b/arch/powerpc/platforms/cell/spu_priv1_mmio.c
index 910a926..67fa724 100644
--- a/arch/powerpc/platforms/cell/spu_priv1_mmio.c
+++ b/arch/powerpc/platforms/cell/spu_priv1_mmio.c
@@ -37,490 +37,112 @@
 #include "interrupt.h"
 #include "spu_priv1_mmio.h"
 
-static DEFINE_MUTEX(add_spumem_mutex);
-
-struct spu_pdata {
-	struct device_node *devnode;
-	struct spu_priv1 __iomem *priv1;
-};
-
-static struct spu_pdata *spu_get_pdata(struct spu *spu)
-{
-	BUG_ON(!spu->pdata);
-	return spu->pdata;
-}
-
-struct device_node *spu_devnode(struct spu *spu)
-{
-	return spu_get_pdata(spu)->devnode;
-}
-
-EXPORT_SYMBOL_GPL(spu_devnode);
-
-static int __init cell_spuprop_present(struct spu *spu, struct device_node *spe,
-		const char *prop)
-{
-	const struct address_prop {
-		unsigned long address;
-		unsigned int len;
-	} __attribute__((packed)) *p;
-	int proplen;
-
-	unsigned long start_pfn, nr_pages;
-	struct pglist_data *pgdata;
-	struct zone *zone;
-	int ret;
-
-	p = get_property(spe, prop, &proplen);
-	WARN_ON(proplen != sizeof (*p));
-
-	start_pfn = p->address >> PAGE_SHIFT;
-	nr_pages = ((unsigned long)p->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
-
-	pgdata = NODE_DATA(spu->node);
-	zone = pgdata->node_zones;
-
-	/* XXX rethink locking here */
-	mutex_lock(&add_spumem_mutex);
-	ret = __add_pages(zone, start_pfn, nr_pages);
-	mutex_unlock(&add_spumem_mutex);
-
-	return ret;
-}
-
-static void __iomem * __init map_spe_prop(struct spu *spu,
-		struct device_node *n, const char *name)
-{
-	const struct address_prop {
-		unsigned long address;
-		unsigned int len;
-	} __attribute__((packed)) *prop;
-
-	const void *p;
-	int proplen;
-	void __iomem *ret = NULL;
-	int err = 0;
-
-	p = get_property(n, name, &proplen);
-	if (proplen != sizeof (struct address_prop))
-		return NULL;
-
-	prop = p;
-
-	err = cell_spuprop_present(spu, n, name);
-	if (err && (err != -EEXIST))
-		goto out;
-
-	ret = ioremap(prop->address, prop->len);
-
- out:
-	return ret;
-}
-
-static void spu_unmap(struct spu *spu)
-{
-	iounmap(spu->priv2);
-	iounmap(spu_get_pdata(spu)->priv1);
-	iounmap(spu->problem);
-	iounmap((__force u8 __iomem *)spu->local_store);
-}
-
-static int __init spu_map_interrupts_old(struct spu *spu,
-	struct device_node *np)
-{
-	unsigned int isrc;
-	const u32 *tmp;
-	int nid;
-
-	/* Get the interrupt source unit from the device-tree */
-	tmp = get_property(np, "isrc", NULL);
-	if (!tmp)
-		return -ENODEV;
-	isrc = tmp[0];
-
-	tmp = get_property(np->parent->parent, "node-id", NULL);
-	if (!tmp) {
-		printk(KERN_WARNING "%s: can't find node-id\n", __FUNCTION__);
-		nid = spu->node;
-	} else
-		nid = tmp[0];
-
-	/* Add the node number */
-	isrc |= nid << IIC_IRQ_NODE_SHIFT;
-
-	/* Now map interrupts of all 3 classes */
-	spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc);
-	spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc);
-	spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc);
-
-	/* Right now, we only fail if class 2 failed */
-	return spu->irqs[2] == NO_IRQ ? -EINVAL : 0;
-}
-
-static int __init spu_map_device_old(struct spu *spu, struct device_node *node)
-{
-	const char *prop;
-	int ret;
-
-	ret = -ENODEV;
-	spu->name = get_property(node, "name", NULL);
-	if (!spu->name)
-		goto out;
-
-	prop = get_property(node, "local-store", NULL);
-	if (!prop)
-		goto out;
-	spu->local_store_phys = *(unsigned long *)prop;
-
-	/* we use local store as ram, not io memory */
-	spu->local_store = (void __force *)
-		map_spe_prop(spu, node, "local-store");
-	if (!spu->local_store)
-		goto out;
-
-	prop = get_property(node, "problem", NULL);
-	if (!prop)
-		goto out_unmap;
-	spu->problem_phys = *(unsigned long *)prop;
-
-	spu->problem= map_spe_prop(spu, node, "problem");
-	if (!spu->problem)
-		goto out_unmap;
-
-	spu_get_pdata(spu)->priv1= map_spe_prop(spu, node, "priv1");
-
-	spu->priv2= map_spe_prop(spu, node, "priv2");
-	if (!spu->priv2)
-		goto out_unmap;
-	ret = 0;
-	goto out;
-
-out_unmap:
-	spu_unmap(spu);
-out:
-	return ret;
-}
-
-static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
-{
-	struct of_irq oirq;
-	int ret;
-	int i;
-
-	for (i=0; i < 3; i++) {
-		ret = of_irq_map_one(np, i, &oirq);
-		if (ret) {
-			pr_debug("spu_new: failed to get irq %d\n", i);
-			goto err;
-		}
-		ret = -EINVAL;
-		pr_debug("  irq %d no 0x%x on %s\n", i, oirq.specifier[0],
-			 oirq.controller->full_name);
-		spu->irqs[i] = irq_create_of_mapping(oirq.controller,
-					oirq.specifier, oirq.size);
-		if (spu->irqs[i] == NO_IRQ) {
-			pr_debug("spu_new: failed to map it !\n");
-			goto err;
-		}
-	}
-	return 0;
-
-err:
-	pr_debug("failed to map irq %x for spu %s\n", *oirq.specifier,
-		spu->name);
-	for (; i >= 0; i--) {
-		if (spu->irqs[i] != NO_IRQ)
-			irq_dispose_mapping(spu->irqs[i]);
-	}
-	return ret;
-}
-
-static int spu_map_resource(struct spu *spu, int nr,
-			    void __iomem** virt, unsigned long *phys)
-{
-	struct device_node *np = spu_get_pdata(spu)->devnode;
-	unsigned long start_pfn, nr_pages;
-	struct pglist_data *pgdata;
-	struct zone *zone;
-	struct resource resource = { };
-	unsigned long len;
-	int ret;
-
-	ret = of_address_to_resource(np, nr, &resource);
-	if (ret)
-		goto out;
-
-	if (phys)
-		*phys = resource.start;
-	len = resource.end - resource.start + 1;
-	*virt = ioremap(resource.start, len);
-	if (!*virt)
-		ret = -EINVAL;
-
-	start_pfn = resource.start >> PAGE_SHIFT;
-	nr_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
-
-	pgdata = NODE_DATA(spu->node);
-	zone = pgdata->node_zones;
-
-	/* XXX rethink locking here */
-	mutex_lock(&add_spumem_mutex);
-	ret = __add_pages(zone, start_pfn, nr_pages);
-	mutex_unlock(&add_spumem_mutex);
-
-out:
-	return ret;
-}
-
-static int __init spu_map_device(struct spu *spu)
-{
-	struct device_node *np = spu_get_pdata(spu)->devnode;
-	int ret = -ENODEV;
-
-	spu->name = get_property(np, "name", NULL);
-	if (!spu->name)
-		goto out;
-
-	ret = spu_map_resource(spu, 0, (void __iomem**)&spu->local_store,
-			       &spu->local_store_phys);
-	if (ret) {
-		pr_debug("spu_new: failed to map %s resource 0\n",
-			 np->full_name);
-		goto out;
-	}
-	ret = spu_map_resource(spu, 1, (void __iomem**)&spu->problem,
-			       &spu->problem_phys);
-	if (ret) {
-		pr_debug("spu_new: failed to map %s resource 1\n",
-			 np->full_name);
-		goto out_unmap;
-	}
-	ret = spu_map_resource(spu, 2, (void __iomem**)&spu->priv2, NULL);
-	if (ret) {
-		pr_debug("spu_new: failed to map %s resource 2\n",
-			 np->full_name);
-		goto out_unmap;
-	}
-	if (!firmware_has_feature(FW_FEATURE_LPAR))
-		ret = spu_map_resource(spu, 3,
-			       (void __iomem**)&spu_get_pdata(spu)->priv1, NULL);
-	if (ret) {
-		pr_debug("spu_new: failed to map %s resource 3\n",
-			 np->full_name);
-		goto out_unmap;
-	}
-	pr_debug("spu_new: %s maps:\n", np->full_name);
-	pr_debug("  local store   : 0x%016lx -> 0x%p\n",
-		 spu->local_store_phys, spu->local_store);
-	pr_debug("  problem state : 0x%016lx -> 0x%p\n",
-		 spu->problem_phys, spu->problem);
-	pr_debug("  priv2         :                       0x%p\n", spu->priv2);
-	pr_debug("  priv1         :                       0x%p\n",
-		 spu_get_pdata(spu)->priv1);
-
-	return 0;
-
-out_unmap:
-	spu_unmap(spu);
-out:
-	pr_debug("failed to map spe %s: %d\n", spu->name, ret);
-	return ret;
-}
-
-static int __init of_enumerate_spus(int (*fn)(void *data))
-{
-	int ret;
-	struct device_node *node;
-
-	ret = -ENODEV;
-	for (node = of_find_node_by_type(NULL, "spe");
-			node; node = of_find_node_by_type(node, "spe")) {
-		ret = fn(node);
-		if (ret) {
-			printk(KERN_WARNING "%s: Error initializing %s\n",
-				__FUNCTION__, node->name);
-			break;
-		}
-	}
-	return ret;
-}
-
-static int __init of_create_spu(struct spu *spu, void *data)
-{
-	int ret;
-	struct device_node *spe = (struct device_node *)data;
-
-	spu->pdata = kzalloc(sizeof(struct spu_pdata),
-		GFP_KERNEL);
-	if (!spu->pdata) {
-		ret = -ENOMEM;
-		goto out;
-	}
-	spu_get_pdata(spu)->devnode = of_node_get(spe);
-
-	spu->node = of_node_to_nid(spe);
-	if (spu->node >= MAX_NUMNODES) {
-		printk(KERN_WARNING "SPE %s on node %d ignored,"
-		       " node number too big\n", spe->full_name, spu->node);
-		printk(KERN_WARNING "Check if CONFIG_NUMA is enabled.\n");
-		ret = -ENODEV;
-		goto out_free;
-	}
-
-	ret = spu_map_device(spu);
-	/* try old method */
-	if (ret)
-		ret = spu_map_device_old(spu, spe);
-	if (ret)
-		goto out_free;
-
-	ret = spu_map_interrupts(spu, spe);
-	if (ret)
-		ret = spu_map_interrupts_old(spu, spe);
-	if (ret)
-		goto out_unmap;
-
-	pr_debug(KERN_DEBUG "Using SPE %s %p %p %p %p %d\n", spu->name,
-		spu->local_store, spu->problem, spu_get_pdata(spu)->priv1,
-		spu->priv2, spu->number);
-	goto out;
-
-out_unmap:
-	spu_unmap(spu);
-out_free:
-	kfree(spu->pdata);
-	spu->pdata = NULL;
-out:
-	return ret;
-}
-
-static int of_destroy_spu(struct spu *spu)
-{
-	spu_unmap(spu);
-	of_node_put(spu_get_pdata(spu)->devnode);
-	kfree(spu->pdata);
-	spu->pdata = NULL;
-	return 0;
-}
-
-const struct spu_management_ops spu_management_of_ops = {
-	.enumerate_spus = of_enumerate_spus,
-	.create_spu = of_create_spu,
-	.destroy_spu = of_destroy_spu,
-};
-
 static void int_mask_and(struct spu *spu, int class, u64 mask)
 {
 	u64 old_mask;
 
-	old_mask = in_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class]);
-	out_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class],
-		old_mask & mask);
+	old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
+	out_be64(&spu->priv1->int_mask_RW[class], old_mask & mask);
 }
 
 static void int_mask_or(struct spu *spu, int class, u64 mask)
 {
 	u64 old_mask;
 
-	old_mask = in_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class]);
-	out_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class],
-		old_mask | mask);
+	old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
+	out_be64(&spu->priv1->int_mask_RW[class], old_mask | mask);
 }
 
 static void int_mask_set(struct spu *spu, int class, u64 mask)
 {
-	out_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class], mask);
+	out_be64(&spu->priv1->int_mask_RW[class], mask);
 }
 
 static u64 int_mask_get(struct spu *spu, int class)
 {
-	return in_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class]);
+	return in_be64(&spu->priv1->int_mask_RW[class]);
 }
 
 static void int_stat_clear(struct spu *spu, int class, u64 stat)
 {
-	out_be64(&spu_get_pdata(spu)->priv1->int_stat_RW[class], stat);
+	out_be64(&spu->priv1->int_stat_RW[class], stat);
 }
 
 static u64 int_stat_get(struct spu *spu, int class)
 {
-	return in_be64(&spu_get_pdata(spu)->priv1->int_stat_RW[class]);
+	return in_be64(&spu->priv1->int_stat_RW[class]);
 }
 
 static void cpu_affinity_set(struct spu *spu, int cpu)
 {
 	u64 target = iic_get_target_id(cpu);
 	u64 route = target << 48 | target << 32 | target << 16;
-	out_be64(&spu_get_pdata(spu)->priv1->int_route_RW, route);
+	out_be64(&spu->priv1->int_route_RW, route);
 }
 
 static u64 mfc_dar_get(struct spu *spu)
 {
-	return in_be64(&spu_get_pdata(spu)->priv1->mfc_dar_RW);
+	return in_be64(&spu->priv1->mfc_dar_RW);
 }
 
 static u64 mfc_dsisr_get(struct spu *spu)
 {
-	return in_be64(&spu_get_pdata(spu)->priv1->mfc_dsisr_RW);
+	return in_be64(&spu->priv1->mfc_dsisr_RW);
 }
 
 static void mfc_dsisr_set(struct spu *spu, u64 dsisr)
 {
-	out_be64(&spu_get_pdata(spu)->priv1->mfc_dsisr_RW, dsisr);
+	out_be64(&spu->priv1->mfc_dsisr_RW, dsisr);
 }
 
 static void mfc_sdr_setup(struct spu *spu)
 {
-	out_be64(&spu_get_pdata(spu)->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1));
+	out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1));
 }
 
 static void mfc_sr1_set(struct spu *spu, u64 sr1)
 {
-	out_be64(&spu_get_pdata(spu)->priv1->mfc_sr1_RW, sr1);
+	out_be64(&spu->priv1->mfc_sr1_RW, sr1);
 }
 
 static u64 mfc_sr1_get(struct spu *spu)
 {
-	return in_be64(&spu_get_pdata(spu)->priv1->mfc_sr1_RW);
+	return in_be64(&spu->priv1->mfc_sr1_RW);
 }
 
 static void mfc_tclass_id_set(struct spu *spu, u64 tclass_id)
 {
-	out_be64(&spu_get_pdata(spu)->priv1->mfc_tclass_id_RW, tclass_id);
+	out_be64(&spu->priv1->mfc_tclass_id_RW, tclass_id);
 }
 
 static u64 mfc_tclass_id_get(struct spu *spu)
 {
-	return in_be64(&spu_get_pdata(spu)->priv1->mfc_tclass_id_RW);
+	return in_be64(&spu->priv1->mfc_tclass_id_RW);
 }
 
 static void tlb_invalidate(struct spu *spu)
 {
-	out_be64(&spu_get_pdata(spu)->priv1->tlb_invalidate_entry_W, 0ul);
+	out_be64(&spu->priv1->tlb_invalidate_entry_W, 0ul);
 }
 
 static void resource_allocation_groupID_set(struct spu *spu, u64 id)
 {
-	out_be64(&spu_get_pdata(spu)->priv1->resource_allocation_groupID_RW,
-		id);
+	out_be64(&spu->priv1->resource_allocation_groupID_RW, id);
 }
 
 static u64 resource_allocation_groupID_get(struct spu *spu)
 {
-	return in_be64(
-		&spu_get_pdata(spu)->priv1->resource_allocation_groupID_RW);
+	return in_be64(&spu->priv1->resource_allocation_groupID_RW);
 }
 
 static void resource_allocation_enable_set(struct spu *spu, u64 enable)
 {
-	out_be64(&spu_get_pdata(spu)->priv1->resource_allocation_enable_RW,
-		enable);
+	out_be64(&spu->priv1->resource_allocation_enable_RW, enable);
 }
 
 static u64 resource_allocation_enable_get(struct spu *spu)
 {
-	return in_be64(
-		&spu_get_pdata(spu)->priv1->resource_allocation_enable_RW);
+	return in_be64(&spu->priv1->resource_allocation_enable_RW);
 }
 
 const struct spu_priv1_ops spu_priv1_mmio_ops =
diff --git a/arch/powerpc/platforms/celleb/Makefile b/arch/powerpc/platforms/celleb/Makefile
new file mode 100644
index 0000000..3baf658
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/Makefile
@@ -0,0 +1,9 @@
+obj-y				+= interrupt.o iommu.o setup.o \
+				   htab.o beat.o pci.o \
+				   scc_epci.o hvCall.o
+
+obj-$(CONFIG_SMP)		+= smp.o
+obj-$(CONFIG_PPC_UDBG_BEAT)	+= udbg_beat.o
+obj-$(CONFIG_USB)		+= scc_uhc.o
+obj-$(CONFIG_HAS_TXX9_SERIAL)	+= scc_sio.o
+obj-$(CONFIG_SPU_BASE)		+= spu_priv1.o
diff --git a/arch/powerpc/platforms/celleb/beat.c b/arch/powerpc/platforms/celleb/beat.c
new file mode 100644
index 0000000..99341ce
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/beat.c
@@ -0,0 +1,163 @@
+/*
+ * Simple routines for Celleb/Beat
+ *
+ * (C) Copyright 2006-2007 TOSHIBA 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; 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/rtc.h>
+
+#include <asm/hvconsole.h>
+#include <asm/time.h>
+
+#include "beat_wrapper.h"
+#include "beat.h"
+
+void beat_restart(char *cmd)
+{
+	beat_shutdown_logical_partition(1);
+}
+
+void beat_power_off(void)
+{
+	beat_shutdown_logical_partition(0);
+}
+
+u64 beat_halt_code = 0x1000000000000000UL;
+
+void beat_halt(void)
+{
+	beat_shutdown_logical_partition(beat_halt_code);
+}
+
+int beat_set_rtc_time(struct rtc_time *rtc_time)
+{
+	u64 tim;
+	tim = mktime(rtc_time->tm_year+1900,
+		     rtc_time->tm_mon+1, rtc_time->tm_mday,
+		     rtc_time->tm_hour, rtc_time->tm_min, rtc_time->tm_sec);
+	if (beat_rtc_write(tim))
+		return -1;
+	return 0;
+}
+
+void beat_get_rtc_time(struct rtc_time *rtc_time)
+{
+	u64 tim;
+
+	if (beat_rtc_read(&tim))
+		tim = 0;
+	to_tm(tim, rtc_time);
+	rtc_time->tm_year -= 1900;
+	rtc_time->tm_mon -= 1;
+}
+
+#define	BEAT_NVRAM_SIZE	4096
+
+ssize_t beat_nvram_read(char *buf, size_t count, loff_t *index)
+{
+	unsigned int i;
+	unsigned long len;
+	char *p = buf;
+
+	if (*index >= BEAT_NVRAM_SIZE)
+		return -ENODEV;
+	i = *index;
+	if (i + count > BEAT_NVRAM_SIZE)
+		count = BEAT_NVRAM_SIZE - i;
+
+	for (; count != 0; count -= len) {
+		len = count;
+		if (len > BEAT_NVRW_CNT)
+			len = BEAT_NVRW_CNT;
+		if (beat_eeprom_read(i, len, p)) {
+			return -EIO;
+		}
+
+		p += len;
+		i += len;
+	}
+	*index = i;
+	return p - buf;
+}
+
+ssize_t beat_nvram_write(char *buf, size_t count, loff_t *index)
+{
+	unsigned int i;
+	unsigned long len;
+	char *p = buf;
+
+	if (*index >= BEAT_NVRAM_SIZE)
+		return -ENODEV;
+	i = *index;
+	if (i + count > BEAT_NVRAM_SIZE)
+		count = BEAT_NVRAM_SIZE - i;
+
+	for (; count != 0; count -= len) {
+		len = count;
+		if (len > BEAT_NVRW_CNT)
+			len = BEAT_NVRW_CNT;
+		if (beat_eeprom_write(i, len, p)) {
+			return -EIO;
+		}
+
+		p += len;
+		i += len;
+	}
+	*index = i;
+	return p - buf;
+}
+
+ssize_t beat_nvram_get_size(void)
+{
+	return BEAT_NVRAM_SIZE;
+}
+
+int beat_set_xdabr(unsigned long dabr)
+{
+	if (beat_set_dabr(dabr, DABRX_KERNEL | DABRX_USER))
+		return -1;
+	return 0;
+}
+
+int64_t beat_get_term_char(u64 vterm, u64 *len, u64 *t1, u64 *t2)
+{
+	u64 db[2];
+	s64 ret;
+
+	ret = beat_get_characters_from_console(vterm, len, (u8*)db);
+	if (ret == 0) {
+		*t1 = db[0];
+		*t2 = db[1];
+	}
+	return ret;
+}
+
+int64_t beat_put_term_char(u64 vterm, u64 len, u64 t1, u64 t2)
+{
+	u64 db[2];
+
+	db[0] = t1;
+	db[1] = t2;
+	return beat_put_characters_to_console(vterm, len, (u8*)db);
+}
+
+EXPORT_SYMBOL(beat_get_term_char);
+EXPORT_SYMBOL(beat_put_term_char);
+EXPORT_SYMBOL(beat_halt_code);
diff --git a/arch/powerpc/platforms/celleb/beat.h b/arch/powerpc/platforms/celleb/beat.h
new file mode 100644
index 0000000..2b16bf3
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/beat.h
@@ -0,0 +1,40 @@
+/*
+ * Guest OS Interfaces.
+ *
+ * (C) Copyright 2006 TOSHIBA 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; 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CELLEB_BEAT_H
+#define _CELLEB_BEAT_H
+
+#define DABRX_KERNEL		(1UL<<1)
+#define DABRX_USER		(1UL<<0)
+
+int64_t beat_get_term_char(uint64_t,uint64_t*,uint64_t*,uint64_t*);
+int64_t beat_put_term_char(uint64_t,uint64_t,uint64_t,uint64_t);
+int64_t beat_repository_encode(int, const char *, uint64_t[4]);
+void beat_restart(char *);
+void beat_power_off(void);
+void beat_halt(void);
+int beat_set_rtc_time(struct rtc_time *);
+void beat_get_rtc_time(struct rtc_time *);
+ssize_t beat_nvram_get_size(void);
+ssize_t beat_nvram_read(char *, size_t, loff_t *);
+ssize_t beat_nvram_write(char *, size_t, loff_t *);
+int beat_set_xdabr(unsigned long);
+
+#endif /* _CELLEB_BEAT_H */
diff --git a/arch/powerpc/platforms/celleb/beat_syscall.h b/arch/powerpc/platforms/celleb/beat_syscall.h
new file mode 100644
index 0000000..14e1697
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/beat_syscall.h
@@ -0,0 +1,160 @@
+/*
+ * Beat hypervisor call numbers
+ *
+ * (C) Copyright 2004-2007 TOSHIBA 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; 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef BEAT_BEAT_syscall_H
+#define BEAT_BEAT_syscall_H
+
+#ifdef	__ASSEMBLY__
+#define	__BEAT_ADD_VENDOR_ID(__x, __v)	((__v)<<60|(__x))
+#else
+#define	__BEAT_ADD_VENDOR_ID(__x, __v)	((u64)(__v)<<60|(__x))
+#endif
+#define HV_allocate_memory __BEAT_ADD_VENDOR_ID(0, 0)
+#define HV_construct_virtual_address_space __BEAT_ADD_VENDOR_ID(2, 0)
+#define HV_destruct_virtual_address_space __BEAT_ADD_VENDOR_ID(10, 0)
+#define HV_get_virtual_address_space_id_of_ppe __BEAT_ADD_VENDOR_ID(4, 0)
+#define HV_query_logical_partition_address_region_info 			\
+						__BEAT_ADD_VENDOR_ID(6, 0)
+#define HV_release_memory __BEAT_ADD_VENDOR_ID(13, 0)
+#define HV_select_virtual_address_space __BEAT_ADD_VENDOR_ID(7, 0)
+#define HV_load_range_registers __BEAT_ADD_VENDOR_ID(68, 0)
+#define HV_set_ppe_l2cache_rmt_entry __BEAT_ADD_VENDOR_ID(70, 0)
+#define HV_set_ppe_tlb_rmt_entry __BEAT_ADD_VENDOR_ID(71, 0)
+#define HV_set_spe_tlb_rmt_entry __BEAT_ADD_VENDOR_ID(72, 0)
+#define HV_get_io_address_translation_fault_info __BEAT_ADD_VENDOR_ID(14, 0)
+#define HV_get_iopte __BEAT_ADD_VENDOR_ID(16, 0)
+#define HV_preload_iopt_cache __BEAT_ADD_VENDOR_ID(17, 0)
+#define HV_put_iopte __BEAT_ADD_VENDOR_ID(15, 0)
+#define HV_connect_event_ports __BEAT_ADD_VENDOR_ID(21, 0)
+#define HV_construct_event_receive_port __BEAT_ADD_VENDOR_ID(18, 0)
+#define HV_destruct_event_receive_port __BEAT_ADD_VENDOR_ID(19, 0)
+#define HV_destruct_event_send_port __BEAT_ADD_VENDOR_ID(22, 0)
+#define HV_get_state_of_event_send_port __BEAT_ADD_VENDOR_ID(25, 0)
+#define HV_request_to_connect_event_ports __BEAT_ADD_VENDOR_ID(20, 0)
+#define HV_send_event_externally __BEAT_ADD_VENDOR_ID(23, 0)
+#define HV_send_event_locally __BEAT_ADD_VENDOR_ID(24, 0)
+#define HV_construct_and_connect_irq_plug __BEAT_ADD_VENDOR_ID(28, 0)
+#define HV_destruct_irq_plug __BEAT_ADD_VENDOR_ID(29, 0)
+#define HV_detect_pending_interrupts __BEAT_ADD_VENDOR_ID(26, 0)
+#define HV_end_of_interrupt __BEAT_ADD_VENDOR_ID(27, 0)
+#define HV_assign_control_signal_notification_port __BEAT_ADD_VENDOR_ID(45, 0)
+#define HV_end_of_control_signal_processing __BEAT_ADD_VENDOR_ID(48, 0)
+#define HV_get_control_signal __BEAT_ADD_VENDOR_ID(46, 0)
+#define HV_set_irq_mask_for_spe __BEAT_ADD_VENDOR_ID(61, 0)
+#define HV_shutdown_logical_partition __BEAT_ADD_VENDOR_ID(44, 0)
+#define HV_connect_message_ports __BEAT_ADD_VENDOR_ID(35, 0)
+#define HV_destruct_message_port __BEAT_ADD_VENDOR_ID(36, 0)
+#define HV_receive_message __BEAT_ADD_VENDOR_ID(37, 0)
+#define HV_get_message_port_info __BEAT_ADD_VENDOR_ID(34, 0)
+#define HV_request_to_connect_message_ports __BEAT_ADD_VENDOR_ID(33, 0)
+#define HV_send_message __BEAT_ADD_VENDOR_ID(32, 0)
+#define HV_get_logical_ppe_id __BEAT_ADD_VENDOR_ID(69, 0)
+#define HV_pause __BEAT_ADD_VENDOR_ID(9, 0)
+#define HV_destruct_shared_memory_handle __BEAT_ADD_VENDOR_ID(51, 0)
+#define HV_get_shared_memory_info __BEAT_ADD_VENDOR_ID(52, 0)
+#define HV_permit_sharing_memory __BEAT_ADD_VENDOR_ID(50, 0)
+#define HV_request_to_attach_shared_memory __BEAT_ADD_VENDOR_ID(49, 0)
+#define HV_enable_logical_spe_execution __BEAT_ADD_VENDOR_ID(55, 0)
+#define HV_construct_logical_spe __BEAT_ADD_VENDOR_ID(53, 0)
+#define HV_disable_logical_spe_execution __BEAT_ADD_VENDOR_ID(56, 0)
+#define HV_destruct_logical_spe __BEAT_ADD_VENDOR_ID(54, 0)
+#define HV_sense_spe_execution_status __BEAT_ADD_VENDOR_ID(58, 0)
+#define HV_insert_htab_entry __BEAT_ADD_VENDOR_ID(101, 0)
+#define HV_read_htab_entries __BEAT_ADD_VENDOR_ID(95, 0)
+#define HV_write_htab_entry __BEAT_ADD_VENDOR_ID(94, 0)
+#define HV_assign_io_address_translation_fault_port 			\
+						__BEAT_ADD_VENDOR_ID(100, 0)
+#define HV_set_interrupt_mask __BEAT_ADD_VENDOR_ID(73, 0)
+#define HV_get_logical_partition_id __BEAT_ADD_VENDOR_ID(74, 0)
+#define HV_create_repository_node2 __BEAT_ADD_VENDOR_ID(90, 0)
+#define HV_create_repository_node __BEAT_ADD_VENDOR_ID(90, 0) /* alias */
+#define HV_get_repository_node_value2 __BEAT_ADD_VENDOR_ID(91, 0)
+#define HV_get_repository_node_value __BEAT_ADD_VENDOR_ID(91, 0) /* alias */
+#define HV_modify_repository_node_value2 __BEAT_ADD_VENDOR_ID(92, 0)
+#define HV_modify_repository_node_value __BEAT_ADD_VENDOR_ID(92, 0) /* alias */
+#define HV_remove_repository_node2 __BEAT_ADD_VENDOR_ID(93, 0)
+#define HV_remove_repository_node __BEAT_ADD_VENDOR_ID(93, 0) /* alias */
+#define HV_cancel_shared_memory __BEAT_ADD_VENDOR_ID(104, 0)
+#define HV_clear_interrupt_status_of_spe __BEAT_ADD_VENDOR_ID(206, 0)
+#define HV_construct_spe_irq_outlet __BEAT_ADD_VENDOR_ID(80, 0)
+#define HV_destruct_spe_irq_outlet __BEAT_ADD_VENDOR_ID(81, 0)
+#define HV_disconnect_ipspc_service __BEAT_ADD_VENDOR_ID(88, 0)
+#define HV_execute_ipspc_command __BEAT_ADD_VENDOR_ID(86, 0)
+#define HV_get_interrupt_status_of_spe __BEAT_ADD_VENDOR_ID(205, 0)
+#define HV_get_spe_privileged_state_1_registers __BEAT_ADD_VENDOR_ID(208, 0)
+#define HV_permit_use_of_ipspc_service __BEAT_ADD_VENDOR_ID(85, 0)
+#define HV_reinitialize_logical_spe __BEAT_ADD_VENDOR_ID(82, 0)
+#define HV_request_ipspc_service __BEAT_ADD_VENDOR_ID(84, 0)
+#define HV_stop_ipspc_command __BEAT_ADD_VENDOR_ID(87, 0)
+#define HV_set_spe_privileged_state_1_registers __BEAT_ADD_VENDOR_ID(204, 0)
+#define HV_get_status_of_ipspc_service __BEAT_ADD_VENDOR_ID(203, 0)
+#define HV_put_characters_to_console __BEAT_ADD_VENDOR_ID(0x101, 1)
+#define HV_get_characters_from_console __BEAT_ADD_VENDOR_ID(0x102, 1)
+#define HV_get_base_clock __BEAT_ADD_VENDOR_ID(0x111, 1)
+#define HV_set_base_clock __BEAT_ADD_VENDOR_ID(0x112, 1)
+#define HV_get_frame_cycle __BEAT_ADD_VENDOR_ID(0x114, 1)
+#define HV_disable_console __BEAT_ADD_VENDOR_ID(0x115, 1)
+#define HV_disable_all_console __BEAT_ADD_VENDOR_ID(0x116, 1)
+#define HV_oneshot_timer __BEAT_ADD_VENDOR_ID(0x117, 1)
+#define HV_set_dabr __BEAT_ADD_VENDOR_ID(0x118, 1)
+#define HV_get_dabr __BEAT_ADD_VENDOR_ID(0x119, 1)
+#define HV_start_hv_stats __BEAT_ADD_VENDOR_ID(0x21c, 1)
+#define HV_stop_hv_stats __BEAT_ADD_VENDOR_ID(0x21d, 1)
+#define HV_get_hv_stats __BEAT_ADD_VENDOR_ID(0x21e, 1)
+#define HV_get_hv_error_stats __BEAT_ADD_VENDOR_ID(0x221, 1)
+#define HV_get_stats __BEAT_ADD_VENDOR_ID(0x224, 1)
+#define HV_get_heap_stats __BEAT_ADD_VENDOR_ID(0x225, 1)
+#define HV_get_memory_stats __BEAT_ADD_VENDOR_ID(0x227, 1)
+#define HV_get_memory_detail __BEAT_ADD_VENDOR_ID(0x228, 1)
+#define HV_set_priority_of_irq_outlet __BEAT_ADD_VENDOR_ID(0x122, 1)
+#define HV_get_physical_spe_by_reservation_id __BEAT_ADD_VENDOR_ID(0x128, 1)
+#define HV_get_spe_context __BEAT_ADD_VENDOR_ID(0x129, 1)
+#define HV_set_spe_context __BEAT_ADD_VENDOR_ID(0x12a, 1)
+#define HV_downcount_of_interrupt __BEAT_ADD_VENDOR_ID(0x12e, 1)
+#define HV_peek_spe_context __BEAT_ADD_VENDOR_ID(0x12f, 1)
+#define HV_read_bpa_register __BEAT_ADD_VENDOR_ID(0x131, 1)
+#define HV_write_bpa_register __BEAT_ADD_VENDOR_ID(0x132, 1)
+#define HV_map_context_table_of_spe __BEAT_ADD_VENDOR_ID(0x137, 1)
+#define HV_get_slb_for_logical_spe __BEAT_ADD_VENDOR_ID(0x138, 1)
+#define HV_set_slb_for_logical_spe __BEAT_ADD_VENDOR_ID(0x139, 1)
+#define HV_init_pm __BEAT_ADD_VENDOR_ID(0x150, 1)
+#define HV_set_pm_signal __BEAT_ADD_VENDOR_ID(0x151, 1)
+#define HV_get_pm_signal __BEAT_ADD_VENDOR_ID(0x152, 1)
+#define HV_set_pm_config __BEAT_ADD_VENDOR_ID(0x153, 1)
+#define HV_get_pm_config __BEAT_ADD_VENDOR_ID(0x154, 1)
+#define HV_get_inner_trace_data __BEAT_ADD_VENDOR_ID(0x155, 1)
+#define HV_set_ext_trace_buffer __BEAT_ADD_VENDOR_ID(0x156, 1)
+#define HV_get_ext_trace_buffer __BEAT_ADD_VENDOR_ID(0x157, 1)
+#define HV_set_pm_interrupt __BEAT_ADD_VENDOR_ID(0x158, 1)
+#define HV_get_pm_interrupt __BEAT_ADD_VENDOR_ID(0x159, 1)
+#define HV_kick_pm __BEAT_ADD_VENDOR_ID(0x160, 1)
+#define HV_construct_pm_context __BEAT_ADD_VENDOR_ID(0x164, 1)
+#define HV_destruct_pm_context __BEAT_ADD_VENDOR_ID(0x165, 1)
+#define HV_be_slow __BEAT_ADD_VENDOR_ID(0x170, 1)
+#define HV_assign_ipspc_server_connection_status_notification_port 	\
+						__BEAT_ADD_VENDOR_ID(0x173, 1)
+#define HV_get_raid_of_physical_spe __BEAT_ADD_VENDOR_ID(0x174, 1)
+#define HV_set_physical_spe_to_rag __BEAT_ADD_VENDOR_ID(0x175, 1)
+#define HV_release_physical_spe_from_rag __BEAT_ADD_VENDOR_ID(0x176, 1)
+#define HV_rtc_read __BEAT_ADD_VENDOR_ID(0x190, 1)
+#define HV_rtc_write __BEAT_ADD_VENDOR_ID(0x191, 1)
+#define HV_eeprom_read __BEAT_ADD_VENDOR_ID(0x192, 1)
+#define HV_eeprom_write __BEAT_ADD_VENDOR_ID(0x193, 1)
+#endif
diff --git a/arch/powerpc/platforms/celleb/beat_wrapper.h b/arch/powerpc/platforms/celleb/beat_wrapper.h
new file mode 100644
index 0000000..76ea0a6
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/beat_wrapper.h
@@ -0,0 +1,220 @@
+/*
+ * Beat hypervisor call I/F
+ *
+ * (C) Copyright 2007 TOSHIBA CORPORATION
+ *
+ * This code is based on arch/powerpc/platforms/pseries/plpar_wrapper.h.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef BEAT_HCALL
+#include "beat_syscall.h"
+
+/* defined in hvCall.S */
+extern s64 beat_hcall_norets(u64 opcode, ...);
+extern s64 beat_hcall_norets8(u64 opcode, u64 arg1, u64 arg2, u64 arg3,
+	u64 arg4, u64 arg5, u64 arg6, u64 arg7, u64 arg8);
+extern s64 beat_hcall1(u64 opcode, u64 retbuf[1], ...);
+extern s64 beat_hcall2(u64 opcode, u64 retbuf[2], ...);
+extern s64 beat_hcall3(u64 opcode, u64 retbuf[3], ...);
+extern s64 beat_hcall4(u64 opcode, u64 retbuf[4], ...);
+extern s64 beat_hcall5(u64 opcode, u64 retbuf[5], ...);
+extern s64 beat_hcall6(u64 opcode, u64 retbuf[6], ...);
+
+static inline s64 beat_downcount_of_interrupt(u64 plug_id)
+{
+	return beat_hcall_norets(HV_downcount_of_interrupt, plug_id);
+}
+
+static inline s64 beat_set_interrupt_mask(u64 index,
+	u64 val0, u64 val1, u64 val2, u64 val3)
+{
+	return beat_hcall_norets(HV_set_interrupt_mask, index,
+	       val0, val1, val2, val3);
+}
+
+static inline s64 beat_destruct_irq_plug(u64 plug_id)
+{
+	return beat_hcall_norets(HV_destruct_irq_plug, plug_id);
+}
+
+static inline s64 beat_construct_and_connect_irq_plug(u64 plug_id,
+	u64 outlet_id)
+{
+	return beat_hcall_norets(HV_construct_and_connect_irq_plug, plug_id,
+	       outlet_id);
+}
+
+static inline s64 beat_detect_pending_interrupts(u64 index, u64 *retbuf)
+{
+	return beat_hcall4(HV_detect_pending_interrupts, retbuf, index);
+}
+
+static inline s64 beat_pause(u64 style)
+{
+	return beat_hcall_norets(HV_pause, style);
+}
+
+static inline s64 beat_read_htab_entries(u64 htab_id, u64 index, u64 *retbuf)
+{
+	return beat_hcall5(HV_read_htab_entries, retbuf, htab_id, index);
+}
+
+static inline s64 beat_insert_htab_entry(u64 htab_id, u64 group,
+	u64 bitmask, u64 hpte_v, u64 hpte_r, u64 *slot)
+{
+	u64 dummy[3];
+	s64 ret;
+
+	ret = beat_hcall3(HV_insert_htab_entry, dummy, htab_id, group,
+		bitmask, hpte_v, hpte_r);
+	*slot = dummy[0];
+	return ret;
+}
+
+static inline s64 beat_write_htab_entry(u64 htab_id, u64 slot,
+	u64 hpte_v, u64 hpte_r, u64 mask_v, u64 mask_r,
+	u64 *ret_v, u64 *ret_r)
+{
+	u64 dummy[2];
+	s64 ret;
+
+	ret = beat_hcall2(HV_write_htab_entry, dummy, htab_id, slot,
+		hpte_v, hpte_r, mask_v, mask_r);
+	*ret_v = dummy[0];
+	*ret_r = dummy[1];
+	return ret;
+}
+
+static inline void beat_shutdown_logical_partition(u64 code)
+{
+	(void)beat_hcall_norets(HV_shutdown_logical_partition, code);
+}
+
+static inline s64 beat_rtc_write(u64 time_from_epoch)
+{
+	return beat_hcall_norets(HV_rtc_write, time_from_epoch);
+}
+
+static inline s64 beat_rtc_read(u64 *time_from_epoch)
+{
+	u64 dummy[1];
+	s64 ret;
+
+	ret = beat_hcall1(HV_rtc_read, dummy);
+	*time_from_epoch = dummy[0];
+	return ret;
+}
+
+#define	BEAT_NVRW_CNT	(sizeof(u64) * 6)
+
+static inline s64 beat_eeprom_write(u64 index, u64 length, u8 *buffer)
+{
+	u64	b[6];
+
+	if (length > BEAT_NVRW_CNT)
+		return -1;
+	memcpy(b, buffer, sizeof(b));
+	return beat_hcall_norets8(HV_eeprom_write, index, length,
+		b[0], b[1], b[2], b[3], b[4], b[5]);
+}
+
+static inline s64 beat_eeprom_read(u64 index, u64 length, u8 *buffer)
+{
+	u64	b[6];
+	s64	ret;
+
+	if (length > BEAT_NVRW_CNT)
+		return -1;
+	ret = beat_hcall6(HV_eeprom_read, b, index, length);
+	memcpy(buffer, b, length);
+	return ret;
+}
+
+static inline s64 beat_set_dabr(u64 value, u64 style)
+{
+	return beat_hcall_norets(HV_set_dabr, value, style);
+}
+
+static inline s64 beat_get_characters_from_console(u64 termno, u64 *len,
+	u8 *buffer)
+{
+	u64 dummy[3];
+	s64 ret;
+
+	ret = beat_hcall3(HV_get_characters_from_console, dummy, termno, len);
+	*len = dummy[0];
+	memcpy(buffer, dummy + 1, *len);
+	return ret;
+}
+
+static inline s64 beat_put_characters_to_console(u64 termno, u64 len,
+	u8 *buffer)
+{
+	u64 b[2];
+
+	memcpy(b, buffer, len);
+	return beat_hcall_norets(HV_put_characters_to_console, termno, len,					 b[0], b[1]);
+}
+
+static inline s64 beat_get_spe_privileged_state_1_registers(
+		u64 id, u64 offsetof, u64 *value)
+{
+	u64 dummy[1];
+	s64 ret;
+
+	ret = beat_hcall1(HV_get_spe_privileged_state_1_registers, dummy, id,
+		offsetof);
+	*value = dummy[0];
+	return ret;
+}
+
+static inline s64 beat_set_irq_mask_for_spe(u64 id, u64 class, u64 mask)
+{
+	return beat_hcall_norets(HV_set_irq_mask_for_spe, id, class, mask);
+}
+
+static inline s64 beat_clear_interrupt_status_of_spe(u64 id, u64 class,
+	u64 mask)
+{
+	return beat_hcall_norets(HV_clear_interrupt_status_of_spe,
+		id, class, mask);
+}
+
+static inline s64 beat_set_spe_privileged_state_1_registers(
+		u64 id, u64 offsetof, u64 value)
+{
+	return beat_hcall_norets(HV_set_spe_privileged_state_1_registers,
+		id, offsetof, value);
+}
+
+static inline s64 beat_get_interrupt_status_of_spe(u64 id, u64 class, u64 *val)
+{
+	u64 dummy[1];
+	s64 ret;
+
+	ret = beat_hcall1(HV_get_interrupt_status_of_spe, dummy, id, class);
+	*val = dummy[0];
+	return ret;
+}
+
+static inline s64 beat_put_iopte(u64 ioas_id, u64 io_addr, u64 real_addr,
+	u64 ioid, u64 flags)
+{
+	return beat_hcall_norets(HV_put_iopte, ioas_id, io_addr, real_addr,
+		ioid, flags);
+}
+
+#endif
diff --git a/arch/powerpc/platforms/celleb/htab.c b/arch/powerpc/platforms/celleb/htab.c
new file mode 100644
index 0000000..ffa7c2c
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/htab.c
@@ -0,0 +1,311 @@
+/*
+ * "Cell Reference Set" HTAB support.
+ *
+ * (C) Copyright 2006-2007 TOSHIBA CORPORATION
+ *
+ * This code is based on arch/powerpc/platforms/pseries/lpar.c:
+ *  Copyright (C) 2001 Todd Inglett, IBM 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; 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#undef DEBUG_LOW
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+
+#include <asm/mmu.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/udbg.h>
+
+#include "beat_wrapper.h"
+
+#ifdef DEBUG_LOW
+#define DBG_LOW(fmt...) do { udbg_printf(fmt); } while(0)
+#else
+#define DBG_LOW(fmt...) do { } while(0)
+#endif
+
+static DEFINE_SPINLOCK(beat_htab_lock);
+
+static inline unsigned int beat_read_mask(unsigned hpte_group)
+{
+	unsigned long hpte_v[5];
+	unsigned long rmask = 0;
+
+	beat_read_htab_entries(0, hpte_group + 0, hpte_v);
+	if (!(hpte_v[0] & HPTE_V_BOLTED))
+		rmask |= 0x8000;
+	if (!(hpte_v[1] & HPTE_V_BOLTED))
+		rmask |= 0x4000;
+	if (!(hpte_v[2] & HPTE_V_BOLTED))
+		rmask |= 0x2000;
+	if (!(hpte_v[3] & HPTE_V_BOLTED))
+		rmask |= 0x1000;
+	beat_read_htab_entries(0, hpte_group + 4, hpte_v);
+	if (!(hpte_v[0] & HPTE_V_BOLTED))
+		rmask |= 0x0800;
+	if (!(hpte_v[1] & HPTE_V_BOLTED))
+		rmask |= 0x0400;
+	if (!(hpte_v[2] & HPTE_V_BOLTED))
+		rmask |= 0x0200;
+	if (!(hpte_v[3] & HPTE_V_BOLTED))
+		rmask |= 0x0100;
+	hpte_group = ~hpte_group & (htab_hash_mask * HPTES_PER_GROUP);
+	beat_read_htab_entries(0, hpte_group + 0, hpte_v);
+	if (!(hpte_v[0] & HPTE_V_BOLTED))
+		rmask |= 0x80;
+	if (!(hpte_v[1] & HPTE_V_BOLTED))
+		rmask |= 0x40;
+	if (!(hpte_v[2] & HPTE_V_BOLTED))
+		rmask |= 0x20;
+	if (!(hpte_v[3] & HPTE_V_BOLTED))
+		rmask |= 0x10;
+	beat_read_htab_entries(0, hpte_group + 4, hpte_v);
+	if (!(hpte_v[0] & HPTE_V_BOLTED))
+		rmask |= 0x08;
+	if (!(hpte_v[1] & HPTE_V_BOLTED))
+		rmask |= 0x04;
+	if (!(hpte_v[2] & HPTE_V_BOLTED))
+		rmask |= 0x02;
+	if (!(hpte_v[3] & HPTE_V_BOLTED))
+		rmask |= 0x01;
+	return rmask;
+}
+
+static long beat_lpar_hpte_insert(unsigned long hpte_group,
+				  unsigned long va, unsigned long pa,
+				  unsigned long rflags, unsigned long vflags,
+				  int psize)
+{
+	unsigned long lpar_rc;
+	unsigned long slot;
+	unsigned long hpte_v, hpte_r;
+	unsigned long flags;
+
+	/* same as iseries */
+	if (vflags & HPTE_V_SECONDARY)
+		return -1;
+
+	if (!(vflags & HPTE_V_BOLTED))
+		DBG_LOW("hpte_insert(group=%lx, va=%016lx, pa=%016lx, "
+			"rflags=%lx, vflags=%lx, psize=%d)\n",
+		hpte_group, va, pa, rflags, vflags, psize);
+
+	hpte_v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID;
+	hpte_r = hpte_encode_r(pa, psize) | rflags;
+
+	if (!(vflags & HPTE_V_BOLTED))
+		DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r);
+
+	if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE))
+		hpte_r &= ~_PAGE_COHERENT;
+
+	spin_lock_irqsave(&beat_htab_lock, flags);
+	if ((lpar_rc = beat_read_mask(hpte_group)) == 0) {
+		if (!(vflags & HPTE_V_BOLTED))
+			DBG_LOW(" full\n");
+		spin_unlock_irqrestore(&beat_htab_lock, flags);
+		return -1;
+	}
+
+	lpar_rc = beat_insert_htab_entry(0, hpte_group, lpar_rc << 48,
+		hpte_v, hpte_r, &slot);
+	spin_unlock_irqrestore(&beat_htab_lock, flags);
+
+	/*
+	 * Since we try and ioremap PHBs we don't own, the pte insert
+	 * will fail. However we must catch the failure in hash_page
+	 * or we will loop forever, so return -2 in this case.
+	 */
+	if (unlikely(lpar_rc != 0)) {
+		if (!(vflags & HPTE_V_BOLTED))
+			DBG_LOW(" lpar err %lx\n", lpar_rc);
+		return -2;
+	}
+	if (!(vflags & HPTE_V_BOLTED))
+		DBG_LOW(" -> slot: %lx\n", slot);
+
+	/* We have to pass down the secondary bucket bit here as well */
+	return (slot ^ hpte_group) & 15;
+}
+
+static long beat_lpar_hpte_remove(unsigned long hpte_group)
+{
+	DBG_LOW("hpte_remove(group=%lx)\n", hpte_group);
+	return -1;
+}
+
+static unsigned long beat_lpar_hpte_getword0(unsigned long slot)
+{
+	unsigned long dword0, dword[5];
+	unsigned long lpar_rc;
+
+	lpar_rc = beat_read_htab_entries(0, slot & ~3UL, dword);
+
+	dword0 = dword[slot&3];
+
+	BUG_ON(lpar_rc != 0);
+
+	return dword0;
+}
+
+static void beat_lpar_hptab_clear(void)
+{
+	unsigned long size_bytes = 1UL << ppc64_pft_size;
+	unsigned long hpte_count = size_bytes >> 4;
+	int i;
+	unsigned long dummy0, dummy1;
+
+	/* TODO: Use bulk call */
+	for (i = 0; i < hpte_count; i++)
+		beat_write_htab_entry(0, i, 0, 0, -1UL, -1UL, &dummy0, &dummy1);
+}
+
+/*
+ * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and
+ * the low 3 bits of flags happen to line up.  So no transform is needed.
+ * We can probably optimize here and assume the high bits of newpp are
+ * already zero.  For now I am paranoid.
+ */
+static long beat_lpar_hpte_updatepp(unsigned long slot,
+				    unsigned long newpp,
+				    unsigned long va,
+				    int psize, int local)
+{
+	unsigned long lpar_rc;
+	unsigned long dummy0, dummy1, want_v;
+	unsigned long flags;
+
+	want_v = hpte_encode_v(va, psize);
+
+	DBG_LOW("    update: "
+		"avpnv=%016lx, slot=%016lx, psize: %d, newpp %016lx ... ",
+		want_v & HPTE_V_AVPN, slot, psize, newpp);
+
+	spin_lock_irqsave(&beat_htab_lock, flags);
+	dummy0 = beat_lpar_hpte_getword0(slot);
+	if ((dummy0 & ~0x7FUL) != (want_v & ~0x7FUL)) {
+		DBG_LOW("not found !\n");
+		spin_unlock_irqrestore(&beat_htab_lock, flags);
+		return -1;
+	}
+
+	lpar_rc = beat_write_htab_entry(0, slot, 0, newpp, 0, 7, &dummy0,
+					&dummy1);
+	spin_unlock_irqrestore(&beat_htab_lock, flags);
+	if (lpar_rc != 0 || dummy0 == 0) {
+		DBG_LOW("not found !\n");
+		return -1;
+	}
+
+	DBG_LOW("ok %lx %lx\n", dummy0, dummy1);
+
+	BUG_ON(lpar_rc != 0);
+
+	return 0;
+}
+
+static long beat_lpar_hpte_find(unsigned long va, int psize)
+{
+	unsigned long hash;
+	unsigned long i, j;
+	long slot;
+	unsigned long want_v, hpte_v;
+
+	hash = hpt_hash(va, mmu_psize_defs[psize].shift);
+	want_v = hpte_encode_v(va, psize);
+
+	for (j = 0; j < 2; j++) {
+		slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+		for (i = 0; i < HPTES_PER_GROUP; i++) {
+			hpte_v = beat_lpar_hpte_getword0(slot);
+
+			if (HPTE_V_COMPARE(hpte_v, want_v)
+			    && (hpte_v & HPTE_V_VALID)
+			    && (!!(hpte_v & HPTE_V_SECONDARY) == j)) {
+				/* HPTE matches */
+				if (j)
+					slot = -slot;
+				return slot;
+			}
+			++slot;
+		}
+		hash = ~hash;
+	}
+
+	return -1;
+}
+
+static void beat_lpar_hpte_updateboltedpp(unsigned long newpp,
+					  unsigned long ea,
+					  int psize)
+{
+	unsigned long lpar_rc, slot, vsid, va, dummy0, dummy1;
+	unsigned long flags;
+
+	vsid = get_kernel_vsid(ea);
+	va = (vsid << 28) | (ea & 0x0fffffff);
+
+	spin_lock_irqsave(&beat_htab_lock, flags);
+	slot = beat_lpar_hpte_find(va, psize);
+	BUG_ON(slot == -1);
+
+	lpar_rc = beat_write_htab_entry(0, slot, 0, newpp, 0, 7,
+		&dummy0, &dummy1);
+	spin_unlock_irqrestore(&beat_htab_lock, flags);
+
+	BUG_ON(lpar_rc != 0);
+}
+
+static void beat_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
+					 int psize, int local)
+{
+	unsigned long want_v;
+	unsigned long lpar_rc;
+	unsigned long dummy1, dummy2;
+	unsigned long flags;
+
+	DBG_LOW("    inval : slot=%lx, va=%016lx, psize: %d, local: %d\n",
+		slot, va, psize, local);
+	want_v = hpte_encode_v(va, psize);
+
+	spin_lock_irqsave(&beat_htab_lock, flags);
+	dummy1 = beat_lpar_hpte_getword0(slot);
+
+	if ((dummy1 & ~0x7FUL) != (want_v & ~0x7FUL)) {
+		DBG_LOW("not found !\n");
+		spin_unlock_irqrestore(&beat_htab_lock, flags);
+		return;
+	}
+
+	lpar_rc = beat_write_htab_entry(0, slot, 0, 0, HPTE_V_VALID, 0,
+		&dummy1, &dummy2);
+	spin_unlock_irqrestore(&beat_htab_lock, flags);
+
+	BUG_ON(lpar_rc != 0);
+}
+
+void __init hpte_init_beat(void)
+{
+	ppc_md.hpte_invalidate	= beat_lpar_hpte_invalidate;
+	ppc_md.hpte_updatepp	= beat_lpar_hpte_updatepp;
+	ppc_md.hpte_updateboltedpp = beat_lpar_hpte_updateboltedpp;
+	ppc_md.hpte_insert	= beat_lpar_hpte_insert;
+	ppc_md.hpte_remove	= beat_lpar_hpte_remove;
+	ppc_md.hpte_clear_all	= beat_lpar_hptab_clear;
+}
diff --git a/arch/powerpc/platforms/celleb/hvCall.S b/arch/powerpc/platforms/celleb/hvCall.S
new file mode 100644
index 0000000..74c8174
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/hvCall.S
@@ -0,0 +1,287 @@
+/*
+ * Beat hypervisor call I/F
+ *
+ * (C) Copyright 2007 TOSHIBA CORPORATION
+ *
+ * This code is based on arch/powerpc/platforms/pseries/hvCall.S.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <asm/ppc_asm.h>
+
+#define	STK_PARM(i)	(48 + ((i)-3)*8)
+
+/* Not implemented on Beat, now */
+#define	HCALL_INST_PRECALL
+#define	HCALL_INST_POSTCALL
+
+	.text
+
+#define	HVSC	.long	0x44000022
+
+/* Note: takes only 7 input parameters at maximum */
+_GLOBAL(beat_hcall_norets)
+	HMT_MEDIUM
+
+	mfcr	r0
+	stw	r0,8(r1)
+
+	HCALL_INST_PRECALL
+
+	mr	r11,r3
+	mr	r3,r4
+	mr	r4,r5
+	mr	r5,r6
+	mr	r6,r7
+	mr	r7,r8
+	mr	r8,r9
+
+	HVSC				/* invoke the hypervisor */
+
+	HCALL_INST_POSTCALL
+
+	lwz	r0,8(r1)
+	mtcrf	0xff,r0
+
+	blr				/* return r3 = status */
+
+/* Note: takes 8 input parameters at maximum */
+_GLOBAL(beat_hcall_norets8)
+	HMT_MEDIUM
+
+	mfcr	r0
+	stw	r0,8(r1)
+
+	HCALL_INST_PRECALL
+
+	mr	r11,r3
+	mr	r3,r4
+	mr	r4,r5
+	mr	r5,r6
+	mr	r6,r7
+	mr	r7,r8
+	mr	r8,r9
+	ld	r10,STK_PARM(r10)(r1)
+
+	HVSC				/* invoke the hypervisor */
+
+	HCALL_INST_POSTCALL
+
+	lwz	r0,8(r1)
+	mtcrf	0xff,r0
+
+	blr				/* return r3 = status */
+
+/* Note: takes only 6 input parameters, 1 output parameters at maximum */
+_GLOBAL(beat_hcall1)
+	HMT_MEDIUM
+
+	mfcr	r0
+	stw	r0,8(r1)
+
+	HCALL_INST_PRECALL
+
+	std	r4,STK_PARM(r4)(r1)	/* save ret buffer */
+
+	mr	r11,r3
+	mr	r3,r5
+	mr	r4,r6
+	mr	r5,r7
+	mr	r6,r8
+	mr	r7,r9
+	mr	r8,r10
+
+	HVSC				/* invoke the hypervisor */
+
+	HCALL_INST_POSTCALL
+
+	ld	r12,STK_PARM(r4)(r1)
+	std	r4,  0(r12)
+
+	lwz	r0,8(r1)
+	mtcrf	0xff,r0
+
+	blr				/* return r3 = status */
+
+/* Note: takes only 6 input parameters, 2 output parameters at maximum */
+_GLOBAL(beat_hcall2)
+	HMT_MEDIUM
+
+	mfcr	r0
+	stw	r0,8(r1)
+
+	HCALL_INST_PRECALL
+
+	std	r4,STK_PARM(r4)(r1)	/* save ret buffer */
+
+	mr	r11,r3
+	mr	r3,r5
+	mr	r4,r6
+	mr	r5,r7
+	mr	r6,r8
+	mr	r7,r9
+	mr	r8,r10
+
+	HVSC				/* invoke the hypervisor */
+
+	HCALL_INST_POSTCALL
+
+	ld	r12,STK_PARM(r4)(r1)
+	std	r4,  0(r12)
+	std	r5,  8(r12)
+
+	lwz	r0,8(r1)
+	mtcrf	0xff,r0
+
+	blr				/* return r3 = status */
+
+/* Note: takes only 6 input parameters, 3 output parameters at maximum */
+_GLOBAL(beat_hcall3)
+	HMT_MEDIUM
+
+	mfcr	r0
+	stw	r0,8(r1)
+
+	HCALL_INST_PRECALL
+
+	std	r4,STK_PARM(r4)(r1)	/* save ret buffer */
+
+	mr	r11,r3
+	mr	r3,r5
+	mr	r4,r6
+	mr	r5,r7
+	mr	r6,r8
+	mr	r7,r9
+	mr	r8,r10
+
+	HVSC				/* invoke the hypervisor */
+
+	HCALL_INST_POSTCALL
+
+	ld	r12,STK_PARM(r4)(r1)
+	std	r4,  0(r12)
+	std	r5,  8(r12)
+	std	r6, 16(r12)
+
+	lwz	r0,8(r1)
+	mtcrf	0xff,r0
+
+	blr				/* return r3 = status */
+
+/* Note: takes only 6 input parameters, 4 output parameters at maximum */
+_GLOBAL(beat_hcall4)
+	HMT_MEDIUM
+
+	mfcr	r0
+	stw	r0,8(r1)
+
+	HCALL_INST_PRECALL
+
+	std	r4,STK_PARM(r4)(r1)	/* save ret buffer */
+
+	mr	r11,r3
+	mr	r3,r5
+	mr	r4,r6
+	mr	r5,r7
+	mr	r6,r8
+	mr	r7,r9
+	mr	r8,r10
+
+	HVSC				/* invoke the hypervisor */
+
+	HCALL_INST_POSTCALL
+
+	ld	r12,STK_PARM(r4)(r1)
+	std	r4,  0(r12)
+	std	r5,  8(r12)
+	std	r6, 16(r12)
+	std	r7, 24(r12)
+
+	lwz	r0,8(r1)
+	mtcrf	0xff,r0
+
+	blr				/* return r3 = status */
+
+/* Note: takes only 6 input parameters, 5 output parameters at maximum */
+_GLOBAL(beat_hcall5)
+	HMT_MEDIUM
+
+	mfcr	r0
+	stw	r0,8(r1)
+
+	HCALL_INST_PRECALL
+
+	std	r4,STK_PARM(r4)(r1)	/* save ret buffer */
+
+	mr	r11,r3
+	mr	r3,r5
+	mr	r4,r6
+	mr	r5,r7
+	mr	r6,r8
+	mr	r7,r9
+	mr	r8,r10
+
+	HVSC				/* invoke the hypervisor */
+
+	HCALL_INST_POSTCALL
+
+	ld	r12,STK_PARM(r4)(r1)
+	std	r4,  0(r12)
+	std	r5,  8(r12)
+	std	r6, 16(r12)
+	std	r7, 24(r12)
+	std	r8, 32(r12)
+
+	lwz	r0,8(r1)
+	mtcrf	0xff,r0
+
+	blr				/* return r3 = status */
+
+/* Note: takes only 6 input parameters, 6 output parameters at maximum */
+_GLOBAL(beat_hcall6)
+	HMT_MEDIUM
+
+	mfcr	r0
+	stw	r0,8(r1)
+
+	HCALL_INST_PRECALL
+
+	std	r4,STK_PARM(r4)(r1)	/* save ret buffer */
+
+	mr	r11,r3
+	mr	r3,r5
+	mr	r4,r6
+	mr	r5,r7
+	mr	r6,r8
+	mr	r7,r9
+	mr	r8,r10
+
+	HVSC				/* invoke the hypervisor */
+
+	HCALL_INST_POSTCALL
+
+	ld	r12,STK_PARM(r4)(r1)
+	std	r4,  0(r12)
+	std	r5,  8(r12)
+	std	r6, 16(r12)
+	std	r7, 24(r12)
+	std	r8, 32(r12)
+	std	r9, 40(r12)
+
+	lwz	r0,8(r1)
+	mtcrf	0xff,r0
+
+	blr				/* return r3 = status */
diff --git a/arch/powerpc/platforms/celleb/interrupt.c b/arch/powerpc/platforms/celleb/interrupt.c
new file mode 100644
index 0000000..98e6665
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/interrupt.c
@@ -0,0 +1,274 @@
+/*
+ * Celleb/Beat Interrupt controller
+ *
+ * (C) Copyright 2006-2007 TOSHIBA 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; 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/percpu.h>
+#include <linux/types.h>
+
+#include <asm/machdep.h>
+
+#include "interrupt.h"
+#include "beat_wrapper.h"
+
+#define	MAX_IRQS	NR_IRQS
+static DEFINE_SPINLOCK(beatic_irq_mask_lock);
+static uint64_t	beatic_irq_mask_enable[(MAX_IRQS+255)/64];
+static uint64_t	beatic_irq_mask_ack[(MAX_IRQS+255)/64];
+
+static struct irq_host *beatic_host = NULL;
+
+/*
+ * In this implementation, "virq" == "IRQ plug number",
+ * "(irq_hw_number_t)hwirq" == "IRQ outlet number".
+ */
+
+/* assumption: locked */
+static inline void beatic_update_irq_mask(unsigned int irq_plug)
+{
+	int off;
+	unsigned long masks[4];
+
+	off = (irq_plug / 256) * 4;
+	masks[0] = beatic_irq_mask_enable[off + 0]
+	           & beatic_irq_mask_ack[off + 0];
+	masks[1] = beatic_irq_mask_enable[off + 1]
+	           & beatic_irq_mask_ack[off + 1];
+	masks[2] = beatic_irq_mask_enable[off + 2]
+	           & beatic_irq_mask_ack[off + 2];
+	masks[3] = beatic_irq_mask_enable[off + 3]
+	           & beatic_irq_mask_ack[off + 3];
+	if (beat_set_interrupt_mask(irq_plug&~255UL,
+		masks[0], masks[1], masks[2], masks[3]) != 0)
+		panic("Failed to set mask IRQ!");
+}
+
+static void beatic_mask_irq(unsigned int irq_plug)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&beatic_irq_mask_lock, flags);
+	beatic_irq_mask_enable[irq_plug/64] &= ~(1UL << (63 - (irq_plug%64)));
+	beatic_update_irq_mask(irq_plug);
+	spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
+}
+
+static void beatic_unmask_irq(unsigned int irq_plug)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&beatic_irq_mask_lock, flags);
+	beatic_irq_mask_enable[irq_plug/64] |= 1UL << (63 - (irq_plug%64));
+	beatic_update_irq_mask(irq_plug);
+	spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
+}
+
+static void beatic_ack_irq(unsigned int irq_plug)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&beatic_irq_mask_lock, flags);
+	beatic_irq_mask_ack[irq_plug/64] &= ~(1UL << (63 - (irq_plug%64)));
+	beatic_update_irq_mask(irq_plug);
+	spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
+}
+
+static void beatic_end_irq(unsigned int irq_plug)
+{
+	s64 err;
+	unsigned long flags;
+
+	if ((err = beat_downcount_of_interrupt(irq_plug)) != 0) {
+		if ((err & 0xFFFFFFFF) != 0xFFFFFFF5) /* -11: wrong state */
+			panic("Failed to downcount IRQ! Error = %16lx", err);
+
+		printk(KERN_ERR "IRQ over-downcounted, plug %d\n", irq_plug);
+	}
+	spin_lock_irqsave(&beatic_irq_mask_lock, flags);
+	beatic_irq_mask_ack[irq_plug/64] |= 1UL << (63 - (irq_plug%64));
+	beatic_update_irq_mask(irq_plug);
+	spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
+}
+
+static struct irq_chip beatic_pic = {
+	.typename = " CELL-BEAT ",
+	.unmask = beatic_unmask_irq,
+	.mask = beatic_mask_irq,
+	.eoi = beatic_end_irq,
+};
+
+/*
+ * Dispose binding hardware IRQ number (hw) and Virtuql IRQ number (virq),
+ * update flags.
+ *
+ * Note that the number (virq) is already assigned at upper layer.
+ */
+static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq)
+{
+	beat_destruct_irq_plug(virq);
+}
+
+/*
+ * Create or update binding hardware IRQ number (hw) and Virtuql
+ * IRQ number (virq). This is called only once for a given mapping.
+ *
+ * Note that the number (virq) is already assigned at upper layer.
+ */
+static int beatic_pic_host_map(struct irq_host *h, unsigned int virq,
+			       irq_hw_number_t hw)
+{
+	struct irq_desc *desc = get_irq_desc(virq);
+	int64_t	err;
+
+	if ((err = beat_construct_and_connect_irq_plug(virq, hw)) < 0)
+		return -EIO;
+
+	desc->status |= IRQ_LEVEL;
+	set_irq_chip_and_handler(virq, &beatic_pic, handle_fasteoi_irq);
+	return 0;
+}
+
+/*
+ * Update binding hardware IRQ number (hw) and Virtuql
+ * IRQ number (virq). This is called only once for a given mapping.
+ */
+static void beatic_pic_host_remap(struct irq_host *h, unsigned int virq,
+			       irq_hw_number_t hw)
+{
+	beat_construct_and_connect_irq_plug(virq, hw);
+}
+
+/*
+ * Translate device-tree interrupt spec to irq_hw_number_t style (ulong),
+ * to pass away to irq_create_mapping().
+ *
+ * Called from irq_create_of_mapping() only.
+ * Note: We have only 1 entry to translate.
+ */
+static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct,
+				 u32 *intspec, unsigned int intsize,
+				 irq_hw_number_t *out_hwirq,
+				 unsigned int *out_flags)
+{
+	u64 *intspec2 = (u64 *)intspec;
+
+	*out_hwirq = *intspec2;
+	*out_flags |= IRQ_TYPE_LEVEL_LOW;
+	return 0;
+}
+
+static struct irq_host_ops beatic_pic_host_ops = {
+	.map = beatic_pic_host_map,
+	.remap = beatic_pic_host_remap,
+	.unmap = beatic_pic_host_unmap,
+	.xlate = beatic_pic_host_xlate,
+};
+
+/*
+ * Get an IRQ number
+ * Note: returns VIRQ
+ */
+static inline unsigned int beatic_get_irq_plug(void)
+{
+	int i;
+	uint64_t	pending[4], ub;
+
+	for (i = 0; i < MAX_IRQS; i += 256) {
+		beat_detect_pending_interrupts(i, pending);
+		__asm__ ("cntlzd %0,%1":"=r"(ub):
+			"r"(pending[0] & beatic_irq_mask_enable[i/64+0]
+			               & beatic_irq_mask_ack[i/64+0]));
+		if (ub != 64)
+			return i + ub + 0;
+		__asm__ ("cntlzd %0,%1":"=r"(ub):
+			"r"(pending[1] & beatic_irq_mask_enable[i/64+1]
+			               & beatic_irq_mask_ack[i/64+1]));
+		if (ub != 64)
+			return i + ub + 64;
+		__asm__ ("cntlzd %0,%1":"=r"(ub):
+			"r"(pending[2] & beatic_irq_mask_enable[i/64+2]
+			               & beatic_irq_mask_ack[i/64+2]));
+		if (ub != 64)
+			return i + ub + 128;
+		__asm__ ("cntlzd %0,%1":"=r"(ub):
+			"r"(pending[3] & beatic_irq_mask_enable[i/64+3]
+			               & beatic_irq_mask_ack[i/64+3]));
+		if (ub != 64)
+			return i + ub + 192;
+	}
+
+	return NO_IRQ;
+}
+unsigned int beatic_get_irq(void)
+{
+	unsigned int ret;
+
+	ret = beatic_get_irq_plug();
+	if (ret != NO_IRQ)
+		beatic_ack_irq(ret);
+	return ret;
+}
+
+/*
+ */
+void __init beatic_init_IRQ(void)
+{
+	int	i;
+
+	memset(beatic_irq_mask_enable, 0, sizeof(beatic_irq_mask_enable));
+	memset(beatic_irq_mask_ack, 255, sizeof(beatic_irq_mask_ack));
+	for (i = 0; i < MAX_IRQS; i += 256)
+		beat_set_interrupt_mask(i, 0L, 0L, 0L, 0L);
+
+	/* Set out get_irq function */
+	ppc_md.get_irq = beatic_get_irq;
+
+	/* Allocate an irq host */
+	beatic_host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0,
+					 &beatic_pic_host_ops,
+					 0);
+	BUG_ON(beatic_host == NULL);
+	irq_set_default_host(beatic_host);
+}
+
+#ifdef CONFIG_SMP
+
+/* Nullified to compile with SMP mode */
+void beatic_setup_cpu(int cpu)
+{
+}
+
+void beatic_cause_IPI(int cpu, int mesg)
+{
+}
+
+void beatic_request_IPIs(void)
+{
+}
+#endif /* CONFIG_SMP */
+
+void beatic_deinit_IRQ(void)
+{
+	int	i;
+
+	for (i = 1; i < NR_IRQS; i++)
+		beat_destruct_irq_plug(i);
+}
diff --git a/arch/powerpc/platforms/celleb/interrupt.h b/arch/powerpc/platforms/celleb/interrupt.h
new file mode 100644
index 0000000..b470fd0
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/interrupt.h
@@ -0,0 +1,33 @@
+/*
+ * Celleb/Beat Interrupt controller
+ *
+ * (C) Copyright 2006 TOSHIBA 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; 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef ASM_BEAT_PIC_H
+#define ASM_BEAT_PIC_H
+#ifdef __KERNEL__
+
+extern void beatic_init_IRQ(void);
+extern unsigned int beatic_get_irq(void);
+extern void beatic_cause_IPI(int cpu, int mesg);
+extern void beatic_request_IPIs(void);
+extern void beatic_setup_cpu(int);
+extern void beatic_deinit_IRQ(void);
+
+#endif
+#endif /* ASM_BEAT_PIC_H */
diff --git a/arch/powerpc/platforms/celleb/iommu.c b/arch/powerpc/platforms/celleb/iommu.c
new file mode 100644
index 0000000..f63b94c
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/iommu.c
@@ -0,0 +1,104 @@
+/*
+ * Support for IOMMU on Celleb platform.
+ *
+ * (C) Copyright 2006-2007 TOSHIBA 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; 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+
+#include <asm/of_platform.h>
+
+#include "beat_wrapper.h"
+
+#define DMA_FLAGS 0xf800000000000000UL	/* r/w permitted, coherency required,
+					   strongest order */
+
+static int __init find_dma_window(u64 *io_space_id, u64 *ioid,
+				  u64 *base, u64 *size, u64 *io_page_size)
+{
+	struct device_node *dn;
+	const unsigned long *dma_window;
+
+	for_each_node_by_type(dn, "ioif") {
+		dma_window = get_property(dn, "toshiba,dma-window", NULL);
+		if (dma_window) {
+			*io_space_id = (dma_window[0] >> 32) & 0xffffffffUL;
+			*ioid = dma_window[0] & 0x7ffUL;
+			*base = dma_window[1];
+			*size = dma_window[2];
+			*io_page_size = 1 << dma_window[3];
+			of_node_put(dn);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static void __init celleb_init_direct_mapping(void)
+{
+	u64 lpar_addr, io_addr;
+	u64 io_space_id, ioid, dma_base, dma_size, io_page_size;
+
+	if (!find_dma_window(&io_space_id, &ioid, &dma_base, &dma_size,
+			     &io_page_size)) {
+		pr_info("No dma window found !\n");
+		return;
+	}
+
+	for (lpar_addr = 0; lpar_addr < dma_size; lpar_addr += io_page_size) {
+		io_addr = lpar_addr + dma_base;
+		(void)beat_put_iopte(io_space_id, io_addr, lpar_addr,
+				     ioid, DMA_FLAGS);
+	}
+
+	dma_direct_offset = dma_base;
+}
+
+static int celleb_of_bus_notify(struct notifier_block *nb,
+				unsigned long action, void *data)
+{
+	struct device *dev = data;
+
+	/* We are only intereted in device addition */
+	if (action != BUS_NOTIFY_ADD_DEVICE)
+		return 0;
+
+	dev->archdata.dma_ops = pci_dma_ops;
+
+	return 0;
+}
+
+static struct notifier_block celleb_of_bus_notifier = {
+	.notifier_call = celleb_of_bus_notify
+};
+
+static int __init celleb_init_iommu(void)
+{
+	if (!machine_is(celleb))
+		return -ENODEV;
+
+	celleb_init_direct_mapping();
+	pci_dma_ops = &dma_direct_ops;
+	bus_register_notifier(&of_platform_bus_type, &celleb_of_bus_notifier);
+
+	return 0;
+}
+
+arch_initcall(celleb_init_iommu);
diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/celleb/pci.c
new file mode 100644
index 0000000..98de836
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/pci.c
@@ -0,0 +1,481 @@
+/*
+ * Support for PCI on Celleb platform.
+ *
+ * (C) Copyright 2006-2007 TOSHIBA CORPORATION
+ *
+ * This code is based on arch/powerpc/kernel/rtas_pci.c:
+ *  Copyright (C) 2001 Dave Engebretsen, IBM Corporation
+ *  Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/threads.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/pci_regs.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
+
+#include "pci.h"
+#include "interrupt.h"
+
+#define MAX_PCI_DEVICES    32
+#define MAX_PCI_FUNCTIONS   8
+#define MAX_PCI_BASE_ADDRS  3 /* use 64 bit address */
+
+/* definition for fake pci configuration area for GbE, .... ,and etc. */
+
+struct celleb_pci_resource {
+	struct resource r[MAX_PCI_BASE_ADDRS];
+};
+
+struct celleb_pci_private {
+	unsigned char *fake_config[MAX_PCI_DEVICES][MAX_PCI_FUNCTIONS];
+	struct celleb_pci_resource *res[MAX_PCI_DEVICES][MAX_PCI_FUNCTIONS];
+};
+
+static inline u8 celleb_fake_config_readb(void *addr)
+{
+	u8 *p = addr;
+	return *p;
+}
+
+static inline u16 celleb_fake_config_readw(void *addr)
+{
+	__le16 *p = addr;
+	return le16_to_cpu(*p);
+}
+
+static inline u32 celleb_fake_config_readl(void *addr)
+{
+	__le32 *p = addr;
+	return le32_to_cpu(*p);
+}
+
+static inline void celleb_fake_config_writeb(u32 val, void *addr)
+{
+	u8 *p = addr;
+	*p = val;
+}
+
+static inline void celleb_fake_config_writew(u32 val, void *addr)
+{
+	__le16 val16;
+	__le16 *p = addr;
+	val16 = cpu_to_le16(val);
+	*p = val16;
+}
+
+static inline void celleb_fake_config_writel(u32 val, void *addr)
+{
+	__le32 val32;
+	__le32 *p = addr;
+	val32 = cpu_to_le32(val);
+	*p = val32;
+}
+
+static unsigned char *get_fake_config_start(struct pci_controller *hose,
+					    int devno, int fn)
+{
+	struct celleb_pci_private *private = hose->private_data;
+
+	if (private == NULL)
+		return NULL;
+
+	return private->fake_config[devno][fn];
+}
+
+static struct celleb_pci_resource *get_resource_start(
+				struct pci_controller *hose,
+				int devno, int fn)
+{
+	struct celleb_pci_private *private = hose->private_data;
+
+	if (private == NULL)
+		return NULL;
+
+	return private->res[devno][fn];
+}
+
+
+static void celleb_config_read_fake(unsigned char *config, int where,
+				    int size, u32 *val)
+{
+	char *p = config + where;
+
+	switch (size) {
+	case 1:
+		*val = celleb_fake_config_readb(p);
+		break;
+	case 2:
+		*val = celleb_fake_config_readw(p);
+		break;
+	case 4:
+		*val = celleb_fake_config_readl(p);
+		break;
+	}
+
+	return;
+}
+
+static void celleb_config_write_fake(unsigned char *config, int where,
+				     int size, u32 val)
+{
+	char *p = config + where;
+
+	switch (size) {
+	case 1:
+		celleb_fake_config_writeb(val, p);
+		break;
+	case 2:
+		celleb_fake_config_writew(val, p);
+		break;
+	case 4:
+		celleb_fake_config_writel(val, p);
+		break;
+	}
+	return;
+}
+
+static int celleb_fake_pci_read_config(struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 *val)
+{
+	char *config;
+	struct device_node *node;
+	struct pci_controller *hose;
+	unsigned int devno = devfn >> 3;
+	unsigned int fn = devfn & 0x7;
+
+	/* allignment check */
+	BUG_ON(where % size);
+
+	pr_debug("    fake read: bus=0x%x, ", bus->number);
+	node = (struct device_node *)bus->sysdata;
+	hose = pci_find_hose_for_OF_device(node);
+	config = get_fake_config_start(hose, devno, fn);
+
+	pr_debug("devno=0x%x, where=0x%x, size=0x%x, ", devno, where, size);
+	if (!config) {
+		pr_debug("failed\n");
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	celleb_config_read_fake(config, where, size, val);
+	pr_debug("val=0x%x\n", *val);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int celleb_fake_pci_write_config(struct pci_bus *bus,
+		 unsigned int devfn, int where, int size, u32 val)
+{
+	char *config;
+	struct device_node *node;
+	struct pci_controller *hose;
+	struct celleb_pci_resource *res;
+	unsigned int devno = devfn >> 3;
+	unsigned int fn = devfn & 0x7;
+
+	/* allignment check */
+	BUG_ON(where % size);
+
+	node = (struct device_node *)bus->sysdata;
+	hose = pci_find_hose_for_OF_device(node);
+	config = get_fake_config_start(hose, devno, fn);
+
+	if (!config)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (val == ~0) {
+		int i = (where - PCI_BASE_ADDRESS_0) >> 3;
+
+		switch (where) {
+		case PCI_BASE_ADDRESS_0:
+		case PCI_BASE_ADDRESS_2:
+			if (size != 4)
+				return PCIBIOS_DEVICE_NOT_FOUND;
+			res = get_resource_start(hose, devno, fn);
+			if (!res)
+				return PCIBIOS_DEVICE_NOT_FOUND;
+			celleb_config_write_fake(config, where, size,
+					(res->r[i].end - res->r[i].start));
+			return PCIBIOS_SUCCESSFUL;
+		case PCI_BASE_ADDRESS_1:
+		case PCI_BASE_ADDRESS_3:
+		case PCI_BASE_ADDRESS_4:
+		case PCI_BASE_ADDRESS_5:
+			break;
+		default:
+			break;
+		}
+	}
+
+	celleb_config_write_fake(config, where, size, val);
+	pr_debug("    fake write: where=%x, size=%d, val=%x\n",
+		 where, size, val);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops celleb_fake_pci_ops = {
+	celleb_fake_pci_read_config,
+	celleb_fake_pci_write_config
+};
+
+static inline void celleb_setup_pci_base_addrs(struct pci_controller *hose,
+					unsigned int devno, unsigned int fn,
+					unsigned int num_base_addr)
+{
+	u32 val;
+	unsigned char *config;
+	struct celleb_pci_resource *res;
+
+	config = get_fake_config_start(hose, devno, fn);
+	res = get_resource_start(hose, devno, fn);
+
+	if (!config || !res)
+		return;
+
+	switch (num_base_addr) {
+	case 3:
+		val = (res->r[2].start & 0xfffffff0)
+		    | PCI_BASE_ADDRESS_MEM_TYPE_64;
+		celleb_config_write_fake(config, PCI_BASE_ADDRESS_4, 4, val);
+		val = res->r[2].start >> 32;
+		celleb_config_write_fake(config, PCI_BASE_ADDRESS_5, 4, val);
+		/* FALLTHROUGH */
+	case 2:
+		val = (res->r[1].start & 0xfffffff0)
+		    | PCI_BASE_ADDRESS_MEM_TYPE_64;
+		celleb_config_write_fake(config, PCI_BASE_ADDRESS_2, 4, val);
+		val = res->r[1].start >> 32;
+		celleb_config_write_fake(config, PCI_BASE_ADDRESS_3, 4, val);
+		/* FALLTHROUGH */
+	case 1:
+		val = (res->r[0].start & 0xfffffff0)
+		    | PCI_BASE_ADDRESS_MEM_TYPE_64;
+		celleb_config_write_fake(config, PCI_BASE_ADDRESS_0, 4, val);
+		val = res->r[0].start >> 32;
+		celleb_config_write_fake(config, PCI_BASE_ADDRESS_1, 4, val);
+		break;
+	}
+
+	val = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+	celleb_config_write_fake(config, PCI_COMMAND, 2, val);
+}
+
+static int __devinit celleb_setup_fake_pci_device(struct device_node *node,
+						  struct pci_controller *hose)
+{
+	unsigned int rlen;
+	int num_base_addr = 0;
+	u32 val;
+	const u32 *wi0, *wi1, *wi2, *wi3, *wi4;
+	unsigned int devno, fn;
+	struct celleb_pci_private *private = hose->private_data;
+	unsigned char **config = NULL;
+	struct celleb_pci_resource **res = NULL;
+	const char *name;
+	const unsigned long *li;
+	int size, result;
+
+	if (private == NULL) {
+		printk(KERN_ERR "PCI: "
+		       "memory space for pci controller is not assigned\n");
+		goto error;
+	}
+
+	name = get_property(node, "model", &rlen);
+	if (!name) {
+		printk(KERN_ERR "PCI: model property not found.\n");
+		goto error;
+	}
+
+	wi4 = get_property(node, "reg", &rlen);
+	if (wi4 == NULL)
+		goto error;
+
+	devno = ((wi4[0] >> 8) & 0xff) >> 3;
+	fn = (wi4[0] >> 8) & 0x7;
+
+	pr_debug("PCI: celleb_setup_fake_pci() %s devno=%x fn=%x\n", name,
+		 devno, fn);
+
+	size = 256;
+	config = &private->fake_config[devno][fn];
+	if (mem_init_done)
+		*config = kzalloc(size, GFP_KERNEL);
+	else
+		*config = alloc_bootmem(size);
+	if (*config == NULL) {
+		printk(KERN_ERR "PCI: "
+		       "not enough memory for fake configuration space\n");
+		goto error;
+	}
+	pr_debug("PCI: fake config area assigned 0x%016lx\n",
+		 (unsigned long)*config);
+
+	size = sizeof(struct celleb_pci_resource);
+	res = &private->res[devno][fn];
+	if (mem_init_done)
+		*res = kzalloc(size, GFP_KERNEL);
+	else
+		*res = alloc_bootmem(size);
+	if (*res == NULL) {
+		printk(KERN_ERR
+		       "PCI: not enough memory for resource data space\n");
+		goto error;
+	}
+	pr_debug("PCI: res assigned 0x%016lx\n", (unsigned long)*res);
+
+	wi0 = get_property(node, "device-id", NULL);
+	wi1 = get_property(node, "vendor-id", NULL);
+	wi2 = get_property(node, "class-code", NULL);
+	wi3 = get_property(node, "revision-id", NULL);
+
+	celleb_config_write_fake(*config, PCI_DEVICE_ID, 2, wi0[0] & 0xffff);
+	celleb_config_write_fake(*config, PCI_VENDOR_ID, 2, wi1[0] & 0xffff);
+	pr_debug("class-code = 0x%08x\n", wi2[0]);
+
+	celleb_config_write_fake(*config, PCI_CLASS_PROG, 1, wi2[0] & 0xff);
+	celleb_config_write_fake(*config, PCI_CLASS_DEVICE, 2,
+				 (wi2[0] >> 8) & 0xffff);
+	celleb_config_write_fake(*config, PCI_REVISION_ID, 1, wi3[0]);
+
+	while (num_base_addr < MAX_PCI_BASE_ADDRS) {
+		result = of_address_to_resource(node,
+				num_base_addr, &(*res)->r[num_base_addr]);
+		if (result)
+			break;
+		num_base_addr++;
+	}
+
+	celleb_setup_pci_base_addrs(hose, devno, fn, num_base_addr);
+
+	li = get_property(node, "interrupts", &rlen);
+	val = li[0];
+	celleb_config_write_fake(*config, PCI_INTERRUPT_PIN, 1, 1);
+	celleb_config_write_fake(*config, PCI_INTERRUPT_LINE, 1, val);
+
+#ifdef DEBUG
+	pr_debug("PCI: %s irq=%ld\n", name, li[0]);
+	for (i = 0; i < 6; i++) {
+		celleb_config_read_fake(*config,
+					PCI_BASE_ADDRESS_0 + 0x4 * i, 4,
+					&val);
+		pr_debug("PCI: %s fn=%d base_address_%d=0x%x\n",
+			 name, fn, i, val);
+	}
+#endif
+
+	celleb_config_write_fake(*config, PCI_HEADER_TYPE, 1,
+				 PCI_HEADER_TYPE_NORMAL);
+
+	return 0;
+
+error:
+	if (mem_init_done) {
+		if (config && *config)
+			kfree(*config);
+		if (res && *res)
+			kfree(*res);
+
+	} else {
+		if (config && *config) {
+			size = 256;
+			free_bootmem((unsigned long)(*config), size);
+		}
+		if (res && *res) {
+			size = sizeof(struct celleb_pci_resource);
+			free_bootmem((unsigned long)(*res), size);
+		}
+	}
+
+	return 1;
+}
+
+static int __devinit phb_set_bus_ranges(struct device_node *dev,
+					struct pci_controller *phb)
+{
+	const int *bus_range;
+	unsigned int len;
+
+	bus_range = get_property(dev, "bus-range", &len);
+	if (bus_range == NULL || len < 2 * sizeof(int))
+		return 1;
+
+	phb->first_busno = bus_range[0];
+	phb->last_busno = bus_range[1];
+
+	return 0;
+}
+
+static void __devinit celleb_alloc_private_mem(struct pci_controller *hose)
+{
+	if (mem_init_done)
+		hose->private_data =
+			kzalloc(sizeof(struct celleb_pci_private), GFP_KERNEL);
+	else
+		hose->private_data =
+			alloc_bootmem(sizeof(struct celleb_pci_private));
+}
+
+int __devinit celleb_setup_phb(struct pci_controller *phb)
+{
+	const char *name;
+	struct device_node *dev = phb->arch_data;
+	struct device_node *node;
+	unsigned int rlen;
+
+	name = get_property(dev, "name", &rlen);
+	if (!name)
+		return 1;
+
+	pr_debug("PCI: celleb_setup_phb() %s\n", name);
+	phb_set_bus_ranges(dev, phb);
+
+	if (strcmp(name, "epci") == 0) {
+		phb->ops = &celleb_epci_ops;
+		return celleb_setup_epci(dev, phb);
+
+	} else if (strcmp(name, "pci-pseudo") == 0) {
+		phb->ops = &celleb_fake_pci_ops;
+		celleb_alloc_private_mem(phb);
+		for (node = of_get_next_child(dev, NULL);
+		     node != NULL; node = of_get_next_child(dev, node))
+			celleb_setup_fake_pci_device(node, phb);
+
+	} else
+		return 1;
+
+	return 0;
+}
+
+int celleb_pci_probe_mode(struct pci_bus *bus)
+{
+	return PCI_PROBE_DEVTREE;
+}
diff --git a/arch/powerpc/platforms/celleb/pci.h b/arch/powerpc/platforms/celleb/pci.h
new file mode 100644
index 0000000..5340e34
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/pci.h
@@ -0,0 +1,35 @@
+/*
+ * pci prototypes for Celleb platform
+ *
+ * (C) Copyright 2006-2007 TOSHIBA 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; 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CELLEB_PCI_H
+#define _CELLEB_PCI_H
+
+#include <linux/pci.h>
+
+#include <asm/pci-bridge.h>
+#include <asm/prom.h>
+
+extern int celleb_setup_phb(struct pci_controller *);
+extern int celleb_pci_probe_mode(struct pci_bus *);
+
+extern struct pci_ops celleb_epci_ops;
+extern int celleb_setup_epci(struct device_node *, struct pci_controller *);
+
+#endif /* _CELLEB_PCI_H */
diff --git a/arch/powerpc/platforms/celleb/scc.h b/arch/powerpc/platforms/celleb/scc.h
new file mode 100644
index 0000000..e9ce8a7
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/scc.h
@@ -0,0 +1,145 @@
+/*
+ * SCC (Super Companion Chip) definitions
+ *
+ * (C) Copyright 2004-2006 TOSHIBA 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; 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CELLEB_SCC_H
+#define _CELLEB_SCC_H
+
+#define PCI_VENDOR_ID_TOSHIBA_2                 0x102f
+#define PCI_DEVICE_ID_TOSHIBA_SCC_PCIEXC_BRIDGE 0x01b0
+#define PCI_DEVICE_ID_TOSHIBA_SCC_EPCI_BRIDGE   0x01b1
+#define PCI_DEVICE_ID_TOSHIBA_SCC_BRIDGE        0x01b2
+#define PCI_DEVICE_ID_TOSHIBA_SCC_GBE           0x01b3
+#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA           0x01b4
+#define PCI_DEVICE_ID_TOSHIBA_SCC_USB2          0x01b5
+#define PCI_DEVICE_ID_TOSHIBA_SCC_USB           0x01b6
+#define PCI_DEVICE_ID_TOSHIBA_SCC_ENCDEC        0x01b7
+
+#define SCC_EPCI_REG            0x0000d000
+
+/* EPCI registers */
+#define SCC_EPCI_CNF10_REG      0x010
+#define SCC_EPCI_CNF14_REG      0x014
+#define SCC_EPCI_CNF18_REG      0x018
+#define SCC_EPCI_PVBAT          0x100
+#define SCC_EPCI_VPMBAT         0x104
+#define SCC_EPCI_VPIBAT         0x108
+#define SCC_EPCI_VCSR           0x110
+#define SCC_EPCI_VIENAB         0x114
+#define SCC_EPCI_VISTAT         0x118
+#define SCC_EPCI_VRDCOUNT       0x124
+#define SCC_EPCI_BAM0           0x12c
+#define SCC_EPCI_BAM1           0x134
+#define SCC_EPCI_BAM2           0x13c
+#define SCC_EPCI_IADR           0x164
+#define SCC_EPCI_CLKRST         0x800
+#define SCC_EPCI_INTSET         0x804
+#define SCC_EPCI_STATUS         0x808
+#define SCC_EPCI_ABTSET         0x80c
+#define SCC_EPCI_WATRP          0x810
+#define SCC_EPCI_DUMMYRADR      0x814
+#define SCC_EPCI_SWRESP         0x818
+#define SCC_EPCI_CNTOPT         0x81c
+#define SCC_EPCI_ECMODE         0xf00
+#define SCC_EPCI_IOM_AC_NUM     5
+#define SCC_EPCI_IOM_ACTE(n)    (0xf10 + (n) * 4)
+#define SCC_EPCI_IOT_AC_NUM     4
+#define SCC_EPCI_IOT_ACTE(n)    (0xf30 + (n) * 4)
+#define SCC_EPCI_MAEA           0xf50
+#define SCC_EPCI_MAEC           0xf54
+#define SCC_EPCI_CKCTRL         0xff0
+
+/* bits for SCC_EPCI_VCSR */
+#define SCC_EPCI_VCSR_FRE       0x00020000
+#define SCC_EPCI_VCSR_FWE       0x00010000
+#define SCC_EPCI_VCSR_DR        0x00000400
+#define SCC_EPCI_VCSR_SR        0x00000008
+#define SCC_EPCI_VCSR_AT        0x00000004
+
+/* bits for SCC_EPCI_VIENAB/SCC_EPCI_VISTAT */
+#define SCC_EPCI_VISTAT_PMPE    0x00000008
+#define SCC_EPCI_VISTAT_PMFE    0x00000004
+#define SCC_EPCI_VISTAT_PRA     0x00000002
+#define SCC_EPCI_VISTAT_PRD     0x00000001
+#define SCC_EPCI_VISTAT_ALL     0x0000000f
+
+#define SCC_EPCI_VIENAB_PMPEE   0x00000008
+#define SCC_EPCI_VIENAB_PMFEE   0x00000004
+#define SCC_EPCI_VIENAB_PRA     0x00000002
+#define SCC_EPCI_VIENAB_PRD     0x00000001
+#define SCC_EPCI_VIENAB_ALL     0x0000000f
+
+/* bits for SCC_EPCI_CLKRST */
+#define SCC_EPCI_CLKRST_CKS_MASK 0x00030000
+#define SCC_EPCI_CLKRST_CKS_2   0x00000000
+#define SCC_EPCI_CLKRST_CKS_4   0x00010000
+#define SCC_EPCI_CLKRST_CKS_8   0x00020000
+#define SCC_EPCI_CLKRST_PCICRST 0x00000400
+#define SCC_EPCI_CLKRST_BC      0x00000200
+#define SCC_EPCI_CLKRST_PCIRST  0x00000100
+#define SCC_EPCI_CLKRST_PCKEN   0x00000001
+
+/* bits for SCC_EPCI_INTSET/SCC_EPCI_STATUS */
+#define SCC_EPCI_INT_2M         0x01000000
+#define SCC_EPCI_INT_RERR       0x00200000
+#define SCC_EPCI_INT_SERR       0x00100000
+#define SCC_EPCI_INT_PRTER      0x00080000
+#define SCC_EPCI_INT_SER        0x00040000
+#define SCC_EPCI_INT_PER        0x00020000
+#define SCC_EPCI_INT_PAI        0x00010000
+#define SCC_EPCI_INT_1M         0x00000100
+#define SCC_EPCI_INT_PME        0x00000010
+#define SCC_EPCI_INT_INTD       0x00000008
+#define SCC_EPCI_INT_INTC       0x00000004
+#define SCC_EPCI_INT_INTB       0x00000002
+#define SCC_EPCI_INT_INTA       0x00000001
+#define SCC_EPCI_INT_DEVINT     0x0000000f
+#define SCC_EPCI_INT_ALL        0x003f001f
+#define SCC_EPCI_INT_ALLERR     0x003f0000
+
+/* bits for SCC_EPCI_CKCTRL */
+#define SCC_EPCI_CKCTRL_CRST0   0x00010000
+#define SCC_EPCI_CKCTRL_CRST1   0x00020000
+#define SCC_EPCI_CKCTRL_OCLKEN  0x00000100
+#define SCC_EPCI_CKCTRL_LCLKEN  0x00000001
+
+#define SCC_EPCI_IDSEL_AD_TO_SLOT(ad)       ((ad) - 10)
+#define SCC_EPCI_MAX_DEVNU      SCC_EPCI_IDSEL_AD_TO_SLOT(32)
+
+/* bits for SCC_EPCI_CNTOPT */
+#define SCC_EPCI_CNTOPT_O2PMB   0x00000002
+
+/* UHC registers */
+#define SCC_UHC_CKRCTRL         0xff0
+#define SCC_UHC_ECMODE          0xf00
+
+/* bits for SCC_UHC_CKRCTRL */
+#define SCC_UHC_F48MCKLEN       0x00000001
+#define SCC_UHC_P_SUSPEND       0x00000002
+#define SCC_UHC_PHY_SUSPEND_SEL 0x00000004
+#define SCC_UHC_HCLKEN          0x00000100
+#define SCC_UHC_USBEN           0x00010000
+#define SCC_UHC_USBCEN          0x00020000
+#define SCC_UHC_PHYEN           0x00040000
+
+/* bits for SCC_UHC_ECMODE */
+#define SCC_UHC_ECMODE_BY_BYTE  0x00000555
+#define SCC_UHC_ECMODE_BY_WORD  0x00000aaa
+
+#endif /* _CELLEB_SCC_H */
diff --git a/arch/powerpc/platforms/celleb/scc_epci.c b/arch/powerpc/platforms/celleb/scc_epci.c
new file mode 100644
index 0000000..c11b39c
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/scc_epci.c
@@ -0,0 +1,409 @@
+/*
+ * Support for SCC external PCI
+ *
+ * (C) Copyright 2004-2007 TOSHIBA 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; 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/threads.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/pci_regs.h>
+#include <linux/bootmem.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
+
+#include "scc.h"
+#include "pci.h"
+#include "interrupt.h"
+
+#define MAX_PCI_DEVICES   32
+#define MAX_PCI_FUNCTIONS  8
+
+#define iob()  __asm__ __volatile__("eieio; sync":::"memory")
+
+
+#if 0 /* test code for epci dummy read */
+static void celleb_epci_dummy_read(struct pci_dev *dev)
+{
+	void __iomem *epci_base;
+	struct device_node *node;
+	struct pci_controller *hose;
+	u32 val;
+
+	node = (struct device_node *)dev->bus->sysdata;
+	hose = pci_find_hose_for_OF_device(node);
+
+	if (!hose)
+		return;
+
+	epci_base = hose->cfg_addr;
+
+	val = in_be32(epci_base + SCC_EPCI_WATRP);
+	iosync();
+
+	return;
+}
+#endif
+
+static inline void clear_and_disable_master_abort_interrupt(
+					struct pci_controller *hose)
+{
+	void __iomem *addr;
+	addr = hose->cfg_addr + PCI_COMMAND;
+	out_be32(addr, in_be32(addr) | (PCI_STATUS_REC_MASTER_ABORT << 16));
+}
+
+static int celleb_epci_check_abort(struct pci_controller *hose,
+				   void __iomem *addr)
+{
+	void __iomem *reg, *epci_base;
+	u32 val;
+
+	iob();
+	epci_base = hose->cfg_addr;
+
+	reg = epci_base + PCI_COMMAND;
+	val = in_be32(reg);
+
+	if (val & (PCI_STATUS_REC_MASTER_ABORT << 16)) {
+		out_be32(reg,
+			 (val & 0xffff) | (PCI_STATUS_REC_MASTER_ABORT << 16));
+
+		/* clear PCI Controller error, FRE, PMFE */
+		reg = epci_base + SCC_EPCI_STATUS;
+		out_be32(reg, SCC_EPCI_INT_PAI);
+
+		reg = epci_base + SCC_EPCI_VCSR;
+		val = in_be32(reg) & 0xffff;
+		val |= SCC_EPCI_VCSR_FRE;
+		out_be32(reg, val);
+
+		reg = epci_base + SCC_EPCI_VISTAT;
+		out_be32(reg, SCC_EPCI_VISTAT_PMFE);
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static void __iomem *celleb_epci_make_config_addr(struct pci_controller *hose,
+					unsigned int devfn, int where)
+{
+	void __iomem *addr;
+	struct pci_bus *bus = hose->bus;
+
+	if (bus->self)
+		addr = hose->cfg_data +
+		       (((bus->number & 0xff) << 16)
+		        | ((devfn & 0xff) << 8)
+		        | (where & 0xff)
+		        | 0x01000000);
+	else
+		addr = hose->cfg_data +
+		       (((devfn & 0xff) << 8) | (where & 0xff));
+
+	pr_debug("EPCI: config_addr = 0x%p\n", addr);
+
+	return addr;
+}
+
+static int celleb_epci_read_config(struct pci_bus *bus,
+			unsigned int devfn, int where, int size, u32 * val)
+{
+	void __iomem *addr;
+	struct device_node *node;
+	struct pci_controller *hose;
+
+	/* allignment check */
+	BUG_ON(where % size);
+
+	node = (struct device_node *)bus->sysdata;
+	hose = pci_find_hose_for_OF_device(node);
+
+	if (!hose->cfg_data)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (bus->number == hose->first_busno && devfn == 0) {
+		/* EPCI controller self */
+
+		addr = hose->cfg_addr + where;
+
+		switch (size) {
+		case 1:
+			*val = in_8(addr);
+			break;
+		case 2:
+			*val = in_be16(addr);
+			break;
+		case 4:
+			*val = in_be32(addr);
+			break;
+		default:
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		}
+
+	} else {
+
+		clear_and_disable_master_abort_interrupt(hose);
+		addr = celleb_epci_make_config_addr(hose, devfn, where);
+
+		switch (size) {
+		case 1:
+			*val = in_8(addr);
+			break;
+		case 2:
+			*val = in_le16(addr);
+			break;
+		case 4:
+			*val = in_le32(addr);
+			break;
+		default:
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		}
+	}
+
+	pr_debug("EPCI: "
+		 "addr=0x%lx, devfn=0x%x, where=0x%x, size=0x%x, val=0x%x\n",
+		 addr, devfn, where, size, *val);
+
+	return celleb_epci_check_abort(hose, NULL);
+}
+
+static int celleb_epci_write_config(struct pci_bus *bus,
+			unsigned int devfn, int where, int size, u32 val)
+{
+	void __iomem *addr;
+	struct device_node *node;
+	struct pci_controller *hose;
+
+	/* allignment check */
+	BUG_ON(where % size);
+
+	node = (struct device_node *)bus->sysdata;
+	hose = pci_find_hose_for_OF_device(node);
+
+	if (!hose->cfg_data)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (bus->number == hose->first_busno && devfn == 0) {
+		/* EPCI controller self */
+
+		addr = hose->cfg_addr + where;
+
+		switch (size) {
+		case 1:
+			out_8(addr, val);
+			break;
+		case 2:
+			out_be16(addr, val);
+			break;
+		case 4:
+			out_be32(addr, val);
+			break;
+		default:
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		}
+
+	} else {
+
+		clear_and_disable_master_abort_interrupt(hose);
+		addr = celleb_epci_make_config_addr(hose, devfn, where);
+
+		switch (size) {
+		case 1:
+			out_8(addr, val);
+			break;
+		case 2:
+			out_le16(addr, val);
+			break;
+		case 4:
+			out_le32(addr, val);
+			break;
+		default:
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		}
+	}
+
+	return celleb_epci_check_abort(hose, addr);
+}
+
+struct pci_ops celleb_epci_ops = {
+	celleb_epci_read_config,
+	celleb_epci_write_config,
+};
+
+/* to be moved in FW */
+static int __devinit celleb_epci_init(struct pci_controller *hose)
+{
+	u32 val;
+	void __iomem *reg, *epci_base;
+	int hwres = 0;
+
+	epci_base = hose->cfg_addr;
+
+	/* PCI core reset(Internal bus and PCI clock) */
+	reg = epci_base + SCC_EPCI_CKCTRL;
+	val = in_be32(reg);
+	if (val == 0x00030101)
+		hwres = 1;
+	else {
+		val &= ~(SCC_EPCI_CKCTRL_CRST0 | SCC_EPCI_CKCTRL_CRST1);
+		out_be32(reg, val);
+
+		/* set PCI core clock */
+		val = in_be32(reg);
+		val |= (SCC_EPCI_CKCTRL_OCLKEN | SCC_EPCI_CKCTRL_LCLKEN);
+		out_be32(reg, val);
+
+		/* release PCI core reset (internal bus) */
+		val = in_be32(reg);
+		val |= SCC_EPCI_CKCTRL_CRST0;
+		out_be32(reg, val);
+
+		/* set PCI clock select */
+		reg = epci_base + SCC_EPCI_CLKRST;
+		val = in_be32(reg);
+		val &= ~SCC_EPCI_CLKRST_CKS_MASK;
+		val |= SCC_EPCI_CLKRST_CKS_2;
+		out_be32(reg, val);
+
+		/* set arbiter */
+		reg = epci_base + SCC_EPCI_ABTSET;
+		out_be32(reg, 0x0f1f001f);	/* temporary value */
+
+		/* buffer on */
+		reg = epci_base + SCC_EPCI_CLKRST;
+		val = in_be32(reg);
+		val |= SCC_EPCI_CLKRST_BC;
+		out_be32(reg, val);
+
+		/* PCI clock enable */
+		val = in_be32(reg);
+		val |= SCC_EPCI_CLKRST_PCKEN;
+		out_be32(reg, val);
+
+		/* release PCI core reset (all) */
+		reg = epci_base + SCC_EPCI_CKCTRL;
+		val = in_be32(reg);
+		val |= (SCC_EPCI_CKCTRL_CRST0 | SCC_EPCI_CKCTRL_CRST1);
+		out_be32(reg, val);
+
+		/* set base translation registers. (already set by Beat) */
+
+		/* set base address masks. (already set by Beat) */
+	}
+
+	/* release interrupt masks and clear all interrupts */
+	reg = epci_base + SCC_EPCI_INTSET;
+	out_be32(reg, 0x013f011f);	/* all interrupts enable */
+	reg = epci_base + SCC_EPCI_VIENAB;
+	val = SCC_EPCI_VIENAB_PMPEE | SCC_EPCI_VIENAB_PMFEE;
+	out_be32(reg, val);
+	reg = epci_base + SCC_EPCI_STATUS;
+	out_be32(reg, 0xffffffff);
+	reg = epci_base + SCC_EPCI_VISTAT;
+	out_be32(reg, 0xffffffff);
+
+	/* disable PCI->IB address translation */
+	reg = epci_base + SCC_EPCI_VCSR;
+	val = in_be32(reg);
+	val &= ~(SCC_EPCI_VCSR_DR | SCC_EPCI_VCSR_AT);
+	out_be32(reg, val);
+
+	/* set base addresses. (no need to set?) */
+
+	/* memory space, bus master enable */
+	reg = epci_base + PCI_COMMAND;
+	val = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+	out_be32(reg, val);
+
+	/* endian mode setup */
+	reg = epci_base + SCC_EPCI_ECMODE;
+	val = 0x00550155;
+	out_be32(reg, val);
+
+	/* set control option */
+	reg = epci_base + SCC_EPCI_CNTOPT;
+	val = in_be32(reg);
+	val |= SCC_EPCI_CNTOPT_O2PMB;
+	out_be32(reg, val);
+
+	/* XXX: temporay: set registers for address conversion setup */
+	reg = epci_base + SCC_EPCI_CNF10_REG;
+	out_be32(reg, 0x80000008);
+	reg = epci_base + SCC_EPCI_CNF14_REG;
+	out_be32(reg, 0x40000008);
+
+	reg = epci_base + SCC_EPCI_BAM0;
+	out_be32(reg, 0x80000000);
+	reg = epci_base + SCC_EPCI_BAM1;
+	out_be32(reg, 0xe0000000);
+
+	reg = epci_base + SCC_EPCI_PVBAT;
+	out_be32(reg, 0x80000000);
+
+	if (!hwres) {
+		/* release external PCI reset */
+		reg = epci_base + SCC_EPCI_CLKRST;
+		val = in_be32(reg);
+		val |= SCC_EPCI_CLKRST_PCIRST;
+		out_be32(reg, val);
+	}
+
+	return 0;
+}
+
+int __devinit celleb_setup_epci(struct device_node *node,
+				struct pci_controller *hose)
+{
+	struct resource r;
+
+	pr_debug("PCI: celleb_setup_epci()\n");
+
+	if (of_address_to_resource(node, 0, &r))
+		goto error;
+	hose->cfg_addr = ioremap(r.start, (r.end - r.start + 1));
+	if (!hose->cfg_addr)
+		goto error;
+	pr_debug("EPCI: cfg_addr map 0x%016lx->0x%016lx + 0x%016lx\n",
+		 r.start, (unsigned long)hose->cfg_addr,
+		(r.end - r.start + 1));
+
+	if (of_address_to_resource(node, 2, &r))
+		goto error;
+	hose->cfg_data = ioremap(r.start, (r.end - r.start + 1));
+	if (!hose->cfg_data)
+		goto error;
+	pr_debug("EPCI: cfg_data map 0x%016lx->0x%016lx + 0x%016lx\n",
+		 r.start, (unsigned long)hose->cfg_data,
+		(r.end - r.start + 1));
+
+	celleb_epci_init(hose);
+
+	return 0;
+
+error:
+	return 1;
+}
diff --git a/arch/powerpc/platforms/celleb/scc_sio.c b/arch/powerpc/platforms/celleb/scc_sio.c
new file mode 100644
index 0000000..bcd25f5
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/scc_sio.c
@@ -0,0 +1,101 @@
+/*
+ * setup serial port in SCC
+ *
+ * (C) Copyright 2006 TOSHIBA 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; 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/console.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+
+/* sio irq0=0xb00010022 irq0=0xb00010023 irq2=0xb00010024
+    mmio=0xfff000-0x1000,0xff2000-0x1000 */
+static int txx9_serial_bitmap = 0;
+
+static struct {
+	uint32_t offset;
+	uint32_t index;
+} txx9_scc_tab[3] = {
+	{ 0x300, 0 },	/* 0xFFF300 */
+	{ 0x400, 0 },	/* 0xFFF400 */
+	{ 0x800, 1 }	/* 0xFF2800 */
+};
+
+static int txx9_serial_init(void)
+{
+	extern int early_serial_txx9_setup(struct uart_port *port);
+	struct device_node *node;
+	int i;
+	struct uart_port req;
+	struct of_irq irq;
+	struct resource res;
+
+	node = of_find_node_by_path("/ioif1/sio");
+	if (!node)
+		return 0;
+
+	for(i = 0; i < sizeof(txx9_scc_tab)/sizeof(txx9_scc_tab[0]); i++) {
+		if (!(txx9_serial_bitmap & (1<<i)))
+			continue;
+
+		if (of_irq_map_one(node, i, &irq))
+			continue;
+		if (of_address_to_resource(node, txx9_scc_tab[i].index, &res))
+			continue;
+
+		memset(&req, 0, sizeof(req));
+		req.line = i;
+		req.iotype = UPIO_MEM;
+		req.mapbase = res.start + txx9_scc_tab[i].offset;
+#ifdef CONFIG_SERIAL_TXX9_CONSOLE
+		req.membase = ioremap(req.mapbase, 0x24);
+#endif
+		req.irq = irq_create_of_mapping(irq.controller,
+			irq.specifier, irq.size);
+		req.flags |= UPF_IOREMAP | UPF_BUGGY_UART /*HAVE_CTS_LINE*/;
+		req.uartclk = 83300000;
+		early_serial_txx9_setup(&req);
+	}
+
+	of_node_put(node);
+	return 0;
+}
+
+static int txx9_serial_config(char *ptr)
+{
+	int	i;
+
+	for (;;) {
+		switch(get_option(&ptr, &i)) {
+		default:
+			return 0;
+		case 2:
+			txx9_serial_bitmap |= 1 << i;
+			break;
+		case 1:
+			txx9_serial_bitmap |= 1 << i;
+			return 0;
+		}
+	}
+}
+__setup("txx9_serial=", txx9_serial_config);
+
+console_initcall(txx9_serial_init);
diff --git a/arch/powerpc/platforms/celleb/scc_uhc.c b/arch/powerpc/platforms/celleb/scc_uhc.c
new file mode 100644
index 0000000..a7c548b
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/scc_uhc.c
@@ -0,0 +1,94 @@
+/*
+ * SCC (Super Companion Chip) UHC setup
+ *
+ * (C) Copyright 2006-2007 TOSHIBA 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; 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+
+#include "scc.h"
+
+#define UHC_RESET_WAIT_MAX 10000
+
+static inline int uhc_clkctrl_ready(u32 val)
+{
+	const u32 mask = SCC_UHC_USBCEN | SCC_UHC_USBCEN;
+	return((val & mask) == mask);
+}
+
+/*
+ * UHC(usb host controler) enable function.
+ * affect to both of OHCI and EHCI core module.
+ */
+static void enable_scc_uhc(struct pci_dev *dev)
+{
+	void __iomem *uhc_base;
+	u32 __iomem *uhc_clkctrl;
+	u32 __iomem *uhc_ecmode;
+	u32 val = 0;
+	int i;
+
+	if (!machine_is(celleb))
+		return;
+
+	uhc_base = ioremap(pci_resource_start(dev, 0),
+			   pci_resource_len(dev, 0));
+	if (!uhc_base) {
+		printk(KERN_ERR "failed to map UHC register base.\n");
+		return;
+	}
+	uhc_clkctrl = uhc_base + SCC_UHC_CKRCTRL;
+	uhc_ecmode  = uhc_base + SCC_UHC_ECMODE;
+
+	/* setup for normal mode */
+	val |= SCC_UHC_F48MCKLEN;
+	out_be32(uhc_clkctrl, val);
+	val |= SCC_UHC_PHY_SUSPEND_SEL;
+	out_be32(uhc_clkctrl, val);
+	udelay(10);
+	val |= SCC_UHC_PHYEN;
+	out_be32(uhc_clkctrl, val);
+	udelay(50);
+
+	/* disable reset */
+	val |= SCC_UHC_HCLKEN;
+	out_be32(uhc_clkctrl, val);
+	val |= (SCC_UHC_USBCEN | SCC_UHC_USBEN);
+	out_be32(uhc_clkctrl, val);
+	i = 0;
+	while (!uhc_clkctrl_ready(in_be32(uhc_clkctrl))) {
+		udelay(10);
+		if (i++ > UHC_RESET_WAIT_MAX) {
+			printk(KERN_ERR "Failed to disable UHC reset %x\n",
+			       in_be32(uhc_clkctrl));
+			break;
+		}
+	}
+
+	/* Endian Conversion Mode for Master ALL area */
+	out_be32(uhc_ecmode, SCC_UHC_ECMODE_BY_BYTE);
+
+	iounmap(uhc_base);
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2,
+		 PCI_DEVICE_ID_TOSHIBA_SCC_USB, enable_scc_uhc);
diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c
new file mode 100644
index 0000000..1de63ac
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/setup.c
@@ -0,0 +1,191 @@
+/*
+ * Celleb setup code
+ *
+ * (C) Copyright 2006-2007 TOSHIBA CORPORATION
+ *
+ * This code is based on arch/powerpc/platforms/cell/setup.c:
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  Modified by PPC64 Team, IBM Corp
+ *  Modified by Cell Team, IBM Deutschland Entwicklung GmbH
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#undef DEBUG
+
+#include <linux/cpu.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/console.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/kexec.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/cputable.h>
+#include <asm/irq.h>
+#include <asm/spu_priv1.h>
+#include <asm/firmware.h>
+#include <asm/of_platform.h>
+
+#include "interrupt.h"
+#include "beat_wrapper.h"
+#include "beat.h"
+#include "pci.h"
+
+static char celleb_machine_type[128] = "Celleb";
+
+static void celleb_show_cpuinfo(struct seq_file *m)
+{
+	struct device_node *root;
+	const char *model = "";
+
+	root = of_find_node_by_path("/");
+	if (root)
+		model = get_property(root, "model", NULL);
+	/* using "CHRP" is to trick anaconda into installing FCx into Celleb */
+	seq_printf(m, "machine\t\t: %s %s\n", celleb_machine_type, model);
+	of_node_put(root);
+}
+
+static int celleb_machine_type_hack(char *ptr)
+{
+	strncpy(celleb_machine_type, ptr, sizeof(celleb_machine_type));
+	celleb_machine_type[sizeof(celleb_machine_type)-1] = 0;
+	return 0;
+}
+
+__setup("celleb_machine_type_hack", celleb_machine_type_hack);
+
+static void celleb_progress(char *s, unsigned short hex)
+{
+	printk("*** %04x : %s\n", hex, s ? s : "");
+}
+
+static void __init celleb_setup_arch(void)
+{
+#ifdef CONFIG_SPU_BASE
+	spu_priv1_ops = &spu_priv1_beat_ops;
+	spu_management_ops = &spu_management_of_ops;
+#endif
+
+#ifdef CONFIG_SMP
+	smp_init_celleb();
+#endif
+
+	/* init to some ~sane value until calibrate_delay() runs */
+	loops_per_jiffy = 50000000;
+
+	if (ROOT_DEV == 0) {
+		printk("No ramdisk, default root is /dev/hda2\n");
+		ROOT_DEV = Root_HDA2;
+	}
+
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp = &dummy_con;
+#endif
+}
+
+static void beat_power_save(void)
+{
+	beat_pause(0);
+}
+
+static int __init celleb_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	if (!of_flat_dt_is_compatible(root, "Beat"))
+		return 0;
+
+	powerpc_firmware_features |= FW_FEATURE_CELLEB_POSSIBLE;
+	hpte_init_beat();
+	return 1;
+}
+
+/*
+ * Cell has no legacy IO; anything calling this function has to
+ * fail or bad things will happen
+ */
+static int celleb_check_legacy_ioport(unsigned int baseport)
+{
+	return -ENODEV;
+}
+
+static void celleb_kexec_cpu_down(int crash, int secondary)
+{
+	beatic_deinit_IRQ();
+}
+
+static struct of_device_id celleb_bus_ids[] = {
+	{ .type = "scc", },
+	{ .type = "ioif", },	/* old style */
+	{},
+};
+
+static int __init celleb_publish_devices(void)
+{
+	if (!machine_is(celleb))
+		return 0;
+
+	/* Publish OF platform devices for southbridge IOs */
+	of_platform_bus_probe(NULL, celleb_bus_ids, NULL);
+
+	return 0;
+}
+device_initcall(celleb_publish_devices);
+
+define_machine(celleb) {
+	.name			= "Cell Reference Set",
+	.probe			= celleb_probe,
+	.setup_arch		= celleb_setup_arch,
+	.show_cpuinfo		= celleb_show_cpuinfo,
+	.restart		= beat_restart,
+	.power_off		= beat_power_off,
+	.halt			= beat_halt,
+	.get_rtc_time		= beat_get_rtc_time,
+	.set_rtc_time		= beat_set_rtc_time,
+	.calibrate_decr		= generic_calibrate_decr,
+	.check_legacy_ioport	= celleb_check_legacy_ioport,
+	.progress		= celleb_progress,
+	.power_save		= beat_power_save,
+	.nvram_size		= beat_nvram_get_size,
+	.nvram_read		= beat_nvram_read,
+	.nvram_write		= beat_nvram_write,
+	.set_dabr		= beat_set_xdabr,
+	.init_IRQ		= beatic_init_IRQ,
+	.get_irq		= beatic_get_irq,
+	.pci_probe_mode 	= celleb_pci_probe_mode,
+	.pci_setup_phb		= celleb_setup_phb,
+#ifdef CONFIG_KEXEC
+	.kexec_cpu_down		= celleb_kexec_cpu_down,
+	.machine_kexec		= default_machine_kexec,
+	.machine_kexec_prepare	= default_machine_kexec_prepare,
+	.machine_crash_shutdown	= default_machine_crash_shutdown,
+#endif
+};
diff --git a/arch/powerpc/platforms/celleb/smp.c b/arch/powerpc/platforms/celleb/smp.c
new file mode 100644
index 0000000..a763125
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/smp.c
@@ -0,0 +1,124 @@
+/*
+ * SMP support for Celleb platform. (Incomplete)
+ *
+ * (C) Copyright 2006 TOSHIBA CORPORATION
+ *
+ * This code is based on arch/powerpc/platforms/cell/smp.c:
+ * Dave Engebretsen, Peter Bergner, and
+ * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
+ * Plus various changes from other IBM teams...
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/threads.h>
+#include <linux/cpu.h>
+
+#include <asm/irq.h>
+#include <asm/smp.h>
+#include <asm/machdep.h>
+#include <asm/udbg.h>
+
+#include "interrupt.h"
+
+#ifdef DEBUG
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+/*
+ * The primary thread of each non-boot processor is recorded here before
+ * smp init.
+ */
+/* static cpumask_t of_spin_map; */
+
+/**
+ * smp_startup_cpu() - start the given cpu
+ *
+ * At boot time, there is nothing to do for primary threads which were
+ * started from Open Firmware.  For anything else, call RTAS with the
+ * appropriate start location.
+ *
+ * Returns:
+ *	0	- failure
+ *	1	- success
+ */
+static inline int __devinit smp_startup_cpu(unsigned int lcpu)
+{
+	return 0;
+}
+
+static void smp_beatic_message_pass(int target, int msg)
+{
+	unsigned int i;
+
+	if (target < NR_CPUS) {
+		beatic_cause_IPI(target, msg);
+	} else {
+		for_each_online_cpu(i) {
+			if (target == MSG_ALL_BUT_SELF
+			    && i == smp_processor_id())
+				continue;
+			beatic_cause_IPI(i, msg);
+		}
+	}
+}
+
+static int __init smp_beatic_probe(void)
+{
+	return cpus_weight(cpu_possible_map);
+}
+
+static void __devinit smp_beatic_setup_cpu(int cpu)
+{
+	beatic_setup_cpu(cpu);
+}
+
+static void __devinit smp_celleb_kick_cpu(int nr)
+{
+	BUG_ON(nr < 0 || nr >= NR_CPUS);
+
+	if (!smp_startup_cpu(nr))
+		return;
+}
+
+static int smp_celleb_cpu_bootable(unsigned int nr)
+{
+	return 1;
+}
+static struct smp_ops_t bpa_beatic_smp_ops = {
+	.message_pass	= smp_beatic_message_pass,
+	.probe		= smp_beatic_probe,
+	.kick_cpu	= smp_celleb_kick_cpu,
+	.setup_cpu	= smp_beatic_setup_cpu,
+	.cpu_bootable	= smp_celleb_cpu_bootable,
+};
+
+/* This is called very early */
+void __init smp_init_celleb(void)
+{
+	DBG(" -> smp_init_celleb()\n");
+
+	smp_ops = &bpa_beatic_smp_ops;
+
+	DBG(" <- smp_init_celleb()\n");
+}
diff --git a/arch/powerpc/platforms/celleb/spu_priv1.c b/arch/powerpc/platforms/celleb/spu_priv1.c
new file mode 100644
index 0000000..2bf6700
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/spu_priv1.c
@@ -0,0 +1,208 @@
+/*
+ * spu hypervisor abstraction for Beat
+ *
+ * (C) Copyright 2006-2007 TOSHIBA 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; 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+
+#include <asm/types.h>
+#include <asm/spu.h>
+#include <asm/spu_priv1.h>
+
+#include "beat_wrapper.h"
+
+static inline void _int_mask_set(struct spu *spu, int class, u64 mask)
+{
+	spu->shadow_int_mask_RW[class] = mask;
+	beat_set_irq_mask_for_spe(spu->spe_id, class, mask);
+}
+
+static inline u64 _int_mask_get(struct spu *spu, int class)
+{
+	return spu->shadow_int_mask_RW[class];
+}
+
+static void int_mask_set(struct spu *spu, int class, u64 mask)
+{
+	_int_mask_set(spu, class, mask);
+}
+
+static u64 int_mask_get(struct spu *spu, int class)
+{
+	return _int_mask_get(spu, class);
+}
+
+static void int_mask_and(struct spu *spu, int class, u64 mask)
+{
+	u64 old_mask;
+	old_mask = _int_mask_get(spu, class);
+	_int_mask_set(spu, class, old_mask & mask);
+}
+
+static void int_mask_or(struct spu *spu, int class, u64 mask)
+{
+	u64 old_mask;
+	old_mask = _int_mask_get(spu, class);
+	_int_mask_set(spu, class, old_mask | mask);
+}
+
+static void int_stat_clear(struct spu *spu, int class, u64 stat)
+{
+	beat_clear_interrupt_status_of_spe(spu->spe_id, class, stat);
+}
+
+static u64 int_stat_get(struct spu *spu, int class)
+{
+	u64 int_stat;
+	beat_get_interrupt_status_of_spe(spu->spe_id, class, &int_stat);
+	return int_stat;
+}
+
+static void cpu_affinity_set(struct spu *spu, int cpu)
+{
+	return;
+}
+
+static u64 mfc_dar_get(struct spu *spu)
+{
+	u64 dar;
+	beat_get_spe_privileged_state_1_registers(
+		spu->spe_id,
+		offsetof(struct spu_priv1, mfc_dar_RW), &dar);
+	return dar;
+}
+
+static u64 mfc_dsisr_get(struct spu *spu)
+{
+	u64 dsisr;
+	beat_get_spe_privileged_state_1_registers(
+		spu->spe_id,
+		offsetof(struct spu_priv1, mfc_dsisr_RW), &dsisr);
+	return dsisr;
+}
+
+static void mfc_dsisr_set(struct spu *spu, u64 dsisr)
+{
+	beat_set_spe_privileged_state_1_registers(
+		spu->spe_id,
+		offsetof(struct spu_priv1, mfc_dsisr_RW), dsisr);
+}
+
+static void mfc_sdr_setup(struct spu *spu)
+{
+	return;
+}
+
+static void mfc_sr1_set(struct spu *spu, u64 sr1)
+{
+	beat_set_spe_privileged_state_1_registers(
+		spu->spe_id,
+		offsetof(struct spu_priv1, mfc_sr1_RW), sr1);
+}
+
+static u64 mfc_sr1_get(struct spu *spu)
+{
+	u64 sr1;
+	beat_get_spe_privileged_state_1_registers(
+		spu->spe_id,
+		offsetof(struct spu_priv1, mfc_sr1_RW), &sr1);
+	return sr1;
+}
+
+static void mfc_tclass_id_set(struct spu *spu, u64 tclass_id)
+{
+	beat_set_spe_privileged_state_1_registers(
+		spu->spe_id,
+		offsetof(struct spu_priv1, mfc_tclass_id_RW), tclass_id);
+}
+
+static u64 mfc_tclass_id_get(struct spu *spu)
+{
+	u64 tclass_id;
+	beat_get_spe_privileged_state_1_registers(
+		spu->spe_id,
+		offsetof(struct spu_priv1, mfc_tclass_id_RW), &tclass_id);
+	return tclass_id;
+}
+
+static void tlb_invalidate(struct spu *spu)
+{
+	beat_set_spe_privileged_state_1_registers(
+		spu->spe_id,
+		offsetof(struct spu_priv1, tlb_invalidate_entry_W), 0ul);
+}
+
+static void resource_allocation_groupID_set(struct spu *spu, u64 id)
+{
+	beat_set_spe_privileged_state_1_registers(
+		spu->spe_id,
+		offsetof(struct spu_priv1, resource_allocation_groupID_RW),
+		id);
+}
+
+static u64 resource_allocation_groupID_get(struct spu *spu)
+{
+	u64 id;
+	beat_get_spe_privileged_state_1_registers(
+		spu->spe_id,
+		offsetof(struct spu_priv1, resource_allocation_groupID_RW),
+		&id);
+	return id;
+}
+
+static void resource_allocation_enable_set(struct spu *spu, u64 enable)
+{
+	beat_set_spe_privileged_state_1_registers(
+		spu->spe_id,
+		offsetof(struct spu_priv1, resource_allocation_enable_RW),
+		enable);
+}
+
+static u64 resource_allocation_enable_get(struct spu *spu)
+{
+	u64 enable;
+	beat_get_spe_privileged_state_1_registers(
+		spu->spe_id,
+		offsetof(struct spu_priv1, resource_allocation_enable_RW),
+		&enable);
+	return enable;
+}
+
+const struct spu_priv1_ops spu_priv1_beat_ops =
+{
+	.int_mask_and = int_mask_and,
+	.int_mask_or = int_mask_or,
+	.int_mask_set = int_mask_set,
+	.int_mask_get = int_mask_get,
+	.int_stat_clear = int_stat_clear,
+	.int_stat_get = int_stat_get,
+	.cpu_affinity_set = cpu_affinity_set,
+	.mfc_dar_get = mfc_dar_get,
+	.mfc_dsisr_get = mfc_dsisr_get,
+	.mfc_dsisr_set = mfc_dsisr_set,
+	.mfc_sdr_setup = mfc_sdr_setup,
+	.mfc_sr1_set = mfc_sr1_set,
+	.mfc_sr1_get = mfc_sr1_get,
+	.mfc_tclass_id_set = mfc_tclass_id_set,
+	.mfc_tclass_id_get = mfc_tclass_id_get,
+	.tlb_invalidate = tlb_invalidate,
+	.resource_allocation_groupID_set = resource_allocation_groupID_set,
+	.resource_allocation_groupID_get = resource_allocation_groupID_get,
+	.resource_allocation_enable_set = resource_allocation_enable_set,
+	.resource_allocation_enable_get = resource_allocation_enable_get,
+};
diff --git a/arch/powerpc/platforms/celleb/udbg_beat.c b/arch/powerpc/platforms/celleb/udbg_beat.c
new file mode 100644
index 0000000..d888c46
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/udbg_beat.c
@@ -0,0 +1,97 @@
+/*
+ * udbg function for Beat
+ *
+ * (C) Copyright 2006 TOSHIBA 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; 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/console.h>
+
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+
+#include "beat.h"
+
+#define	celleb_vtermno	0
+
+static void udbg_putc_beat(char c)
+{
+	unsigned long rc;
+
+	if (c == '\n')
+		udbg_putc_beat('\r');
+
+	rc = beat_put_term_char(celleb_vtermno, 1, (uint64_t)c << 56, 0);
+}
+
+/* Buffered chars getc */
+static long inbuflen;
+static long inbuf[2];	/* must be 2 longs */
+
+static int udbg_getc_poll_beat(void)
+{
+	/* The interface is tricky because it may return up to 16 chars.
+	 * We save them statically for future calls to udbg_getc().
+	 */
+	char ch, *buf = (char *)inbuf;
+	int i;
+	long rc;
+	if (inbuflen == 0) {
+		/* get some more chars. */
+		inbuflen = 0;
+		rc = beat_get_term_char(celleb_vtermno, &inbuflen, inbuf+0, inbuf+1);
+		if (rc != 0)
+			inbuflen = 0;	/* otherwise inbuflen is garbage */
+	}
+	if (inbuflen <= 0 || inbuflen > 16) {
+		/* Catch error case as well as other oddities (corruption) */
+		inbuflen = 0;
+		return -1;
+	}
+	ch = buf[0];
+	for (i = 1; i < inbuflen; i++)	/* shuffle them down. */
+		buf[i-1] = buf[i];
+	inbuflen--;
+	return ch;
+}
+
+static int udbg_getc_beat(void)
+{
+	int ch;
+	for (;;) {
+		ch = udbg_getc_poll_beat();
+		if (ch == -1) {
+			/* This shouldn't be needed...but... */
+			volatile unsigned long delay;
+			for (delay=0; delay < 2000000; delay++)
+				;
+		} else {
+			return ch;
+		}
+	}
+}
+
+/* call this from early_init() for a working debug console on
+ * vterm capable LPAR machines
+ */
+void __init udbg_init_debug_beat(void)
+{
+	udbg_putc = udbg_putc_beat;
+	udbg_getc = udbg_getc_beat;
+	udbg_getc_poll = udbg_getc_poll_beat;
+}
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index e1f51d4..117c9a0 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -75,7 +75,7 @@
 extern unsigned long loops_per_jiffy;
 
 /* To be replaced by RTAS when available */
-static unsigned int *briq_SPOR;
+static unsigned int __iomem *briq_SPOR;
 
 #ifdef CONFIG_SMP
 extern struct smp_ops_t chrp_smp_ops;
@@ -267,7 +267,7 @@
 	} else if (machine && strncmp(machine, "TotalImpact,BRIQ-1", 18) == 0) {
 		_chrp_type = _CHRP_briq;
 		/* Map the SPOR register on briq and change the restart hook */
-		briq_SPOR = (unsigned int *)ioremap(0xff0000e8, 4);
+		briq_SPOR = ioremap(0xff0000e8, 4);
 		ppc_md.restart = briq_restart;
 	} else {
 		/* Let's assume it is an IBM chrp if all else fails */
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig
index b3c2ce4..886c522 100644
--- a/arch/powerpc/platforms/embedded6xx/Kconfig
+++ b/arch/powerpc/platforms/embedded6xx/Kconfig
@@ -104,15 +104,6 @@
 config PAL4
 	bool "SBS-Palomar4"
 
-config GEMINI
-	bool "Synergy-Gemini"
-	select PPC_INDIRECT_PCI
-	depends on BROKEN
-	help
-	  Select Gemini if configuring for a Synergy Microsystems' Gemini
-	  series Single Board Computer.  More information is available at:
-	  <http://www.synergymicro.com/PressRel/97_10_15.html>.
-
 config EST8260
 	bool "EST8260"
 	---help---
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c
index 3f6a69f..73c5990 100644
--- a/arch/powerpc/platforms/maple/pci.c
+++ b/arch/powerpc/platforms/maple/pci.c
@@ -425,14 +425,6 @@
         hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
         hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
 
-        /* The bus contains a bridge from root -> device, we need to
-         * make it visible on bus 0 so that we pick the right type
-         * of config cycles. If we didn't, we would have to force all
-         * config cycles to be type 1. So we override the "bus-range"
-         * property here
-         */
-        hose->first_busno = 0x00;
-        hose->last_busno = 0xff;
         u4_pcie = hose;
 }
 
@@ -560,13 +552,16 @@
 		return;
 	}
 	for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) {
-		if (np->name == NULL)
+		if (!np->type)
 			continue;
-		if (!strcmp(np->name, "pci") || !strcmp(np->name, "pcie")) {
-			if (add_bridge(np) == 0)
-				of_node_get(np);
-		}
-		if (strcmp(np->name, "ht") == 0) {
+		if (strcmp(np->type, "pci") && strcmp(np->type, "ht"))
+			continue;
+		if ((device_is_compatible(np, "u4-pcie") ||
+		     device_is_compatible(np, "u3-agp")) &&
+		    add_bridge(np) == 0)
+			of_node_get(np);
+
+		if (device_is_compatible(np, "u3-ht")) {
 			of_node_get(np);
 			ht = np;
 		}
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index 50855d4..82d3f9e 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -62,6 +62,7 @@
 #include <asm/mpic.h>
 #include <asm/rtas.h>
 #include <asm/udbg.h>
+#include <asm/nvram.h>
 
 #include "maple.h"
 
@@ -195,6 +196,8 @@
 	maple_use_rtas_reboot_and_halt_if_present();
 
 	printk(KERN_DEBUG "Using native/NAP idle loop\n");
+
+	mmio_nvram_init();
 }
 
 /* 
diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig
new file mode 100644
index 0000000..68dc529
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/Kconfig
@@ -0,0 +1,10 @@
+menu "PA Semi PWRficient options"
+	depends on PPC_PASEMI
+
+config PPC_PASEMI_IOMMU
+	bool "PA Semi IOMMU support"
+	depends on PPC_PASEMI
+	help
+	  IOMMU support for PA6T-1682M
+
+endmenu
diff --git a/arch/powerpc/platforms/pasemi/Makefile b/arch/powerpc/platforms/pasemi/Makefile
index 1be1a99..e657cca 100644
--- a/arch/powerpc/platforms/pasemi/Makefile
+++ b/arch/powerpc/platforms/pasemi/Makefile
@@ -1 +1,2 @@
-obj-y	+= setup.o pci.o time.o
+obj-y	+= setup.o pci.o time.o idle.o powersave.o iommu.o
+
diff --git a/arch/powerpc/platforms/pasemi/idle.c b/arch/powerpc/platforms/pasemi/idle.c
new file mode 100644
index 0000000..1ca3ff3
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/idle.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/machdep.h>
+#include <asm/reg.h>
+
+#include "pasemi.h"
+
+struct sleep_mode {
+	char *name;
+	void (*entry)(void);
+};
+
+static struct sleep_mode modes[] = {
+	{ .name = "spin", .entry = &idle_spin },
+	{ .name = "doze", .entry = &idle_doze },
+};
+
+static int current_mode = 0;
+
+static int pasemi_system_reset_exception(struct pt_regs *regs)
+{
+	/* If we were woken up from power savings, we need to return
+	 * to the calling function, since nip is not saved across
+	 * all modes.
+	 */
+
+	if (regs->msr & SRR1_WAKEMASK)
+		regs->nip = regs->link;
+
+	switch (regs->msr & SRR1_WAKEMASK) {
+	case SRR1_WAKEEE:
+		do_IRQ(regs);
+		break;
+	case SRR1_WAKEDEC:
+		timer_interrupt(regs);
+		break;
+	default:
+		/* do system reset */
+		return 0;
+	}
+	/* everything handled */
+	regs->msr |= MSR_RI;
+	return 1;
+}
+
+void __init pasemi_idle_init(void)
+{
+	ppc_md.system_reset_exception = pasemi_system_reset_exception;
+	ppc_md.power_save = modes[current_mode].entry;
+	printk(KERN_INFO "Using PA6T idle loop (%s)\n", modes[current_mode].name);
+}
+
+static int __init idle_param(char *p)
+{
+	int i;
+	for (i = 0; i < sizeof(modes)/sizeof(struct sleep_mode); i++) {
+		if (!strcmp(modes[i].name, p)) {
+			current_mode = i;
+			break;
+		}
+	}
+	return 0;
+}
+
+early_param("idle", idle_param);
diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c
new file mode 100644
index 0000000..459a53b
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/iommu.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2005-2007, PA Semi, Inc
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#undef DEBUG
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <asm/iommu.h>
+#include <asm/machdep.h>
+#include <asm/abs_addr.h>
+
+
+#define IOBMAP_PAGE_SHIFT	12
+#define IOBMAP_PAGE_SIZE	(1 << IOBMAP_PAGE_SHIFT)
+#define IOBMAP_PAGE_MASK	(IOBMAP_PAGE_SIZE - 1)
+
+#define IOBMAP_PAGE_FACTOR	(PAGE_SHIFT - IOBMAP_PAGE_SHIFT)
+
+#define IOB_BASE		0xe0000000
+#define IOB_SIZE		0x3000
+/* Configuration registers */
+#define IOBCAP_REG		0x10
+#define IOBCOM_REG		0x40
+/* Enable IOB address translation */
+#define IOBCOM_ATEN		0x00000100
+
+/* Address decode configuration register */
+#define IOB_AD_REG		0x53
+/* IOBCOM_AD_REG fields */
+#define IOB_AD_VGPRT		0x00000e00
+#define IOB_AD_VGAEN		0x00000100
+/* Direct mapping settings */
+#define IOB_AD_MPSEL_MASK	0x00000030
+#define IOB_AD_MPSEL_B38	0x00000000
+#define IOB_AD_MPSEL_B40	0x00000010
+#define IOB_AD_MPSEL_B42	0x00000020
+/* Translation window size / enable */
+#define IOB_AD_TRNG_MASK	0x00000003
+#define IOB_AD_TRNG_256M	0x00000000
+#define IOB_AD_TRNG_2G		0x00000001
+#define IOB_AD_TRNG_128G	0x00000003
+
+#define IOB_TABLEBASE_REG	0x55
+
+/* Base of the 64 4-byte L1 registers */
+#define IOB_XLT_L1_REGBASE	0xac0
+
+/* Register to invalidate TLB entries */
+#define IOB_AT_INVAL_TLB_REG	0xb40
+
+/* The top two bits of the level 1 entry contains valid and type flags */
+#define IOBMAP_L1E_V		0x40000000
+#define IOBMAP_L1E_V_B		0x80000000
+
+/* For big page entries, the bottom two bits contains flags */
+#define IOBMAP_L1E_BIG_CACHED	0x00000002
+#define IOBMAP_L1E_BIG_PRIORITY	0x00000001
+
+/* For regular level 2 entries, top 2 bits contain valid and cache flags */
+#define IOBMAP_L2E_V		0x80000000
+#define IOBMAP_L2E_V_CACHED	0xc0000000
+
+static u32 *iob;
+static u32 iob_l1_emptyval;
+static u32 iob_l2_emptyval;
+static u32 *iob_l2_base;
+
+static struct iommu_table iommu_table_iobmap;
+static int iommu_table_iobmap_inited;
+
+static void iobmap_build(struct iommu_table *tbl, long index,
+			 long npages, unsigned long uaddr,
+			 enum dma_data_direction direction)
+{
+	u32 *ip;
+	u32 rpn;
+	unsigned long bus_addr;
+
+	pr_debug("iobmap: build at: %lx, %lx, addr: %lx\n", index, npages, uaddr);
+
+	bus_addr = (tbl->it_offset + index) << PAGE_SHIFT;
+
+	npages <<= IOBMAP_PAGE_FACTOR;
+	index <<= IOBMAP_PAGE_FACTOR;
+
+	ip = ((u32 *)tbl->it_base) + index;
+
+	while (npages--) {
+		rpn = virt_to_abs(uaddr) >> IOBMAP_PAGE_SHIFT;
+
+		*(ip++) = IOBMAP_L2E_V | rpn;
+		/* invalidate tlb, can be optimized more */
+		out_le32(iob+IOB_AT_INVAL_TLB_REG, bus_addr >> 14);
+
+		uaddr += IOBMAP_PAGE_SIZE;
+		bus_addr += IOBMAP_PAGE_SIZE;
+	}
+}
+
+
+static void iobmap_free(struct iommu_table *tbl, long index,
+			long npages)
+{
+	u32 *ip;
+	unsigned long bus_addr;
+
+	pr_debug("iobmap: free at: %lx, %lx\n", index, npages);
+
+	bus_addr = (tbl->it_offset + index) << PAGE_SHIFT;
+
+	npages <<= IOBMAP_PAGE_FACTOR;
+	index <<= IOBMAP_PAGE_FACTOR;
+
+	ip = ((u32 *)tbl->it_base) + index;
+
+	while (npages--) {
+		*(ip++) = iob_l2_emptyval;
+		/* invalidate tlb, can be optimized more */
+		out_le32(iob+IOB_AT_INVAL_TLB_REG, bus_addr >> 14);
+		bus_addr += IOBMAP_PAGE_SIZE;
+	}
+}
+
+
+static void iommu_table_iobmap_setup(void)
+{
+	pr_debug(" -> %s\n", __func__);
+	iommu_table_iobmap.it_busno = 0;
+	iommu_table_iobmap.it_offset = 0;
+	/* it_size is in number of entries */
+	iommu_table_iobmap.it_size = 0x80000000 >> PAGE_SHIFT;
+
+	/* Initialize the common IOMMU code */
+	iommu_table_iobmap.it_base = (unsigned long)iob_l2_base;
+	iommu_table_iobmap.it_index = 0;
+	/* XXXOJN tune this to avoid IOB cache invals.
+	 * Should probably be 8 (64 bytes)
+	 */
+	iommu_table_iobmap.it_blocksize = 4;
+	iommu_init_table(&iommu_table_iobmap, 0);
+	pr_debug(" <- %s\n", __func__);
+}
+
+
+
+static void pci_dma_bus_setup_pasemi(struct pci_bus *bus)
+{
+	struct device_node *dn;
+
+	pr_debug("pci_dma_bus_setup, bus %p, bus->self %p\n", bus, bus->self);
+
+	if (!iommu_table_iobmap_inited) {
+		iommu_table_iobmap_inited = 1;
+		iommu_table_iobmap_setup();
+	}
+
+	dn = pci_bus_to_OF_node(bus);
+
+	if (dn)
+		PCI_DN(dn)->iommu_table = &iommu_table_iobmap;
+
+}
+
+
+static void pci_dma_dev_setup_pasemi(struct pci_dev *dev)
+{
+	pr_debug("pci_dma_dev_setup, dev %p (%s)\n", dev, pci_name(dev));
+
+	/* DMA device is untranslated, but all other PCI-e goes through
+	 * the IOMMU
+	 */
+	if (dev->vendor == 0x1959 && dev->device == 0xa007)
+		dev->dev.archdata.dma_ops = &dma_direct_ops;
+	else
+		dev->dev.archdata.dma_data = &iommu_table_iobmap;
+}
+
+static void pci_dma_bus_setup_null(struct pci_bus *b) { }
+static void pci_dma_dev_setup_null(struct pci_dev *d) { }
+
+int iob_init(struct device_node *dn)
+{
+	unsigned long tmp;
+	u32 regword;
+	int i;
+
+	pr_debug(" -> %s\n", __func__);
+
+	/* Allocate a spare page to map all invalid IOTLB pages. */
+	tmp = lmb_alloc(IOBMAP_PAGE_SIZE, IOBMAP_PAGE_SIZE);
+	if (!tmp)
+		panic("IOBMAP: Cannot allocate spare page!");
+	/* Empty l1 is marked invalid */
+	iob_l1_emptyval = 0;
+	/* Empty l2 is mapped to dummy page */
+	iob_l2_emptyval = IOBMAP_L2E_V | (tmp >> IOBMAP_PAGE_SHIFT);
+
+	iob = ioremap(IOB_BASE, IOB_SIZE);
+	if (!iob)
+		panic("IOBMAP: Cannot map registers!");
+
+	/* setup direct mapping of the L1 entries */
+	for (i = 0; i < 64; i++) {
+		/* Each L1 covers 32MB, i.e. 8K entries = 32K of ram */
+		regword = IOBMAP_L1E_V | (__pa(iob_l2_base + i*0x2000) >> 12);
+		out_le32(iob+IOB_XLT_L1_REGBASE+i, regword);
+	}
+
+	/* set 2GB translation window, based at 0 */
+	regword = in_le32(iob+IOB_AD_REG);
+	regword &= ~IOB_AD_TRNG_MASK;
+	regword |= IOB_AD_TRNG_2G;
+	out_le32(iob+IOB_AD_REG, regword);
+
+	/* Enable translation */
+	regword = in_le32(iob+IOBCOM_REG);
+	regword |= IOBCOM_ATEN;
+	out_le32(iob+IOBCOM_REG, regword);
+
+	pr_debug(" <- %s\n", __func__);
+
+	return 0;
+}
+
+
+/* These are called very early. */
+void iommu_init_early_pasemi(void)
+{
+	int iommu_off;
+
+#ifndef CONFIG_PPC_PASEMI_IOMMU
+	iommu_off = 1;
+#else
+	iommu_off = of_chosen &&
+			get_property(of_chosen, "linux,iommu-off", NULL);
+#endif
+	if (iommu_off) {
+		/* Direct I/O, IOMMU off */
+		ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_null;
+		ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_null;
+		pci_dma_ops = &dma_direct_ops;
+
+		return;
+	}
+
+	iob_init(NULL);
+
+	ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_pasemi;
+	ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pasemi;
+	ppc_md.tce_build = iobmap_build;
+	ppc_md.tce_free  = iobmap_free;
+	pci_dma_ops = &dma_iommu_ops;
+}
+
+void __init alloc_iobmap_l2(void)
+{
+#ifndef CONFIG_PPC_PASEMI_IOMMU
+	return;
+#endif
+	/* For 2G space, 8x64 pages (2^21 bytes) is max total l2 size */
+	iob_l2_base = (u32 *)abs_to_virt(lmb_alloc_base(1UL<<21, 1UL<<21, 0x80000000));
+
+	printk(KERN_INFO "IOBMAP L2 allocated at: %p\n", iob_l2_base);
+}
diff --git a/arch/powerpc/platforms/pasemi/pasemi.h b/arch/powerpc/platforms/pasemi/pasemi.h
index 51c2a23..2d3927e 100644
--- a/arch/powerpc/platforms/pasemi/pasemi.h
+++ b/arch/powerpc/platforms/pasemi/pasemi.h
@@ -3,5 +3,17 @@
 
 extern unsigned long pas_get_boot_time(void);
 extern void pas_pci_init(void);
+extern void __devinit pas_pci_irq_fixup(struct pci_dev *dev);
+extern void __devinit pas_pci_dma_dev_setup(struct pci_dev *dev);
+
+extern void __init alloc_iobmap_l2(void);
+
+extern void __init pasemi_idle_init(void);
+
+/* Power savings modes, implemented in asm */
+extern void idle_spin(void);
+extern void idle_doze(void);
+
+
 
 #endif /* _PASEMI_PASEMI_H */
diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c
index faa618e..7ecb2ba 100644
--- a/arch/powerpc/platforms/pasemi/pci.c
+++ b/arch/powerpc/platforms/pasemi/pci.c
@@ -163,6 +163,19 @@
 }
 
 
+void __devinit pas_pci_irq_fixup(struct pci_dev *dev)
+{
+	/* DMA is special, 84 interrupts (128 -> 211), all but 128
+	 * need to be mapped by hand here.
+	 */
+	if (dev->vendor == 0x1959 && dev->device == 0xa007) {
+		int i;
+		for (i = 129; i < 212; i++)
+			irq_create_mapping(NULL, i);
+	}
+}
+
+
 void __init pas_pci_init(void)
 {
 	struct device_node *np, *root;
diff --git a/arch/powerpc/platforms/pasemi/powersave.S b/arch/powerpc/platforms/pasemi/powersave.S
new file mode 100644
index 0000000..6d0fba6
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/powersave.S
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/cputable.h>
+#include <asm/cache.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+
+/* Power savings opcodes since not all binutils have them at this time */
+#define DOZE	.long	0x4c000324
+#define NAP	.long	0x4c000364
+#define SLEEP	.long	0x4c0003a4
+#define RVW	.long	0x4c0003e4
+
+/* Common sequence to do before going to any of the
+ * powersavings modes.
+ */
+
+#define PRE_SLEEP_SEQUENCE	\
+	std	r3,8(r1);	\
+	ptesync	;		\
+	ld	r3,8(r1);	\
+1:	cmpd 	r3,r3;		\
+	bne	1b
+
+_doze:
+	PRE_SLEEP_SEQUENCE
+	DOZE
+	b	.
+
+
+_GLOBAL(idle_spin)
+	blr
+
+_GLOBAL(idle_doze)
+	LOAD_REG_ADDR(r3, _doze)
+	b	sleep_common
+
+/* Add more modes here later */
+
+sleep_common:
+	mflr	r0
+	std	r0, 16(r1)
+	stdu	r1,-64(r1)
+
+	LOAD_REG_IMMEDIATE(r6,MSR_DR|MSR_IR|MSR_ME|MSR_EE)
+	mfmsr	r4
+	andc	r5,r4,r6
+	mtmsrd	r5,0
+
+	mtctr	r3
+	bctrl
+
+	mtmsrd	r4,0
+
+	addi	r1,r1,64
+	ld	r0,16(r1)
+	mtlr	r0
+	blr
+
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
index bea7d1b..449cf1a 100644
--- a/arch/powerpc/platforms/pasemi/setup.c
+++ b/arch/powerpc/platforms/pasemi/setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 PA Semi, Inc
+ * Copyright (C) 2006-2007 PA Semi, Inc
  *
  * Authors: Kip Walker, PA Semi
  *	    Olof Johansson, PA Semi
@@ -38,31 +38,46 @@
 
 #include "pasemi.h"
 
+static void __iomem *reset_reg;
+
 static void pas_restart(char *cmd)
 {
-	printk("restart unimplemented, looping...\n");
-	for (;;) ;
-}
-
-static void pas_power_off(void)
-{
-	printk("power off unimplemented, looping...\n");
-	for (;;) ;
-}
-
-static void pas_halt(void)
-{
-	pas_power_off();
+	printk("Restarting...\n");
+	while (1)
+		out_le32(reset_reg, 0x6000000);
 }
 
 #ifdef CONFIG_SMP
+static DEFINE_SPINLOCK(timebase_lock);
+
+static void __devinit pas_give_timebase(void)
+{
+	unsigned long tb;
+
+	spin_lock(&timebase_lock);
+	mtspr(SPRN_TBCTL, TBCTL_FREEZE);
+	tb = mftb();
+	mtspr(SPRN_TBCTL, TBCTL_UPDATE_LOWER | (tb & 0xffffffff));
+	mtspr(SPRN_TBCTL, TBCTL_UPDATE_UPPER | (tb >> 32));
+	mtspr(SPRN_TBCTL, TBCTL_RESTART);
+	spin_unlock(&timebase_lock);
+	pr_debug("pas_give_timebase: cpu %d gave tb %lx\n",
+		 smp_processor_id(), tb);
+}
+
+static void __devinit pas_take_timebase(void)
+{
+	pr_debug("pas_take_timebase: cpu %d has tb %lx\n",
+		 smp_processor_id(), mftb());
+}
+
 struct smp_ops_t pas_smp_ops = {
 	.probe		= smp_mpic_probe,
 	.message_pass	= smp_mpic_message_pass,
 	.kick_cpu	= smp_generic_kick_cpu,
 	.setup_cpu	= smp_mpic_setup_cpu,
-	.give_timebase	= smp_generic_give_timebase,
-	.take_timebase	= smp_generic_take_timebase,
+	.give_timebase	= pas_give_timebase,
+	.take_timebase	= pas_take_timebase,
 };
 #endif /* CONFIG_SMP */
 
@@ -72,9 +87,6 @@
 	/* Setup SMP callback */
 	smp_ops = &pas_smp_ops;
 #endif
-	/* no iommu yet */
-	pci_dma_ops = &dma_direct_ops;
-
 	/* Lookup PCI hosts */
 	pas_pci_init();
 
@@ -82,7 +94,11 @@
 	conswitchp = &dummy_con;
 #endif
 
-	printk(KERN_DEBUG "Using default idle loop\n");
+	/* Remap SDC register for doing reset */
+	/* XXXOJN This should maybe come out of the device tree */
+	reset_reg = ioremap(0xfc101100, 4);
+
+	pasemi_idle_init();
 }
 
 /* No legacy IO on our parts */
@@ -130,8 +146,9 @@
 	openpic_addr = of_read_number(opprop, naddr);
 	printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr);
 
-	mpic = mpic_alloc(mpic_node, openpic_addr, MPIC_PRIMARY, 0, 0,
-			  " PAS-OPIC  ");
+	mpic = mpic_alloc(mpic_node, openpic_addr,
+			  MPIC_PRIMARY|MPIC_LARGE_VECTORS,
+			  0, 0, " PAS-OPIC  ");
 	BUG_ON(!mpic);
 
 	mpic_assign_isu(mpic, 0, openpic_addr + 0x10000);
@@ -146,6 +163,53 @@
 }
 
 
+static int pas_machine_check_handler(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+	unsigned long srr0, srr1, dsisr;
+
+	srr0 = regs->nip;
+	srr1 = regs->msr;
+	dsisr = mfspr(SPRN_DSISR);
+	printk(KERN_ERR "Machine Check on CPU %d\n", cpu);
+	printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1);
+	printk(KERN_ERR "DSISR 0x%016lx DAR 0x%016lx\n", dsisr, regs->dar);
+	printk(KERN_ERR "Cause:\n");
+
+	if (srr1 & 0x200000)
+		printk(KERN_ERR "Signalled by SDC\n");
+	if (srr1 & 0x100000) {
+		printk(KERN_ERR "Load/Store detected error:\n");
+		if (dsisr & 0x8000)
+			printk(KERN_ERR "D-cache ECC double-bit error or bus error\n");
+		if (dsisr & 0x4000)
+			printk(KERN_ERR "LSU snoop response error\n");
+		if (dsisr & 0x2000)
+			printk(KERN_ERR "MMU SLB multi-hit or invalid B field\n");
+		if (dsisr & 0x1000)
+			printk(KERN_ERR "Recoverable Duptags\n");
+		if (dsisr & 0x800)
+			printk(KERN_ERR "Recoverable D-cache parity error count overflow\n");
+		if (dsisr & 0x400)
+			printk(KERN_ERR "TLB parity error count overflow\n");
+	}
+	if (srr1 & 0x80000)
+		printk(KERN_ERR "Bus Error\n");
+	if (srr1 & 0x40000)
+		printk(KERN_ERR "I-side SLB multiple hit\n");
+	if (srr1 & 0x20000)
+		printk(KERN_ERR "I-cache parity error hit\n");
+
+	/* SRR1[62] is from MSR[62] if recoverable, so pass that back */
+	return !!(srr1 & 0x2);
+}
+
+static void __init pas_init_early(void)
+{
+	iommu_init_early_pasemi();
+}
+
+
 /*
  * Called very early, MMU is off, device-tree isn't unflattened
  */
@@ -158,6 +222,8 @@
 
 	hpte_init_native();
 
+	alloc_iobmap_l2();
+
 	return 1;
 }
 
@@ -165,13 +231,14 @@
 	.name			= "PA Semi PA6T-1682M",
 	.probe			= pas_probe,
 	.setup_arch		= pas_setup_arch,
+	.init_early		= pas_init_early,
 	.init_IRQ		= pas_init_IRQ,
 	.get_irq		= mpic_get_irq,
 	.restart		= pas_restart,
-	.power_off		= pas_power_off,
-	.halt			= pas_halt,
 	.get_boot_time		= pas_get_boot_time,
 	.calibrate_decr		= generic_calibrate_decr,
 	.check_legacy_ioport    = pas_check_legacy_ioport,
 	.progress		= pas_progress,
+	.machine_check_exception = pas_machine_check_handler,
+	.pci_irq_fixup		= pas_pci_irq_fixup,
 };
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index eeb2ae5..d73fb73 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -795,7 +795,6 @@
 		ppc_md.progress("smp_core99_kick_cpu", 0x346);
 
 	local_irq_save(flags);
-	local_irq_disable();
 
 	/* Save reset vector */
 	save_vector = *vector;
diff --git a/arch/powerpc/platforms/ps3/Makefile b/arch/powerpc/platforms/ps3/Makefile
index 1994904..a0048fc 100644
--- a/arch/powerpc/platforms/ps3/Makefile
+++ b/arch/powerpc/platforms/ps3/Makefile
@@ -1,5 +1,6 @@
 obj-y += setup.o mm.o time.o hvcall.o htab.o repository.o
 obj-y += interrupt.o exports.o os-area.o
+obj-y += system-bus.o
 
 obj-$(CONFIG_SMP) += smp.o
 obj-$(CONFIG_SPU_BASE) += spu.o
diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c
index 8fe1769..a4b5a1b 100644
--- a/arch/powerpc/platforms/ps3/htab.c
+++ b/arch/powerpc/platforms/ps3/htab.c
@@ -23,7 +23,6 @@
 #include <asm/machdep.h>
 #include <asm/lmb.h>
 #include <asm/udbg.h>
-#include <asm/ps3.h>
 #include <asm/lv1call.h>
 
 #include "platform.h"
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index 6f5de43..631c300 100644
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -24,7 +24,6 @@
 
 #include <asm/machdep.h>
 #include <asm/udbg.h>
-#include <asm/ps3.h>
 #include <asm/lv1call.h>
 
 #include "platform.h"
@@ -36,15 +35,148 @@
 #endif
 
 /**
+ * struct ps3_bmp - a per cpu irq status and mask bitmap structure
+ * @status: 256 bit status bitmap indexed by plug
+ * @unused_1:
+ * @mask: 256 bit mask bitmap indexed by plug
+ * @unused_2:
+ * @lock:
+ * @ipi_debug_brk_mask:
+ *
+ * The HV mantains per SMT thread mappings of HV outlet to HV plug on
+ * behalf of the guest.  These mappings are implemented as 256 bit guest
+ * supplied bitmaps indexed by plug number.  The addresses of the bitmaps
+ * are registered with the HV through lv1_configure_irq_state_bitmap().
+ * The HV requires that the 512 bits of status + mask not cross a page
+ * boundary.  PS3_BMP_MINALIGN is used to define this minimal 64 byte
+ * alignment.
+ *
+ * The HV supports 256 plugs per thread, assigned as {0..255}, for a total
+ * of 512 plugs supported on a processor.  To simplify the logic this
+ * implementation equates HV plug value to Linux virq value, constrains each
+ * interrupt to have a system wide unique plug number, and limits the range
+ * of the plug values to map into the first dword of the bitmaps.  This
+ * gives a usable range of plug values of  {NUM_ISA_INTERRUPTS..63}.  Note
+ * that there is no constraint on how many in this set an individual thread
+ * can acquire.
+ */
+
+#define PS3_BMP_MINALIGN 64
+
+struct ps3_bmp {
+	struct {
+		u64 status;
+		u64 unused_1[3];
+		u64 mask;
+		u64 unused_2[3];
+	};
+	u64 ipi_debug_brk_mask;
+	spinlock_t lock;
+};
+
+/**
+ * struct ps3_private - a per cpu data structure
+ * @bmp: ps3_bmp structure
+ * @node: HV logical_ppe_id
+ * @cpu: HV thread_id
+ */
+
+struct ps3_private {
+	struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN)));
+	u64 node;
+	unsigned int cpu;
+};
+
+static DEFINE_PER_CPU(struct ps3_private, ps3_private);
+
+int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
+	unsigned int *virq)
+{
+	int result;
+	struct ps3_private *pd;
+
+	/* This defines the default interrupt distribution policy. */
+
+	if (cpu == PS3_BINDING_CPU_ANY)
+		cpu = 0;
+
+	pd = &per_cpu(ps3_private, cpu);
+
+	*virq = irq_create_mapping(NULL, outlet);
+
+	if (*virq == NO_IRQ) {
+		pr_debug("%s:%d: irq_create_mapping failed: outlet %lu\n",
+			__func__, __LINE__, outlet);
+		result = -ENOMEM;
+		goto fail_create;
+	}
+
+	/* Binds outlet to cpu + virq. */
+
+	result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0);
+
+	if (result) {
+		pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",
+		__func__, __LINE__, ps3_result(result));
+		result = -EPERM;
+		goto fail_connect;
+	}
+
+	pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__,
+		outlet, cpu, *virq);
+
+	result = set_irq_chip_data(*virq, pd);
+
+	if (result) {
+		pr_debug("%s:%d: set_irq_chip_data failed\n",
+			__func__, __LINE__);
+		goto fail_set;
+	}
+
+	return result;
+
+fail_set:
+	lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, *virq);
+fail_connect:
+	irq_dispose_mapping(*virq);
+fail_create:
+	return result;
+}
+EXPORT_SYMBOL_GPL(ps3_alloc_irq);
+
+int ps3_free_irq(unsigned int virq)
+{
+	int result;
+	const struct ps3_private *pd = get_irq_chip_data(virq);
+
+	pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__,
+		pd->node, pd->cpu, virq);
+
+	result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq);
+
+	if (result)
+		pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",
+		__func__, __LINE__, ps3_result(result));
+
+	set_irq_chip_data(virq, NULL);
+	irq_dispose_mapping(virq);
+	return result;
+}
+EXPORT_SYMBOL_GPL(ps3_free_irq);
+
+/**
  * ps3_alloc_io_irq - Assign a virq to a system bus device.
- * interrupt_id: The device interrupt id read from the system repository.
+ * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+ * serviced on.
+ * @interrupt_id: The device interrupt id read from the system repository.
  * @virq: The assigned Linux virq.
  *
  * An io irq represents a non-virtualized device interrupt.  interrupt_id
  * coresponds to the interrupt number of the interrupt controller.
  */
 
-int ps3_alloc_io_irq(unsigned int interrupt_id, unsigned int *virq)
+int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
+	unsigned int *virq)
 {
 	int result;
 	unsigned long outlet;
@@ -57,13 +189,12 @@
 		return result;
 	}
 
-	*virq = irq_create_mapping(NULL, outlet);
+	result = ps3_alloc_irq(cpu, outlet, virq);
+	BUG_ON(result);
 
-	pr_debug("%s:%d: interrupt_id %u => outlet %lu, virq %u\n",
-		__func__, __LINE__, interrupt_id, outlet, *virq);
-
-	return 0;
+	return result;
 }
+EXPORT_SYMBOL_GPL(ps3_alloc_io_irq);
 
 int ps3_free_io_irq(unsigned int virq)
 {
@@ -75,13 +206,16 @@
 		pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
 			__func__, __LINE__, ps3_result(result));
 
-	irq_dispose_mapping(virq);
+	ps3_free_irq(virq);
 
 	return result;
 }
+EXPORT_SYMBOL_GPL(ps3_free_io_irq);
 
 /**
  * ps3_alloc_event_irq - Allocate a virq for use with a system event.
+ * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+ * serviced on.
  * @virq: The assigned Linux virq.
  *
  * The virq can be used with lv1_connect_interrupt_event_receive_port() to
@@ -89,7 +223,7 @@
  * events.
  */
 
-int ps3_alloc_event_irq(unsigned int *virq)
+int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq)
 {
 	int result;
 	unsigned long outlet;
@@ -103,12 +237,10 @@
 		return result;
 	}
 
-	*virq = irq_create_mapping(NULL, outlet);
+	result = ps3_alloc_irq(cpu, outlet, virq);
+	BUG_ON(result);
 
-	pr_debug("%s:%d: outlet %lu, virq %u\n", __func__, __LINE__, outlet,
-		*virq);
-
-	return 0;
+	return result;
 }
 
 int ps3_free_event_irq(unsigned int virq)
@@ -123,7 +255,7 @@
 		pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n",
 			__func__, __LINE__, ps3_result(result));
 
-	irq_dispose_mapping(virq);
+	ps3_free_irq(virq);
 
 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
 	return result;
@@ -136,6 +268,8 @@
 
 /**
  * ps3_connect_event_irq - Assign a virq to a system bus device.
+ * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+ * serviced on.
  * @did: The HV device identifier read from the system repository.
  * @interrupt_id: The device interrupt id read from the system repository.
  * @virq: The assigned Linux virq.
@@ -144,12 +278,13 @@
  * coresponds to the software interrupt number.
  */
 
-int ps3_connect_event_irq(const struct ps3_device_id *did,
-	unsigned int interrupt_id, unsigned int *virq)
+int ps3_connect_event_irq(enum ps3_cpu_binding cpu,
+	const struct ps3_device_id *did, unsigned int interrupt_id,
+	unsigned int *virq)
 {
 	int result;
 
-	result = ps3_alloc_event_irq(virq);
+	result = ps3_alloc_event_irq(cpu, virq);
 
 	if (result)
 		return result;
@@ -196,6 +331,8 @@
 
 /**
  * ps3_alloc_vuart_irq - Configure the system virtual uart virq.
+ * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+ * serviced on.
  * @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap.
  * @virq: The assigned Linux virq.
  *
@@ -203,13 +340,14 @@
  * freeing the interrupt will return a wrong state error.
  */
 
-int ps3_alloc_vuart_irq(void* virt_addr_bmp, unsigned int *virq)
+int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
+	unsigned int *virq)
 {
 	int result;
 	unsigned long outlet;
-	unsigned long lpar_addr;
+	u64 lpar_addr;
 
-	BUG_ON(!is_kernel_addr((unsigned long)virt_addr_bmp));
+	BUG_ON(!is_kernel_addr((u64)virt_addr_bmp));
 
 	lpar_addr = ps3_mm_phys_to_lpar(__pa(virt_addr_bmp));
 
@@ -221,12 +359,10 @@
 		return result;
 	}
 
-	*virq = irq_create_mapping(NULL, outlet);
+	result = ps3_alloc_irq(cpu, outlet, virq);
+	BUG_ON(result);
 
-	pr_debug("%s:%d: outlet %lu, virq %u\n", __func__, __LINE__,
-		outlet, *virq);
-
-	return 0;
+	return result;
 }
 
 int ps3_free_vuart_irq(unsigned int virq)
@@ -241,21 +377,23 @@
 		return result;
 	}
 
-	irq_dispose_mapping(virq);
+	ps3_free_irq(virq);
 
 	return result;
 }
 
 /**
  * ps3_alloc_spe_irq - Configure an spe virq.
+ * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+ * serviced on.
  * @spe_id: The spe_id returned from lv1_construct_logical_spe().
  * @class: The spe interrupt class {0,1,2}.
  * @virq: The assigned Linux virq.
  *
  */
 
-int ps3_alloc_spe_irq(unsigned long spe_id, unsigned int class,
-	unsigned int *virq)
+int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id,
+	unsigned int class, unsigned int *virq)
 {
 	int result;
 	unsigned long outlet;
@@ -270,73 +408,24 @@
 		return result;
 	}
 
-	*virq = irq_create_mapping(NULL, outlet);
+	result = ps3_alloc_irq(cpu, outlet, virq);
+	BUG_ON(result);
 
-	pr_debug("%s:%d: spe_id %lu, class %u, outlet %lu, virq %u\n",
-		__func__, __LINE__, spe_id, class, outlet, *virq);
-
-	return 0;
+	return result;
 }
 
 int ps3_free_spe_irq(unsigned int virq)
 {
-	irq_dispose_mapping(virq);
+	ps3_free_irq(virq);
 	return 0;
 }
 
+
 #define PS3_INVALID_OUTLET ((irq_hw_number_t)-1)
 #define PS3_PLUG_MAX 63
 
-/**
- * struct bmp - a per cpu irq status and mask bitmap structure
- * @status: 256 bit status bitmap indexed by plug
- * @unused_1:
- * @mask: 256 bit mask bitmap indexed by plug
- * @unused_2:
- * @lock:
- * @ipi_debug_brk_mask:
- *
- * The HV mantains per SMT thread mappings of HV outlet to HV plug on
- * behalf of the guest.  These mappings are implemented as 256 bit guest
- * supplied bitmaps indexed by plug number.  The address of the bitmaps are
- * registered with the HV through lv1_configure_irq_state_bitmap().
- *
- * The HV supports 256 plugs per thread, assigned as {0..255}, for a total
- * of 512 plugs supported on a processor.  To simplify the logic this
- * implementation equates HV plug value to linux virq value, constrains each
- * interrupt to have a system wide unique plug number, and limits the range
- * of the plug values to map into the first dword of the bitmaps.  This
- * gives a usable range of plug values of  {NUM_ISA_INTERRUPTS..63}.  Note
- * that there is no constraint on how many in this set an individual thread
- * can aquire.
- */
-
-struct bmp {
-	struct {
-		unsigned long status;
-		unsigned long unused_1[3];
-		unsigned long mask;
-		unsigned long unused_2[3];
-	} __attribute__ ((packed));
-	spinlock_t lock;
-	unsigned long ipi_debug_brk_mask;
-};
-
-/**
- * struct private - a per cpu data structure
- * @node: HV node id
- * @cpu: HV thread id
- * @bmp: an HV bmp structure
- */
-
-struct private {
-	unsigned long node;
-	unsigned int cpu;
-	struct bmp bmp;
-};
-
 #if defined(DEBUG)
-static void _dump_64_bmp(const char *header, const unsigned long *p, unsigned cpu,
+static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu,
 	const char* func, int line)
 {
 	pr_debug("%s:%d: %s %u {%04lx_%04lx_%04lx_%04lx}\n",
@@ -346,14 +435,14 @@
 }
 
 static void __attribute__ ((unused)) _dump_256_bmp(const char *header,
-	const unsigned long *p, unsigned cpu, const char* func, int line)
+	const u64 *p, unsigned cpu, const char* func, int line)
 {
 	pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n",
 		func, line, header, cpu, p[0], p[1], p[2], p[3]);
 }
 
 #define dump_bmp(_x) _dump_bmp(_x, __func__, __LINE__)
-static void _dump_bmp(struct private* pd, const char* func, int line)
+static void _dump_bmp(struct ps3_private* pd, const char* func, int line)
 {
 	unsigned long flags;
 
@@ -364,7 +453,7 @@
 }
 
 #define dump_mask(_x) _dump_mask(_x, __func__, __LINE__)
-static void __attribute__ ((unused)) _dump_mask(struct private* pd,
+static void __attribute__ ((unused)) _dump_mask(struct ps3_private* pd,
 	const char* func, int line)
 {
 	unsigned long flags;
@@ -374,109 +463,94 @@
 	spin_unlock_irqrestore(&pd->bmp.lock, flags);
 }
 #else
-static void dump_bmp(struct private* pd) {};
+static void dump_bmp(struct ps3_private* pd) {};
 #endif /* defined(DEBUG) */
 
-static void chip_mask(unsigned int virq)
+static void ps3_chip_mask(unsigned int virq)
 {
+	struct ps3_private *pd = get_irq_chip_data(virq);
+	u64 bit = 0x8000000000000000UL >> virq;
+	u64 *p = &pd->bmp.mask;
+	u64 old;
 	unsigned long flags;
-	struct private *pd = get_irq_chip_data(virq);
 
 	pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
 
-	BUG_ON(virq < NUM_ISA_INTERRUPTS);
-	BUG_ON(virq > PS3_PLUG_MAX);
-
-	spin_lock_irqsave(&pd->bmp.lock, flags);
-	pd->bmp.mask &= ~(0x8000000000000000UL >> virq);
-	spin_unlock_irqrestore(&pd->bmp.lock, flags);
+	local_irq_save(flags);
+	asm volatile(
+		     "1:	ldarx %0,0,%3\n"
+		     "andc	%0,%0,%2\n"
+		     "stdcx.	%0,0,%3\n"
+		     "bne-	1b"
+		     : "=&r" (old), "+m" (*p)
+		     : "r" (bit), "r" (p)
+		     : "cc" );
 
 	lv1_did_update_interrupt_mask(pd->node, pd->cpu);
+	local_irq_restore(flags);
 }
 
-static void chip_unmask(unsigned int virq)
+static void ps3_chip_unmask(unsigned int virq)
 {
+	struct ps3_private *pd = get_irq_chip_data(virq);
+	u64 bit = 0x8000000000000000UL >> virq;
+	u64 *p = &pd->bmp.mask;
+	u64 old;
 	unsigned long flags;
-	struct private *pd = get_irq_chip_data(virq);
 
 	pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
 
-	BUG_ON(virq < NUM_ISA_INTERRUPTS);
-	BUG_ON(virq > PS3_PLUG_MAX);
-
-	spin_lock_irqsave(&pd->bmp.lock, flags);
-	pd->bmp.mask |= (0x8000000000000000UL >> virq);
-	spin_unlock_irqrestore(&pd->bmp.lock, flags);
+	local_irq_save(flags);
+	asm volatile(
+		     "1:	ldarx %0,0,%3\n"
+		     "or	%0,%0,%2\n"
+		     "stdcx.	%0,0,%3\n"
+		     "bne-	1b"
+		     : "=&r" (old), "+m" (*p)
+		     : "r" (bit), "r" (p)
+		     : "cc" );
 
 	lv1_did_update_interrupt_mask(pd->node, pd->cpu);
+	local_irq_restore(flags);
 }
 
-static void chip_eoi(unsigned int virq)
+static void ps3_chip_eoi(unsigned int virq)
 {
-	lv1_end_of_interrupt(virq);
+	const struct ps3_private *pd = get_irq_chip_data(virq);
+	lv1_end_of_interrupt_ext(pd->node, pd->cpu, virq);
 }
 
 static struct irq_chip irq_chip = {
 	.typename = "ps3",
-	.mask = chip_mask,
-	.unmask = chip_unmask,
-	.eoi = chip_eoi,
+	.mask = ps3_chip_mask,
+	.unmask = ps3_chip_unmask,
+	.eoi = ps3_chip_eoi,
 };
 
-static void host_unmap(struct irq_host *h, unsigned int virq)
+static void ps3_host_unmap(struct irq_host *h, unsigned int virq)
 {
-	int result;
-
-	pr_debug("%s:%d: virq %d\n", __func__, __LINE__, virq);
-
-	lv1_disconnect_irq_plug(virq);
-
-	result = set_irq_chip_data(virq, NULL);
-	BUG_ON(result);
+	set_irq_chip_data(virq, NULL);
 }
 
-static DEFINE_PER_CPU(struct private, private);
-
-static int host_map(struct irq_host *h, unsigned int virq,
+static int ps3_host_map(struct irq_host *h, unsigned int virq,
 	irq_hw_number_t hwirq)
 {
-	int result;
-	unsigned int cpu;
-
-	pr_debug(" -> %s:%d\n", __func__, __LINE__);
-	pr_debug("%s:%d: hwirq %lu => virq %u\n", __func__, __LINE__, hwirq,
+	pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq,
 		virq);
 
-	/* bind this virq to a cpu */
-
-	preempt_disable();
-	cpu = smp_processor_id();
-	result = lv1_connect_irq_plug(virq, hwirq);
-	preempt_enable();
-
-	if (result) {
-		pr_info("%s:%d: lv1_connect_irq_plug failed:"
-			" %s\n", __func__, __LINE__, ps3_result(result));
-		return -EPERM;
-	}
-
-	result = set_irq_chip_data(virq, &per_cpu(private, cpu));
-	BUG_ON(result);
-
 	set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq);
 
-	pr_debug(" <- %s:%d\n", __func__, __LINE__);
-	return result;
+	return 0;
 }
 
-static struct irq_host_ops host_ops = {
-	.map = host_map,
-	.unmap = host_unmap,
+static struct irq_host_ops ps3_host_ops = {
+	.map = ps3_host_map,
+	.unmap = ps3_host_unmap,
 };
 
 void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq)
 {
-	struct private *pd = &per_cpu(private, cpu);
+	struct ps3_private *pd = &per_cpu(ps3_private, cpu);
 
 	pd->bmp.ipi_debug_brk_mask = 0x8000000000000000UL >> virq;
 
@@ -484,57 +558,32 @@
 		cpu, virq, pd->bmp.ipi_debug_brk_mask);
 }
 
-static int bmp_get_and_clear_status_bit(struct bmp *m)
+unsigned int ps3_get_irq(void)
 {
-	unsigned long flags;
-	unsigned int bit;
-	unsigned long x;
-
-	spin_lock_irqsave(&m->lock, flags);
+	struct ps3_private *pd = &__get_cpu_var(ps3_private);
+	u64 x = (pd->bmp.status & pd->bmp.mask);
+	unsigned int plug;
 
 	/* check for ipi break first to stop this cpu ASAP */
 
-	if (m->status & m->ipi_debug_brk_mask) {
-		m->status &= ~m->ipi_debug_brk_mask;
-		spin_unlock_irqrestore(&m->lock, flags);
-		return __ilog2(m->ipi_debug_brk_mask);
-	}
+	if (x & pd->bmp.ipi_debug_brk_mask)
+		x &= pd->bmp.ipi_debug_brk_mask;
 
-	x = (m->status & m->mask);
+	asm volatile("cntlzd %0,%1" : "=r" (plug) : "r" (x));
+	plug &= 0x3f;
 
-	for (bit = NUM_ISA_INTERRUPTS, x <<= bit; x; bit++, x <<= 1)
-		if (x & 0x8000000000000000UL) {
-			m->status &= ~(0x8000000000000000UL >> bit);
-			spin_unlock_irqrestore(&m->lock, flags);
-			return bit;
-		}
-
-	spin_unlock_irqrestore(&m->lock, flags);
-
-	pr_debug("%s:%d: not found\n", __func__, __LINE__);
-	return -1;
-}
-
-unsigned int ps3_get_irq(void)
-{
-	int plug;
-
-	struct private *pd = &__get_cpu_var(private);
-
-	plug = bmp_get_and_clear_status_bit(&pd->bmp);
-
-	if (plug < 1) {
+	if (unlikely(plug) == NO_IRQ) {
 		pr_debug("%s:%d: no plug found: cpu %u\n", __func__, __LINE__,
 			pd->cpu);
-		dump_bmp(&per_cpu(private, 0));
-		dump_bmp(&per_cpu(private, 1));
+		dump_bmp(&per_cpu(ps3_private, 0));
+		dump_bmp(&per_cpu(ps3_private, 1));
 		return NO_IRQ;
 	}
 
 #if defined(DEBUG)
-	if (plug < NUM_ISA_INTERRUPTS || plug > PS3_PLUG_MAX) {
-		dump_bmp(&per_cpu(private, 0));
-		dump_bmp(&per_cpu(private, 1));
+	if (unlikely(plug < NUM_ISA_INTERRUPTS || plug > PS3_PLUG_MAX)) {
+		dump_bmp(&per_cpu(ps3_private, 0));
+		dump_bmp(&per_cpu(ps3_private, 1));
 		BUG();
 	}
 #endif
@@ -544,26 +593,27 @@
 void __init ps3_init_IRQ(void)
 {
 	int result;
-	unsigned long node;
 	unsigned cpu;
 	struct irq_host *host;
 
-	lv1_get_logical_ppe_id(&node);
-
-	host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &host_ops,
+	host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops,
 		PS3_INVALID_OUTLET);
 	irq_set_default_host(host);
 	irq_set_virq_count(PS3_PLUG_MAX + 1);
 
 	for_each_possible_cpu(cpu) {
-		struct private *pd = &per_cpu(private, cpu);
+		struct ps3_private *pd = &per_cpu(ps3_private, cpu);
 
-		pd->node = node;
-		pd->cpu = cpu;
+		lv1_get_logical_ppe_id(&pd->node);
+		pd->cpu = get_hard_smp_processor_id(cpu);
 		spin_lock_init(&pd->bmp.lock);
 
-		result = lv1_configure_irq_state_bitmap(node, cpu,
-			ps3_mm_phys_to_lpar(__pa(&pd->bmp.status)));
+		pr_debug("%s:%d: node %lu, cpu %d, bmp %lxh\n", __func__,
+			__LINE__, pd->node, pd->cpu,
+			ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
+
+		result = lv1_configure_irq_state_bitmap(pd->node, pd->cpu,
+			ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
 
 		if (result)
 			pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:"
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c
index 49c0d01..42354de 100644
--- a/arch/powerpc/platforms/ps3/mm.c
+++ b/arch/powerpc/platforms/ps3/mm.c
@@ -25,7 +25,6 @@
 #include <asm/firmware.h>
 #include <asm/lmb.h>
 #include <asm/udbg.h>
-#include <asm/ps3.h>
 #include <asm/lv1call.h>
 
 #include "platform.h"
diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c
index 5835830..5c3da08 100644
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -22,7 +22,6 @@
 #include <linux/io.h>
 
 #include <asm/lmb.h>
-#include <asm/ps3.h>
 
 #include "platform.h"
 
@@ -59,7 +58,7 @@
 	u32 ldr_format;
 	u32 ldr_size;
 	u32 _reserved_2[6];
-} __attribute__ ((packed));
+};
 
 enum {
 	PARAM_BOOT_FLAG_GAME_OS = 0,
@@ -67,13 +66,6 @@
 };
 
 enum {
-	PARAM_AV_MULTI_OUT_NTSC = 0,
-	PARAM_AV_MULTI_OUT_PAL_RGB = 1,
-	PARAM_AV_MULTI_OUT_PAL_YCBCR = 2,
-	PARAM_AV_MULTI_OUT_SECAM = 3,
-};
-
-enum {
 	PARAM_CTRL_BUTTON_O_IS_YES = 0,
 	PARAM_CTRL_BUTTON_X_IS_YES = 1,
 };
@@ -114,7 +106,7 @@
 	u8 dns_primary[4];
 	u8 dns_secondary[4];
 	u8 _reserved_5[8];
-} __attribute__ ((packed));
+};
 
 /**
  * struct saved_params - Static working copies of data from the 'Other OS' area.
@@ -257,3 +249,13 @@
 {
 	return saved_params.rtc_diff ? saved_params.rtc_diff : 946684800UL;
 }
+
+/**
+ * ps3_os_area_get_av_multi_out - Returns the default video mode.
+ */
+
+enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void)
+{
+    return saved_params.av_multi_out;
+}
+EXPORT_SYMBOL_GPL(ps3_os_area_get_av_multi_out);
diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h
index 23b111b..ca04f03 100644
--- a/arch/powerpc/platforms/ps3/platform.h
+++ b/arch/powerpc/platforms/ps3/platform.h
@@ -22,6 +22,9 @@
 #define _PS3_PLATFORM_H
 
 #include <linux/rtc.h>
+#include <scsi/scsi.h>
+
+#include <asm/ps3.h>
 
 /* htab */
 
@@ -65,4 +68,152 @@
 static inline void ps3_spu_set_platform (void) {}
 #endif
 
+/* repository bus info */
+
+enum ps3_bus_type {
+	PS3_BUS_TYPE_SB = 4,
+	PS3_BUS_TYPE_STORAGE = 5,
+};
+
+enum ps3_dev_type {
+	PS3_DEV_TYPE_STOR_DISK = TYPE_DISK,	/* 0 */
+	PS3_DEV_TYPE_SB_GELIC = 3,
+	PS3_DEV_TYPE_SB_USB = 4,
+	PS3_DEV_TYPE_STOR_ROM = TYPE_ROM,	/* 5 */
+	PS3_DEV_TYPE_SB_GPIO = 6,
+	PS3_DEV_TYPE_STOR_FLASH = TYPE_RBC,	/* 14 */
+};
+
+int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str,
+	u64 *value);
+int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id);
+int ps3_repository_read_bus_type(unsigned int bus_index,
+	enum ps3_bus_type *bus_type);
+int ps3_repository_read_bus_num_dev(unsigned int bus_index,
+	unsigned int *num_dev);
+
+/* repository bus device info */
+
+enum ps3_interrupt_type {
+	PS3_INTERRUPT_TYPE_EVENT_PORT = 2,
+	PS3_INTERRUPT_TYPE_SB_OHCI = 3,
+	PS3_INTERRUPT_TYPE_SB_EHCI = 4,
+	PS3_INTERRUPT_TYPE_OTHER = 5,
+};
+
+enum ps3_reg_type {
+	PS3_REG_TYPE_SB_OHCI = 3,
+	PS3_REG_TYPE_SB_EHCI = 4,
+	PS3_REG_TYPE_SB_GPIO = 5,
+};
+
+int ps3_repository_read_dev_str(unsigned int bus_index,
+	unsigned int dev_index, const char *dev_str, u64 *value);
+int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index,
+	unsigned int *dev_id);
+int ps3_repository_read_dev_type(unsigned int bus_index,
+	unsigned int dev_index, enum ps3_dev_type *dev_type);
+int ps3_repository_read_dev_intr(unsigned int bus_index,
+	unsigned int dev_index, unsigned int intr_index,
+	enum ps3_interrupt_type *intr_type, unsigned int *interrupt_id);
+int ps3_repository_read_dev_reg_type(unsigned int bus_index,
+	unsigned int dev_index, unsigned int reg_index,
+	enum ps3_reg_type *reg_type);
+int ps3_repository_read_dev_reg_addr(unsigned int bus_index,
+	unsigned int dev_index, unsigned int reg_index, u64 *bus_addr,
+	u64 *len);
+int ps3_repository_read_dev_reg(unsigned int bus_index,
+	unsigned int dev_index, unsigned int reg_index,
+	enum ps3_reg_type *reg_type, u64 *bus_addr, u64 *len);
+
+/* repository bus enumerators */
+
+struct ps3_repository_device {
+	unsigned int bus_index;
+	unsigned int dev_index;
+	struct ps3_device_id did;
+};
+
+int ps3_repository_find_device(enum ps3_bus_type bus_type,
+	enum ps3_dev_type dev_type,
+	const struct ps3_repository_device *start_dev,
+	struct ps3_repository_device *dev);
+static inline int ps3_repository_find_first_device(
+	enum ps3_bus_type bus_type, enum ps3_dev_type dev_type,
+	struct ps3_repository_device *dev)
+{
+	return ps3_repository_find_device(bus_type, dev_type, NULL, dev);
+}
+int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
+	enum ps3_interrupt_type intr_type, unsigned int *interrupt_id);
+int ps3_repository_find_reg(const struct ps3_repository_device *dev,
+	enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len);
+
+/* repository block device info */
+
+int ps3_repository_read_stor_dev_port(unsigned int bus_index,
+	unsigned int dev_index, u64 *port);
+int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index,
+	unsigned int dev_index, u64 *blk_size);
+int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index,
+	unsigned int dev_index, u64 *num_blocks);
+int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index,
+	unsigned int dev_index, unsigned int *num_regions);
+int ps3_repository_read_stor_dev_region_id(unsigned int bus_index,
+	unsigned int dev_index, unsigned int region_index,
+	unsigned int *region_id);
+int ps3_repository_read_stor_dev_region_size(unsigned int bus_index,
+	unsigned int dev_index,	unsigned int region_index, u64 *region_size);
+int ps3_repository_read_stor_dev_region_start(unsigned int bus_index,
+	unsigned int dev_index, unsigned int region_index, u64 *region_start);
+int ps3_repository_read_stor_dev_info(unsigned int bus_index,
+	unsigned int dev_index, u64 *port, u64 *blk_size,
+	u64 *num_blocks, unsigned int *num_regions);
+int ps3_repository_read_stor_dev_region(unsigned int bus_index,
+	unsigned int dev_index, unsigned int region_index,
+	unsigned int *region_id, u64 *region_start, u64 *region_size);
+
+/* repository pu and memory info */
+
+int ps3_repository_read_num_pu(unsigned int *num_pu);
+int ps3_repository_read_ppe_id(unsigned int *pu_index, unsigned int *ppe_id);
+int ps3_repository_read_rm_base(unsigned int ppe_id, u64 *rm_base);
+int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size);
+int ps3_repository_read_region_total(u64 *region_total);
+int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size,
+	u64 *region_total);
+
+/* repository pme info */
+
+int ps3_repository_read_num_be(unsigned int *num_be);
+int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id);
+int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq);
+int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq);
+
+/* repository 'Other OS' area */
+
+int ps3_repository_read_boot_dat_addr(u64 *lpar_addr);
+int ps3_repository_read_boot_dat_size(unsigned int *size);
+int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size);
+
+/* repository spu info */
+
+/**
+ * enum spu_resource_type - Type of spu resource.
+ * @spu_resource_type_shared: Logical spu is shared with other partions.
+ * @spu_resource_type_exclusive: Logical spu is not shared with other partions.
+ *
+ * Returned by ps3_repository_read_spu_resource_id().
+ */
+
+enum ps3_spu_resource_type {
+	PS3_SPU_RESOURCE_TYPE_SHARED = 0,
+	PS3_SPU_RESOURCE_TYPE_EXCLUSIVE = 0x8000000000000000UL,
+};
+
+int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved);
+int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id);
+int ps3_repository_read_spu_resource_id(unsigned int res_index,
+	enum ps3_spu_resource_type* resource_type, unsigned int *resource_id);
+
 #endif
diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c
index 273a0d6..ae586a0 100644
--- a/arch/powerpc/platforms/ps3/repository.c
+++ b/arch/powerpc/platforms/ps3/repository.c
@@ -18,9 +18,10 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <asm/ps3.h>
 #include <asm/lv1call.h>
 
+#include "platform.h"
+
 enum ps3_vendor_id {
 	PS3_VENDOR_ID_NONE = 0,
 	PS3_VENDOR_ID_SONY = 0x8000000000000000UL,
@@ -257,7 +258,7 @@
 
 int ps3_repository_read_dev_intr(unsigned int bus_index,
 	unsigned int dev_index, unsigned int intr_index,
-	unsigned int *intr_type, unsigned int* interrupt_id)
+	enum ps3_interrupt_type *intr_type, unsigned int* interrupt_id)
 {
 	int result;
 	u64 v1;
@@ -275,7 +276,8 @@
 }
 
 int ps3_repository_read_dev_reg_type(unsigned int bus_index,
-	unsigned int dev_index, unsigned int reg_index, unsigned int *reg_type)
+	unsigned int dev_index, unsigned int reg_index,
+	enum ps3_reg_type *reg_type)
 {
 	int result;
 	u64 v1;
@@ -302,8 +304,8 @@
 }
 
 int ps3_repository_read_dev_reg(unsigned int bus_index,
-	unsigned int dev_index, unsigned int reg_index, unsigned int *reg_type,
-	u64 *bus_addr, u64 *len)
+	unsigned int dev_index, unsigned int reg_index,
+	enum ps3_reg_type *reg_type, u64 *bus_addr, u64 *len)
 {
 	int result = ps3_repository_read_dev_reg_type(bus_index, dev_index,
 		reg_index, reg_type);
@@ -343,7 +345,7 @@
 	}
 
 	for (res_index = 0; res_index < 10; res_index++) {
-		enum ps3_region_type reg_type;
+		enum ps3_reg_type reg_type;
 		u64 bus_addr;
 		u64 len;
 
@@ -367,7 +369,55 @@
 	return result;
 }
 
-static int dump_device_info(unsigned int bus_index, unsigned int num_dev)
+static int dump_stor_dev_info(unsigned int bus_index, unsigned int dev_index)
+{
+	int result = 0;
+	unsigned int num_regions, region_index;
+	u64 port, blk_size, num_blocks;
+
+	pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,
+		bus_index, dev_index);
+
+	result = ps3_repository_read_stor_dev_info(bus_index, dev_index, &port,
+		&blk_size, &num_blocks, &num_regions);
+	if (result) {
+		pr_debug("%s:%d ps3_repository_read_stor_dev_info"
+			" (%u:%u) failed\n", __func__, __LINE__,
+			bus_index, dev_index);
+		goto out;
+	}
+
+	pr_debug("%s:%d  (%u:%u): port %lu, blk_size %lu, num_blocks "
+		 "%lu, num_regions %u\n",
+		 __func__, __LINE__, bus_index, dev_index, port,
+		 blk_size, num_blocks, num_regions);
+
+	for (region_index = 0; region_index < num_regions; region_index++) {
+		unsigned int region_id;
+		u64 region_start, region_size;
+
+		result = ps3_repository_read_stor_dev_region(bus_index,
+			dev_index, region_index, &region_id, &region_start,
+			&region_size);
+		if (result) {
+			 pr_debug("%s:%d ps3_repository_read_stor_dev_region"
+				  " (%u:%u) failed\n", __func__, __LINE__,
+				  bus_index, dev_index);
+			break;
+		}
+
+		pr_debug("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n",
+			 __func__, __LINE__, bus_index, dev_index, region_id,
+			 region_start, region_size);
+	}
+
+out:
+	pr_debug(" <- %s:%d\n", __func__, __LINE__);
+	return result;
+}
+
+static int dump_device_info(unsigned int bus_index, enum ps3_bus_type bus_type,
+			    unsigned int num_dev)
 {
 	int result = 0;
 	unsigned int dev_index;
@@ -402,6 +452,9 @@
 			__LINE__, bus_index, dev_index, dev_type, dev_id);
 
 		ps3_repository_dump_resource_info(bus_index, dev_index);
+
+		if (bus_type == PS3_BUS_TYPE_STORAGE)
+			dump_stor_dev_info(bus_index, dev_index);
 	}
 
 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
@@ -452,7 +505,7 @@
 			__func__, __LINE__, bus_index, bus_type, bus_id,
 			num_dev);
 
-		dump_device_info(bus_index, num_dev);
+		dump_device_info(bus_index, bus_type, num_dev);
 	}
 
 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
@@ -487,7 +540,8 @@
 			break;
 	}
 
-	BUG_ON(dev_index == num_dev);
+	if (dev_index == num_dev)
+		return -1;
 
 	pr_debug("%s:%d: found dev_type %u at dev_index %u\n",
 		__func__, __LINE__, dev_type, dev_index);
@@ -521,7 +575,7 @@
 	pr_debug("%s:%d: find bus_type %u, dev_type %u\n", __func__, __LINE__,
 		bus_type, dev_type);
 
-	dev->bus_index = UINT_MAX;
+	BUG_ON(start_dev && start_dev->bus_index > 10);
 
 	for (bus_index = start_dev ? start_dev->bus_index : 0; bus_index < 10;
 		bus_index++) {
@@ -532,13 +586,15 @@
 		if (result) {
 			pr_debug("%s:%d read_bus_type failed\n",
 				__func__, __LINE__);
+			dev->bus_index = UINT_MAX;
 			return result;
 		}
 		if (x == bus_type)
 			break;
 	}
 
-	BUG_ON(bus_index == 10);
+	if (bus_index >= 10)
+		return -ENODEV;
 
 	pr_debug("%s:%d: found bus_type %u at bus_index %u\n",
 		__func__, __LINE__, bus_type, bus_index);
@@ -604,7 +660,8 @@
 		}
 	}
 
-	BUG_ON(res_index == 10);
+	if (res_index == 10)
+		return -ENODEV;
 
 	pr_debug("%s:%d: found intr_type %u at res_index %u\n",
 		__func__, __LINE__, intr_type, res_index);
@@ -612,8 +669,8 @@
 	return result;
 }
 
-int ps3_repository_find_region(const struct ps3_repository_device *dev,
-	enum ps3_region_type reg_type, u64 *bus_addr, u64 *len)
+int ps3_repository_find_reg(const struct ps3_repository_device *dev,
+	enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len)
 {
 	int result = 0;
 	unsigned int res_index;
@@ -623,7 +680,7 @@
 	*bus_addr = *len = 0;
 
 	for (res_index = 0; res_index < 10; res_index++) {
-		enum ps3_region_type t;
+		enum ps3_reg_type t;
 		u64 a;
 		u64 l;
 
@@ -643,7 +700,8 @@
 		}
 	}
 
-	BUG_ON(res_index == 10);
+	if (res_index == 10)
+		return -ENODEV;
 
 	pr_debug("%s:%d: found reg_type %u at res_index %u\n",
 		__func__, __LINE__, reg_type, res_index);
@@ -651,6 +709,136 @@
 	return result;
 }
 
+int ps3_repository_read_stor_dev_port(unsigned int bus_index,
+	unsigned int dev_index, u64 *port)
+{
+	return read_node(PS3_LPAR_ID_PME,
+		make_first_field("bus", bus_index),
+		make_field("dev", dev_index),
+		make_field("port", 0),
+		0, port, 0);
+}
+
+int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index,
+	unsigned int dev_index, u64 *blk_size)
+{
+	return read_node(PS3_LPAR_ID_PME,
+		make_first_field("bus", bus_index),
+		make_field("dev", dev_index),
+		make_field("blk_size", 0),
+		0, blk_size, 0);
+}
+
+int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index,
+	unsigned int dev_index, u64 *num_blocks)
+{
+	return read_node(PS3_LPAR_ID_PME,
+		make_first_field("bus", bus_index),
+		make_field("dev", dev_index),
+		make_field("n_blocks", 0),
+		0, num_blocks, 0);
+}
+
+int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index,
+	unsigned int dev_index, unsigned int *num_regions)
+{
+	int result;
+	u64 v1;
+
+	result = read_node(PS3_LPAR_ID_PME,
+		make_first_field("bus", bus_index),
+		make_field("dev", dev_index),
+		make_field("n_regs", 0),
+		0, &v1, 0);
+	*num_regions = v1;
+	return result;
+}
+
+int ps3_repository_read_stor_dev_region_id(unsigned int bus_index,
+	unsigned int dev_index, unsigned int region_index,
+	unsigned int *region_id)
+{
+	int result;
+	u64 v1;
+
+	result = read_node(PS3_LPAR_ID_PME,
+	    make_first_field("bus", bus_index),
+	    make_field("dev", dev_index),
+	    make_field("region", region_index),
+	    make_field("id", 0),
+	    &v1, 0);
+	*region_id = v1;
+	return result;
+}
+
+int ps3_repository_read_stor_dev_region_size(unsigned int bus_index,
+	unsigned int dev_index,	unsigned int region_index, u64 *region_size)
+{
+	return read_node(PS3_LPAR_ID_PME,
+	    make_first_field("bus", bus_index),
+	    make_field("dev", dev_index),
+	    make_field("region", region_index),
+	    make_field("size", 0),
+	    region_size, 0);
+}
+
+int ps3_repository_read_stor_dev_region_start(unsigned int bus_index,
+	unsigned int dev_index, unsigned int region_index, u64 *region_start)
+{
+	return read_node(PS3_LPAR_ID_PME,
+	    make_first_field("bus", bus_index),
+	    make_field("dev", dev_index),
+	    make_field("region", region_index),
+	    make_field("start", 0),
+	    region_start, 0);
+}
+
+int ps3_repository_read_stor_dev_info(unsigned int bus_index,
+	unsigned int dev_index, u64 *port, u64 *blk_size,
+	u64 *num_blocks, unsigned int *num_regions)
+{
+	int result;
+
+	result = ps3_repository_read_stor_dev_port(bus_index, dev_index, port);
+	if (result)
+	    return result;
+
+	result = ps3_repository_read_stor_dev_blk_size(bus_index, dev_index,
+		blk_size);
+	if (result)
+	    return result;
+
+	result = ps3_repository_read_stor_dev_num_blocks(bus_index, dev_index,
+		num_blocks);
+	if (result)
+	    return result;
+
+	result = ps3_repository_read_stor_dev_num_regions(bus_index, dev_index,
+		num_regions);
+	return result;
+}
+
+int ps3_repository_read_stor_dev_region(unsigned int bus_index,
+	unsigned int dev_index, unsigned int region_index,
+	unsigned int *region_id, u64 *region_start, u64 *region_size)
+{
+	int result;
+
+	result = ps3_repository_read_stor_dev_region_id(bus_index, dev_index,
+		region_index, region_id);
+	if (result)
+	    return result;
+
+	result = ps3_repository_read_stor_dev_region_start(bus_index, dev_index,
+		region_index, region_start);
+	if (result)
+	    return result;
+
+	result = ps3_repository_read_stor_dev_region_size(bus_index, dev_index,
+		region_index, region_size);
+	return result;
+}
+
 int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size)
 {
 	return read_node(PS3_LPAR_ID_CURRENT,
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
index d8b5cad..e62505e 100644
--- a/arch/powerpc/platforms/ps3/setup.c
+++ b/arch/powerpc/platforms/ps3/setup.c
@@ -41,10 +41,18 @@
 #define DBG(fmt...) do{if(0)printk(fmt);}while(0)
 #endif
 
-static void ps3_show_cpuinfo(struct seq_file *m)
+int ps3_get_firmware_version(union ps3_firmware_version *v)
 {
-	seq_printf(m, "machine\t\t: %s\n", ppc_md.name);
+	int result = lv1_get_version_info(&v->raw);
+
+	if (result) {
+		v->raw = 0;
+		return -1;
+	}
+
+	return result;
 }
+EXPORT_SYMBOL_GPL(ps3_get_firmware_version);
 
 static void ps3_power_save(void)
 {
@@ -74,8 +82,14 @@
 
 static void __init ps3_setup_arch(void)
 {
+	union ps3_firmware_version v;
+
 	DBG(" -> %s:%d\n", __func__, __LINE__);
 
+	ps3_get_firmware_version(&v);
+	printk(KERN_INFO "PS3 firmware version %u.%u.%u\n", v.major, v.minor,
+		v.rev);
+
 	ps3_spu_set_platform();
 	ps3_map_htab();
 
@@ -156,7 +170,6 @@
 	.name				= "PS3",
 	.probe				= ps3_probe,
 	.setup_arch			= ps3_setup_arch,
-	.show_cpuinfo			= ps3_show_cpuinfo,
 	.init_IRQ			= ps3_init_IRQ,
 	.panic				= ps3_panic,
 	.get_boot_time			= ps3_get_boot_time,
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
index 11d2080..6fb8879 100644
--- a/arch/powerpc/platforms/ps3/smp.c
+++ b/arch/powerpc/platforms/ps3/smp.c
@@ -23,7 +23,6 @@
 
 #include <asm/machdep.h>
 #include <asm/udbg.h>
-#include <asm/ps3.h>
 
 #include "platform.h"
 
@@ -111,7 +110,7 @@
 	BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3);
 
 	for (i = 0; i < MSG_COUNT; i++) {
-		result = ps3_alloc_event_irq(&virqs[i]);
+		result = ps3_alloc_event_irq(cpu, &virqs[i]);
 
 		if (result)
 			continue;
diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c
index 644532c..d192972 100644
--- a/arch/powerpc/platforms/ps3/spu.c
+++ b/arch/powerpc/platforms/ps3/spu.c
@@ -26,9 +26,10 @@
 
 #include <asm/spu.h>
 #include <asm/spu_priv1.h>
-#include <asm/ps3.h>
 #include <asm/lv1call.h>
 
+#include "platform.h"
+
 /* spu_management_ops */
 
 /**
@@ -50,7 +51,7 @@
  */
 
 struct spe_shadow {
-	u8 padding_0000[0x0140];
+	u8 padding_0140[0x0140];
 	u64 int_status_class0_RW;       /* 0x0140 */
 	u64 int_status_class1_RW;       /* 0x0148 */
 	u64 int_status_class2_RW;       /* 0x0150 */
@@ -67,8 +68,7 @@
 	u8 padding_0c08[0x0f00-0x0c08];
 	u64 spe_execution_status;       /* 0x0f00 */
 	u8 padding_0f08[0x1000-0x0f08];
-} __attribute__ ((packed));
-
+};
 
 /**
  * enum spe_ex_state - Logical spe execution state.
@@ -268,20 +268,20 @@
 {
 	int result;
 
-	result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 0,
-		&spu->irqs[0]);
+	result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
+		0, &spu->irqs[0]);
 
 	if (result)
 		goto fail_alloc_0;
 
-	result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 1,
-		&spu->irqs[1]);
+	result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
+		1, &spu->irqs[1]);
 
 	if (result)
 		goto fail_alloc_1;
 
-	result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 2,
-		&spu->irqs[2]);
+	result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
+		2, &spu->irqs[2]);
 
 	if (result)
 		goto fail_alloc_2;
diff --git a/drivers/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c
similarity index 93%
rename from drivers/ps3/system-bus.c
rename to arch/powerpc/platforms/ps3/system-bus.c
index d79f949..a9f7e4a 100644
--- a/drivers/ps3/system-bus.c
+++ b/arch/powerpc/platforms/ps3/system-bus.c
@@ -25,10 +25,11 @@
 #include <linux/err.h>
 
 #include <asm/udbg.h>
-#include <asm/ps3.h>
 #include <asm/lv1call.h>
 #include <asm/firmware.h>
 
+#include "platform.h"
+
 #define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__)
 static void _dump_mmio_region(const struct ps3_mmio_region* r,
 	const char* func, int line)
@@ -50,27 +51,29 @@
 	if (result) {
 		pr_debug("%s:%d: lv1_map_device_mmio_region failed: %s\n",
 			__func__, __LINE__, ps3_result(result));
-		r->lpar_addr = r->len = r->bus_addr = 0;
+		r->lpar_addr = 0;
 	}
 
 	dump_mmio_region(r);
 	return result;
 }
+EXPORT_SYMBOL_GPL(ps3_mmio_region_create);
 
 int ps3_free_mmio_region(struct ps3_mmio_region *r)
 {
 	int result;
 
 	result = lv1_unmap_device_mmio_region(r->did.bus_id, r->did.dev_id,
-		r->bus_addr);
+		r->lpar_addr);
 
 	if (result)
 		pr_debug("%s:%d: lv1_unmap_device_mmio_region failed: %s\n",
 			__func__, __LINE__, ps3_result(result));
 
-	r->lpar_addr = r->len = r->bus_addr = 0;
+	r->lpar_addr = 0;
 	return result;
 }
+EXPORT_SYMBOL_GPL(ps3_free_mmio_region);
 
 static int ps3_system_bus_match(struct device *_dev,
 	struct device_driver *_drv)
@@ -158,7 +161,7 @@
 }
 
 struct bus_type ps3_system_bus_type = {
-        .name = "ps3_system_bus",
+	.name = "ps3_system_bus",
 	.match = ps3_system_bus_match,
 	.probe = ps3_system_bus_probe,
 	.remove = ps3_system_bus_remove,
@@ -271,10 +274,29 @@
 static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
 	enum dma_data_direction direction)
 {
+	struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+	int i;
+
 #if defined(CONFIG_PS3_DYNAMIC_DMA)
 	BUG_ON("do");
+	return -EPERM;
+#else
+	for (i = 0; i < nents; i++, sg++) {
+		int result = ps3_dma_map(dev->d_region,
+			page_to_phys(sg->page) + sg->offset, sg->length,
+			&sg->dma_address);
+
+		if (result) {
+			pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
+				__func__, __LINE__, result);
+			return -EINVAL;
+		}
+
+		sg->dma_length = sg->length;
+	}
+
+	return nents;
 #endif
-	return 0;
 }
 
 static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg,
@@ -287,7 +309,7 @@
 
 static int ps3_dma_supported(struct device *_dev, u64 mask)
 {
-	return 1;
+	return mask >= DMA_32BIT_MASK;
 }
 
 static struct dma_mapping_ops ps3_dma_ops = {
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index da6e536..9437f48 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -747,6 +747,7 @@
 /* Enable eeh for the given device node. */
 static void *early_enable_eeh(struct device_node *dn, void *data)
 {
+	unsigned int rets[3];
 	struct eeh_early_enable_info *info = data;
 	int ret;
 	const char *status = get_property(dn, "status", NULL);
@@ -803,16 +804,14 @@
 		                regs[0], info->buid_hi, info->buid_lo,
 		                EEH_ENABLE);
 
+		enable = 0;
 		if (ret == 0) {
-			eeh_subsystem_enabled = 1;
-			pdn->eeh_mode |= EEH_MODE_SUPPORTED;
 			pdn->eeh_config_addr = regs[0];
 
 			/* If the newer, better, ibm,get-config-addr-info is supported, 
 			 * then use that instead. */
 			pdn->eeh_pe_config_addr = 0;
 			if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) {
-				unsigned int rets[2];
 				ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets, 
 					pdn->eeh_config_addr, 
 					info->buid_hi, info->buid_lo,
@@ -820,6 +819,20 @@
 				if (ret == 0)
 					pdn->eeh_pe_config_addr = rets[0];
 			}
+
+			/* Some older systems (Power4) allow the
+			 * ibm,set-eeh-option call to succeed even on nodes
+			 * where EEH is not supported. Verify support
+			 * explicitly. */
+			ret = read_slot_reset_state(pdn, rets);
+			if ((ret == 0) && (rets[1] == 1))
+				enable = 1;
+		}
+
+		if (enable) {
+			eeh_subsystem_enabled = 1;
+			pdn->eeh_mode |= EEH_MODE_SUPPORTED;
+
 #ifdef DEBUG
 			printk(KERN_DEBUG "EEH: %s: eeh enabled, config=%x pe_config=%x\n",
 			       dn->full_name, pdn->eeh_config_addr, pdn->eeh_pe_config_addr);
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index cbd6b07..a4c0bf8 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -446,7 +446,8 @@
 	 */
 	printk(KERN_ERR
 	   "EEH: PCI device at location=%s driver=%s pci addr=%s \n"
-		"has failed %d times and has been permanently disabled. \n"
+		"has failed %d times in the last hour "
+		"and has been permanently disabled. \n"
 		"Please try reseating this device or replacing it.\n",
 		location, drv_str, pci_str, frozen_pdn->eeh_freeze_count);
 	goto perm_error;
diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c
index 1c7b2ba..90522e3 100644
--- a/arch/powerpc/platforms/pseries/firmware.c
+++ b/arch/powerpc/platforms/pseries/firmware.c
@@ -59,6 +59,7 @@
 	{FW_FEATURE_XDABR,		"hcall-xdabr"},
 	{FW_FEATURE_MULTITCE,		"hcall-multi-tce"},
 	{FW_FEATURE_SPLPAR,		"hcall-splpar"},
+	{FW_FEATURE_BULK_REMOVE,	"hcall-bulk"},
 };
 
 /* Build up the firmware features bitmask using the contents of
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 721436d..7496005 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -502,23 +502,70 @@
 	BUG_ON(lpar_rc != H_SUCCESS);
 }
 
+/* Flag bits for H_BULK_REMOVE */
+#define HBR_REQUEST	0x4000000000000000UL
+#define HBR_RESPONSE	0x8000000000000000UL
+#define HBR_END		0xc000000000000000UL
+#define HBR_AVPN	0x0200000000000000UL
+#define HBR_ANDCOND	0x0100000000000000UL
+
 /*
  * Take a spinlock around flushes to avoid bouncing the hypervisor tlbie
  * lock.
  */
 static void pSeries_lpar_flush_hash_range(unsigned long number, int local)
 {
-	int i;
+	unsigned long i, pix, rc;
 	unsigned long flags = 0;
 	struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
 	int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE);
+	unsigned long param[9];
+	unsigned long va;
+	unsigned long hash, index, shift, hidx, slot;
+	real_pte_t pte;
+	int psize;
 
 	if (lock_tlbie)
 		spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags);
 
-	for (i = 0; i < number; i++)
-		flush_hash_page(batch->vaddr[i], batch->pte[i],
-				batch->psize, local);
+	psize = batch->psize;
+	pix = 0;
+	for (i = 0; i < number; i++) {
+		va = batch->vaddr[i];
+		pte = batch->pte[i];
+		pte_iterate_hashed_subpages(pte, psize, va, index, shift) {
+			hash = hpt_hash(va, shift);
+			hidx = __rpte_to_hidx(pte, index);
+			if (hidx & _PTEIDX_SECONDARY)
+				hash = ~hash;
+			slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+			slot += hidx & _PTEIDX_GROUP_IX;
+			if (!firmware_has_feature(FW_FEATURE_BULK_REMOVE)) {
+				pSeries_lpar_hpte_invalidate(slot, va, psize,
+							     local);
+			} else {
+				param[pix] = HBR_REQUEST | HBR_AVPN | slot;
+				param[pix+1] = hpte_encode_v(va, psize) &
+					HPTE_V_AVPN;
+				pix += 2;
+				if (pix == 8) {
+					rc = plpar_hcall9(H_BULK_REMOVE, param,
+						param[0], param[1], param[2],
+						param[3], param[4], param[5],
+						param[6], param[7]);
+					BUG_ON(rc != H_SUCCESS);
+					pix = 0;
+				}
+			}
+		} pte_iterate_hashed_end();
+	}
+	if (pix) {
+		param[pix] = HBR_END;
+		rc = plpar_hcall9(H_BULK_REMOVE, param, param[0], param[1],
+				  param[2], param[3], param[4], param[5],
+				  param[6], param[7]);
+		BUG_ON(rc != H_SUCCESS);
+	}
 
 	if (lock_tlbie)
 		spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags);
diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c
index 715db5c..c69bd15 100644
--- a/arch/powerpc/platforms/pseries/pci.c
+++ b/arch/powerpc/platforms/pseries/pci.c
@@ -77,7 +77,7 @@
 
 /*
  * Assume the winbond 82c105 is the IDE controller on a
- * p610.  We should probably be more careful in case
+ * p610/p615/p630. We should probably be more careful in case
  * someone tries to plug in a similar adapter.
  */
 static void fixup_winbond_82c105(struct pci_dev* dev)
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 2621a7e..85dcdf1 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -22,4 +22,6 @@
 ifeq ($(ARCH),powerpc)
 obj-$(CONFIG_MTD)		+= rom.o
 obj-$(CONFIG_CPM2)		+= cpm2_common.o cpm2_pic.o
+obj-$(CONFIG_8xx)		+= mpc8xx_pic.o commproc.o
+obj-$(CONFIG_UCODE_PATCH)	+= micropatch.o
 endif
diff --git a/arch/powerpc/sysdev/commproc.c b/arch/powerpc/sysdev/commproc.c
new file mode 100644
index 0000000..9b4fafd
--- /dev/null
+++ b/arch/powerpc/sysdev/commproc.c
@@ -0,0 +1,398 @@
+/*
+ * General Purpose functions for the global management of the
+ * Communication Processor Module.
+ * Copyright (c) 1997 Dan error_act (dmalek@jlc.net)
+ *
+ * In addition to the individual control of the communication
+ * channels, there are a few functions that globally affect the
+ * communication processor.
+ *
+ * Buffer descriptors must be allocated from the dual ported memory
+ * space.  The allocator for that is here.  When the communication
+ * process is reset, we reclaim the memory available.  There is
+ * currently no deallocator for this memory.
+ * The amount of space available is platform dependent.  On the
+ * MBX, the EPPC software loads additional microcode into the
+ * communication processor, and uses some of the DP ram for this
+ * purpose.  Current, the first 512 bytes and the last 256 bytes of
+ * memory are used.  Right now I am conservative and only use the
+ * memory that can never be used for microcode.  If there are
+ * applications that require more DP ram, we can expand the boundaries
+ * but then we have to be careful of any downloaded microcode.
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <asm/mpc8xx.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+#include <asm/io.h>
+#include <asm/tlbflush.h>
+#include <asm/rheap.h>
+#include <asm/prom.h>
+
+#include <asm/fs_pd.h>
+
+#define CPM_MAP_SIZE    (0x4000)
+
+static void m8xx_cpm_dpinit(void);
+static	uint	host_buffer;	/* One page of host buffer */
+static	uint	host_end;	/* end + 1 */
+cpm8xx_t	*cpmp;		/* Pointer to comm processor space */
+cpic8xx_t	*cpic_reg;
+
+static struct device_node *cpm_pic_node;
+static struct irq_host *cpm_pic_host;
+
+static void cpm_mask_irq(unsigned int irq)
+{
+	unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq;
+
+	clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec));
+}
+
+static void cpm_unmask_irq(unsigned int irq)
+{
+	unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq;
+
+	setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec));
+}
+
+static void cpm_end_irq(unsigned int irq)
+{
+	unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq;
+
+	out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec));
+}
+
+static struct irq_chip cpm_pic = {
+	.typename = " CPM PIC ",
+	.mask = cpm_mask_irq,
+	.unmask = cpm_unmask_irq,
+	.eoi = cpm_end_irq,
+};
+
+int cpm_get_irq(void)
+{
+	int cpm_vec;
+
+	/* Get the vector by setting the ACK bit and then reading
+	 * the register.
+	 */
+	out_be16(&cpic_reg->cpic_civr, 1);
+	cpm_vec = in_be16(&cpic_reg->cpic_civr);
+	cpm_vec >>= 11;
+
+	return irq_linear_revmap(cpm_pic_host, cpm_vec);
+}
+
+static int cpm_pic_host_match(struct irq_host *h, struct device_node *node)
+{
+	return cpm_pic_node == node;
+}
+
+static int cpm_pic_host_map(struct irq_host *h, unsigned int virq,
+			  irq_hw_number_t hw)
+{
+	pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw);
+
+	get_irq_desc(virq)->status |= IRQ_LEVEL;
+	set_irq_chip_and_handler(virq, &cpm_pic, handle_fasteoi_irq);
+	return 0;
+}
+
+/* The CPM can generate the error interrupt when there is a race condition
+ * between generating and masking interrupts.  All we have to do is ACK it
+ * and return.  This is a no-op function so we don't need any special
+ * tests in the interrupt handler.
+ */
+static	irqreturn_t cpm_error_interrupt(int irq, void *dev)
+{
+	return IRQ_HANDLED;
+}
+
+static struct irqaction cpm_error_irqaction = {
+	.handler = cpm_error_interrupt,
+	.mask = CPU_MASK_NONE,
+	.name = "error",
+};
+
+static struct irq_host_ops cpm_pic_host_ops = {
+	.match = cpm_pic_host_match,
+	.map = cpm_pic_host_map,
+};
+
+unsigned int cpm_pic_init(void)
+{
+	struct device_node *np = NULL;
+	struct resource res;
+	unsigned int sirq = NO_IRQ, hwirq, eirq;
+	int ret;
+
+	pr_debug("cpm_pic_init\n");
+
+	np = of_find_compatible_node(NULL, "cpm-pic", "CPM");
+	if (np == NULL) {
+		printk(KERN_ERR "CPM PIC init: can not find cpm-pic node\n");
+		return sirq;
+	}
+	ret = of_address_to_resource(np, 0, &res);
+	if (ret)
+		goto end;
+
+	cpic_reg = (void *)ioremap(res.start, res.end - res.start + 1);
+	if (cpic_reg == NULL)
+		goto end;
+
+	sirq = irq_of_parse_and_map(np, 0);
+	if (sirq == NO_IRQ)
+		goto end;
+
+	/* Initialize the CPM interrupt controller. */
+	hwirq = (unsigned int)irq_map[sirq].hwirq;
+	out_be32(&cpic_reg->cpic_cicr,
+	    (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
+		((hwirq/2) << 13) | CICR_HP_MASK);
+
+	out_be32(&cpic_reg->cpic_cimr, 0);
+
+	cpm_pic_node = of_node_get(np);
+
+	cpm_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 64, &cpm_pic_host_ops, 64);
+	if (cpm_pic_host == NULL) {
+		printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
+		sirq = NO_IRQ;
+		goto end;
+	}
+	of_node_put(np);
+
+	/* Install our own error handler. */
+	np = of_find_node_by_type(NULL, "cpm");
+	if (np == NULL) {
+		printk(KERN_ERR "CPM PIC init: can not find cpm node\n");
+		goto end;
+	}
+	eirq= irq_of_parse_and_map(np, 0);
+	if (eirq == NO_IRQ)
+		goto end;
+
+	if (setup_irq(eirq, &cpm_error_irqaction))
+		printk(KERN_ERR "Could not allocate CPM error IRQ!");
+
+	setbits32(&cpic_reg->cpic_cicr, CICR_IEN);
+
+end:
+	of_node_put(np);
+	return sirq;
+}
+
+void cpm_reset(void)
+{
+	cpm8xx_t	*commproc;
+	sysconf8xx_t    *siu_conf;
+
+	commproc = (cpm8xx_t *)ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE);
+
+#ifdef CONFIG_UCODE_PATCH
+	/* Perform a reset.
+	*/
+	out_be16(&commproc->cp_cpcr,  CPM_CR_RST | CPM_CR_FLG);
+
+	/* Wait for it.
+	*/
+	while (in_be16(&commproc->cp_cpcr) & CPM_CR_FLG);
+
+	cpm_load_patch(commproc);
+#endif
+
+	/* Set SDMA Bus Request priority 5.
+	 * On 860T, this also enables FEC priority 6.  I am not sure
+	 * this is what we realy want for some applications, but the
+	 * manual recommends it.
+	 * Bit 25, FAM can also be set to use FEC aggressive mode (860T).
+	 */
+	siu_conf = (sysconf8xx_t*)immr_map(im_siu_conf);
+	out_be32(&siu_conf->sc_sdcr, 1);
+	immr_unmap(siu_conf);
+
+	/* Reclaim the DP memory for our use. */
+	m8xx_cpm_dpinit();
+
+	/* Tell everyone where the comm processor resides.
+	*/
+	cpmp = commproc;
+}
+
+/* We used to do this earlier, but have to postpone as long as possible
+ * to ensure the kernel VM is now running.
+ */
+static void
+alloc_host_memory(void)
+{
+	dma_addr_t	physaddr;
+
+	/* Set the host page for allocation.
+	*/
+	host_buffer = (uint)dma_alloc_coherent(NULL, PAGE_SIZE, &physaddr,
+			GFP_KERNEL);
+	host_end = host_buffer + PAGE_SIZE;
+}
+
+/* We also own one page of host buffer space for the allocation of
+ * UART "fifos" and the like.
+ */
+uint
+m8xx_cpm_hostalloc(uint size)
+{
+	uint	retloc;
+
+	if (host_buffer == 0)
+		alloc_host_memory();
+
+	if ((host_buffer + size) >= host_end)
+		return(0);
+
+	retloc = host_buffer;
+	host_buffer += size;
+
+	return(retloc);
+}
+
+/* Set a baud rate generator.  This needs lots of work.  There are
+ * four BRGs, any of which can be wired to any channel.
+ * The internal baud rate clock is the system clock divided by 16.
+ * This assumes the baudrate is 16x oversampled by the uart.
+ */
+#define BRG_INT_CLK		(get_brgfreq())
+#define BRG_UART_CLK		(BRG_INT_CLK/16)
+#define BRG_UART_CLK_DIV16	(BRG_UART_CLK/16)
+
+void
+cpm_setbrg(uint brg, uint rate)
+{
+	volatile uint	*bp;
+
+	/* This is good enough to get SMCs running.....
+	*/
+	bp = (uint *)&cpmp->cp_brgc1;
+	bp += brg;
+	/* The BRG has a 12-bit counter.  For really slow baud rates (or
+	 * really fast processors), we may have to further divide by 16.
+	 */
+	if (((BRG_UART_CLK / rate) - 1) < 4096)
+		*bp = (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN;
+	else
+		*bp = (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) |
+						CPM_BRG_EN | CPM_BRG_DIV16;
+}
+
+/*
+ * dpalloc / dpfree bits.
+ */
+static spinlock_t cpm_dpmem_lock;
+/*
+ * 16 blocks should be enough to satisfy all requests
+ * until the memory subsystem goes up...
+ */
+static rh_block_t cpm_boot_dpmem_rh_block[16];
+static rh_info_t cpm_dpmem_info;
+
+#define CPM_DPMEM_ALIGNMENT	8
+static u8* dpram_vbase;
+static uint dpram_pbase;
+
+void m8xx_cpm_dpinit(void)
+{
+	spin_lock_init(&cpm_dpmem_lock);
+
+	dpram_vbase = immr_map_size(im_cpm.cp_dpmem, CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE);
+	dpram_pbase = (uint)&((immap_t *)IMAP_ADDR)->im_cpm.cp_dpmem;
+
+	/* Initialize the info header */
+	rh_init(&cpm_dpmem_info, CPM_DPMEM_ALIGNMENT,
+			sizeof(cpm_boot_dpmem_rh_block) /
+			sizeof(cpm_boot_dpmem_rh_block[0]),
+			cpm_boot_dpmem_rh_block);
+
+	/*
+	 * Attach the usable dpmem area.
+	 * XXX: This is actually crap.  CPM_DATAONLY_BASE and
+	 * CPM_DATAONLY_SIZE are a subset of the available dparm.  It varies
+	 * with the processor and the microcode patches applied / activated.
+	 * But the following should be at least safe.
+	 */
+	rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
+}
+
+/*
+ * Allocate the requested size worth of DP memory.
+ * This function returns an offset into the DPRAM area.
+ * Use cpm_dpram_addr() to get the virtual address of the area.
+ */
+uint cpm_dpalloc(uint size, uint align)
+{
+	void *start;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cpm_dpmem_lock, flags);
+	cpm_dpmem_info.alignment = align;
+	start = rh_alloc(&cpm_dpmem_info, size, "commproc");
+	spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
+
+	return (uint)start;
+}
+EXPORT_SYMBOL(cpm_dpalloc);
+
+int cpm_dpfree(uint offset)
+{
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cpm_dpmem_lock, flags);
+	ret = rh_free(&cpm_dpmem_info, (void *)offset);
+	spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(cpm_dpfree);
+
+uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
+{
+	void *start;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cpm_dpmem_lock, flags);
+	cpm_dpmem_info.alignment = align;
+	start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc");
+	spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
+
+	return (uint)start;
+}
+EXPORT_SYMBOL(cpm_dpalloc_fixed);
+
+void cpm_dpdump(void)
+{
+	rh_dump(&cpm_dpmem_info);
+}
+EXPORT_SYMBOL(cpm_dpdump);
+
+void *cpm_dpram_addr(uint offset)
+{
+	return (void *)(dpram_vbase + offset);
+}
+EXPORT_SYMBOL(cpm_dpram_addr);
+
+uint cpm_dpram_phys(u8* addr)
+{
+	return (dpram_pbase + (uint)(addr - dpram_vbase));
+}
+EXPORT_SYMBOL(cpm_dpram_addr);
diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c
index 767ee66..eabfe06 100644
--- a/arch/powerpc/sysdev/cpm2_pic.c
+++ b/arch/powerpc/sysdev/cpm2_pic.c
@@ -36,9 +36,20 @@
 #include <asm/mpc8260.h>
 #include <asm/io.h>
 #include <asm/prom.h>
+#include <asm/fs_pd.h>
 
 #include "cpm2_pic.h"
 
+/* External IRQS */
+#define CPM2_IRQ_EXT1		19
+#define CPM2_IRQ_EXT7		25
+
+/* Port C IRQS */
+#define CPM2_IRQ_PORTC15	48
+#define CPM2_IRQ_PORTC0		63
+
+static intctl_cpm2_t *cpm2_intctl;
+
 static struct device_node *cpm2_pic_node;
 static struct irq_host *cpm2_pic_host;
 #define NR_MASK_WORDS   ((NR_IRQS + 31) / 32)
@@ -68,68 +79,55 @@
 	24, 25, 26, 27, 28, 29, 30, 31,
 };
 
-static void cpm2_mask_irq(unsigned int irq_nr)
+static void cpm2_mask_irq(unsigned int virq)
 {
 	int	bit, word;
-	volatile uint	*simr;
-
-	irq_nr -= CPM_IRQ_OFFSET;
+	unsigned int irq_nr = virq_to_hw(virq);
 
 	bit = irq_to_siubit[irq_nr];
 	word = irq_to_siureg[irq_nr];
 
-	simr = &(cpm2_intctl->ic_simrh);
 	ppc_cached_irq_mask[word] &= ~(1 << bit);
-	simr[word] = ppc_cached_irq_mask[word];
+	out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
 }
 
-static void cpm2_unmask_irq(unsigned int irq_nr)
+static void cpm2_unmask_irq(unsigned int virq)
 {
 	int	bit, word;
-	volatile uint	*simr;
-
-	irq_nr -= CPM_IRQ_OFFSET;
+	unsigned int irq_nr = virq_to_hw(virq);
 
 	bit = irq_to_siubit[irq_nr];
 	word = irq_to_siureg[irq_nr];
 
-	simr = &(cpm2_intctl->ic_simrh);
 	ppc_cached_irq_mask[word] |= 1 << bit;
-	simr[word] = ppc_cached_irq_mask[word];
+	out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
 }
 
-static void cpm2_mask_and_ack(unsigned int irq_nr)
+static void cpm2_ack(unsigned int virq)
 {
 	int	bit, word;
-	volatile uint	*simr, *sipnr;
-
-	irq_nr -= CPM_IRQ_OFFSET;
+	unsigned int irq_nr = virq_to_hw(virq);
 
 	bit = irq_to_siubit[irq_nr];
 	word = irq_to_siureg[irq_nr];
 
-	simr = &(cpm2_intctl->ic_simrh);
-	sipnr = &(cpm2_intctl->ic_sipnrh);
-	ppc_cached_irq_mask[word] &= ~(1 << bit);
-	simr[word] = ppc_cached_irq_mask[word];
-	sipnr[word] = 1 << bit;
+	out_be32(&cpm2_intctl->ic_sipnrh + word, 1 << bit);
 }
 
-static void cpm2_end_irq(unsigned int irq_nr)
+static void cpm2_end_irq(unsigned int virq)
 {
 	int	bit, word;
-	volatile uint	*simr;
+	unsigned int irq_nr = virq_to_hw(virq);
 
 	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
 			&& irq_desc[irq_nr].action) {
 
-		irq_nr -= CPM_IRQ_OFFSET;
 		bit = irq_to_siubit[irq_nr];
 		word = irq_to_siureg[irq_nr];
 
-		simr = &(cpm2_intctl->ic_simrh);
 		ppc_cached_irq_mask[word] |= 1 << bit;
-		simr[word] = ppc_cached_irq_mask[word];
+		out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
+
 		/*
 		 * Work around large numbers of spurious IRQs on PowerPC 82xx
 		 * systems.
@@ -138,13 +136,59 @@
 	}
 }
 
+static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type)
+{
+	unsigned int src = virq_to_hw(virq);
+	struct irq_desc *desc = get_irq_desc(virq);
+	unsigned int vold, vnew, edibit;
+
+	if (flow_type == IRQ_TYPE_NONE)
+		flow_type = IRQ_TYPE_LEVEL_LOW;
+
+	if (flow_type & IRQ_TYPE_EDGE_RISING) {
+		printk(KERN_ERR "CPM2 PIC: sense type 0x%x not supported\n",
+			flow_type);
+		return -EINVAL;
+	}
+
+	desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
+	desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
+	if (flow_type & IRQ_TYPE_LEVEL_LOW)  {
+		desc->status |= IRQ_LEVEL;
+		desc->handle_irq = handle_level_irq;
+	} else
+		desc->handle_irq = handle_edge_irq;
+
+	/* internal IRQ senses are LEVEL_LOW
+	 * EXT IRQ and Port C IRQ senses are programmable
+	 */
+	if (src >= CPM2_IRQ_EXT1 && src <= CPM2_IRQ_EXT7)
+			edibit = (14 - (src - CPM2_IRQ_EXT1));
+	else
+		if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0)
+			edibit = (31 - (src - CPM2_IRQ_PORTC15));
+		else
+			return (flow_type & IRQ_TYPE_LEVEL_LOW) ? 0 : -EINVAL;
+
+	vold = in_be32(&cpm2_intctl->ic_siexr);
+
+	if ((flow_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_FALLING)
+		vnew = vold | (1 << edibit);
+	else
+		vnew = vold & ~(1 << edibit);
+
+	if (vold != vnew)
+		out_be32(&cpm2_intctl->ic_siexr, vnew);
+	return 0;
+}
+
 static struct irq_chip cpm2_pic = {
 	.typename = " CPM2 SIU ",
-	.enable = cpm2_unmask_irq,
-	.disable = cpm2_mask_irq,
+	.mask = cpm2_mask_irq,
 	.unmask = cpm2_unmask_irq,
-	.mask_ack = cpm2_mask_and_ack,
-	.end = cpm2_end_irq,
+	.ack = cpm2_ack,
+	.eoi = cpm2_end_irq,
+	.set_type = cpm2_set_irq_type,
 };
 
 unsigned int cpm2_get_irq(void)
@@ -154,17 +198,17 @@
 
        /* For CPM2, read the SIVEC register and shift the bits down
          * to get the irq number.         */
-        bits = cpm2_intctl->ic_sivec;
+        bits = in_be32(&cpm2_intctl->ic_sivec);
         irq = bits >> 26;
 
 	if (irq == 0)
 		return(-1);
-	return irq+CPM_IRQ_OFFSET;
+	return irq_linear_revmap(cpm2_pic_host, irq);
 }
 
 static int cpm2_pic_host_match(struct irq_host *h, struct device_node *node)
 {
-	return cpm2_pic_node == NULL || cpm2_pic_node == node;
+	return cpm2_pic_node == node;
 }
 
 static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq,
@@ -177,39 +221,21 @@
 	return 0;
 }
 
-static void cpm2_host_unmap(struct irq_host *h, unsigned int virq)
-{
-	/* Make sure irq is masked in hardware */
-	cpm2_mask_irq(virq);
-
-	/* remove chip and handler */
-	set_irq_chip_and_handler(virq, NULL, NULL);
-}
-
 static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct,
 			    u32 *intspec, unsigned int intsize,
 			    irq_hw_number_t *out_hwirq, unsigned int *out_flags)
 {
-	static const unsigned char map_cpm2_senses[4] = {
-		IRQ_TYPE_LEVEL_LOW,
-		IRQ_TYPE_LEVEL_HIGH,
-		IRQ_TYPE_EDGE_FALLING,
-		IRQ_TYPE_EDGE_RISING,
-	};
-
 	*out_hwirq = intspec[0];
-	if (intsize > 1 && intspec[1] < 4)
-		*out_flags = map_cpm2_senses[intspec[1]];
+	if (intsize > 1)
+		*out_flags = intspec[1];
 	else
 		*out_flags = IRQ_TYPE_NONE;
-
 	return 0;
 }
 
 static struct irq_host_ops cpm2_pic_host_ops = {
 	.match = cpm2_pic_host_match,
 	.map = cpm2_pic_host_map,
-	.unmap = cpm2_host_unmap,
 	.xlate = cpm2_pic_host_xlate,
 };
 
@@ -217,37 +243,37 @@
 {
 	int i;
 
+	cpm2_intctl = cpm2_map(im_intctl);
+
 	/* Clear the CPM IRQ controller, in case it has any bits set
 	 * from the bootloader
 	 */
 
 	/* Mask out everything */
 
-	cpm2_intctl->ic_simrh = 0x00000000;
-	cpm2_intctl->ic_simrl = 0x00000000;
+	out_be32(&cpm2_intctl->ic_simrh, 0x00000000);
+	out_be32(&cpm2_intctl->ic_simrl, 0x00000000);
 
 	wmb();
 
 	/* Ack everything */
-	cpm2_intctl->ic_sipnrh = 0xffffffff;
-	cpm2_intctl->ic_sipnrl = 0xffffffff;
+	out_be32(&cpm2_intctl->ic_sipnrh, 0xffffffff);
+	out_be32(&cpm2_intctl->ic_sipnrl, 0xffffffff);
 	wmb();
 
 	/* Dummy read of the vector */
-	i = cpm2_intctl->ic_sivec;
+	i = in_be32(&cpm2_intctl->ic_sivec);
 	rmb();
 
 	/* Initialize the default interrupt mapping priorities,
 	 * in case the boot rom changed something on us.
 	 */
-	cpm2_intctl->ic_sicr = 0;
-	cpm2_intctl->ic_scprrh = 0x05309770;
-	cpm2_intctl->ic_scprrl = 0x05309770;
+	out_be16(&cpm2_intctl->ic_sicr, 0);
+	out_be32(&cpm2_intctl->ic_scprrh, 0x05309770);
+	out_be32(&cpm2_intctl->ic_scprrl, 0x05309770);
 
 	/* create a legacy host */
-	if (node)
-		cpm2_pic_node = of_node_get(node);
-
+	cpm2_pic_node = of_node_get(node);
 	cpm2_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 64, &cpm2_pic_host_ops, 64);
 	if (cpm2_pic_host == NULL) {
 		printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
diff --git a/arch/powerpc/sysdev/cpm2_pic.h b/arch/powerpc/sysdev/cpm2_pic.h
index 2840616..30e5828 100644
--- a/arch/powerpc/sysdev/cpm2_pic.h
+++ b/arch/powerpc/sysdev/cpm2_pic.h
@@ -1,8 +1,6 @@
 #ifndef _PPC_KERNEL_CPM2_H
 #define _PPC_KERNEL_CPM2_H
 
-extern intctl_cpm2_t *cpm2_intctl;
-
 extern unsigned int cpm2_get_irq(void);
 
 extern void cpm2_pic_init(struct device_node*);
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index ad31e56..9f2a9a4 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -38,7 +38,8 @@
 #include <asm/cpm2.h>
 
 extern void init_fcc_ioports(struct fs_platform_info*);
-extern void init_scc_ioports(struct fs_uart_platform_info*);
+extern void init_fec_ioports(struct fs_platform_info*);
+extern void init_smc_ioports(struct fs_uart_platform_info*);
 static phys_addr_t immrbase = -1;
 
 phys_addr_t get_immrbase(void)
@@ -63,7 +64,7 @@
 
 EXPORT_SYMBOL(get_immrbase);
 
-#ifdef CONFIG_CPM2
+#if defined(CONFIG_CPM2) || defined(CONFIG_8xx)
 
 static u32 brgfreq = -1;
 
@@ -544,6 +545,8 @@
 
 #ifdef CONFIG_CPM2
 
+extern void init_scc_ioports(struct fs_uart_platform_info*);
+
 static const char fcc_regs[] = "fcc_regs";
 static const char fcc_regs_c[] = "fcc_regs_c";
 static const char fcc_pram[] = "fcc_pram";
@@ -792,3 +795,270 @@
 
 arch_initcall(cpm_uart_of_init);
 #endif /* CONFIG_CPM2 */
+
+#ifdef CONFIG_8xx
+
+extern void init_scc_ioports(struct fs_platform_info*);
+extern int platform_device_skip(char *model, int id);
+
+static int __init fs_enet_mdio_of_init(void)
+{
+	struct device_node *np;
+	unsigned int i;
+	struct platform_device *mdio_dev;
+	struct resource res;
+	int ret;
+
+	for (np = NULL, i = 0;
+	     (np = of_find_compatible_node(np, "mdio", "fs_enet")) != NULL;
+	     i++) {
+		struct fs_mii_fec_platform_info mdio_data;
+
+		memset(&res, 0, sizeof(res));
+		memset(&mdio_data, 0, sizeof(mdio_data));
+
+		ret = of_address_to_resource(np, 0, &res);
+		if (ret)
+			goto err;
+
+		mdio_dev =
+		    platform_device_register_simple("fsl-cpm-fec-mdio",
+						    res.start, &res, 1);
+		if (IS_ERR(mdio_dev)) {
+			ret = PTR_ERR(mdio_dev);
+			goto err;
+		}
+
+		mdio_data.mii_speed = ((((ppc_proc_freq + 4999999) / 2500000) / 2) & 0x3F) << 1;
+
+		ret =
+		    platform_device_add_data(mdio_dev, &mdio_data,
+					     sizeof(struct fs_mii_fec_platform_info));
+		if (ret)
+			goto unreg;
+	}
+	return 0;
+
+unreg:
+	platform_device_unregister(mdio_dev);
+err:
+	return ret;
+}
+
+arch_initcall(fs_enet_mdio_of_init);
+
+static const char *enet_regs = "regs";
+static const char *enet_pram = "pram";
+static const char *enet_irq = "interrupt";
+static char bus_id[9][BUS_ID_SIZE];
+
+static int __init fs_enet_of_init(void)
+{
+	struct device_node *np;
+	unsigned int i;
+	struct platform_device *fs_enet_dev = NULL;
+	struct resource res;
+	int ret;
+
+	for (np = NULL, i = 0;
+	     (np = of_find_compatible_node(np, "network", "fs_enet")) != NULL;
+	     i++) {
+		struct resource r[4];
+		struct device_node *phy = NULL, *mdio = NULL;
+		struct fs_platform_info fs_enet_data;
+		unsigned int *id, *phy_addr;
+		void *mac_addr;
+		phandle *ph;
+		char *model;
+
+		memset(r, 0, sizeof(r));
+		memset(&fs_enet_data, 0, sizeof(fs_enet_data));
+
+		model = (char *)get_property(np, "model", NULL);
+		if (model == NULL) {
+			ret = -ENODEV;
+			goto unreg;
+		}
+
+		id = (u32 *) get_property(np, "device-id", NULL);
+		fs_enet_data.fs_no = *id;
+
+		if (platform_device_skip(model, *id))
+			continue;
+
+		ret = of_address_to_resource(np, 0, &r[0]);
+		if (ret)
+			goto err;
+		r[0].name = enet_regs;
+
+		mac_addr = (void *)get_property(np, "mac-address", NULL);
+		memcpy(fs_enet_data.macaddr, mac_addr, 6);
+
+		ph = (phandle *) get_property(np, "phy-handle", NULL);
+		if (ph != NULL)
+			phy = of_find_node_by_phandle(*ph);
+
+		if (phy != NULL) {
+			phy_addr = (u32 *) get_property(phy, "reg", NULL);
+			fs_enet_data.phy_addr = *phy_addr;
+			fs_enet_data.has_phy = 1;
+
+			mdio = of_get_parent(phy);
+			ret = of_address_to_resource(mdio, 0, &res);
+			if (ret) {
+				of_node_put(phy);
+				of_node_put(mdio);
+                                goto unreg;
+			}
+		}
+
+		model = (char*)get_property(np, "model", NULL);
+		strcpy(fs_enet_data.fs_type, model);
+
+		if (strstr(model, "FEC")) {
+			r[1].start = r[1].end = irq_of_parse_and_map(np, 0);
+			r[1].flags = IORESOURCE_IRQ;
+			r[1].name = enet_irq;
+
+			fs_enet_dev =
+				    platform_device_register_simple("fsl-cpm-fec", i, &r[0], 2);
+
+			if (IS_ERR(fs_enet_dev)) {
+				ret = PTR_ERR(fs_enet_dev);
+				goto err;
+			}
+
+			fs_enet_data.rx_ring = 128;
+			fs_enet_data.tx_ring = 16;
+			fs_enet_data.rx_copybreak = 240;
+			fs_enet_data.use_napi = 1;
+			fs_enet_data.napi_weight = 17;
+
+			snprintf((char*)&bus_id[i], BUS_ID_SIZE, "%x:%02x",
+							(u32)res.start, fs_enet_data.phy_addr);
+			fs_enet_data.bus_id = (char*)&bus_id[i];
+			fs_enet_data.init_ioports = init_fec_ioports;
+		}
+		if (strstr(model, "SCC")) {
+			ret = of_address_to_resource(np, 1, &r[1]);
+			if (ret)
+				goto err;
+			r[1].name = enet_pram;
+
+			r[2].start = r[2].end = irq_of_parse_and_map(np, 0);
+			r[2].flags = IORESOURCE_IRQ;
+			r[2].name = enet_irq;
+
+			fs_enet_dev =
+				    platform_device_register_simple("fsl-cpm-scc", i, &r[0], 3);
+
+			if (IS_ERR(fs_enet_dev)) {
+				ret = PTR_ERR(fs_enet_dev);
+				goto err;
+			}
+
+			fs_enet_data.rx_ring = 64;
+			fs_enet_data.tx_ring = 8;
+			fs_enet_data.rx_copybreak = 240;
+			fs_enet_data.use_napi = 1;
+			fs_enet_data.napi_weight = 17;
+
+			snprintf((char*)&bus_id[i], BUS_ID_SIZE, "%s", "fixed@10:1");
+                        fs_enet_data.bus_id = (char*)&bus_id[i];
+			fs_enet_data.init_ioports = init_scc_ioports;
+		}
+
+		of_node_put(phy);
+		of_node_put(mdio);
+
+		ret = platform_device_add_data(fs_enet_dev, &fs_enet_data,
+					     sizeof(struct
+						    fs_platform_info));
+		if (ret)
+			goto unreg;
+	}
+	return 0;
+
+unreg:
+	platform_device_unregister(fs_enet_dev);
+err:
+	return ret;
+}
+
+arch_initcall(fs_enet_of_init);
+
+
+static const char *smc_regs = "regs";
+static const char *smc_pram = "pram";
+
+static int __init cpm_smc_uart_of_init(void)
+{
+	struct device_node *np;
+	unsigned int i;
+	struct platform_device *cpm_uart_dev;
+	int ret;
+
+	for (np = NULL, i = 0;
+	     (np = of_find_compatible_node(np, "serial", "cpm_uart")) != NULL;
+	     i++) {
+		struct resource r[3];
+		struct fs_uart_platform_info cpm_uart_data;
+		int *id;
+		char *model;
+
+		memset(r, 0, sizeof(r));
+		memset(&cpm_uart_data, 0, sizeof(cpm_uart_data));
+
+		ret = of_address_to_resource(np, 0, &r[0]);
+		if (ret)
+			goto err;
+
+		r[0].name = smc_regs;
+
+		ret = of_address_to_resource(np, 1, &r[1]);
+		if (ret)
+			goto err;
+		r[1].name = smc_pram;
+
+		r[2].start = r[2].end = irq_of_parse_and_map(np, 0);
+		r[2].flags = IORESOURCE_IRQ;
+
+		cpm_uart_dev =
+		    platform_device_register_simple("fsl-cpm-smc:uart", i, &r[0], 3);
+
+		if (IS_ERR(cpm_uart_dev)) {
+			ret = PTR_ERR(cpm_uart_dev);
+			goto err;
+		}
+
+		model = (char*)get_property(np, "model", NULL);
+		strcpy(cpm_uart_data.fs_type, model);
+
+		id = (int*)get_property(np, "device-id", NULL);
+		cpm_uart_data.fs_no = *id;
+		cpm_uart_data.uart_clk = ppc_proc_freq;
+
+		cpm_uart_data.tx_num_fifo = 4;
+		cpm_uart_data.tx_buf_size = 32;
+		cpm_uart_data.rx_num_fifo = 4;
+		cpm_uart_data.rx_buf_size = 32;
+
+		ret =
+		    platform_device_add_data(cpm_uart_dev, &cpm_uart_data,
+					     sizeof(struct
+						    fs_uart_platform_info));
+		if (ret)
+			goto unreg;
+	}
+
+	return 0;
+
+unreg:
+	platform_device_unregister(cpm_uart_dev);
+err:
+	return ret;
+}
+
+arch_initcall(cpm_smc_uart_of_init);
+
+#endif /* CONFIG_8xx */
diff --git a/arch/powerpc/sysdev/grackle.c b/arch/powerpc/sysdev/grackle.c
index b6ec793..4205362 100644
--- a/arch/powerpc/sysdev/grackle.c
+++ b/arch/powerpc/sysdev/grackle.c
@@ -56,6 +56,8 @@
 void __init setup_grackle(struct pci_controller *hose)
 {
 	setup_indirect_pci(hose, 0xfec00000, 0xfee00000);
+	if (machine_is_compatible("PowerMac1,1"))
+		pci_assign_all_buses = 1;
 	if (machine_is_compatible("AAPL,PowerBook1998"))
 		grackle_set_loop_snoop(hose, 1);
 #if 0	/* Disabled for now, HW problems ??? */
diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
index 746f78c..473c415 100644
--- a/arch/powerpc/sysdev/ipic.c
+++ b/arch/powerpc/sysdev/ipic.c
@@ -557,8 +557,7 @@
 	.xlate	= ipic_host_xlate,
 };
 
-void __init ipic_init(struct device_node *node,
-		unsigned int flags)
+struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)
 {
 	struct ipic	*ipic;
 	struct resource res;
@@ -566,22 +565,24 @@
 
 	ipic = alloc_bootmem(sizeof(struct ipic));
 	if (ipic == NULL)
-		return;
+		return NULL;
 
 	memset(ipic, 0, sizeof(struct ipic));
-	ipic->of_node = node ? of_node_get(node) : NULL;
+	ipic->of_node = of_node_get(node);
 
 	ipic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR,
 				       NR_IPIC_INTS,
 				       &ipic_host_ops, 0);
 	if (ipic->irqhost == NULL) {
 		of_node_put(node);
-		return;
+		return NULL;
 	}
 
 	ret = of_address_to_resource(node, 0, &res);
-	if (ret)
-		return;
+	if (ret) {
+		of_node_put(node);
+		return NULL;
+	}
 
 	ipic->regs = ioremap(res.start, res.end - res.start + 1);
 
@@ -625,6 +626,8 @@
 
 	printk ("IPIC (%d IRQ sources) at %p\n", NR_IPIC_INTS,
 			primary_ipic->regs);
+
+	return ipic;
 }
 
 int ipic_set_priority(unsigned int virq, unsigned int priority)
diff --git a/arch/powerpc/sysdev/micropatch.c b/arch/powerpc/sysdev/micropatch.c
new file mode 100644
index 0000000..712b10a
--- /dev/null
+++ b/arch/powerpc/sysdev/micropatch.c
@@ -0,0 +1,743 @@
+
+/* Microcode patches for the CPM as supplied by Motorola.
+ * This is the one for IIC/SPI.  There is a newer one that
+ * also relocates SMC2, but this would require additional changes
+ * to uart.c, so I am holding off on that for a moment.
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/mpc8xx.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+
+/*
+ * I2C/SPI relocation patch arrays.
+ */
+
+#ifdef CONFIG_I2C_SPI_UCODE_PATCH
+
+uint patch_2000[] = {
+	0x7FFFEFD9,
+	0x3FFD0000,
+	0x7FFB49F7,
+	0x7FF90000,
+	0x5FEFADF7,
+	0x5F89ADF7,
+	0x5FEFAFF7,
+	0x5F89AFF7,
+	0x3A9CFBC8,
+	0xE7C0EDF0,
+	0x77C1E1BB,
+	0xF4DC7F1D,
+	0xABAD932F,
+	0x4E08FDCF,
+	0x6E0FAFF8,
+	0x7CCF76CF,
+	0xFD1FF9CF,
+	0xABF88DC6,
+	0xAB5679F7,
+	0xB0937383,
+	0xDFCE79F7,
+	0xB091E6BB,
+	0xE5BBE74F,
+	0xB3FA6F0F,
+	0x6FFB76CE,
+	0xEE0DF9CF,
+	0x2BFBEFEF,
+	0xCFEEF9CF,
+	0x76CEAD24,
+	0x90B2DF9A,
+	0x7FDDD0BF,
+	0x4BF847FD,
+	0x7CCF76CE,
+	0xCFEF7E1F,
+	0x7F1D7DFD,
+	0xF0B6EF71,
+	0x7FC177C1,
+	0xFBC86079,
+	0xE722FBC8,
+	0x5FFFDFFF,
+	0x5FB2FFFB,
+	0xFBC8F3C8,
+	0x94A67F01,
+	0x7F1D5F39,
+	0xAFE85F5E,
+	0xFFDFDF96,
+	0xCB9FAF7D,
+	0x5FC1AFED,
+	0x8C1C5FC1,
+	0xAFDD5FC3,
+	0xDF9A7EFD,
+	0xB0B25FB2,
+	0xFFFEABAD,
+	0x5FB2FFFE,
+	0x5FCE600B,
+	0xE6BB600B,
+	0x5FCEDFC6,
+	0x27FBEFDF,
+	0x5FC8CFDE,
+	0x3A9CE7C0,
+	0xEDF0F3C8,
+	0x7F0154CD,
+	0x7F1D2D3D,
+	0x363A7570,
+	0x7E0AF1CE,
+	0x37EF2E68,
+	0x7FEE10EC,
+	0xADF8EFDE,
+	0xCFEAE52F,
+	0x7D0FE12B,
+	0xF1CE5F65,
+	0x7E0A4DF8,
+	0xCFEA5F72,
+	0x7D0BEFEE,
+	0xCFEA5F74,
+	0xE522EFDE,
+	0x5F74CFDA,
+	0x0B627385,
+	0xDF627E0A,
+	0x30D8145B,
+	0xBFFFF3C8,
+	0x5FFFDFFF,
+	0xA7F85F5E,
+	0xBFFE7F7D,
+	0x10D31450,
+	0x5F36BFFF,
+	0xAF785F5E,
+	0xBFFDA7F8,
+	0x5F36BFFE,
+	0x77FD30C0,
+	0x4E08FDCF,
+	0xE5FF6E0F,
+	0xAFF87E1F,
+	0x7E0FFD1F,
+	0xF1CF5F1B,
+	0xABF80D5E,
+	0x5F5EFFEF,
+	0x79F730A2,
+	0xAFDD5F34,
+	0x47F85F34,
+	0xAFED7FDD,
+	0x50B24978,
+	0x47FD7F1D,
+	0x7DFD70AD,
+	0xEF717EC1,
+	0x6BA47F01,
+	0x2D267EFD,
+	0x30DE5F5E,
+	0xFFFD5F5E,
+	0xFFEF5F5E,
+	0xFFDF0CA0,
+	0xAFED0A9E,
+	0xAFDD0C3A,
+	0x5F3AAFBD,
+	0x7FBDB082,
+	0x5F8247F8
+};
+
+uint patch_2f00[] = {
+	0x3E303430,
+	0x34343737,
+	0xABF7BF9B,
+	0x994B4FBD,
+	0xBD599493,
+	0x349FFF37,
+	0xFB9B177D,
+	0xD9936956,
+	0xBBFDD697,
+	0xBDD2FD11,
+	0x31DB9BB3,
+	0x63139637,
+	0x93733693,
+	0x193137F7,
+	0x331737AF,
+	0x7BB9B999,
+	0xBB197957,
+	0x7FDFD3D5,
+	0x73B773F7,
+	0x37933B99,
+	0x1D115316,
+	0x99315315,
+	0x31694BF4,
+	0xFBDBD359,
+	0x31497353,
+	0x76956D69,
+	0x7B9D9693,
+	0x13131979,
+	0x79376935
+};
+#endif
+
+/*
+ * I2C/SPI/SMC1 relocation patch arrays.
+ */
+
+#ifdef CONFIG_I2C_SPI_SMC1_UCODE_PATCH
+
+uint patch_2000[] = {
+	0x3fff0000,
+	0x3ffd0000,
+	0x3ffb0000,
+	0x3ff90000,
+	0x5f13eff8,
+	0x5eb5eff8,
+	0x5f88adf7,
+	0x5fefadf7,
+	0x3a9cfbc8,
+	0x77cae1bb,
+	0xf4de7fad,
+	0xabae9330,
+	0x4e08fdcf,
+	0x6e0faff8,
+	0x7ccf76cf,
+	0xfdaff9cf,
+	0xabf88dc8,
+	0xab5879f7,
+	0xb0925d8d,
+	0xdfd079f7,
+	0xb090e6bb,
+	0xe5bbe74f,
+	0x9e046f0f,
+	0x6ffb76ce,
+	0xee0cf9cf,
+	0x2bfbefef,
+	0xcfeef9cf,
+	0x76cead23,
+	0x90b3df99,
+	0x7fddd0c1,
+	0x4bf847fd,
+	0x7ccf76ce,
+	0xcfef77ca,
+	0x7eaf7fad,
+	0x7dfdf0b7,
+	0xef7a7fca,
+	0x77cafbc8,
+	0x6079e722,
+	0xfbc85fff,
+	0xdfff5fb3,
+	0xfffbfbc8,
+	0xf3c894a5,
+	0xe7c9edf9,
+	0x7f9a7fad,
+	0x5f36afe8,
+	0x5f5bffdf,
+	0xdf95cb9e,
+	0xaf7d5fc3,
+	0xafed8c1b,
+	0x5fc3afdd,
+	0x5fc5df99,
+	0x7efdb0b3,
+	0x5fb3fffe,
+	0xabae5fb3,
+	0xfffe5fd0,
+	0x600be6bb,
+	0x600b5fd0,
+	0xdfc827fb,
+	0xefdf5fca,
+	0xcfde3a9c,
+	0xe7c9edf9,
+	0xf3c87f9e,
+	0x54ca7fed,
+	0x2d3a3637,
+	0x756f7e9a,
+	0xf1ce37ef,
+	0x2e677fee,
+	0x10ebadf8,
+	0xefdecfea,
+	0xe52f7d9f,
+	0xe12bf1ce,
+	0x5f647e9a,
+	0x4df8cfea,
+	0x5f717d9b,
+	0xefeecfea,
+	0x5f73e522,
+	0xefde5f73,
+	0xcfda0b61,
+	0x5d8fdf61,
+	0xe7c9edf9,
+	0x7e9a30d5,
+	0x1458bfff,
+	0xf3c85fff,
+	0xdfffa7f8,
+	0x5f5bbffe,
+	0x7f7d10d0,
+	0x144d5f33,
+	0xbfffaf78,
+	0x5f5bbffd,
+	0xa7f85f33,
+	0xbffe77fd,
+	0x30bd4e08,
+	0xfdcfe5ff,
+	0x6e0faff8,
+	0x7eef7e9f,
+	0xfdeff1cf,
+	0x5f17abf8,
+	0x0d5b5f5b,
+	0xffef79f7,
+	0x309eafdd,
+	0x5f3147f8,
+	0x5f31afed,
+	0x7fdd50af,
+	0x497847fd,
+	0x7f9e7fed,
+	0x7dfd70a9,
+	0xef7e7ece,
+	0x6ba07f9e,
+	0x2d227efd,
+	0x30db5f5b,
+	0xfffd5f5b,
+	0xffef5f5b,
+	0xffdf0c9c,
+	0xafed0a9a,
+	0xafdd0c37,
+	0x5f37afbd,
+	0x7fbdb081,
+	0x5f8147f8,
+	0x3a11e710,
+	0xedf0ccdd,
+	0xf3186d0a,
+	0x7f0e5f06,
+	0x7fedbb38,
+	0x3afe7468,
+	0x7fedf4fc,
+	0x8ffbb951,
+	0xb85f77fd,
+	0xb0df5ddd,
+	0xdefe7fed,
+	0x90e1e74d,
+	0x6f0dcbf7,
+	0xe7decfed,
+	0xcb74cfed,
+	0xcfeddf6d,
+	0x91714f74,
+	0x5dd2deef,
+	0x9e04e7df,
+	0xefbb6ffb,
+	0xe7ef7f0e,
+	0x9e097fed,
+	0xebdbeffa,
+	0xeb54affb,
+	0x7fea90d7,
+	0x7e0cf0c3,
+	0xbffff318,
+	0x5fffdfff,
+	0xac59efea,
+	0x7fce1ee5,
+	0xe2ff5ee1,
+	0xaffbe2ff,
+	0x5ee3affb,
+	0xf9cc7d0f,
+	0xaef8770f,
+	0x7d0fb0c6,
+	0xeffbbfff,
+	0xcfef5ede,
+	0x7d0fbfff,
+	0x5ede4cf8,
+	0x7fddd0bf,
+	0x49f847fd,
+	0x7efdf0bb,
+	0x7fedfffd,
+	0x7dfdf0b7,
+	0xef7e7e1e,
+	0x5ede7f0e,
+	0x3a11e710,
+	0xedf0ccab,
+	0xfb18ad2e,
+	0x1ea9bbb8,
+	0x74283b7e,
+	0x73c2e4bb,
+	0x2ada4fb8,
+	0xdc21e4bb,
+	0xb2a1ffbf,
+	0x5e2c43f8,
+	0xfc87e1bb,
+	0xe74ffd91,
+	0x6f0f4fe8,
+	0xc7ba32e2,
+	0xf396efeb,
+	0x600b4f78,
+	0xe5bb760b,
+	0x53acaef8,
+	0x4ef88b0e,
+	0xcfef9e09,
+	0xabf8751f,
+	0xefef5bac,
+	0x741f4fe8,
+	0x751e760d,
+	0x7fdbf081,
+	0x741cafce,
+	0xefcc7fce,
+	0x751e70ac,
+	0x741ce7bb,
+	0x3372cfed,
+	0xafdbefeb,
+	0xe5bb760b,
+	0x53f2aef8,
+	0xafe8e7eb,
+	0x4bf8771e,
+	0x7e247fed,
+	0x4fcbe2cc,
+	0x7fbc30a9,
+	0x7b0f7a0f,
+	0x34d577fd,
+	0x308b5db7,
+	0xde553e5f,
+	0xaf78741f,
+	0x741f30f0,
+	0xcfef5e2c,
+	0x741f3eac,
+	0xafb8771e,
+	0x5e677fed,
+	0x0bd3e2cc,
+	0x741ccfec,
+	0xe5ca53cd,
+	0x6fcb4f74,
+	0x5dadde4b,
+	0x2ab63d38,
+	0x4bb3de30,
+	0x751f741c,
+	0x6c42effa,
+	0xefea7fce,
+	0x6ffc30be,
+	0xefec3fca,
+	0x30b3de2e,
+	0xadf85d9e,
+	0xaf7daefd,
+	0x5d9ede2e,
+	0x5d9eafdd,
+	0x761f10ac,
+	0x1da07efd,
+	0x30adfffe,
+	0x4908fb18,
+	0x5fffdfff,
+	0xafbb709b,
+	0x4ef85e67,
+	0xadf814ad,
+	0x7a0f70ad,
+	0xcfef50ad,
+	0x7a0fde30,
+	0x5da0afed,
+	0x3c12780f,
+	0xefef780f,
+	0xefef790f,
+	0xa7f85e0f,
+	0xffef790f,
+	0xefef790f,
+	0x14adde2e,
+	0x5d9eadfd,
+	0x5e2dfffb,
+	0xe79addfd,
+	0xeff96079,
+	0x607ae79a,
+	0xddfceff9,
+	0x60795dff,
+	0x607acfef,
+	0xefefefdf,
+	0xefbfef7f,
+	0xeeffedff,
+	0xebffe7ff,
+	0xafefafdf,
+	0xafbfaf7f,
+	0xaeffadff,
+	0xabffa7ff,
+	0x6fef6fdf,
+	0x6fbf6f7f,
+	0x6eff6dff,
+	0x6bff67ff,
+	0x2fef2fdf,
+	0x2fbf2f7f,
+	0x2eff2dff,
+	0x2bff27ff,
+	0x4e08fd1f,
+	0xe5ff6e0f,
+	0xaff87eef,
+	0x7e0ffdef,
+	0xf11f6079,
+	0xabf8f542,
+	0x7e0af11c,
+	0x37cfae3a,
+	0x7fec90be,
+	0xadf8efdc,
+	0xcfeae52f,
+	0x7d0fe12b,
+	0xf11c6079,
+	0x7e0a4df8,
+	0xcfea5dc4,
+	0x7d0befec,
+	0xcfea5dc6,
+	0xe522efdc,
+	0x5dc6cfda,
+	0x4e08fd1f,
+	0x6e0faff8,
+	0x7c1f761f,
+	0xfdeff91f,
+	0x6079abf8,
+	0x761cee24,
+	0xf91f2bfb,
+	0xefefcfec,
+	0xf91f6079,
+	0x761c27fb,
+	0xefdf5da7,
+	0xcfdc7fdd,
+	0xd09c4bf8,
+	0x47fd7c1f,
+	0x761ccfcf,
+	0x7eef7fed,
+	0x7dfdf093,
+	0xef7e7f1e,
+	0x771efb18,
+	0x6079e722,
+	0xe6bbe5bb,
+	0xae0ae5bb,
+	0x600bae85,
+	0xe2bbe2bb,
+	0xe2bbe2bb,
+	0xaf02e2bb,
+	0xe2bb2ff9,
+	0x6079e2bb
+};
+
+uint patch_2f00[] = {
+	0x30303030,
+	0x3e3e3434,
+	0xabbf9b99,
+	0x4b4fbdbd,
+	0x59949334,
+	0x9fff37fb,
+	0x9b177dd9,
+	0x936956bb,
+	0xfbdd697b,
+	0xdd2fd113,
+	0x1db9f7bb,
+	0x36313963,
+	0x79373369,
+	0x3193137f,
+	0x7331737a,
+	0xf7bb9b99,
+	0x9bb19795,
+	0x77fdfd3d,
+	0x573b773f,
+	0x737933f7,
+	0xb991d115,
+	0x31699315,
+	0x31531694,
+	0xbf4fbdbd,
+	0x35931497,
+	0x35376956,
+	0xbd697b9d,
+	0x96931313,
+	0x19797937,
+	0x6935af78,
+	0xb9b3baa3,
+	0xb8788683,
+	0x368f78f7,
+	0x87778733,
+	0x3ffffb3b,
+	0x8e8f78b8,
+	0x1d118e13,
+	0xf3ff3f8b,
+	0x6bd8e173,
+	0xd1366856,
+	0x68d1687b,
+	0x3daf78b8,
+	0x3a3a3f87,
+	0x8f81378f,
+	0xf876f887,
+	0x77fd8778,
+	0x737de8d6,
+	0xbbf8bfff,
+	0xd8df87f7,
+	0xfd876f7b,
+	0x8bfff8bd,
+	0x8683387d,
+	0xb873d87b,
+	0x3b8fd7f8,
+	0xf7338883,
+	0xbb8ee1f8,
+	0xef837377,
+	0x3337b836,
+	0x817d11f8,
+	0x7378b878,
+	0xd3368b7d,
+	0xed731b7d,
+	0x833731f3,
+	0xf22f3f23
+};
+
+uint patch_2e00[] = {
+	0x27eeeeee,
+	0xeeeeeeee,
+	0xeeeeeeee,
+	0xeeeeeeee,
+	0xee4bf4fb,
+	0xdbd259bb,
+	0x1979577f,
+	0xdfd2d573,
+	0xb773f737,
+	0x4b4fbdbd,
+	0x25b9b177,
+	0xd2d17376,
+	0x956bbfdd,
+	0x697bdd2f,
+	0xff9f79ff,
+	0xff9ff22f
+};
+#endif
+
+/*
+ *  USB SOF patch arrays.
+ */
+
+#ifdef CONFIG_USB_SOF_UCODE_PATCH
+
+uint patch_2000[] = {
+	0x7fff0000,
+	0x7ffd0000,
+	0x7ffb0000,
+	0x49f7ba5b,
+	0xba383ffb,
+	0xf9b8b46d,
+	0xe5ab4e07,
+	0xaf77bffe,
+	0x3f7bbf79,
+	0xba5bba38,
+	0xe7676076,
+	0x60750000
+};
+
+uint patch_2f00[] = {
+	0x3030304c,
+	0xcab9e441,
+	0xa1aaf220
+};
+#endif
+
+void
+cpm_load_patch(cpm8xx_t	*cp)
+{
+	volatile uint		*dp;		/* Dual-ported RAM. */
+	volatile cpm8xx_t	*commproc;
+	volatile iic_t		*iip;
+	volatile spi_t		*spp;
+	volatile smc_uart_t	*smp;
+	int	i;
+
+	commproc = cp;
+
+#ifdef CONFIG_USB_SOF_UCODE_PATCH
+	commproc->cp_rccr = 0;
+
+	dp = (uint *)(commproc->cp_dpmem);
+	for (i=0; i<(sizeof(patch_2000)/4); i++)
+		*dp++ = patch_2000[i];
+
+	dp = (uint *)&(commproc->cp_dpmem[0x0f00]);
+	for (i=0; i<(sizeof(patch_2f00)/4); i++)
+		*dp++ = patch_2f00[i];
+
+	commproc->cp_rccr = 0x0009;
+
+	printk("USB SOF microcode patch installed\n");
+#endif /* CONFIG_USB_SOF_UCODE_PATCH */
+
+#if defined(CONFIG_I2C_SPI_UCODE_PATCH) || \
+    defined(CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
+
+	commproc->cp_rccr = 0;
+
+	dp = (uint *)(commproc->cp_dpmem);
+	for (i=0; i<(sizeof(patch_2000)/4); i++)
+		*dp++ = patch_2000[i];
+
+	dp = (uint *)&(commproc->cp_dpmem[0x0f00]);
+	for (i=0; i<(sizeof(patch_2f00)/4); i++)
+		*dp++ = patch_2f00[i];
+
+	iip = (iic_t *)&commproc->cp_dparam[PROFF_IIC];
+# define RPBASE 0x0500
+	iip->iic_rpbase = RPBASE;
+
+	/* Put SPI above the IIC, also 32-byte aligned.
+	*/
+	i = (RPBASE + sizeof(iic_t) + 31) & ~31;
+	spp = (spi_t *)&commproc->cp_dparam[PROFF_SPI];
+	spp->spi_rpbase = i;
+
+# if defined(CONFIG_I2C_SPI_UCODE_PATCH)
+	commproc->cp_cpmcr1 = 0x802a;
+	commproc->cp_cpmcr2 = 0x8028;
+	commproc->cp_cpmcr3 = 0x802e;
+	commproc->cp_cpmcr4 = 0x802c;
+	commproc->cp_rccr = 1;
+
+	printk("I2C/SPI microcode patch installed.\n");
+# endif /* CONFIG_I2C_SPI_UCODE_PATCH */
+
+# if defined(CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
+
+	dp = (uint *)&(commproc->cp_dpmem[0x0e00]);
+	for (i=0; i<(sizeof(patch_2e00)/4); i++)
+		*dp++ = patch_2e00[i];
+
+	commproc->cp_cpmcr1 = 0x8080;
+	commproc->cp_cpmcr2 = 0x808a;
+	commproc->cp_cpmcr3 = 0x8028;
+	commproc->cp_cpmcr4 = 0x802a;
+	commproc->cp_rccr = 3;
+
+	smp = (smc_uart_t *)&commproc->cp_dparam[PROFF_SMC1];
+	smp->smc_rpbase = 0x1FC0;
+
+	printk("I2C/SPI/SMC1 microcode patch installed.\n");
+# endif /* CONFIG_I2C_SPI_SMC1_UCODE_PATCH) */
+
+#endif /* some variation of the I2C/SPI patch was selected */
+}
+
+/*
+ *  Take this entire routine out, since no one calls it and its
+ * logic is suspect.
+ */
+
+#if 0
+void
+verify_patch(volatile immap_t *immr)
+{
+	volatile uint		*dp;
+	volatile cpm8xx_t	*commproc;
+	int i;
+
+	commproc = (cpm8xx_t *)&immr->im_cpm;
+
+	printk("cp_rccr %x\n", commproc->cp_rccr);
+	commproc->cp_rccr = 0;
+
+	dp = (uint *)(commproc->cp_dpmem);
+	for (i=0; i<(sizeof(patch_2000)/4); i++)
+		if (*dp++ != patch_2000[i]) {
+			printk("patch_2000 bad at %d\n", i);
+			dp--;
+			printk("found 0x%X, wanted 0x%X\n", *dp, patch_2000[i]);
+			break;
+		}
+
+	dp = (uint *)&(commproc->cp_dpmem[0x0f00]);
+	for (i=0; i<(sizeof(patch_2f00)/4); i++)
+		if (*dp++ != patch_2f00[i]) {
+			printk("patch_2f00 bad at %d\n", i);
+			dp--;
+			printk("found 0x%X, wanted 0x%X\n", *dp, patch_2f00[i]);
+			break;
+		}
+
+	commproc->cp_rccr = 0x0009;
+}
+#endif
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c
new file mode 100644
index 0000000..2fc2bcd
--- /dev/null
+++ b/arch/powerpc/sysdev/mpc8xx_pic.c
@@ -0,0 +1,197 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/irq.h>
+#include <linux/dma-mapping.h>
+#include <asm/prom.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/8xx_immap.h>
+#include <asm/mpc8xx.h>
+
+#include "mpc8xx_pic.h"
+
+
+#define PIC_VEC_SPURRIOUS      15
+
+extern int cpm_get_irq(struct pt_regs *regs);
+
+static struct device_node *mpc8xx_pic_node;
+static struct irq_host *mpc8xx_pic_host;
+#define NR_MASK_WORDS   ((NR_IRQS + 31) / 32)
+static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
+static sysconf8xx_t	*siu_reg;
+
+int cpm_get_irq(struct pt_regs *regs);
+
+static void mpc8xx_unmask_irq(unsigned int virq)
+{
+	int	bit, word;
+	unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
+
+	bit = irq_nr & 0x1f;
+	word = irq_nr >> 5;
+
+	ppc_cached_irq_mask[word] |= (1 << (31-bit));
+	out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]);
+}
+
+static void mpc8xx_mask_irq(unsigned int virq)
+{
+	int	bit, word;
+	unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
+
+	bit = irq_nr & 0x1f;
+	word = irq_nr >> 5;
+
+	ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
+	out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]);
+}
+
+static void mpc8xx_ack(unsigned int virq)
+{
+	int	bit;
+	unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
+
+	bit = irq_nr & 0x1f;
+	out_be32(&siu_reg->sc_sipend, 1 << (31-bit));
+}
+
+static void mpc8xx_end_irq(unsigned int virq)
+{
+	int bit, word;
+	unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
+
+	bit = irq_nr & 0x1f;
+	word = irq_nr >> 5;
+
+	ppc_cached_irq_mask[word] |= (1 << (31-bit));
+	out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]);
+}
+
+static int mpc8xx_set_irq_type(unsigned int virq, unsigned int flow_type)
+{
+	struct irq_desc *desc = get_irq_desc(virq);
+
+	desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
+	desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
+	if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
+		desc->status |= IRQ_LEVEL;
+
+	if (flow_type & IRQ_TYPE_EDGE_FALLING) {
+		irq_hw_number_t hw = (unsigned int)irq_map[virq].hwirq;
+		unsigned int siel = in_be32(&siu_reg->sc_siel);
+
+		/* only external IRQ senses are programmable */
+		if ((hw & 1) == 0) {
+			siel |= (0x80000000 >> hw);
+			out_be32(&siu_reg->sc_siel, siel);
+			desc->handle_irq = handle_edge_irq;
+		}
+	}
+	return 0;
+}
+
+static struct irq_chip mpc8xx_pic = {
+	.typename = " MPC8XX SIU ",
+	.unmask = mpc8xx_unmask_irq,
+	.mask = mpc8xx_mask_irq,
+	.ack = mpc8xx_ack,
+	.eoi = mpc8xx_end_irq,
+	.set_type = mpc8xx_set_irq_type,
+};
+
+unsigned int mpc8xx_get_irq(void)
+{
+	int irq;
+
+	/* For MPC8xx, read the SIVEC register and shift the bits down
+	 * to get the irq number.
+	 */
+	irq = in_be32(&siu_reg->sc_sivec) >> 26;
+
+	if (irq == PIC_VEC_SPURRIOUS)
+		irq = NO_IRQ;
+
+        return irq_linear_revmap(mpc8xx_pic_host, irq);
+
+}
+
+static int mpc8xx_pic_host_match(struct irq_host *h, struct device_node *node)
+{
+	return mpc8xx_pic_node == node;
+}
+
+static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq,
+			  irq_hw_number_t hw)
+{
+	pr_debug("mpc8xx_pic_host_map(%d, 0x%lx)\n", virq, hw);
+
+	/* Set default irq handle */
+	set_irq_chip_and_handler(virq, &mpc8xx_pic, handle_level_irq);
+	return 0;
+}
+
+
+static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct,
+			    u32 *intspec, unsigned int intsize,
+			    irq_hw_number_t *out_hwirq, unsigned int *out_flags)
+{
+	static unsigned char map_pic_senses[4] = {
+		IRQ_TYPE_EDGE_RISING,
+		IRQ_TYPE_LEVEL_LOW,
+		IRQ_TYPE_LEVEL_HIGH,
+		IRQ_TYPE_EDGE_FALLING,
+	};
+
+	*out_hwirq = intspec[0];
+	if (intsize > 1 && intspec[1] < 4)
+		*out_flags = map_pic_senses[intspec[1]];
+	else
+		*out_flags = IRQ_TYPE_NONE;
+
+	return 0;
+}
+
+
+static struct irq_host_ops mpc8xx_pic_host_ops = {
+	.match = mpc8xx_pic_host_match,
+	.map = mpc8xx_pic_host_map,
+	.xlate = mpc8xx_pic_host_xlate,
+};
+
+int mpc8xx_pic_init(void)
+{
+	struct resource res;
+	struct device_node *np = NULL;
+	int ret;
+
+	np = of_find_node_by_type(np, "mpc8xx-pic");
+
+	if (np == NULL) {
+		printk(KERN_ERR "Could not find open-pic node\n");
+		return -ENOMEM;
+	}
+
+	mpc8xx_pic_node = of_node_get(np);
+
+	ret = of_address_to_resource(np, 0, &res);
+	of_node_put(np);
+	if (ret)
+		return ret;
+
+	siu_reg = (void *)ioremap(res.start, res.end - res.start + 1);
+	if (siu_reg == NULL)
+		return -EINVAL;
+
+	mpc8xx_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 64, &mpc8xx_pic_host_ops, 64);
+	if (mpc8xx_pic_host == NULL) {
+		printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n");
+		ret = -ENOMEM;
+	}
+
+	return ret;
+}
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.h b/arch/powerpc/sysdev/mpc8xx_pic.h
new file mode 100644
index 0000000..afa2ee6
--- /dev/null
+++ b/arch/powerpc/sysdev/mpc8xx_pic.h
@@ -0,0 +1,12 @@
+#ifndef _PPC_KERNEL_MPC8xx_H
+#define _PPC_KERNEL_MPC8xx_H
+
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+extern struct hw_interrupt_type mpc8xx_pic;
+
+int mpc8xx_pic_init(void);
+unsigned int mpc8xx_get_irq(void);
+
+#endif /* _PPC_KERNEL_PPC8xx_H */
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index d01ced1..aa701cc 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -496,13 +496,18 @@
 static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi)
 {
 	unsigned int src = mpic_irq_to_hw(irq);
+	struct mpic *mpic;
 
 	if (irq < NUM_ISA_INTERRUPTS)
 		return NULL;
-	if (is_ipi)
-		*is_ipi = (src >= MPIC_VEC_IPI_0 && src <= MPIC_VEC_IPI_3);
 
-	return irq_desc[irq].chip_data;
+	mpic = irq_desc[irq].chip_data;
+
+	if (is_ipi)
+		*is_ipi = (src >= mpic->ipi_vecs[0] &&
+			   src <= mpic->ipi_vecs[3]);
+
+	return mpic;
 }
 
 /* Convert a cpu mask from logical to physical cpu numbers. */
@@ -540,7 +545,11 @@
 #ifdef CONFIG_SMP
 static irqreturn_t mpic_ipi_action(int irq, void *dev_id)
 {
-	smp_message_recv(mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0);
+	struct mpic *mpic;
+
+	mpic = mpic_find(irq, NULL);
+	smp_message_recv(mpic_irq_to_hw(irq) - mpic->ipi_vecs[0]);
+
 	return IRQ_HANDLED;
 }
 #endif /* CONFIG_SMP */
@@ -663,7 +672,7 @@
 static void mpic_unmask_ipi(unsigned int irq)
 {
 	struct mpic *mpic = mpic_from_ipi(irq);
-	unsigned int src = mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0;
+	unsigned int src = mpic_irq_to_hw(irq) - mpic->ipi_vecs[0];
 
 	DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src);
 	mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK);
@@ -807,11 +816,11 @@
 
 	DBG("mpic: map virq %d, hwirq 0x%lx\n", virq, hw);
 
-	if (hw == MPIC_VEC_SPURRIOUS)
+	if (hw == mpic->spurious_vec)
 		return -EINVAL;
 
 #ifdef CONFIG_SMP
-	else if (hw >= MPIC_VEC_IPI_0) {
+	else if (hw >= mpic->ipi_vecs[0]) {
 		WARN_ON(!(mpic->flags & MPIC_PRIMARY));
 
 		DBG("mpic: mapping as IPI\n");
@@ -904,6 +913,7 @@
 	u32		reg;
 	const char	*vers;
 	int		i;
+	int		intvec_top;
 	u64		paddr = phys_addr;
 
 	mpic = alloc_bootmem(sizeof(struct mpic));
@@ -912,11 +922,11 @@
 	
 	memset(mpic, 0, sizeof(struct mpic));
 	mpic->name = name;
-	mpic->of_node = node ? of_node_get(node) : NULL;
+	mpic->of_node = of_node_get(node);
 
-	mpic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 256,
+	mpic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, isu_size,
 				       &mpic_host_ops,
-				       MPIC_VEC_SPURRIOUS);
+				       flags & MPIC_LARGE_VECTORS ? 2048 : 256);
 	if (mpic->irqhost == NULL) {
 		of_node_put(node);
 		return NULL;
@@ -944,6 +954,21 @@
 	mpic->irq_count = irq_count;
 	mpic->num_sources = 0; /* so far */
 
+	if (flags & MPIC_LARGE_VECTORS)
+		intvec_top = 2047;
+	else
+		intvec_top = 255;
+
+	mpic->timer_vecs[0] = intvec_top - 8;
+	mpic->timer_vecs[1] = intvec_top - 7;
+	mpic->timer_vecs[2] = intvec_top - 6;
+	mpic->timer_vecs[3] = intvec_top - 5;
+	mpic->ipi_vecs[0]   = intvec_top - 4;
+	mpic->ipi_vecs[1]   = intvec_top - 3;
+	mpic->ipi_vecs[2]   = intvec_top - 2;
+	mpic->ipi_vecs[3]   = intvec_top - 1;
+	mpic->spurious_vec  = intvec_top;
+
 	/* Check for "big-endian" in device-tree */
 	if (node && get_property(node, "big-endian", NULL) != NULL)
 		mpic->flags |= MPIC_BIG_ENDIAN;
@@ -1084,11 +1109,6 @@
 	int i;
 
 	BUG_ON(mpic->num_sources == 0);
-	WARN_ON(mpic->num_sources > MPIC_VEC_IPI_0);
-
-	/* Sanitize source count */
-	if (mpic->num_sources > MPIC_VEC_IPI_0)
-		mpic->num_sources = MPIC_VEC_IPI_0;
 
 	printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources);
 
@@ -1104,7 +1124,7 @@
 			   i * MPIC_INFO(TIMER_STRIDE) +
 			   MPIC_INFO(TIMER_VECTOR_PRI),
 			   MPIC_VECPRI_MASK |
-			   (MPIC_VEC_TIMER_0 + i));
+			   (mpic->timer_vecs[0] + i));
 	}
 
 	/* Initialize IPIs to our reserved vectors and mark them disabled for now */
@@ -1113,7 +1133,7 @@
 		mpic_ipi_write(i,
 			       MPIC_VECPRI_MASK |
 			       (10 << MPIC_VECPRI_PRIORITY_SHIFT) |
-			       (MPIC_VEC_IPI_0 + i));
+			       (mpic->ipi_vecs[0] + i));
 	}
 
 	/* Initialize interrupt sources */
@@ -1136,8 +1156,8 @@
 			       1 << hard_smp_processor_id());
 	}
 	
-	/* Init spurrious vector */
-	mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS), MPIC_VEC_SPURRIOUS);
+	/* Init spurious vector */
+	mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS), mpic->spurious_vec);
 
 	/* Disable 8259 passthrough, if supported */
 	if (!(mpic->flags & MPIC_NO_PTHROU_DIS))
@@ -1184,9 +1204,9 @@
 
 	spin_lock_irqsave(&mpic_lock, flags);
 	if (is_ipi) {
-		reg = mpic_ipi_read(src - MPIC_VEC_IPI_0) &
+		reg = mpic_ipi_read(src - mpic->ipi_vecs[0]) &
 			~MPIC_VECPRI_PRIORITY_MASK;
-		mpic_ipi_write(src - MPIC_VEC_IPI_0,
+		mpic_ipi_write(src - mpic->ipi_vecs[0],
 			       reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
 	} else {
 		reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI))
@@ -1207,7 +1227,7 @@
 
 	spin_lock_irqsave(&mpic_lock, flags);
 	if (is_ipi)
-		reg = mpic_ipi_read(src = MPIC_VEC_IPI_0);
+		reg = mpic_ipi_read(src = mpic->ipi_vecs[0]);
 	else
 		reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI));
 	spin_unlock_irqrestore(&mpic_lock, flags);
@@ -1313,7 +1333,7 @@
 #ifdef DEBUG_LOW
 	DBG("%s: get_one_irq(): %d\n", mpic->name, src);
 #endif
-	if (unlikely(src == MPIC_VEC_SPURRIOUS))
+	if (unlikely(src == mpic->spurious_vec))
 		return NO_IRQ;
 	return irq_linear_revmap(mpic->irqhost, src);
 }
@@ -1345,7 +1365,7 @@
 
 	for (i = 0; i < 4; i++) {
 		unsigned int vipi = irq_create_mapping(mpic->irqhost,
-						       MPIC_VEC_IPI_0 + i);
+						       mpic->ipi_vecs[0] + i);
 		if (vipi == NO_IRQ) {
 			printk(KERN_ERR "Failed to map IPI %d\n", i);
 			break;
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c
index 74e48d9..4d1dcb4 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_ic.c
+++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
@@ -323,7 +323,7 @@
 	return irq_linear_revmap(qe_ic->irqhost, irq);
 }
 
-void fastcall qe_ic_cascade_low(unsigned int irq, struct irq_desc *desc)
+void qe_ic_cascade_low(unsigned int irq, struct irq_desc *desc)
 {
 	struct qe_ic *qe_ic = desc->handler_data;
 	unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
@@ -332,7 +332,7 @@
 		generic_handle_irq(cascade_irq);
 }
 
-void fastcall qe_ic_cascade_high(unsigned int irq, struct irq_desc *desc)
+void qe_ic_cascade_high(unsigned int irq, struct irq_desc *desc)
 {
 	struct qe_ic *qe_ic = desc->handler_data;
 	unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
@@ -352,7 +352,7 @@
 		return;
 
 	memset(qe_ic, 0, sizeof(struct qe_ic));
-	qe_ic->of_node = node ? of_node_get(node) : NULL;
+	qe_ic->of_node = of_node_get(node);
 
 	qe_ic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR,
 					NR_QE_IC_INTS, &qe_ic_host_ops, 0);
diff --git a/arch/powerpc/xmon/ppc-opc.c b/arch/powerpc/xmon/ppc-opc.c
index 5d841f4..af3780e 100644
--- a/arch/powerpc/xmon/ppc-opc.c
+++ b/arch/powerpc/xmon/ppc-opc.c
@@ -21,6 +21,7 @@
    02110-1301, USA.  */
 
 #include <linux/stddef.h>
+#include <linux/kernel.h>
 #include "nonstdio.h"
 #include "ppc.h"
 
@@ -4932,8 +4933,7 @@
 
 };
 
-const int powerpc_num_opcodes =
-  sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]);
+const int powerpc_num_opcodes = ARRAY_SIZE(powerpc_opcodes);
 
 /* The macro table.  This is only used by the assembler.  */
 
@@ -4989,5 +4989,4 @@
 { "clrlslwi.",4,  PPCCOM,	"rlwinm. %0,%1,%3,(%2)-(%3),31-(%3)" },
 };
 
-const int powerpc_num_macros =
-  sizeof (powerpc_macros) / sizeof (powerpc_macros[0]);
+const int powerpc_num_macros = ARRAY_SIZE(powerpc_macros);
diff --git a/arch/powerpc/xmon/spu-dis.c b/arch/powerpc/xmon/spu-dis.c
index ee929c6..e5f8983 100644
--- a/arch/powerpc/xmon/spu-dis.c
+++ b/arch/powerpc/xmon/spu-dis.c
@@ -85,7 +85,7 @@
   if ((index = spu_disassemble_table[opcode & 0x7ff]) != 0)
     return index;
 
-  return 0;
+  return NULL;
 }
 
 /* Print a Spu instruction.  */
diff --git a/arch/powerpc/xmon/spu-opc.c b/arch/powerpc/xmon/spu-opc.c
index efffde9..530df3d 100644
--- a/arch/powerpc/xmon/spu-opc.c
+++ b/arch/powerpc/xmon/spu-opc.c
@@ -18,6 +18,7 @@
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
+#include <linux/kernel.h>
 #include "spu.h"
 
 /* This file holds the Spu opcode table */
@@ -40,5 +41,4 @@
 #undef APUOPFB
 };
 
-const int spu_num_opcodes =
-  sizeof (spu_opcodes) / sizeof (spu_opcodes[0]);
+const int spu_num_opcodes = ARRAY_SIZE(spu_opcodes);
diff --git a/arch/ppc/8xx_io/cs4218_tdm.c b/arch/ppc/8xx_io/cs4218_tdm.c
index b7bb5f0..684ed04 100644
--- a/arch/ppc/8xx_io/cs4218_tdm.c
+++ b/arch/ppc/8xx_io/cs4218_tdm.c
@@ -1379,7 +1379,6 @@
 }
 
 static DEFINE_TIMER(beep_timer, cs_nosound, 0, 0);
-};
 
 static void cs_mksound(unsigned int hz, unsigned int ticks)
 {
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
index 8eb82ef..c22e606 100644
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -670,15 +670,6 @@
 config PAL4
 	bool "SBS-Palomar4"
 
-config GEMINI
-	bool "Synergy-Gemini"
-	depends on BROKEN
-	select PPC_INDIRECT_PCI
-	help
-	  Select Gemini if configuring for a Synergy Microsystems' Gemini
-	  series Single Board Computer.  More information is available at:
-	  <http://www.synergymicro.com/PressRel/97_10_15.html>.
-
 config EST8260
 	bool "EST8260"
 	---help---
diff --git a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile
index 28be01b..bcfb6cd 100644
--- a/arch/ppc/boot/simple/Makefile
+++ b/arch/ppc/boot/simple/Makefile
@@ -116,10 +116,6 @@
      extra.o-$(CONFIG_CHESTNUT)		:= misc-chestnut.o
          end-$(CONFIG_CHESTNUT)		:= chestnut
 
-      zimage-$(CONFIG_GEMINI)		:= zImage-STRIPELF
-zimageinitrd-$(CONFIG_GEMINI)		:= zImage.initrd-STRIPELF
-         end-$(CONFIG_GEMINI)		:= gemini
-
      extra.o-$(CONFIG_KATANA)		:= misc-katana.o
          end-$(CONFIG_KATANA)		:= katana
    cacheflag-$(CONFIG_KATANA)		:= -include $(clear_L2_L3)
diff --git a/arch/ppc/boot/simple/misc.c b/arch/ppc/boot/simple/misc.c
index a5df089..c3d3305 100644
--- a/arch/ppc/boot/simple/misc.c
+++ b/arch/ppc/boot/simple/misc.c
@@ -42,14 +42,11 @@
 #endif
 
 /* Will / Can the user give input?
- * Val Henson has requested that Gemini doesn't wait for the
- * user to edit the cmdline or not.
  */
 #if (defined(CONFIG_SERIAL_8250_CONSOLE) \
 	|| defined(CONFIG_VGA_CONSOLE) \
 	|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
-	|| defined(CONFIG_SERIAL_MPSC_CONSOLE)) \
-	&& !defined(CONFIG_GEMINI)
+	|| defined(CONFIG_SERIAL_MPSC_CONSOLE))
 #define INTERACTIVE_CONSOLE	1
 #endif
 
@@ -178,16 +175,6 @@
 
 	if (keyb_present)
 		CRT_tstc();  /* Forces keyboard to be initialized */
-#ifdef CONFIG_GEMINI
-	/*
-	 * If cmd_line is empty and cmd_preset is not, copy cmd_preset
-	 * to cmd_line.  This way we can override cmd_preset with the
-	 * command line from Smon.
-	 */
-
-	if ( (cmd_line[0] == '\0') && (cmd_preset[0] != '\0'))
-		memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
-#endif
 
 	/* Display standard Linux/PPC boot prompt for kernel args */
 	puts("\nLinux/PPC load: ");
diff --git a/arch/ppc/configs/gemini_defconfig b/arch/ppc/configs/gemini_defconfig
deleted file mode 100644
index ebcd17b..0000000
--- a/arch/ppc/configs/gemini_defconfig
+++ /dev/null
@@ -1,618 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_EMBEDDED is not set
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_6xx=y
-# CONFIG_40x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_8xx is not set
-
-#
-# IBM 4xx options
-#
-# CONFIG_8260 is not set
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_PPC_STD_MMU=y
-# CONFIG_PPC_MULTIPLATFORM is not set
-# CONFIG_APUS is not set
-# CONFIG_WILLOW_2 is not set
-# CONFIG_PCORE is not set
-# CONFIG_POWERPMC250 is not set
-# CONFIG_EV64260 is not set
-# CONFIG_SPRUCE is not set
-# CONFIG_LOPEC is not set
-# CONFIG_MCPN765 is not set
-# CONFIG_MVME5100 is not set
-# CONFIG_PPLUS is not set
-# CONFIG_PRPMC750 is not set
-# CONFIG_PRPMC800 is not set
-# CONFIG_SANDPOINT is not set
-# CONFIG_ADIR is not set
-# CONFIG_K2 is not set
-# CONFIG_PAL4 is not set
-CONFIG_GEMINI=y
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-CONFIG_ALTIVEC=y
-CONFIG_TAU=y
-# CONFIG_TAU_INT is not set
-# CONFIG_TAU_AVERAGE is not set
-# CONFIG_CPU_FREQ is not set
-
-#
-# General setup
-#
-# CONFIG_HIGHMEM is not set
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-# CONFIG_PPC601_SYNC_FIX is not set
-# CONFIG_CMDLINE_BOOL is not set
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00800000
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_REPORT_LUNS is not set
-CONFIG_SCSI_CONSTANTS=y
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-CONFIG_SCSI_SYM53C8XX_2=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
-CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-
-#
-# IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_ARPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_XFRM_USER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
-# CONFIG_OAKNET is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_PCI is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices (depends on LLC=y)
-#
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Macintosh device drivers
-#
-
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-CONFIG_NFSD=y
-# CONFIG_NFSD_V3 is not set
-# CONFIG_NFSD_TCP is not set
-CONFIG_LOCKD=y
-CONFIG_EXPORTFS=y
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-CONFIG_SOLARIS_X86_PARTITION=y
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index 466437f..6b4f022 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -12,7 +12,6 @@
 					setup.o \
 					ppc_htab.o
 obj-$(CONFIG_MODULES)		+= ppc_ksyms.o
-obj-$(CONFIG_NOT_COHERENT_CACHE)	+= dma-mapping.o
 obj-$(CONFIG_PCI)		+= pci.o
 obj-$(CONFIG_RAPIDIO)		+= rio.o
 obj-$(CONFIG_KGDB)		+= ppc-stub.o
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index 100052a..c7cb9d5 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -310,12 +310,7 @@
 /* System reset */
 /* core99 pmac starts the seconary here by changing the vector, and
    putting it back to what it was (unknown_exception) when done.  */
-#if defined(CONFIG_GEMINI) && defined(CONFIG_SMP)
-	. = 0x100
-	b	__secondary_start_gemini
-#else
 	EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD)
-#endif
 
 /* Machine check */
 	. = 0x200
@@ -897,19 +892,6 @@
 #endif /* CONFIG_APUS */
 
 #ifdef CONFIG_SMP
-#ifdef CONFIG_GEMINI
-	.globl	__secondary_start_gemini
-__secondary_start_gemini:
-        mfspr   r4,SPRN_HID0
-        ori     r4,r4,HID0_ICFI
-        li      r3,0
-        ori     r3,r3,HID0_ICE
-        andc    r4,r4,r3
-        mtspr   SPRN_HID0,r4
-        sync
-        b       __secondary_start
-#endif /* CONFIG_GEMINI */
-
 	.globl	__secondary_start_pmac_0
 __secondary_start_pmac_0:
 	/* NB the entries for cpus 0, 1, 2 must each occupy 8 bytes. */
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index c8b65ca..1f49503 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -43,6 +43,7 @@
 #include <asm/div64.h>
 #include <asm/xmon.h>
 #include <asm/signal.h>
+#include <asm/dcr.h>
 
 #ifdef  CONFIG_8xx
 #include <asm/commproc.h>
diff --git a/arch/ppc/lib/rheap.c b/arch/ppc/lib/rheap.c
index 31e5118..d407007 100644
--- a/arch/ppc/lib/rheap.c
+++ b/arch/ppc/lib/rheap.c
@@ -14,6 +14,7 @@
  */
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 
@@ -654,7 +655,7 @@
 	int maxnr;
 	int i, nr;
 
-	maxnr = sizeof(st) / sizeof(st[0]);
+	maxnr = ARRAY_SIZE(st);
 
 	printk(KERN_INFO
 	       "info @0x%p (%d slots empty / %d max)\n",
diff --git a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c
index 354a940..82b06a1 100644
--- a/arch/ppc/mm/pgtable.c
+++ b/arch/ppc/mm/pgtable.c
@@ -313,11 +313,8 @@
 	}
 }
 
-/* is x a power of 2? */
-#define is_power_of_2(x)	((x) != 0 && (((x) & ((x) - 1)) == 0))
-
 /* is x a power of 4? */
-#define is_power_of_4(x)	((x) != 0 && (((x) & (x-1)) == 0) && (ffs(x) & 1))
+#define is_power_of_4(x)	is_power_of_2(x) && (ffs(x) & 1))
 
 /*
  * Set up a mapping for a block of I/O.
diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile
index 90c6222..e17fad4 100644
--- a/arch/ppc/platforms/Makefile
+++ b/arch/ppc/platforms/Makefile
@@ -13,7 +13,6 @@
 obj-$(CONFIG_CPCI690)		+= cpci690.o
 obj-$(CONFIG_EV64260)		+= ev64260.o
 obj-$(CONFIG_CHESTNUT)		+= chestnut.o
-obj-$(CONFIG_GEMINI)		+= gemini_pci.o gemini_setup.o gemini_prom.o
 obj-$(CONFIG_LOPEC)		+= lopec.o
 obj-$(CONFIG_KATANA)		+= katana.o
 obj-$(CONFIG_HDPU)		+= hdpu.o
diff --git a/arch/ppc/platforms/gemini.h b/arch/ppc/platforms/gemini.h
deleted file mode 100644
index 5528fd0..0000000
--- a/arch/ppc/platforms/gemini.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- *  Onboard registers and descriptions for Synergy Microsystems'
- *  "Gemini" boards.
- *
- */
-#ifdef __KERNEL__
-#ifndef __PPC_GEMINI_H
-#define __PPC_GEMINI_H
-
-/*  Registers  */
-
-#define GEMINI_SERIAL_B     (0xffeffb00)
-#define GEMINI_SERIAL_A     (0xffeffb08)
-#define GEMINI_USWITCH      (0xffeffd00)
-#define GEMINI_BREV         (0xffeffe00)
-#define GEMINI_BECO         (0xffeffe08)
-#define GEMINI_FEAT         (0xffeffe10)
-#define GEMINI_BSTAT        (0xffeffe18)
-#define GEMINI_CPUSTAT      (0xffeffe20)
-#define GEMINI_L2CFG        (0xffeffe30)
-#define GEMINI_MEMCFG       (0xffeffe38)
-#define GEMINI_FLROM        (0xffeffe40)
-#define GEMINI_P0PCI        (0xffeffe48)
-#define GEMINI_FLWIN        (0xffeffe50)
-#define GEMINI_P0INTMASK    (0xffeffe60)
-#define GEMINI_P0INTAP      (0xffeffe68)
-#define GEMINI_PCIERR       (0xffeffe70)
-#define GEMINI_LEDBASE      (0xffeffe80)
-#define GEMINI_RTC          (0xffe9fff8)
-#define GEMINI_LEDS         8
-#define GEMINI_SWITCHES     8
-
-
-/* Flash ROM bit definitions */
-#define GEMINI_FLS_WEN      (1<<0)
-#define GEMINI_FLS_JMP      (1<<6)
-#define GEMINI_FLS_BOOT     (1<<7)
-
-/* Memory bit definitions */
-#define GEMINI_MEM_TYPE_MASK 0xc0
-#define GEMINI_MEM_SIZE_MASK 0x38
-#define GEMINI_MEM_BANK_MASK 0x07
-
-/* L2 cache bit definitions */
-#define GEMINI_L2_SIZE_MASK  0xc0
-#define GEMINI_L2_RATIO_MASK 0x03
-
-/* Timebase register bit definitons */
-#define GEMINI_TIMEB0_EN     (1<<0)
-#define GEMINI_TIMEB1_EN     (1<<1)
-#define GEMINI_TIMEB2_EN     (1<<2)
-#define GEMINI_TIMEB3_EN     (1<<3)
-
-/* CPU status bit definitions */
-#define GEMINI_CPU_ID_MASK   0x03
-#define GEMINI_CPU_COUNT_MASK 0x0c
-#define GEMINI_CPU0_HALTED   (1<<4)
-#define GEMINI_CPU1_HALTED   (1<<5)
-#define GEMINI_CPU2_HALTED   (1<<6)
-#define GEMINI_CPU3_HALTED   (1<<7)
-
-/* Board status bit definitions */
-#define GEMINI_BRD_FAIL      (1<<0)   /* FAIL led is lit */
-#define GEMINI_BRD_BUS_MASK  0x0c     /* PowerPC bus speed */
-
-/* Board family/feature bit descriptions */
-#define GEMINI_FEAT_HAS_FLASH (1<<0)
-#define GEMINI_FEAT_HAS_ETH   (1<<1)
-#define GEMINI_FEAT_HAS_SCSI  (1<<2)
-#define GEMINI_FEAT_HAS_P0    (1<<3)
-#define GEMINI_FEAT_FAM_MASK  0xf0
-
-/* Mod/ECO bit definitions */
-#define GEMINI_ECO_LEVEL_MASK 0x0f
-#define GEMINI_MOD_MASK       0xf0
-
-/* Type/revision bit definitions */
-#define GEMINI_REV_MASK       0x0f
-#define GEMINI_TYPE_MASK      0xf0
-
-/* User switch definitions */
-#define GEMINI_SWITCH_VERBOSE    1     /* adds "debug" to boot cmd line */
-#define GEMINI_SWITCH_SINGLE_USER 7    /* boots into "single-user" mode */
-
-#define SGS_RTC_CONTROL  0
-#define SGS_RTC_SECONDS  1
-#define SGS_RTC_MINUTES  2
-#define SGS_RTC_HOURS    3
-#define SGS_RTC_DAY      4
-#define SGS_RTC_DAY_OF_MONTH 5
-#define SGS_RTC_MONTH    6
-#define SGS_RTC_YEAR     7
-
-#define SGS_RTC_SET  0x80
-#define SGS_RTC_IS_STOPPED 0x80
-
-#define GRACKLE_CONFIG_ADDR_ADDR  (0xfec00000)
-#define GRACKLE_CONFIG_DATA_ADDR  (0xfee00000)
-
-#define GEMINI_BOOT_INIT  (0xfff00100)
-
-#ifndef __ASSEMBLY__
-
-static inline void grackle_write( unsigned long addr, unsigned long data )
-{
-  __asm__ __volatile__(
-  " stwbrx %1, 0, %0\n \
-    sync\n \
-    stwbrx %3, 0, %2\n \
-    sync "
-  : /* no output */
-  : "r" (GRACKLE_CONFIG_ADDR_ADDR), "r" (addr),
-    "r" (GRACKLE_CONFIG_DATA_ADDR), "r" (data));
-}
-
-static inline unsigned long grackle_read( unsigned long addr )
-{
-  unsigned long val;
-
-  __asm__ __volatile__(
-  " stwbrx %1, 0, %2\n \
-    sync\n \
-    lwbrx %0, 0, %3\n \
-    sync "
-  : "=r" (val)
-  : "r" (addr), "r" (GRACKLE_CONFIG_ADDR_ADDR),
-    "r" (GRACKLE_CONFIG_DATA_ADDR));
-
-  return val;
-}
-
-static inline void gemini_led_on( int led )
-{
-  if (led >= 0 && led < GEMINI_LEDS)
-    *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 1;
-}
-
-static inline void gemini_led_off(int led)
-{
-  if (led >= 0 && led < GEMINI_LEDS)
-    *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 0;
-}
-
-static inline int gemini_led_val(int led)
-{
-  int val = 0;
-  if (led >= 0 && led < GEMINI_LEDS)
-    val = *(unsigned char *)(GEMINI_LEDBASE + (led<<3));
-  return (val & 0x1);
-}
-
-/* returns processor id from the board */
-static inline int gemini_processor(void)
-{
-  unsigned char cpu = *(unsigned char *)(GEMINI_CPUSTAT);
-  return (int) ((cpu == 0) ? 4 : (cpu & GEMINI_CPU_ID_MASK));
-}
-
-
-extern void _gemini_reboot(void);
-extern void gemini_prom_init(void);
-extern void gemini_init_l2(void);
-#endif /* __ASSEMBLY__ */
-#endif
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/gemini_pci.c b/arch/ppc/platforms/gemini_pci.c
deleted file mode 100644
index 9565609..0000000
--- a/arch/ppc/platforms/gemini_pci.c
+++ /dev/null
@@ -1,41 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include <asm/machdep.h>
-#include <platforms/gemini.h>
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/pci-bridge.h>
-
-void __init gemini_pcibios_fixup(void)
-{
-	int i;
-	struct pci_dev *dev = NULL;
-	
-	for_each_pci_dev(dev) {
-		for(i = 0; i < 6; i++) {
-			if (dev->resource[i].flags & IORESOURCE_IO) {
-				dev->resource[i].start |= (0xfe << 24);
-				dev->resource[i].end |= (0xfe << 24);
-			}
-		}
-	}
-}
-
-
-/* The "bootloader" for Synergy boards does none of this for us, so we need to
-   lay it all out ourselves... --Dan */
-void __init gemini_find_bridges(void)
-{
-	struct pci_controller* hose;
-	
-	ppc_md.pcibios_fixup = gemini_pcibios_fixup;
-
-	hose = pcibios_alloc_controller();
-	if (!hose)
-		return;
-	setup_indirect_pci(hose, 0xfec00000, 0xfee00000);
-}
diff --git a/arch/ppc/platforms/gemini_prom.S b/arch/ppc/platforms/gemini_prom.S
deleted file mode 100644
index e8c84d2..0000000
--- a/arch/ppc/platforms/gemini_prom.S
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- *  Not really prom support code (yet), but sort of anti-prom code.  The current
- *  bootloader does a number of things it shouldn't and doesn't do things that it
- *  should.  The stuff in here is mainly a hodge-podge collection of setup code
- *  to get the board up and running.
- *    ---Dan
- */
-
-#include <asm/reg.h>
-#include <asm/page.h>
-#include <platforms/gemini.h>
-#include <asm/ppc_asm.h>
-
-/*
- *  On 750's the MMU is on when Linux is booted, so we need to clear out the
- *  bootloader's BAT settings, make sure we're in supervisor state (gotcha!),
- *  and turn off the MMU.
- *
- */
-
-_GLOBAL(gemini_prom_init)
-#ifdef CONFIG_SMP
-	/* Since the MMU's on, get stuff in rom space that we'll need */
-	lis	r4,GEMINI_CPUSTAT@h
-	ori	r4,r4,GEMINI_CPUSTAT@l
-	lbz	r5,0(r4)
-	andi.	r5,r5,3
-	mr	r24,r5		/* cpu # used later on */
-#endif
-	mfmsr	r4
-	li	r3,MSR_PR	/* ensure supervisor! */
-	ori	r3,r3,MSR_IR|MSR_DR
-	andc	r4,r4,r3
-	mtmsr	r4
-	isync
-#if 0
-	/* zero out the bats now that the MMU is off */
-prom_no_mmu:	
-	li	r3,0
-        mtspr   SPRN_IBAT0U,r3
-        mtspr   SPRN_IBAT0L,r3
-        mtspr   SPRN_IBAT1U,r3
-        mtspr   SPRN_IBAT1L,r3
-        mtspr   SPRN_IBAT2U,r3
-        mtspr   SPRN_IBAT2L,r3
-        mtspr   SPRN_IBAT3U,r3
-        mtspr   SPRN_IBAT3L,r3
-
-        mtspr   SPRN_DBAT0U,r3
-        mtspr   SPRN_DBAT0L,r3
-        mtspr   SPRN_DBAT1U,r3
-        mtspr   SPRN_DBAT1L,r3
-        mtspr   SPRN_DBAT2U,r3
-	mtspr   SPRN_DBAT2L,r3
-        mtspr   SPRN_DBAT3U,r3
-        mtspr   SPRN_DBAT3L,r3
-#endif
-
-	/* the bootloader (as far as I'm currently aware) doesn't mess with page
-	   tables, but since we're already here, might as well zap these, too */
-	li	r4,0
-	mtspr	SPRN_SDR1,r4
-
-	li	r4,16
-	mtctr	r4
-	li	r3,0
-	li	r4,0
-3:	mtsrin	r3,r4
-	addi	r3,r3,1
-	bdnz	3b
-
-#ifdef CONFIG_SMP
-	/* The 750 book (and Mot/IBM support) says that this will "assist" snooping
-	   when in SMP.  Not sure yet whether this should stay or leave... */
-	mfspr	r4,SPRN_HID0
-	ori	r4,r4,HID0_ABE
-	mtspr	SPRN_HID0,r4
-	sync
-#endif /* CONFIG_SMP */
-	blr
-
-/*  apparently, SMon doesn't pay attention to HID0[SRST].  Disable the MMU and
-    branch to 0xfff00100 */
-_GLOBAL(_gemini_reboot)
-	lis	r5,GEMINI_BOOT_INIT@h
-	ori	r5,r5,GEMINI_BOOT_INIT@l
-	li	r6,MSR_IP
-	mtspr	SPRN_SRR0,r5
-	mtspr	SPRN_SRR1,r6
-	rfi
diff --git a/arch/ppc/platforms/gemini_serial.h b/arch/ppc/platforms/gemini_serial.h
deleted file mode 100644
index b915eff..0000000
--- a/arch/ppc/platforms/gemini_serial.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifdef __KERNEL__
-#ifndef __ASMPPC_GEMINI_SERIAL_H
-#define __ASMPPC_GEMINI_SERIAL_H
-
-#include <platforms/gemini.h>
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define RS_TABLE_SIZE  64
-#else
-#define RS_TABLE_SIZE  4
-#endif
-
-/* Rate for the 24.576 Mhz clock for the onboard serial chip */
-#define BASE_BAUD  (24576000 / 16)
-
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF)
-#endif
-
-#define STD_SERIAL_PORT_DEFNS \
-        { 0, BASE_BAUD, GEMINI_SERIAL_A, 15, STD_COM_FLAGS }, /* ttyS0 */ \
-        { 0, BASE_BAUD, GEMINI_SERIAL_B, 14, STD_COM_FLAGS }, /* ttyS1 */ \
-
-#ifdef CONFIG_GEMINI_PU32
-#define PU32_SERIAL_PORT_DEFNS \
-        { 0, BASE_BAUD, NULL, 0, STD_COM_FLAGS },
-#else
-#define PU32_SERIAL_PORT_DEFNS
-#endif
-
-#define SERIAL_PORT_DFNS \
-        STD_SERIAL_PORT_DEFNS \
-        PU32_SERIAL_PORT_DEFNS
-
-#endif
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/gemini_setup.c b/arch/ppc/platforms/gemini_setup.c
deleted file mode 100644
index f48048f..0000000
--- a/arch/ppc/platforms/gemini_setup.c
+++ /dev/null
@@ -1,577 +0,0 @@
-/*
- *  Copyright (C) 1995 Linus Torvalds
- *  Adapted from 'alpha' version by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu)
- *  Synergy Microsystems board support by Dan Cox (dan@synergymicro.com)
- *
- */
-
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/reboot.h>
-#include <linux/pci.h>
-#include <linux/time.h>
-#include <linux/kdev_t.h>
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/initrd.h>
-#include <linux/console.h>
-#include <linux/seq_file.h>
-#include <linux/root_dev.h>
-#include <linux/bcd.h>
-
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/m48t35.h>
-#include <platforms/gemini.h>
-#include <asm/time.h>
-#include <asm/open_pic.h>
-#include <asm/bootinfo.h>
-#include <asm/machdep.h>
-
-void gemini_find_bridges(void);
-static int gemini_get_clock_speed(void);
-extern void gemini_pcibios_fixup(void);
-
-static char *gemini_board_families[] = {
-  "VGM", "VSS", "KGM", "VGR", "VCM", "VCS", "KCM", "VCR"
-};
-static int gemini_board_count = sizeof(gemini_board_families) /
-                                 sizeof(gemini_board_families[0]);
-
-static unsigned int cpu_7xx[16] = {
-	0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0
-};
-static unsigned int cpu_6xx[16] = {
-	0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0
-};
-
-/*
- * prom_init is the Gemini version of prom.c:prom_init.  We only need
- * the BSS clearing code, so I copied that out of prom.c.  This is a
- * lot simpler than hacking prom.c so it will build with Gemini. -VAL
- */
-
-#define PTRRELOC(x)	((typeof(x))((unsigned long)(x) + offset))
-
-unsigned long
-prom_init(void)
-{
-	unsigned long offset = reloc_offset();
-	unsigned long phys;
-	extern char __bss_start, _end;
-
-	/* First zero the BSS -- use memset, some arches don't have
-	 * caches on yet */
-	memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start);
-
- 	/* Default */
- 	phys = offset + KERNELBASE;
-
-	gemini_prom_init();
-
-	return phys;
-}
-
-int
-gemini_show_cpuinfo(struct seq_file *m)
-{
-	unsigned char reg, rev;
-	char *family;
-	unsigned int type;
-
-	reg = readb(GEMINI_FEAT);
-	family = gemini_board_families[((reg>>4) & 0xf)];
-	if (((reg>>4) & 0xf) > gemini_board_count)
-		printk(KERN_ERR "cpuinfo(): unable to determine board family\n");
-
-	reg = readb(GEMINI_BREV);
-	type = (reg>>4) & 0xf;
-	rev = reg & 0xf;
-
-	reg = readb(GEMINI_BECO);
-
-	seq_printf(m, "machine\t\t: Gemini %s%d, rev %c, eco %d\n",
-		   family, type, (rev + 'A'), (reg & 0xf));
-
-	seq_printf(m, "board\t\t: Gemini %s", family);
-	if (type > 9)
-		seq_printf(m, "%c", (type - 10) + 'A');
-	else
-		seq_printf(m, "%d", type);
-
-	seq_printf(m, ", rev %c, eco %d\n", (rev + 'A'), (reg & 0xf));
-
-	seq_printf(m, "clock\t\t: %dMhz\n", gemini_get_clock_speed());
-
-	return 0;
-}
-
-static u_char gemini_openpic_initsenses[] = {
-	1,
-	1,
-	1,
-	1,
-	0,
-	0,
-	1, /* remainder are level-triggered */
-};
-
-#define GEMINI_MPIC_ADDR (0xfcfc0000)
-#define GEMINI_MPIC_PCI_CFG (0x80005800)
-
-void __init gemini_openpic_init(void)
-{
-
-	OpenPIC_Addr = (volatile struct OpenPIC *)
-		grackle_read(GEMINI_MPIC_PCI_CFG + 0x10);
-	OpenPIC_InitSenses = gemini_openpic_initsenses;
-	OpenPIC_NumInitSenses = sizeof( gemini_openpic_initsenses );
-
-	ioremap( GEMINI_MPIC_ADDR, OPENPIC_SIZE);
-}
-
-
-extern unsigned long loops_per_jiffy;
-extern int root_mountflags;
-extern char cmd_line[];
-
-void
-gemini_heartbeat(void)
-{
-	static unsigned long led = GEMINI_LEDBASE+(4*8);
-	static char direction = 8;
-
-
-	/* We only want to do this on 1 CPU */
-	if (smp_processor_id())
-		return;
-	*(char *)led = 0;
-	if ( (led + direction) > (GEMINI_LEDBASE+(7*8)) ||
-	     (led + direction) < (GEMINI_LEDBASE+(4*8)) )
-		direction *= -1;
-	led += direction;
-	*(char *)led = 0xff;
-	ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
-}
-
-void __init gemini_setup_arch(void)
-{
-	extern char cmd_line[];
-
-
-	loops_per_jiffy = 50000000/HZ;
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	/* bootable off CDROM */
-	if (initrd_start)
-		ROOT_DEV = Root_SR0;
-	else
-#endif
-		ROOT_DEV = Root_SDA1;
-
-	/* nothing but serial consoles... */
-	sprintf(cmd_line, "%s console=ttyS0", cmd_line);
-
-	printk("Boot arguments: %s\n", cmd_line);
-
-	ppc_md.heartbeat = gemini_heartbeat;
-	ppc_md.heartbeat_reset = HZ/8;
-	ppc_md.heartbeat_count = 1;
-
-	/* Lookup PCI hosts */
-	gemini_find_bridges();
-	/* take special pains to map the MPIC, since it isn't mapped yet */
-	gemini_openpic_init();
-	/* start the L2 */
-	gemini_init_l2();
-}
-
-
-int
-gemini_get_clock_speed(void)
-{
-	unsigned long hid1, pvr;
-	int clock;
-
-	pvr = mfspr(SPRN_PVR);
-	hid1 = (mfspr(SPRN_HID1) >> 28) & 0xf;
-	if (PVR_VER(pvr) == 8 ||
-	    PVR_VER(pvr) == 12)
-		hid1 = cpu_7xx[hid1];
-	else
-		hid1 = cpu_6xx[hid1];
-
-	switch((readb(GEMINI_BSTAT) & 0xc) >> 2) {
-
-	case 0:
-	default:
-		clock = (hid1*100)/3;
-		break;
-
-	case 1:
-		clock = (hid1*125)/3;
-		break;
-
-	case 2:
-		clock = (hid1*50);
-		break;
-	}
-
-	return clock;
-}
-
-void __init gemini_init_l2(void)
-{
-        unsigned char reg, brev, fam, creg;
-        unsigned long cache;
-        unsigned long pvr;
-
-        reg = readb(GEMINI_L2CFG);
-        brev = readb(GEMINI_BREV);
-        fam = readb(GEMINI_FEAT);
-        pvr = mfspr(SPRN_PVR);
-
-        switch(PVR_VER(pvr)) {
-
-        case 8:
-                if (reg & 0xc0)
-                        cache = (((reg >> 6) & 0x3) << 28);
-                else
-                        cache = 0x3 << 28;
-
-#ifdef CONFIG_SMP
-                /* Pre-3.0 processor revs had snooping errata.  Leave
-                   their L2's disabled with SMP. -- Dan */
-                if (PVR_CFG(pvr) < 3) {
-                        printk("Pre-3.0 750; L2 left disabled!\n");
-                        return;
-                }
-#endif /* CONFIG_SMP */
-
-                /* Special case: VGM5-B's came before L2 ratios were set on
-                   the board.  Processor speed shouldn't be too high, so
-                   set L2 ratio to 1:1.5.  */
-                if ((brev == 0x51) && ((fam & 0xa0) >> 4) == 0)
-                        reg |= 1;
-
-                /* determine best cache ratio based upon what the board
-                   tells us (which sometimes _may_ not be true) and
-                   the processor speed. */
-                else {
-                        if (gemini_get_clock_speed() > 250)
-                                reg = 2;
-                }
-                break;
-        case 12:
-	{
-		static unsigned long l2_size_val = 0;
-
-		if (!l2_size_val)
-			l2_size_val = _get_L2CR();
-		cache = l2_size_val;
-                break;
-	}
-        case 4:
-        case 9:
-                creg = readb(GEMINI_CPUSTAT);
-                if (((creg & 0xc) >> 2) != 1)
-                        printk("Dual-604 boards don't support the use of L2\n");
-                else
-                        writeb(1, GEMINI_L2CFG);
-                return;
-        default:
-                printk("Unknown processor; L2 left disabled\n");
-                return;
-        }
-
-        cache |= ((1<<reg) << 25);
-        cache |= (L2CR_L2RAM_MASK|L2CR_L2CTL|L2CR_L2DO);
-        _set_L2CR(0);
-        _set_L2CR(cache | L2CR_L2E);
-
-}
-
-void
-gemini_restart(char *cmd)
-{
-	local_irq_disable();
-	/* make a clean restart, not via the MPIC */
-	_gemini_reboot();
-	for(;;);
-}
-
-void
-gemini_power_off(void)
-{
-	for(;;);
-}
-
-void
-gemini_halt(void)
-{
-	gemini_restart(NULL);
-}
-
-void __init gemini_init_IRQ(void)
-{
-	/* gemini has no 8259 */
-	openpic_init(1, 0, 0, -1);
-}
-
-#define gemini_rtc_read(x)       (readb(GEMINI_RTC+(x)))
-#define gemini_rtc_write(val,x)  (writeb((val),(GEMINI_RTC+(x))))
-
-/* ensure that the RTC is up and running */
-long __init gemini_time_init(void)
-{
-	unsigned char reg;
-
-	reg = gemini_rtc_read(M48T35_RTC_CONTROL);
-
-	if ( reg & M48T35_RTC_STOPPED ) {
-		printk(KERN_INFO "M48T35 real-time-clock was stopped. Now starting...\n");
-		gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL);
-		gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL);
-	}
-	return 0;
-}
-
-#undef DEBUG_RTC
-
-unsigned long
-gemini_get_rtc_time(void)
-{
-	unsigned int year, mon, day, hour, min, sec;
-	unsigned char reg;
-
-	reg = gemini_rtc_read(M48T35_RTC_CONTROL);
-	gemini_rtc_write((reg|M48T35_RTC_READ), M48T35_RTC_CONTROL);
-#ifdef DEBUG_RTC
-	printk("get rtc: reg = %x\n", reg);
-#endif
-
-	do {
-		sec = gemini_rtc_read(M48T35_RTC_SECONDS);
-		min = gemini_rtc_read(M48T35_RTC_MINUTES);
-		hour = gemini_rtc_read(M48T35_RTC_HOURS);
-		day = gemini_rtc_read(M48T35_RTC_DOM);
-		mon = gemini_rtc_read(M48T35_RTC_MONTH);
-		year = gemini_rtc_read(M48T35_RTC_YEAR);
-	} while( sec != gemini_rtc_read(M48T35_RTC_SECONDS));
-#ifdef DEBUG_RTC
-	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n",
-	       sec, min, hour, day, mon, year);
-#endif
-
-	gemini_rtc_write(reg, M48T35_RTC_CONTROL);
-
-	BCD_TO_BIN(sec);
-	BCD_TO_BIN(min);
-	BCD_TO_BIN(hour);
-	BCD_TO_BIN(day);
-	BCD_TO_BIN(mon);
-	BCD_TO_BIN(year);
-
-	if ((year += 1900) < 1970)
-		year += 100;
-#ifdef DEBUG_RTC
-	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n",
-	       sec, min, hour, day, mon, year);
-#endif
-
-	return mktime( year, mon, day, hour, min, sec );
-}
-
-
-int
-gemini_set_rtc_time( unsigned long now )
-{
-	unsigned char reg;
-	struct rtc_time tm;
-
-	to_tm( now, &tm );
-
-	reg = gemini_rtc_read(M48T35_RTC_CONTROL);
-#ifdef DEBUG_RTC
-	printk("set rtc: reg = %x\n", reg);
-#endif
-
-	gemini_rtc_write((reg|M48T35_RTC_SET), M48T35_RTC_CONTROL);
-#ifdef DEBUG_RTC
-	printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n",
-	       tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year);
-#endif
-
-	tm.tm_year -= 1900;
-	BIN_TO_BCD(tm.tm_sec);
-	BIN_TO_BCD(tm.tm_min);
-	BIN_TO_BCD(tm.tm_hour);
-	BIN_TO_BCD(tm.tm_mon);
-	BIN_TO_BCD(tm.tm_mday);
-	BIN_TO_BCD(tm.tm_year);
-#ifdef DEBUG_RTC
-	printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n",
-	       tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year);
-#endif
-
-	gemini_rtc_write(tm.tm_sec, M48T35_RTC_SECONDS);
-	gemini_rtc_write(tm.tm_min, M48T35_RTC_MINUTES);
-	gemini_rtc_write(tm.tm_hour, M48T35_RTC_HOURS);
-	gemini_rtc_write(tm.tm_mday, M48T35_RTC_DOM);
-	gemini_rtc_write(tm.tm_mon, M48T35_RTC_MONTH);
-	gemini_rtc_write(tm.tm_year, M48T35_RTC_YEAR);
-
-	/* done writing */
-	gemini_rtc_write(reg, M48T35_RTC_CONTROL);
-
-	return 0;
-}
-
-/*  use the RTC to determine the decrementer count */
-void __init gemini_calibrate_decr(void)
-{
-	int freq, divisor;
-	unsigned char reg;
-
-	/* determine processor bus speed */
-	reg = readb(GEMINI_BSTAT);
-
-	switch(((reg & 0x0c)>>2)&0x3) {
-	case 0:
-	default:
-		freq = 66667;
-		break;
-	case 1:
-		freq = 83000;
-		break;
-	case 2:
-		freq = 100000;
-		break;
-	}
-
-	freq *= 1000;
-	divisor = 4;
-	tb_ticks_per_jiffy = freq / HZ / divisor;
-	tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
-}
-
-unsigned long __init gemini_find_end_of_memory(void)
-{
-	unsigned long total;
-	unsigned char reg;
-
-	reg = readb(GEMINI_MEMCFG);
-	total = ((1<<((reg & 0x7) - 1)) *
-		 (8<<((reg >> 3) & 0x7)));
-	total *= (1024*1024);
-	return total;
-}
-
-static void __init
-gemini_map_io(void)
-{
-	io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
-	io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO);
-}
-
-#ifdef CONFIG_SMP
-static int
-smp_gemini_probe(void)
-{
-	int i, nr;
-
-        nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK) >> 2;
-	if (nr == 0)
-		nr = 4;
-
-	if (nr > 1) {
-		openpic_request_IPIs();
-		for (i = 1; i < nr; ++i)
-			smp_hw_index[i] = i;
-	}
-
-	return nr;
-}
-
-static void
-smp_gemini_kick_cpu(int nr)
-{
-	openpic_reset_processor_phys(1 << nr);
-	openpic_reset_processor_phys(0);
-}
-
-static void
-smp_gemini_setup_cpu(int cpu_nr)
-{
-	if (OpenPIC_Addr)
-		do_openpic_setup_cpu();
-	if (cpu_nr > 0)
-		gemini_init_l2();
-}
-
-static struct smp_ops_t gemini_smp_ops = {
-	smp_openpic_message_pass,
-	smp_gemini_probe,
-	smp_gemini_kick_cpu,
-	smp_gemini_setup_cpu,
-	.give_timebase = smp_generic_give_timebase,
-	.take_timebase = smp_generic_take_timebase,
-};
-#endif /* CONFIG_SMP */
-
-void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
-			  unsigned long r6, unsigned long r7)
-{
-	int i;
-
-	/* Restore BATs for now */
-	mtspr(SPRN_DBAT3U, 0xf0001fff);
-	mtspr(SPRN_DBAT3L, 0xf000002a);
-
-	parse_bootinfo(find_bootinfo());
-
-	for(i = 0; i < GEMINI_LEDS; i++)
-		gemini_led_off(i);
-
-	ISA_DMA_THRESHOLD = 0;
-	DMA_MODE_READ = 0;
-	DMA_MODE_WRITE = 0;
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	if ( r4 )
-	{
-		initrd_start = r4 + KERNELBASE;
-		initrd_end = r5 + KERNELBASE;
-	}
-#endif
-
-	ppc_md.setup_arch = gemini_setup_arch;
-	ppc_md.show_cpuinfo = gemini_show_cpuinfo;
-	ppc_md.init_IRQ = gemini_init_IRQ;
-	ppc_md.get_irq = openpic_get_irq;
-	ppc_md.init = NULL;
-
-	ppc_md.restart = gemini_restart;
-	ppc_md.power_off = gemini_power_off;
-	ppc_md.halt = gemini_halt;
-
-	ppc_md.time_init = gemini_time_init;
-	ppc_md.set_rtc_time = gemini_set_rtc_time;
-	ppc_md.get_rtc_time = gemini_get_rtc_time;
-	ppc_md.calibrate_decr = gemini_calibrate_decr;
-
-	ppc_md.find_end_of_memory = gemini_find_end_of_memory;
-	ppc_md.setup_io_mappings = gemini_map_io;
-
-	ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup;
-
-#ifdef CONFIG_SMP
-	smp_ops = &gemini_smp_ops;
-#endif /* CONFIG_SMP */
-}
diff --git a/arch/ppc/platforms/mpc866ads_setup.c b/arch/ppc/platforms/mpc866ads_setup.c
index 8a0c07e..5b05d4b 100644
--- a/arch/ppc/platforms/mpc866ads_setup.c
+++ b/arch/ppc/platforms/mpc866ads_setup.c
@@ -369,7 +369,7 @@
 	ppc_sys_device_setfunc(MPC8xx_CPM_SMC1, PPC_SYS_FUNC_UART);
 #endif
 
-#ifdef CONFIG_SERIAL_CPM_SMC
+#ifdef CONFIG_SERIAL_CPM_SMC2
 	ppc_sys_device_enable(MPC8xx_CPM_SMC2);
 	ppc_sys_device_setfunc(MPC8xx_CPM_SMC2, PPC_SYS_FUNC_UART);
 #endif
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
index dca23f2..d84f0466 100644
--- a/arch/ppc/syslib/Makefile
+++ b/arch/ppc/syslib/Makefile
@@ -45,7 +45,6 @@
 obj-$(CONFIG_EV64260)		+= todc_time.o pci_auto.o
 obj-$(CONFIG_EV64360)		+= todc_time.o
 obj-$(CONFIG_CHESTNUT)		+= mv64360_pic.o pci_auto.o
-obj-$(CONFIG_GEMINI)		+= open_pic.o
 obj-$(CONFIG_GT64260)		+= gt64260_pic.o
 obj-$(CONFIG_LOPEC)		+= pci_auto.o todc_time.o
 obj-$(CONFIG_HDPU)		+= pci_auto.o
diff --git a/arch/ppc/syslib/m8260_pci_erratum9.c b/arch/ppc/syslib/m8260_pci_erratum9.c
index 5475709..ebb8c8f 100644
--- a/arch/ppc/syslib/m8260_pci_erratum9.c
+++ b/arch/ppc/syslib/m8260_pci_erratum9.c
@@ -105,7 +105,8 @@
 	idma_reg[IDMA_CHAN].idmr = 0;		/* mask all IDMA interrupts */
 	idma_reg[IDMA_CHAN].idsr = 0xff;	/* clear all event flags */
 
-	printk("<4>Using IDMA%d for MPC8260 device erratum PCI 9 workaround\n",
+	printk(KERN_WARNING
+		"Using IDMA%d for MPC8260 device erratum PCI 9 workaround\n",
 		IDMA_CHAN + 1);
 
 	return;
diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c
index d8d299b..01e48d8 100644
--- a/arch/ppc/syslib/m8xx_setup.c
+++ b/arch/ppc/syslib/m8xx_setup.c
@@ -77,7 +77,7 @@
 	}
 };
 
-#define mpc8xxads_part_num (sizeof (mpc8xxads_partitions) / sizeof (mpc8xxads_partitions[0]))
+#define mpc8xxads_part_num ARRAY_SIZE(mpc8xxads_partitions)
 
 #endif
 
diff --git a/arch/ppc/syslib/ppc85xx_rio.c b/arch/ppc/syslib/ppc85xx_rio.c
index 05b0e94..2b09780 100644
--- a/arch/ppc/syslib/ppc85xx_rio.c
+++ b/arch/ppc/syslib/ppc85xx_rio.c
@@ -59,8 +59,6 @@
 #define DBELL_TID(x)		(*(u8 *)(x + DOORBELL_TID_OFFSET))
 #define DBELL_INF(x)		(*(u16 *)(x + DOORBELL_INFO_OFFSET))
 
-#define is_power_of_2(x)	(((x) & ((x) - 1)) == 0)
-
 struct rio_atmu_regs {
 	u32 rowtar;
 	u32 pad1;
diff --git a/arch/ppc/xmon/ppc-opc.c b/arch/ppc/xmon/ppc-opc.c
index 533a6c9..034313c 100644
--- a/arch/ppc/xmon/ppc-opc.c
+++ b/arch/ppc/xmon/ppc-opc.c
@@ -19,6 +19,7 @@
 Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include <linux/posix_types.h>
+#include <linux/kernel.h>
 #include "ansidecl.h"
 #include "ppc.h"
 
@@ -2669,8 +2670,7 @@
 
 };
 
-const int powerpc_num_opcodes =
-  sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]);
+const int powerpc_num_opcodes = ARRAY_SIZE(powerpc_opcodes);
 
 /* The macro table.  This is only used by the assembler.  */
 
@@ -2717,5 +2717,4 @@
 
 };
 
-const int powerpc_num_macros =
-  sizeof (powerpc_macros) / sizeof (powerpc_macros[0]);
+const int powerpc_num_macros = ARRAY_SIZE(powerpc_macros);
diff --git a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c
index d74a883..8f0b953 100644
--- a/arch/ppc/xmon/start.c
+++ b/arch/ppc/xmon/start.c
@@ -58,10 +58,7 @@
 void
 xmon_map_scc(void)
 {
-#if defined(CONFIG_GEMINI)
-	/* should already be mapped by the kernel boot */
-	sccd = (volatile unsigned char *) 0xffeffb08;
-#elif defined(CONFIG_405GP)
+#if defined(CONFIG_405GP)
 	sccd = (volatile unsigned char *)0xef600300;
 #elif defined(CONFIG_440EP)
 	sccd = (volatile unsigned char *) ioremap(PPC440EP_UART0_ADDR, 8);
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 1227236..eaed402 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -34,10 +34,6 @@
 	bool
 	default y
 
-config GENERIC_CALIBRATE_DELAY
-	bool
-	default y
-
 config GENERIC_TIME
 	def_bool y
 
@@ -134,6 +130,31 @@
 	bool
 	default y
 
+config S390_SWITCH_AMODE
+	bool "Switch kernel/user addressing modes"
+	help
+	  This option allows to switch the addressing modes of kernel and user
+	  space. The kernel parameter switch_amode=on will enable this feature,
+	  default is disabled. Enabling this (via kernel parameter) on machines
+	  earlier than IBM System z9-109 EC/BC will reduce system performance.
+
+	  Note that this option will also be selected by selecting the execute
+	  protection option below. Enabling the execute protection via the
+	  noexec kernel parameter will also switch the addressing modes,
+	  independent of the switch_amode kernel parameter.
+
+
+config S390_EXEC_PROTECT
+	bool "Data execute protection"
+	select S390_SWITCH_AMODE
+	help
+	  This option allows to enable a buffer overflow protection for user
+	  space programs and it also selects the addressing mode option above.
+	  The kernel parameter noexec=on will enable this feature and also
+	  switch the addressing modes, default is disabled. Enabling this (via
+	  kernel parameter) on machines earlier than IBM System z9-109 EC/BC
+	  will reduce system performance.
+
 comment "Code generation options"
 
 choice
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
index b8c2372..c9da7d1 100644
--- a/arch/s390/appldata/appldata_base.c
+++ b/arch/s390/appldata/appldata_base.c
@@ -81,7 +81,7 @@
 /*
  * Timer
  */
-DEFINE_PER_CPU(struct vtimer_list, appldata_timer);
+static DEFINE_PER_CPU(struct vtimer_list, appldata_timer);
 static atomic_t appldata_expire_count = ATOMIC_INIT(0);
 
 static DEFINE_SPINLOCK(appldata_timer_lock);
diff --git a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c
index 8aea369..4ca6157 100644
--- a/arch/s390/appldata/appldata_mem.c
+++ b/arch/s390/appldata/appldata_mem.c
@@ -36,7 +36,7 @@
  * book:
  * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
  */
-struct appldata_mem_data {
+static struct appldata_mem_data {
 	u64 timestamp;
 	u32 sync_count_1;       /* after VM collected the record data, */
 	u32 sync_count_2;	/* sync_count_1 and sync_count_2 should be the
diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c
index 075e619..f64b8c8 100644
--- a/arch/s390/appldata/appldata_net_sum.c
+++ b/arch/s390/appldata/appldata_net_sum.c
@@ -34,7 +34,7 @@
  * book:
  * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
  */
-struct appldata_net_sum_data {
+static struct appldata_net_sum_data {
 	u64 timestamp;
 	u32 sync_count_1;	/* after VM collected the record data, */
 	u32 sync_count_2;	/* sync_count_1 and sync_count_2 should be the
diff --git a/arch/s390/crypto/Kconfig b/arch/s390/crypto/Kconfig
new file mode 100644
index 0000000..99ff9f0
--- /dev/null
+++ b/arch/s390/crypto/Kconfig
@@ -0,0 +1,60 @@
+config CRYPTO_SHA1_S390
+	tristate "SHA1 digest algorithm"
+	depends on S390
+	select CRYPTO_ALGAPI
+	help
+	  This is the s390 hardware accelerated implementation of the
+	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
+
+config CRYPTO_SHA256_S390
+	tristate "SHA256 digest algorithm"
+	depends on S390
+	select CRYPTO_ALGAPI
+	help
+	  This is the s390 hardware accelerated implementation of the
+	  SHA256 secure hash standard (DFIPS 180-2).
+
+	  This version of SHA implements a 256 bit hash with 128 bits of
+	  security against collision attacks.
+
+config CRYPTO_DES_S390
+	tristate "DES and Triple DES cipher algorithms"
+	depends on S390
+	select CRYPTO_ALGAPI
+	select CRYPTO_BLKCIPHER
+	help
+	  This us the s390 hardware accelerated implementation of the
+	  DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+
+config CRYPTO_AES_S390
+	tristate "AES cipher algorithms"
+	depends on S390
+	select CRYPTO_ALGAPI
+	select CRYPTO_BLKCIPHER
+	help
+	  This is the s390 hardware accelerated implementation of the
+	  AES cipher algorithms (FIPS-197). AES uses the Rijndael
+	  algorithm.
+
+	  Rijndael appears to be consistently a very good performer in
+	  both hardware and software across a wide range of computing
+	  environments regardless of its use in feedback or non-feedback
+	  modes. Its key setup time is excellent, and its key agility is
+	  good. Rijndael's very low memory requirements make it very well
+	  suited for restricted-space environments, in which it also
+	  demonstrates excellent performance. Rijndael's operations are
+	  among the easiest to defend against power and timing attacks.
+
+	  On s390 the System z9-109 currently only supports the key size
+	  of 128 bit.
+
+config S390_PRNG
+	tristate "Pseudo random number generator device driver"
+	depends on S390
+	default "m"
+	help
+	  Select this option if you want to use the s390 pseudo random number
+	  generator. The PRNG is part of the cryptograhic processor functions
+	  and uses triple-DES to generate secure random numbers like the
+	  ANSI X9.17 standard. The PRNG is usable via the char device
+	  /dev/prandom.
diff --git a/arch/s390/crypto/Makefile b/arch/s390/crypto/Makefile
index bfe2541..14e552c 100644
--- a/arch/s390/crypto/Makefile
+++ b/arch/s390/crypto/Makefile
@@ -6,5 +6,4 @@
 obj-$(CONFIG_CRYPTO_SHA256_S390) += sha256_s390.o
 obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o des_check_key.o
 obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o
-
-obj-$(CONFIG_CRYPTO_TEST) += crypt_s390_query.o
+obj-$(CONFIG_S390_PRNG) += prng.o
diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c
index 15c9eec..9163635 100644
--- a/arch/s390/crypto/aes_s390.c
+++ b/arch/s390/crypto/aes_s390.c
@@ -4,7 +4,7 @@
  * s390 implementation of the AES Cipher Algorithm.
  *
  * s390 Version:
- *   Copyright (C) 2005 IBM Deutschland GmbH, IBM Corporation
+ *   Copyright IBM Corp. 2005,2007
  *   Author(s): Jan Glauber (jang@de.ibm.com)
  *
  * Derived from "crypto/aes.c"
@@ -27,9 +27,11 @@
 /* data block size for all key lengths */
 #define AES_BLOCK_SIZE		16
 
-int has_aes_128 = 0;
-int has_aes_192 = 0;
-int has_aes_256 = 0;
+#define AES_KEYLEN_128		1
+#define AES_KEYLEN_192		2
+#define AES_KEYLEN_256		4
+
+static char keylen_flag = 0;
 
 struct s390_aes_ctx {
 	u8 iv[AES_BLOCK_SIZE];
@@ -47,20 +49,19 @@
 
 	switch (key_len) {
 	case 16:
-		if (!has_aes_128)
+		if (!(keylen_flag & AES_KEYLEN_128))
 			goto fail;
 		break;
 	case 24:
-		if (!has_aes_192)
+		if (!(keylen_flag & AES_KEYLEN_192))
 			goto fail;
 
 		break;
 	case 32:
-		if (!has_aes_256)
+		if (!(keylen_flag & AES_KEYLEN_256))
 			goto fail;
 		break;
 	default:
-		/* invalid key length */
 		goto fail;
 		break;
 	}
@@ -322,34 +323,32 @@
 	int ret;
 
 	if (crypt_s390_func_available(KM_AES_128_ENCRYPT))
-		has_aes_128 = 1;
+		keylen_flag |= AES_KEYLEN_128;
 	if (crypt_s390_func_available(KM_AES_192_ENCRYPT))
-		has_aes_192 = 1;
+		keylen_flag |= AES_KEYLEN_192;
 	if (crypt_s390_func_available(KM_AES_256_ENCRYPT))
-		has_aes_256 = 1;
+		keylen_flag |= AES_KEYLEN_256;
 
-	if (!has_aes_128 && !has_aes_192 && !has_aes_256)
-		return -ENOSYS;
+	if (!keylen_flag)
+		return -EOPNOTSUPP;
+
+	/* z9 109 and z9 BC/EC only support 128 bit key length */
+	if (keylen_flag == AES_KEYLEN_128)
+		printk(KERN_INFO
+		       "aes_s390: hardware acceleration only available for"
+		       "128 bit keys\n");
 
 	ret = crypto_register_alg(&aes_alg);
-	if (ret != 0) {
-		printk(KERN_INFO "crypt_s390: aes-s390 couldn't be loaded.\n");
+	if (ret)
 		goto aes_err;
-	}
 
 	ret = crypto_register_alg(&ecb_aes_alg);
-	if (ret != 0) {
-		printk(KERN_INFO
-		       "crypt_s390: ecb-aes-s390 couldn't be loaded.\n");
+	if (ret)
 		goto ecb_aes_err;
-	}
 
 	ret = crypto_register_alg(&cbc_aes_alg);
-	if (ret != 0) {
-		printk(KERN_INFO
-		       "crypt_s390: cbc-aes-s390 couldn't be loaded.\n");
+	if (ret)
 		goto cbc_aes_err;
-	}
 
 out:
 	return ret;
diff --git a/arch/s390/crypto/crypt_s390.h b/arch/s390/crypto/crypt_s390.h
index 2b13708..2775d26 100644
--- a/arch/s390/crypto/crypt_s390.h
+++ b/arch/s390/crypto/crypt_s390.h
@@ -3,8 +3,9 @@
  *
  * Support for s390 cryptographic instructions.
  *
- *   Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
- *   Author(s): Thomas Spatzier (tspat@de.ibm.com)
+ *   Copyright IBM Corp. 2003,2007
+ *   Author(s): Thomas Spatzier
+ *		Jan Glauber (jan.glauber@de.ibm.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -32,7 +33,8 @@
 	CRYPT_S390_KMAC = 0x0500
 };
 
-/* function codes for KM (CIPHER MESSAGE) instruction
+/*
+ * function codes for KM (CIPHER MESSAGE) instruction
  * 0x80 is the decipher modifier bit
  */
 enum crypt_s390_km_func {
@@ -51,7 +53,8 @@
 	KM_AES_256_DECRYPT  = CRYPT_S390_KM | 0x14 | 0x80,
 };
 
-/* function codes for KMC (CIPHER MESSAGE WITH CHAINING)
+/*
+ * function codes for KMC (CIPHER MESSAGE WITH CHAINING)
  * instruction
  */
 enum crypt_s390_kmc_func {
@@ -68,9 +71,11 @@
 	KMC_AES_192_DECRYPT  = CRYPT_S390_KMC | 0x13 | 0x80,
 	KMC_AES_256_ENCRYPT  = CRYPT_S390_KMC | 0x14,
 	KMC_AES_256_DECRYPT  = CRYPT_S390_KMC | 0x14 | 0x80,
+	KMC_PRNG	     = CRYPT_S390_KMC | 0x43,
 };
 
-/* function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST)
+/*
+ * function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST)
  * instruction
  */
 enum crypt_s390_kimd_func {
@@ -79,7 +84,8 @@
 	KIMD_SHA_256 = CRYPT_S390_KIMD | 2,
 };
 
-/* function codes for KLMD (COMPUTE LAST MESSAGE DIGEST)
+/*
+ * function codes for KLMD (COMPUTE LAST MESSAGE DIGEST)
  * instruction
  */
 enum crypt_s390_klmd_func {
@@ -88,7 +94,8 @@
 	KLMD_SHA_256 = CRYPT_S390_KLMD | 2,
 };
 
-/* function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
+/*
+ * function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
  * instruction
  */
 enum crypt_s390_kmac_func {
@@ -98,229 +105,219 @@
 	KMAC_TDEA_192 = CRYPT_S390_KMAC | 3
 };
 
-/* status word for s390 crypto instructions' QUERY functions */
-struct crypt_s390_query_status {
-	u64 high;
-	u64 low;
-};
-
-/*
+/**
+ * crypt_s390_km:
+ * @func: the function code passed to KM; see crypt_s390_km_func
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
  * Executes the KM (CIPHER MESSAGE) operation of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_km_func
- * @param param: address of parameter block; see POP for details on each func
- * @param dest: address of destination memory area
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- * 	for encryption/decryption funcs
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for encryption/decryption funcs
  */
-static inline int
-crypt_s390_km(long func, void* param, u8* dest, const u8* src, long src_len)
+static inline int crypt_s390_km(long func, void *param,
+				u8 *dest, const u8 *src, long src_len)
 {
 	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
-	register void* __param asm("1") = param;
-	register const u8* __src asm("2") = src;
+	register void *__param asm("1") = param;
+	register const u8 *__src asm("2") = src;
 	register long __src_len asm("3") = src_len;
-	register u8* __dest asm("4") = dest;
+	register u8 *__dest asm("4") = dest;
 	int ret;
 
 	asm volatile(
 		"0:	.insn	rre,0xb92e0000,%3,%1 \n" /* KM opcode */
 		"1:	brc	1,0b \n" /* handle partial completion */
-		"	ahi	%0,%h7\n"
-		"2:	ahi	%0,%h8\n"
-		"3:\n"
-		EX_TABLE(0b,3b) EX_TABLE(1b,2b)
+		"	la	%0,0\n"
+		"2:\n"
+		EX_TABLE(0b,2b) EX_TABLE(1b,2b)
 		: "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
-		: "d" (__func), "a" (__param), "0" (-EFAULT),
-		  "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
-	if (ret < 0)
-		return ret;
-	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
-}
-
-/*
- * Executes the KMC (CIPHER MESSAGE WITH CHAINING) operation of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_kmc_func
- * @param param: address of parameter block; see POP for details on each func
- * @param dest: address of destination memory area
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- * 	for encryption/decryption funcs
- */
-static inline int
-crypt_s390_kmc(long func, void* param, u8* dest, const u8* src, long src_len)
-{
-	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
-	register void* __param asm("1") = param;
-	register const u8* __src asm("2") = src;
-	register long __src_len asm("3") = src_len;
-	register u8* __dest asm("4") = dest;
-	int ret;
-
-	asm volatile(
-		"0:	.insn	rre,0xb92f0000,%3,%1 \n" /* KMC opcode */
-		"1:	brc	1,0b \n" /* handle partial completion */
-		"	ahi	%0,%h7\n"
-		"2:	ahi	%0,%h8\n"
-		"3:\n"
-		EX_TABLE(0b,3b) EX_TABLE(1b,2b)
-		: "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
-		: "d" (__func), "a" (__param), "0" (-EFAULT),
-		  "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
-	if (ret < 0)
-		return ret;
-	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
-}
-
-/*
- * Executes the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) operation
- * of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_kimd_func
- * @param param: address of parameter block; see POP for details on each func
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- * 	for digest funcs
- */
-static inline int
-crypt_s390_kimd(long func, void* param, const u8* src, long src_len)
-{
-	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
-	register void* __param asm("1") = param;
-	register const u8* __src asm("2") = src;
-	register long __src_len asm("3") = src_len;
-	int ret;
-
-	asm volatile(
-		"0:	.insn	rre,0xb93e0000,%1,%1 \n" /* KIMD opcode */
-		"1:	brc	1,0b \n" /* handle partial completion */
-		"	ahi	%0,%h6\n"
-		"2:	ahi	%0,%h7\n"
-		"3:\n"
-		EX_TABLE(0b,3b) EX_TABLE(1b,2b)
-		: "=d" (ret), "+a" (__src), "+d" (__src_len)
-		: "d" (__func), "a" (__param), "0" (-EFAULT),
-		  "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
-	if (ret < 0)
-		return ret;
-	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
-}
-
-/*
- * Executes the KLMD (COMPUTE LAST MESSAGE DIGEST) operation of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_klmd_func
- * @param param: address of parameter block; see POP for details on each func
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- * 	for digest funcs
- */
-static inline int
-crypt_s390_klmd(long func, void* param, const u8* src, long src_len)
-{
-	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
-	register void* __param asm("1") = param;
-	register const u8* __src asm("2") = src;
-	register long __src_len asm("3") = src_len;
-	int ret;
-
-	asm volatile(
-		"0:	.insn	rre,0xb93f0000,%1,%1 \n" /* KLMD opcode */
-		"1:	brc	1,0b \n" /* handle partial completion */
-		"	ahi	%0,%h6\n"
-		"2:	ahi	%0,%h7\n"
-		"3:\n"
-		EX_TABLE(0b,3b) EX_TABLE(1b,2b)
-		: "=d" (ret), "+a" (__src), "+d" (__src_len)
-		: "d" (__func), "a" (__param), "0" (-EFAULT),
-		  "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
-	if (ret < 0)
-		return ret;
-	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
-}
-
-/*
- * Executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) operation
- * of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_klmd_func
- * @param param: address of parameter block; see POP for details on each func
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- * 	for digest funcs
- */
-static inline int
-crypt_s390_kmac(long func, void* param, const u8* src, long src_len)
-{
-	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
-	register void* __param asm("1") = param;
-	register const u8* __src asm("2") = src;
-	register long __src_len asm("3") = src_len;
-	int ret;
-
-	asm volatile(
-		"0:	.insn	rre,0xb91e0000,%1,%1 \n" /* KLAC opcode */
-		"1:	brc	1,0b \n" /* handle partial completion */
-		"	ahi	%0,%h6\n"
-		"2:	ahi	%0,%h7\n"
-		"3:\n"
-		EX_TABLE(0b,3b) EX_TABLE(1b,2b)
-		: "=d" (ret), "+a" (__src), "+d" (__src_len)
-		: "d" (__func), "a" (__param), "0" (-EFAULT),
-		  "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+		: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
 	if (ret < 0)
 		return ret;
 	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
 }
 
 /**
- * Tests if a specific crypto function is implemented on the machine.
- * @param func:	the function code of the specific function; 0 if op in general
- * @return	1 if func available; 0 if func or op in general not available
+ * crypt_s390_kmc:
+ * @func: the function code passed to KM; see crypt_s390_kmc_func
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
+ * Executes the KMC (CIPHER MESSAGE WITH CHAINING) operation of the CPU.
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for encryption/decryption funcs
  */
-static inline int
-crypt_s390_func_available(int func)
+static inline int crypt_s390_kmc(long func, void *param,
+				 u8 *dest, const u8 *src, long src_len)
 {
+	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
+	register void *__param asm("1") = param;
+	register const u8 *__src asm("2") = src;
+	register long __src_len asm("3") = src_len;
+	register u8 *__dest asm("4") = dest;
 	int ret;
 
-	struct crypt_s390_query_status status = {
-		.high = 0,
-		.low = 0
-	};
-	switch (func & CRYPT_S390_OP_MASK){
-		case CRYPT_S390_KM:
-			ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
-			break;
-		case CRYPT_S390_KMC:
-			ret = crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
-			break;
-		case CRYPT_S390_KIMD:
-			ret = crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
-			break;
-		case CRYPT_S390_KLMD:
-			ret = crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
-			break;
-		case CRYPT_S390_KMAC:
-			ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
-			break;
-		default:
-			ret = 0;
-			return ret;
-	}
-	if (ret >= 0){
-		func &= CRYPT_S390_FUNC_MASK;
-		func &= 0x7f; //mask modifier bit
-		if (func < 64){
-			ret = (status.high >> (64 - func - 1)) & 0x1;
-		} else {
-			ret = (status.low >> (128 - func - 1)) & 0x1;
-		}
-	} else {
-		ret = 0;
-	}
-	return ret;
+	asm volatile(
+		"0:	.insn	rre,0xb92f0000,%3,%1 \n" /* KMC opcode */
+		"1:	brc	1,0b \n" /* handle partial completion */
+		"	la	%0,0\n"
+		"2:\n"
+		EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+		: "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
+		: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
+	if (ret < 0)
+		return ret;
+	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
 }
 
-#endif // _CRYPTO_ARCH_S390_CRYPT_S390_H
+/**
+ * crypt_s390_kimd:
+ * @func: the function code passed to KM; see crypt_s390_kimd_func
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
+ * Executes the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) operation
+ * of the CPU.
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for digest funcs
+ */
+static inline int crypt_s390_kimd(long func, void *param,
+				  const u8 *src, long src_len)
+{
+	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
+	register void *__param asm("1") = param;
+	register const u8 *__src asm("2") = src;
+	register long __src_len asm("3") = src_len;
+	int ret;
+
+	asm volatile(
+		"0:	.insn	rre,0xb93e0000,%1,%1 \n" /* KIMD opcode */
+		"1:	brc	1,0b \n" /* handle partial completion */
+		"	la	%0,0\n"
+		"2:\n"
+		EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+		: "=d" (ret), "+a" (__src), "+d" (__src_len)
+		: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
+	if (ret < 0)
+		return ret;
+	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
+}
+
+/**
+ * crypt_s390_klmd:
+ * @func: the function code passed to KM; see crypt_s390_klmd_func
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
+ * Executes the KLMD (COMPUTE LAST MESSAGE DIGEST) operation of the CPU.
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for digest funcs
+ */
+static inline int crypt_s390_klmd(long func, void *param,
+				  const u8 *src, long src_len)
+{
+	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
+	register void *__param asm("1") = param;
+	register const u8 *__src asm("2") = src;
+	register long __src_len asm("3") = src_len;
+	int ret;
+
+	asm volatile(
+		"0:	.insn	rre,0xb93f0000,%1,%1 \n" /* KLMD opcode */
+		"1:	brc	1,0b \n" /* handle partial completion */
+		"	la	%0,0\n"
+		"2:\n"
+		EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+		: "=d" (ret), "+a" (__src), "+d" (__src_len)
+		: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
+	if (ret < 0)
+		return ret;
+	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
+}
+
+/**
+ * crypt_s390_kmac:
+ * @func: the function code passed to KM; see crypt_s390_klmd_func
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
+ * Executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) operation
+ * of the CPU.
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for digest funcs
+ */
+static inline int crypt_s390_kmac(long func, void *param,
+				  const u8 *src, long src_len)
+{
+	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
+	register void *__param asm("1") = param;
+	register const u8 *__src asm("2") = src;
+	register long __src_len asm("3") = src_len;
+	int ret;
+
+	asm volatile(
+		"0:	.insn	rre,0xb91e0000,%1,%1 \n" /* KLAC opcode */
+		"1:	brc	1,0b \n" /* handle partial completion */
+		"	la	%0,0\n"
+		"2:\n"
+		EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+		: "=d" (ret), "+a" (__src), "+d" (__src_len)
+		: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
+	if (ret < 0)
+		return ret;
+	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
+}
+
+/**
+ * crypt_s390_func_available:
+ * @func: the function code of the specific function; 0 if op in general
+ *
+ * Tests if a specific crypto function is implemented on the machine.
+ *
+ * Returns 1 if func available; 0 if func or op in general not available
+ */
+static inline int crypt_s390_func_available(int func)
+{
+	unsigned char status[16];
+	int ret;
+
+	switch (func & CRYPT_S390_OP_MASK) {
+	case CRYPT_S390_KM:
+		ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
+		break;
+	case CRYPT_S390_KMC:
+		ret = crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
+		break;
+	case CRYPT_S390_KIMD:
+		ret = crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
+		break;
+	case CRYPT_S390_KLMD:
+		ret = crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
+		break;
+	case CRYPT_S390_KMAC:
+		ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
+		break;
+	default:
+		return 0;
+	}
+	if (ret < 0)
+		return 0;
+	func &= CRYPT_S390_FUNC_MASK;
+	func &= 0x7f;		/* mask modifier bit */
+	return (status[func >> 3] & (0x80 >> (func & 7))) != 0;
+}
+
+#endif	/* _CRYPTO_ARCH_S390_CRYPT_S390_H */
diff --git a/arch/s390/crypto/crypt_s390_query.c b/arch/s390/crypto/crypt_s390_query.c
deleted file mode 100644
index 54fb11d..0000000
--- a/arch/s390/crypto/crypt_s390_query.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Support for s390 cryptographic instructions.
- * Testing module for querying processor crypto capabilities.
- *
- * Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Thomas Spatzier (tspat@de.ibm.com)
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/errno.h>
-#include "crypt_s390.h"
-
-static void query_available_functions(void)
-{
-	printk(KERN_INFO "#####################\n");
-
-	/* query available KM functions */
-	printk(KERN_INFO "KM_QUERY: %d\n",
-		crypt_s390_func_available(KM_QUERY));
-	printk(KERN_INFO "KM_DEA: %d\n",
-		crypt_s390_func_available(KM_DEA_ENCRYPT));
-	printk(KERN_INFO "KM_TDEA_128: %d\n",
-		crypt_s390_func_available(KM_TDEA_128_ENCRYPT));
-	printk(KERN_INFO "KM_TDEA_192: %d\n",
-		crypt_s390_func_available(KM_TDEA_192_ENCRYPT));
-	printk(KERN_INFO "KM_AES_128: %d\n",
-		crypt_s390_func_available(KM_AES_128_ENCRYPT));
-	printk(KERN_INFO "KM_AES_192: %d\n",
-		crypt_s390_func_available(KM_AES_192_ENCRYPT));
-	printk(KERN_INFO "KM_AES_256: %d\n",
-		crypt_s390_func_available(KM_AES_256_ENCRYPT));
-
-	/* query available KMC functions */
-	printk(KERN_INFO "KMC_QUERY: %d\n",
-		crypt_s390_func_available(KMC_QUERY));
-	printk(KERN_INFO "KMC_DEA: %d\n",
-		crypt_s390_func_available(KMC_DEA_ENCRYPT));
-	printk(KERN_INFO "KMC_TDEA_128: %d\n",
-		crypt_s390_func_available(KMC_TDEA_128_ENCRYPT));
-	printk(KERN_INFO "KMC_TDEA_192: %d\n",
-		crypt_s390_func_available(KMC_TDEA_192_ENCRYPT));
-	printk(KERN_INFO "KMC_AES_128: %d\n",
-		crypt_s390_func_available(KMC_AES_128_ENCRYPT));
-	printk(KERN_INFO "KMC_AES_192: %d\n",
-		crypt_s390_func_available(KMC_AES_192_ENCRYPT));
-	printk(KERN_INFO "KMC_AES_256: %d\n",
-		crypt_s390_func_available(KMC_AES_256_ENCRYPT));
-
-	/* query available KIMD functions */
-	printk(KERN_INFO "KIMD_QUERY: %d\n",
-		crypt_s390_func_available(KIMD_QUERY));
-	printk(KERN_INFO "KIMD_SHA_1: %d\n",
-		crypt_s390_func_available(KIMD_SHA_1));
-	printk(KERN_INFO "KIMD_SHA_256: %d\n",
-		crypt_s390_func_available(KIMD_SHA_256));
-
-	/* query available KLMD functions */
-	printk(KERN_INFO "KLMD_QUERY: %d\n",
-		crypt_s390_func_available(KLMD_QUERY));
-	printk(KERN_INFO "KLMD_SHA_1: %d\n",
-		crypt_s390_func_available(KLMD_SHA_1));
-	printk(KERN_INFO "KLMD_SHA_256: %d\n",
-		crypt_s390_func_available(KLMD_SHA_256));
-
-	/* query available KMAC functions */
-	printk(KERN_INFO "KMAC_QUERY: %d\n",
-		crypt_s390_func_available(KMAC_QUERY));
-	printk(KERN_INFO "KMAC_DEA: %d\n",
-		crypt_s390_func_available(KMAC_DEA));
-	printk(KERN_INFO "KMAC_TDEA_128: %d\n",
-		crypt_s390_func_available(KMAC_TDEA_128));
-	printk(KERN_INFO "KMAC_TDEA_192: %d\n",
-		crypt_s390_func_available(KMAC_TDEA_192));
-}
-
-static int init(void)
-{
-	struct crypt_s390_query_status status = {
-		.high = 0,
-		.low = 0
-	};
-
-	printk(KERN_INFO "crypt_s390: querying available crypto functions\n");
-	crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
-	printk(KERN_INFO "KM:\t%016llx %016llx\n",
-			(unsigned long long) status.high,
-			(unsigned long long) status.low);
-	status.high = status.low = 0;
-	crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
-	printk(KERN_INFO "KMC:\t%016llx %016llx\n",
-			(unsigned long long) status.high,
-			(unsigned long long) status.low);
-	status.high = status.low = 0;
-	crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
-	printk(KERN_INFO "KIMD:\t%016llx %016llx\n",
-			(unsigned long long) status.high,
-			(unsigned long long) status.low);
-	status.high = status.low = 0;
-	crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
-	printk(KERN_INFO "KLMD:\t%016llx %016llx\n",
-			(unsigned long long) status.high,
-			(unsigned long long) status.low);
-	status.high = status.low = 0;
-	crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
-	printk(KERN_INFO "KMAC:\t%016llx %016llx\n",
-			(unsigned long long) status.high,
-			(unsigned long long) status.low);
-
-	query_available_functions();
-	return -ECANCELED;
-}
-
-static void __exit cleanup(void)
-{
-}
-
-module_init(init);
-module_exit(cleanup);
-
-MODULE_LICENSE("GPL");
diff --git a/arch/s390/crypto/des_check_key.c b/arch/s390/crypto/des_check_key.c
index e3f5c5f..5706af2 100644
--- a/arch/s390/crypto/des_check_key.c
+++ b/arch/s390/crypto/des_check_key.c
@@ -10,8 +10,9 @@
  * scatterlist interface.  Changed LGPL to GPL per section 3 of the LGPL.
  *
  * s390 Version:
- *   Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
- *   Author(s): Thomas Spatzier (tspat@de.ibm.com)
+ *   Copyright IBM Corp. 2003
+ *   Author(s): Thomas Spatzier
+ *		Jan Glauber (jan.glauber@de.ibm.com)
  *
  * Derived from "crypto/des.c"
  *   Copyright (c) 1992 Dana L. How.
@@ -30,6 +31,7 @@
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/crypto.h>
+#include "crypto_des.h"
 
 #define ROR(d,c,o)	((d) = (d) >> (c) | (d) << (o))
 
diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c
index 2aba048..ea22707 100644
--- a/arch/s390/crypto/des_s390.c
+++ b/arch/s390/crypto/des_s390.c
@@ -3,9 +3,9 @@
  *
  * s390 implementation of the DES Cipher Algorithm.
  *
- * Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Thomas Spatzier (tspat@de.ibm.com)
- *
+ * Copyright IBM Corp. 2003,2007
+ * Author(s): Thomas Spatzier
+ *	      Jan Glauber (jan.glauber@de.ibm.com)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -557,7 +557,7 @@
 	if (!crypt_s390_func_available(KM_DEA_ENCRYPT) ||
 	    !crypt_s390_func_available(KM_TDEA_128_ENCRYPT) ||
 	    !crypt_s390_func_available(KM_TDEA_192_ENCRYPT))
-		return -ENOSYS;
+		return -EOPNOTSUPP;
 
 	ret = crypto_register_alg(&des_alg);
 	if (ret)
diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c
new file mode 100644
index 0000000..8eb3a1a
--- /dev/null
+++ b/arch/s390/crypto/prng.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright IBM Corp. 2006,2007
+ * Author(s): Jan Glauber <jan.glauber@de.ibm.com>
+ * Driver for the s390 pseudo random number generator
+ */
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/random.h>
+#include <asm/debug.h>
+#include <asm/uaccess.h>
+
+#include "crypt_s390.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jan Glauber <jan.glauber@de.ibm.com>");
+MODULE_DESCRIPTION("s390 PRNG interface");
+
+static int prng_chunk_size = 256;
+module_param(prng_chunk_size, int, S_IRUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC(prng_chunk_size, "PRNG read chunk size in bytes");
+
+static int prng_entropy_limit = 4096;
+module_param(prng_entropy_limit, int, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
+MODULE_PARM_DESC(prng_entropy_limit,
+	"PRNG add entropy after that much bytes were produced");
+
+/*
+ * Any one who considers arithmetical methods of producing random digits is,
+ * of course, in a state of sin. -- John von Neumann
+ */
+
+struct s390_prng_data {
+	unsigned long count; /* how many bytes were produced */
+	char *buf;
+};
+
+static struct s390_prng_data *p;
+
+/* copied from libica, use a non-zero initial parameter block */
+static unsigned char parm_block[32] = {
+0x0F,0x2B,0x8E,0x63,0x8C,0x8E,0xD2,0x52,0x64,0xB7,0xA0,0x7B,0x75,0x28,0xB8,0xF4,
+0x75,0x5F,0xD2,0xA6,0x8D,0x97,0x11,0xFF,0x49,0xD8,0x23,0xF3,0x7E,0x21,0xEC,0xA0,
+};
+
+static int prng_open(struct inode *inode, struct file *file)
+{
+	return nonseekable_open(inode, file);
+}
+
+static void prng_add_entropy(void)
+{
+	__u64 entropy[4];
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < 16; i++) {
+		ret = crypt_s390_kmc(KMC_PRNG, parm_block, (char *)entropy,
+				     (char *)entropy, sizeof(entropy));
+		BUG_ON(ret < 0 || ret != sizeof(entropy));
+		memcpy(parm_block, entropy, sizeof(entropy));
+	}
+}
+
+static void prng_seed(int nbytes)
+{
+	char buf[16];
+	int i = 0;
+
+	BUG_ON(nbytes > 16);
+	get_random_bytes(buf, nbytes);
+
+	/* Add the entropy */
+	while (nbytes >= 8) {
+		*((__u64 *)parm_block) ^= *((__u64 *)buf+i*8);
+		prng_add_entropy();
+		i += 8;
+		nbytes -= 8;
+	}
+	prng_add_entropy();
+}
+
+static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
+			 loff_t *ppos)
+{
+	int chunk, n;
+	int ret = 0;
+	int tmp;
+
+	/* nbytes can be arbitrary long, we spilt it into chunks */
+	while (nbytes) {
+		/* same as in extract_entropy_user in random.c */
+		if (need_resched()) {
+			if (signal_pending(current)) {
+				if (ret == 0)
+					ret = -ERESTARTSYS;
+				break;
+			}
+			schedule();
+		}
+
+		/*
+		 * we lose some random bytes if an attacker issues
+		 * reads < 8 bytes, but we don't care
+		 */
+		chunk = min_t(int, nbytes, prng_chunk_size);
+
+		/* PRNG only likes multiples of 8 bytes */
+		n = (chunk + 7) & -8;
+
+		if (p->count > prng_entropy_limit)
+			prng_seed(8);
+
+		/* if the CPU supports PRNG stckf is present too */
+		asm volatile(".insn     s,0xb27c0000,%0"
+			     : "=m" (*((unsigned long long *)p->buf)) : : "cc");
+
+		/*
+		 * Beside the STCKF the input for the TDES-EDE is the output
+		 * of the last operation. We differ here from X9.17 since we
+		 * only store one timestamp into the buffer. Padding the whole
+		 * buffer with timestamps does not improve security, since
+		 * successive stckf have nearly constant offsets.
+		 * If an attacker knows the first timestamp it would be
+		 * trivial to guess the additional values. One timestamp
+		 * is therefore enough and still guarantees unique input values.
+		 *
+		 * Note: you can still get strict X9.17 conformity by setting
+		 * prng_chunk_size to 8 bytes.
+		*/
+		tmp = crypt_s390_kmc(KMC_PRNG, parm_block, p->buf, p->buf, n);
+		BUG_ON((tmp < 0) || (tmp != n));
+
+		p->count += n;
+
+		if (copy_to_user(ubuf, p->buf, chunk))
+			return -EFAULT;
+
+		nbytes -= chunk;
+		ret += chunk;
+		ubuf += chunk;
+	}
+	return ret;
+}
+
+static struct file_operations prng_fops = {
+	.owner		= THIS_MODULE,
+	.open		= &prng_open,
+	.release	= NULL,
+	.read		= &prng_read,
+};
+
+static struct miscdevice prng_dev = {
+	.name	= "prandom",
+	.minor	= MISC_DYNAMIC_MINOR,
+	.fops	= &prng_fops,
+};
+
+static int __init prng_init(void)
+{
+	int ret;
+
+	/* check if the CPU has a PRNG */
+	if (!crypt_s390_func_available(KMC_PRNG))
+		return -EOPNOTSUPP;
+
+	if (prng_chunk_size < 8)
+		return -EINVAL;
+
+	p = kmalloc(sizeof(struct s390_prng_data), GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+	p->count = 0;
+
+	p->buf = kmalloc(prng_chunk_size, GFP_KERNEL);
+	if (!p->buf) {
+		ret = -ENOMEM;
+		goto out_free;
+	}
+
+	/* initialize the PRNG, add 128 bits of entropy */
+	prng_seed(16);
+
+	ret = misc_register(&prng_dev);
+	if (ret) {
+		printk(KERN_WARNING
+		       "Could not register misc device for PRNG.\n");
+		goto out_buf;
+	}
+	return 0;
+
+out_buf:
+	kfree(p->buf);
+out_free:
+	kfree(p);
+	return ret;
+}
+
+static void __exit prng_exit(void)
+{
+	/* wipe me */
+	memset(p->buf, 0, prng_chunk_size);
+	kfree(p->buf);
+	kfree(p);
+
+	misc_deregister(&prng_dev);
+}
+
+module_init(prng_init);
+module_exit(prng_exit);
diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c
index 49ca869..969639f 100644
--- a/arch/s390/crypto/sha1_s390.c
+++ b/arch/s390/crypto/sha1_s390.c
@@ -8,8 +8,9 @@
  * implementation written by Steve Reid.
  *
  * s390 Version:
- *   Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
- *   Author(s): Thomas Spatzier (tspat@de.ibm.com)
+ *   Copyright IBM Corp. 2003,2007
+ *   Author(s): Thomas Spatzier
+ *		Jan Glauber (jan.glauber@de.ibm.com)
  *
  * Derived from "crypto/sha1.c"
  *   Copyright (c) Alan Smithee.
@@ -43,16 +44,14 @@
 static void sha1_init(struct crypto_tfm *tfm)
 {
 	struct crypt_s390_sha1_ctx *ctx = crypto_tfm_ctx(tfm);
-	static const u32 initstate[5] = {
-		0x67452301,
-		0xEFCDAB89,
-		0x98BADCFE,
-		0x10325476,
-		0xC3D2E1F0
-	};
+
+	ctx->state[0] = 0x67452301;
+	ctx->state[1] =	0xEFCDAB89;
+	ctx->state[2] =	0x98BADCFE;
+	ctx->state[3] = 0x10325476;
+	ctx->state[4] =	0xC3D2E1F0;
 
 	ctx->count = 0;
-	memcpy(ctx->state, &initstate, sizeof(initstate));
 	ctx->buf_len = 0;
 }
 
@@ -63,13 +62,13 @@
 	long imd_len;
 
 	sctx = crypto_tfm_ctx(tfm);
-	sctx->count += len * 8; //message bit length
+	sctx->count += len * 8; /* message bit length */
 
-	//anything in buffer yet? -> must be completed
+	/* anything in buffer yet? -> must be completed */
 	if (sctx->buf_len && (sctx->buf_len + len) >= SHA1_BLOCK_SIZE) {
-		//complete full block and hash
+		/* complete full block and hash */
 		memcpy(sctx->buffer + sctx->buf_len, data,
-				SHA1_BLOCK_SIZE - sctx->buf_len);
+		       SHA1_BLOCK_SIZE - sctx->buf_len);
 		crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer,
 				SHA1_BLOCK_SIZE);
 		data += SHA1_BLOCK_SIZE - sctx->buf_len;
@@ -77,37 +76,36 @@
 		sctx->buf_len = 0;
 	}
 
-	//rest of data contains full blocks?
+	/* rest of data contains full blocks? */
 	imd_len = len & ~0x3ful;
-	if (imd_len){
+	if (imd_len) {
 		crypt_s390_kimd(KIMD_SHA_1, sctx->state, data, imd_len);
 		data += imd_len;
 		len -= imd_len;
 	}
-	//anything left? store in buffer
-	if (len){
+	/* anything left? store in buffer */
+	if (len) {
 		memcpy(sctx->buffer + sctx->buf_len , data, len);
 		sctx->buf_len += len;
 	}
 }
 
 
-static void
-pad_message(struct crypt_s390_sha1_ctx* sctx)
+static void pad_message(struct crypt_s390_sha1_ctx* sctx)
 {
 	int index;
 
 	index = sctx->buf_len;
-	sctx->buf_len = (sctx->buf_len < 56)?
-		SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE;
-	//start pad with 1
+	sctx->buf_len = (sctx->buf_len < 56) ?
+			 SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE;
+	/* start pad with 1 */
 	sctx->buffer[index] = 0x80;
-	//pad with zeros
+	/* pad with zeros */
 	index++;
 	memset(sctx->buffer + index, 0x00, sctx->buf_len - index);
-	//append length
+	/* append length */
 	memcpy(sctx->buffer + sctx->buf_len - 8, &sctx->count,
-			sizeof sctx->count);
+	       sizeof sctx->count);
 }
 
 /* Add padding and return the message digest. */
@@ -115,47 +113,40 @@
 {
 	struct crypt_s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
 
-	//must perform manual padding
+	/* must perform manual padding */
 	pad_message(sctx);
 	crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, sctx->buf_len);
-	//copy digest to out
+	/* copy digest to out */
 	memcpy(out, sctx->state, SHA1_DIGEST_SIZE);
-	/* Wipe context */
+	/* wipe context */
 	memset(sctx, 0, sizeof *sctx);
 }
 
 static struct crypto_alg alg = {
 	.cra_name	=	"sha1",
-	.cra_driver_name =	"sha1-s390",
+	.cra_driver_name=	"sha1-s390",
 	.cra_priority	=	CRYPT_S390_PRIORITY,
 	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
 	.cra_blocksize	=	SHA1_BLOCK_SIZE,
 	.cra_ctxsize	=	sizeof(struct crypt_s390_sha1_ctx),
 	.cra_module	=	THIS_MODULE,
-	.cra_list       =       LIST_HEAD_INIT(alg.cra_list),
+	.cra_list	=	LIST_HEAD_INIT(alg.cra_list),
 	.cra_u		=	{ .digest = {
 	.dia_digestsize	=	SHA1_DIGEST_SIZE,
-	.dia_init   	= 	sha1_init,
-	.dia_update 	=	sha1_update,
-	.dia_final  	=	sha1_final } }
+	.dia_init	=	sha1_init,
+	.dia_update	=	sha1_update,
+	.dia_final	=	sha1_final } }
 };
 
-static int
-init(void)
+static int __init init(void)
 {
-	int ret = -ENOSYS;
+	if (!crypt_s390_func_available(KIMD_SHA_1))
+		return -EOPNOTSUPP;
 
-	if (crypt_s390_func_available(KIMD_SHA_1)){
-		ret = crypto_register_alg(&alg);
-		if (ret == 0){
-			printk(KERN_INFO "crypt_s390: sha1_s390 loaded.\n");
-		}
-	}
-	return ret;
+	return crypto_register_alg(&alg);
 }
 
-static void __exit
-fini(void)
+static void __exit fini(void)
 {
 	crypto_unregister_alg(&alg);
 }
diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c
index 8e4e675..78436c6 100644
--- a/arch/s390/crypto/sha256_s390.c
+++ b/arch/s390/crypto/sha256_s390.c
@@ -4,7 +4,7 @@
  * s390 implementation of the SHA256 Secure Hash Algorithm.
  *
  * s390 Version:
- *   Copyright (C) 2005 IBM Deutschland GmbH, IBM Corporation
+ *   Copyright IBM Corp. 2005,2007
  *   Author(s): Jan Glauber (jang@de.ibm.com)
  *
  * Derived from "crypto/sha256.c"
@@ -143,15 +143,10 @@
 
 static int init(void)
 {
-	int ret;
-
 	if (!crypt_s390_func_available(KIMD_SHA_256))
-		return -ENOSYS;
+		return -EOPNOTSUPP;
 
-	ret = crypto_register_alg(&alg);
-	if (ret != 0)
-		printk(KERN_INFO "crypt_s390: sha256_s390 couldn't be loaded.");
-	return ret;
+	return crypto_register_alg(&alg);
 }
 
 static void __exit fini(void)
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index 5368cf4..1406400 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -108,6 +108,8 @@
 CONFIG_COMPAT=y
 CONFIG_SYSVIPC_COMPAT=y
 CONFIG_AUDIT_ARCH=y
+CONFIG_S390_SWITCH_AMODE=y
+CONFIG_S390_EXEC_PROTECT=y
 
 #
 # Code generation options
@@ -177,6 +179,8 @@
 # CONFIG_XFRM_USER is not set
 # CONFIG_XFRM_SUB_POLICY is not set
 CONFIG_NET_KEY=y
+CONFIG_IUCV=m
+CONFIG_AFIUCV=m
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
@@ -431,7 +435,6 @@
 CONFIG_TN3215=y
 CONFIG_TN3215_CONSOLE=y
 CONFIG_CCW_CONSOLE=y
-CONFIG_SCLP=y
 CONFIG_SCLP_TTY=y
 CONFIG_SCLP_CONSOLE=y
 CONFIG_SCLP_VT220_TTY=y
@@ -507,7 +510,6 @@
 #
 CONFIG_LCS=m
 CONFIG_CTC=m
-CONFIG_IUCV=m
 # CONFIG_NETIUCV is not set
 # CONFIG_SMSGIUCV is not set
 # CONFIG_CLAW is not set
@@ -724,9 +726,7 @@
 # CONFIG_CRYPTO_MD4 is not set
 # CONFIG_CRYPTO_MD5 is not set
 # CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA1_S390 is not set
 # CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA256_S390 is not set
 # CONFIG_CRYPTO_SHA512 is not set
 # CONFIG_CRYPTO_WP512 is not set
 # CONFIG_CRYPTO_TGR192 is not set
@@ -735,12 +735,10 @@
 CONFIG_CRYPTO_CBC=y
 # CONFIG_CRYPTO_LRW is not set
 # CONFIG_CRYPTO_DES is not set
-# CONFIG_CRYPTO_DES_S390 is not set
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
 # CONFIG_CRYPTO_SERPENT is not set
 # CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_AES_S390 is not set
 # CONFIG_CRYPTO_CAST5 is not set
 # CONFIG_CRYPTO_CAST6 is not set
 # CONFIG_CRYPTO_TEA is not set
@@ -755,6 +753,11 @@
 #
 # Hardware crypto devices
 #
+# CONFIG_CRYPTO_SHA1_S390 is not set
+# CONFIG_CRYPTO_SHA256_S390 is not set
+# CONFIG_CRYPTO_DES_S390 is not set
+# CONFIG_CRYPTO_AES_S390 is not set
+CONFIG_S390_PRNG=m
 
 #
 # Library routines
diff --git a/arch/s390/hypfs/Makefile b/arch/s390/hypfs/Makefile
index f4b00cd..b08d2ab 100644
--- a/arch/s390/hypfs/Makefile
+++ b/arch/s390/hypfs/Makefile
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o
 
-s390_hypfs-objs := inode.o hypfs_diag.o
+s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o
diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h
index f3dbd91..aea5720 100644
--- a/arch/s390/hypfs/hypfs.h
+++ b/arch/s390/hypfs/hypfs.h
@@ -27,4 +27,13 @@
 				       struct dentry *dir, const char *name,
 				       char *string);
 
+/* LPAR Hypervisor */
+extern int hypfs_diag_init(void);
+extern void hypfs_diag_exit(void);
+extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root);
+
+/* VM Hypervisor */
+extern int hypfs_vm_init(void);
+extern int hypfs_vm_create_files(struct super_block *sb, struct dentry *root);
+
 #endif /* _HYPFS_H_ */
diff --git a/arch/s390/hypfs/hypfs_diag.h b/arch/s390/hypfs/hypfs_diag.h
deleted file mode 100644
index 256b384..0000000
--- a/arch/s390/hypfs/hypfs_diag.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- *  arch/s390/hypfs_diag.h
- *    Hypervisor filesystem for Linux on s390.
- *
- *    Copyright (C) IBM Corp. 2006
- *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
- */
-
-#ifndef _HYPFS_DIAG_H_
-#define _HYPFS_DIAG_H_
-
-extern int hypfs_diag_init(void);
-extern void hypfs_diag_exit(void);
-extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root);
-
-#endif /* _HYPFS_DIAG_H_ */
diff --git a/arch/s390/hypfs/hypfs_vm.c b/arch/s390/hypfs/hypfs_vm.c
new file mode 100644
index 0000000..d01fc8f
--- /dev/null
+++ b/arch/s390/hypfs/hypfs_vm.c
@@ -0,0 +1,231 @@
+/*
+ *    Hypervisor filesystem for Linux on s390. z/VM implementation.
+ *
+ *    Copyright (C) IBM Corp. 2006
+ *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <asm/ebcdic.h>
+#include "hypfs.h"
+
+#define NAME_LEN 8
+
+static char local_guest[] = "        ";
+static char all_guests[] = "*       ";
+static char *guest_query;
+
+struct diag2fc_data {
+	__u32 version;
+	__u32 flags;
+	__u64 used_cpu;
+	__u64 el_time;
+	__u64 mem_min_kb;
+	__u64 mem_max_kb;
+	__u64 mem_share_kb;
+	__u64 mem_used_kb;
+	__u32 pcpus;
+	__u32 lcpus;
+	__u32 vcpus;
+	__u32 cpu_min;
+	__u32 cpu_max;
+	__u32 cpu_shares;
+	__u32 cpu_use_samp;
+	__u32 cpu_delay_samp;
+	__u32 page_wait_samp;
+	__u32 idle_samp;
+	__u32 other_samp;
+	__u32 total_samp;
+	char  guest_name[NAME_LEN];
+};
+
+struct diag2fc_parm_list {
+	char userid[NAME_LEN];
+	char aci_grp[NAME_LEN];
+	__u64 addr;
+	__u32 size;
+	__u32 fmt;
+};
+
+static int diag2fc(int size, char* query, void *addr)
+{
+	unsigned long residual_cnt;
+	unsigned long rc;
+	struct diag2fc_parm_list parm_list;
+
+	memcpy(parm_list.userid, query, NAME_LEN);
+	ASCEBC(parm_list.userid, NAME_LEN);
+	parm_list.addr = (unsigned long) addr ;
+	parm_list.size = size;
+	parm_list.fmt = 0x02;
+	memset(parm_list.aci_grp, 0x40, NAME_LEN);
+	rc = -1;
+
+	asm volatile(
+		"	diag    %0,%1,0x2fc\n"
+		"0:\n"
+		EX_TABLE(0b,0b)
+		: "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory");
+
+	if ((rc != 0 ) && (rc != -2))
+		return rc;
+	else
+		return -residual_cnt;
+}
+
+static struct diag2fc_data *diag2fc_store(char *query, int *count)
+{
+	int size;
+	struct diag2fc_data *data;
+
+	do {
+		size = diag2fc(0, query, NULL);
+		if (size < 0)
+			return ERR_PTR(-EACCES);
+		data = vmalloc(size);
+		if (!data)
+			return ERR_PTR(-ENOMEM);
+		if (diag2fc(size, query, data) == 0)
+			break;
+		vfree(data);
+	} while (1);
+	*count = (size / sizeof(*data));
+
+	return data;
+}
+
+static void diag2fc_free(void *data)
+{
+	vfree(data);
+}
+
+#define ATTRIBUTE(sb, dir, name, member) \
+do { \
+	void *rc; \
+	rc = hypfs_create_u64(sb, dir, name, member); \
+	if (IS_ERR(rc)) \
+		return PTR_ERR(rc); \
+} while(0)
+
+static int hpyfs_vm_create_guest(struct super_block *sb,
+				 struct dentry *systems_dir,
+				 struct diag2fc_data *data)
+{
+	char guest_name[NAME_LEN + 1] = {};
+	struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir;
+	int dedicated_flag, capped_value;
+
+	capped_value = (data->flags & 0x00000006) >> 1;
+	dedicated_flag = (data->flags & 0x00000008) >> 3;
+
+	/* guest dir */
+	memcpy(guest_name, data->guest_name, NAME_LEN);
+	EBCASC(guest_name, NAME_LEN);
+	strstrip(guest_name);
+	guest_dir = hypfs_mkdir(sb, systems_dir, guest_name);
+	if (IS_ERR(guest_dir))
+		return PTR_ERR(guest_dir);
+	ATTRIBUTE(sb, guest_dir, "onlinetime_us", data->el_time);
+
+	/* logical cpu information */
+	cpus_dir = hypfs_mkdir(sb, guest_dir, "cpus");
+	if (IS_ERR(cpus_dir))
+		return PTR_ERR(cpus_dir);
+	ATTRIBUTE(sb, cpus_dir, "cputime_us", data->used_cpu);
+	ATTRIBUTE(sb, cpus_dir, "capped", capped_value);
+	ATTRIBUTE(sb, cpus_dir, "dedicated", dedicated_flag);
+	ATTRIBUTE(sb, cpus_dir, "count", data->vcpus);
+	ATTRIBUTE(sb, cpus_dir, "weight_min", data->cpu_min);
+	ATTRIBUTE(sb, cpus_dir, "weight_max", data->cpu_max);
+	ATTRIBUTE(sb, cpus_dir, "weight_cur", data->cpu_shares);
+
+	/* memory information */
+	mem_dir = hypfs_mkdir(sb, guest_dir, "mem");
+	if (IS_ERR(mem_dir))
+		return PTR_ERR(mem_dir);
+	ATTRIBUTE(sb, mem_dir, "min_KiB", data->mem_min_kb);
+	ATTRIBUTE(sb, mem_dir, "max_KiB", data->mem_max_kb);
+	ATTRIBUTE(sb, mem_dir, "used_KiB", data->mem_used_kb);
+	ATTRIBUTE(sb, mem_dir, "share_KiB", data->mem_share_kb);
+
+	/* samples */
+	samples_dir = hypfs_mkdir(sb, guest_dir, "samples");
+	if (IS_ERR(samples_dir))
+		return PTR_ERR(samples_dir);
+	ATTRIBUTE(sb, samples_dir, "cpu_using", data->cpu_use_samp);
+	ATTRIBUTE(sb, samples_dir, "cpu_delay", data->cpu_delay_samp);
+	ATTRIBUTE(sb, samples_dir, "mem_delay", data->page_wait_samp);
+	ATTRIBUTE(sb, samples_dir, "idle", data->idle_samp);
+	ATTRIBUTE(sb, samples_dir, "other", data->other_samp);
+	ATTRIBUTE(sb, samples_dir, "total", data->total_samp);
+	return 0;
+}
+
+int hypfs_vm_create_files(struct super_block *sb, struct dentry *root)
+{
+	struct dentry *dir, *file;
+	struct diag2fc_data *data;
+	int rc, i, count = 0;
+
+	data = diag2fc_store(guest_query, &count);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	/* Hpervisor Info */
+	dir = hypfs_mkdir(sb, root, "hyp");
+	if (IS_ERR(dir)) {
+		rc = PTR_ERR(dir);
+		goto failed;
+	}
+	file = hypfs_create_str(sb, dir, "type", "z/VM Hypervisor");
+	if (IS_ERR(file)) {
+		rc = PTR_ERR(file);
+		goto failed;
+	}
+
+	/* physical cpus */
+	dir = hypfs_mkdir(sb, root, "cpus");
+	if (IS_ERR(dir)) {
+		rc = PTR_ERR(dir);
+		goto failed;
+	}
+	file = hypfs_create_u64(sb, dir, "count", data->lcpus);
+	if (IS_ERR(file)) {
+		rc = PTR_ERR(file);
+		goto failed;
+	}
+
+	/* guests */
+	dir = hypfs_mkdir(sb, root, "systems");
+	if (IS_ERR(dir)) {
+		rc = PTR_ERR(dir);
+		goto failed;
+	}
+
+	for (i = 0; i < count; i++) {
+		rc = hpyfs_vm_create_guest(sb, dir, &(data[i]));
+		if (rc)
+			goto failed;
+	}
+	diag2fc_free(data);
+	return 0;
+
+failed:
+	diag2fc_free(data);
+	return rc;
+}
+
+int hypfs_vm_init(void)
+{
+	if (diag2fc(0, all_guests, NULL) > 0)
+		guest_query = all_guests;
+	else if (diag2fc(0, local_guest, NULL) > 0)
+		guest_query = local_guest;
+	else
+		return -EACCES;
+
+	return 0;
+}
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index b6716c4..a4fda7b 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -19,7 +19,6 @@
 #include <linux/module.h>
 #include <asm/ebcdic.h>
 #include "hypfs.h"
-#include "hypfs_diag.h"
 
 #define HYPFS_MAGIC 0x687970	/* ASCII 'hyp' */
 #define TMP_SIZE 64		/* size of temporary buffers */
@@ -192,7 +191,10 @@
 		goto out;
 	}
 	hypfs_delete_tree(sb->s_root);
-	rc = hypfs_diag_create_files(sb, sb->s_root);
+	if (MACHINE_IS_VM)
+		rc = hypfs_vm_create_files(sb, sb->s_root);
+	else
+		rc = hypfs_diag_create_files(sb, sb->s_root);
 	if (rc) {
 		printk(KERN_ERR "hypfs: Update failed\n");
 		hypfs_delete_tree(sb->s_root);
@@ -289,7 +291,10 @@
 		rc = -ENOMEM;
 		goto err_alloc;
 	}
-	rc = hypfs_diag_create_files(sb, root_dentry);
+	if (MACHINE_IS_VM)
+		rc = hypfs_vm_create_files(sb, root_dentry);
+	else
+		rc = hypfs_diag_create_files(sb, root_dentry);
 	if (rc)
 		goto err_tree;
 	sbi->update_file = hypfs_create_update_file(sb, root_dentry);
@@ -462,11 +467,15 @@
 {
 	int rc;
 
-	if (MACHINE_IS_VM)
-		return -ENODATA;
-	if (hypfs_diag_init()) {
-		rc = -ENODATA;
-		goto fail_diag;
+	if (MACHINE_IS_VM) {
+		if (hypfs_vm_init())
+			/* no diag 2fc, just exit */
+			return -ENODATA;
+	} else {
+		if (hypfs_diag_init()) {
+			rc = -ENODATA;
+			goto fail_diag;
+		}
 	}
 	kset_set_kset_s(&s390_subsys, hypervisor_subsys);
 	rc = subsystem_register(&s390_subsys);
@@ -480,7 +489,8 @@
 fail_filesystem:
 	subsystem_unregister(&s390_subsys);
 fail_sysfs:
-	hypfs_diag_exit();
+	if (!MACHINE_IS_VM)
+		hypfs_diag_exit();
 fail_diag:
 	printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc);
 	return rc;
@@ -488,7 +498,8 @@
 
 static void __exit hypfs_exit(void)
 {
-	hypfs_diag_exit();
+	if (!MACHINE_IS_VM)
+		hypfs_diag_exit();
 	unregister_filesystem(&hypfs_type);
 	subsystem_unregister(&s390_subsys);
 }
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index a81881c..5492d25 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -4,9 +4,9 @@
 
 EXTRA_AFLAGS	:= -traditional
 
-obj-y	:=  bitmap.o traps.o time.o process.o reset.o \
+obj-y	:=  bitmap.o traps.o time.o process.o base.o early.o \
             setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
-	    semaphore.o s390_ext.o debug.o profile.o irq.o ipl.o
+	    semaphore.o s390_ext.o debug.o irq.o ipl.o
 
 obj-y	+= $(if $(CONFIG_64BIT),entry64.o,entry.o)
 obj-y	+= $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
diff --git a/arch/s390/kernel/base.S b/arch/s390/kernel/base.S
new file mode 100644
index 0000000..dc7e525
--- /dev/null
+++ b/arch/s390/kernel/base.S
@@ -0,0 +1,150 @@
+/*
+ *  arch/s390/kernel/base.S
+ *
+ *    Copyright IBM Corp. 2006,2007
+ *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ *		 Michael Holzheu <holzheu@de.ibm.com>
+ */
+
+#include <asm/ptrace.h>
+#include <asm/lowcore.h>
+
+#ifdef CONFIG_64BIT
+
+	.globl	s390_base_mcck_handler
+s390_base_mcck_handler:
+	basr	%r13,0
+0:	lg	%r15,__LC_PANIC_STACK	# load panic stack
+	aghi	%r15,-STACK_FRAME_OVERHEAD
+	larl	%r1,s390_base_mcck_handler_fn
+	lg	%r1,0(%r1)
+	ltgr	%r1,%r1
+	jz	1f
+	basr	%r14,%r1
+1:	la	%r1,4095
+	lmg	%r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)
+	lpswe	__LC_MCK_OLD_PSW
+
+	.section .bss
+	.globl	s390_base_mcck_handler_fn
+s390_base_mcck_handler_fn:
+	.quad	0
+	.previous
+
+	.globl	s390_base_ext_handler
+s390_base_ext_handler:
+	stmg	%r0,%r15,__LC_SAVE_AREA
+	basr	%r13,0
+0:	aghi	%r15,-STACK_FRAME_OVERHEAD
+	larl	%r1,s390_base_ext_handler_fn
+	lg	%r1,0(%r1)
+	ltgr	%r1,%r1
+	jz	1f
+	basr	%r14,%r1
+1:	lmg	%r0,%r15,__LC_SAVE_AREA
+	ni	__LC_EXT_OLD_PSW+1,0xfd	# clear wait state bit
+	lpswe	__LC_EXT_OLD_PSW
+
+	.section .bss
+	.globl s390_base_ext_handler_fn
+s390_base_ext_handler_fn:
+	.quad	0
+	.previous
+
+	.globl	s390_base_pgm_handler
+s390_base_pgm_handler:
+	stmg	%r0,%r15,__LC_SAVE_AREA
+	basr	%r13,0
+0:	aghi	%r15,-STACK_FRAME_OVERHEAD
+	larl	%r1,s390_base_pgm_handler_fn
+	lg	%r1,0(%r1)
+	ltgr	%r1,%r1
+	jz	1f
+	basr	%r14,%r1
+	lmg	%r0,%r15,__LC_SAVE_AREA
+	lpswe	__LC_PGM_OLD_PSW
+1:	lpswe	disabled_wait_psw-0b(%r13)
+
+	.align	8
+disabled_wait_psw:
+	.quad	0x0002000180000000,0x0000000000000000 + s390_base_pgm_handler
+
+	.section .bss
+	.globl s390_base_pgm_handler_fn
+s390_base_pgm_handler_fn:
+	.quad	0
+	.previous
+
+#else /* CONFIG_64BIT */
+
+	.globl	s390_base_mcck_handler
+s390_base_mcck_handler:
+	basr	%r13,0
+0:	l	%r15,__LC_PANIC_STACK	# load panic stack
+	ahi	%r15,-STACK_FRAME_OVERHEAD
+	l	%r1,2f-0b(%r13)
+	l	%r1,0(%r1)
+	ltr	%r1,%r1
+	jz	1f
+	basr	%r14,%r1
+1:	lm	%r0,%r15,__LC_GPREGS_SAVE_AREA
+	lpsw	__LC_MCK_OLD_PSW
+
+2:	.long	s390_base_mcck_handler_fn
+
+	.section .bss
+	.globl	s390_base_mcck_handler_fn
+s390_base_mcck_handler_fn:
+	.long	0
+	.previous
+
+	.globl	s390_base_ext_handler
+s390_base_ext_handler:
+	stm	%r0,%r15,__LC_SAVE_AREA
+	basr	%r13,0
+0:	ahi	%r15,-STACK_FRAME_OVERHEAD
+	l	%r1,2f-0b(%r13)
+	l	%r1,0(%r1)
+	ltr	%r1,%r1
+	jz	1f
+	basr	%r14,%r1
+1:	lm	%r0,%r15,__LC_SAVE_AREA
+	ni	__LC_EXT_OLD_PSW+1,0xfd	# clear wait state bit
+	lpsw	__LC_EXT_OLD_PSW
+
+2:	.long	s390_base_ext_handler_fn
+
+	.section .bss
+	.globl	s390_base_ext_handler_fn
+s390_base_ext_handler_fn:
+	.long	0
+	.previous
+
+	.globl	s390_base_pgm_handler
+s390_base_pgm_handler:
+	stm	%r0,%r15,__LC_SAVE_AREA
+	basr	%r13,0
+0:	ahi	%r15,-STACK_FRAME_OVERHEAD
+	l	%r1,2f-0b(%r13)
+	l	%r1,0(%r1)
+	ltr	%r1,%r1
+	jz	1f
+	basr	%r14,%r1
+	lm	%r0,%r15,__LC_SAVE_AREA
+	lpsw	__LC_PGM_OLD_PSW
+
+1:	lpsw	disabled_wait_psw-0b(%r13)
+
+2:	.long	s390_base_pgm_handler_fn
+
+disabled_wait_psw:
+	.align	8
+	.long	0x000a0000,0x00000000 + s390_base_pgm_handler
+
+	.section .bss
+	.globl	s390_base_pgm_handler_fn
+s390_base_pgm_handler_fn:
+	.long	0
+	.previous
+
+#endif /* CONFIG_64BIT */
diff --git a/arch/s390/kernel/binfmt_elf32.c b/arch/s390/kernel/binfmt_elf32.c
index 5c46054..f1e40ca 100644
--- a/arch/s390/kernel/binfmt_elf32.c
+++ b/arch/s390/kernel/binfmt_elf32.c
@@ -192,7 +192,7 @@
 
 #undef cputime_to_timeval
 #define cputime_to_timeval cputime_to_compat_timeval
-static __inline__ void
+static inline void
 cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
 {
 	value->tv_usec = cputime % 1000000;
diff --git a/arch/s390/kernel/compat_exec_domain.c b/arch/s390/kernel/compat_exec_domain.c
index 71d27c4..914d494 100644
--- a/arch/s390/kernel/compat_exec_domain.c
+++ b/arch/s390/kernel/compat_exec_domain.c
@@ -12,10 +12,9 @@
 #include <linux/personality.h>
 #include <linux/sched.h>
 
-struct exec_domain s390_exec_domain;
+static struct exec_domain s390_exec_domain;
 
-static int __init
-s390_init (void)
+static int __init s390_init (void)
 {
 	s390_exec_domain.name = "Linux/s390";
 	s390_exec_domain.handler = NULL;
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index 5b33f82..666bb6d 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -69,6 +69,12 @@
 
 #include "compat_linux.h"
 
+long psw_user32_bits	= (PSW_BASE32_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
+			   PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+			   PSW_MASK_PSTATE | PSW_DEFAULT_KEY);
+long psw32_user_bits	= (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME |
+			   PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK |
+			   PSW32_MASK_PSTATE);
  
 /* For this source file, we want overflow handling. */
 
@@ -416,7 +422,7 @@
 	mm_segment_t old_fs = get_fs ();
 	
 	set_fs (KERNEL_DS);
-	ret = sys_sysinfo((struct sysinfo __user *) &s);
+	ret = sys_sysinfo((struct sysinfo __force __user *) &s);
 	set_fs (old_fs);
 	err = put_user (s.uptime, &info->uptime);
 	err |= __put_user (s.loads[0], &info->loads[0]);
@@ -445,7 +451,8 @@
 	mm_segment_t old_fs = get_fs ();
 	
 	set_fs (KERNEL_DS);
-	ret = sys_sched_rr_get_interval(pid, (struct timespec __user *) &t);
+	ret = sys_sched_rr_get_interval(pid,
+					(struct timespec __force __user *) &t);
 	set_fs (old_fs);
 	if (put_compat_timespec(&t, interval))
 		return -EFAULT;
@@ -472,8 +479,8 @@
 	}
 	set_fs (KERNEL_DS);
 	ret = sys_rt_sigprocmask(how,
-				 set ? (sigset_t __user *) &s : NULL,
-				 oset ? (sigset_t __user *) &s : NULL,
+				 set ? (sigset_t __force __user *) &s : NULL,
+				 oset ? (sigset_t __force __user *) &s : NULL,
 				 sigsetsize);
 	set_fs (old_fs);
 	if (ret) return ret;
@@ -499,7 +506,7 @@
 	mm_segment_t old_fs = get_fs();
 		
 	set_fs (KERNEL_DS);
-	ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize);
+	ret = sys_rt_sigpending((sigset_t __force __user *) &s, sigsetsize);
 	set_fs (old_fs);
 	if (!ret) {
 		switch (_NSIG_WORDS) {
@@ -524,7 +531,7 @@
 	if (copy_siginfo_from_user32(&info, uinfo))
 		return -EFAULT;
 	set_fs (KERNEL_DS);
-	ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info);
+	ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __force __user *) &info);
 	set_fs (old_fs);
 	return ret;
 }
@@ -682,7 +689,7 @@
 		
 	set_fs(KERNEL_DS);
 	ret = sys_sendfile(out_fd, in_fd,
-			   offset ? (off_t __user *) &of : NULL, count);
+			   offset ? (off_t __force __user *) &of : NULL, count);
 	set_fs(old_fs);
 	
 	if (offset && put_user(of, offset))
@@ -703,7 +710,8 @@
 		
 	set_fs(KERNEL_DS);
 	ret = sys_sendfile64(out_fd, in_fd,
-			     offset ? (loff_t __user *) &lof : NULL, count);
+			     offset ? (loff_t __force __user *) &lof : NULL,
+			     count);
 	set_fs(old_fs);
 	
 	if (offset && put_user(lof, offset))
diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h
index 1a18e29..e89f8c0 100644
--- a/arch/s390/kernel/compat_linux.h
+++ b/arch/s390/kernel/compat_linux.h
@@ -115,37 +115,6 @@
         __u32	addr;
 } _psw_t32 __attribute__ ((aligned(8)));
 
-#define PSW32_MASK_PER		0x40000000UL
-#define PSW32_MASK_DAT		0x04000000UL
-#define PSW32_MASK_IO		0x02000000UL
-#define PSW32_MASK_EXT		0x01000000UL
-#define PSW32_MASK_KEY		0x00F00000UL
-#define PSW32_MASK_MCHECK	0x00040000UL
-#define PSW32_MASK_WAIT		0x00020000UL
-#define PSW32_MASK_PSTATE	0x00010000UL
-#define PSW32_MASK_ASC		0x0000C000UL
-#define PSW32_MASK_CC		0x00003000UL
-#define PSW32_MASK_PM		0x00000f00UL
-
-#define PSW32_ADDR_AMODE31	0x80000000UL
-#define PSW32_ADDR_INSN		0x7FFFFFFFUL
-
-#define PSW32_BASE_BITS		0x00080000UL
-
-#define PSW32_ASC_PRIMARY	0x00000000UL
-#define PSW32_ASC_ACCREG	0x00004000UL
-#define PSW32_ASC_SECONDARY	0x00008000UL
-#define PSW32_ASC_HOME		0x0000C000UL
-
-#define PSW32_USER_BITS	(PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME | \
-			 PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | \
-			 PSW32_MASK_PSTATE)
-
-#define PSW32_MASK_MERGE(CURRENT,NEW) \
-        (((CURRENT) & ~(PSW32_MASK_CC|PSW32_MASK_PM)) | \
-         ((NEW) & (PSW32_MASK_CC|PSW32_MASK_PM)))
-
-
 typedef struct
 {
 	_psw_t32	psw;
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index 861888a..887a988 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -275,8 +275,8 @@
 	}
 
 	set_fs (KERNEL_DS);
-	ret = do_sigaltstack((stack_t __user *) (uss ? &kss : NULL),
-			     (stack_t __user *) (uoss ? &koss : NULL),
+	ret = do_sigaltstack((stack_t __force __user *) (uss ? &kss : NULL),
+			     (stack_t __force __user *) (uoss ? &koss : NULL),
 			     regs->gprs[15]);
 	set_fs (old_fs);
 
@@ -298,7 +298,7 @@
 	_s390_regs_common32 regs32;
 	int err, i;
 
-	regs32.psw.mask = PSW32_MASK_MERGE(PSW32_USER_BITS,
+	regs32.psw.mask = PSW32_MASK_MERGE(psw32_user_bits,
 					   (__u32)(regs->psw.mask >> 32));
 	regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr;
 	for (i = 0; i < NUM_GPRS; i++)
@@ -401,7 +401,7 @@
 		goto badframe; 
 
 	set_fs (KERNEL_DS);
-	do_sigaltstack((stack_t __user *)&st, NULL, regs->gprs[15]);
+	do_sigaltstack((stack_t __force __user *)&st, NULL, regs->gprs[15]);
 	set_fs (old_fs);
 
 	return regs->gprs[2];
diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c
index a5972f1..6c89f30 100644
--- a/arch/s390/kernel/cpcmd.c
+++ b/arch/s390/kernel/cpcmd.c
@@ -16,6 +16,7 @@
 #include <asm/ebcdic.h>
 #include <asm/cpcmd.h>
 #include <asm/system.h>
+#include <asm/io.h>
 
 static DEFINE_SPINLOCK(cpcmd_lock);
 static char cpcmd_buf[241];
@@ -88,13 +89,8 @@
 	int len;
 	unsigned long flags;
 
-	if ((rlen == 0) || (response == NULL)
-	    || !((unsigned long)response >> 31)) {
-		spin_lock_irqsave(&cpcmd_lock, flags);
-		len = __cpcmd(cmd, response, rlen, response_code);
-		spin_unlock_irqrestore(&cpcmd_lock, flags);
-	}
-	else {
+	if ((virt_to_phys(response) != (unsigned long) response) ||
+			(((unsigned long)response + rlen) >> 31)) {
 		lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA);
 		if (!lowbuf) {
 			printk(KERN_WARNING
@@ -106,6 +102,10 @@
 		spin_unlock_irqrestore(&cpcmd_lock, flags);
 		memcpy(response, lowbuf, rlen);
 		kfree(lowbuf);
+	} else {
+		spin_lock_irqsave(&cpcmd_lock, flags);
+		len = __cpcmd(cmd, response, rlen, response_code);
+		spin_unlock_irqrestore(&cpcmd_lock, flags);
 	}
 	return len;
 }
diff --git a/arch/s390/kernel/crash.c b/arch/s390/kernel/crash.c
index 926ccee..8cc7c9f 100644
--- a/arch/s390/kernel/crash.c
+++ b/arch/s390/kernel/crash.c
@@ -9,6 +9,7 @@
 
 #include <linux/threads.h>
 #include <linux/kexec.h>
+#include <linux/reboot.h>
 
 void machine_crash_shutdown(struct pt_regs *regs)
 {
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
index bb57bc0..f4b62df 100644
--- a/arch/s390/kernel/debug.c
+++ b/arch/s390/kernel/debug.c
@@ -120,7 +120,7 @@
 	NULL
 };
 
-struct debug_view debug_level_view = {
+static struct debug_view debug_level_view = {
 	"level",
 	&debug_prolog_level_fn,
 	NULL,
@@ -129,7 +129,7 @@
 	NULL
 };
 
-struct debug_view debug_pages_view = {
+static struct debug_view debug_pages_view = {
 	"pages",
 	&debug_prolog_pages_fn,
 	NULL,
@@ -138,7 +138,7 @@
 	NULL
 };
 
-struct debug_view debug_flush_view = {
+static struct debug_view debug_flush_view = {
         "flush",
         NULL,
         NULL,
@@ -156,14 +156,14 @@
 	NULL
 };
 
-
+/* used by dump analysis tools to determine version of debug feature */
 unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION;
 
 /* static globals */
 
 static debug_info_t *debug_area_first = NULL;
 static debug_info_t *debug_area_last = NULL;
-DECLARE_MUTEX(debug_lock);
+static DECLARE_MUTEX(debug_lock);
 
 static int initialized;
 
@@ -905,7 +905,7 @@
 	{ .ctl_name = 0 }
 };
 
-struct ctl_table_header *s390dbf_sysctl_header;
+static struct ctl_table_header *s390dbf_sysctl_header;
 
 void
 debug_stop_all(void)
@@ -1300,8 +1300,7 @@
  * flushes debug areas
  */
  
-void
-debug_flush(debug_info_t* id, int area)
+static void debug_flush(debug_info_t* id, int area)
 {
         unsigned long flags;
         int i,j;
@@ -1511,8 +1510,7 @@
 /*
  * clean up module
  */
-void
-__exit debug_exit(void)
+static void __exit debug_exit(void)
 {
 	debugfs_remove(debug_debugfs_root_entry);
 	unregister_sysctl_table(s390dbf_sysctl_header);
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
new file mode 100644
index 0000000..e518dd5
--- /dev/null
+++ b/arch/s390/kernel/early.c
@@ -0,0 +1,306 @@
+/*
+ *  arch/s390/kernel/early.c
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Hongjie Yang <hongjie@us.ibm.com>,
+ *		 Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/pfn.h>
+#include <linux/uaccess.h>
+#include <asm/lowcore.h>
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/setup.h>
+#include <asm/cpcmd.h>
+#include <asm/sclp.h>
+
+/*
+ * Create a Kernel NSS if the SAVESYS= parameter is defined
+ */
+#define DEFSYS_CMD_SIZE		96
+#define SAVESYS_CMD_SIZE	32
+
+char kernel_nss_name[NSS_NAME_SIZE + 1];
+
+#ifdef CONFIG_SHARED_KERNEL
+static noinline __init void create_kernel_nss(void)
+{
+	unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
+#ifdef CONFIG_BLK_DEV_INITRD
+	unsigned int sinitrd_pfn, einitrd_pfn;
+#endif
+	int response;
+	char *savesys_ptr;
+	char upper_command_line[COMMAND_LINE_SIZE];
+	char defsys_cmd[DEFSYS_CMD_SIZE];
+	char savesys_cmd[SAVESYS_CMD_SIZE];
+
+	/* Do nothing if we are not running under VM */
+	if (!MACHINE_IS_VM)
+		return;
+
+	/* Convert COMMAND_LINE to upper case */
+	for (i = 0; i < strlen(COMMAND_LINE); i++)
+		upper_command_line[i] = toupper(COMMAND_LINE[i]);
+
+	savesys_ptr = strstr(upper_command_line, "SAVESYS=");
+
+	if (!savesys_ptr)
+		return;
+
+	savesys_ptr += 8;    /* Point to the beginning of the NSS name */
+	for (i = 0; i < NSS_NAME_SIZE; i++) {
+		if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0')
+			break;
+		kernel_nss_name[i] = savesys_ptr[i];
+	}
+
+	stext_pfn = PFN_DOWN(__pa(&_stext));
+	eshared_pfn = PFN_DOWN(__pa(&_eshared));
+	end_pfn = PFN_UP(__pa(&_end));
+	min_size = end_pfn << 2;
+
+	sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X",
+		kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1,
+		eshared_pfn, end_pfn);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (INITRD_START && INITRD_SIZE) {
+		sinitrd_pfn = PFN_DOWN(__pa(INITRD_START));
+		einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE));
+		min_size = einitrd_pfn << 2;
+		sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd,
+		sinitrd_pfn, einitrd_pfn);
+	}
+#endif
+
+	sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK", defsys_cmd, min_size);
+	sprintf(savesys_cmd, "SAVESYS %s \n IPL %s",
+		kernel_nss_name, kernel_nss_name);
+
+	__cpcmd(defsys_cmd, NULL, 0, &response);
+
+	if (response != 0)
+		return;
+
+	__cpcmd(savesys_cmd, NULL, 0, &response);
+
+	if (response != strlen(savesys_cmd))
+		return;
+
+	ipl_flags = IPL_NSS_VALID;
+}
+
+#else /* CONFIG_SHARED_KERNEL */
+
+static inline void create_kernel_nss(void) { }
+
+#endif /* CONFIG_SHARED_KERNEL */
+
+/*
+ * Clear bss memory
+ */
+static noinline __init void clear_bss_section(void)
+{
+	memset(__bss_start, 0, _end - __bss_start);
+}
+
+/*
+ * Initialize storage key for kernel pages
+ */
+static noinline __init void init_kernel_storage_key(void)
+{
+	unsigned long end_pfn, init_pfn;
+
+	end_pfn = PFN_UP(__pa(&_end));
+
+	for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++)
+		page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
+}
+
+static noinline __init void detect_machine_type(void)
+{
+	struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data;
+
+	asm volatile("stidp %0" : "=m" (S390_lowcore.cpu_data.cpu_id));
+
+	/* Running under z/VM ? */
+	if (cpuinfo->cpu_id.version == 0xff)
+		machine_flags |= 1;
+
+	/* Running on a P/390 ? */
+	if (cpuinfo->cpu_id.machine == 0x7490)
+		machine_flags |= 4;
+}
+
+static noinline __init int memory_fast_detect(void)
+{
+
+	unsigned long val0 = 0;
+	unsigned long val1 = 0xc;
+	int ret = -ENOSYS;
+
+	if (ipl_flags & IPL_NSS_VALID)
+		return -ENOSYS;
+
+	asm volatile(
+		"	diag	%1,%2,0x260\n"
+		"0:	lhi	%0,0\n"
+		"1:\n"
+		EX_TABLE(0b,1b)
+		: "+d" (ret), "+d" (val0), "+d" (val1) : : "cc");
+
+	if (ret || val0 != val1)
+		return -ENOSYS;
+
+	memory_chunk[0].size = val0;
+	return 0;
+}
+
+#define ADDR2G	(1UL << 31)
+
+static noinline __init unsigned long sclp_memory_detect(void)
+{
+	struct sclp_readinfo_sccb *sccb;
+	unsigned long long memsize;
+
+	sccb = &s390_readinfo_sccb;
+
+	if (sccb->header.response_code != 0x10)
+		return 0;
+
+	if (sccb->rnsize)
+		memsize = sccb->rnsize << 20;
+	else
+		memsize = sccb->rnsize2 << 20;
+	if (sccb->rnmax)
+		memsize *= sccb->rnmax;
+	else
+		memsize *= sccb->rnmax2;
+#ifndef CONFIG_64BIT
+	/*
+	 * Can't deal with more than 2G in 31 bit addressing mode, so
+	 * limit the value in order to avoid strange side effects.
+	 */
+	if (memsize > ADDR2G)
+		memsize = ADDR2G;
+#endif
+	return (unsigned long) memsize;
+}
+
+static inline __init unsigned long __tprot(unsigned long addr)
+{
+	int cc = -1;
+
+	asm volatile(
+		"	tprot	0(%1),0\n"
+		"0:	ipm	%0\n"
+		"	srl	%0,28\n"
+		"1:\n"
+		EX_TABLE(0b,1b)
+		: "+d" (cc) : "a" (addr) : "cc");
+	return (unsigned long)cc;
+}
+
+/* Checking memory in 128KB increments. */
+#define CHUNK_INCR	(1UL << 17)
+
+static noinline __init void find_memory_chunks(unsigned long memsize)
+{
+	unsigned long addr = 0, old_addr = 0;
+	unsigned long old_cc = CHUNK_READ_WRITE;
+	unsigned long cc;
+	int chunk = 0;
+
+	while (chunk < MEMORY_CHUNKS) {
+		cc = __tprot(addr);
+		while (cc == old_cc) {
+			addr += CHUNK_INCR;
+			cc = __tprot(addr);
+#ifndef CONFIG_64BIT
+			if (addr == ADDR2G)
+				break;
+#endif
+		}
+
+		if (old_addr != addr &&
+		    (old_cc == CHUNK_READ_WRITE || old_cc == CHUNK_READ_ONLY)) {
+			memory_chunk[chunk].addr = old_addr;
+			memory_chunk[chunk].size = addr - old_addr;
+			memory_chunk[chunk].type = old_cc;
+			chunk++;
+		}
+
+		old_addr = addr;
+		old_cc = cc;
+
+#ifndef CONFIG_64BIT
+		if (addr == ADDR2G)
+			break;
+#endif
+		/*
+		 * Finish memory detection at the first hole, unless
+		 * - we reached the hsa -> skip it.
+		 * - we know there must be more.
+		 */
+		if (cc == -1UL && !memsize && old_addr != ADDR2G)
+			break;
+		if (memsize && addr >= memsize)
+			break;
+	}
+}
+
+static __init void early_pgm_check_handler(void)
+{
+	unsigned long addr;
+	const struct exception_table_entry *fixup;
+
+	addr = S390_lowcore.program_old_psw.addr;
+	fixup = search_exception_tables(addr & PSW_ADDR_INSN);
+	if (!fixup)
+		disabled_wait(0);
+	S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE;
+}
+
+static noinline __init void setup_lowcore_early(void)
+{
+	psw_t psw;
+
+	psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
+	psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_ext_handler;
+	S390_lowcore.external_new_psw = psw;
+	psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
+	S390_lowcore.program_new_psw = psw;
+	s390_base_pgm_handler_fn = early_pgm_check_handler;
+}
+
+/*
+ * Save ipl parameters, clear bss memory, initialize storage keys
+ * and create a kernel NSS at startup if the SAVESYS= parm is defined
+ */
+void __init startup_init(void)
+{
+	unsigned long memsize;
+
+	ipl_save_parameters();
+	clear_bss_section();
+	init_kernel_storage_key();
+	lockdep_init();
+	lockdep_off();
+	detect_machine_type();
+	create_kernel_nss();
+	sort_main_extable();
+	setup_lowcore_early();
+	sclp_readinfo_early();
+	memsize = sclp_memory_detect();
+	if (memory_fast_detect() < 0)
+		find_memory_chunks(memsize);
+	lockdep_on();
+}
diff --git a/arch/s390/kernel/ebcdic.c b/arch/s390/kernel/ebcdic.c
index bb0f973..cc0dc60 100644
--- a/arch/s390/kernel/ebcdic.c
+++ b/arch/s390/kernel/ebcdic.c
@@ -11,6 +11,7 @@
 
 #include <linux/module.h>
 #include <asm/types.h>
+#include <asm/ebcdic.h>
 
 /*
  * ASCII (IBM PC 437)  -> EBCDIC 037
diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S
index eca5070..453fd3b 100644
--- a/arch/s390/kernel/head31.S
+++ b/arch/s390/kernel/head31.S
@@ -51,176 +51,15 @@
 	st	%r15,__LC_KERNEL_STACK	# set end of kernel stack
 	ahi	%r15,-96
 	xc	__SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
-
-	l	%r14,.Lipl_save_parameters-.LPG1(%r13)
+#
+# Save ipl parameters, clear bss memory, initialize storage key for kernel pages,
+# and create a kernel NSS if the SAVESYS= parm is defined
+#
+	l	%r14,.Lstartup_init-.LPG1(%r13)
 	basr	%r14,%r14
-#
-# clear bss memory
-#
-	l	%r2,.Lbss_bgn-.LPG1(%r13) # start of bss
-	l	%r3,.Lbss_end-.LPG1(%r13) # end of bss
-	sr	%r3,%r2			# length of bss
-	sr	%r4,%r4
-	sr	%r5,%r5			# set src,length and pad to zero
-	sr	%r0,%r0
-	mvcle	%r2,%r4,0		# clear mem
-	jo	.-4			# branch back, if not finish
 
-	l	%r2,.Lrcp-.LPG1(%r13)	# Read SCP forced command word
-.Lservicecall:
-	stosm	.Lpmask-.LPG1(%r13),0x01	# authorize ext interrupts
-
-	stctl	%r0, %r0,.Lcr-.LPG1(%r13)	# get cr0
-	la	%r1,0x200		# set bit 22
-	o	%r1,.Lcr-.LPG1(%r13)	# or old cr0 with r1
-	st	%r1,.Lcr-.LPG1(%r13)
-	lctl	%r0, %r0,.Lcr-.LPG1(%r13)	# load modified cr0
-
-	mvc	__LC_EXT_NEW_PSW(8),.Lpcext-.LPG1(%r13) # set postcall psw
-	la	%r1, .Lsclph-.LPG1(%r13)
-	a	%r1,__LC_EXT_NEW_PSW+4	# set handler
-	st	%r1,__LC_EXT_NEW_PSW+4
-
-	l	%r4,.Lsccbaddr-.LPG1(%r13) # %r4 is our index for sccb stuff
-	lr	%r1,%r4			# our sccb
-	.insn	rre,0xb2200000,%r2,%r1	# service call
-	ipm	%r1
-	srl	%r1,28			# get cc code
-	xr	%r3, %r3
-	chi	%r1,3
-	be	.Lfchunk-.LPG1(%r13)	# leave
-	chi	%r1,2
-	be	.Lservicecall-.LPG1(%r13)
-	lpsw	.Lwaitsclp-.LPG1(%r13)
-.Lsclph:
-	lh	%r1,.Lsccbr-.Lsccb(%r4)
-	chi	%r1,0x10		# 0x0010 is the sucess code
-	je	.Lprocsccb		# let's process the sccb
-	chi	%r1,0x1f0
-	bne	.Lfchunk-.LPG1(%r13)	# unhandled error code
-	c	%r2, .Lrcp-.LPG1(%r13)	# Did we try Read SCP forced
-	bne	.Lfchunk-.LPG1(%r13)	# if no, give up
-	l	%r2, .Lrcp2-.LPG1(%r13)	# try with Read SCP
-	b	.Lservicecall-.LPG1(%r13)
-.Lprocsccb:
-	lhi	%r1,0
-	icm	%r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0
-	jnz	.Lscnd
-	lhi	%r1,0x800		# otherwise report 2GB
-.Lscnd:
-	lhi	%r3,0x800		# limit reported memory size to 2GB
-	cr	%r1,%r3
-	jl	.Lno2gb
-	lr	%r1,%r3
-.Lno2gb:
-	xr	%r3,%r3			# same logic
-	ic	%r3,.Lscpa1-.Lsccb(%r4)
-	chi	%r3,0x00
-	jne	.Lcompmem
-	l	%r3,.Lscpa2-.Lsccb(%r4)
-.Lcompmem:
-	mr	%r2,%r1			# mem in MB on 128-bit
-	l	%r1,.Lonemb-.LPG1(%r13)
-	mr	%r2,%r1			# mem size in bytes in %r3
-	b	.Lfchunk-.LPG1(%r13)
-
-	.align 4
-.Lipl_save_parameters:
-	.long	ipl_save_parameters
-.Linittu:
-	.long	init_thread_union
-.Lpmask:
-	.byte	0
-	.align	8
-.Lpcext:.long	0x00080000,0x80000000
-.Lcr:
-	.long	0x00			# place holder for cr0
-	.align	8
-.Lwaitsclp:
-	.long 0x010a0000,0x80000000 + .Lsclph
-.Lrcp:
-	.int	0x00120001		# Read SCP forced code
-.Lrcp2:
-	.int	0x00020001		# Read SCP code
-.Lonemb:
-	.int	0x100000
-.Lfchunk:
-
-#
-# find memory chunks.
-#
-	lr	%r9,%r3			# end of mem
-	mvc	__LC_PGM_NEW_PSW(8),.Lpcmem-.LPG1(%r13)
-	la	%r1,1			# test in increments of 128KB
-	sll	%r1,17
-	l	%r3,.Lmchunk-.LPG1(%r13) # get pointer to memory_chunk array
-	slr	%r4,%r4			# set start of chunk to zero
-	slr	%r5,%r5			# set end of chunk to zero
-	slr	%r6,%r6			# set access code to zero
-	la	%r10,MEMORY_CHUNKS	# number of chunks
-.Lloop:
-	tprot	0(%r5),0		# test protection of first byte
-	ipm	%r7
-	srl	%r7,28
-	clr	%r6,%r7			# compare cc with last access code
-	be	.Lsame-.LPG1(%r13)
-	lhi	%r8,0			# no program checks
-	b	.Lsavchk-.LPG1(%r13)
-.Lsame:
-	ar	%r5,%r1			# add 128KB to end of chunk
-	bno	.Lloop-.LPG1(%r13)	# r1 < 0x80000000 -> loop
-.Lchkmem:				# > 2GB or tprot got a program check
-	lhi	%r8,1			# set program check flag
-.Lsavchk:
-	clr	%r4,%r5			# chunk size > 0?
-	be	.Lchkloop-.LPG1(%r13)
-	st	%r4,0(%r3)		# store start address of chunk
-	lr	%r0,%r5
-	slr	%r0,%r4
-	st	%r0,4(%r3)		# store size of chunk
-	st	%r6,8(%r3)		# store type of chunk
-	la	%r3,12(%r3)
-	ahi	%r10,-1			# update chunk number
-.Lchkloop:
-	lr	%r6,%r7			# set access code to last cc
-	# we got an exception or we're starting a new
-	# chunk , we must check if we should
-	# still try to find valid memory (if we detected
-	# the amount of available storage), and if we
-	# have chunks left
-	xr	%r0,%r0
-	clr	%r0,%r9			# did we detect memory?
-	je	.Ldonemem		# if not, leave
-	chi	%r10,0			# do we have chunks left?
-	je	.Ldonemem
-	chi	%r8,1			# program check ?
-	je	.Lpgmchk
-	lr	%r4,%r5			# potential new chunk
-	alr	%r5,%r1			# add 128KB to end of chunk
-	j	.Llpcnt
-.Lpgmchk:
-	alr	%r5,%r1			# add 128KB to end of chunk
-	lr	%r4,%r5			# potential new chunk
-.Llpcnt:
-	clr	%r5,%r9			# should we go on?
-	jl	.Lloop
-.Ldonemem:
 	l	%r12,.Lmflags-.LPG1(%r13) # get address of machine_flags
 #
-# find out if we are running under VM
-#
-	stidp	__LC_CPUID		# store cpuid
-	tm	__LC_CPUID,0xff		# running under VM ?
-	bno	.Lnovm-.LPG1(%r13)
-	oi	3(%r12),1		# set VM flag
-.Lnovm:
-	lh	%r0,__LC_CPUID+4	# get cpu version
-	chi	%r0,0x7490		# running on a P/390 ?
-	bne	.Lnop390-.LPG1(%r13)
-	oi	3(%r12),4		# set P/390 flag
-.Lnop390:
-
-#
 # find out if we have an IEEE fpu
 #
 	mvc	__LC_PGM_NEW_PSW(8),.Lpcfpu-.LPG1(%r13)
@@ -295,7 +134,6 @@
 	.long	0			# cr15: linkage stack operations
 .Lduct:	.long	0,0,0,0,0,0,0,0
 	.long	0,0,0,0,0,0,0,0
-.Lpcmem:.long	0x00080000,0x80000000 + .Lchkmem
 .Lpcfpu:.long	0x00080000,0x80000000 + .Lchkfpu
 .Lpccsp:.long	0x00080000,0x80000000 + .Lchkcsp
 .Lpcmvpg:.long	0x00080000,0x80000000 + .Lchkmvpg
@@ -306,7 +144,9 @@
 .Lbss_bgn:  .long __bss_start
 .Lbss_end:  .long _end
 .Lparmaddr: .long PARMAREA
-.Lsccbaddr: .long .Lsccb
+.Linittu:   .long init_thread_union
+.Lstartup_init:
+	    .long startup_init
 
 	.globl ipl_schib
 ipl_schib:
@@ -322,26 +162,6 @@
 	.word 0
 
 	.org	0x12000
-.globl s390_readinfo_sccb
-s390_readinfo_sccb:
-.Lsccb:
-	.hword	0x1000			# length, one page
-	.byte	0x00,0x00,0x00
-	.byte	0x80			# variable response bit set
-.Lsccbr:
-	.hword	0x00			# response code
-.Lscpincr1:
-	.hword	0x00
-.Lscpa1:
-	.byte	0x00
-	.fill	89,1,0
-.Lscpa2:
-	.int	0x00
-.Lscpincr2:
-	.quad	0x00
-	.fill	3984,1,0
-	.org	0x13000
-
 #ifdef CONFIG_SHARED_KERNEL
 	.org	0x100000
 #endif
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
index 6ba3f45..b8fec4e 100644
--- a/arch/s390/kernel/head64.S
+++ b/arch/s390/kernel/head64.S
@@ -58,183 +58,15 @@
 	stg	%r15,__LC_KERNEL_STACK	# set end of kernel stack
 	aghi	%r15,-160
 	xc	__SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
-
-	brasl	%r14,ipl_save_parameters
 #
-# clear bss memory
+# Save ipl parameters, clear bss memory, initialize storage key for kernel pages,
+# and create a kernel NSS if the SAVESYS= parm is defined
 #
-	larl	%r2,__bss_start 	# start of bss segment
-	larl	%r3,_end		# end of bss segment
-	sgr	%r3,%r2 		# length of bss
-	sgr	%r4,%r4 		#
-	sgr	%r5,%r5 		# set src,length and pad to zero
-	mvcle	%r2,%r4,0		# clear mem
-	jo	.-4			# branch back, if not finish
+	brasl	%r14,startup_init
 					# set program check new psw mask
 	mvc	__LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
-	larl	%r1,.Lslowmemdetect	# set program check address
-	stg	%r1,__LC_PGM_NEW_PSW+8
-	lghi	%r1,0xc
-	diag	%r0,%r1,0x260		# get memory size of virtual machine
-	cgr	%r0,%r1			# different? -> old detection routine
-	jne	.Lslowmemdetect
-	aghi	%r1,1			# size is one more than end
-	larl	%r2,memory_chunk
-	stg	%r1,8(%r2)		# store size of chunk
-	j	.Ldonemem
-
-.Lslowmemdetect:
-	l	%r2,.Lrcp-.LPG1(%r13)	# Read SCP forced command word
-.Lservicecall:
-	stosm	.Lpmask-.LPG1(%r13),0x01	# authorize ext interrupts
-
-	stctg	%r0,%r0,.Lcr-.LPG1(%r13)	# get cr0
-	la	%r1,0x200		# set bit 22
-	og	%r1,.Lcr-.LPG1(%r13)	# or old cr0 with r1
-	stg	%r1,.Lcr-.LPG1(%r13)
-	lctlg	%r0,%r0,.Lcr-.LPG1(%r13)	# load modified cr0
-
-	mvc	__LC_EXT_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) # set postcall psw
-	larl	%r1,.Lsclph
-	stg	%r1,__LC_EXT_NEW_PSW+8	# set handler
-
-	larl	%r4,.Lsccb		# %r4 is our index for sccb stuff
-	lgr	%r1,%r4			# our sccb
-	.insn	rre,0xb2200000,%r2,%r1	# service call
-	ipm	%r1
-	srl	%r1,28			# get cc code
-	xr	%r3,%r3
-	chi	%r1,3
-	be	.Lfchunk-.LPG1(%r13)	# leave
-	chi	%r1,2
-	be	.Lservicecall-.LPG1(%r13)
-	lpswe	.Lwaitsclp-.LPG1(%r13)
-.Lsclph:
-	lh	%r1,.Lsccbr-.Lsccb(%r4)
-	chi	%r1,0x10		# 0x0010 is the sucess code
-	je	.Lprocsccb		# let's process the sccb
-	chi	%r1,0x1f0
-	bne	.Lfchunk-.LPG1(%r13)	# unhandled error code
-	c	%r2,.Lrcp-.LPG1(%r13)	# Did we try Read SCP forced
-	bne	.Lfchunk-.LPG1(%r13)	# if no, give up
-	l	%r2,.Lrcp2-.LPG1(%r13)	# try with Read SCP
-	b	.Lservicecall-.LPG1(%r13)
-.Lprocsccb:
-	lghi	%r1,0
-	icm	%r1,3,.Lscpincr1-.Lsccb(%r4)	# use this one if != 0
-	jnz	.Lscnd
-	lg	%r1,.Lscpincr2-.Lsccb(%r4)	# otherwise use this one
-.Lscnd:
-	xr	%r3,%r3			# same logic
-	ic	%r3,.Lscpa1-.Lsccb(%r4)
-	chi	%r3,0x00
-	jne	.Lcompmem
-	l	%r3,.Lscpa2-.Lsccb(%r4)
-.Lcompmem:
-	mlgr	%r2,%r1			# mem in MB on 128-bit
-	l	%r1,.Lonemb-.LPG1(%r13)
-	mlgr	%r2,%r1			# mem size in bytes in %r3
-	b	.Lfchunk-.LPG1(%r13)
-
-	.align	4
-.Lpmask:
-	.byte	0
-	.align	8
-.Lcr:
-	.quad	0x00  # place holder for cr0
-.Lwaitsclp:
-	.quad	0x0102000180000000,.Lsclph
-.Lrcp:
-	.int	0x00120001 # Read SCP forced code
-.Lrcp2:
-	.int	0x00020001 # Read SCP code
-.Lonemb:
-	.int	0x100000
-
-.Lfchunk:
-
-#
-# find memory chunks.
-#
-	lgr	%r9,%r3			# end of mem
-	larl	%r1,.Lchkmem		# set program check address
-	stg	%r1,__LC_PGM_NEW_PSW+8
-	la	%r1,1			# test in increments of 128KB
-	sllg	%r1,%r1,17
-	larl	%r3,memory_chunk
-	slgr	%r4,%r4 		# set start of chunk to zero
-	slgr	%r5,%r5 		# set end of chunk to zero
-	slr	%r6,%r6			# set access code to zero
-	la	%r10,MEMORY_CHUNKS	# number of chunks
-.Lloop:
-	tprot	0(%r5),0		# test protection of first byte
-	ipm	%r7
-	srl	%r7,28
-	clr	%r6,%r7			# compare cc with last access code
-	je	.Lsame
-	lghi	%r8,0			# no program checks
-	j	.Lsavchk
-.Lsame:
-	algr	%r5,%r1			# add 128KB to end of chunk
-					# no need to check here,
-	brc	12,.Lloop		# this is the same chunk
-.Lchkmem:				# > 16EB or tprot got a program check
-	lghi	%r8,1			# set program check flag
-.Lsavchk:
-	clgr	%r4,%r5			# chunk size > 0?
-	je	.Lchkloop
-	stg	%r4,0(%r3)		# store start address of chunk
-	lgr	%r0,%r5
-	slgr	%r0,%r4
-	stg	%r0,8(%r3)		# store size of chunk
-	st	%r6,20(%r3)		# store type of chunk
-	la	%r3,24(%r3)
-	ahi	%r10,-1			# update chunk number
-.Lchkloop:
-	lr	%r6,%r7			# set access code to last cc
-	# we got an exception or we're starting a new
-	# chunk , we must check if we should
-	# still try to find valid memory (if we detected
-	# the amount of available storage), and if we
-	# have chunks left
-	lghi	%r4,1
-	sllg	%r4,%r4,31
-	clgr	%r5,%r4
-	je	.Lhsaskip
-	xr	%r0, %r0
-	clgr	%r0, %r9		# did we detect memory?
-	je	.Ldonemem		# if not, leave
-	chi	%r10, 0			# do we have chunks left?
-	je	.Ldonemem
-.Lhsaskip:
-	chi	%r8,1			# program check ?
-	je	.Lpgmchk
-	lgr	%r4,%r5			# potential new chunk
-	algr	%r5,%r1			# add 128KB to end of chunk
-	j	.Llpcnt
-.Lpgmchk:
-	algr	%r5,%r1			# add 128KB to end of chunk
-	lgr	%r4,%r5			# potential new chunk
-.Llpcnt:
-	clgr	%r5,%r9			# should we go on?
-	jl	.Lloop
-.Ldonemem:
-
 	larl	%r12,machine_flags
 #
-# find out if we are running under VM
-#
-	stidp	__LC_CPUID		# store cpuid
-	tm	__LC_CPUID,0xff 	# running under VM ?
-	bno	0f-.LPG1(%r13)
-	oi	7(%r12),1		# set VM flag
-0:	lh	%r0,__LC_CPUID+4	# get cpu version
-	chi	%r0,0x7490		# running on a P/390 ?
-	bne	1f-.LPG1(%r13)
-	oi	7(%r12),4		# set P/390 flag
-1:
-
-#
 # find out if we have the MVPG instruction
 #
 	la	%r1,0f-.LPG1(%r13)	# set program check address
@@ -336,25 +168,6 @@
 	.word 0
 
 	.org	0x12000
-.globl s390_readinfo_sccb
-s390_readinfo_sccb:
-.Lsccb:
-	.hword	0x1000			# length, one page
-	.byte	0x00,0x00,0x00
-	.byte	0x80			# variable response bit set
-.Lsccbr:
-	.hword	0x00			# response code
-.Lscpincr1:
-	.hword	0x00
-.Lscpa1:
-	.byte	0x00
-	.fill	89,1,0
-.Lscpa2:
-	.int	0x00
-.Lscpincr2:
-	.quad	0x00
-	.fill	3984,1,0
-	.org	0x13000
 
 #ifdef CONFIG_SHARED_KERNEL
 	.org	0x100000
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 9e9972e..0522595 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -20,26 +20,27 @@
 #include <asm/cio.h>
 #include <asm/ebcdic.h>
 #include <asm/reset.h>
+#include <asm/sclp.h>
 
 #define IPL_PARM_BLOCK_VERSION 0
-#define LOADPARM_LEN 8
 
-extern char s390_readinfo_sccb[];
-#define SCCB_VALID (*((__u16*)&s390_readinfo_sccb[6]) == 0x0010)
-#define SCCB_LOADPARM (&s390_readinfo_sccb[24])
-#define SCCB_FLAG (s390_readinfo_sccb[91])
+#define SCCB_VALID (s390_readinfo_sccb.header.response_code == 0x10)
+#define SCCB_LOADPARM (&s390_readinfo_sccb.loadparm)
+#define SCCB_FLAG (s390_readinfo_sccb.flags)
 
 enum ipl_type {
 	IPL_TYPE_NONE	 = 1,
 	IPL_TYPE_UNKNOWN = 2,
 	IPL_TYPE_CCW	 = 4,
 	IPL_TYPE_FCP	 = 8,
+	IPL_TYPE_NSS	 = 16,
 };
 
 #define IPL_NONE_STR	 "none"
 #define IPL_UNKNOWN_STR  "unknown"
 #define IPL_CCW_STR	 "ccw"
 #define IPL_FCP_STR	 "fcp"
+#define IPL_NSS_STR	 "nss"
 
 static char *ipl_type_str(enum ipl_type type)
 {
@@ -50,6 +51,8 @@
 		return IPL_CCW_STR;
 	case IPL_TYPE_FCP:
 		return IPL_FCP_STR;
+	case IPL_TYPE_NSS:
+		return IPL_NSS_STR;
 	case IPL_TYPE_UNKNOWN:
 	default:
 		return IPL_UNKNOWN_STR;
@@ -64,6 +67,7 @@
 	IPL_METHOD_FCP_RO_DIAG,
 	IPL_METHOD_FCP_RW_DIAG,
 	IPL_METHOD_FCP_RO_VM,
+	IPL_METHOD_NSS,
 };
 
 enum shutdown_action {
@@ -114,11 +118,14 @@
 static int diag308_set_works = 0;
 
 static int reipl_capabilities = IPL_TYPE_UNKNOWN;
+
 static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
 static enum ipl_method reipl_method = IPL_METHOD_NONE;
 static struct ipl_parameter_block *reipl_block_fcp;
 static struct ipl_parameter_block *reipl_block_ccw;
 
+static char reipl_nss_name[NSS_NAME_SIZE + 1];
+
 static int dump_capabilities = IPL_TYPE_NONE;
 static enum ipl_type dump_type = IPL_TYPE_NONE;
 static enum ipl_method dump_method = IPL_METHOD_NONE;
@@ -173,6 +180,24 @@
 			sys_##_prefix##_##_name##_show,			\
 			sys_##_prefix##_##_name##_store);
 
+#define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\
+static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys,	\
+		char *page)						\
+{									\
+	return sprintf(page, _fmt_out, _value);				\
+}									\
+static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\
+		const char *buf, size_t len)				\
+{									\
+	if (sscanf(buf, _fmt_in, _value) != 1)				\
+		return -EINVAL;						\
+	return len;							\
+}									\
+static struct subsys_attribute sys_##_prefix##_##_name##_attr =		\
+	__ATTR(_name,(S_IRUGO | S_IWUSR),				\
+			sys_##_prefix##_##_name##_show,			\
+			sys_##_prefix##_##_name##_store);
+
 static void make_attrs_ro(struct attribute **attrs)
 {
 	while (*attrs) {
@@ -189,6 +214,8 @@
 {
 	struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
 
+	if (ipl_flags & IPL_NSS_VALID)
+		return IPL_TYPE_NSS;
 	if (!(ipl_flags & IPL_DEVNO_VALID))
 		return IPL_TYPE_UNKNOWN;
 	if (!(ipl_flags & IPL_PARMBLOCK_VALID))
@@ -324,6 +351,20 @@
 	.attrs = ipl_ccw_attrs,
 };
 
+/* NSS ipl device attributes */
+
+DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name);
+
+static struct attribute *ipl_nss_attrs[] = {
+	&sys_ipl_type_attr.attr,
+	&sys_ipl_nss_name_attr.attr,
+	NULL,
+};
+
+static struct attribute_group ipl_nss_attr_group = {
+	.attrs = ipl_nss_attrs,
+};
+
 /* UNKNOWN ipl device attributes */
 
 static struct attribute *ipl_unknown_attrs[] = {
@@ -432,6 +473,21 @@
 	.attrs = reipl_ccw_attrs,
 };
 
+
+/* NSS reipl device attributes */
+
+DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name);
+
+static struct attribute *reipl_nss_attrs[] = {
+	&sys_reipl_nss_name_attr.attr,
+	NULL,
+};
+
+static struct attribute_group reipl_nss_attr_group = {
+	.name  = IPL_NSS_STR,
+	.attrs = reipl_nss_attrs,
+};
+
 /* reipl type */
 
 static int reipl_set_type(enum ipl_type type)
@@ -454,6 +510,9 @@
 		else
 			reipl_method = IPL_METHOD_FCP_RO_DIAG;
 		break;
+	case IPL_TYPE_NSS:
+		reipl_method = IPL_METHOD_NSS;
+		break;
 	default:
 		reipl_method = IPL_METHOD_NONE;
 	}
@@ -475,6 +534,8 @@
 		rc = reipl_set_type(IPL_TYPE_CCW);
 	else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
 		rc = reipl_set_type(IPL_TYPE_FCP);
+	else if (strncmp(buf, IPL_NSS_STR, strlen(IPL_NSS_STR)) == 0)
+		rc = reipl_set_type(IPL_TYPE_NSS);
 	return (rc != 0) ? rc : len;
 }
 
@@ -647,6 +708,10 @@
 	case IPL_METHOD_FCP_RO_VM:
 		__cpcmd("IPL", NULL, 0, NULL);
 		break;
+	case IPL_METHOD_NSS:
+		sprintf(buf, "IPL %s", reipl_nss_name);
+		__cpcmd(buf, NULL, 0, NULL);
+		break;
 	case IPL_METHOD_NONE:
 	default:
 		if (MACHINE_IS_VM)
@@ -733,6 +798,10 @@
 	case IPL_TYPE_FCP:
 		rc = ipl_register_fcp_files();
 		break;
+	case IPL_TYPE_NSS:
+		rc = sysfs_create_group(&ipl_subsys.kset.kobj,
+					&ipl_nss_attr_group);
+		break;
 	default:
 		rc = sysfs_create_group(&ipl_subsys.kset.kobj,
 					&ipl_unknown_attr_group);
@@ -755,6 +824,20 @@
 	free_page((unsigned long)buffer);
 }
 
+static int __init reipl_nss_init(void)
+{
+	int rc;
+
+	if (!MACHINE_IS_VM)
+		return 0;
+	rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_nss_attr_group);
+	if (rc)
+		return rc;
+	strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
+	reipl_capabilities |= IPL_TYPE_NSS;
+	return 0;
+}
+
 static int __init reipl_ccw_init(void)
 {
 	int rc;
@@ -837,6 +920,9 @@
 	rc = reipl_fcp_init();
 	if (rc)
 		return rc;
+	rc = reipl_nss_init();
+	if (rc)
+		return rc;
 	rc = reipl_set_type(ipl_get_type());
 	if (rc)
 		return rc;
@@ -993,8 +1079,6 @@
 		reset->fn();
 }
 
-extern void reset_mcck_handler(void);
-extern void reset_pgm_handler(void);
 extern __u32 dump_prefix_page;
 
 void s390_reset_system(void)
@@ -1016,14 +1100,14 @@
 	__ctl_clear_bit(0,28);
 
 	/* Set new machine check handler */
-	S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK;
+	S390_lowcore.mcck_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
 	S390_lowcore.mcck_new_psw.addr =
-		PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler;
+		PSW_ADDR_AMODE | (unsigned long) s390_base_mcck_handler;
 
 	/* Set new program check handler */
-	S390_lowcore.program_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK;
+	S390_lowcore.program_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
 	S390_lowcore.program_new_psw.addr =
-		PSW_ADDR_AMODE | (unsigned long) &reset_pgm_handler;
+		PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
 
 	do_reset_calls();
 }
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index 1eef509..8f0cbca 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -1,9 +1,9 @@
 /*
  *  arch/s390/kernel/irq.c
  *
- *  S390 version
- *    Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright IBM Corp. 2004,2007
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *		 Thomas Spatzier (tspat@de.ibm.com)
  *
  * This file contains interrupt related functions.
  */
@@ -14,6 +14,8 @@
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
 #include <linux/cpu.h>
+#include <linux/proc_fs.h>
+#include <linux/profile.h>
 
 /*
  * show_interrupts is needed by /proc/interrupts.
@@ -93,5 +95,12 @@
 
 	local_irq_restore(flags);
 }
-
 EXPORT_SYMBOL(do_softirq);
+
+void init_irq_proc(void)
+{
+	struct proc_dir_entry *root_irq_dir;
+
+	root_irq_dir = proc_mkdir("irq", NULL);
+	create_prof_cpu_mask(root_irq_dir);
+}
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index 576368c..a466bab 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -155,15 +155,34 @@
 static int __kprobes swap_instruction(void *aref)
 {
 	struct ins_replace_args *args = aref;
+	u32 *addr;
+	u32 instr;
 	int err = -EFAULT;
 
+	/*
+	 * Text segment is read-only, hence we use stura to bypass dynamic
+	 * address translation to exchange the instruction. Since stura
+	 * always operates on four bytes, but we only want to exchange two
+	 * bytes do some calculations to get things right. In addition we
+	 * shall not cross any page boundaries (vmalloc area!) when writing
+	 * the new instruction.
+	 */
+	addr = (u32 *)ALIGN((unsigned long)args->ptr, 4);
+	if ((unsigned long)args->ptr & 2)
+		instr = ((*addr) & 0xffff0000) | args->new;
+	else
+		instr = ((*addr) & 0x0000ffff) | args->new << 16;
+
 	asm volatile(
-		"0: mvc  0(2,%2),0(%3)\n"
-		"1: la   %0,0\n"
+		"	lra	%1,0(%1)\n"
+		"0:	stura	%2,%1\n"
+		"1:	la	%0,0\n"
 		"2:\n"
 		EX_TABLE(0b,2b)
-		: "+d" (err), "=m" (*args->ptr)
-		: "a" (args->ptr), "a" (&args->new), "m" (args->new));
+		: "+d" (err)
+		: "a" (addr), "d" (instr)
+		: "memory", "cc");
+
 	return err;
 }
 
@@ -356,7 +375,7 @@
  *	- When the probed function returns, this probe
  *		causes the handlers to fire
  */
-void __kprobes kretprobe_trampoline_holder(void)
+void kretprobe_trampoline_holder(void)
 {
 	asm volatile(".global kretprobe_trampoline\n"
 		     "kretprobe_trampoline: bcr 0,0\n");
@@ -365,7 +384,8 @@
 /*
  * Called when the probe at kretprobe trampoline is hit
  */
-int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+static int __kprobes trampoline_probe_handler(struct kprobe *p,
+					      struct pt_regs *regs)
 {
 	struct kretprobe_instance *ri = NULL;
 	struct hlist_head *head, empty_rp;
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c
index f6d9bcc..52f57af 100644
--- a/arch/s390/kernel/machine_kexec.c
+++ b/arch/s390/kernel/machine_kexec.c
@@ -11,6 +11,7 @@
 #include <linux/mm.h>
 #include <linux/kexec.h>
 #include <linux/delay.h>
+#include <linux/reboot.h>
 #include <asm/cio.h>
 #include <asm/setup.h>
 #include <asm/pgtable.h>
diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
index d989ed4..39d1dd7 100644
--- a/arch/s390/kernel/module.c
+++ b/arch/s390/kernel/module.c
@@ -30,6 +30,7 @@
 #include <linux/fs.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/moduleloader.h>
 
 #if 0
 #define DEBUGP printk
@@ -58,7 +59,7 @@
            table entries. */
 }
 
-static inline void
+static void
 check_rela(Elf_Rela *rela, struct module *me)
 {
 	struct mod_arch_syminfo *info;
@@ -181,7 +182,7 @@
 	return -ENOEXEC;
 }
 
-static inline int
+static int
 apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, 
 	   struct module *me)
 {
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 6603fbb..5acfac6 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -144,7 +144,7 @@
 
 	trace_hardirqs_on();
 	/* Wait for external, I/O or machine check interrupt. */
-	__load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_WAIT |
+	__load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT |
 			PSW_MASK_IO | PSW_MASK_EXT);
 }
 
@@ -190,7 +190,7 @@
 	struct pt_regs regs;
 
 	memset(&regs, 0, sizeof(regs));
-	regs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT;
+	regs.psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT;
 	regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE;
 	regs.gprs[9] = (unsigned long) fn;
 	regs.gprs[10] = (unsigned long) arg;
diff --git a/arch/s390/kernel/profile.c b/arch/s390/kernel/profile.c
deleted file mode 100644
index b81aa1f..0000000
--- a/arch/s390/kernel/profile.c
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * arch/s390/kernel/profile.c
- *
- * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Thomas Spatzier (tspat@de.ibm.com)
- *
- */
-#include <linux/proc_fs.h>
-#include <linux/profile.h>
-
-static struct proc_dir_entry * root_irq_dir;
-
-void init_irq_proc(void)
-{
-	/* create /proc/irq */
-	root_irq_dir = proc_mkdir("irq", NULL);
-
-	/* create /proc/irq/prof_cpu_mask */
-	create_prof_cpu_mask(root_irq_dir);
-}
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 8f36504..2a8f087 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -86,15 +86,13 @@
 		per_info->control_regs.bits.storage_alt_space_ctl = 0;
 }
 
-void
-set_single_step(struct task_struct *task)
+static void set_single_step(struct task_struct *task)
 {
 	task->thread.per_info.single_step = 1;
 	FixPerRegisters(task);
 }
 
-void
-clear_single_step(struct task_struct *task)
+static void clear_single_step(struct task_struct *task)
 {
 	task->thread.per_info.single_step = 0;
 	FixPerRegisters(task);
@@ -232,9 +230,9 @@
 		 */
 		if (addr == (addr_t) &dummy->regs.psw.mask &&
 #ifdef CONFIG_COMPAT
-		    data != PSW_MASK_MERGE(PSW_USER32_BITS, data) &&
+		    data != PSW_MASK_MERGE(psw_user32_bits, data) &&
 #endif
-		    data != PSW_MASK_MERGE(PSW_USER_BITS, data))
+		    data != PSW_MASK_MERGE(psw_user_bits, data))
 			/* Invalid psw mask. */
 			return -EINVAL;
 #ifndef CONFIG_64BIT
@@ -309,7 +307,7 @@
 		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
 		if (copied != sizeof(tmp))
 			return -EIO;
-		return put_user(tmp, (unsigned long __user *) data);
+		return put_user(tmp, (unsigned long __force __user *) data);
 
 	case PTRACE_PEEKUSR:
 		/* read the word at location addr in the USER area. */
@@ -331,7 +329,7 @@
 
 	case PTRACE_PEEKUSR_AREA:
 	case PTRACE_POKEUSR_AREA:
-		if (copy_from_user(&parea, (void __user *) addr,
+		if (copy_from_user(&parea, (void __force __user *) addr,
 							sizeof(parea)))
 			return -EFAULT;
 		addr = parea.kernel_addr;
@@ -341,10 +339,11 @@
 			if (request == PTRACE_PEEKUSR_AREA)
 				ret = peek_user(child, addr, data);
 			else {
-				addr_t tmp;
-				if (get_user (tmp, (addr_t __user *) data))
+				addr_t utmp;
+				if (get_user(utmp,
+					     (addr_t __force __user *) data))
 					return -EFAULT;
-				ret = poke_user(child, addr, tmp);
+				ret = poke_user(child, addr, utmp);
 			}
 			if (ret)
 				return ret;
@@ -394,7 +393,7 @@
 		if (addr == (addr_t) &dummy32->regs.psw.mask) {
 			/* Fake a 31 bit psw mask. */
 			tmp = (__u32)(task_pt_regs(child)->psw.mask >> 32);
-			tmp = PSW32_MASK_MERGE(PSW32_USER_BITS, tmp);
+			tmp = PSW32_MASK_MERGE(psw32_user_bits, tmp);
 		} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
 			/* Fake a 31 bit psw address. */
 			tmp = (__u32) task_pt_regs(child)->psw.addr |
@@ -469,11 +468,11 @@
 		 */
 		if (addr == (addr_t) &dummy32->regs.psw.mask) {
 			/* Build a 64 bit psw mask from 31 bit mask. */
-			if (tmp != PSW32_MASK_MERGE(PSW32_USER_BITS, tmp))
+			if (tmp != PSW32_MASK_MERGE(psw32_user_bits, tmp))
 				/* Invalid psw mask. */
 				return -EINVAL;
 			task_pt_regs(child)->psw.mask =
-				PSW_MASK_MERGE(PSW_USER32_BITS, (__u64) tmp << 32);
+				PSW_MASK_MERGE(psw_user32_bits, (__u64) tmp << 32);
 		} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
 			/* Build a 64 bit psw address from 31 bit address. */
 			task_pt_regs(child)->psw.addr =
@@ -550,7 +549,7 @@
 		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
 		if (copied != sizeof(tmp))
 			return -EIO;
-		return put_user(tmp, (unsigned int __user *) data);
+		return put_user(tmp, (unsigned int __force __user *) data);
 
 	case PTRACE_PEEKUSR:
 		/* read the word at location addr in the USER area. */
@@ -571,7 +570,7 @@
 
 	case PTRACE_PEEKUSR_AREA:
 	case PTRACE_POKEUSR_AREA:
-		if (copy_from_user(&parea, (void __user *) addr,
+		if (copy_from_user(&parea, (void __force __user *) addr,
 							sizeof(parea)))
 			return -EFAULT;
 		addr = parea.kernel_addr;
@@ -581,10 +580,11 @@
 			if (request == PTRACE_PEEKUSR_AREA)
 				ret = peek_user_emu31(child, addr, data);
 			else {
-				__u32 tmp;
-				if (get_user (tmp, (__u32 __user *) data))
+				__u32 utmp;
+				if (get_user(utmp,
+					     (__u32 __force __user *) data))
 					return -EFAULT;
-				ret = poke_user_emu31(child, addr, tmp);
+				ret = poke_user_emu31(child, addr, utmp);
 			}
 			if (ret)
 				return ret;
@@ -595,17 +595,19 @@
 		return 0;
 	case PTRACE_GETEVENTMSG:
 		return put_user((__u32) child->ptrace_message,
-				(unsigned int __user *) data);
+				(unsigned int __force __user *) data);
 	case PTRACE_GETSIGINFO:
 		if (child->last_siginfo == NULL)
 			return -EINVAL;
-		return copy_siginfo_to_user32((compat_siginfo_t __user *) data,
+		return copy_siginfo_to_user32((compat_siginfo_t
+					       __force __user *) data,
 					      child->last_siginfo);
 	case PTRACE_SETSIGINFO:
 		if (child->last_siginfo == NULL)
 			return -EINVAL;
 		return copy_siginfo_from_user32(child->last_siginfo,
-						(compat_siginfo_t __user *) data);
+						(compat_siginfo_t
+						 __force __user *) data);
 	}
 	return ptrace_request(child, request, addr, data);
 }
diff --git a/arch/s390/kernel/reset.S b/arch/s390/kernel/reset.S
deleted file mode 100644
index 8a87355..0000000
--- a/arch/s390/kernel/reset.S
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- *  arch/s390/kernel/reset.S
- *
- *    Copyright (C) IBM Corp. 2006
- *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
- *		 Michael Holzheu <holzheu@de.ibm.com>
- */
-
-#include <asm/ptrace.h>
-#include <asm/lowcore.h>
-
-#ifdef CONFIG_64BIT
-
-	.globl	reset_mcck_handler
-reset_mcck_handler:
-	basr	%r13,0
-0:	lg	%r15,__LC_PANIC_STACK	# load panic stack
-	aghi	%r15,-STACK_FRAME_OVERHEAD
-	lg	%r1,s390_reset_mcck_handler-0b(%r13)
-	ltgr	%r1,%r1
-	jz	1f
-	basr	%r14,%r1
-1:	la	%r1,4095
-	lmg	%r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)
-	lpswe	__LC_MCK_OLD_PSW
-
-	.globl	s390_reset_mcck_handler
-s390_reset_mcck_handler:
-	.quad	0
-
-	.globl	reset_pgm_handler
-reset_pgm_handler:
-	stmg	%r0,%r15,__LC_SAVE_AREA
-	basr	%r13,0
-0:	lg	%r15,__LC_PANIC_STACK	# load panic stack
-	aghi	%r15,-STACK_FRAME_OVERHEAD
-	lg	%r1,s390_reset_pgm_handler-0b(%r13)
-	ltgr	%r1,%r1
-	jz	1f
-	basr	%r14,%r1
-	lmg	%r0,%r15,__LC_SAVE_AREA
-	lpswe	__LC_PGM_OLD_PSW
-1:	lpswe	disabled_wait_psw-0b(%r13)
-	.globl s390_reset_pgm_handler
-s390_reset_pgm_handler:
-	.quad	0
-	.align	8
-disabled_wait_psw:
-	.quad	0x0002000180000000,0x0000000000000000 + reset_pgm_handler
-
-#else /* CONFIG_64BIT */
-
-	.globl	reset_mcck_handler
-reset_mcck_handler:
-	basr	%r13,0
-0:	l	%r15,__LC_PANIC_STACK	# load panic stack
-	ahi	%r15,-STACK_FRAME_OVERHEAD
-	l	%r1,s390_reset_mcck_handler-0b(%r13)
-	ltr	%r1,%r1
-	jz	1f
-	basr	%r14,%r1
-1:	lm	%r0,%r15,__LC_GPREGS_SAVE_AREA
-	lpsw	__LC_MCK_OLD_PSW
-
-	.globl	s390_reset_mcck_handler
-s390_reset_mcck_handler:
-	.long	0
-
-	.globl	reset_pgm_handler
-reset_pgm_handler:
-	stm	%r0,%r15,__LC_SAVE_AREA
-	basr	%r13,0
-0:	l	%r15,__LC_PANIC_STACK	# load panic stack
-	ahi	%r15,-STACK_FRAME_OVERHEAD
-	l	%r1,s390_reset_pgm_handler-0b(%r13)
-	ltr	%r1,%r1
-	jz	1f
-	basr	%r14,%r1
-	lm	%r0,%r15,__LC_SAVE_AREA
-	lpsw	__LC_PGM_OLD_PSW
-
-1:	lpsw	disabled_wait_psw-0b(%r13)
-	.globl	s390_reset_pgm_handler
-s390_reset_pgm_handler:
-	.long	0
-disabled_wait_psw:
-	.align 8
-	.long	0x000a0000,0x00000000 + reset_pgm_handler
-
-#endif /* CONFIG_64BIT */
diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c
index bc5beaa..acf93db 100644
--- a/arch/s390/kernel/s390_ext.c
+++ b/arch/s390/kernel/s390_ext.c
@@ -125,14 +125,12 @@
 		 * Make sure that the i/o interrupt did not "overtake"
 		 * the last HZ timer interrupt.
 		 */
-		account_ticks();
+		account_ticks(S390_lowcore.int_clock);
 	kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
         index = ext_hash(code);
 	for (p = ext_int_hash[index]; p; p = p->next) {
-		if (likely(p->code == code)) {
-			if (likely(p->handler))
-				p->handler(code);
-		}
+		if (likely(p->code == code))
+			p->handler(code);
 	}
 	irq_exit();
 	set_irq_regs(old_regs);
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 5d8ee3b..0373981 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -38,6 +38,8 @@
 #include <linux/device.h>
 #include <linux/notifier.h>
 #include <linux/pfn.h>
+#include <linux/ctype.h>
+#include <linux/reboot.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -49,6 +51,14 @@
 #include <asm/page.h>
 #include <asm/ptrace.h>
 #include <asm/sections.h>
+#include <asm/ebcdic.h>
+#include <asm/compat.h>
+
+long psw_kernel_bits	= (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY |
+			   PSW_MASK_MCHECK | PSW_DEFAULT_KEY);
+long psw_user_bits	= (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
+			   PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+			   PSW_MASK_PSTATE | PSW_DEFAULT_KEY);
 
 /*
  * User copy operations.
@@ -117,9 +127,9 @@
  */
 char vmhalt_cmd[128] = "";
 char vmpoff_cmd[128] = "";
-char vmpanic_cmd[128] = "";
+static char vmpanic_cmd[128] = "";
 
-static inline void strncpy_skip_quote(char *dst, char *src, int n)
+static void strncpy_skip_quote(char *dst, char *src, int n)
 {
         int sx, dx;
 
@@ -275,10 +285,6 @@
 }
 
 #ifdef CONFIG_SMP
-extern void machine_restart_smp(char *);
-extern void machine_halt_smp(void);
-extern void machine_power_off_smp(void);
-
 void (*_machine_restart)(char *command) = machine_restart_smp;
 void (*_machine_halt)(void) = machine_halt_smp;
 void (*_machine_power_off)(void) = machine_power_off_smp;
@@ -386,6 +392,84 @@
 }
 early_param("ipldelay", early_parse_ipldelay);
 
+#ifdef CONFIG_S390_SWITCH_AMODE
+unsigned int switch_amode = 0;
+EXPORT_SYMBOL_GPL(switch_amode);
+
+static void set_amode_and_uaccess(unsigned long user_amode,
+				  unsigned long user32_amode)
+{
+	psw_user_bits = PSW_BASE_BITS | PSW_MASK_DAT | user_amode |
+			PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+			PSW_MASK_PSTATE | PSW_DEFAULT_KEY;
+#ifdef CONFIG_COMPAT
+	psw_user32_bits = PSW_BASE32_BITS | PSW_MASK_DAT | user_amode |
+			  PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+			  PSW_MASK_PSTATE | PSW_DEFAULT_KEY;
+	psw32_user_bits = PSW32_BASE_BITS | PSW32_MASK_DAT | user32_amode |
+			  PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK |
+			  PSW32_MASK_PSTATE;
+#endif
+	psw_kernel_bits = PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
+			  PSW_MASK_MCHECK | PSW_DEFAULT_KEY;
+
+	if (MACHINE_HAS_MVCOS) {
+		printk("mvcos available.\n");
+		memcpy(&uaccess, &uaccess_mvcos_switch, sizeof(uaccess));
+	} else {
+		printk("mvcos not available.\n");
+		memcpy(&uaccess, &uaccess_pt, sizeof(uaccess));
+	}
+}
+
+/*
+ * Switch kernel/user addressing modes?
+ */
+static int __init early_parse_switch_amode(char *p)
+{
+	switch_amode = 1;
+	return 0;
+}
+early_param("switch_amode", early_parse_switch_amode);
+
+#else /* CONFIG_S390_SWITCH_AMODE */
+static inline void set_amode_and_uaccess(unsigned long user_amode,
+					 unsigned long user32_amode)
+{
+}
+#endif /* CONFIG_S390_SWITCH_AMODE */
+
+#ifdef CONFIG_S390_EXEC_PROTECT
+unsigned int s390_noexec = 0;
+EXPORT_SYMBOL_GPL(s390_noexec);
+
+/*
+ * Enable execute protection?
+ */
+static int __init early_parse_noexec(char *p)
+{
+	if (!strncmp(p, "off", 3))
+		return 0;
+	switch_amode = 1;
+	s390_noexec = 1;
+	return 0;
+}
+early_param("noexec", early_parse_noexec);
+#endif /* CONFIG_S390_EXEC_PROTECT */
+
+static void setup_addressing_mode(void)
+{
+	if (s390_noexec) {
+		printk("S390 execute protection active, ");
+		set_amode_and_uaccess(PSW_ASC_SECONDARY, PSW32_ASC_SECONDARY);
+		return;
+	}
+	if (switch_amode) {
+		printk("S390 address spaces switched, ");
+		set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY);
+	}
+}
+
 static void __init
 setup_lowcore(void)
 {
@@ -402,19 +486,21 @@
 	lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
 	lc->restart_psw.addr =
 		PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
-	lc->external_new_psw.mask = PSW_KERNEL_BITS;
+	if (switch_amode)
+		lc->restart_psw.mask |= PSW_ASC_HOME;
+	lc->external_new_psw.mask = psw_kernel_bits;
 	lc->external_new_psw.addr =
 		PSW_ADDR_AMODE | (unsigned long) ext_int_handler;
-	lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT;
+	lc->svc_new_psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT;
 	lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call;
-	lc->program_new_psw.mask = PSW_KERNEL_BITS;
+	lc->program_new_psw.mask = psw_kernel_bits;
 	lc->program_new_psw.addr =
 		PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
 	lc->mcck_new_psw.mask =
-		PSW_KERNEL_BITS & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT;
+		psw_kernel_bits & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT;
 	lc->mcck_new_psw.addr =
 		PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
-	lc->io_new_psw.mask = PSW_KERNEL_BITS;
+	lc->io_new_psw.mask = psw_kernel_bits;
 	lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
 	lc->ipl_device = S390_lowcore.ipl_device;
 	lc->jiffy_timer = -1LL;
@@ -439,7 +525,7 @@
 static void __init
 setup_resources(void)
 {
-	struct resource *res;
+	struct resource *res, *sub_res;
 	int i;
 
 	code_resource.start = (unsigned long) &_text;
@@ -464,8 +550,38 @@
 		res->start = memory_chunk[i].addr;
 		res->end = memory_chunk[i].addr +  memory_chunk[i].size - 1;
 		request_resource(&iomem_resource, res);
-		request_resource(res, &code_resource);
-		request_resource(res, &data_resource);
+
+		if (code_resource.start >= res->start  &&
+			code_resource.start <= res->end &&
+			code_resource.end > res->end) {
+			sub_res = alloc_bootmem_low(sizeof(struct resource));
+			memcpy(sub_res, &code_resource,
+				sizeof(struct resource));
+			sub_res->end = res->end;
+			code_resource.start = res->end + 1;
+			request_resource(res, sub_res);
+		}
+
+		if (code_resource.start >= res->start &&
+			code_resource.start <= res->end &&
+			code_resource.end <= res->end)
+			request_resource(res, &code_resource);
+
+		if (data_resource.start >= res->start &&
+			data_resource.start <= res->end &&
+			data_resource.end > res->end) {
+			sub_res = alloc_bootmem_low(sizeof(struct resource));
+			memcpy(sub_res, &data_resource,
+				sizeof(struct resource));
+			sub_res->end = res->end;
+			data_resource.start = res->end + 1;
+			request_resource(res, sub_res);
+		}
+
+		if (data_resource.start >= res->start &&
+			data_resource.start <= res->end &&
+			data_resource.end <= res->end)
+			request_resource(res, &data_resource);
 	}
 }
 
@@ -495,16 +611,13 @@
 	}
 	if (!memory_end)
 		memory_end = memory_size;
-	if (real_size > memory_end)
-		printk("More memory detected than supported. Unused: %luk\n",
-		       (real_size - memory_end) >> 10);
 }
 
 static void __init
 setup_memory(void)
 {
         unsigned long bootmap_size;
-	unsigned long start_pfn, end_pfn, init_pfn;
+	unsigned long start_pfn, end_pfn;
 	int i;
 
 	/*
@@ -514,10 +627,6 @@
 	start_pfn = PFN_UP(__pa(&_end));
 	end_pfn = max_pfn = PFN_DOWN(memory_end);
 
-	/* Initialize storage key for kernel pages */
-	for (init_pfn = 0 ; init_pfn < start_pfn; init_pfn++)
-		page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
-
 #ifdef CONFIG_BLK_DEV_INITRD
 	/*
 	 * Move the initrd in case the bitmap of the bootmem allocater
@@ -651,6 +760,7 @@
 	parse_early_param();
 
 	setup_memory_end();
+	setup_addressing_mode();
 	setup_memory();
 	setup_resources();
 	setup_lowcore();
@@ -694,6 +804,7 @@
         struct cpuinfo_S390 *cpuinfo;
 	unsigned long n = (unsigned long) v - 1;
 
+	s390_adjust_jiffies();
 	preempt_disable();
 	if (!n) {
 		seq_printf(m, "vendor_id       : IBM/S390\n"
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index 4c8a795..554f9cf 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -119,7 +119,7 @@
 
 	/* Copy a 'clean' PSW mask to the user to avoid leaking
 	   information about whether PER is currently on.  */
-	user_sregs.regs.psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.mask);
+	user_sregs.regs.psw.mask = PSW_MASK_MERGE(psw_user_bits, regs->psw.mask);
 	user_sregs.regs.psw.addr = regs->psw.addr;
 	memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs));
 	memcpy(&user_sregs.regs.acrs, current->thread.acrs,
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index c0cd255..65b5232 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -22,23 +22,23 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
-
 #include <linux/mm.h>
 #include <linux/spinlock.h>
 #include <linux/kernel_stat.h>
 #include <linux/smp_lock.h>
-
 #include <linux/delay.h>
 #include <linux/cache.h>
 #include <linux/interrupt.h>
 #include <linux/cpu.h>
-
+#include <linux/timex.h>
+#include <asm/setup.h>
 #include <asm/sigp.h>
 #include <asm/pgalloc.h>
 #include <asm/irq.h>
 #include <asm/s390_ext.h>
 #include <asm/cpcmd.h>
 #include <asm/tlbflush.h>
+#include <asm/timer.h>
 
 extern volatile int __cpu_logical_map[];
 
@@ -53,12 +53,6 @@
 
 static struct task_struct *current_set[NR_CPUS];
 
-/*
- * Reboot, halt and power_off routines for SMP.
- */
-extern char vmhalt_cmd[];
-extern char vmpoff_cmd[];
-
 static void smp_ext_bitcall(int, ec_bit_sig);
 static void smp_ext_bitcall_others(ec_bit_sig);
 
@@ -200,7 +194,7 @@
 }
 EXPORT_SYMBOL(smp_call_function_on);
 
-static inline void do_send_stop(void)
+static void do_send_stop(void)
 {
         int cpu, rc;
 
@@ -214,7 +208,7 @@
 	}
 }
 
-static inline void do_store_status(void)
+static void do_store_status(void)
 {
         int cpu, rc;
 
@@ -230,7 +224,7 @@
         }
 }
 
-static inline void do_wait_for_stop(void)
+static void do_wait_for_stop(void)
 {
 	int cpu;
 
@@ -250,7 +244,7 @@
 void smp_send_stop(void)
 {
 	/* Disable all interrupts/machine checks */
-	__load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK);
+	__load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK);
 
         /* write magic number to zero page (absolute 0) */
 	lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC;
@@ -298,7 +292,7 @@
  * cpus are handled.
  */
 
-void do_ext_call_interrupt(__u16 code)
+static void do_ext_call_interrupt(__u16 code)
 {
         unsigned long bits;
 
@@ -385,7 +379,7 @@
 /*
  * callback for setting/clearing control bits
  */
-void smp_ctl_bit_callback(void *info) {
+static void smp_ctl_bit_callback(void *info) {
 	struct ec_creg_mask_parms *pp = info;
 	unsigned long cregs[16];
 	int i;
@@ -458,17 +452,15 @@
 /*
  *      Activate a secondary processor.
  */
-extern void init_cpu_timer(void);
-extern void init_cpu_vtimer(void);
-
 int __devinit start_secondary(void *cpuvoid)
 {
         /* Setup the cpu */
         cpu_init();
 	preempt_disable();
-        /* init per CPU timer */
+	/* Enable TOD clock interrupts on the secondary cpu. */
         init_cpu_timer();
 #ifdef CONFIG_VIRT_TIMER
+	/* Enable cpu timer interrupts on the secondary cpu. */
         init_cpu_vtimer();
 #endif
 	/* Enable pfault pseudo page faults on this cpu. */
@@ -542,7 +534,7 @@
 	spin_unlock_irqrestore(&smp_reserve_lock, flags);
 }
 
-static inline int
+static int
 cpu_stopped(int cpu)
 {
 	__u32 status;
diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c
index 0d14a47..2e5c65a 100644
--- a/arch/s390/kernel/stacktrace.c
+++ b/arch/s390/kernel/stacktrace.c
@@ -11,11 +11,11 @@
 #include <linux/stacktrace.h>
 #include <linux/kallsyms.h>
 
-static inline unsigned long save_context_stack(struct stack_trace *trace,
-					       unsigned int *skip,
-					       unsigned long sp,
-					       unsigned long low,
-					       unsigned long high)
+static unsigned long save_context_stack(struct stack_trace *trace,
+					unsigned int *skip,
+					unsigned long sp,
+					unsigned long low,
+					unsigned long high)
 {
 	struct stack_frame *sf;
 	struct pt_regs *regs;
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 6cceed4..3b91f27 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -37,11 +37,15 @@
 #include <asm/irq.h>
 #include <asm/irq_regs.h>
 #include <asm/timer.h>
+#include <asm/etr.h>
 
 /* change this if you have some constant time drift */
 #define USECS_PER_JIFFY     ((unsigned long) 1000000/HZ)
 #define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12)
 
+/* The value of the TOD clock for 1.1.1970. */
+#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
+
 /*
  * Create a small time difference between the timer interrupts
  * on the different cpus to avoid lock contention.
@@ -51,6 +55,7 @@
 #define TICK_SIZE tick
 
 static ext_int_info_t ext_int_info_cc;
+static ext_int_info_t ext_int_etr_cc;
 static u64 init_timer_cc;
 static u64 jiffies_timer_cc;
 static u64 xtime_cc;
@@ -89,29 +94,21 @@
 #define s390_do_profile()	do { ; } while(0)
 #endif /* CONFIG_PROFILING */
 
-
 /*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
+ * Advance the per cpu tick counter up to the time given with the
+ * "time" argument. The per cpu update consists of accounting
+ * the virtual cpu time, calling update_process_times and calling
+ * the profiling hook. If xtime is before time it is advanced as well.
  */
-void account_ticks(void)
+void account_ticks(u64 time)
 {
-	__u64 tmp;
 	__u32 ticks;
+	__u64 tmp;
 
 	/* Calculate how many ticks have passed. */
-	if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) {
-		/*
-		 * We have to program the clock comparator even if
-		 * no tick has passed. That happens if e.g. an i/o
-		 * interrupt wakes up an idle processor that has
-		 * switched off its hz timer.
-		 */
-		tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION;
-		asm volatile ("SCKC %0" : : "m" (tmp));
+	if (time < S390_lowcore.jiffy_timer)
 		return;
-	}
-	tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer;
+	tmp = time - S390_lowcore.jiffy_timer;
 	if (tmp >= 2*CLK_TICKS_PER_JIFFY) {  /* more than two ticks ? */
 		ticks = __div(tmp, CLK_TICKS_PER_JIFFY) + 1;
 		S390_lowcore.jiffy_timer +=
@@ -124,10 +121,6 @@
 		S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
 	}
 
-	/* set clock comparator for next tick */
-	tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION;
-        asm volatile ("SCKC %0" : : "m" (tmp));
-
 #ifdef CONFIG_SMP
 	/*
 	 * Do not rely on the boot cpu to do the calls to do_timer.
@@ -173,7 +166,7 @@
  * Stop the HZ tick on the current CPU.
  * Only cpu_idle may call this function.
  */
-static inline void stop_hz_timer(void)
+static void stop_hz_timer(void)
 {
 	unsigned long flags;
 	unsigned long seq, next;
@@ -210,20 +203,21 @@
 		if (timer >= jiffies_timer_cc)
 			todval = timer;
 	}
-	asm volatile ("SCKC %0" : : "m" (todval));
+	set_clock_comparator(todval);
 }
 
 /*
  * Start the HZ tick on the current CPU.
  * Only cpu_idle may call this function.
  */
-static inline void start_hz_timer(void)
+static void start_hz_timer(void)
 {
 	BUG_ON(!in_interrupt());
 
 	if (!cpu_isset(smp_processor_id(), nohz_cpu_mask))
 		return;
-	account_ticks();
+	account_ticks(get_clock());
+	set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION);
 	cpu_clear(smp_processor_id(), nohz_cpu_mask);
 }
 
@@ -245,7 +239,7 @@
 	.notifier_call = nohz_idle_notify,
 };
 
-void __init nohz_init(void)
+static void __init nohz_init(void)
 {
 	if (register_idle_notifier(&nohz_idle_nb))
 		panic("Couldn't register idle notifier");
@@ -254,24 +248,57 @@
 #endif
 
 /*
- * Start the clock comparator on the current CPU.
+ * Set up per cpu jiffy timer and set the clock comparator.
+ */
+static void setup_jiffy_timer(void)
+{
+	/* Set up clock comparator to next jiffy. */
+	S390_lowcore.jiffy_timer =
+		jiffies_timer_cc + (jiffies_64 + 1) * CLK_TICKS_PER_JIFFY;
+	set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION);
+}
+
+/*
+ * Set up lowcore and control register of the current cpu to
+ * enable TOD clock and clock comparator interrupts.
  */
 void init_cpu_timer(void)
 {
-	unsigned long cr0;
-	__u64 timer;
+	setup_jiffy_timer();
 
-	timer = jiffies_timer_cc + jiffies_64 * CLK_TICKS_PER_JIFFY;
-	S390_lowcore.jiffy_timer = timer + CLK_TICKS_PER_JIFFY;
-	timer += CLK_TICKS_PER_JIFFY + CPU_DEVIATION;
-	asm volatile ("SCKC %0" : : "m" (timer));
-        /* allow clock comparator timer interrupt */
-	__ctl_store(cr0, 0, 0);
-        cr0 |= 0x800;
-	__ctl_load(cr0, 0, 0);
+	/* Enable clock comparator timer interrupt. */
+	__ctl_set_bit(0,11);
+
+	/* Always allow ETR external interrupts, even without an ETR. */
+	__ctl_set_bit(0, 4);
 }
 
-extern void vtime_init(void);
+static void clock_comparator_interrupt(__u16 code)
+{
+	/* set clock comparator for next tick */
+	set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION);
+}
+
+static void etr_reset(void);
+static void etr_init(void);
+static void etr_ext_handler(__u16);
+
+/*
+ * Get the TOD clock running.
+ */
+static u64 __init reset_tod_clock(void)
+{
+	u64 time;
+
+	etr_reset();
+	if (store_clock(&time) == 0)
+		return time;
+	/* TOD clock not running. Set the clock to Unix Epoch. */
+	if (set_clock(TOD_UNIX_EPOCH) != 0 || store_clock(&time) != 0)
+		panic("TOD clock not operational.");
+
+	return TOD_UNIX_EPOCH;
+}
 
 static cycle_t read_tod_clock(void)
 {
@@ -295,48 +322,31 @@
  */
 void __init time_init(void)
 {
-	__u64 set_time_cc;
-	int cc;
-
-        /* kick the TOD clock */
-	asm volatile(
-		"	stck	0(%2)\n"
-		"	ipm	%0\n"
-		"	srl	%0,28"
-		: "=d" (cc), "=m" (init_timer_cc)
-		: "a" (&init_timer_cc) : "cc");
-        switch (cc) {
-        case 0: /* clock in set state: all is fine */
-                break;
-        case 1: /* clock in non-set state: FIXME */
-                printk("time_init: TOD clock in non-set state\n");
-                break;
-        case 2: /* clock in error state: FIXME */
-                printk("time_init: TOD clock in error state\n");
-                break;
-        case 3: /* clock in stopped or not-operational state: FIXME */
-                printk("time_init: TOD clock stopped/non-operational\n");
-                break;
-        }
+	init_timer_cc = reset_tod_clock();
+	xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY;
 	jiffies_timer_cc = init_timer_cc - jiffies_64 * CLK_TICKS_PER_JIFFY;
 
 	/* set xtime */
-	xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY;
-	set_time_cc = init_timer_cc - 0x8126d60e46000000LL +
-		(0x3c26700LL*1000000*4096);
-        tod_to_timeval(set_time_cc, &xtime);
+	tod_to_timeval(init_timer_cc - TOD_UNIX_EPOCH, &xtime);
         set_normalized_timespec(&wall_to_monotonic,
                                 -xtime.tv_sec, -xtime.tv_nsec);
 
 	/* request the clock comparator external interrupt */
-	if (register_early_external_interrupt(0x1004, NULL,
+	if (register_early_external_interrupt(0x1004,
+					      clock_comparator_interrupt,
 					      &ext_int_info_cc) != 0)
                 panic("Couldn't request external interrupt 0x1004");
 
 	if (clocksource_register(&clocksource_tod) != 0)
 		panic("Could not register TOD clock source");
 
-        init_cpu_timer();
+	/* request the etr external interrupt */
+	if (register_early_external_interrupt(0x1406, etr_ext_handler,
+					      &ext_int_etr_cc) != 0)
+		panic("Couldn't request external interrupt 0x1406");
+
+	/* Enable TOD clock interrupts on the boot cpu. */
+	init_cpu_timer();
 
 #ifdef CONFIG_NO_IDLE_HZ
 	nohz_init();
@@ -345,5 +355,1048 @@
 #ifdef CONFIG_VIRT_TIMER
 	vtime_init();
 #endif
+	etr_init();
 }
 
+/*
+ * External Time Reference (ETR) code.
+ */
+static int etr_port0_online;
+static int etr_port1_online;
+
+static int __init early_parse_etr(char *p)
+{
+	if (strncmp(p, "off", 3) == 0)
+		etr_port0_online = etr_port1_online = 0;
+	else if (strncmp(p, "port0", 5) == 0)
+		etr_port0_online = 1;
+	else if (strncmp(p, "port1", 5) == 0)
+		etr_port1_online = 1;
+	else if (strncmp(p, "on", 2) == 0)
+		etr_port0_online = etr_port1_online = 1;
+	return 0;
+}
+early_param("etr", early_parse_etr);
+
+enum etr_event {
+	ETR_EVENT_PORT0_CHANGE,
+	ETR_EVENT_PORT1_CHANGE,
+	ETR_EVENT_PORT_ALERT,
+	ETR_EVENT_SYNC_CHECK,
+	ETR_EVENT_SWITCH_LOCAL,
+	ETR_EVENT_UPDATE,
+};
+
+enum etr_flags {
+	ETR_FLAG_ENOSYS,
+	ETR_FLAG_EACCES,
+	ETR_FLAG_STEAI,
+};
+
+/*
+ * Valid bit combinations of the eacr register are (x = don't care):
+ * e0 e1 dp p0 p1 ea es sl
+ *  0  0  x  0	0  0  0  0  initial, disabled state
+ *  0  0  x  0	1  1  0  0  port 1 online
+ *  0  0  x  1	0  1  0  0  port 0 online
+ *  0  0  x  1	1  1  0  0  both ports online
+ *  0  1  x  0	1  1  0  0  port 1 online and usable, ETR or PPS mode
+ *  0  1  x  0	1  1  0  1  port 1 online, usable and ETR mode
+ *  0  1  x  0	1  1  1  0  port 1 online, usable, PPS mode, in-sync
+ *  0  1  x  0	1  1  1  1  port 1 online, usable, ETR mode, in-sync
+ *  0  1  x  1	1  1  0  0  both ports online, port 1 usable
+ *  0  1  x  1	1  1  1  0  both ports online, port 1 usable, PPS mode, in-sync
+ *  0  1  x  1	1  1  1  1  both ports online, port 1 usable, ETR mode, in-sync
+ *  1  0  x  1	0  1  0  0  port 0 online and usable, ETR or PPS mode
+ *  1  0  x  1	0  1  0  1  port 0 online, usable and ETR mode
+ *  1  0  x  1	0  1  1  0  port 0 online, usable, PPS mode, in-sync
+ *  1  0  x  1	0  1  1  1  port 0 online, usable, ETR mode, in-sync
+ *  1  0  x  1	1  1  0  0  both ports online, port 0 usable
+ *  1  0  x  1	1  1  1  0  both ports online, port 0 usable, PPS mode, in-sync
+ *  1  0  x  1	1  1  1  1  both ports online, port 0 usable, ETR mode, in-sync
+ *  1  1  x  1	1  1  1  0  both ports online & usable, ETR, in-sync
+ *  1  1  x  1	1  1  1  1  both ports online & usable, ETR, in-sync
+ */
+static struct etr_eacr etr_eacr;
+static u64 etr_tolec;			/* time of last eacr update */
+static unsigned long etr_flags;
+static struct etr_aib etr_port0;
+static int etr_port0_uptodate;
+static struct etr_aib etr_port1;
+static int etr_port1_uptodate;
+static unsigned long etr_events;
+static struct timer_list etr_timer;
+static struct tasklet_struct etr_tasklet;
+static DEFINE_PER_CPU(atomic_t, etr_sync_word);
+
+static void etr_timeout(unsigned long dummy);
+static void etr_tasklet_fn(unsigned long dummy);
+
+/*
+ * The etr get_clock function. It will write the current clock value
+ * to the clock pointer and return 0 if the clock is in sync with the
+ * external time source. If the clock mode is local it will return
+ * -ENOSYS and -EAGAIN if the clock is not in sync with the external
+ * reference. This function is what ETR is all about..
+ */
+int get_sync_clock(unsigned long long *clock)
+{
+	atomic_t *sw_ptr;
+	unsigned int sw0, sw1;
+
+	sw_ptr = &get_cpu_var(etr_sync_word);
+	sw0 = atomic_read(sw_ptr);
+	*clock = get_clock();
+	sw1 = atomic_read(sw_ptr);
+	put_cpu_var(etr_sync_sync);
+	if (sw0 == sw1 && (sw0 & 0x80000000U))
+		/* Success: time is in sync. */
+		return 0;
+	if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
+		return -ENOSYS;
+	if (test_bit(ETR_FLAG_EACCES, &etr_flags))
+		return -EACCES;
+	return -EAGAIN;
+}
+EXPORT_SYMBOL(get_sync_clock);
+
+/*
+ * Make get_sync_clock return -EAGAIN.
+ */
+static void etr_disable_sync_clock(void *dummy)
+{
+	atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word);
+	/*
+	 * Clear the in-sync bit 2^31. All get_sync_clock calls will
+	 * fail until the sync bit is turned back on. In addition
+	 * increase the "sequence" counter to avoid the race of an
+	 * etr event and the complete recovery against get_sync_clock.
+	 */
+	atomic_clear_mask(0x80000000, sw_ptr);
+	atomic_inc(sw_ptr);
+}
+
+/*
+ * Make get_sync_clock return 0 again.
+ * Needs to be called from a context disabled for preemption.
+ */
+static void etr_enable_sync_clock(void)
+{
+	atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word);
+	atomic_set_mask(0x80000000, sw_ptr);
+}
+
+/*
+ * Reset ETR attachment.
+ */
+static void etr_reset(void)
+{
+	etr_eacr =  (struct etr_eacr) {
+		.e0 = 0, .e1 = 0, ._pad0 = 4, .dp = 0,
+		.p0 = 0, .p1 = 0, ._pad1 = 0, .ea = 0,
+		.es = 0, .sl = 0 };
+	if (etr_setr(&etr_eacr) == 0)
+		etr_tolec = get_clock();
+	else {
+		set_bit(ETR_FLAG_ENOSYS, &etr_flags);
+		if (etr_port0_online || etr_port1_online) {
+			printk(KERN_WARNING "Running on non ETR capable "
+			       "machine, only local mode available.\n");
+			etr_port0_online = etr_port1_online = 0;
+		}
+	}
+}
+
+static void etr_init(void)
+{
+	struct etr_aib aib;
+
+	if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
+		return;
+	/* Check if this machine has the steai instruction. */
+	if (etr_steai(&aib, ETR_STEAI_STEPPING_PORT) == 0)
+		set_bit(ETR_FLAG_STEAI, &etr_flags);
+	setup_timer(&etr_timer, etr_timeout, 0UL);
+	tasklet_init(&etr_tasklet, etr_tasklet_fn, 0);
+	if (!etr_port0_online && !etr_port1_online)
+		set_bit(ETR_FLAG_EACCES, &etr_flags);
+	if (etr_port0_online) {
+		set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
+		tasklet_hi_schedule(&etr_tasklet);
+	}
+	if (etr_port1_online) {
+		set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
+		tasklet_hi_schedule(&etr_tasklet);
+	}
+}
+
+/*
+ * Two sorts of ETR machine checks. The architecture reads:
+ * "When a machine-check niterruption occurs and if a switch-to-local or
+ *  ETR-sync-check interrupt request is pending but disabled, this pending
+ *  disabled interruption request is indicated and is cleared".
+ * Which means that we can get etr_switch_to_local events from the machine
+ * check handler although the interruption condition is disabled. Lovely..
+ */
+
+/*
+ * Switch to local machine check. This is called when the last usable
+ * ETR port goes inactive. After switch to local the clock is not in sync.
+ */
+void etr_switch_to_local(void)
+{
+	if (!etr_eacr.sl)
+		return;
+	etr_disable_sync_clock(NULL);
+	set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events);
+	tasklet_hi_schedule(&etr_tasklet);
+}
+
+/*
+ * ETR sync check machine check. This is called when the ETR OTE and the
+ * local clock OTE are farther apart than the ETR sync check tolerance.
+ * After a ETR sync check the clock is not in sync. The machine check
+ * is broadcasted to all cpus at the same time.
+ */
+void etr_sync_check(void)
+{
+	if (!etr_eacr.es)
+		return;
+	etr_disable_sync_clock(NULL);
+	set_bit(ETR_EVENT_SYNC_CHECK, &etr_events);
+	tasklet_hi_schedule(&etr_tasklet);
+}
+
+/*
+ * ETR external interrupt. There are two causes:
+ * 1) port state change, check the usability of the port
+ * 2) port alert, one of the ETR-data-validity bits (v1-v2 bits of the
+ *    sldr-status word) or ETR-data word 1 (edf1) or ETR-data word 3 (edf3)
+ *    or ETR-data word 4 (edf4) has changed.
+ */
+static void etr_ext_handler(__u16 code)
+{
+	struct etr_interruption_parameter *intparm =
+		(struct etr_interruption_parameter *) &S390_lowcore.ext_params;
+
+	if (intparm->pc0)
+		/* ETR port 0 state change. */
+		set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
+	if (intparm->pc1)
+		/* ETR port 1 state change. */
+		set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
+	if (intparm->eai)
+		/*
+		 * ETR port alert on either port 0, 1 or both.
+		 * Both ports are not up-to-date now.
+		 */
+		set_bit(ETR_EVENT_PORT_ALERT, &etr_events);
+	tasklet_hi_schedule(&etr_tasklet);
+}
+
+static void etr_timeout(unsigned long dummy)
+{
+	set_bit(ETR_EVENT_UPDATE, &etr_events);
+	tasklet_hi_schedule(&etr_tasklet);
+}
+
+/*
+ * Check if the etr mode is pss.
+ */
+static inline int etr_mode_is_pps(struct etr_eacr eacr)
+{
+	return eacr.es && !eacr.sl;
+}
+
+/*
+ * Check if the etr mode is etr.
+ */
+static inline int etr_mode_is_etr(struct etr_eacr eacr)
+{
+	return eacr.es && eacr.sl;
+}
+
+/*
+ * Check if the port can be used for TOD synchronization.
+ * For PPS mode the port has to receive OTEs. For ETR mode
+ * the port has to receive OTEs, the ETR stepping bit has to
+ * be zero and the validity bits for data frame 1, 2, and 3
+ * have to be 1.
+ */
+static int etr_port_valid(struct etr_aib *aib, int port)
+{
+	unsigned int psc;
+
+	/* Check that this port is receiving OTEs. */
+	if (aib->tsp == 0)
+		return 0;
+
+	psc = port ? aib->esw.psc1 : aib->esw.psc0;
+	if (psc == etr_lpsc_pps_mode)
+		return 1;
+	if (psc == etr_lpsc_operational_step)
+		return !aib->esw.y && aib->slsw.v1 &&
+			aib->slsw.v2 && aib->slsw.v3;
+	return 0;
+}
+
+/*
+ * Check if two ports are on the same network.
+ */
+static int etr_compare_network(struct etr_aib *aib1, struct etr_aib *aib2)
+{
+	// FIXME: any other fields we have to compare?
+	return aib1->edf1.net_id == aib2->edf1.net_id;
+}
+
+/*
+ * Wrapper for etr_stei that converts physical port states
+ * to logical port states to be consistent with the output
+ * of stetr (see etr_psc vs. etr_lpsc).
+ */
+static void etr_steai_cv(struct etr_aib *aib, unsigned int func)
+{
+	BUG_ON(etr_steai(aib, func) != 0);
+	/* Convert port state to logical port state. */
+	if (aib->esw.psc0 == 1)
+		aib->esw.psc0 = 2;
+	else if (aib->esw.psc0 == 0 && aib->esw.p == 0)
+		aib->esw.psc0 = 1;
+	if (aib->esw.psc1 == 1)
+		aib->esw.psc1 = 2;
+	else if (aib->esw.psc1 == 0 && aib->esw.p == 1)
+		aib->esw.psc1 = 1;
+}
+
+/*
+ * Check if the aib a2 is still connected to the same attachment as
+ * aib a1, the etv values differ by one and a2 is valid.
+ */
+static int etr_aib_follows(struct etr_aib *a1, struct etr_aib *a2, int p)
+{
+	int state_a1, state_a2;
+
+	/* Paranoia check: e0/e1 should better be the same. */
+	if (a1->esw.eacr.e0 != a2->esw.eacr.e0 ||
+	    a1->esw.eacr.e1 != a2->esw.eacr.e1)
+		return 0;
+
+	/* Still connected to the same etr ? */
+	state_a1 = p ? a1->esw.psc1 : a1->esw.psc0;
+	state_a2 = p ? a2->esw.psc1 : a2->esw.psc0;
+	if (state_a1 == etr_lpsc_operational_step) {
+		if (state_a2 != etr_lpsc_operational_step ||
+		    a1->edf1.net_id != a2->edf1.net_id ||
+		    a1->edf1.etr_id != a2->edf1.etr_id ||
+		    a1->edf1.etr_pn != a2->edf1.etr_pn)
+			return 0;
+	} else if (state_a2 != etr_lpsc_pps_mode)
+		return 0;
+
+	/* The ETV value of a2 needs to be ETV of a1 + 1. */
+	if (a1->edf2.etv + 1 != a2->edf2.etv)
+		return 0;
+
+	if (!etr_port_valid(a2, p))
+		return 0;
+
+	return 1;
+}
+
+/*
+ * The time is "clock". xtime is what we think the time is.
+ * Adjust the value by a multiple of jiffies and add the delta to ntp.
+ * "delay" is an approximation how long the synchronization took. If
+ * the time correction is positive, then "delay" is subtracted from
+ * the time difference and only the remaining part is passed to ntp.
+ */
+static void etr_adjust_time(unsigned long long clock, unsigned long long delay)
+{
+	unsigned long long delta, ticks;
+	struct timex adjust;
+
+	/*
+	 * We don't have to take the xtime lock because the cpu
+	 * executing etr_adjust_time is running disabled in
+	 * tasklet context and all other cpus are looping in
+	 * etr_sync_cpu_start.
+	 */
+	if (clock > xtime_cc) {
+		/* It is later than we thought. */
+		delta = ticks = clock - xtime_cc;
+		delta = ticks = (delta < delay) ? 0 : delta - delay;
+		delta -= do_div(ticks, CLK_TICKS_PER_JIFFY);
+		init_timer_cc = init_timer_cc + delta;
+		jiffies_timer_cc = jiffies_timer_cc + delta;
+		xtime_cc = xtime_cc + delta;
+		adjust.offset = ticks * (1000000 / HZ);
+	} else {
+		/* It is earlier than we thought. */
+		delta = ticks = xtime_cc - clock;
+		delta -= do_div(ticks, CLK_TICKS_PER_JIFFY);
+		init_timer_cc = init_timer_cc - delta;
+		jiffies_timer_cc = jiffies_timer_cc - delta;
+		xtime_cc = xtime_cc - delta;
+		adjust.offset = -ticks * (1000000 / HZ);
+	}
+	if (adjust.offset != 0) {
+		printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n",
+		       adjust.offset);
+		adjust.modes = ADJ_OFFSET_SINGLESHOT;
+		do_adjtimex(&adjust);
+	}
+}
+
+static void etr_sync_cpu_start(void *dummy)
+{
+	int *in_sync = dummy;
+
+	etr_enable_sync_clock();
+	/*
+	 * This looks like a busy wait loop but it isn't. etr_sync_cpus
+	 * is called on all other cpus while the TOD clocks is stopped.
+	 * __udelay will stop the cpu on an enabled wait psw until the
+	 * TOD is running again.
+	 */
+	while (*in_sync == 0)
+		__udelay(1);
+	if (*in_sync != 1)
+		/* Didn't work. Clear per-cpu in sync bit again. */
+		etr_disable_sync_clock(NULL);
+	/*
+	 * This round of TOD syncing is done. Set the clock comparator
+	 * to the next tick and let the processor continue.
+	 */
+	setup_jiffy_timer();
+}
+
+static void etr_sync_cpu_end(void *dummy)
+{
+}
+
+/*
+ * Sync the TOD clock using the port refered to by aibp. This port
+ * has to be enabled and the other port has to be disabled. The
+ * last eacr update has to be more than 1.6 seconds in the past.
+ */
+static int etr_sync_clock(struct etr_aib *aib, int port)
+{
+	struct etr_aib *sync_port;
+	unsigned long long clock, delay;
+	int in_sync, follows;
+	int rc;
+
+	/* Check if the current aib is adjacent to the sync port aib. */
+	sync_port = (port == 0) ? &etr_port0 : &etr_port1;
+	follows = etr_aib_follows(sync_port, aib, port);
+	memcpy(sync_port, aib, sizeof(*aib));
+	if (!follows)
+		return -EAGAIN;
+
+	/*
+	 * Catch all other cpus and make them wait until we have
+	 * successfully synced the clock. smp_call_function will
+	 * return after all other cpus are in etr_sync_cpu_start.
+	 */
+	in_sync = 0;
+	preempt_disable();
+	smp_call_function(etr_sync_cpu_start,&in_sync,0,0);
+	local_irq_disable();
+	etr_enable_sync_clock();
+
+	/* Set clock to next OTE. */
+	__ctl_set_bit(14, 21);
+	__ctl_set_bit(0, 29);
+	clock = ((unsigned long long) (aib->edf2.etv + 1)) << 32;
+	if (set_clock(clock) == 0) {
+		__udelay(1);	/* Wait for the clock to start. */
+		__ctl_clear_bit(0, 29);
+		__ctl_clear_bit(14, 21);
+		etr_stetr(aib);
+		/* Adjust Linux timing variables. */
+		delay = (unsigned long long)
+			(aib->edf2.etv - sync_port->edf2.etv) << 32;
+		etr_adjust_time(clock, delay);
+		setup_jiffy_timer();
+		/* Verify that the clock is properly set. */
+		if (!etr_aib_follows(sync_port, aib, port)) {
+			/* Didn't work. */
+			etr_disable_sync_clock(NULL);
+			in_sync = -EAGAIN;
+			rc = -EAGAIN;
+		} else {
+			in_sync = 1;
+			rc = 0;
+		}
+	} else {
+		/* Could not set the clock ?!? */
+		__ctl_clear_bit(0, 29);
+		__ctl_clear_bit(14, 21);
+		etr_disable_sync_clock(NULL);
+		in_sync = -EAGAIN;
+		rc = -EAGAIN;
+	}
+	local_irq_enable();
+	smp_call_function(etr_sync_cpu_end,NULL,0,0);
+	preempt_enable();
+	return rc;
+}
+
+/*
+ * Handle the immediate effects of the different events.
+ * The port change event is used for online/offline changes.
+ */
+static struct etr_eacr etr_handle_events(struct etr_eacr eacr)
+{
+	if (test_and_clear_bit(ETR_EVENT_SYNC_CHECK, &etr_events))
+		eacr.es = 0;
+	if (test_and_clear_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events))
+		eacr.es = eacr.sl = 0;
+	if (test_and_clear_bit(ETR_EVENT_PORT_ALERT, &etr_events))
+		etr_port0_uptodate = etr_port1_uptodate = 0;
+
+	if (test_and_clear_bit(ETR_EVENT_PORT0_CHANGE, &etr_events)) {
+		if (eacr.e0)
+			/*
+			 * Port change of an enabled port. We have to
+			 * assume that this can have caused an stepping
+			 * port switch.
+			 */
+			etr_tolec = get_clock();
+		eacr.p0 = etr_port0_online;
+		if (!eacr.p0)
+			eacr.e0 = 0;
+		etr_port0_uptodate = 0;
+	}
+	if (test_and_clear_bit(ETR_EVENT_PORT1_CHANGE, &etr_events)) {
+		if (eacr.e1)
+			/*
+			 * Port change of an enabled port. We have to
+			 * assume that this can have caused an stepping
+			 * port switch.
+			 */
+			etr_tolec = get_clock();
+		eacr.p1 = etr_port1_online;
+		if (!eacr.p1)
+			eacr.e1 = 0;
+		etr_port1_uptodate = 0;
+	}
+	clear_bit(ETR_EVENT_UPDATE, &etr_events);
+	return eacr;
+}
+
+/*
+ * Set up a timer that expires after the etr_tolec + 1.6 seconds if
+ * one of the ports needs an update.
+ */
+static void etr_set_tolec_timeout(unsigned long long now)
+{
+	unsigned long micros;
+
+	if ((!etr_eacr.p0 || etr_port0_uptodate) &&
+	    (!etr_eacr.p1 || etr_port1_uptodate))
+		return;
+	micros = (now > etr_tolec) ? ((now - etr_tolec) >> 12) : 0;
+	micros = (micros > 1600000) ? 0 : 1600000 - micros;
+	mod_timer(&etr_timer, jiffies + (micros * HZ) / 1000000 + 1);
+}
+
+/*
+ * Set up a time that expires after 1/2 second.
+ */
+static void etr_set_sync_timeout(void)
+{
+	mod_timer(&etr_timer, jiffies + HZ/2);
+}
+
+/*
+ * Update the aib information for one or both ports.
+ */
+static struct etr_eacr etr_handle_update(struct etr_aib *aib,
+					 struct etr_eacr eacr)
+{
+	/* With both ports disabled the aib information is useless. */
+	if (!eacr.e0 && !eacr.e1)
+		return eacr;
+
+	/* Update port0 or port1 with aib stored in etr_tasklet_fn. */
+	if (aib->esw.q == 0) {
+		/* Information for port 0 stored. */
+		if (eacr.p0 && !etr_port0_uptodate) {
+			etr_port0 = *aib;
+			if (etr_port0_online)
+				etr_port0_uptodate = 1;
+		}
+	} else {
+		/* Information for port 1 stored. */
+		if (eacr.p1 && !etr_port1_uptodate) {
+			etr_port1 = *aib;
+			if (etr_port0_online)
+				etr_port1_uptodate = 1;
+		}
+	}
+
+	/*
+	 * Do not try to get the alternate port aib if the clock
+	 * is not in sync yet.
+	 */
+	if (!eacr.es)
+		return eacr;
+
+	/*
+	 * If steai is available we can get the information about
+	 * the other port immediately. If only stetr is available the
+	 * data-port bit toggle has to be used.
+	 */
+	if (test_bit(ETR_FLAG_STEAI, &etr_flags)) {
+		if (eacr.p0 && !etr_port0_uptodate) {
+			etr_steai_cv(&etr_port0, ETR_STEAI_PORT_0);
+			etr_port0_uptodate = 1;
+		}
+		if (eacr.p1 && !etr_port1_uptodate) {
+			etr_steai_cv(&etr_port1, ETR_STEAI_PORT_1);
+			etr_port1_uptodate = 1;
+		}
+	} else {
+		/*
+		 * One port was updated above, if the other
+		 * port is not uptodate toggle dp bit.
+		 */
+		if ((eacr.p0 && !etr_port0_uptodate) ||
+		    (eacr.p1 && !etr_port1_uptodate))
+			eacr.dp ^= 1;
+		else
+			eacr.dp = 0;
+	}
+	return eacr;
+}
+
+/*
+ * Write new etr control register if it differs from the current one.
+ * Return 1 if etr_tolec has been updated as well.
+ */
+static void etr_update_eacr(struct etr_eacr eacr)
+{
+	int dp_changed;
+
+	if (memcmp(&etr_eacr, &eacr, sizeof(eacr)) == 0)
+		/* No change, return. */
+		return;
+	/*
+	 * The disable of an active port of the change of the data port
+	 * bit can/will cause a change in the data port.
+	 */
+	dp_changed = etr_eacr.e0 > eacr.e0 || etr_eacr.e1 > eacr.e1 ||
+		(etr_eacr.dp ^ eacr.dp) != 0;
+	etr_eacr = eacr;
+	etr_setr(&etr_eacr);
+	if (dp_changed)
+		etr_tolec = get_clock();
+}
+
+/*
+ * ETR tasklet. In this function you'll find the main logic. In
+ * particular this is the only function that calls etr_update_eacr(),
+ * it "controls" the etr control register.
+ */
+static void etr_tasklet_fn(unsigned long dummy)
+{
+	unsigned long long now;
+	struct etr_eacr eacr;
+	struct etr_aib aib;
+	int sync_port;
+
+	/* Create working copy of etr_eacr. */
+	eacr = etr_eacr;
+
+	/* Check for the different events and their immediate effects. */
+	eacr = etr_handle_events(eacr);
+
+	/* Check if ETR is supposed to be active. */
+	eacr.ea = eacr.p0 || eacr.p1;
+	if (!eacr.ea) {
+		/* Both ports offline. Reset everything. */
+		eacr.dp = eacr.es = eacr.sl = 0;
+		on_each_cpu(etr_disable_sync_clock, NULL, 0, 1);
+		del_timer_sync(&etr_timer);
+		etr_update_eacr(eacr);
+		set_bit(ETR_FLAG_EACCES, &etr_flags);
+		return;
+	}
+
+	/* Store aib to get the current ETR status word. */
+	BUG_ON(etr_stetr(&aib) != 0);
+	etr_port0.esw = etr_port1.esw = aib.esw;	/* Copy status word. */
+	now = get_clock();
+
+	/*
+	 * Update the port information if the last stepping port change
+	 * or data port change is older than 1.6 seconds.
+	 */
+	if (now >= etr_tolec + (1600000 << 12))
+		eacr = etr_handle_update(&aib, eacr);
+
+	/*
+	 * Select ports to enable. The prefered synchronization mode is PPS.
+	 * If a port can be enabled depends on a number of things:
+	 * 1) The port needs to be online and uptodate. A port is not
+	 *    disabled just because it is not uptodate, but it is only
+	 *    enabled if it is uptodate.
+	 * 2) The port needs to have the same mode (pps / etr).
+	 * 3) The port needs to be usable -> etr_port_valid() == 1
+	 * 4) To enable the second port the clock needs to be in sync.
+	 * 5) If both ports are useable and are ETR ports, the network id
+	 *    has to be the same.
+	 * The eacr.sl bit is used to indicate etr mode vs. pps mode.
+	 */
+	if (eacr.p0 && aib.esw.psc0 == etr_lpsc_pps_mode) {
+		eacr.sl = 0;
+		eacr.e0 = 1;
+		if (!etr_mode_is_pps(etr_eacr))
+			eacr.es = 0;
+		if (!eacr.es || !eacr.p1 || aib.esw.psc1 != etr_lpsc_pps_mode)
+			eacr.e1 = 0;
+		// FIXME: uptodate checks ?
+		else if (etr_port0_uptodate && etr_port1_uptodate)
+			eacr.e1 = 1;
+		sync_port = (etr_port0_uptodate &&
+			     etr_port_valid(&etr_port0, 0)) ? 0 : -1;
+		clear_bit(ETR_FLAG_EACCES, &etr_flags);
+	} else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_pps_mode) {
+		eacr.sl = 0;
+		eacr.e0 = 0;
+		eacr.e1 = 1;
+		if (!etr_mode_is_pps(etr_eacr))
+			eacr.es = 0;
+		sync_port = (etr_port1_uptodate &&
+			     etr_port_valid(&etr_port1, 1)) ? 1 : -1;
+		clear_bit(ETR_FLAG_EACCES, &etr_flags);
+	} else if (eacr.p0 && aib.esw.psc0 == etr_lpsc_operational_step) {
+		eacr.sl = 1;
+		eacr.e0 = 1;
+		if (!etr_mode_is_etr(etr_eacr))
+			eacr.es = 0;
+		if (!eacr.es || !eacr.p1 ||
+		    aib.esw.psc1 != etr_lpsc_operational_alt)
+			eacr.e1 = 0;
+		else if (etr_port0_uptodate && etr_port1_uptodate &&
+			 etr_compare_network(&etr_port0, &etr_port1))
+			eacr.e1 = 1;
+		sync_port = (etr_port0_uptodate &&
+			     etr_port_valid(&etr_port0, 0)) ? 0 : -1;
+		clear_bit(ETR_FLAG_EACCES, &etr_flags);
+	} else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_operational_step) {
+		eacr.sl = 1;
+		eacr.e0 = 0;
+		eacr.e1 = 1;
+		if (!etr_mode_is_etr(etr_eacr))
+			eacr.es = 0;
+		sync_port = (etr_port1_uptodate &&
+			     etr_port_valid(&etr_port1, 1)) ? 1 : -1;
+		clear_bit(ETR_FLAG_EACCES, &etr_flags);
+	} else {
+		/* Both ports not usable. */
+		eacr.es = eacr.sl = 0;
+		sync_port = -1;
+		set_bit(ETR_FLAG_EACCES, &etr_flags);
+	}
+
+	/*
+	 * If the clock is in sync just update the eacr and return.
+	 * If there is no valid sync port wait for a port update.
+	 */
+	if (eacr.es || sync_port < 0) {
+		etr_update_eacr(eacr);
+		etr_set_tolec_timeout(now);
+		return;
+	}
+
+	/*
+	 * Prepare control register for clock syncing
+	 * (reset data port bit, set sync check control.
+	 */
+	eacr.dp = 0;
+	eacr.es = 1;
+
+	/*
+	 * Update eacr and try to synchronize the clock. If the update
+	 * of eacr caused a stepping port switch (or if we have to
+	 * assume that a stepping port switch has occured) or the
+	 * clock syncing failed, reset the sync check control bit
+	 * and set up a timer to try again after 0.5 seconds
+	 */
+	etr_update_eacr(eacr);
+	if (now < etr_tolec + (1600000 << 12) ||
+	    etr_sync_clock(&aib, sync_port) != 0) {
+		/* Sync failed. Try again in 1/2 second. */
+		eacr.es = 0;
+		etr_update_eacr(eacr);
+		etr_set_sync_timeout();
+	} else
+		etr_set_tolec_timeout(now);
+}
+
+/*
+ * Sysfs interface functions
+ */
+static struct sysdev_class etr_sysclass = {
+	set_kset_name("etr")
+};
+
+static struct sys_device etr_port0_dev = {
+	.id	= 0,
+	.cls	= &etr_sysclass,
+};
+
+static struct sys_device etr_port1_dev = {
+	.id	= 1,
+	.cls	= &etr_sysclass,
+};
+
+/*
+ * ETR class attributes
+ */
+static ssize_t etr_stepping_port_show(struct sysdev_class *class, char *buf)
+{
+	return sprintf(buf, "%i\n", etr_port0.esw.p);
+}
+
+static SYSDEV_CLASS_ATTR(stepping_port, 0400, etr_stepping_port_show, NULL);
+
+static ssize_t etr_stepping_mode_show(struct sysdev_class *class, char *buf)
+{
+	char *mode_str;
+
+	if (etr_mode_is_pps(etr_eacr))
+		mode_str = "pps";
+	else if (etr_mode_is_etr(etr_eacr))
+		mode_str = "etr";
+	else
+		mode_str = "local";
+	return sprintf(buf, "%s\n", mode_str);
+}
+
+static SYSDEV_CLASS_ATTR(stepping_mode, 0400, etr_stepping_mode_show, NULL);
+
+/*
+ * ETR port attributes
+ */
+static inline struct etr_aib *etr_aib_from_dev(struct sys_device *dev)
+{
+	if (dev == &etr_port0_dev)
+		return etr_port0_online ? &etr_port0 : NULL;
+	else
+		return etr_port1_online ? &etr_port1 : NULL;
+}
+
+static ssize_t etr_online_show(struct sys_device *dev, char *buf)
+{
+	unsigned int online;
+
+	online = (dev == &etr_port0_dev) ? etr_port0_online : etr_port1_online;
+	return sprintf(buf, "%i\n", online);
+}
+
+static ssize_t etr_online_store(struct sys_device *dev,
+			      const char *buf, size_t count)
+{
+	unsigned int value;
+
+	value = simple_strtoul(buf, NULL, 0);
+	if (value != 0 && value != 1)
+		return -EINVAL;
+	if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
+		return -ENOSYS;
+	if (dev == &etr_port0_dev) {
+		if (etr_port0_online == value)
+			return count;	/* Nothing to do. */
+		etr_port0_online = value;
+		set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
+		tasklet_hi_schedule(&etr_tasklet);
+	} else {
+		if (etr_port1_online == value)
+			return count;	/* Nothing to do. */
+		etr_port1_online = value;
+		set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
+		tasklet_hi_schedule(&etr_tasklet);
+	}
+	return count;
+}
+
+static SYSDEV_ATTR(online, 0600, etr_online_show, etr_online_store);
+
+static ssize_t etr_stepping_control_show(struct sys_device *dev, char *buf)
+{
+	return sprintf(buf, "%i\n", (dev == &etr_port0_dev) ?
+		       etr_eacr.e0 : etr_eacr.e1);
+}
+
+static SYSDEV_ATTR(stepping_control, 0400, etr_stepping_control_show, NULL);
+
+static ssize_t etr_mode_code_show(struct sys_device *dev, char *buf)
+{
+	if (!etr_port0_online && !etr_port1_online)
+		/* Status word is not uptodate if both ports are offline. */
+		return -ENODATA;
+	return sprintf(buf, "%i\n", (dev == &etr_port0_dev) ?
+		       etr_port0.esw.psc0 : etr_port0.esw.psc1);
+}
+
+static SYSDEV_ATTR(state_code, 0400, etr_mode_code_show, NULL);
+
+static ssize_t etr_untuned_show(struct sys_device *dev, char *buf)
+{
+	struct etr_aib *aib = etr_aib_from_dev(dev);
+
+	if (!aib || !aib->slsw.v1)
+		return -ENODATA;
+	return sprintf(buf, "%i\n", aib->edf1.u);
+}
+
+static SYSDEV_ATTR(untuned, 0400, etr_untuned_show, NULL);
+
+static ssize_t etr_network_id_show(struct sys_device *dev, char *buf)
+{
+	struct etr_aib *aib = etr_aib_from_dev(dev);
+
+	if (!aib || !aib->slsw.v1)
+		return -ENODATA;
+	return sprintf(buf, "%i\n", aib->edf1.net_id);
+}
+
+static SYSDEV_ATTR(network, 0400, etr_network_id_show, NULL);
+
+static ssize_t etr_id_show(struct sys_device *dev, char *buf)
+{
+	struct etr_aib *aib = etr_aib_from_dev(dev);
+
+	if (!aib || !aib->slsw.v1)
+		return -ENODATA;
+	return sprintf(buf, "%i\n", aib->edf1.etr_id);
+}
+
+static SYSDEV_ATTR(id, 0400, etr_id_show, NULL);
+
+static ssize_t etr_port_number_show(struct sys_device *dev, char *buf)
+{
+	struct etr_aib *aib = etr_aib_from_dev(dev);
+
+	if (!aib || !aib->slsw.v1)
+		return -ENODATA;
+	return sprintf(buf, "%i\n", aib->edf1.etr_pn);
+}
+
+static SYSDEV_ATTR(port, 0400, etr_port_number_show, NULL);
+
+static ssize_t etr_coupled_show(struct sys_device *dev, char *buf)
+{
+	struct etr_aib *aib = etr_aib_from_dev(dev);
+
+	if (!aib || !aib->slsw.v3)
+		return -ENODATA;
+	return sprintf(buf, "%i\n", aib->edf3.c);
+}
+
+static SYSDEV_ATTR(coupled, 0400, etr_coupled_show, NULL);
+
+static ssize_t etr_local_time_show(struct sys_device *dev, char *buf)
+{
+	struct etr_aib *aib = etr_aib_from_dev(dev);
+
+	if (!aib || !aib->slsw.v3)
+		return -ENODATA;
+	return sprintf(buf, "%i\n", aib->edf3.blto);
+}
+
+static SYSDEV_ATTR(local_time, 0400, etr_local_time_show, NULL);
+
+static ssize_t etr_utc_offset_show(struct sys_device *dev, char *buf)
+{
+	struct etr_aib *aib = etr_aib_from_dev(dev);
+
+	if (!aib || !aib->slsw.v3)
+		return -ENODATA;
+	return sprintf(buf, "%i\n", aib->edf3.buo);
+}
+
+static SYSDEV_ATTR(utc_offset, 0400, etr_utc_offset_show, NULL);
+
+static struct sysdev_attribute *etr_port_attributes[] = {
+	&attr_online,
+	&attr_stepping_control,
+	&attr_state_code,
+	&attr_untuned,
+	&attr_network,
+	&attr_id,
+	&attr_port,
+	&attr_coupled,
+	&attr_local_time,
+	&attr_utc_offset,
+	NULL
+};
+
+static int __init etr_register_port(struct sys_device *dev)
+{
+	struct sysdev_attribute **attr;
+	int rc;
+
+	rc = sysdev_register(dev);
+	if (rc)
+		goto out;
+	for (attr = etr_port_attributes; *attr; attr++) {
+		rc = sysdev_create_file(dev, *attr);
+		if (rc)
+			goto out_unreg;
+	}
+	return 0;
+out_unreg:
+	for (; attr >= etr_port_attributes; attr--)
+		sysdev_remove_file(dev, *attr);
+	sysdev_unregister(dev);
+out:
+	return rc;
+}
+
+static void __init etr_unregister_port(struct sys_device *dev)
+{
+	struct sysdev_attribute **attr;
+
+	for (attr = etr_port_attributes; *attr; attr++)
+		sysdev_remove_file(dev, *attr);
+	sysdev_unregister(dev);
+}
+
+static int __init etr_init_sysfs(void)
+{
+	int rc;
+
+	rc = sysdev_class_register(&etr_sysclass);
+	if (rc)
+		goto out;
+	rc = sysdev_class_create_file(&etr_sysclass, &attr_stepping_port);
+	if (rc)
+		goto out_unreg_class;
+	rc = sysdev_class_create_file(&etr_sysclass, &attr_stepping_mode);
+	if (rc)
+		goto out_remove_stepping_port;
+	rc = etr_register_port(&etr_port0_dev);
+	if (rc)
+		goto out_remove_stepping_mode;
+	rc = etr_register_port(&etr_port1_dev);
+	if (rc)
+		goto out_remove_port0;
+	return 0;
+
+out_remove_port0:
+	etr_unregister_port(&etr_port0_dev);
+out_remove_stepping_mode:
+	sysdev_class_remove_file(&etr_sysclass, &attr_stepping_mode);
+out_remove_stepping_port:
+	sysdev_class_remove_file(&etr_sysclass, &attr_stepping_port);
+out_unreg_class:
+	sysdev_class_unregister(&etr_sysclass);
+out:
+	return rc;
+}
+
+device_initcall(etr_init_sysfs);
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 3cbb0dc..f0e5a32 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -283,7 +283,7 @@
 	return buffer;
 }
 
-DEFINE_SPINLOCK(die_lock);
+static DEFINE_SPINLOCK(die_lock);
 
 void die(const char * str, struct pt_regs * regs, long err)
 {
@@ -364,8 +364,7 @@
 		force_sig(SIGTRAP, current);
 }
 
-asmlinkage void
-default_trap_handler(struct pt_regs * regs, long interruption_code)
+static void default_trap_handler(struct pt_regs * regs, long interruption_code)
 {
         if (regs->psw.mask & PSW_MASK_PSTATE) {
 		local_irq_enable();
@@ -376,7 +375,7 @@
 }
 
 #define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
-asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+static void name(struct pt_regs * regs, long interruption_code) \
 { \
         siginfo_t info; \
         info.si_signo = signr; \
@@ -442,7 +441,7 @@
 		"floating point exception", regs, &si);
 }
 
-asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
+static void illegal_op(struct pt_regs * regs, long interruption_code)
 {
 	siginfo_t info;
         __u8 opcode[6];
@@ -491,8 +490,15 @@
 #endif
 		} else
 			signal = SIGILL;
-	} else
-		signal = SIGILL;
+	} else {
+		/*
+		 * If we get an illegal op in kernel mode, send it through the
+		 * kprobes notifier. If kprobes doesn't pick it up, SIGILL
+		 */
+		if (notify_die(DIE_BPT, "bpt", regs, interruption_code,
+			       3, SIGTRAP) != NOTIFY_STOP)
+			signal = SIGILL;
+	}
 
 #ifdef CONFIG_MATHEMU
         if (signal == SIGFPE)
@@ -585,7 +591,7 @@
 	      ILL_ILLOPN, get_check_address(regs));
 #endif
 
-asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
+static void data_exception(struct pt_regs * regs, long interruption_code)
 {
 	__u16 __user *location;
 	int signal = 0;
@@ -675,7 +681,7 @@
 	}
 }
 
-asmlinkage void space_switch_exception(struct pt_regs * regs, long int_code)
+static void space_switch_exception(struct pt_regs * regs, long int_code)
 {
         siginfo_t info;
 
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index fe0f2e9..a489073 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -31,19 +31,20 @@
 
   _etext = .;			/* End of text section */
 
-  . = ALIGN(16);		/* Exception table */
-  __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
-  __stop___ex_table = .;
-
   RODATA
 
 #ifdef CONFIG_SHARED_KERNEL
   . = ALIGN(1048576);		/* VM shared segments are 1MB aligned */
-
-  _eshared = .;			/* End of shareable data */
 #endif
 
+  . = ALIGN(4096);
+  _eshared = .;			/* End of shareable data */
+
+  . = ALIGN(16);		/* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
   .data : {			/* Data */
 	*(.data)
 	CONSTRUCTORS
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index 21baaf5..9d5b028 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -25,7 +25,7 @@
 #include <asm/irq_regs.h>
 
 static ext_int_info_t ext_int_info_timer;
-DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
+static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 /*
@@ -524,16 +524,15 @@
 void init_cpu_vtimer(void)
 {
 	struct vtimer_queue *vt_list;
-	unsigned long cr0;
 
 	/* kick the virtual timer */
 	S390_lowcore.exit_timer = VTIMER_MAX_SLICE;
 	S390_lowcore.last_update_timer = VTIMER_MAX_SLICE;
 	asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
 	asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock));
-	__ctl_store(cr0, 0, 0);
-	cr0 |= 0x400;
-	__ctl_load(cr0, 0, 0);
+
+	/* enable cpu timer interrupts */
+	__ctl_set_bit(0,10);
 
 	vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
 	INIT_LIST_HEAD(&vt_list->list);
@@ -572,6 +571,7 @@
 	if (register_idle_notifier(&vtimer_idle_nb))
 		panic("Couldn't register idle notifier");
 
+	/* Enable cpu timer interrupts on the boot cpu. */
 	init_cpu_vtimer();
 }
 
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile
index b5f94cf..7a44fed 100644
--- a/arch/s390/lib/Makefile
+++ b/arch/s390/lib/Makefile
@@ -4,7 +4,7 @@
 
 EXTRA_AFLAGS := -traditional
 
-lib-y += delay.o string.o uaccess_std.o uaccess_pt.o
+lib-y += delay.o string.o uaccess_std.o uaccess_pt.o qrnnd.o
 lib-$(CONFIG_32BIT) += div64.o
 lib-$(CONFIG_64BIT) += uaccess_mvcos.o
 lib-$(CONFIG_SMP) += spinlock.o
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c
index 027c474..0285444 100644
--- a/arch/s390/lib/delay.c
+++ b/arch/s390/lib/delay.c
@@ -1,5 +1,5 @@
 /*
- *  arch/s390/kernel/delay.c
+ *  arch/s390/lib/delay.c
  *    Precise Delay Loops for S390
  *
  *  S390 version
@@ -13,10 +13,8 @@
 
 #include <linux/sched.h>
 #include <linux/delay.h>
-
-#ifdef CONFIG_SMP
-#include <asm/smp.h>
-#endif
+#include <linux/timex.h>
+#include <linux/irqflags.h>
 
 void __delay(unsigned long loops)
 {
@@ -31,17 +29,39 @@
 }
 
 /*
- * Waits for 'usecs' microseconds using the tod clock, giving up the time slice
- * of the virtual PU inbetween to avoid congestion.
+ * Waits for 'usecs' microseconds using the TOD clock comparator.
  */
 void __udelay(unsigned long usecs)
 {
-	uint64_t start_cc;
+	u64 end, time, jiffy_timer = 0;
+	unsigned long flags, cr0, mask, dummy;
 
-        if (usecs == 0)
-                return;
-	start_cc = get_clock();
-        do {
-		cpu_relax();
-	} while (((get_clock() - start_cc)/4096) < usecs);
+	local_irq_save(flags);
+	if (raw_irqs_disabled_flags(flags)) {
+		jiffy_timer = S390_lowcore.jiffy_timer;
+		S390_lowcore.jiffy_timer = -1ULL - (4096 << 12);
+		__ctl_store(cr0, 0, 0);
+		dummy = (cr0 & 0xffff00e0) | 0x00000800;
+		__ctl_load(dummy , 0, 0);
+		mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT;
+	} else
+		mask = psw_kernel_bits | PSW_MASK_WAIT |
+			PSW_MASK_EXT | PSW_MASK_IO;
+
+	end = get_clock() + ((u64) usecs << 12);
+	do {
+		time = end < S390_lowcore.jiffy_timer ?
+			end : S390_lowcore.jiffy_timer;
+		set_clock_comparator(time);
+		trace_hardirqs_on();
+		__load_psw_mask(mask);
+		local_irq_disable();
+	} while (get_clock() < end);
+
+	if (raw_irqs_disabled_flags(flags)) {
+		__ctl_load(cr0, 0, 0);
+		S390_lowcore.jiffy_timer = jiffy_timer;
+	}
+	set_clock_comparator(S390_lowcore.jiffy_timer);
+	local_irq_restore(flags);
 }
diff --git a/arch/s390/lib/qrnnd.S b/arch/s390/lib/qrnnd.S
new file mode 100644
index 0000000..eb1df63
--- /dev/null
+++ b/arch/s390/lib/qrnnd.S
@@ -0,0 +1,77 @@
+# S/390 __udiv_qrnnd
+
+# r2 : &__r
+# r3 : upper half of 64 bit word n
+# r4 : lower half of 64 bit word n
+# r5 : divisor d
+# the reminder r of the division is to be stored to &__r and
+# the quotient q is to be returned
+
+	.text
+	.globl __udiv_qrnnd
+__udiv_qrnnd:
+	st    %r2,24(%r15)	  # store pointer to reminder for later
+	lr    %r0,%r3		  # reload n
+	lr    %r1,%r4
+	ltr   %r2,%r5		  # reload and test divisor
+	jp    5f
+	# divisor >= 0x80000000
+	srdl  %r0,2		  # n/4
+	srl   %r2,1		  # d/2
+	slr   %r1,%r2		  # special case if last bit of d is set
+	brc   3,0f		  #  (n/4) div (n/2) can overflow by 1
+	ahi   %r0,-1		  #  trick: subtract n/2, then divide
+0:	dr    %r0,%r2		  # signed division
+	ahi   %r1,1		  #  trick part 2: add 1 to the quotient
+	# now (n >> 2) = (d >> 1) * %r1 + %r0
+	lhi   %r3,1
+	nr    %r3,%r1		  # test last bit of q
+	jz    1f
+	alr   %r0,%r2		  # add (d>>1) to r
+1:	srl   %r1,1		  # q >>= 1
+	# now (n >> 2) = (d&-2) * %r1 + %r0
+	lhi   %r3,1
+	nr    %r3,%r5		  # test last bit of d
+	jz    2f
+	slr   %r0,%r1		  # r -= q
+	brc   3,2f		  # borrow ?
+	alr   %r0,%r5		  # r += d
+	ahi   %r1,-1
+2:	# now (n >> 2) = d * %r1 + %r0
+	alr   %r1,%r1		  # q <<= 1
+	alr   %r0,%r0		  # r <<= 1
+	brc   12,3f		  # overflow on r ?
+	slr   %r0,%r5		  # r -= d
+	ahi   %r1,1		  # q += 1
+3:	lhi   %r3,2
+	nr    %r3,%r4		  # test next to last bit of n
+	jz    4f
+	ahi   %r0,1		  # r += 1
+4:	clr   %r0,%r5		  # r >= d ?
+	jl    6f
+	slr   %r0,%r5		  # r -= d
+	ahi   %r1,1		  # q += 1
+	# now (n >> 1) = d * %r1 + %r0
+	j     6f
+5:	# divisor < 0x80000000
+	srdl  %r0,1
+	dr    %r0,%r2		  # signed division
+	# now (n >> 1) = d * %r1 + %r0
+6:	alr   %r1,%r1		  # q <<= 1
+	alr   %r0,%r0		  # r <<= 1
+	brc   12,7f		  # overflow on r ?
+	slr   %r0,%r5		  # r -= d
+	ahi   %r1,1		  # q += 1
+7:	lhi   %r3,1
+	nr    %r3,%r4		  # isolate last bit of n
+	alr   %r0,%r3		  # r += (n & 1)
+	clr   %r0,%r5		  # r >= d ?
+	jl    8f
+	slr   %r0,%r5		  # r -= d
+	ahi   %r1,1		  # q += 1
+8:	# now n = d * %r1 + %r0
+	l     %r2,24(%r15)
+	st    %r0,0(%r2)
+	lr    %r2,%r1
+	br    %r14
+	.end	__udiv_qrnnd
diff --git a/arch/s390/lib/uaccess.h b/arch/s390/lib/uaccess.h
new file mode 100644
index 0000000..126011d
--- /dev/null
+++ b/arch/s390/lib/uaccess.h
@@ -0,0 +1,23 @@
+/*
+ *  arch/s390/uaccess.h
+ *
+ *    Copyright IBM Corp. 2007
+ *
+ */
+
+#ifndef __ARCH_S390_LIB_UACCESS_H
+#define __ARCH_S390_LIB_UACCESS_H
+
+extern size_t copy_from_user_std(size_t, const void __user *, void *);
+extern size_t copy_to_user_std(size_t, void __user *, const void *);
+extern size_t strnlen_user_std(size_t, const char __user *);
+extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
+extern int futex_atomic_cmpxchg_std(int __user *, int, int);
+extern int futex_atomic_op_std(int, int __user *, int, int *);
+
+extern size_t copy_from_user_pt(size_t, const void __user *, void *);
+extern size_t copy_to_user_pt(size_t, void __user *, const void *);
+extern int futex_atomic_op_pt(int, int __user *, int, int *);
+extern int futex_atomic_cmpxchg_pt(int __user *, int, int);
+
+#endif /* __ARCH_S390_LIB_UACCESS_H */
diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c
index f9a23d5..6d87723 100644
--- a/arch/s390/lib/uaccess_mvcos.c
+++ b/arch/s390/lib/uaccess_mvcos.c
@@ -12,6 +12,7 @@
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 #include <asm/futex.h>
+#include "uaccess.h"
 
 #ifndef __s390x__
 #define AHI	"ahi"
@@ -27,10 +28,7 @@
 #define SLR	"slgr"
 #endif
 
-extern size_t copy_from_user_std(size_t, const void __user *, void *);
-extern size_t copy_to_user_std(size_t, void __user *, const void *);
-
-size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
+static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
 {
 	register unsigned long reg0 asm("0") = 0x81UL;
 	unsigned long tmp1, tmp2;
@@ -69,14 +67,14 @@
 	return size;
 }
 
-size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x)
+static size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x)
 {
 	if (size <= 256)
 		return copy_from_user_std(size, ptr, x);
 	return copy_from_user_mvcos(size, ptr, x);
 }
 
-size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
+static size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
 {
 	register unsigned long reg0 asm("0") = 0x810000UL;
 	unsigned long tmp1, tmp2;
@@ -105,14 +103,16 @@
 	return size;
 }
 
-size_t copy_to_user_mvcos_check(size_t size, void __user *ptr, const void *x)
+static size_t copy_to_user_mvcos_check(size_t size, void __user *ptr,
+				       const void *x)
 {
 	if (size <= 256)
 		return copy_to_user_std(size, ptr, x);
 	return copy_to_user_mvcos(size, ptr, x);
 }
 
-size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from)
+static size_t copy_in_user_mvcos(size_t size, void __user *to,
+				 const void __user *from)
 {
 	register unsigned long reg0 asm("0") = 0x810081UL;
 	unsigned long tmp1, tmp2;
@@ -134,7 +134,7 @@
 	return size;
 }
 
-size_t clear_user_mvcos(size_t size, void __user *to)
+static size_t clear_user_mvcos(size_t size, void __user *to)
 {
 	register unsigned long reg0 asm("0") = 0x810000UL;
 	unsigned long tmp1, tmp2;
@@ -162,10 +162,43 @@
 	return size;
 }
 
-extern size_t strnlen_user_std(size_t, const char __user *);
-extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
-extern int futex_atomic_op(int, int __user *, int, int *);
-extern int futex_atomic_cmpxchg(int __user *, int, int);
+static size_t strnlen_user_mvcos(size_t count, const char __user *src)
+{
+	char buf[256];
+	int rc;
+	size_t done, len, len_str;
+
+	done = 0;
+	do {
+		len = min(count - done, (size_t) 256);
+		rc = uaccess.copy_from_user(len, src + done, buf);
+		if (unlikely(rc == len))
+			return 0;
+		len -= rc;
+		len_str = strnlen(buf, len);
+		done += len_str;
+	} while ((len_str == len) && (done < count));
+	return done + 1;
+}
+
+static size_t strncpy_from_user_mvcos(size_t count, const char __user *src,
+				      char *dst)
+{
+	int rc;
+	size_t done, len, len_str;
+
+	done = 0;
+	do {
+		len = min(count - done, (size_t) 4096);
+		rc = uaccess.copy_from_user(len, src + done, dst);
+		if (unlikely(rc == len))
+			return -EFAULT;
+		len -= rc;
+		len_str = strnlen(dst, len);
+		done += len_str;
+	} while ((len_str == len) && (done < count));
+	return done;
+}
 
 struct uaccess_ops uaccess_mvcos = {
 	.copy_from_user = copy_from_user_mvcos_check,
@@ -176,6 +209,21 @@
 	.clear_user = clear_user_mvcos,
 	.strnlen_user = strnlen_user_std,
 	.strncpy_from_user = strncpy_from_user_std,
-	.futex_atomic_op = futex_atomic_op,
-	.futex_atomic_cmpxchg = futex_atomic_cmpxchg,
+	.futex_atomic_op = futex_atomic_op_std,
+	.futex_atomic_cmpxchg = futex_atomic_cmpxchg_std,
 };
+
+#ifdef CONFIG_S390_SWITCH_AMODE
+struct uaccess_ops uaccess_mvcos_switch = {
+	.copy_from_user = copy_from_user_mvcos,
+	.copy_from_user_small = copy_from_user_mvcos,
+	.copy_to_user = copy_to_user_mvcos,
+	.copy_to_user_small = copy_to_user_mvcos,
+	.copy_in_user = copy_in_user_mvcos,
+	.clear_user = clear_user_mvcos,
+	.strnlen_user = strnlen_user_mvcos,
+	.strncpy_from_user = strncpy_from_user_mvcos,
+	.futex_atomic_op = futex_atomic_op_pt,
+	.futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
+};
+#endif
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index 49c3e46..6318167 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -1,7 +1,8 @@
 /*
  *  arch/s390/lib/uaccess_pt.c
  *
- *  User access functions based on page table walks.
+ *  User access functions based on page table walks for enhanced
+ *  system layout without hardware support.
  *
  *    Copyright IBM Corp. 2006
  *    Author(s): Gerald Schaefer (gerald.schaefer@de.ibm.com)
@@ -12,9 +13,10 @@
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 #include <asm/futex.h>
+#include "uaccess.h"
 
-static inline int __handle_fault(struct mm_struct *mm, unsigned long address,
-				 int write_access)
+static int __handle_fault(struct mm_struct *mm, unsigned long address,
+			  int write_access)
 {
 	struct vm_area_struct *vma;
 	int ret = -EFAULT;
@@ -79,8 +81,8 @@
 	return ret;
 }
 
-static inline size_t __user_copy_pt(unsigned long uaddr, void *kptr,
-				    size_t n, int write_user)
+static size_t __user_copy_pt(unsigned long uaddr, void *kptr,
+			     size_t n, int write_user)
 {
 	struct mm_struct *mm = current->mm;
 	unsigned long offset, pfn, done, size;
@@ -133,6 +135,49 @@
 	goto retry;
 }
 
+/*
+ * Do DAT for user address by page table walk, return kernel address.
+ * This function needs to be called with current->mm->page_table_lock held.
+ */
+static unsigned long __dat_user_addr(unsigned long uaddr)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long pfn, ret;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+	int rc;
+
+	ret = 0;
+retry:
+	pgd = pgd_offset(mm, uaddr);
+	if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+		goto fault;
+
+	pmd = pmd_offset(pgd, uaddr);
+	if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+		goto fault;
+
+	pte = pte_offset_map(pmd, uaddr);
+	if (!pte || !pte_present(*pte))
+		goto fault;
+
+	pfn = pte_pfn(*pte);
+	if (!pfn_valid(pfn))
+		goto out;
+
+	ret = (pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE - 1));
+out:
+	return ret;
+fault:
+	spin_unlock(&mm->page_table_lock);
+	rc = __handle_fault(mm, uaddr, 0);
+	spin_lock(&mm->page_table_lock);
+	if (rc)
+		goto out;
+	goto retry;
+}
+
 size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
 {
 	size_t rc;
@@ -155,3 +200,277 @@
 	}
 	return __user_copy_pt((unsigned long) to, (void *) from, n, 1);
 }
+
+static size_t clear_user_pt(size_t n, void __user *to)
+{
+	long done, size, ret;
+
+	if (segment_eq(get_fs(), KERNEL_DS)) {
+		memset((void __kernel __force *) to, 0, n);
+		return 0;
+	}
+	done = 0;
+	do {
+		if (n - done > PAGE_SIZE)
+			size = PAGE_SIZE;
+		else
+			size = n - done;
+		ret = __user_copy_pt((unsigned long) to + done,
+				      &empty_zero_page, size, 1);
+		done += size;
+		if (ret)
+			return ret + n - done;
+	} while (done < n);
+	return 0;
+}
+
+static size_t strnlen_user_pt(size_t count, const char __user *src)
+{
+	char *addr;
+	unsigned long uaddr = (unsigned long) src;
+	struct mm_struct *mm = current->mm;
+	unsigned long offset, pfn, done, len;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+	size_t len_str;
+
+	if (segment_eq(get_fs(), KERNEL_DS))
+		return strnlen((const char __kernel __force *) src, count) + 1;
+	done = 0;
+retry:
+	spin_lock(&mm->page_table_lock);
+	do {
+		pgd = pgd_offset(mm, uaddr);
+		if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+			goto fault;
+
+		pmd = pmd_offset(pgd, uaddr);
+		if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+			goto fault;
+
+		pte = pte_offset_map(pmd, uaddr);
+		if (!pte || !pte_present(*pte))
+			goto fault;
+
+		pfn = pte_pfn(*pte);
+		if (!pfn_valid(pfn)) {
+			done = -1;
+			goto out;
+		}
+
+		offset = uaddr & (PAGE_SIZE-1);
+		addr = (char *)(pfn << PAGE_SHIFT) + offset;
+		len = min(count - done, PAGE_SIZE - offset);
+		len_str = strnlen(addr, len);
+		done += len_str;
+		uaddr += len_str;
+	} while ((len_str == len) && (done < count));
+out:
+	spin_unlock(&mm->page_table_lock);
+	return done + 1;
+fault:
+	spin_unlock(&mm->page_table_lock);
+	if (__handle_fault(mm, uaddr, 0)) {
+		return 0;
+	}
+	goto retry;
+}
+
+static size_t strncpy_from_user_pt(size_t count, const char __user *src,
+				   char *dst)
+{
+	size_t n = strnlen_user_pt(count, src);
+
+	if (!n)
+		return -EFAULT;
+	if (n > count)
+		n = count;
+	if (segment_eq(get_fs(), KERNEL_DS)) {
+		memcpy(dst, (const char __kernel __force *) src, n);
+		if (dst[n-1] == '\0')
+			return n-1;
+		else
+			return n;
+	}
+	if (__user_copy_pt((unsigned long) src, dst, n, 0))
+		return -EFAULT;
+	if (dst[n-1] == '\0')
+		return n-1;
+	else
+		return n;
+}
+
+static size_t copy_in_user_pt(size_t n, void __user *to,
+			      const void __user *from)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long offset_from, offset_to, offset_max, pfn_from, pfn_to,
+		      uaddr, done, size;
+	unsigned long uaddr_from = (unsigned long) from;
+	unsigned long uaddr_to = (unsigned long) to;
+	pgd_t *pgd_from, *pgd_to;
+	pmd_t *pmd_from, *pmd_to;
+	pte_t *pte_from, *pte_to;
+	int write_user;
+
+	done = 0;
+retry:
+	spin_lock(&mm->page_table_lock);
+	do {
+		pgd_from = pgd_offset(mm, uaddr_from);
+		if (pgd_none(*pgd_from) || unlikely(pgd_bad(*pgd_from))) {
+			uaddr = uaddr_from;
+			write_user = 0;
+			goto fault;
+		}
+		pgd_to = pgd_offset(mm, uaddr_to);
+		if (pgd_none(*pgd_to) || unlikely(pgd_bad(*pgd_to))) {
+			uaddr = uaddr_to;
+			write_user = 1;
+			goto fault;
+		}
+
+		pmd_from = pmd_offset(pgd_from, uaddr_from);
+		if (pmd_none(*pmd_from) || unlikely(pmd_bad(*pmd_from))) {
+			uaddr = uaddr_from;
+			write_user = 0;
+			goto fault;
+		}
+		pmd_to = pmd_offset(pgd_to, uaddr_to);
+		if (pmd_none(*pmd_to) || unlikely(pmd_bad(*pmd_to))) {
+			uaddr = uaddr_to;
+			write_user = 1;
+			goto fault;
+		}
+
+		pte_from = pte_offset_map(pmd_from, uaddr_from);
+		if (!pte_from || !pte_present(*pte_from)) {
+			uaddr = uaddr_from;
+			write_user = 0;
+			goto fault;
+		}
+		pte_to = pte_offset_map(pmd_to, uaddr_to);
+		if (!pte_to || !pte_present(*pte_to) || !pte_write(*pte_to)) {
+			uaddr = uaddr_to;
+			write_user = 1;
+			goto fault;
+		}
+
+		pfn_from = pte_pfn(*pte_from);
+		if (!pfn_valid(pfn_from))
+			goto out;
+		pfn_to = pte_pfn(*pte_to);
+		if (!pfn_valid(pfn_to))
+			goto out;
+
+		offset_from = uaddr_from & (PAGE_SIZE-1);
+		offset_to = uaddr_from & (PAGE_SIZE-1);
+		offset_max = max(offset_from, offset_to);
+		size = min(n - done, PAGE_SIZE - offset_max);
+
+		memcpy((void *)(pfn_to << PAGE_SHIFT) + offset_to,
+		       (void *)(pfn_from << PAGE_SHIFT) + offset_from, size);
+		done += size;
+		uaddr_from += size;
+		uaddr_to += size;
+	} while (done < n);
+out:
+	spin_unlock(&mm->page_table_lock);
+	return n - done;
+fault:
+	spin_unlock(&mm->page_table_lock);
+	if (__handle_fault(mm, uaddr, write_user))
+		return n - done;
+	goto retry;
+}
+
+#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg)	\
+	asm volatile("0: l   %1,0(%6)\n"				\
+		     "1: " insn						\
+		     "2: cs  %1,%2,0(%6)\n"				\
+		     "3: jl  1b\n"					\
+		     "   lhi %0,0\n"					\
+		     "4:\n"						\
+		     EX_TABLE(0b,4b) EX_TABLE(2b,4b) EX_TABLE(3b,4b)	\
+		     : "=d" (ret), "=&d" (oldval), "=&d" (newval),	\
+		       "=m" (*uaddr)					\
+		     : "0" (-EFAULT), "d" (oparg), "a" (uaddr),		\
+		       "m" (*uaddr) : "cc" );
+
+int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
+{
+	int oldval = 0, newval, ret;
+
+	spin_lock(&current->mm->page_table_lock);
+	uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
+	if (!uaddr) {
+		spin_unlock(&current->mm->page_table_lock);
+		return -EFAULT;
+	}
+	get_page(virt_to_page(uaddr));
+	spin_unlock(&current->mm->page_table_lock);
+	switch (op) {
+	case FUTEX_OP_SET:
+		__futex_atomic_op("lr %2,%5\n",
+				  ret, oldval, newval, uaddr, oparg);
+		break;
+	case FUTEX_OP_ADD:
+		__futex_atomic_op("lr %2,%1\nar %2,%5\n",
+				  ret, oldval, newval, uaddr, oparg);
+		break;
+	case FUTEX_OP_OR:
+		__futex_atomic_op("lr %2,%1\nor %2,%5\n",
+				  ret, oldval, newval, uaddr, oparg);
+		break;
+	case FUTEX_OP_ANDN:
+		__futex_atomic_op("lr %2,%1\nnr %2,%5\n",
+				  ret, oldval, newval, uaddr, oparg);
+		break;
+	case FUTEX_OP_XOR:
+		__futex_atomic_op("lr %2,%1\nxr %2,%5\n",
+				  ret, oldval, newval, uaddr, oparg);
+		break;
+	default:
+		ret = -ENOSYS;
+	}
+	put_page(virt_to_page(uaddr));
+	*old = oldval;
+	return ret;
+}
+
+int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+{
+	int ret;
+
+	spin_lock(&current->mm->page_table_lock);
+	uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
+	if (!uaddr) {
+		spin_unlock(&current->mm->page_table_lock);
+		return -EFAULT;
+	}
+	get_page(virt_to_page(uaddr));
+	spin_unlock(&current->mm->page_table_lock);
+	asm volatile("   cs   %1,%4,0(%5)\n"
+		     "0: lr   %0,%1\n"
+		     "1:\n"
+		     EX_TABLE(0b,1b)
+		     : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
+		     : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
+		     : "cc", "memory" );
+	put_page(virt_to_page(uaddr));
+	return ret;
+}
+
+struct uaccess_ops uaccess_pt = {
+	.copy_from_user		= copy_from_user_pt,
+	.copy_from_user_small	= copy_from_user_pt,
+	.copy_to_user		= copy_to_user_pt,
+	.copy_to_user_small	= copy_to_user_pt,
+	.copy_in_user		= copy_in_user_pt,
+	.clear_user		= clear_user_pt,
+	.strnlen_user		= strnlen_user_pt,
+	.strncpy_from_user	= strncpy_from_user_pt,
+	.futex_atomic_op	= futex_atomic_op_pt,
+	.futex_atomic_cmpxchg	= futex_atomic_cmpxchg_pt,
+};
diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c
index 56a0214..28c4500 100644
--- a/arch/s390/lib/uaccess_std.c
+++ b/arch/s390/lib/uaccess_std.c
@@ -13,6 +13,7 @@
 #include <linux/mm.h>
 #include <linux/uaccess.h>
 #include <asm/futex.h>
+#include "uaccess.h"
 
 #ifndef __s390x__
 #define AHI	"ahi"
@@ -28,9 +29,6 @@
 #define SLR	"slgr"
 #endif
 
-extern size_t copy_from_user_pt(size_t n, const void __user *from, void *to);
-extern size_t copy_to_user_pt(size_t n, void __user *to, const void *from);
-
 size_t copy_from_user_std(size_t size, const void __user *ptr, void *x)
 {
 	unsigned long tmp1, tmp2;
@@ -72,7 +70,8 @@
 	return size;
 }
 
-size_t copy_from_user_std_check(size_t size, const void __user *ptr, void *x)
+static size_t copy_from_user_std_check(size_t size, const void __user *ptr,
+				       void *x)
 {
 	if (size <= 1024)
 		return copy_from_user_std(size, ptr, x);
@@ -110,14 +109,16 @@
 	return size;
 }
 
-size_t copy_to_user_std_check(size_t size, void __user *ptr, const void *x)
+static size_t copy_to_user_std_check(size_t size, void __user *ptr,
+				     const void *x)
 {
 	if (size <= 1024)
 		return copy_to_user_std(size, ptr, x);
 	return copy_to_user_pt(size, ptr, x);
 }
 
-size_t copy_in_user_std(size_t size, void __user *to, const void __user *from)
+static size_t copy_in_user_std(size_t size, void __user *to,
+			       const void __user *from)
 {
 	unsigned long tmp1;
 
@@ -148,7 +149,7 @@
 	return size;
 }
 
-size_t clear_user_std(size_t size, void __user *to)
+static size_t clear_user_std(size_t size, void __user *to)
 {
 	unsigned long tmp1, tmp2;
 
@@ -254,7 +255,7 @@
 		: "0" (-EFAULT), "d" (oparg), "a" (uaddr),		\
 		  "m" (*uaddr) : "cc");
 
-int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old)
+int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
 {
 	int oldval = 0, newval, ret;
 
@@ -286,7 +287,7 @@
 	return ret;
 }
 
-int futex_atomic_cmpxchg(int __user *uaddr, int oldval, int newval)
+int futex_atomic_cmpxchg_std(int __user *uaddr, int oldval, int newval)
 {
 	int ret;
 
@@ -311,6 +312,6 @@
 	.clear_user = clear_user_std,
 	.strnlen_user = strnlen_user_std,
 	.strncpy_from_user = strncpy_from_user_std,
-	.futex_atomic_op = futex_atomic_op,
-	.futex_atomic_cmpxchg = futex_atomic_cmpxchg,
+	.futex_atomic_op = futex_atomic_op_std,
+	.futex_atomic_cmpxchg = futex_atomic_cmpxchg_std,
 };
diff --git a/arch/s390/math-emu/Makefile b/arch/s390/math-emu/Makefile
index c10df14..73b3e72 100644
--- a/arch/s390/math-emu/Makefile
+++ b/arch/s390/math-emu/Makefile
@@ -2,7 +2,7 @@
 # Makefile for the FPU instruction emulation.
 #
 
-obj-$(CONFIG_MATHEMU) := math.o qrnnd.o
+obj-$(CONFIG_MATHEMU) := math.o
 
 EXTRA_CFLAGS := -I$(src) -Iinclude/math-emu -w
 EXTRA_AFLAGS := -traditional
diff --git a/arch/s390/math-emu/math.c b/arch/s390/math-emu/math.c
index 6b9aec5..3ee78cc 100644
--- a/arch/s390/math-emu/math.c
+++ b/arch/s390/math-emu/math.c
@@ -15,7 +15,7 @@
 #include <asm/uaccess.h>
 #include <asm/lowcore.h>
 
-#include "sfp-util.h"
+#include <asm/sfp-util.h>
 #include <math-emu/soft-fp.h>
 #include <math-emu/single.h>
 #include <math-emu/double.h>
diff --git a/arch/s390/math-emu/qrnnd.S b/arch/s390/math-emu/qrnnd.S
deleted file mode 100644
index b01c2b6..0000000
--- a/arch/s390/math-emu/qrnnd.S
+++ /dev/null
@@ -1,77 +0,0 @@
-# S/390 __udiv_qrnnd
-
-# r2 : &__r
-# r3 : upper half of 64 bit word n
-# r4 : lower half of 64 bit word n
-# r5 : divisor d
-# the reminder r of the division is to be stored to &__r and
-# the quotient q is to be returned
-
-        .text
-        .globl __udiv_qrnnd
-__udiv_qrnnd:
-        st    %r2,24(%r15)        # store pointer to reminder for later
-        lr    %r0,%r3             # reload n
-	lr    %r1,%r4
-	ltr   %r2,%r5             # reload and test divisor
-        jp    5f
-        # divisor >= 0x80000000
-	srdl  %r0,2               # n/4
-        srl   %r2,1               # d/2
-        slr   %r1,%r2             # special case if last bit of d is set
-        brc   3,0f                #  (n/4) div (n/2) can overflow by 1
-        ahi   %r0,-1              #  trick: subtract n/2, then divide
-0:      dr    %r0,%r2             # signed division
-        ahi   %r1,1               #  trick part 2: add 1 to the quotient
-        # now (n >> 2) = (d >> 1) * %r1 + %r0
-	lhi   %r3,1
-        nr    %r3,%r1             # test last bit of q
-        jz    1f
-        alr   %r0,%r2             # add (d>>1) to r
-1:      srl   %r1,1               # q >>= 1
-        # now (n >> 2) = (d&-2) * %r1 + %r0
-        lhi   %r3,1
-        nr    %r3,%r5             # test last bit of d
-        jz    2f
-        slr   %r0,%r1             # r -= q
-	brc   3,2f                # borrow ?
-	alr   %r0,%r5             # r += d
-	ahi   %r1,-1
-2:      # now (n >> 2) = d * %r1 + %r0
-        alr   %r1,%r1             # q <<= 1
-        alr   %r0,%r0             # r <<= 1
-        brc   12,3f               # overflow on r ?
-        slr   %r0,%r5             # r -= d
-        ahi   %r1,1               # q += 1
-3:      lhi   %r3,2
-        nr    %r3,%r4             # test next to last bit of n
-        jz    4f
-        ahi   %r0,1               # r += 1
-4:      clr   %r0,%r5             # r >= d ?
-        jl    6f
-        slr   %r0,%r5             # r -= d
-        ahi   %r1,1               # q += 1
-        # now (n >> 1) = d * %r1 + %r0
-        j     6f
-5:      # divisor < 0x80000000
-	srdl  %r0,1
-        dr    %r0,%r2             # signed division
-        # now (n >> 1) = d * %r1 + %r0
-6:      alr   %r1,%r1             # q <<= 1
-        alr   %r0,%r0             # r <<= 1
-        brc   12,7f               # overflow on r ?
-        slr   %r0,%r5             # r -= d
-        ahi   %r1,1               # q += 1
-7:      lhi   %r3,1
-        nr    %r3,%r4             # isolate last bit of n
-        alr   %r0,%r3             # r += (n & 1)
-        clr   %r0,%r5             # r >= d ?
-        jl    8f
-        slr   %r0,%r5             # r -= d
-        ahi   %r1,1               # q += 1
-8:      # now n = d * %r1 + %r0
-	l     %r2,24(%r15)
-        st    %r0,0(%r2)
-        lr    %r2,%r1
-        br    %r14
-	.end	__udiv_qrnnd
diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c
index 607f50e..f93a056 100644
--- a/arch/s390/mm/cmm.c
+++ b/arch/s390/mm/cmm.c
@@ -245,7 +245,7 @@
 	cmm_set_timer();
 }
 
-static inline int
+static int
 cmm_skip_blanks(char *cp, char **endp)
 {
 	char *str;
@@ -414,7 +414,7 @@
 }
 #endif
 
-struct ctl_table_header *cmm_sysctl_header;
+static struct ctl_table_header *cmm_sysctl_header;
 
 static int
 cmm_init (void)
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c
index 775bf19..394980b 100644
--- a/arch/s390/mm/extmem.c
+++ b/arch/s390/mm/extmem.c
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/bootmem.h>
 #include <linux/ctype.h>
+#include <linux/ioport.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/ebcdic.h>
@@ -70,6 +71,7 @@
 struct dcss_segment {
 	struct list_head list;
 	char dcss_name[8];
+	char res_name[15];
 	unsigned long start_addr;
 	unsigned long end;
 	atomic_t ref_count;
@@ -77,6 +79,7 @@
 	unsigned int vm_segtype;
 	struct qrange range[6];
 	int segcnt;
+	struct resource *res;
 };
 
 static DEFINE_MUTEX(dcss_lock);
@@ -88,7 +91,7 @@
  * Create the 8 bytes, ebcdic VM segment name from
  * an ascii name.
  */
-static void inline
+static void
 dcss_mkname(char *name, char *dcss_name)
 {
 	int i;
@@ -303,6 +306,29 @@
 		goto out_free;
 	}
 
+	seg->res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+	if (seg->res == NULL) {
+		rc = -ENOMEM;
+		goto out_shared;
+	}
+	seg->res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
+	seg->res->start = seg->start_addr;
+	seg->res->end = seg->end;
+	memcpy(&seg->res_name, seg->dcss_name, 8);
+	EBCASC(seg->res_name, 8);
+	seg->res_name[8] = '\0';
+	strncat(seg->res_name, " (DCSS)", 7);
+	seg->res->name = seg->res_name;
+	rc = seg->vm_segtype;
+	if (rc == SEG_TYPE_SC ||
+	    ((rc == SEG_TYPE_SR || rc == SEG_TYPE_ER) && !do_nonshared))
+		seg->res->flags |= IORESOURCE_READONLY;
+	if (request_resource(&iomem_resource, seg->res)) {
+		rc = -EBUSY;
+		kfree(seg->res);
+		goto out_shared;
+	}
+
 	if (do_nonshared)
 		dcss_command = DCSS_LOADNSR;
 	else
@@ -316,12 +342,11 @@
 		rc = dcss_diag_translate_rc (seg->end);
 		dcss_diag(DCSS_PURGESEG, seg->dcss_name,
 				&seg->start_addr, &seg->end);
-		goto out_shared;
+		goto out_resource;
 	}
 	seg->do_nonshared = do_nonshared;
 	atomic_set(&seg->ref_count, 1);
 	list_add(&seg->list, &dcss_list);
-	rc = seg->vm_segtype;
 	*addr = seg->start_addr;
 	*end  = seg->end;
 	if (do_nonshared)
@@ -329,12 +354,16 @@
 				"type %s in non-shared mode\n", name,
 				(void*)seg->start_addr, (void*)seg->end,
 				segtype_string[seg->vm_segtype]);
-	else
+	else {
 		PRINT_INFO ("segment_load: loaded segment %s range %p .. %p "
 				"type %s in shared mode\n", name,
 				(void*)seg->start_addr, (void*)seg->end,
 				segtype_string[seg->vm_segtype]);
+	}
 	goto out;
+ out_resource:
+	release_resource(seg->res);
+	kfree(seg->res);
  out_shared:
 	remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
  out_free:
@@ -401,6 +430,7 @@
  * -ENOENT  : no such segment (segment gone!)
  * -EAGAIN  : segment is in use by other exploiters, try later
  * -EINVAL  : no segment with the given name is currently loaded - name invalid
+ * -EBUSY   : segment can temporarily not be used (overlaps with dcss)
  * 0	    : operation succeeded
  */
 int
@@ -428,12 +458,24 @@
 		rc = -EAGAIN;
 		goto out_unlock;
 	}
-	dcss_diag(DCSS_PURGESEG, seg->dcss_name,
-		  &dummy, &dummy);
-	if (do_nonshared)
+	release_resource(seg->res);
+	if (do_nonshared) {
 		dcss_command = DCSS_LOADNSR;
-	else
-	dcss_command = DCSS_LOADNOLY;
+		seg->res->flags &= ~IORESOURCE_READONLY;
+	} else {
+		dcss_command = DCSS_LOADNOLY;
+		if (seg->vm_segtype == SEG_TYPE_SR ||
+		    seg->vm_segtype == SEG_TYPE_ER)
+			seg->res->flags |= IORESOURCE_READONLY;
+	}
+	if (request_resource(&iomem_resource, seg->res)) {
+		PRINT_WARN("segment_modify_shared: could not reload segment %s"
+			   " - overlapping resources\n", name);
+		rc = -EBUSY;
+		kfree(seg->res);
+		goto out_del;
+	}
+	dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
 	diag_cc = dcss_diag(dcss_command, seg->dcss_name,
 			&seg->start_addr, &seg->end);
 	if (diag_cc > 1) {
@@ -446,9 +488,9 @@
 	rc = 0;
 	goto out_unlock;
  out_del:
+	remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
 	list_del(&seg->list);
-	dcss_diag(DCSS_PURGESEG, seg->dcss_name,
-		  &dummy, &dummy);
+	dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
 	kfree(seg);
  out_unlock:
 	mutex_unlock(&dcss_lock);
@@ -478,6 +520,8 @@
 	}
 	if (atomic_dec_return(&seg->ref_count) != 0)
 		goto out_unlock;
+	release_resource(seg->res);
+	kfree(seg->res);
 	remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
 	list_del(&seg->list);
 	dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index cd85e34..9ff143e 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -52,7 +52,7 @@
 extern void die(const char *,struct pt_regs *,long);
 
 #ifdef CONFIG_KPROBES
-ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
+static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
 int register_page_fault_notifier(struct notifier_block *nb)
 {
 	return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
@@ -137,7 +137,9 @@
 
 /*
  * Check which address space the address belongs to.
- * Returns 1 for user space and 0 for kernel space.
+ * May return 1 or 2 for user space and 0 for kernel space.
+ * Returns 2 for user space in primary addressing mode with
+ * CONFIG_S390_EXEC_PROTECT on and kernel parameter noexec=on.
  */
 static inline int check_user_space(struct pt_regs *regs, int error_code)
 {
@@ -154,7 +156,7 @@
 		return __check_access_register(regs, error_code);
 	if (descriptor == 2)
 		return current->thread.mm_segment.ar4;
-	return descriptor != 0;
+	return ((descriptor != 0) ^ (switch_amode)) << s390_noexec;
 }
 
 /*
@@ -183,6 +185,77 @@
 	force_sig_info(SIGSEGV, &si, current);
 }
 
+#ifdef CONFIG_S390_EXEC_PROTECT
+extern long sys_sigreturn(struct pt_regs *regs);
+extern long sys_rt_sigreturn(struct pt_regs *regs);
+extern long sys32_sigreturn(struct pt_regs *regs);
+extern long sys32_rt_sigreturn(struct pt_regs *regs);
+
+static inline void do_sigreturn(struct mm_struct *mm, struct pt_regs *regs,
+				int rt)
+{
+	up_read(&mm->mmap_sem);
+	clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
+#ifdef CONFIG_COMPAT
+	if (test_tsk_thread_flag(current, TIF_31BIT)) {
+		if (rt)
+			sys32_rt_sigreturn(regs);
+		else
+			sys32_sigreturn(regs);
+		return;
+	}
+#endif /* CONFIG_COMPAT */
+	if (rt)
+		sys_rt_sigreturn(regs);
+	else
+		sys_sigreturn(regs);
+	return;
+}
+
+static int signal_return(struct mm_struct *mm, struct pt_regs *regs,
+			 unsigned long address, unsigned long error_code)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+	u16 *instruction;
+	unsigned long pfn, uaddr = regs->psw.addr;
+
+	spin_lock(&mm->page_table_lock);
+	pgd = pgd_offset(mm, uaddr);
+	if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+		goto out_fault;
+	pmd = pmd_offset(pgd, uaddr);
+	if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+		goto out_fault;
+	pte = pte_offset_map(pmd_offset(pgd_offset(mm, uaddr), uaddr), uaddr);
+	if (!pte || !pte_present(*pte))
+		goto out_fault;
+	pfn = pte_pfn(*pte);
+	if (!pfn_valid(pfn))
+		goto out_fault;
+	spin_unlock(&mm->page_table_lock);
+
+	instruction = (u16 *) ((pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE-1)));
+	if (*instruction == 0x0a77)
+		do_sigreturn(mm, regs, 0);
+	else if (*instruction == 0x0aad)
+		do_sigreturn(mm, regs, 1);
+	else {
+		printk("- XXX - do_exception: task = %s, primary, NO EXEC "
+		       "-> SIGSEGV\n", current->comm);
+		up_read(&mm->mmap_sem);
+		current->thread.prot_addr = address;
+		current->thread.trap_no = error_code;
+		do_sigsegv(regs, error_code, SEGV_MAPERR, address);
+	}
+	return 0;
+out_fault:
+	spin_unlock(&mm->page_table_lock);
+	return -EFAULT;
+}
+#endif /* CONFIG_S390_EXEC_PROTECT */
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
@@ -260,6 +333,17 @@
         vma = find_vma(mm, address);
         if (!vma)
                 goto bad_area;
+
+#ifdef CONFIG_S390_EXEC_PROTECT
+	if (unlikely((user_address == 2) && !(vma->vm_flags & VM_EXEC)))
+		if (!signal_return(mm, regs, address, error_code))
+			/*
+			 * signal_return() has done an up_read(&mm->mmap_sem)
+			 * if it returns 0.
+			 */
+			return;
+#endif
+
         if (vma->vm_start <= address) 
                 goto good_area;
         if (!(vma->vm_flags & VM_GROWSDOWN))
@@ -452,8 +536,7 @@
 		: : "a" (&refbk), "m" (refbk) : "cc");
 }
 
-asmlinkage void
-pfault_interrupt(__u16 error_code)
+static void pfault_interrupt(__u16 error_code)
 {
 	struct task_struct *tsk;
 	__u16 subcode;
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index 4bb21be..b3e7c45 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -25,7 +25,7 @@
 #include <linux/bootmem.h>
 #include <linux/pfn.h>
 #include <linux/poison.h>
-
+#include <linux/initrd.h>
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -95,20 +95,18 @@
 	pte_t new_pte;
 	unsigned long address, end;
 
-	address = ((unsigned long)&__start_rodata) & PAGE_MASK;
-	end = PFN_ALIGN((unsigned long)&__end_rodata);
+	address = ((unsigned long)&_stext) & PAGE_MASK;
+	end = PFN_ALIGN((unsigned long)&_eshared);
 
 	for (; address < end; address += PAGE_SIZE) {
 		pgd = pgd_offset_k(address);
 		pmd = pmd_offset(pgd, address);
 		pte = pte_offset_kernel(pmd, address);
 		new_pte = mk_pte_phys(address, __pgprot(_PAGE_RO));
-		set_pte(pte, new_pte);
+		*pte = new_pte;
 	}
 }
 
-extern void vmem_map_init(void);
-
 /*
  * paging_init() sets up the page tables
  */
@@ -125,11 +123,11 @@
 #ifdef CONFIG_64BIT
 	pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERN_REGION_TABLE;
 	for (i = 0; i < PTRS_PER_PGD; i++)
-		pgd_clear(pg_dir + i);
+		pgd_clear_kernel(pg_dir + i);
 #else
 	pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
 	for (i = 0; i < PTRS_PER_PGD; i++)
-		pmd_clear((pmd_t *)(pg_dir + i));
+		pmd_clear_kernel((pmd_t *)(pg_dir + i));
 #endif
 	vmem_map_init();
 	setup_ro_region();
@@ -174,10 +172,8 @@
                 datasize >>10,
                 initsize >> 10);
 	printk("Write protected kernel read-only data: %#lx - %#lx\n",
-	       (unsigned long)&__start_rodata,
-	       PFN_ALIGN((unsigned long)&__end_rodata) - 1);
-	printk("Virtual memmap size: %ldk\n",
-	       (max_pfn * sizeof(struct page)) >> 10);
+	       (unsigned long)&_stext,
+	       PFN_ALIGN((unsigned long)&_eshared) - 1);
 }
 
 void free_initmem(void)
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index cd3d93e..92a5651 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -82,7 +82,7 @@
 	if (!pmd)
 		return NULL;
 	for (i = 0; i < PTRS_PER_PMD; i++)
-		pmd_clear(pmd + i);
+		pmd_clear_kernel(pmd + i);
 	return pmd;
 }
 
@@ -97,7 +97,7 @@
 		return NULL;
 	pte_val(empty_pte) = _PAGE_TYPE_EMPTY;
 	for (i = 0; i < PTRS_PER_PTE; i++)
-		set_pte(pte + i, empty_pte);
+		pte[i] = empty_pte;
 	return pte;
 }
 
@@ -119,7 +119,7 @@
 			pm_dir = vmem_pmd_alloc();
 			if (!pm_dir)
 				goto out;
-			pgd_populate(&init_mm, pg_dir, pm_dir);
+			pgd_populate_kernel(&init_mm, pg_dir, pm_dir);
 		}
 
 		pm_dir = pmd_offset(pg_dir, address);
@@ -132,7 +132,7 @@
 
 		pt_dir = pte_offset_kernel(pm_dir, address);
 		pte = pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL);
-		set_pte(pt_dir, pte);
+		*pt_dir = pte;
 	}
 	ret = 0;
 out:
@@ -161,7 +161,7 @@
 		if (pmd_none(*pm_dir))
 			continue;
 		pt_dir = pte_offset_kernel(pm_dir, address);
-		set_pte(pt_dir, pte);
+		*pt_dir = pte;
 	}
 	flush_tlb_kernel_range(start, start + size);
 }
@@ -191,7 +191,7 @@
 			pm_dir = vmem_pmd_alloc();
 			if (!pm_dir)
 				goto out;
-			pgd_populate(&init_mm, pg_dir, pm_dir);
+			pgd_populate_kernel(&init_mm, pg_dir, pm_dir);
 		}
 
 		pm_dir = pmd_offset(pg_dir, address);
@@ -210,7 +210,7 @@
 			if (!new_page)
 				goto out;
 			pte = pfn_pte(new_page >> PAGE_SHIFT, PAGE_KERNEL);
-			set_pte(pt_dir, pte);
+			*pt_dir = pte;
 		}
 	}
 	ret = 0;
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 3aa3b88..4f38912 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -48,6 +48,9 @@
 config GENERIC_TIME
 	def_bool n
 
+config SYS_SUPPORTS_APM_EMULATION
+	bool
+
 config ARCH_MAY_HAVE_PC_FDC
 	bool
 
@@ -126,6 +129,7 @@
 
 config SH_HP6XX
 	bool "HP6XX"
+	select SYS_SUPPORTS_APM_EMULATION
 	help
 	  Select HP6XX if configuring for a HP jornada HP6xx.
 	  More information (hardware only) at
@@ -694,9 +698,6 @@
 
 source kernel/power/Kconfig
 
-config APM
-	bool "Advanced Power Management Emulation"
-	depends on PM
 endmenu
 
 source "net/Kconfig"
diff --git a/arch/sh/boards/hp6xx/hp6xx_apm.c b/arch/sh/boards/hp6xx/hp6xx_apm.c
index d146cda..d1c1460 100644
--- a/arch/sh/boards/hp6xx/hp6xx_apm.c
+++ b/arch/sh/boards/hp6xx/hp6xx_apm.c
@@ -7,12 +7,11 @@
  * modify it under the terms of the GNU General Public License.
  */
 #include <linux/module.h>
-#include <linux/apm_bios.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/io.h>
-#include <asm/apm.h>
+#include <linux/apm-emulation.h>
+#include <linux/io.h>
 #include <asm/adc.h>
 #include <asm/hp6xx.h>
 
@@ -27,60 +26,41 @@
 
 #define MODNAME "hp6x0_apm"
 
-static int hp6x0_apm_get_info(char *buf, char **start, off_t fpos, int length)
+static void hp6x0_apm_get_power_status(struct apm_power_info *info)
 {
+	int battery, backup, charging, percentage;
 	u8 pgdr;
-	char *p;
-	int battery_status;
-	int battery_flag;
-	int ac_line_status;
-	int time_units = APM_BATTERY_LIFE_UNKNOWN;
 
-	int battery = adc_single(ADC_CHANNEL_BATTERY);
-	int backup = adc_single(ADC_CHANNEL_BACKUP);
-	int charging = adc_single(ADC_CHANNEL_CHARGE);
-	int percentage;
+	battery		= adc_single(ADC_CHANNEL_BATTERY);
+	backup		= adc_single(ADC_CHANNEL_BACKUP);
+	charging	= adc_single(ADC_CHANNEL_CHARGE);
 
 	percentage = 100 * (battery - HP680_BATTERY_MIN) /
 			   (HP680_BATTERY_MAX - HP680_BATTERY_MIN);
 
-	ac_line_status = (battery > HP680_BATTERY_AC_ON) ?
+	info->ac_line_status = (battery > HP680_BATTERY_AC_ON) ?
 			 APM_AC_ONLINE : APM_AC_OFFLINE;
 
-	p = buf;
-
 	pgdr = ctrl_inb(SH7709_PGDR);
 	if (pgdr & PGDR_MAIN_BATTERY_OUT) {
-		battery_status = APM_BATTERY_STATUS_NOT_PRESENT;
-		battery_flag = 0x80;
-		percentage = -1;
-	} else if (charging < 8 ) {
-		battery_status = APM_BATTERY_STATUS_CHARGING;
-		battery_flag = 0x08;
-		ac_line_status = 0xff;
+		info->battery_status	= APM_BATTERY_STATUS_NOT_PRESENT;
+		info->battery_flag	= 0x80;
+	} else if (charging < 8) {
+		info->battery_status	= APM_BATTERY_STATUS_CHARGING;
+		info->battery_flag	= 0x08;
+		info->ac_line_status = 0xff;
 	} else if (percentage <= APM_CRITICAL) {
-		battery_status = APM_BATTERY_STATUS_CRITICAL;
-		battery_flag = 0x04;
+		info->battery_status	= APM_BATTERY_STATUS_CRITICAL;
+		info->battery_flag	= 0x04;
 	} else if (percentage <= APM_LOW) {
-		battery_status = APM_BATTERY_STATUS_LOW;
-		battery_flag = 0x02;
+		info->battery_status	= APM_BATTERY_STATUS_LOW;
+		info->battery_flag	= 0x02;
 	} else {
-		battery_status = APM_BATTERY_STATUS_HIGH;
-		battery_flag = 0x01;
+		info->battery_status	= APM_BATTERY_STATUS_HIGH;
+		info->battery_flag	= 0x01;
 	}
 
-	p += sprintf(p, "1.0 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
-		     APM_32_BIT_SUPPORT,
-		     ac_line_status,
-		     battery_status,
-		     battery_flag,
-		     percentage,
-		     time_units,
-		     "min");
-	p += sprintf(p, "bat=%d backup=%d charge=%d\n",
-		     battery, backup, charging);
-
-	return p - buf;
+	info->units = 0;
 }
 
 static irqreturn_t hp6x0_apm_interrupt(int irq, void *dev)
@@ -96,14 +76,14 @@
 	int ret;
 
 	ret = request_irq(HP680_BTN_IRQ, hp6x0_apm_interrupt,
-			  IRQF_DISABLED, MODNAME, 0);
+			  IRQF_DISABLED, MODNAME, NULL);
 	if (unlikely(ret < 0)) {
 		printk(KERN_ERR MODNAME ": IRQ %d request failed\n",
 		       HP680_BTN_IRQ);
 		return ret;
 	}
 
-	apm_get_info = hp6x0_apm_get_info;
+	apm_get_power_status = hp6x0_apm_get_power_status;
 
 	return ret;
 }
@@ -111,7 +91,7 @@
 static void __exit hp6x0_apm_exit(void)
 {
 	free_irq(HP680_BTN_IRQ, 0);
-	apm_get_info = 0;
+	apm_get_info = NULL;
 }
 
 module_init(hp6x0_apm_init);
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index 99c7e52..2f6d2bc 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -19,6 +19,5 @@
 obj-$(CONFIG_MODULES)		+= module.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
-obj-$(CONFIG_APM)		+= apm.o
 obj-$(CONFIG_PM)		+= pm.o
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
diff --git a/arch/sh/kernel/apm.c b/arch/sh/kernel/apm.c
deleted file mode 100644
index 4f66f91..0000000
--- a/arch/sh/kernel/apm.c
+++ /dev/null
@@ -1,538 +0,0 @@
-/*
- * bios-less APM driver for hp680
- *
- * Copyright 2005 (c) Andriy Skulysh <askulysh@gmail.com>
- *
- * based on ARM APM driver by
- *  Jamey Hicks <jamey@crl.dec.com>
- *
- * adapted from the APM BIOS driver for Linux by
- *  Stephen Rothwell (sfr@linuxcare.com)
- *
- * APM 1.2 Reference:
- *   Intel Corporation, Microsoft Corporation. Advanced Power Management
- *   (APM) BIOS Interface Specification, Revision 1.2, February 1996.
- *
- * [This document is available from Microsoft at:
- *    http://www.microsoft.com/hwdev/busbios/amp_12.htm]
- */
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/timer.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include <linux/miscdevice.h>
-#include <linux/apm_bios.h>
-#include <linux/pm.h>
-#include <linux/pm_legacy.h>
-#include <asm/apm.h>
-
-#define MODNAME "apm"
-
-/*
- * The apm_bios device is one of the misc char devices.
- * This is its minor number.
- */
-#define APM_MINOR_DEV			134
-
-/*
- * Maximum number of events stored
- */
-#define APM_MAX_EVENTS			16
-
-struct apm_queue {
-	unsigned int		event_head;
-	unsigned int		event_tail;
-	apm_event_t		events[APM_MAX_EVENTS];
-};
-
-/*
- * The per-file APM data
- */
-struct apm_user {
-	struct list_head	list;
-
-	unsigned int		suser: 1;
-	unsigned int		writer: 1;
-	unsigned int		reader: 1;
-
-	int			suspend_result;
-	unsigned int		suspend_state;
-#define SUSPEND_NONE	0		/* no suspend pending */
-#define SUSPEND_PENDING	1		/* suspend pending read */
-#define SUSPEND_READ	2		/* suspend read, pending ack */
-#define SUSPEND_ACKED	3		/* suspend acked */
-#define SUSPEND_DONE	4		/* suspend completed */
-
-	struct apm_queue	queue;
-};
-
-/*
- * Local variables
- */
-static int suspends_pending;
-
-static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
-static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
-
-/*
- * This is a list of everyone who has opened /dev/apm_bios
- */
-static DECLARE_RWSEM(user_list_lock);
-static LIST_HEAD(apm_user_list);
-
-/*
- * kapmd info.  kapmd provides us a process context to handle
- * "APM" events within - specifically necessary if we're going
- * to be suspending the system.
- */
-static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait);
-static DECLARE_COMPLETION(kapmd_exit);
-static DEFINE_SPINLOCK(kapmd_queue_lock);
-static struct apm_queue kapmd_queue;
-
-int apm_suspended;
-EXPORT_SYMBOL(apm_suspended);
-
-/* Platform-specific apm_read_proc(). */
-int (*apm_get_info)(char *buf, char **start, off_t fpos, int length);
-EXPORT_SYMBOL(apm_get_info);
-
-/*
- * APM event queue management.
- */
-static inline int queue_empty(struct apm_queue *q)
-{
-	return q->event_head == q->event_tail;
-}
-
-static inline apm_event_t queue_get_event(struct apm_queue *q)
-{
-	q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
-	return q->events[q->event_tail];
-}
-
-static void queue_add_event(struct apm_queue *q, apm_event_t event)
-{
-	q->event_head = (q->event_head + 1) % APM_MAX_EVENTS;
-	if (q->event_head == q->event_tail) {
-		static int notified;
-
-		if (notified++ == 0)
-			printk(KERN_ERR "apm: an event queue overflowed\n");
-
-		q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
-	}
-	q->events[q->event_head] = event;
-}
-
-static void queue_event_one_user(struct apm_user *as, apm_event_t event)
-{
-	if (as->suser && as->writer) {
-		switch (event) {
-		case APM_SYS_SUSPEND:
-		case APM_USER_SUSPEND:
-			/*
-			 * If this user already has a suspend pending,
-			 * don't queue another one.
-			 */
-			if (as->suspend_state != SUSPEND_NONE)
-				return;
-
-			as->suspend_state = SUSPEND_PENDING;
-			suspends_pending++;
-			break;
-		}
-	}
-	queue_add_event(&as->queue, event);
-}
-
-static void queue_event(apm_event_t event, struct apm_user *sender)
-{
-	struct apm_user *as;
-
-	down_read(&user_list_lock);
-
-	list_for_each_entry(as, &apm_user_list, list)
-		if (as != sender && as->reader)
-			queue_event_one_user(as, event);
-
-	up_read(&user_list_lock);
-	wake_up_interruptible(&apm_waitqueue);
-}
-
-/**
- * apm_queue_event - queue an APM event for kapmd
- * @event: APM event
- *
- * Queue an APM event for kapmd to process and ultimately take the
- * appropriate action.  Only a subset of events are handled:
- *   %APM_LOW_BATTERY
- *   %APM_POWER_STATUS_CHANGE
- *   %APM_USER_SUSPEND
- *   %APM_SYS_SUSPEND
- *   %APM_CRITICAL_SUSPEND
- */
-void apm_queue_event(apm_event_t event)
-{
-	spin_lock_irq(&kapmd_queue_lock);
-	queue_add_event(&kapmd_queue, event);
-	spin_unlock_irq(&kapmd_queue_lock);
-
-	wake_up_interruptible(&kapmd_wait);
-}
-EXPORT_SYMBOL(apm_queue_event);
-
-static void apm_suspend(void)
-{
-	struct apm_user *as;
-	int err;
-
-	apm_suspended = 1;
-	err = pm_suspend(PM_SUSPEND_MEM);
-
-	/*
-	 * Anyone on the APM queues will think we're still suspended.
-	 * Send a message so everyone knows we're now awake again.
-	 */
-	queue_event(APM_NORMAL_RESUME, NULL);
-
-	/*
-	 * Finally, wake up anyone who is sleeping on the suspend.
-	 */
-	down_read(&user_list_lock);
-	list_for_each_entry(as, &apm_user_list, list) {
-		as->suspend_result = err;
-		as->suspend_state = SUSPEND_DONE;
-	}
-	up_read(&user_list_lock);
-
-	wake_up(&apm_suspend_waitqueue);
-	apm_suspended = 0;
-}
-
-static ssize_t apm_read(struct file *fp, char __user *buf,
-			size_t count, loff_t *ppos)
-{
-	struct apm_user *as = fp->private_data;
-	apm_event_t event;
-	int i = count, ret = 0;
-
-	if (count < sizeof(apm_event_t))
-		return -EINVAL;
-
-	if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK)
-		return -EAGAIN;
-
-	wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue));
-
-	while ((i >= sizeof(event)) && !queue_empty(&as->queue)) {
-		event = queue_get_event(&as->queue);
-
-		ret = -EFAULT;
-		if (copy_to_user(buf, &event, sizeof(event)))
-			break;
-
-		if (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND)
-			as->suspend_state = SUSPEND_READ;
-
-		buf += sizeof(event);
-		i -= sizeof(event);
-	}
-
-	if (i < count)
-		ret = count - i;
-
-	return ret;
-}
-
-static unsigned int apm_poll(struct file *fp, poll_table * wait)
-{
-	struct apm_user *as = fp->private_data;
-
-	poll_wait(fp, &apm_waitqueue, wait);
-	return queue_empty(&as->queue) ? 0 : POLLIN | POLLRDNORM;
-}
-
-/*
- * apm_ioctl - handle APM ioctl
- *
- * APM_IOC_SUSPEND
- *   This IOCTL is overloaded, and performs two functions.  It is used to:
- *     - initiate a suspend
- *     - acknowledge a suspend read from /dev/apm_bios.
- *   Only when everyone who has opened /dev/apm_bios with write permission
- *   has acknowledge does the actual suspend happen.
- */
-static int
-apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg)
-{
-	struct apm_user *as = filp->private_data;
-	unsigned long flags;
-	int err = -EINVAL;
-
-	if (!as->suser || !as->writer)
-		return -EPERM;
-
-	switch (cmd) {
-	case APM_IOC_SUSPEND:
-		as->suspend_result = -EINTR;
-
-		if (as->suspend_state == SUSPEND_READ) {
-			/*
-			 * If we read a suspend command from /dev/apm_bios,
-			 * then the corresponding APM_IOC_SUSPEND ioctl is
-			 * interpreted as an acknowledge.
-			 */
-			as->suspend_state = SUSPEND_ACKED;
-			suspends_pending--;
-		} else {
-			/*
-			 * Otherwise it is a request to suspend the system.
-			 * Queue an event for all readers, and expect an
-			 * acknowledge from all writers who haven't already
-			 * acknowledged.
-			 */
-			queue_event(APM_USER_SUSPEND, as);
-		}
-
-		/*
-		 * If there are no further acknowledges required, suspend
-		 * the system.
-		 */
-		if (suspends_pending == 0)
-			apm_suspend();
-
-		/*
-		 * Wait for the suspend/resume to complete.  If there are
-		 * pending acknowledges, we wait here for them.
-		 *
-		 * Note that we need to ensure that the PM subsystem does
-		 * not kick us out of the wait when it suspends the threads.
-		 */
-		flags = current->flags;
-		current->flags |= PF_NOFREEZE;
-
-		/*
-		 * Note: do not allow a thread which is acking the suspend
-		 * to escape until the resume is complete.
-		 */
-		if (as->suspend_state == SUSPEND_ACKED)
-			wait_event(apm_suspend_waitqueue,
-					 as->suspend_state == SUSPEND_DONE);
-		else
-			wait_event_interruptible(apm_suspend_waitqueue,
-					 as->suspend_state == SUSPEND_DONE);
-
-		current->flags = flags;
-		err = as->suspend_result;
-		as->suspend_state = SUSPEND_NONE;
-		break;
-	}
-
-	return err;
-}
-
-static int apm_release(struct inode * inode, struct file * filp)
-{
-	struct apm_user *as = filp->private_data;
-	filp->private_data = NULL;
-
-	down_write(&user_list_lock);
-	list_del(&as->list);
-	up_write(&user_list_lock);
-
-	/*
-	 * We are now unhooked from the chain.  As far as new
-	 * events are concerned, we no longer exist.  However, we
-	 * need to balance suspends_pending, which means the
-	 * possibility of sleeping.
-	 */
-	if (as->suspend_state != SUSPEND_NONE) {
-		suspends_pending -= 1;
-		if (suspends_pending == 0)
-			apm_suspend();
-	}
-
-	kfree(as);
-	return 0;
-}
-
-static int apm_open(struct inode * inode, struct file * filp)
-{
-	struct apm_user *as;
-
-	as = kzalloc(sizeof(*as), GFP_KERNEL);
-	if (as) {
-		/*
-		 * XXX - this is a tiny bit broken, when we consider BSD
-		 * process accounting. If the device is opened by root, we
-		 * instantly flag that we used superuser privs. Who knows,
-		 * we might close the device immediately without doing a
-		 * privileged operation -- cevans
-		 */
-		as->suser = capable(CAP_SYS_ADMIN);
-		as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
-		as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
-
-		down_write(&user_list_lock);
-		list_add(&as->list, &apm_user_list);
-		up_write(&user_list_lock);
-
-		filp->private_data = as;
-	}
-
-	return as ? 0 : -ENOMEM;
-}
-
-static struct file_operations apm_bios_fops = {
-	.owner		= THIS_MODULE,
-	.read		= apm_read,
-	.poll		= apm_poll,
-	.ioctl		= apm_ioctl,
-	.open		= apm_open,
-	.release	= apm_release,
-};
-
-static struct miscdevice apm_device = {
-	.minor		= APM_MINOR_DEV,
-	.name		= "apm_bios",
-	.fops		= &apm_bios_fops
-};
-
-
-#ifdef CONFIG_PROC_FS
-/*
- * Arguments, with symbols from linux/apm_bios.h.
- *
- *   0) Linux driver version (this will change if format changes)
- *   1) APM BIOS Version.  Usually 1.0, 1.1 or 1.2.
- *   2) APM flags from APM Installation Check (0x00):
- *	bit 0: APM_16_BIT_SUPPORT
- *	bit 1: APM_32_BIT_SUPPORT
- *	bit 2: APM_IDLE_SLOWS_CLOCK
- *	bit 3: APM_BIOS_DISABLED
- *	bit 4: APM_BIOS_DISENGAGED
- *   3) AC line status
- *	0x00: Off-line
- *	0x01: On-line
- *	0x02: On backup power (BIOS >= 1.1 only)
- *	0xff: Unknown
- *   4) Battery status
- *	0x00: High
- *	0x01: Low
- *	0x02: Critical
- *	0x03: Charging
- *	0x04: Selected battery not present (BIOS >= 1.2 only)
- *	0xff: Unknown
- *   5) Battery flag
- *	bit 0: High
- *	bit 1: Low
- *	bit 2: Critical
- *	bit 3: Charging
- *	bit 7: No system battery
- *	0xff: Unknown
- *   6) Remaining battery life (percentage of charge):
- *	0-100: valid
- *	-1: Unknown
- *   7) Remaining battery life (time units):
- *	Number of remaining minutes or seconds
- *	-1: Unknown
- *   8) min = minutes; sec = seconds
- */
-static int apm_read_proc(char *buf, char **start, off_t fpos, int length)
-{
-	if (likely(apm_get_info))
-		return apm_get_info(buf, start, fpos, length);
-
-	return -EINVAL;
-}
-#endif
-
-static int kapmd(void *arg)
-{
-	daemonize("kapmd");
-	current->flags |= PF_NOFREEZE;
-
-	do {
-		apm_event_t event;
-
-		wait_event_interruptible(kapmd_wait,
-				!queue_empty(&kapmd_queue) || !pm_active);
-
-		if (!pm_active)
-			break;
-
-		spin_lock_irq(&kapmd_queue_lock);
-		event = 0;
-		if (!queue_empty(&kapmd_queue))
-			event = queue_get_event(&kapmd_queue);
-		spin_unlock_irq(&kapmd_queue_lock);
-
-		switch (event) {
-		case 0:
-			break;
-
-		case APM_LOW_BATTERY:
-		case APM_POWER_STATUS_CHANGE:
-			queue_event(event, NULL);
-			break;
-
-		case APM_USER_SUSPEND:
-		case APM_SYS_SUSPEND:
-			queue_event(event, NULL);
-			if (suspends_pending == 0)
-				apm_suspend();
-			break;
-
-		case APM_CRITICAL_SUSPEND:
-			apm_suspend();
-			break;
-		}
-	} while (1);
-
-	complete_and_exit(&kapmd_exit, 0);
-}
-
-static int __init apm_init(void)
-{
-	int ret;
-
-	pm_active = 1;
-
-	ret = kernel_thread(kapmd, NULL, CLONE_KERNEL);
-	if (unlikely(ret < 0)) {
-		pm_active = 0;
-		return ret;
-	}
-
-	create_proc_info_entry("apm", 0, NULL, apm_read_proc);
-
-	ret = misc_register(&apm_device);
-	if (unlikely(ret != 0)) {
-		remove_proc_entry("apm", NULL);
-
-		pm_active = 0;
-		wake_up(&kapmd_wait);
-		wait_for_completion(&kapmd_exit);
-	}
-
-	return ret;
-}
-
-static void __exit apm_exit(void)
-{
-	misc_deregister(&apm_device);
-	remove_proc_entry("apm", NULL);
-
-	pm_active = 0;
-	wake_up(&kapmd_wait);
-	wait_for_completion(&kapmd_exit);
-}
-
-module_init(apm_init);
-module_exit(apm_exit);
-
-MODULE_AUTHOR("Stephen Rothwell, Andriy Skulysh");
-MODULE_DESCRIPTION("Advanced Power Management");
-MODULE_LICENSE("GPL");
diff --git a/arch/sh/kernel/vsyscall/vsyscall.c b/arch/sh/kernel/vsyscall/vsyscall.c
index deb4694..7b0f66f 100644
--- a/arch/sh/kernel/vsyscall/vsyscall.c
+++ b/arch/sh/kernel/vsyscall/vsyscall.c
@@ -37,11 +37,12 @@
  * of the ELF DSO images included therein.
  */
 extern const char vsyscall_trapa_start, vsyscall_trapa_end;
-static void *syscall_page;
+static struct page *syscall_pages[1];
 
 int __init vsyscall_init(void)
 {
-	syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
+	void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
+	syscall_pages[0] = virt_to_page(syscall_page);
 
 	/*
 	 * XXX: Map this page to a fixmap entry if we get around
@@ -55,37 +56,10 @@
 	return 0;
 }
 
-static struct page *syscall_vma_nopage(struct vm_area_struct *vma,
-				       unsigned long address, int *type)
-{
-	unsigned long offset = address - vma->vm_start;
-	struct page *page;
-
-	if (address < vma->vm_start || address > vma->vm_end)
-		return NOPAGE_SIGBUS;
-
-	page = virt_to_page(syscall_page + offset);
-
-	get_page(page);
-
-	return page;
-}
-
-/* Prevent VMA merging */
-static void syscall_vma_close(struct vm_area_struct *vma)
-{
-}
-
-static struct vm_operations_struct syscall_vm_ops = {
-	.nopage	= syscall_vma_nopage,
-	.close	= syscall_vma_close,
-};
-
 /* Setup a VMA at program startup for the vsyscall page */
 int arch_setup_additional_pages(struct linux_binprm *bprm,
 				int executable_stack)
 {
-	struct vm_area_struct *vma;
 	struct mm_struct *mm = current->mm;
 	unsigned long addr;
 	int ret;
@@ -97,30 +71,16 @@
 		goto up_fail;
 	}
 
-	vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
-	if (!vma) {
-		ret = -ENOMEM;
+	ret = install_special_mapping(mm, addr, PAGE_SIZE,
+				      VM_READ | VM_EXEC |
+				      VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC |
+				      VM_ALWAYSDUMP,
+				      syscall_pages);
+	if (unlikely(ret))
 		goto up_fail;
-	}
-
-	vma->vm_start = addr;
-	vma->vm_end = addr + PAGE_SIZE;
-	/* MAYWRITE to allow gdb to COW and set breakpoints */
-	vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE;
-	vma->vm_flags |= mm->def_flags;
-	vma->vm_page_prot = protection_map[vma->vm_flags & 7];
-	vma->vm_ops = &syscall_vm_ops;
-	vma->vm_mm = mm;
-
-	ret = insert_vm_struct(mm, vma);
-	if (unlikely(ret)) {
-		kmem_cache_free(vm_area_cachep, vma);
-		goto up_fail;
-	}
 
 	current->mm->context.vdso = (void *)addr;
 
-	mm->total_vm++;
 up_fail:
 	up_write(&mm->mmap_sem);
 	return ret;
diff --git a/arch/x86_64/ia32/syscall32.c b/arch/x86_64/ia32/syscall32.c
index 59f1fa1..568ff0d 100644
--- a/arch/x86_64/ia32/syscall32.c
+++ b/arch/x86_64/ia32/syscall32.c
@@ -18,68 +18,34 @@
 extern unsigned char syscall32_sysenter[], syscall32_sysenter_end[];
 extern int sysctl_vsyscall32;
 
-char *syscall32_page; 
+static struct page *syscall32_pages[1];
 static int use_sysenter = -1;
 
-static struct page *
-syscall32_nopage(struct vm_area_struct *vma, unsigned long adr, int *type)
-{
-	struct page *p = virt_to_page(adr - vma->vm_start + syscall32_page);
-	get_page(p);
-	return p;
-}
-
-/* Prevent VMA merging */
-static void syscall32_vma_close(struct vm_area_struct *vma)
-{
-}
-
-static struct vm_operations_struct syscall32_vm_ops = {
-	.close = syscall32_vma_close,
-	.nopage = syscall32_nopage,
-};
-
 struct linux_binprm;
 
 /* Setup a VMA at program startup for the vsyscall page */
 int syscall32_setup_pages(struct linux_binprm *bprm, int exstack)
 {
-	int npages = (VSYSCALL32_END - VSYSCALL32_BASE) >> PAGE_SHIFT;
-	struct vm_area_struct *vma;
 	struct mm_struct *mm = current->mm;
 	int ret;
 
-	vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
-	if (!vma)
-		return -ENOMEM;
-
-	memset(vma, 0, sizeof(struct vm_area_struct));
-	/* Could randomize here */
-	vma->vm_start = VSYSCALL32_BASE;
-	vma->vm_end = VSYSCALL32_END;
-	/* MAYWRITE to allow gdb to COW and set breakpoints */
-	vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE;
+	down_write(&mm->mmap_sem);
 	/*
+	 * MAYWRITE to allow gdb to COW and set breakpoints
+	 *
 	 * Make sure the vDSO gets into every core dump.
 	 * Dumping its contents makes post-mortem fully interpretable later
 	 * without matching up the same kernel and hardware config to see
 	 * what PC values meant.
 	 */
-	vma->vm_flags |= VM_ALWAYSDUMP;
-	vma->vm_flags |= mm->def_flags;
-	vma->vm_page_prot = protection_map[vma->vm_flags & 7];
-	vma->vm_ops = &syscall32_vm_ops;
-	vma->vm_mm = mm;
-
-	down_write(&mm->mmap_sem);
-	if ((ret = insert_vm_struct(mm, vma))) {
-		up_write(&mm->mmap_sem);
-		kmem_cache_free(vm_area_cachep, vma);
-		return ret;
-	}
-	mm->total_vm += npages;
+	/* Could randomize here */
+	ret = install_special_mapping(mm, VSYSCALL32_BASE, PAGE_SIZE,
+				      VM_READ|VM_EXEC|
+				      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
+				      VM_ALWAYSDUMP,
+				      syscall32_pages);
 	up_write(&mm->mmap_sem);
-	return 0;
+	return ret;
 }
 
 const char *arch_vma_name(struct vm_area_struct *vma)
@@ -92,9 +58,10 @@
 
 static int __init init_syscall32(void)
 { 
-	syscall32_page = (void *)get_zeroed_page(GFP_KERNEL); 
+	char *syscall32_page = (void *)get_zeroed_page(GFP_KERNEL);
 	if (!syscall32_page) 
 		panic("Cannot allocate syscall32 page"); 
+	syscall32_pages[0] = virt_to_page(syscall32_page);
  	if (use_sysenter > 0) {
  		memcpy(syscall32_page, syscall32_sysenter,
  		       syscall32_sysenter_end - syscall32_sysenter);
diff --git a/arch/x86_64/kernel/early-quirks.c b/arch/x86_64/kernel/early-quirks.c
index 49802f1..bd30d13 100644
--- a/arch/x86_64/kernel/early-quirks.c
+++ b/arch/x86_64/kernel/early-quirks.c
@@ -32,7 +32,7 @@
 
 static int nvidia_hpet_detected __initdata;
 
-static int __init nvidia_hpet_check(unsigned long phys, unsigned long size)
+static int __init nvidia_hpet_check(struct acpi_table_header *header)
 {
 	nvidia_hpet_detected = 1;
 	return 0;
@@ -53,7 +53,7 @@
 		return;
 
 	nvidia_hpet_detected = 0;
-	acpi_table_parse(ACPI_HPET, nvidia_hpet_check);
+	acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check);
 	if (nvidia_hpet_detected == 0) {
 		acpi_skip_timer_override = 1;
 		printk(KERN_INFO "Nvidia board "
diff --git a/arch/x86_64/kernel/genapic.c b/arch/x86_64/kernel/genapic.c
index b007433..0b3603a 100644
--- a/arch/x86_64/kernel/genapic.c
+++ b/arch/x86_64/kernel/genapic.c
@@ -58,8 +58,8 @@
 	 * Some x86_64 machines use physical APIC mode regardless of how many
 	 * procs/clusters are present (x86_64 ES7000 is an example).
 	 */
-	if (acpi_fadt.revision > FADT2_REVISION_ID)
-		if (acpi_fadt.force_apic_physical_destination_mode) {
+	if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID)
+		if (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL) {
 			genapic = &apic_cluster;
 			goto print;
 		}
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index d7bad90..6be6730 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -1956,24 +1956,31 @@
 	.retrigger	= ioapic_retrigger_irq,
 };
 
-int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
+int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
 {
 	struct msi_msg msg;
-	int ret;
+	int irq, ret;
+	irq = create_irq();
+	if (irq < 0)
+		return irq;
+
+	set_irq_msi(irq, desc);
 	ret = msi_compose_msg(dev, irq, &msg);
-	if (ret < 0)
+	if (ret < 0) {
+		destroy_irq(irq);
 		return ret;
+	}
 
 	write_msi_msg(irq, &msg);
 
 	set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
 
-	return 0;
+	return irq;
 }
 
 void arch_teardown_msi_irq(unsigned int irq)
 {
-	return;
+	destroy_irq(irq);
 }
 
 #endif /* CONFIG_PCI_MSI */
diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c
index 0807256..50dd8be 100644
--- a/arch/x86_64/kernel/mpparse.c
+++ b/arch/x86_64/kernel/mpparse.c
@@ -798,7 +798,7 @@
 		return gsi;
 
 	/* Don't set up the ACPI SCI because it's already set up */
-	if (acpi_fadt.sci_int == gsi)
+	if (acpi_gbl_FADT.sci_interrupt == gsi)
 		return gsi;
 
 	ioapic = mp_find_ioapic(gsi);
diff --git a/arch/x86_64/kernel/pci-swiotlb.c b/arch/x86_64/kernel/pci-swiotlb.c
index 697f0aa..eb18be5 100644
--- a/arch/x86_64/kernel/pci-swiotlb.c
+++ b/arch/x86_64/kernel/pci-swiotlb.c
@@ -29,7 +29,7 @@
 	.dma_supported = NULL,
 };
 
-void pci_swiotlb_init(void)
+void __init pci_swiotlb_init(void)
 {
 	/* don't initialize swiotlb if iommu=off (no_iommu=1) */
 	if (!iommu_detected && !no_iommu && end_pfn > MAX_DMA32_PFN)
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index 5cc76d0..335cc91 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -498,7 +498,7 @@
 {
 	unsigned int year, mon, day, hour, min, sec;
 	unsigned long flags;
-	unsigned extyear = 0;
+	unsigned century = 0;
 
 	spin_lock_irqsave(&rtc_lock, flags);
 
@@ -510,9 +510,9 @@
 		mon = CMOS_READ(RTC_MONTH);
 		year = CMOS_READ(RTC_YEAR);
 #ifdef CONFIG_ACPI
-		if (acpi_fadt.revision >= FADT2_REVISION_ID &&
-					acpi_fadt.century)
-			extyear = CMOS_READ(acpi_fadt.century);
+		if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
+					acpi_gbl_FADT.century)
+			century = CMOS_READ(acpi_gbl_FADT.century);
 #endif
 	} while (sec != CMOS_READ(RTC_SECONDS));
 
@@ -530,10 +530,10 @@
 	BCD_TO_BIN(mon);
 	BCD_TO_BIN(year);
 
-	if (extyear) {
-		BCD_TO_BIN(extyear);
-		year += extyear;
-		printk(KERN_INFO "Extended CMOS year: %d\n", extyear);
+	if (century) {
+		BCD_TO_BIN(century);
+		year += century * 100;
+		printk(KERN_INFO "Extended CMOS year: %d\n", century * 100);
 	} else { 
 		/*
 		 * x86-64 systems only exists since 2002.
@@ -954,7 +954,7 @@
  	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
 #ifdef CONFIG_ACPI
 		/* But TSC doesn't tick in C3 so don't use it there */
-		if (acpi_fadt.length > 0 && acpi_fadt.plvl3_lat < 1000)
+		if (acpi_gbl_FADT.header.length > 0 && acpi_gbl_FADT.C3latency < 1000)
 			return 1;
 #endif
  		return 0;
diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c
index 1087e15..2efe215 100644
--- a/arch/x86_64/mm/srat.c
+++ b/arch/x86_64/mm/srat.c
@@ -101,7 +101,7 @@
 static __init int slit_valid(struct acpi_table_slit *slit)
 {
 	int i, j;
-	int d = slit->localities;
+	int d = slit->locality_count;
 	for (i = 0; i < d; i++) {
 		for (j = 0; j < d; j++)  {
 			u8 val = slit->entry[d*i + j];
@@ -127,18 +127,18 @@
 
 /* Callback for Proximity Domain -> LAPIC mapping */
 void __init
-acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa)
+acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
 {
 	int pxm, node;
 	if (srat_disabled())
 		return;
-	if (pa->header.length != sizeof(struct acpi_table_processor_affinity)) {
+	if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) {
 		bad_srat();
 		return;
 	}
-	if (pa->flags.enabled == 0)
+	if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
 		return;
-	pxm = pa->proximity_domain;
+	pxm = pa->proximity_domain_lo;
 	node = setup_node(pxm);
 	if (node < 0) {
 		printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
@@ -254,21 +254,21 @@
 	/* Looks good */
 
 	if (nd->start == nd->end) {
- 		nd->start = start;
- 		nd->end = end;
+		nd->start = start;
+		nd->end = end;
 		changed = 1;
- 	} else {
- 		if (nd->start == end) {
- 			nd->start = start;
+	} else {
+		if (nd->start == end) {
+			nd->start = start;
 			changed = 1;
 		}
- 		if (nd->end == start) {
- 			nd->end = end;
+		if (nd->end == start) {
+			nd->end = end;
 			changed = 1;
 		}
 		if (!changed)
 			printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n");
- 	}
+	}
 
 	ret = update_end_of_memory(nd->end);
 
@@ -279,7 +279,7 @@
 
 /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
 void __init
-acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
+acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
 {
 	struct bootnode *nd, oldnode;
 	unsigned long start, end;
@@ -288,16 +288,17 @@
 
 	if (srat_disabled())
 		return;
-	if (ma->header.length != sizeof(struct acpi_table_memory_affinity)) {
+	if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) {
 		bad_srat();
 		return;
 	}
-	if (ma->flags.enabled == 0)
+	if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
 		return;
- 	if (ma->flags.hot_pluggable && !save_add_info())
+
+	if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info())
 		return;
-	start = ma->base_addr_lo | ((u64)ma->base_addr_hi << 32);
-	end = start + (ma->length_lo | ((u64)ma->length_hi << 32));
+	start = ma->base_address;
+	end = start + ma->length;
 	pxm = ma->proximity_domain;
 	node = setup_node(pxm);
 	if (node < 0) {
@@ -337,7 +338,8 @@
 	push_node_boundaries(node, nd->start >> PAGE_SHIFT,
 						nd->end >> PAGE_SHIFT);
 
- 	if (ma->flags.hot_pluggable && (reserve_hotadd(node, start, end) < 0)) {
+	if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) &&
+	    (reserve_hotadd(node, start, end) < 0)) {
 		/* Ignore hotadd region. Undo damage */
 		printk(KERN_NOTICE "SRAT: Hotplug region ignored\n");
 		*nd = oldnode;
@@ -394,7 +396,7 @@
 
 	/* First clean up the node list */
 	for (i = 0; i < MAX_NUMNODES; i++) {
- 		cutoff_node(i, start, end);
+		cutoff_node(i, start, end);
 		if ((nodes[i].end - nodes[i].start) < NODE_MIN_SIZE) {
 			unparse_node(i);
 			node_set_offline(i);
@@ -426,7 +428,7 @@
 		if (!node_online(i))
 			setup_node_bootmem(i, nodes[i].start, nodes[i].end);
 
-	for (i = 0; i < NR_CPUS; i++) { 
+	for (i = 0; i < NR_CPUS; i++) {
 		if (cpu_to_node[i] == NUMA_NO_NODE)
 			continue;
 		if (!node_isset(cpu_to_node[i], nodes_parsed))
@@ -461,7 +463,7 @@
 
 	if (!acpi_slit)
 		return a == b ? 10 : 20;
-	index = acpi_slit->localities * node_to_pxm(a);
+	index = acpi_slit->locality_count * node_to_pxm(a);
 	return acpi_slit->entry[index + node_to_pxm(b)];
 }
 
diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
index f8b6b28..faabb6e 100644
--- a/arch/x86_64/pci/mmconfig.c
+++ b/arch/x86_64/pci/mmconfig.c
@@ -1,6 +1,6 @@
 /*
  * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
- * 
+ *
  * This is an 64bit optimized version that always keeps the full mmconfig
  * space mapped. This allows lockless config space operation.
  */
@@ -25,7 +25,7 @@
 
 /* Static virtual mapping of the MMCONFIG aperture */
 struct mmcfg_virt {
-	struct acpi_table_mcfg_config *cfg;
+	struct acpi_mcfg_allocation *cfg;
 	char __iomem *virt;
 };
 static struct mmcfg_virt *pci_mmcfg_virt;
@@ -33,14 +33,14 @@
 static char __iomem *get_virt(unsigned int seg, unsigned bus)
 {
 	int cfg_num = -1;
-	struct acpi_table_mcfg_config *cfg;
+	struct acpi_mcfg_allocation *cfg;
 
 	while (1) {
 		++cfg_num;
 		if (cfg_num >= pci_mmcfg_config_num)
 			break;
 		cfg = pci_mmcfg_virt[cfg_num].cfg;
-		if (cfg->pci_segment_group_number != seg)
+		if (cfg->pci_segment != seg)
 			continue;
 		if ((cfg->start_bus_number <= bus) &&
 		    (cfg->end_bus_number >= bus))
@@ -52,7 +52,7 @@
  	   this applies to all busses. */
 	cfg = &pci_mmcfg_config[0];
 	if (pci_mmcfg_config_num == 1 &&
-		cfg->pci_segment_group_number == 0 &&
+		cfg->pci_segment == 0 &&
 		(cfg->start_bus_number | cfg->end_bus_number) == 0)
 		return pci_mmcfg_virt[0].virt;
 
@@ -170,19 +170,19 @@
 	if ((pci_probe & PCI_PROBE_MMCONF) == 0)
 		return;
 
-	acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+	acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
 	if ((pci_mmcfg_config_num == 0) ||
 	    (pci_mmcfg_config == NULL) ||
-	    (pci_mmcfg_config[0].base_address == 0))
+	    (pci_mmcfg_config[0].address == 0))
 		return;
 
 	/* Only do this check when type 1 works. If it doesn't work
            assume we run on a Mac and always use MCFG */
-	if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].base_address,
-			pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
+	if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].address,
+			pci_mmcfg_config[0].address + MMCONFIG_APER_MIN,
 			E820_RESERVED)) {
-		printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n",
-				pci_mmcfg_config[0].base_address);
+		printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %lx is not E820-reserved\n",
+				(unsigned long)pci_mmcfg_config[0].address);
 		printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
 		return;
 	}
@@ -194,15 +194,16 @@
 	}
 	for (i = 0; i < pci_mmcfg_config_num; ++i) {
 		pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
-		pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address,
+		pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].address,
 							 MMCONFIG_APER_MAX);
 		if (!pci_mmcfg_virt[i].virt) {
 			printk(KERN_ERR "PCI: Cannot map mmconfig aperture for "
 					"segment %d\n",
-			       pci_mmcfg_config[i].pci_segment_group_number);
+				pci_mmcfg_config[i].pci_segment);
 			return;
 		}
-		printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address);
+		printk(KERN_INFO "PCI: Using MMCONFIG at %lx\n",
+			(unsigned long)pci_mmcfg_config[i].address);
 	}
 
 	unreachable_devices();
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index fb67897..38c293b 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -1264,7 +1264,7 @@
 	bio->bi_hw_segments = nr_hw_segs;
 	bio->bi_flags |= (1 << BIO_SEG_VALID);
 }
-
+EXPORT_SYMBOL(blk_recount_segments);
 
 static int blk_phys_contig_segment(request_queue_t *q, struct bio *bio,
 				   struct bio *nxt)
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 92ba249..086fcec 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -74,14 +74,6 @@
 	help
 	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
 
-config CRYPTO_SHA1_S390
-	tristate "SHA1 digest algorithm (s390)"
-	depends on S390
-	select CRYPTO_ALGAPI
-	help
-	  This is the s390 hardware accelerated implementation of the
-	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
-
 config CRYPTO_SHA256
 	tristate "SHA256 digest algorithm"
 	select CRYPTO_ALGAPI
@@ -91,17 +83,6 @@
 	  This version of SHA implements a 256 bit hash with 128 bits of
 	  security against collision attacks.
 
-config CRYPTO_SHA256_S390
-	tristate "SHA256 digest algorithm (s390)"
-	depends on S390
-	select CRYPTO_ALGAPI
-	help
-	  This is the s390 hardware accelerated implementation of the
-	  SHA256 secure hash standard (DFIPS 180-2).
-
-	  This version of SHA implements a 256 bit hash with 128 bits of
-	  security against collision attacks.
-
 config CRYPTO_SHA512
 	tristate "SHA384 and SHA512 digest algorithms"
 	select CRYPTO_ALGAPI
@@ -168,6 +149,15 @@
 	  CBC: Cipher Block Chaining mode
 	  This block cipher algorithm is required for IPSec.
 
+config CRYPTO_PCBC
+	tristate "PCBC support"
+	select CRYPTO_BLKCIPHER
+	select CRYPTO_MANAGER
+	default m
+	help
+	  PCBC: Propagating Cipher Block Chaining mode
+	  This block cipher algorithm is required for RxRPC.
+
 config CRYPTO_LRW
 	tristate "LRW support (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
@@ -187,13 +177,12 @@
 	help
 	  DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
 
-config CRYPTO_DES_S390
-	tristate "DES and Triple DES cipher algorithms (s390)"
-	depends on S390
+config CRYPTO_FCRYPT
+	tristate "FCrypt cipher algorithm"
 	select CRYPTO_ALGAPI
 	select CRYPTO_BLKCIPHER
 	help
-	  DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+	  FCrypt algorithm used by RxRPC.
 
 config CRYPTO_BLOWFISH
 	tristate "Blowfish cipher algorithm"
@@ -336,28 +325,6 @@
 
 	  See <http://csrc.nist.gov/encryption/aes/> for more information.
 
-config CRYPTO_AES_S390
-	tristate "AES cipher algorithms (s390)"
-	depends on S390
-	select CRYPTO_ALGAPI
-	select CRYPTO_BLKCIPHER
-	help
-	  This is the s390 hardware accelerated implementation of the
-	  AES cipher algorithms (FIPS-197). AES uses the Rijndael
-	  algorithm.
-
-	  Rijndael appears to be consistently a very good performer in
-	  both hardware and software across a wide range of computing
-	  environments regardless of its use in feedback or non-feedback
-	  modes. Its key setup time is excellent, and its key agility is
-	  good. Rijndael's very low memory requirements make it very well
-	  suited for restricted-space environments, in which it also
-	  demonstrates excellent performance. Rijndael's operations are
-	  among the easiest to defend against power and timing attacks.
-
-	  On s390 the System z9-109 currently only supports the key size
-	  of 128 bit.
-
 config CRYPTO_CAST5
 	tristate "CAST5 (CAST-128) cipher algorithm"
 	select CRYPTO_ALGAPI
@@ -458,6 +425,21 @@
 	  See Castagnoli93.  This implementation uses lib/libcrc32c.
           Module will be crc32c.
 
+config CRYPTO_CAMELLIA
+	tristate "Camellia cipher algorithms"
+	depends on CRYPTO
+	select CRYPTO_ALGAPI
+	help
+	  Camellia cipher algorithms module.
+
+	  Camellia is a symmetric key block cipher developed jointly
+	  at NTT and Mitsubishi Electric Corporation.
+
+	  The Camellia specifies three key sizes: 128, 192 and 256 bits.
+
+	  See also:
+	  <https://info.isl.ntt.co.jp/crypt/eng/camellia/index_s.html>
+
 config CRYPTO_TEST
 	tristate "Testing module"
 	depends on m
diff --git a/crypto/Makefile b/crypto/Makefile
index 60e3d24..12f93f5 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -27,13 +27,16 @@
 obj-$(CONFIG_CRYPTO_GF128MUL) += gf128mul.o
 obj-$(CONFIG_CRYPTO_ECB) += ecb.o
 obj-$(CONFIG_CRYPTO_CBC) += cbc.o
+obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o
 obj-$(CONFIG_CRYPTO_LRW) += lrw.o
 obj-$(CONFIG_CRYPTO_DES) += des.o
+obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o
 obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o
 obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o
 obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o
 obj-$(CONFIG_CRYPTO_SERPENT) += serpent.o
 obj-$(CONFIG_CRYPTO_AES) += aes.o
+obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia.o
 obj-$(CONFIG_CRYPTO_CAST5) += cast5.o
 obj-$(CONFIG_CRYPTO_CAST6) += cast6.o
 obj-$(CONFIG_CRYPTO_ARC4) += arc4.o
diff --git a/crypto/algapi.c b/crypto/algapi.c
index c915300..f7d2185 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -377,7 +377,8 @@
 }
 EXPORT_SYMBOL_GPL(crypto_drop_spawn);
 
-struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn)
+struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
+				    u32 mask)
 {
 	struct crypto_alg *alg;
 	struct crypto_alg *alg2;
@@ -396,10 +397,18 @@
 		return ERR_PTR(-EAGAIN);
 	}
 
-	tfm = __crypto_alloc_tfm(alg, 0);
-	if (IS_ERR(tfm))
-		crypto_mod_put(alg);
+	tfm = ERR_PTR(-EINVAL);
+	if (unlikely((alg->cra_flags ^ type) & mask))
+		goto out_put_alg;
 
+	tfm = __crypto_alloc_tfm(alg, type, mask);
+	if (IS_ERR(tfm))
+		goto out_put_alg;
+
+	return tfm;
+
+out_put_alg:
+	crypto_mod_put(alg);
 	return tfm;
 }
 EXPORT_SYMBOL_GPL(crypto_spawn_tfm);
diff --git a/crypto/api.c b/crypto/api.c
index 8c44687..55af8bb 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -212,31 +212,12 @@
 }
 EXPORT_SYMBOL_GPL(crypto_alg_mod_lookup);
 
-static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags)
+static int crypto_init_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
 {
-	tfm->crt_flags = flags & CRYPTO_TFM_REQ_MASK;
-	flags &= ~CRYPTO_TFM_REQ_MASK;
-	
-	switch (crypto_tfm_alg_type(tfm)) {
-	case CRYPTO_ALG_TYPE_CIPHER:
-		return crypto_init_cipher_flags(tfm, flags);
-		
-	case CRYPTO_ALG_TYPE_DIGEST:
-		return crypto_init_digest_flags(tfm, flags);
-		
-	case CRYPTO_ALG_TYPE_COMPRESS:
-		return crypto_init_compress_flags(tfm, flags);
-	}
-	
-	return 0;
-}
+	const struct crypto_type *type_obj = tfm->__crt_alg->cra_type;
 
-static int crypto_init_ops(struct crypto_tfm *tfm)
-{
-	const struct crypto_type *type = tfm->__crt_alg->cra_type;
-
-	if (type)
-		return type->init(tfm);
+	if (type_obj)
+		return type_obj->init(tfm, type, mask);
 
 	switch (crypto_tfm_alg_type(tfm)) {
 	case CRYPTO_ALG_TYPE_CIPHER:
@@ -285,29 +266,29 @@
 	}
 }
 
-static unsigned int crypto_ctxsize(struct crypto_alg *alg, int flags)
+static unsigned int crypto_ctxsize(struct crypto_alg *alg, u32 type, u32 mask)
 {
-	const struct crypto_type *type = alg->cra_type;
+	const struct crypto_type *type_obj = alg->cra_type;
 	unsigned int len;
 
 	len = alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1);
-	if (type)
-		return len + type->ctxsize(alg);
+	if (type_obj)
+		return len + type_obj->ctxsize(alg, type, mask);
 
 	switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
 	default:
 		BUG();
 
 	case CRYPTO_ALG_TYPE_CIPHER:
-		len += crypto_cipher_ctxsize(alg, flags);
+		len += crypto_cipher_ctxsize(alg);
 		break;
 		
 	case CRYPTO_ALG_TYPE_DIGEST:
-		len += crypto_digest_ctxsize(alg, flags);
+		len += crypto_digest_ctxsize(alg);
 		break;
 		
 	case CRYPTO_ALG_TYPE_COMPRESS:
-		len += crypto_compress_ctxsize(alg, flags);
+		len += crypto_compress_ctxsize(alg);
 		break;
 	}
 
@@ -322,24 +303,21 @@
 }
 EXPORT_SYMBOL_GPL(crypto_shoot_alg);
 
-struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags)
+struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
+				      u32 mask)
 {
 	struct crypto_tfm *tfm = NULL;
 	unsigned int tfm_size;
 	int err = -ENOMEM;
 
-	tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags);
+	tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, type, mask);
 	tfm = kzalloc(tfm_size, GFP_KERNEL);
 	if (tfm == NULL)
 		goto out_err;
 
 	tfm->__crt_alg = alg;
 
-	err = crypto_init_flags(tfm, flags);
-	if (err)
-		goto out_free_tfm;
-		
-	err = crypto_init_ops(tfm);
+	err = crypto_init_ops(tfm, type, mask);
 	if (err)
 		goto out_free_tfm;
 
@@ -362,31 +340,6 @@
 }
 EXPORT_SYMBOL_GPL(__crypto_alloc_tfm);
 
-struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
-{
-	struct crypto_tfm *tfm = NULL;
-	int err;
-
-	do {
-		struct crypto_alg *alg;
-
-		alg = crypto_alg_mod_lookup(name, 0, CRYPTO_ALG_ASYNC);
-		err = PTR_ERR(alg);
-		if (IS_ERR(alg))
-			continue;
-
-		tfm = __crypto_alloc_tfm(alg, flags);
-		err = 0;
-		if (IS_ERR(tfm)) {
-			crypto_mod_put(alg);
-			err = PTR_ERR(tfm);
-			tfm = NULL;
-		}
-	} while (err == -EAGAIN && !signal_pending(current));
-
-	return tfm;
-}
-
 /*
  *	crypto_alloc_base - Locate algorithm and allocate transform
  *	@alg_name: Name of algorithm
@@ -420,7 +373,7 @@
 			goto err;
 		}
 
-		tfm = __crypto_alloc_tfm(alg, 0);
+		tfm = __crypto_alloc_tfm(alg, type, mask);
 		if (!IS_ERR(tfm))
 			return tfm;
 
@@ -466,7 +419,6 @@
 	kfree(tfm);
 }
 
-EXPORT_SYMBOL_GPL(crypto_alloc_tfm);
 EXPORT_SYMBOL_GPL(crypto_free_tfm);
 
 int crypto_has_alg(const char *name, u32 type, u32 mask)
diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c
index 6e93004f..b5befe8 100644
--- a/crypto/blkcipher.c
+++ b/crypto/blkcipher.c
@@ -16,6 +16,7 @@
 
 #include <linux/crypto.h>
 #include <linux/errno.h>
+#include <linux/hardirq.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/scatterlist.h>
@@ -313,6 +314,9 @@
 	struct crypto_blkcipher *tfm = desc->tfm;
 	unsigned int alignmask = crypto_blkcipher_alignmask(tfm);
 
+	if (WARN_ON_ONCE(in_irq()))
+		return -EDEADLK;
+
 	walk->nbytes = walk->total;
 	if (unlikely(!walk->total))
 		return 0;
@@ -345,7 +349,8 @@
 	return cipher->setkey(tfm, key, keylen);
 }
 
-static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg)
+static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg, u32 type,
+					     u32 mask)
 {
 	struct blkcipher_alg *cipher = &alg->cra_blkcipher;
 	unsigned int len = alg->cra_ctxsize;
@@ -358,7 +363,7 @@
 	return len;
 }
 
-static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm)
+static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
 {
 	struct blkcipher_tfm *crt = &tfm->crt_blkcipher;
 	struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher;
diff --git a/crypto/camellia.c b/crypto/camellia.c
new file mode 100644
index 0000000..6877ecf
--- /dev/null
+++ b/crypto/camellia.c
@@ -0,0 +1,1801 @@
+/*
+ * Copyright (C) 2006
+ * NTT (Nippon Telegraph and Telephone 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; 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.
+ */
+
+/*
+ * Algorithm Specification
+ *  http://info.isl.ntt.co.jp/crypt/eng/camellia/specifications.html
+ */
+
+/*
+ *
+ * NOTE --- NOTE --- NOTE --- NOTE
+ * This implementation assumes that all memory addresses passed
+ * as parameters are four-byte aligned.
+ *
+ */
+
+#include <linux/crypto.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+
+#define CAMELLIA_MIN_KEY_SIZE        16
+#define CAMELLIA_MAX_KEY_SIZE        32
+#define CAMELLIA_BLOCK_SIZE 16
+#define CAMELLIA_TABLE_BYTE_LEN 272
+#define CAMELLIA_TABLE_WORD_LEN (CAMELLIA_TABLE_BYTE_LEN / 4)
+
+typedef u32 KEY_TABLE_TYPE[CAMELLIA_TABLE_WORD_LEN];
+
+
+/* key constants */
+
+#define CAMELLIA_SIGMA1L (0xA09E667FL)
+#define CAMELLIA_SIGMA1R (0x3BCC908BL)
+#define CAMELLIA_SIGMA2L (0xB67AE858L)
+#define CAMELLIA_SIGMA2R (0x4CAA73B2L)
+#define CAMELLIA_SIGMA3L (0xC6EF372FL)
+#define CAMELLIA_SIGMA3R (0xE94F82BEL)
+#define CAMELLIA_SIGMA4L (0x54FF53A5L)
+#define CAMELLIA_SIGMA4R (0xF1D36F1CL)
+#define CAMELLIA_SIGMA5L (0x10E527FAL)
+#define CAMELLIA_SIGMA5R (0xDE682D1DL)
+#define CAMELLIA_SIGMA6L (0xB05688C2L)
+#define CAMELLIA_SIGMA6R (0xB3E6C1FDL)
+
+struct camellia_ctx {
+	int key_length;
+	KEY_TABLE_TYPE key_table;
+};
+
+
+/*
+ *  macros
+ */
+
+
+# define GETU32(pt) (((u32)(pt)[0] << 24)	\
+		     ^ ((u32)(pt)[1] << 16)	\
+		     ^ ((u32)(pt)[2] <<  8)	\
+		     ^ ((u32)(pt)[3]))
+
+#define COPY4WORD(dst, src)			\
+    do {					\
+	(dst)[0]=(src)[0];			\
+	(dst)[1]=(src)[1];			\
+	(dst)[2]=(src)[2];			\
+	(dst)[3]=(src)[3];			\
+    }while(0)
+
+#define SWAP4WORD(word)				\
+    do {					\
+	CAMELLIA_SWAP4((word)[0]);		\
+	CAMELLIA_SWAP4((word)[1]);		\
+	CAMELLIA_SWAP4((word)[2]);		\
+	CAMELLIA_SWAP4((word)[3]);		\
+    }while(0)
+
+#define XOR4WORD(a, b)/* a = a ^ b */		\
+    do {					\
+	(a)[0]^=(b)[0];				\
+	(a)[1]^=(b)[1];				\
+	(a)[2]^=(b)[2];				\
+	(a)[3]^=(b)[3];				\
+    }while(0)
+
+#define XOR4WORD2(a, b, c)/* a = b ^ c */	\
+    do {					\
+	(a)[0]=(b)[0]^(c)[0];			\
+	(a)[1]=(b)[1]^(c)[1];			\
+	(a)[2]=(b)[2]^(c)[2];			\
+	(a)[3]=(b)[3]^(c)[3];			\
+    }while(0)
+
+#define CAMELLIA_SUBKEY_L(INDEX) (subkey[(INDEX)*2])
+#define CAMELLIA_SUBKEY_R(INDEX) (subkey[(INDEX)*2 + 1])
+
+/* rotation right shift 1byte */
+#define CAMELLIA_RR8(x) (((x) >> 8) + ((x) << 24))
+/* rotation left shift 1bit */
+#define CAMELLIA_RL1(x) (((x) << 1) + ((x) >> 31))
+/* rotation left shift 1byte */
+#define CAMELLIA_RL8(x) (((x) << 8) + ((x) >> 24))
+
+#define CAMELLIA_ROLDQ(ll, lr, rl, rr, w0, w1, bits)	\
+    do {						\
+	w0 = ll;					\
+	ll = (ll << bits) + (lr >> (32 - bits));	\
+	lr = (lr << bits) + (rl >> (32 - bits));	\
+	rl = (rl << bits) + (rr >> (32 - bits));	\
+	rr = (rr << bits) + (w0 >> (32 - bits));	\
+    } while(0)
+
+#define CAMELLIA_ROLDQo32(ll, lr, rl, rr, w0, w1, bits)	\
+    do {						\
+	w0 = ll;					\
+	w1 = lr;					\
+	ll = (lr << (bits - 32)) + (rl >> (64 - bits));	\
+	lr = (rl << (bits - 32)) + (rr >> (64 - bits));	\
+	rl = (rr << (bits - 32)) + (w0 >> (64 - bits));	\
+	rr = (w0 << (bits - 32)) + (w1 >> (64 - bits));	\
+    } while(0)
+
+#define CAMELLIA_SP1110(INDEX) (camellia_sp1110[(INDEX)])
+#define CAMELLIA_SP0222(INDEX) (camellia_sp0222[(INDEX)])
+#define CAMELLIA_SP3033(INDEX) (camellia_sp3033[(INDEX)])
+#define CAMELLIA_SP4404(INDEX) (camellia_sp4404[(INDEX)])
+
+#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1)	\
+    do {							\
+	il = xl ^ kl;						\
+	ir = xr ^ kr;						\
+	t0 = il >> 16;						\
+	t1 = ir >> 16;						\
+	yl = CAMELLIA_SP1110(ir & 0xff)				\
+	    ^ CAMELLIA_SP0222((t1 >> 8) & 0xff)			\
+	    ^ CAMELLIA_SP3033(t1 & 0xff)			\
+	    ^ CAMELLIA_SP4404((ir >> 8) & 0xff);		\
+	yr = CAMELLIA_SP1110((t0 >> 8) & 0xff)			\
+	    ^ CAMELLIA_SP0222(t0 & 0xff)			\
+	    ^ CAMELLIA_SP3033((il >> 8) & 0xff)			\
+	    ^ CAMELLIA_SP4404(il & 0xff);			\
+	yl ^= yr;						\
+	yr = CAMELLIA_RR8(yr);					\
+	yr ^= yl;						\
+    } while(0)
+
+
+/*
+ * for speed up
+ *
+ */
+#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) \
+    do {								\
+	t0 = kll;							\
+	t2 = krr;							\
+	t0 &= ll;							\
+	t2 |= rr;							\
+	rl ^= t2;							\
+	lr ^= CAMELLIA_RL1(t0);						\
+	t3 = krl;							\
+	t1 = klr;							\
+	t3 &= rl;							\
+	t1 |= lr;							\
+	ll ^= t1;							\
+	rr ^= CAMELLIA_RL1(t3);						\
+    } while(0)
+
+#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir, t0, t1)	\
+    do {								\
+	ir =  CAMELLIA_SP1110(xr & 0xff);				\
+	il =  CAMELLIA_SP1110((xl>>24) & 0xff);				\
+	ir ^= CAMELLIA_SP0222((xr>>24) & 0xff);				\
+	il ^= CAMELLIA_SP0222((xl>>16) & 0xff);				\
+	ir ^= CAMELLIA_SP3033((xr>>16) & 0xff);				\
+	il ^= CAMELLIA_SP3033((xl>>8) & 0xff);				\
+	ir ^= CAMELLIA_SP4404((xr>>8) & 0xff);				\
+	il ^= CAMELLIA_SP4404(xl & 0xff);				\
+	il ^= kl;							\
+	ir ^= il ^ kr;							\
+	yl ^= ir;							\
+	yr ^= CAMELLIA_RR8(il) ^ ir;					\
+    } while(0)
+
+/**
+ * Stuff related to the Camellia key schedule
+ */
+#define SUBL(x) subL[(x)]
+#define SUBR(x) subR[(x)]
+
+
+static const u32 camellia_sp1110[256] = {
+	0x70707000,0x82828200,0x2c2c2c00,0xececec00,
+	0xb3b3b300,0x27272700,0xc0c0c000,0xe5e5e500,
+	0xe4e4e400,0x85858500,0x57575700,0x35353500,
+	0xeaeaea00,0x0c0c0c00,0xaeaeae00,0x41414100,
+	0x23232300,0xefefef00,0x6b6b6b00,0x93939300,
+	0x45454500,0x19191900,0xa5a5a500,0x21212100,
+	0xededed00,0x0e0e0e00,0x4f4f4f00,0x4e4e4e00,
+	0x1d1d1d00,0x65656500,0x92929200,0xbdbdbd00,
+	0x86868600,0xb8b8b800,0xafafaf00,0x8f8f8f00,
+	0x7c7c7c00,0xebebeb00,0x1f1f1f00,0xcecece00,
+	0x3e3e3e00,0x30303000,0xdcdcdc00,0x5f5f5f00,
+	0x5e5e5e00,0xc5c5c500,0x0b0b0b00,0x1a1a1a00,
+	0xa6a6a600,0xe1e1e100,0x39393900,0xcacaca00,
+	0xd5d5d500,0x47474700,0x5d5d5d00,0x3d3d3d00,
+	0xd9d9d900,0x01010100,0x5a5a5a00,0xd6d6d600,
+	0x51515100,0x56565600,0x6c6c6c00,0x4d4d4d00,
+	0x8b8b8b00,0x0d0d0d00,0x9a9a9a00,0x66666600,
+	0xfbfbfb00,0xcccccc00,0xb0b0b000,0x2d2d2d00,
+	0x74747400,0x12121200,0x2b2b2b00,0x20202000,
+	0xf0f0f000,0xb1b1b100,0x84848400,0x99999900,
+	0xdfdfdf00,0x4c4c4c00,0xcbcbcb00,0xc2c2c200,
+	0x34343400,0x7e7e7e00,0x76767600,0x05050500,
+	0x6d6d6d00,0xb7b7b700,0xa9a9a900,0x31313100,
+	0xd1d1d100,0x17171700,0x04040400,0xd7d7d700,
+	0x14141400,0x58585800,0x3a3a3a00,0x61616100,
+	0xdedede00,0x1b1b1b00,0x11111100,0x1c1c1c00,
+	0x32323200,0x0f0f0f00,0x9c9c9c00,0x16161600,
+	0x53535300,0x18181800,0xf2f2f200,0x22222200,
+	0xfefefe00,0x44444400,0xcfcfcf00,0xb2b2b200,
+	0xc3c3c300,0xb5b5b500,0x7a7a7a00,0x91919100,
+	0x24242400,0x08080800,0xe8e8e800,0xa8a8a800,
+	0x60606000,0xfcfcfc00,0x69696900,0x50505000,
+	0xaaaaaa00,0xd0d0d000,0xa0a0a000,0x7d7d7d00,
+	0xa1a1a100,0x89898900,0x62626200,0x97979700,
+	0x54545400,0x5b5b5b00,0x1e1e1e00,0x95959500,
+	0xe0e0e000,0xffffff00,0x64646400,0xd2d2d200,
+	0x10101000,0xc4c4c400,0x00000000,0x48484800,
+	0xa3a3a300,0xf7f7f700,0x75757500,0xdbdbdb00,
+	0x8a8a8a00,0x03030300,0xe6e6e600,0xdadada00,
+	0x09090900,0x3f3f3f00,0xdddddd00,0x94949400,
+	0x87878700,0x5c5c5c00,0x83838300,0x02020200,
+	0xcdcdcd00,0x4a4a4a00,0x90909000,0x33333300,
+	0x73737300,0x67676700,0xf6f6f600,0xf3f3f300,
+	0x9d9d9d00,0x7f7f7f00,0xbfbfbf00,0xe2e2e200,
+	0x52525200,0x9b9b9b00,0xd8d8d800,0x26262600,
+	0xc8c8c800,0x37373700,0xc6c6c600,0x3b3b3b00,
+	0x81818100,0x96969600,0x6f6f6f00,0x4b4b4b00,
+	0x13131300,0xbebebe00,0x63636300,0x2e2e2e00,
+	0xe9e9e900,0x79797900,0xa7a7a700,0x8c8c8c00,
+	0x9f9f9f00,0x6e6e6e00,0xbcbcbc00,0x8e8e8e00,
+	0x29292900,0xf5f5f500,0xf9f9f900,0xb6b6b600,
+	0x2f2f2f00,0xfdfdfd00,0xb4b4b400,0x59595900,
+	0x78787800,0x98989800,0x06060600,0x6a6a6a00,
+	0xe7e7e700,0x46464600,0x71717100,0xbababa00,
+	0xd4d4d400,0x25252500,0xababab00,0x42424200,
+	0x88888800,0xa2a2a200,0x8d8d8d00,0xfafafa00,
+	0x72727200,0x07070700,0xb9b9b900,0x55555500,
+	0xf8f8f800,0xeeeeee00,0xacacac00,0x0a0a0a00,
+	0x36363600,0x49494900,0x2a2a2a00,0x68686800,
+	0x3c3c3c00,0x38383800,0xf1f1f100,0xa4a4a400,
+	0x40404000,0x28282800,0xd3d3d300,0x7b7b7b00,
+	0xbbbbbb00,0xc9c9c900,0x43434300,0xc1c1c100,
+	0x15151500,0xe3e3e300,0xadadad00,0xf4f4f400,
+	0x77777700,0xc7c7c700,0x80808000,0x9e9e9e00,
+};
+
+static const u32 camellia_sp0222[256] = {
+	0x00e0e0e0,0x00050505,0x00585858,0x00d9d9d9,
+	0x00676767,0x004e4e4e,0x00818181,0x00cbcbcb,
+	0x00c9c9c9,0x000b0b0b,0x00aeaeae,0x006a6a6a,
+	0x00d5d5d5,0x00181818,0x005d5d5d,0x00828282,
+	0x00464646,0x00dfdfdf,0x00d6d6d6,0x00272727,
+	0x008a8a8a,0x00323232,0x004b4b4b,0x00424242,
+	0x00dbdbdb,0x001c1c1c,0x009e9e9e,0x009c9c9c,
+	0x003a3a3a,0x00cacaca,0x00252525,0x007b7b7b,
+	0x000d0d0d,0x00717171,0x005f5f5f,0x001f1f1f,
+	0x00f8f8f8,0x00d7d7d7,0x003e3e3e,0x009d9d9d,
+	0x007c7c7c,0x00606060,0x00b9b9b9,0x00bebebe,
+	0x00bcbcbc,0x008b8b8b,0x00161616,0x00343434,
+	0x004d4d4d,0x00c3c3c3,0x00727272,0x00959595,
+	0x00ababab,0x008e8e8e,0x00bababa,0x007a7a7a,
+	0x00b3b3b3,0x00020202,0x00b4b4b4,0x00adadad,
+	0x00a2a2a2,0x00acacac,0x00d8d8d8,0x009a9a9a,
+	0x00171717,0x001a1a1a,0x00353535,0x00cccccc,
+	0x00f7f7f7,0x00999999,0x00616161,0x005a5a5a,
+	0x00e8e8e8,0x00242424,0x00565656,0x00404040,
+	0x00e1e1e1,0x00636363,0x00090909,0x00333333,
+	0x00bfbfbf,0x00989898,0x00979797,0x00858585,
+	0x00686868,0x00fcfcfc,0x00ececec,0x000a0a0a,
+	0x00dadada,0x006f6f6f,0x00535353,0x00626262,
+	0x00a3a3a3,0x002e2e2e,0x00080808,0x00afafaf,
+	0x00282828,0x00b0b0b0,0x00747474,0x00c2c2c2,
+	0x00bdbdbd,0x00363636,0x00222222,0x00383838,
+	0x00646464,0x001e1e1e,0x00393939,0x002c2c2c,
+	0x00a6a6a6,0x00303030,0x00e5e5e5,0x00444444,
+	0x00fdfdfd,0x00888888,0x009f9f9f,0x00656565,
+	0x00878787,0x006b6b6b,0x00f4f4f4,0x00232323,
+	0x00484848,0x00101010,0x00d1d1d1,0x00515151,
+	0x00c0c0c0,0x00f9f9f9,0x00d2d2d2,0x00a0a0a0,
+	0x00555555,0x00a1a1a1,0x00414141,0x00fafafa,
+	0x00434343,0x00131313,0x00c4c4c4,0x002f2f2f,
+	0x00a8a8a8,0x00b6b6b6,0x003c3c3c,0x002b2b2b,
+	0x00c1c1c1,0x00ffffff,0x00c8c8c8,0x00a5a5a5,
+	0x00202020,0x00898989,0x00000000,0x00909090,
+	0x00474747,0x00efefef,0x00eaeaea,0x00b7b7b7,
+	0x00151515,0x00060606,0x00cdcdcd,0x00b5b5b5,
+	0x00121212,0x007e7e7e,0x00bbbbbb,0x00292929,
+	0x000f0f0f,0x00b8b8b8,0x00070707,0x00040404,
+	0x009b9b9b,0x00949494,0x00212121,0x00666666,
+	0x00e6e6e6,0x00cecece,0x00ededed,0x00e7e7e7,
+	0x003b3b3b,0x00fefefe,0x007f7f7f,0x00c5c5c5,
+	0x00a4a4a4,0x00373737,0x00b1b1b1,0x004c4c4c,
+	0x00919191,0x006e6e6e,0x008d8d8d,0x00767676,
+	0x00030303,0x002d2d2d,0x00dedede,0x00969696,
+	0x00262626,0x007d7d7d,0x00c6c6c6,0x005c5c5c,
+	0x00d3d3d3,0x00f2f2f2,0x004f4f4f,0x00191919,
+	0x003f3f3f,0x00dcdcdc,0x00797979,0x001d1d1d,
+	0x00525252,0x00ebebeb,0x00f3f3f3,0x006d6d6d,
+	0x005e5e5e,0x00fbfbfb,0x00696969,0x00b2b2b2,
+	0x00f0f0f0,0x00313131,0x000c0c0c,0x00d4d4d4,
+	0x00cfcfcf,0x008c8c8c,0x00e2e2e2,0x00757575,
+	0x00a9a9a9,0x004a4a4a,0x00575757,0x00848484,
+	0x00111111,0x00454545,0x001b1b1b,0x00f5f5f5,
+	0x00e4e4e4,0x000e0e0e,0x00737373,0x00aaaaaa,
+	0x00f1f1f1,0x00dddddd,0x00595959,0x00141414,
+	0x006c6c6c,0x00929292,0x00545454,0x00d0d0d0,
+	0x00787878,0x00707070,0x00e3e3e3,0x00494949,
+	0x00808080,0x00505050,0x00a7a7a7,0x00f6f6f6,
+	0x00777777,0x00939393,0x00868686,0x00838383,
+	0x002a2a2a,0x00c7c7c7,0x005b5b5b,0x00e9e9e9,
+	0x00eeeeee,0x008f8f8f,0x00010101,0x003d3d3d,
+};
+
+static const u32 camellia_sp3033[256] = {
+	0x38003838,0x41004141,0x16001616,0x76007676,
+	0xd900d9d9,0x93009393,0x60006060,0xf200f2f2,
+	0x72007272,0xc200c2c2,0xab00abab,0x9a009a9a,
+	0x75007575,0x06000606,0x57005757,0xa000a0a0,
+	0x91009191,0xf700f7f7,0xb500b5b5,0xc900c9c9,
+	0xa200a2a2,0x8c008c8c,0xd200d2d2,0x90009090,
+	0xf600f6f6,0x07000707,0xa700a7a7,0x27002727,
+	0x8e008e8e,0xb200b2b2,0x49004949,0xde00dede,
+	0x43004343,0x5c005c5c,0xd700d7d7,0xc700c7c7,
+	0x3e003e3e,0xf500f5f5,0x8f008f8f,0x67006767,
+	0x1f001f1f,0x18001818,0x6e006e6e,0xaf00afaf,
+	0x2f002f2f,0xe200e2e2,0x85008585,0x0d000d0d,
+	0x53005353,0xf000f0f0,0x9c009c9c,0x65006565,
+	0xea00eaea,0xa300a3a3,0xae00aeae,0x9e009e9e,
+	0xec00ecec,0x80008080,0x2d002d2d,0x6b006b6b,
+	0xa800a8a8,0x2b002b2b,0x36003636,0xa600a6a6,
+	0xc500c5c5,0x86008686,0x4d004d4d,0x33003333,
+	0xfd00fdfd,0x66006666,0x58005858,0x96009696,
+	0x3a003a3a,0x09000909,0x95009595,0x10001010,
+	0x78007878,0xd800d8d8,0x42004242,0xcc00cccc,
+	0xef00efef,0x26002626,0xe500e5e5,0x61006161,
+	0x1a001a1a,0x3f003f3f,0x3b003b3b,0x82008282,
+	0xb600b6b6,0xdb00dbdb,0xd400d4d4,0x98009898,
+	0xe800e8e8,0x8b008b8b,0x02000202,0xeb00ebeb,
+	0x0a000a0a,0x2c002c2c,0x1d001d1d,0xb000b0b0,
+	0x6f006f6f,0x8d008d8d,0x88008888,0x0e000e0e,
+	0x19001919,0x87008787,0x4e004e4e,0x0b000b0b,
+	0xa900a9a9,0x0c000c0c,0x79007979,0x11001111,
+	0x7f007f7f,0x22002222,0xe700e7e7,0x59005959,
+	0xe100e1e1,0xda00dada,0x3d003d3d,0xc800c8c8,
+	0x12001212,0x04000404,0x74007474,0x54005454,
+	0x30003030,0x7e007e7e,0xb400b4b4,0x28002828,
+	0x55005555,0x68006868,0x50005050,0xbe00bebe,
+	0xd000d0d0,0xc400c4c4,0x31003131,0xcb00cbcb,
+	0x2a002a2a,0xad00adad,0x0f000f0f,0xca00caca,
+	0x70007070,0xff00ffff,0x32003232,0x69006969,
+	0x08000808,0x62006262,0x00000000,0x24002424,
+	0xd100d1d1,0xfb00fbfb,0xba00baba,0xed00eded,
+	0x45004545,0x81008181,0x73007373,0x6d006d6d,
+	0x84008484,0x9f009f9f,0xee00eeee,0x4a004a4a,
+	0xc300c3c3,0x2e002e2e,0xc100c1c1,0x01000101,
+	0xe600e6e6,0x25002525,0x48004848,0x99009999,
+	0xb900b9b9,0xb300b3b3,0x7b007b7b,0xf900f9f9,
+	0xce00cece,0xbf00bfbf,0xdf00dfdf,0x71007171,
+	0x29002929,0xcd00cdcd,0x6c006c6c,0x13001313,
+	0x64006464,0x9b009b9b,0x63006363,0x9d009d9d,
+	0xc000c0c0,0x4b004b4b,0xb700b7b7,0xa500a5a5,
+	0x89008989,0x5f005f5f,0xb100b1b1,0x17001717,
+	0xf400f4f4,0xbc00bcbc,0xd300d3d3,0x46004646,
+	0xcf00cfcf,0x37003737,0x5e005e5e,0x47004747,
+	0x94009494,0xfa00fafa,0xfc00fcfc,0x5b005b5b,
+	0x97009797,0xfe00fefe,0x5a005a5a,0xac00acac,
+	0x3c003c3c,0x4c004c4c,0x03000303,0x35003535,
+	0xf300f3f3,0x23002323,0xb800b8b8,0x5d005d5d,
+	0x6a006a6a,0x92009292,0xd500d5d5,0x21002121,
+	0x44004444,0x51005151,0xc600c6c6,0x7d007d7d,
+	0x39003939,0x83008383,0xdc00dcdc,0xaa00aaaa,
+	0x7c007c7c,0x77007777,0x56005656,0x05000505,
+	0x1b001b1b,0xa400a4a4,0x15001515,0x34003434,
+	0x1e001e1e,0x1c001c1c,0xf800f8f8,0x52005252,
+	0x20002020,0x14001414,0xe900e9e9,0xbd00bdbd,
+	0xdd00dddd,0xe400e4e4,0xa100a1a1,0xe000e0e0,
+	0x8a008a8a,0xf100f1f1,0xd600d6d6,0x7a007a7a,
+	0xbb00bbbb,0xe300e3e3,0x40004040,0x4f004f4f,
+};
+
+static const u32 camellia_sp4404[256] = {
+	0x70700070,0x2c2c002c,0xb3b300b3,0xc0c000c0,
+	0xe4e400e4,0x57570057,0xeaea00ea,0xaeae00ae,
+	0x23230023,0x6b6b006b,0x45450045,0xa5a500a5,
+	0xeded00ed,0x4f4f004f,0x1d1d001d,0x92920092,
+	0x86860086,0xafaf00af,0x7c7c007c,0x1f1f001f,
+	0x3e3e003e,0xdcdc00dc,0x5e5e005e,0x0b0b000b,
+	0xa6a600a6,0x39390039,0xd5d500d5,0x5d5d005d,
+	0xd9d900d9,0x5a5a005a,0x51510051,0x6c6c006c,
+	0x8b8b008b,0x9a9a009a,0xfbfb00fb,0xb0b000b0,
+	0x74740074,0x2b2b002b,0xf0f000f0,0x84840084,
+	0xdfdf00df,0xcbcb00cb,0x34340034,0x76760076,
+	0x6d6d006d,0xa9a900a9,0xd1d100d1,0x04040004,
+	0x14140014,0x3a3a003a,0xdede00de,0x11110011,
+	0x32320032,0x9c9c009c,0x53530053,0xf2f200f2,
+	0xfefe00fe,0xcfcf00cf,0xc3c300c3,0x7a7a007a,
+	0x24240024,0xe8e800e8,0x60600060,0x69690069,
+	0xaaaa00aa,0xa0a000a0,0xa1a100a1,0x62620062,
+	0x54540054,0x1e1e001e,0xe0e000e0,0x64640064,
+	0x10100010,0x00000000,0xa3a300a3,0x75750075,
+	0x8a8a008a,0xe6e600e6,0x09090009,0xdddd00dd,
+	0x87870087,0x83830083,0xcdcd00cd,0x90900090,
+	0x73730073,0xf6f600f6,0x9d9d009d,0xbfbf00bf,
+	0x52520052,0xd8d800d8,0xc8c800c8,0xc6c600c6,
+	0x81810081,0x6f6f006f,0x13130013,0x63630063,
+	0xe9e900e9,0xa7a700a7,0x9f9f009f,0xbcbc00bc,
+	0x29290029,0xf9f900f9,0x2f2f002f,0xb4b400b4,
+	0x78780078,0x06060006,0xe7e700e7,0x71710071,
+	0xd4d400d4,0xabab00ab,0x88880088,0x8d8d008d,
+	0x72720072,0xb9b900b9,0xf8f800f8,0xacac00ac,
+	0x36360036,0x2a2a002a,0x3c3c003c,0xf1f100f1,
+	0x40400040,0xd3d300d3,0xbbbb00bb,0x43430043,
+	0x15150015,0xadad00ad,0x77770077,0x80800080,
+	0x82820082,0xecec00ec,0x27270027,0xe5e500e5,
+	0x85850085,0x35350035,0x0c0c000c,0x41410041,
+	0xefef00ef,0x93930093,0x19190019,0x21210021,
+	0x0e0e000e,0x4e4e004e,0x65650065,0xbdbd00bd,
+	0xb8b800b8,0x8f8f008f,0xebeb00eb,0xcece00ce,
+	0x30300030,0x5f5f005f,0xc5c500c5,0x1a1a001a,
+	0xe1e100e1,0xcaca00ca,0x47470047,0x3d3d003d,
+	0x01010001,0xd6d600d6,0x56560056,0x4d4d004d,
+	0x0d0d000d,0x66660066,0xcccc00cc,0x2d2d002d,
+	0x12120012,0x20200020,0xb1b100b1,0x99990099,
+	0x4c4c004c,0xc2c200c2,0x7e7e007e,0x05050005,
+	0xb7b700b7,0x31310031,0x17170017,0xd7d700d7,
+	0x58580058,0x61610061,0x1b1b001b,0x1c1c001c,
+	0x0f0f000f,0x16160016,0x18180018,0x22220022,
+	0x44440044,0xb2b200b2,0xb5b500b5,0x91910091,
+	0x08080008,0xa8a800a8,0xfcfc00fc,0x50500050,
+	0xd0d000d0,0x7d7d007d,0x89890089,0x97970097,
+	0x5b5b005b,0x95950095,0xffff00ff,0xd2d200d2,
+	0xc4c400c4,0x48480048,0xf7f700f7,0xdbdb00db,
+	0x03030003,0xdada00da,0x3f3f003f,0x94940094,
+	0x5c5c005c,0x02020002,0x4a4a004a,0x33330033,
+	0x67670067,0xf3f300f3,0x7f7f007f,0xe2e200e2,
+	0x9b9b009b,0x26260026,0x37370037,0x3b3b003b,
+	0x96960096,0x4b4b004b,0xbebe00be,0x2e2e002e,
+	0x79790079,0x8c8c008c,0x6e6e006e,0x8e8e008e,
+	0xf5f500f5,0xb6b600b6,0xfdfd00fd,0x59590059,
+	0x98980098,0x6a6a006a,0x46460046,0xbaba00ba,
+	0x25250025,0x42420042,0xa2a200a2,0xfafa00fa,
+	0x07070007,0x55550055,0xeeee00ee,0x0a0a000a,
+	0x49490049,0x68680068,0x38380038,0xa4a400a4,
+	0x28280028,0x7b7b007b,0xc9c900c9,0xc1c100c1,
+	0xe3e300e3,0xf4f400f4,0xc7c700c7,0x9e9e009e,
+};
+
+
+
+static void camellia_setup128(const unsigned char *key, u32 *subkey)
+{
+	u32 kll, klr, krl, krr;
+	u32 il, ir, t0, t1, w0, w1;
+	u32 kw4l, kw4r, dw, tl, tr;
+	u32 subL[26];
+	u32 subR[26];
+
+	/**
+	 *  k == kll || klr || krl || krr (|| is concatination)
+	 */
+	kll = GETU32(key     );
+	klr = GETU32(key +  4);
+	krl = GETU32(key +  8);
+	krr = GETU32(key + 12);
+	/**
+	 * generate KL dependent subkeys
+	 */
+	/* kw1 */
+	SUBL(0) = kll; SUBR(0) = klr;
+	/* kw2 */
+	SUBL(1) = krl; SUBR(1) = krr;
+	/* rotation left shift 15bit */
+	CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+	/* k3 */
+	SUBL(4) = kll; SUBR(4) = klr;
+	/* k4 */
+	SUBL(5) = krl; SUBR(5) = krr;
+	/* rotation left shift 15+30bit */
+	CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30);
+	/* k7 */
+	SUBL(10) = kll; SUBR(10) = klr;
+	/* k8 */
+	SUBL(11) = krl; SUBR(11) = krr;
+	/* rotation left shift 15+30+15bit */
+	CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+	/* k10 */
+	SUBL(13) = krl; SUBR(13) = krr;
+	/* rotation left shift 15+30+15+17 bit */
+	CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+	/* kl3 */
+	SUBL(16) = kll; SUBR(16) = klr;
+	/* kl4 */
+	SUBL(17) = krl; SUBR(17) = krr;
+	/* rotation left shift 15+30+15+17+17 bit */
+	CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+	/* k13 */
+	SUBL(18) = kll; SUBR(18) = klr;
+	/* k14 */
+	SUBL(19) = krl; SUBR(19) = krr;
+	/* rotation left shift 15+30+15+17+17+17 bit */
+	CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+	/* k17 */
+	SUBL(22) = kll; SUBR(22) = klr;
+	/* k18 */
+	SUBL(23) = krl; SUBR(23) = krr;
+
+	/* generate KA */
+	kll = SUBL(0); klr = SUBR(0);
+	krl = SUBL(1); krr = SUBR(1);
+	CAMELLIA_F(kll, klr,
+		   CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R,
+		   w0, w1, il, ir, t0, t1);
+	krl ^= w0; krr ^= w1;
+	CAMELLIA_F(krl, krr,
+		   CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R,
+		   kll, klr, il, ir, t0, t1);
+	/* current status == (kll, klr, w0, w1) */
+	CAMELLIA_F(kll, klr,
+		   CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R,
+		   krl, krr, il, ir, t0, t1);
+	krl ^= w0; krr ^= w1;
+	CAMELLIA_F(krl, krr,
+		   CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R,
+		   w0, w1, il, ir, t0, t1);
+	kll ^= w0; klr ^= w1;
+
+	/* generate KA dependent subkeys */
+	/* k1, k2 */
+	SUBL(2) = kll; SUBR(2) = klr;
+	SUBL(3) = krl; SUBR(3) = krr;
+	CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+	/* k5,k6 */
+	SUBL(6) = kll; SUBR(6) = klr;
+	SUBL(7) = krl; SUBR(7) = krr;
+	CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+	/* kl1, kl2 */
+	SUBL(8) = kll; SUBR(8) = klr;
+	SUBL(9) = krl; SUBR(9) = krr;
+	CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+	/* k9 */
+	SUBL(12) = kll; SUBR(12) = klr;
+	CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+	/* k11, k12 */
+	SUBL(14) = kll; SUBR(14) = klr;
+	SUBL(15) = krl; SUBR(15) = krr;
+	CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34);
+	/* k15, k16 */
+	SUBL(20) = kll; SUBR(20) = klr;
+	SUBL(21) = krl; SUBR(21) = krr;
+	CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+	/* kw3, kw4 */
+	SUBL(24) = kll; SUBR(24) = klr;
+	SUBL(25) = krl; SUBR(25) = krr;
+
+
+	/* absorb kw2 to other subkeys */
+	/* round 2 */
+	SUBL(3) ^= SUBL(1); SUBR(3) ^= SUBR(1);
+	/* round 4 */
+	SUBL(5) ^= SUBL(1); SUBR(5) ^= SUBR(1);
+	/* round 6 */
+	SUBL(7) ^= SUBL(1); SUBR(7) ^= SUBR(1);
+	SUBL(1) ^= SUBR(1) & ~SUBR(9);
+	dw = SUBL(1) & SUBL(9),
+		SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl2) */
+	/* round 8 */
+	SUBL(11) ^= SUBL(1); SUBR(11) ^= SUBR(1);
+	/* round 10 */
+	SUBL(13) ^= SUBL(1); SUBR(13) ^= SUBR(1);
+	/* round 12 */
+	SUBL(15) ^= SUBL(1); SUBR(15) ^= SUBR(1);
+	SUBL(1) ^= SUBR(1) & ~SUBR(17);
+	dw = SUBL(1) & SUBL(17),
+		SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl4) */
+	/* round 14 */
+	SUBL(19) ^= SUBL(1); SUBR(19) ^= SUBR(1);
+	/* round 16 */
+	SUBL(21) ^= SUBL(1); SUBR(21) ^= SUBR(1);
+	/* round 18 */
+	SUBL(23) ^= SUBL(1); SUBR(23) ^= SUBR(1);
+	/* kw3 */
+	SUBL(24) ^= SUBL(1); SUBR(24) ^= SUBR(1);
+
+	/* absorb kw4 to other subkeys */
+	kw4l = SUBL(25); kw4r = SUBR(25);
+	/* round 17 */
+	SUBL(22) ^= kw4l; SUBR(22) ^= kw4r;
+	/* round 15 */
+	SUBL(20) ^= kw4l; SUBR(20) ^= kw4r;
+	/* round 13 */
+	SUBL(18) ^= kw4l; SUBR(18) ^= kw4r;
+	kw4l ^= kw4r & ~SUBR(16);
+	dw = kw4l & SUBL(16),
+		kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl3) */
+	/* round 11 */
+	SUBL(14) ^= kw4l; SUBR(14) ^= kw4r;
+	/* round 9 */
+	SUBL(12) ^= kw4l; SUBR(12) ^= kw4r;
+	/* round 7 */
+	SUBL(10) ^= kw4l; SUBR(10) ^= kw4r;
+	kw4l ^= kw4r & ~SUBR(8);
+	dw = kw4l & SUBL(8),
+		kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl1) */
+	/* round 5 */
+	SUBL(6) ^= kw4l; SUBR(6) ^= kw4r;
+	/* round 3 */
+	SUBL(4) ^= kw4l; SUBR(4) ^= kw4r;
+	/* round 1 */
+	SUBL(2) ^= kw4l; SUBR(2) ^= kw4r;
+	/* kw1 */
+	SUBL(0) ^= kw4l; SUBR(0) ^= kw4r;
+
+
+	/* key XOR is end of F-function */
+	CAMELLIA_SUBKEY_L(0) = SUBL(0) ^ SUBL(2);/* kw1 */
+	CAMELLIA_SUBKEY_R(0) = SUBR(0) ^ SUBR(2);
+	CAMELLIA_SUBKEY_L(2) = SUBL(3);       /* round 1 */
+	CAMELLIA_SUBKEY_R(2) = SUBR(3);
+	CAMELLIA_SUBKEY_L(3) = SUBL(2) ^ SUBL(4); /* round 2 */
+	CAMELLIA_SUBKEY_R(3) = SUBR(2) ^ SUBR(4);
+	CAMELLIA_SUBKEY_L(4) = SUBL(3) ^ SUBL(5); /* round 3 */
+	CAMELLIA_SUBKEY_R(4) = SUBR(3) ^ SUBR(5);
+	CAMELLIA_SUBKEY_L(5) = SUBL(4) ^ SUBL(6); /* round 4 */
+	CAMELLIA_SUBKEY_R(5) = SUBR(4) ^ SUBR(6);
+	CAMELLIA_SUBKEY_L(6) = SUBL(5) ^ SUBL(7); /* round 5 */
+	CAMELLIA_SUBKEY_R(6) = SUBR(5) ^ SUBR(7);
+	tl = SUBL(10) ^ (SUBR(10) & ~SUBR(8));
+	dw = tl & SUBL(8),  /* FL(kl1) */
+		tr = SUBR(10) ^ CAMELLIA_RL1(dw);
+	CAMELLIA_SUBKEY_L(7) = SUBL(6) ^ tl; /* round 6 */
+	CAMELLIA_SUBKEY_R(7) = SUBR(6) ^ tr;
+	CAMELLIA_SUBKEY_L(8) = SUBL(8);       /* FL(kl1) */
+	CAMELLIA_SUBKEY_R(8) = SUBR(8);
+	CAMELLIA_SUBKEY_L(9) = SUBL(9);       /* FLinv(kl2) */
+	CAMELLIA_SUBKEY_R(9) = SUBR(9);
+	tl = SUBL(7) ^ (SUBR(7) & ~SUBR(9));
+	dw = tl & SUBL(9),  /* FLinv(kl2) */
+		tr = SUBR(7) ^ CAMELLIA_RL1(dw);
+	CAMELLIA_SUBKEY_L(10) = tl ^ SUBL(11); /* round 7 */
+	CAMELLIA_SUBKEY_R(10) = tr ^ SUBR(11);
+	CAMELLIA_SUBKEY_L(11) = SUBL(10) ^ SUBL(12); /* round 8 */
+	CAMELLIA_SUBKEY_R(11) = SUBR(10) ^ SUBR(12);
+	CAMELLIA_SUBKEY_L(12) = SUBL(11) ^ SUBL(13); /* round 9 */
+	CAMELLIA_SUBKEY_R(12) = SUBR(11) ^ SUBR(13);
+	CAMELLIA_SUBKEY_L(13) = SUBL(12) ^ SUBL(14); /* round 10 */
+	CAMELLIA_SUBKEY_R(13) = SUBR(12) ^ SUBR(14);
+	CAMELLIA_SUBKEY_L(14) = SUBL(13) ^ SUBL(15); /* round 11 */
+	CAMELLIA_SUBKEY_R(14) = SUBR(13) ^ SUBR(15);
+	tl = SUBL(18) ^ (SUBR(18) & ~SUBR(16));
+	dw = tl & SUBL(16), /* FL(kl3) */
+		tr = SUBR(18) ^ CAMELLIA_RL1(dw);
+	CAMELLIA_SUBKEY_L(15) = SUBL(14) ^ tl; /* round 12 */
+	CAMELLIA_SUBKEY_R(15) = SUBR(14) ^ tr;
+	CAMELLIA_SUBKEY_L(16) = SUBL(16);     /* FL(kl3) */
+	CAMELLIA_SUBKEY_R(16) = SUBR(16);
+	CAMELLIA_SUBKEY_L(17) = SUBL(17);     /* FLinv(kl4) */
+	CAMELLIA_SUBKEY_R(17) = SUBR(17);
+	tl = SUBL(15) ^ (SUBR(15) & ~SUBR(17));
+	dw = tl & SUBL(17), /* FLinv(kl4) */
+		tr = SUBR(15) ^ CAMELLIA_RL1(dw);
+	CAMELLIA_SUBKEY_L(18) = tl ^ SUBL(19); /* round 13 */
+	CAMELLIA_SUBKEY_R(18) = tr ^ SUBR(19);
+	CAMELLIA_SUBKEY_L(19) = SUBL(18) ^ SUBL(20); /* round 14 */
+	CAMELLIA_SUBKEY_R(19) = SUBR(18) ^ SUBR(20);
+	CAMELLIA_SUBKEY_L(20) = SUBL(19) ^ SUBL(21); /* round 15 */
+	CAMELLIA_SUBKEY_R(20) = SUBR(19) ^ SUBR(21);
+	CAMELLIA_SUBKEY_L(21) = SUBL(20) ^ SUBL(22); /* round 16 */
+	CAMELLIA_SUBKEY_R(21) = SUBR(20) ^ SUBR(22);
+	CAMELLIA_SUBKEY_L(22) = SUBL(21) ^ SUBL(23); /* round 17 */
+	CAMELLIA_SUBKEY_R(22) = SUBR(21) ^ SUBR(23);
+	CAMELLIA_SUBKEY_L(23) = SUBL(22);     /* round 18 */
+	CAMELLIA_SUBKEY_R(23) = SUBR(22);
+	CAMELLIA_SUBKEY_L(24) = SUBL(24) ^ SUBL(23); /* kw3 */
+	CAMELLIA_SUBKEY_R(24) = SUBR(24) ^ SUBR(23);
+
+	/* apply the inverse of the last half of P-function */
+	dw = CAMELLIA_SUBKEY_L(2) ^ CAMELLIA_SUBKEY_R(2),
+		dw = CAMELLIA_RL8(dw);/* round 1 */
+	CAMELLIA_SUBKEY_R(2) = CAMELLIA_SUBKEY_L(2) ^ dw,
+		CAMELLIA_SUBKEY_L(2) = dw;
+	dw = CAMELLIA_SUBKEY_L(3) ^ CAMELLIA_SUBKEY_R(3),
+		dw = CAMELLIA_RL8(dw);/* round 2 */
+	CAMELLIA_SUBKEY_R(3) = CAMELLIA_SUBKEY_L(3) ^ dw,
+		CAMELLIA_SUBKEY_L(3) = dw;
+	dw = CAMELLIA_SUBKEY_L(4) ^ CAMELLIA_SUBKEY_R(4),
+		dw = CAMELLIA_RL8(dw);/* round 3 */
+	CAMELLIA_SUBKEY_R(4) = CAMELLIA_SUBKEY_L(4) ^ dw,
+		CAMELLIA_SUBKEY_L(4) = dw;
+	dw = CAMELLIA_SUBKEY_L(5) ^ CAMELLIA_SUBKEY_R(5),
+		dw = CAMELLIA_RL8(dw);/* round 4 */
+	CAMELLIA_SUBKEY_R(5) = CAMELLIA_SUBKEY_L(5) ^ dw,
+		CAMELLIA_SUBKEY_L(5) = dw;
+	dw = CAMELLIA_SUBKEY_L(6) ^ CAMELLIA_SUBKEY_R(6),
+		dw = CAMELLIA_RL8(dw);/* round 5 */
+	CAMELLIA_SUBKEY_R(6) = CAMELLIA_SUBKEY_L(6) ^ dw,
+		CAMELLIA_SUBKEY_L(6) = dw;
+	dw = CAMELLIA_SUBKEY_L(7) ^ CAMELLIA_SUBKEY_R(7),
+		dw = CAMELLIA_RL8(dw);/* round 6 */
+	CAMELLIA_SUBKEY_R(7) = CAMELLIA_SUBKEY_L(7) ^ dw,
+		CAMELLIA_SUBKEY_L(7) = dw;
+	dw = CAMELLIA_SUBKEY_L(10) ^ CAMELLIA_SUBKEY_R(10),
+		dw = CAMELLIA_RL8(dw);/* round 7 */
+	CAMELLIA_SUBKEY_R(10) = CAMELLIA_SUBKEY_L(10) ^ dw,
+		CAMELLIA_SUBKEY_L(10) = dw;
+	dw = CAMELLIA_SUBKEY_L(11) ^ CAMELLIA_SUBKEY_R(11),
+		dw = CAMELLIA_RL8(dw);/* round 8 */
+	CAMELLIA_SUBKEY_R(11) = CAMELLIA_SUBKEY_L(11) ^ dw,
+		CAMELLIA_SUBKEY_L(11) = dw;
+	dw = CAMELLIA_SUBKEY_L(12) ^ CAMELLIA_SUBKEY_R(12),
+		dw = CAMELLIA_RL8(dw);/* round 9 */
+	CAMELLIA_SUBKEY_R(12) = CAMELLIA_SUBKEY_L(12) ^ dw,
+		CAMELLIA_SUBKEY_L(12) = dw;
+	dw = CAMELLIA_SUBKEY_L(13) ^ CAMELLIA_SUBKEY_R(13),
+		dw = CAMELLIA_RL8(dw);/* round 10 */
+	CAMELLIA_SUBKEY_R(13) = CAMELLIA_SUBKEY_L(13) ^ dw,
+		CAMELLIA_SUBKEY_L(13) = dw;
+	dw = CAMELLIA_SUBKEY_L(14) ^ CAMELLIA_SUBKEY_R(14),
+		dw = CAMELLIA_RL8(dw);/* round 11 */
+	CAMELLIA_SUBKEY_R(14) = CAMELLIA_SUBKEY_L(14) ^ dw,
+		CAMELLIA_SUBKEY_L(14) = dw;
+	dw = CAMELLIA_SUBKEY_L(15) ^ CAMELLIA_SUBKEY_R(15),
+		dw = CAMELLIA_RL8(dw);/* round 12 */
+	CAMELLIA_SUBKEY_R(15) = CAMELLIA_SUBKEY_L(15) ^ dw,
+		CAMELLIA_SUBKEY_L(15) = dw;
+	dw = CAMELLIA_SUBKEY_L(18) ^ CAMELLIA_SUBKEY_R(18),
+		dw = CAMELLIA_RL8(dw);/* round 13 */
+	CAMELLIA_SUBKEY_R(18) = CAMELLIA_SUBKEY_L(18) ^ dw,
+		CAMELLIA_SUBKEY_L(18) = dw;
+	dw = CAMELLIA_SUBKEY_L(19) ^ CAMELLIA_SUBKEY_R(19),
+		dw = CAMELLIA_RL8(dw);/* round 14 */
+	CAMELLIA_SUBKEY_R(19) = CAMELLIA_SUBKEY_L(19) ^ dw,
+		CAMELLIA_SUBKEY_L(19) = dw;
+	dw = CAMELLIA_SUBKEY_L(20) ^ CAMELLIA_SUBKEY_R(20),
+		dw = CAMELLIA_RL8(dw);/* round 15 */
+	CAMELLIA_SUBKEY_R(20) = CAMELLIA_SUBKEY_L(20) ^ dw,
+		CAMELLIA_SUBKEY_L(20) = dw;
+	dw = CAMELLIA_SUBKEY_L(21) ^ CAMELLIA_SUBKEY_R(21),
+		dw = CAMELLIA_RL8(dw);/* round 16 */
+	CAMELLIA_SUBKEY_R(21) = CAMELLIA_SUBKEY_L(21) ^ dw,
+		CAMELLIA_SUBKEY_L(21) = dw;
+	dw = CAMELLIA_SUBKEY_L(22) ^ CAMELLIA_SUBKEY_R(22),
+		dw = CAMELLIA_RL8(dw);/* round 17 */
+	CAMELLIA_SUBKEY_R(22) = CAMELLIA_SUBKEY_L(22) ^ dw,
+		CAMELLIA_SUBKEY_L(22) = dw;
+	dw = CAMELLIA_SUBKEY_L(23) ^ CAMELLIA_SUBKEY_R(23),
+		dw = CAMELLIA_RL8(dw);/* round 18 */
+	CAMELLIA_SUBKEY_R(23) = CAMELLIA_SUBKEY_L(23) ^ dw,
+		CAMELLIA_SUBKEY_L(23) = dw;
+
+	return;
+}
+
+
+static void camellia_setup256(const unsigned char *key, u32 *subkey)
+{
+	u32 kll,klr,krl,krr;           /* left half of key */
+	u32 krll,krlr,krrl,krrr;       /* right half of key */
+	u32 il, ir, t0, t1, w0, w1;    /* temporary variables */
+	u32 kw4l, kw4r, dw, tl, tr;
+	u32 subL[34];
+	u32 subR[34];
+
+	/**
+	 *  key = (kll || klr || krl || krr || krll || krlr || krrl || krrr)
+	 *  (|| is concatination)
+	 */
+
+	kll  = GETU32(key     );
+	klr  = GETU32(key +  4);
+	krl  = GETU32(key +  8);
+	krr  = GETU32(key + 12);
+	krll = GETU32(key + 16);
+	krlr = GETU32(key + 20);
+	krrl = GETU32(key + 24);
+	krrr = GETU32(key + 28);
+
+	/* generate KL dependent subkeys */
+	/* kw1 */
+	SUBL(0) = kll; SUBR(0) = klr;
+	/* kw2 */
+	SUBL(1) = krl; SUBR(1) = krr;
+	CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 45);
+	/* k9 */
+	SUBL(12) = kll; SUBR(12) = klr;
+	/* k10 */
+	SUBL(13) = krl; SUBR(13) = krr;
+	CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+	/* kl3 */
+	SUBL(16) = kll; SUBR(16) = klr;
+	/* kl4 */
+	SUBL(17) = krl; SUBR(17) = krr;
+	CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+	/* k17 */
+	SUBL(22) = kll; SUBR(22) = klr;
+	/* k18 */
+	SUBL(23) = krl; SUBR(23) = krr;
+	CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34);
+	/* k23 */
+	SUBL(30) = kll; SUBR(30) = klr;
+	/* k24 */
+	SUBL(31) = krl; SUBR(31) = krr;
+
+	/* generate KR dependent subkeys */
+	CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15);
+	/* k3 */
+	SUBL(4) = krll; SUBR(4) = krlr;
+	/* k4 */
+	SUBL(5) = krrl; SUBR(5) = krrr;
+	CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15);
+	/* kl1 */
+	SUBL(8) = krll; SUBR(8) = krlr;
+	/* kl2 */
+	SUBL(9) = krrl; SUBR(9) = krrr;
+	CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
+	/* k13 */
+	SUBL(18) = krll; SUBR(18) = krlr;
+	/* k14 */
+	SUBL(19) = krrl; SUBR(19) = krrr;
+	CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34);
+	/* k19 */
+	SUBL(26) = krll; SUBR(26) = krlr;
+	/* k20 */
+	SUBL(27) = krrl; SUBR(27) = krrr;
+	CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34);
+
+	/* generate KA */
+	kll = SUBL(0) ^ krll; klr = SUBR(0) ^ krlr;
+	krl = SUBL(1) ^ krrl; krr = SUBR(1) ^ krrr;
+	CAMELLIA_F(kll, klr,
+		   CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R,
+		   w0, w1, il, ir, t0, t1);
+	krl ^= w0; krr ^= w1;
+	CAMELLIA_F(krl, krr,
+		   CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R,
+		   kll, klr, il, ir, t0, t1);
+	kll ^= krll; klr ^= krlr;
+	CAMELLIA_F(kll, klr,
+		   CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R,
+		   krl, krr, il, ir, t0, t1);
+	krl ^= w0 ^ krrl; krr ^= w1 ^ krrr;
+	CAMELLIA_F(krl, krr,
+		   CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R,
+		   w0, w1, il, ir, t0, t1);
+	kll ^= w0; klr ^= w1;
+
+	/* generate KB */
+	krll ^= kll; krlr ^= klr;
+	krrl ^= krl; krrr ^= krr;
+	CAMELLIA_F(krll, krlr,
+		   CAMELLIA_SIGMA5L, CAMELLIA_SIGMA5R,
+		   w0, w1, il, ir, t0, t1);
+	krrl ^= w0; krrr ^= w1;
+	CAMELLIA_F(krrl, krrr,
+		   CAMELLIA_SIGMA6L, CAMELLIA_SIGMA6R,
+		   w0, w1, il, ir, t0, t1);
+	krll ^= w0; krlr ^= w1;
+
+	/* generate KA dependent subkeys */
+	CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+	/* k5 */
+	SUBL(6) = kll; SUBR(6) = klr;
+	/* k6 */
+	SUBL(7) = krl; SUBR(7) = krr;
+	CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30);
+	/* k11 */
+	SUBL(14) = kll; SUBR(14) = klr;
+	/* k12 */
+	SUBL(15) = krl; SUBR(15) = krr;
+	/* rotation left shift 32bit */
+	/* kl5 */
+	SUBL(24) = klr; SUBR(24) = krl;
+	/* kl6 */
+	SUBL(25) = krr; SUBR(25) = kll;
+	/* rotation left shift 49 from k11,k12 -> k21,k22 */
+	CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 49);
+	/* k21 */
+	SUBL(28) = kll; SUBR(28) = klr;
+	/* k22 */
+	SUBL(29) = krl; SUBR(29) = krr;
+
+	/* generate KB dependent subkeys */
+	/* k1 */
+	SUBL(2) = krll; SUBR(2) = krlr;
+	/* k2 */
+	SUBL(3) = krrl; SUBR(3) = krrr;
+	CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
+	/* k7 */
+	SUBL(10) = krll; SUBR(10) = krlr;
+	/* k8 */
+	SUBL(11) = krrl; SUBR(11) = krrr;
+	CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
+	/* k15 */
+	SUBL(20) = krll; SUBR(20) = krlr;
+	/* k16 */
+	SUBL(21) = krrl; SUBR(21) = krrr;
+	CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 51);
+	/* kw3 */
+	SUBL(32) = krll; SUBR(32) = krlr;
+	/* kw4 */
+	SUBL(33) = krrl; SUBR(33) = krrr;
+
+	/* absorb kw2 to other subkeys */
+	/* round 2 */
+	SUBL(3) ^= SUBL(1); SUBR(3) ^= SUBR(1);
+	/* round 4 */
+	SUBL(5) ^= SUBL(1); SUBR(5) ^= SUBR(1);
+	/* round 6 */
+	SUBL(7) ^= SUBL(1); SUBR(7) ^= SUBR(1);
+	SUBL(1) ^= SUBR(1) & ~SUBR(9);
+	dw = SUBL(1) & SUBL(9),
+		SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl2) */
+	/* round 8 */
+	SUBL(11) ^= SUBL(1); SUBR(11) ^= SUBR(1);
+	/* round 10 */
+	SUBL(13) ^= SUBL(1); SUBR(13) ^= SUBR(1);
+	/* round 12 */
+	SUBL(15) ^= SUBL(1); SUBR(15) ^= SUBR(1);
+	SUBL(1) ^= SUBR(1) & ~SUBR(17);
+	dw = SUBL(1) & SUBL(17),
+		SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl4) */
+	/* round 14 */
+	SUBL(19) ^= SUBL(1); SUBR(19) ^= SUBR(1);
+	/* round 16 */
+	SUBL(21) ^= SUBL(1); SUBR(21) ^= SUBR(1);
+	/* round 18 */
+	SUBL(23) ^= SUBL(1); SUBR(23) ^= SUBR(1);
+	SUBL(1) ^= SUBR(1) & ~SUBR(25);
+	dw = SUBL(1) & SUBL(25),
+		SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl6) */
+	/* round 20 */
+	SUBL(27) ^= SUBL(1); SUBR(27) ^= SUBR(1);
+	/* round 22 */
+	SUBL(29) ^= SUBL(1); SUBR(29) ^= SUBR(1);
+	/* round 24 */
+	SUBL(31) ^= SUBL(1); SUBR(31) ^= SUBR(1);
+	/* kw3 */
+	SUBL(32) ^= SUBL(1); SUBR(32) ^= SUBR(1);
+
+
+	/* absorb kw4 to other subkeys */
+	kw4l = SUBL(33); kw4r = SUBR(33);
+	/* round 23 */
+	SUBL(30) ^= kw4l; SUBR(30) ^= kw4r;
+	/* round 21 */
+	SUBL(28) ^= kw4l; SUBR(28) ^= kw4r;
+	/* round 19 */
+	SUBL(26) ^= kw4l; SUBR(26) ^= kw4r;
+	kw4l ^= kw4r & ~SUBR(24);
+	dw = kw4l & SUBL(24),
+		kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl5) */
+	/* round 17 */
+	SUBL(22) ^= kw4l; SUBR(22) ^= kw4r;
+	/* round 15 */
+	SUBL(20) ^= kw4l; SUBR(20) ^= kw4r;
+	/* round 13 */
+	SUBL(18) ^= kw4l; SUBR(18) ^= kw4r;
+	kw4l ^= kw4r & ~SUBR(16);
+	dw = kw4l & SUBL(16),
+		kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl3) */
+	/* round 11 */
+	SUBL(14) ^= kw4l; SUBR(14) ^= kw4r;
+	/* round 9 */
+	SUBL(12) ^= kw4l; SUBR(12) ^= kw4r;
+	/* round 7 */
+	SUBL(10) ^= kw4l; SUBR(10) ^= kw4r;
+	kw4l ^= kw4r & ~SUBR(8);
+	dw = kw4l & SUBL(8),
+		kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl1) */
+	/* round 5 */
+	SUBL(6) ^= kw4l; SUBR(6) ^= kw4r;
+	/* round 3 */
+	SUBL(4) ^= kw4l; SUBR(4) ^= kw4r;
+	/* round 1 */
+	SUBL(2) ^= kw4l; SUBR(2) ^= kw4r;
+	/* kw1 */
+	SUBL(0) ^= kw4l; SUBR(0) ^= kw4r;
+
+	/* key XOR is end of F-function */
+	CAMELLIA_SUBKEY_L(0) = SUBL(0) ^ SUBL(2);/* kw1 */
+	CAMELLIA_SUBKEY_R(0) = SUBR(0) ^ SUBR(2);
+	CAMELLIA_SUBKEY_L(2) = SUBL(3);       /* round 1 */
+	CAMELLIA_SUBKEY_R(2) = SUBR(3);
+	CAMELLIA_SUBKEY_L(3) = SUBL(2) ^ SUBL(4); /* round 2 */
+	CAMELLIA_SUBKEY_R(3) = SUBR(2) ^ SUBR(4);
+	CAMELLIA_SUBKEY_L(4) = SUBL(3) ^ SUBL(5); /* round 3 */
+	CAMELLIA_SUBKEY_R(4) = SUBR(3) ^ SUBR(5);
+	CAMELLIA_SUBKEY_L(5) = SUBL(4) ^ SUBL(6); /* round 4 */
+	CAMELLIA_SUBKEY_R(5) = SUBR(4) ^ SUBR(6);
+	CAMELLIA_SUBKEY_L(6) = SUBL(5) ^ SUBL(7); /* round 5 */
+	CAMELLIA_SUBKEY_R(6) = SUBR(5) ^ SUBR(7);
+	tl = SUBL(10) ^ (SUBR(10) & ~SUBR(8));
+	dw = tl & SUBL(8),  /* FL(kl1) */
+		tr = SUBR(10) ^ CAMELLIA_RL1(dw);
+	CAMELLIA_SUBKEY_L(7) = SUBL(6) ^ tl; /* round 6 */
+	CAMELLIA_SUBKEY_R(7) = SUBR(6) ^ tr;
+	CAMELLIA_SUBKEY_L(8) = SUBL(8);       /* FL(kl1) */
+	CAMELLIA_SUBKEY_R(8) = SUBR(8);
+	CAMELLIA_SUBKEY_L(9) = SUBL(9);       /* FLinv(kl2) */
+	CAMELLIA_SUBKEY_R(9) = SUBR(9);
+	tl = SUBL(7) ^ (SUBR(7) & ~SUBR(9));
+	dw = tl & SUBL(9),  /* FLinv(kl2) */
+		tr = SUBR(7) ^ CAMELLIA_RL1(dw);
+	CAMELLIA_SUBKEY_L(10) = tl ^ SUBL(11); /* round 7 */
+	CAMELLIA_SUBKEY_R(10) = tr ^ SUBR(11);
+	CAMELLIA_SUBKEY_L(11) = SUBL(10) ^ SUBL(12); /* round 8 */
+	CAMELLIA_SUBKEY_R(11) = SUBR(10) ^ SUBR(12);
+	CAMELLIA_SUBKEY_L(12) = SUBL(11) ^ SUBL(13); /* round 9 */
+	CAMELLIA_SUBKEY_R(12) = SUBR(11) ^ SUBR(13);
+	CAMELLIA_SUBKEY_L(13) = SUBL(12) ^ SUBL(14); /* round 10 */
+	CAMELLIA_SUBKEY_R(13) = SUBR(12) ^ SUBR(14);
+	CAMELLIA_SUBKEY_L(14) = SUBL(13) ^ SUBL(15); /* round 11 */
+	CAMELLIA_SUBKEY_R(14) = SUBR(13) ^ SUBR(15);
+	tl = SUBL(18) ^ (SUBR(18) & ~SUBR(16));
+	dw = tl & SUBL(16), /* FL(kl3) */
+		tr = SUBR(18) ^ CAMELLIA_RL1(dw);
+	CAMELLIA_SUBKEY_L(15) = SUBL(14) ^ tl; /* round 12 */
+	CAMELLIA_SUBKEY_R(15) = SUBR(14) ^ tr;
+	CAMELLIA_SUBKEY_L(16) = SUBL(16);     /* FL(kl3) */
+	CAMELLIA_SUBKEY_R(16) = SUBR(16);
+	CAMELLIA_SUBKEY_L(17) = SUBL(17);     /* FLinv(kl4) */
+	CAMELLIA_SUBKEY_R(17) = SUBR(17);
+	tl = SUBL(15) ^ (SUBR(15) & ~SUBR(17));
+	dw = tl & SUBL(17), /* FLinv(kl4) */
+		tr = SUBR(15) ^ CAMELLIA_RL1(dw);
+	CAMELLIA_SUBKEY_L(18) = tl ^ SUBL(19); /* round 13 */
+	CAMELLIA_SUBKEY_R(18) = tr ^ SUBR(19);
+	CAMELLIA_SUBKEY_L(19) = SUBL(18) ^ SUBL(20); /* round 14 */
+	CAMELLIA_SUBKEY_R(19) = SUBR(18) ^ SUBR(20);
+	CAMELLIA_SUBKEY_L(20) = SUBL(19) ^ SUBL(21); /* round 15 */
+	CAMELLIA_SUBKEY_R(20) = SUBR(19) ^ SUBR(21);
+	CAMELLIA_SUBKEY_L(21) = SUBL(20) ^ SUBL(22); /* round 16 */
+	CAMELLIA_SUBKEY_R(21) = SUBR(20) ^ SUBR(22);
+	CAMELLIA_SUBKEY_L(22) = SUBL(21) ^ SUBL(23); /* round 17 */
+	CAMELLIA_SUBKEY_R(22) = SUBR(21) ^ SUBR(23);
+	tl = SUBL(26) ^ (SUBR(26)
+			 & ~SUBR(24));
+	dw = tl & SUBL(24), /* FL(kl5) */
+		tr = SUBR(26) ^ CAMELLIA_RL1(dw);
+	CAMELLIA_SUBKEY_L(23) = SUBL(22) ^ tl; /* round 18 */
+	CAMELLIA_SUBKEY_R(23) = SUBR(22) ^ tr;
+	CAMELLIA_SUBKEY_L(24) = SUBL(24);     /* FL(kl5) */
+	CAMELLIA_SUBKEY_R(24) = SUBR(24);
+	CAMELLIA_SUBKEY_L(25) = SUBL(25);     /* FLinv(kl6) */
+	CAMELLIA_SUBKEY_R(25) = SUBR(25);
+	tl = SUBL(23) ^ (SUBR(23) &
+			 ~SUBR(25));
+	dw = tl & SUBL(25), /* FLinv(kl6) */
+		tr = SUBR(23) ^ CAMELLIA_RL1(dw);
+	CAMELLIA_SUBKEY_L(26) = tl ^ SUBL(27); /* round 19 */
+	CAMELLIA_SUBKEY_R(26) = tr ^ SUBR(27);
+	CAMELLIA_SUBKEY_L(27) = SUBL(26) ^ SUBL(28); /* round 20 */
+	CAMELLIA_SUBKEY_R(27) = SUBR(26) ^ SUBR(28);
+	CAMELLIA_SUBKEY_L(28) = SUBL(27) ^ SUBL(29); /* round 21 */
+	CAMELLIA_SUBKEY_R(28) = SUBR(27) ^ SUBR(29);
+	CAMELLIA_SUBKEY_L(29) = SUBL(28) ^ SUBL(30); /* round 22 */
+	CAMELLIA_SUBKEY_R(29) = SUBR(28) ^ SUBR(30);
+	CAMELLIA_SUBKEY_L(30) = SUBL(29) ^ SUBL(31); /* round 23 */
+	CAMELLIA_SUBKEY_R(30) = SUBR(29) ^ SUBR(31);
+	CAMELLIA_SUBKEY_L(31) = SUBL(30);     /* round 24 */
+	CAMELLIA_SUBKEY_R(31) = SUBR(30);
+	CAMELLIA_SUBKEY_L(32) = SUBL(32) ^ SUBL(31); /* kw3 */
+	CAMELLIA_SUBKEY_R(32) = SUBR(32) ^ SUBR(31);
+
+	/* apply the inverse of the last half of P-function */
+	dw = CAMELLIA_SUBKEY_L(2) ^ CAMELLIA_SUBKEY_R(2),
+		dw = CAMELLIA_RL8(dw);/* round 1 */
+	CAMELLIA_SUBKEY_R(2) = CAMELLIA_SUBKEY_L(2) ^ dw,
+		CAMELLIA_SUBKEY_L(2) = dw;
+	dw = CAMELLIA_SUBKEY_L(3) ^ CAMELLIA_SUBKEY_R(3),
+		dw = CAMELLIA_RL8(dw);/* round 2 */
+	CAMELLIA_SUBKEY_R(3) = CAMELLIA_SUBKEY_L(3) ^ dw,
+		CAMELLIA_SUBKEY_L(3) = dw;
+	dw = CAMELLIA_SUBKEY_L(4) ^ CAMELLIA_SUBKEY_R(4),
+		dw = CAMELLIA_RL8(dw);/* round 3 */
+	CAMELLIA_SUBKEY_R(4) = CAMELLIA_SUBKEY_L(4) ^ dw,
+		CAMELLIA_SUBKEY_L(4) = dw;
+	dw = CAMELLIA_SUBKEY_L(5) ^ CAMELLIA_SUBKEY_R(5),
+		dw = CAMELLIA_RL8(dw);/* round 4 */
+	CAMELLIA_SUBKEY_R(5) = CAMELLIA_SUBKEY_L(5) ^ dw,
+	CAMELLIA_SUBKEY_L(5) = dw;
+	dw = CAMELLIA_SUBKEY_L(6) ^ CAMELLIA_SUBKEY_R(6),
+		dw = CAMELLIA_RL8(dw);/* round 5 */
+	CAMELLIA_SUBKEY_R(6) = CAMELLIA_SUBKEY_L(6) ^ dw,
+		CAMELLIA_SUBKEY_L(6) = dw;
+	dw = CAMELLIA_SUBKEY_L(7) ^ CAMELLIA_SUBKEY_R(7),
+		dw = CAMELLIA_RL8(dw);/* round 6 */
+	CAMELLIA_SUBKEY_R(7) = CAMELLIA_SUBKEY_L(7) ^ dw,
+		CAMELLIA_SUBKEY_L(7) = dw;
+	dw = CAMELLIA_SUBKEY_L(10) ^ CAMELLIA_SUBKEY_R(10),
+		dw = CAMELLIA_RL8(dw);/* round 7 */
+	CAMELLIA_SUBKEY_R(10) = CAMELLIA_SUBKEY_L(10) ^ dw,
+		CAMELLIA_SUBKEY_L(10) = dw;
+	dw = CAMELLIA_SUBKEY_L(11) ^ CAMELLIA_SUBKEY_R(11),
+	    dw = CAMELLIA_RL8(dw);/* round 8 */
+	CAMELLIA_SUBKEY_R(11) = CAMELLIA_SUBKEY_L(11) ^ dw,
+		CAMELLIA_SUBKEY_L(11) = dw;
+	dw = CAMELLIA_SUBKEY_L(12) ^ CAMELLIA_SUBKEY_R(12),
+		dw = CAMELLIA_RL8(dw);/* round 9 */
+	CAMELLIA_SUBKEY_R(12) = CAMELLIA_SUBKEY_L(12) ^ dw,
+		CAMELLIA_SUBKEY_L(12) = dw;
+	dw = CAMELLIA_SUBKEY_L(13) ^ CAMELLIA_SUBKEY_R(13),
+		dw = CAMELLIA_RL8(dw);/* round 10 */
+	CAMELLIA_SUBKEY_R(13) = CAMELLIA_SUBKEY_L(13) ^ dw,
+		CAMELLIA_SUBKEY_L(13) = dw;
+	dw = CAMELLIA_SUBKEY_L(14) ^ CAMELLIA_SUBKEY_R(14),
+		dw = CAMELLIA_RL8(dw);/* round 11 */
+	CAMELLIA_SUBKEY_R(14) = CAMELLIA_SUBKEY_L(14) ^ dw,
+		CAMELLIA_SUBKEY_L(14) = dw;
+	dw = CAMELLIA_SUBKEY_L(15) ^ CAMELLIA_SUBKEY_R(15),
+		dw = CAMELLIA_RL8(dw);/* round 12 */
+	CAMELLIA_SUBKEY_R(15) = CAMELLIA_SUBKEY_L(15) ^ dw,
+		CAMELLIA_SUBKEY_L(15) = dw;
+	dw = CAMELLIA_SUBKEY_L(18) ^ CAMELLIA_SUBKEY_R(18),
+		dw = CAMELLIA_RL8(dw);/* round 13 */
+	CAMELLIA_SUBKEY_R(18) = CAMELLIA_SUBKEY_L(18) ^ dw,
+		CAMELLIA_SUBKEY_L(18) = dw;
+	dw = CAMELLIA_SUBKEY_L(19) ^ CAMELLIA_SUBKEY_R(19),
+		dw = CAMELLIA_RL8(dw);/* round 14 */
+	CAMELLIA_SUBKEY_R(19) = CAMELLIA_SUBKEY_L(19) ^ dw,
+		CAMELLIA_SUBKEY_L(19) = dw;
+	dw = CAMELLIA_SUBKEY_L(20) ^ CAMELLIA_SUBKEY_R(20),
+		dw = CAMELLIA_RL8(dw);/* round 15 */
+	CAMELLIA_SUBKEY_R(20) = CAMELLIA_SUBKEY_L(20) ^ dw,
+		CAMELLIA_SUBKEY_L(20) = dw;
+	dw = CAMELLIA_SUBKEY_L(21) ^ CAMELLIA_SUBKEY_R(21),
+		dw = CAMELLIA_RL8(dw);/* round 16 */
+	CAMELLIA_SUBKEY_R(21) = CAMELLIA_SUBKEY_L(21) ^ dw,
+		CAMELLIA_SUBKEY_L(21) = dw;
+	dw = CAMELLIA_SUBKEY_L(22) ^ CAMELLIA_SUBKEY_R(22),
+		dw = CAMELLIA_RL8(dw);/* round 17 */
+	CAMELLIA_SUBKEY_R(22) = CAMELLIA_SUBKEY_L(22) ^ dw,
+		CAMELLIA_SUBKEY_L(22) = dw;
+	dw = CAMELLIA_SUBKEY_L(23) ^ CAMELLIA_SUBKEY_R(23),
+		dw = CAMELLIA_RL8(dw);/* round 18 */
+	CAMELLIA_SUBKEY_R(23) = CAMELLIA_SUBKEY_L(23) ^ dw,
+		CAMELLIA_SUBKEY_L(23) = dw;
+	dw = CAMELLIA_SUBKEY_L(26) ^ CAMELLIA_SUBKEY_R(26),
+		dw = CAMELLIA_RL8(dw);/* round 19 */
+	CAMELLIA_SUBKEY_R(26) = CAMELLIA_SUBKEY_L(26) ^ dw,
+		CAMELLIA_SUBKEY_L(26) = dw;
+	dw = CAMELLIA_SUBKEY_L(27) ^ CAMELLIA_SUBKEY_R(27),
+		dw = CAMELLIA_RL8(dw);/* round 20 */
+	CAMELLIA_SUBKEY_R(27) = CAMELLIA_SUBKEY_L(27) ^ dw,
+		CAMELLIA_SUBKEY_L(27) = dw;
+	dw = CAMELLIA_SUBKEY_L(28) ^ CAMELLIA_SUBKEY_R(28),
+		dw = CAMELLIA_RL8(dw);/* round 21 */
+	CAMELLIA_SUBKEY_R(28) = CAMELLIA_SUBKEY_L(28) ^ dw,
+		CAMELLIA_SUBKEY_L(28) = dw;
+	dw = CAMELLIA_SUBKEY_L(29) ^ CAMELLIA_SUBKEY_R(29),
+		dw = CAMELLIA_RL8(dw);/* round 22 */
+	CAMELLIA_SUBKEY_R(29) = CAMELLIA_SUBKEY_L(29) ^ dw,
+		CAMELLIA_SUBKEY_L(29) = dw;
+	dw = CAMELLIA_SUBKEY_L(30) ^ CAMELLIA_SUBKEY_R(30),
+		dw = CAMELLIA_RL8(dw);/* round 23 */
+	CAMELLIA_SUBKEY_R(30) = CAMELLIA_SUBKEY_L(30) ^ dw,
+		CAMELLIA_SUBKEY_L(30) = dw;
+	dw = CAMELLIA_SUBKEY_L(31) ^ CAMELLIA_SUBKEY_R(31),
+		dw = CAMELLIA_RL8(dw);/* round 24 */
+	CAMELLIA_SUBKEY_R(31) = CAMELLIA_SUBKEY_L(31) ^ dw,
+		CAMELLIA_SUBKEY_L(31) = dw;
+
+	return;
+}
+
+static void camellia_setup192(const unsigned char *key, u32 *subkey)
+{
+	unsigned char kk[32];
+	u32 krll, krlr, krrl,krrr;
+
+	memcpy(kk, key, 24);
+	memcpy((unsigned char *)&krll, key+16,4);
+	memcpy((unsigned char *)&krlr, key+20,4);
+	krrl = ~krll;
+	krrr = ~krlr;
+	memcpy(kk+24, (unsigned char *)&krrl, 4);
+	memcpy(kk+28, (unsigned char *)&krrr, 4);
+	camellia_setup256(kk, subkey);
+	return;
+}
+
+
+/**
+ * Stuff related to camellia encryption/decryption
+ */
+static void camellia_encrypt128(const u32 *subkey, __be32 *io_text)
+{
+	u32 il,ir,t0,t1;               /* temporary valiables */
+
+	u32 io[4];
+
+	io[0] = be32_to_cpu(io_text[0]);
+	io[1] = be32_to_cpu(io_text[1]);
+	io[2] = be32_to_cpu(io_text[2]);
+	io[3] = be32_to_cpu(io_text[3]);
+
+	/* pre whitening but absorb kw2*/
+	io[0] ^= CAMELLIA_SUBKEY_L(0);
+	io[1] ^= CAMELLIA_SUBKEY_R(0);
+	/* main iteration */
+
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7),
+			 io[0],io[1],il,ir,t0,t1);
+
+	CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		     CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8),
+		     CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9),
+		     t0,t1,il,ir);
+
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15),
+			 io[0],io[1],il,ir,t0,t1);
+
+	CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		     CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16),
+		     CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17),
+		     t0,t1,il,ir);
+
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23),
+			 io[0],io[1],il,ir,t0,t1);
+
+	/* post whitening but kw4 */
+	io[2] ^= CAMELLIA_SUBKEY_L(24);
+	io[3] ^= CAMELLIA_SUBKEY_R(24);
+
+	t0 = io[0];
+	t1 = io[1];
+	io[0] = io[2];
+	io[1] = io[3];
+	io[2] = t0;
+	io[3] = t1;
+
+	io_text[0] = cpu_to_be32(io[0]);
+	io_text[1] = cpu_to_be32(io[1]);
+	io_text[2] = cpu_to_be32(io[2]);
+	io_text[3] = cpu_to_be32(io[3]);
+
+	return;
+}
+
+static void camellia_decrypt128(const u32 *subkey, __be32 *io_text)
+{
+	u32 il,ir,t0,t1;               /* temporary valiables */
+
+	u32 io[4];
+
+	io[0] = be32_to_cpu(io_text[0]);
+	io[1] = be32_to_cpu(io_text[1]);
+	io[2] = be32_to_cpu(io_text[2]);
+	io[3] = be32_to_cpu(io_text[3]);
+
+	/* pre whitening but absorb kw2*/
+	io[0] ^= CAMELLIA_SUBKEY_L(24);
+	io[1] ^= CAMELLIA_SUBKEY_R(24);
+
+	/* main iteration */
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18),
+			 io[0],io[1],il,ir,t0,t1);
+
+	CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		     CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17),
+		     CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16),
+		     t0,t1,il,ir);
+
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10),
+			 io[0],io[1],il,ir,t0,t1);
+
+	CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		     CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9),
+		     CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8),
+		     t0,t1,il,ir);
+
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2),
+			 io[0],io[1],il,ir,t0,t1);
+
+	/* post whitening but kw4 */
+	io[2] ^= CAMELLIA_SUBKEY_L(0);
+	io[3] ^= CAMELLIA_SUBKEY_R(0);
+
+	t0 = io[0];
+	t1 = io[1];
+	io[0] = io[2];
+	io[1] = io[3];
+	io[2] = t0;
+	io[3] = t1;
+
+	io_text[0] = cpu_to_be32(io[0]);
+	io_text[1] = cpu_to_be32(io[1]);
+	io_text[2] = cpu_to_be32(io[2]);
+	io_text[3] = cpu_to_be32(io[3]);
+
+	return;
+}
+
+
+/**
+ * stuff for 192 and 256bit encryption/decryption
+ */
+static void camellia_encrypt256(const u32 *subkey, __be32 *io_text)
+{
+	u32 il,ir,t0,t1;           /* temporary valiables */
+
+	u32 io[4];
+
+	io[0] = be32_to_cpu(io_text[0]);
+	io[1] = be32_to_cpu(io_text[1]);
+	io[2] = be32_to_cpu(io_text[2]);
+	io[3] = be32_to_cpu(io_text[3]);
+
+	/* pre whitening but absorb kw2*/
+	io[0] ^= CAMELLIA_SUBKEY_L(0);
+	io[1] ^= CAMELLIA_SUBKEY_R(0);
+
+	/* main iteration */
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7),
+			 io[0],io[1],il,ir,t0,t1);
+
+	CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		     CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8),
+		     CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9),
+		     t0,t1,il,ir);
+
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15),
+			 io[0],io[1],il,ir,t0,t1);
+
+	CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		     CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16),
+		     CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17),
+		     t0,t1,il,ir);
+
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23),
+			 io[0],io[1],il,ir,t0,t1);
+
+	CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		     CAMELLIA_SUBKEY_L(24),CAMELLIA_SUBKEY_R(24),
+		     CAMELLIA_SUBKEY_L(25),CAMELLIA_SUBKEY_R(25),
+		     t0,t1,il,ir);
+
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(26),CAMELLIA_SUBKEY_R(26),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(27),CAMELLIA_SUBKEY_R(27),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(28),CAMELLIA_SUBKEY_R(28),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(29),CAMELLIA_SUBKEY_R(29),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(30),CAMELLIA_SUBKEY_R(30),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(31),CAMELLIA_SUBKEY_R(31),
+			 io[0],io[1],il,ir,t0,t1);
+
+	/* post whitening but kw4 */
+	io[2] ^= CAMELLIA_SUBKEY_L(32);
+	io[3] ^= CAMELLIA_SUBKEY_R(32);
+
+	t0 = io[0];
+	t1 = io[1];
+	io[0] = io[2];
+	io[1] = io[3];
+	io[2] = t0;
+	io[3] = t1;
+
+	io_text[0] = cpu_to_be32(io[0]);
+	io_text[1] = cpu_to_be32(io[1]);
+	io_text[2] = cpu_to_be32(io[2]);
+	io_text[3] = cpu_to_be32(io[3]);
+
+	return;
+}
+
+
+static void camellia_decrypt256(const u32 *subkey, __be32 *io_text)
+{
+	u32 il,ir,t0,t1;           /* temporary valiables */
+
+	u32 io[4];
+
+	io[0] = be32_to_cpu(io_text[0]);
+	io[1] = be32_to_cpu(io_text[1]);
+	io[2] = be32_to_cpu(io_text[2]);
+	io[3] = be32_to_cpu(io_text[3]);
+
+	/* pre whitening but absorb kw2*/
+	io[0] ^= CAMELLIA_SUBKEY_L(32);
+	io[1] ^= CAMELLIA_SUBKEY_R(32);
+
+	/* main iteration */
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(31),CAMELLIA_SUBKEY_R(31),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(30),CAMELLIA_SUBKEY_R(30),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(29),CAMELLIA_SUBKEY_R(29),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(28),CAMELLIA_SUBKEY_R(28),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(27),CAMELLIA_SUBKEY_R(27),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(26),CAMELLIA_SUBKEY_R(26),
+			 io[0],io[1],il,ir,t0,t1);
+
+	CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		     CAMELLIA_SUBKEY_L(25),CAMELLIA_SUBKEY_R(25),
+		     CAMELLIA_SUBKEY_L(24),CAMELLIA_SUBKEY_R(24),
+		     t0,t1,il,ir);
+
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18),
+			 io[0],io[1],il,ir,t0,t1);
+
+	CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		     CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17),
+		     CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16),
+		     t0,t1,il,ir);
+
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10),
+			 io[0],io[1],il,ir,t0,t1);
+
+	CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+		     CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9),
+		     CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8),
+		     t0,t1,il,ir);
+
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4),
+			 io[0],io[1],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[0],io[1],
+			 CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3),
+			 io[2],io[3],il,ir,t0,t1);
+	CAMELLIA_ROUNDSM(io[2],io[3],
+			 CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2),
+			 io[0],io[1],il,ir,t0,t1);
+
+	/* post whitening but kw4 */
+	io[2] ^= CAMELLIA_SUBKEY_L(0);
+	io[3] ^= CAMELLIA_SUBKEY_R(0);
+
+	t0 = io[0];
+	t1 = io[1];
+	io[0] = io[2];
+	io[1] = io[3];
+	io[2] = t0;
+	io[3] = t1;
+
+	io_text[0] = cpu_to_be32(io[0]);
+	io_text[1] = cpu_to_be32(io[1]);
+	io_text[2] = cpu_to_be32(io[2]);
+	io_text[3] = cpu_to_be32(io[3]);
+
+	return;
+}
+
+
+static int
+camellia_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+		 unsigned int key_len)
+{
+	struct camellia_ctx *cctx = crypto_tfm_ctx(tfm);
+	const unsigned char *key = (const unsigned char *)in_key;
+	u32 *flags = &tfm->crt_flags;
+
+	if (key_len != 16 && key_len != 24 && key_len != 32) {
+		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		return -EINVAL;
+	}
+
+	cctx->key_length = key_len;
+
+	switch(key_len) {
+	case 16:
+		camellia_setup128(key, cctx->key_table);
+		break;
+	case 24:
+		camellia_setup192(key, cctx->key_table);
+		break;
+	case 32:
+		camellia_setup256(key, cctx->key_table);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+
+static void camellia_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+	const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm);
+	const __be32 *src = (const __be32 *)in;
+	__be32 *dst = (__be32 *)out;
+
+	__be32 tmp[4];
+
+	memcpy(tmp, src, CAMELLIA_BLOCK_SIZE);
+
+	switch (cctx->key_length) {
+	case 16:
+		camellia_encrypt128(cctx->key_table, tmp);
+		break;
+	case 24:
+		/* fall through */
+	case 32:
+		camellia_encrypt256(cctx->key_table, tmp);
+		break;
+	default:
+		break;
+	}
+
+	memcpy(dst, tmp, CAMELLIA_BLOCK_SIZE);
+}
+
+
+static void camellia_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+	const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm);
+	const __be32 *src = (const __be32 *)in;
+	__be32 *dst = (__be32 *)out;
+
+	__be32 tmp[4];
+
+	memcpy(tmp, src, CAMELLIA_BLOCK_SIZE);
+
+	switch (cctx->key_length) {
+	case 16:
+		camellia_decrypt128(cctx->key_table, tmp);
+		break;
+	case 24:
+		/* fall through */
+	case 32:
+		camellia_decrypt256(cctx->key_table, tmp);
+		break;
+	default:
+		break;
+	}
+
+	memcpy(dst, tmp, CAMELLIA_BLOCK_SIZE);
+}
+
+
+static struct crypto_alg camellia_alg = {
+	.cra_name		=	"camellia",
+	.cra_driver_name	=	"camellia-generic",
+	.cra_priority		=	100,
+	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize		=	CAMELLIA_BLOCK_SIZE,
+	.cra_ctxsize		=	sizeof(struct camellia_ctx),
+	.cra_alignmask		=	3,
+	.cra_module		=	THIS_MODULE,
+	.cra_list		=	LIST_HEAD_INIT(camellia_alg.cra_list),
+	.cra_u			=	{
+		.cipher = {
+			.cia_min_keysize	=	CAMELLIA_MIN_KEY_SIZE,
+			.cia_max_keysize	=	CAMELLIA_MAX_KEY_SIZE,
+			.cia_setkey		=	camellia_set_key,
+			.cia_encrypt		=	camellia_encrypt,
+			.cia_decrypt		=	camellia_decrypt
+		}
+	}
+};
+
+static int __init camellia_init(void)
+{
+	return crypto_register_alg(&camellia_alg);
+}
+
+
+static void __exit camellia_fini(void)
+{
+	crypto_unregister_alg(&camellia_alg);
+}
+
+
+module_init(camellia_init);
+module_exit(camellia_fini);
+
+
+MODULE_DESCRIPTION("Camellia Cipher Algorithm");
+MODULE_LICENSE("GPL");
diff --git a/crypto/cbc.c b/crypto/cbc.c
index f5542b4..136fea7 100644
--- a/crypto/cbc.c
+++ b/crypto/cbc.c
@@ -243,6 +243,7 @@
 	struct crypto_instance *inst = (void *)tfm->__crt_alg;
 	struct crypto_spawn *spawn = crypto_instance_ctx(inst);
 	struct crypto_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_cipher *cipher;
 
 	switch (crypto_tfm_alg_blocksize(tfm)) {
 	case 8:
@@ -260,11 +261,11 @@
 			ctx->xor = xor_quad;
 	}
 
-	tfm = crypto_spawn_tfm(spawn);
-	if (IS_ERR(tfm))
-		return PTR_ERR(tfm);
+	cipher = crypto_spawn_cipher(spawn);
+	if (IS_ERR(cipher))
+		return PTR_ERR(cipher);
 
-	ctx->child = crypto_cipher_cast(tfm);
+	ctx->child = cipher;
 	return 0;
 }
 
diff --git a/crypto/cipher.c b/crypto/cipher.c
index 9e03701..333aab2 100644
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -12,274 +12,13 @@
  * any later version.
  *
  */
-#include <linux/compiler.h>
+
 #include <linux/kernel.h>
 #include <linux/crypto.h>
 #include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
+#include <linux/scatterlist.h>
 #include <linux/string.h>
-#include <asm/scatterlist.h>
 #include "internal.h"
-#include "scatterwalk.h"
-
-struct cipher_alg_compat {
-	unsigned int cia_min_keysize;
-	unsigned int cia_max_keysize;
-	int (*cia_setkey)(struct crypto_tfm *tfm, const u8 *key,
-	                  unsigned int keylen);
-	void (*cia_encrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
-	void (*cia_decrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
-
-	unsigned int (*cia_encrypt_ecb)(const struct cipher_desc *desc,
-					u8 *dst, const u8 *src,
-					unsigned int nbytes);
-	unsigned int (*cia_decrypt_ecb)(const struct cipher_desc *desc,
-					u8 *dst, const u8 *src,
-					unsigned int nbytes);
-	unsigned int (*cia_encrypt_cbc)(const struct cipher_desc *desc,
-					u8 *dst, const u8 *src,
-					unsigned int nbytes);
-	unsigned int (*cia_decrypt_cbc)(const struct cipher_desc *desc,
-					u8 *dst, const u8 *src,
-					unsigned int nbytes);
-};
-
-static inline void xor_64(u8 *a, const u8 *b)
-{
-	((u32 *)a)[0] ^= ((u32 *)b)[0];
-	((u32 *)a)[1] ^= ((u32 *)b)[1];
-}
-
-static inline void xor_128(u8 *a, const u8 *b)
-{
-	((u32 *)a)[0] ^= ((u32 *)b)[0];
-	((u32 *)a)[1] ^= ((u32 *)b)[1];
-	((u32 *)a)[2] ^= ((u32 *)b)[2];
-	((u32 *)a)[3] ^= ((u32 *)b)[3];
-}
-
-static unsigned int crypt_slow(const struct cipher_desc *desc,
-			       struct scatter_walk *in,
-			       struct scatter_walk *out, unsigned int bsize)
-{
-	unsigned long alignmask = crypto_tfm_alg_alignmask(desc->tfm);
-	u8 buffer[bsize * 2 + alignmask];
-	u8 *src = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
-	u8 *dst = src + bsize;
-
-	scatterwalk_copychunks(src, in, bsize, 0);
-	desc->prfn(desc, dst, src, bsize);
-	scatterwalk_copychunks(dst, out, bsize, 1);
-
-	return bsize;
-}
-
-static inline unsigned int crypt_fast(const struct cipher_desc *desc,
-				      struct scatter_walk *in,
-				      struct scatter_walk *out,
-				      unsigned int nbytes, u8 *tmp)
-{
-	u8 *src, *dst;
-	u8 *real_src, *real_dst;
-
-	real_src = scatterwalk_map(in, 0);
-	real_dst = scatterwalk_map(out, 1);
-
-	src = real_src;
-	dst = scatterwalk_samebuf(in, out) ? src : real_dst;
-
-	if (tmp) {
-		memcpy(tmp, src, nbytes);
-		src = tmp;
-		dst = tmp;
-	}
-
-	nbytes = desc->prfn(desc, dst, src, nbytes);
-
-	if (tmp)
-		memcpy(real_dst, tmp, nbytes);
-
-	scatterwalk_unmap(real_src, 0);
-	scatterwalk_unmap(real_dst, 1);
-
-	scatterwalk_advance(in, nbytes);
-	scatterwalk_advance(out, nbytes);
-
-	return nbytes;
-}
-
-/* 
- * Generic encrypt/decrypt wrapper for ciphers, handles operations across
- * multiple page boundaries by using temporary blocks.  In user context,
- * the kernel is given a chance to schedule us once per page.
- */
-static int crypt(const struct cipher_desc *desc,
-		 struct scatterlist *dst,
-		 struct scatterlist *src,
-		 unsigned int nbytes)
-{
-	struct scatter_walk walk_in, walk_out;
-	struct crypto_tfm *tfm = desc->tfm;
-	const unsigned int bsize = crypto_tfm_alg_blocksize(tfm);
-	unsigned int alignmask = crypto_tfm_alg_alignmask(tfm);
-	unsigned long buffer = 0;
-
-	if (!nbytes)
-		return 0;
-
-	if (nbytes % bsize) {
-		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
-		return -EINVAL;
-	}
-
-	scatterwalk_start(&walk_in, src);
-	scatterwalk_start(&walk_out, dst);
-
-	for(;;) {
-		unsigned int n = nbytes;
-		u8 *tmp = NULL;
-
-		if (!scatterwalk_aligned(&walk_in, alignmask) ||
-		    !scatterwalk_aligned(&walk_out, alignmask)) {
-			if (!buffer) {
-				buffer = __get_free_page(GFP_ATOMIC);
-				if (!buffer)
-					n = 0;
-			}
-			tmp = (u8 *)buffer;
-		}
-
-		n = scatterwalk_clamp(&walk_in, n);
-		n = scatterwalk_clamp(&walk_out, n);
-
-		if (likely(n >= bsize))
-			n = crypt_fast(desc, &walk_in, &walk_out, n, tmp);
-		else
-			n = crypt_slow(desc, &walk_in, &walk_out, bsize);
-
-		nbytes -= n;
-
-		scatterwalk_done(&walk_in, 0, nbytes);
-		scatterwalk_done(&walk_out, 1, nbytes);
-
-		if (!nbytes)
-			break;
-
-		crypto_yield(tfm->crt_flags);
-	}
-
-	if (buffer)
-		free_page(buffer);
-
-	return 0;
-}
-
-static int crypt_iv_unaligned(struct cipher_desc *desc,
-			      struct scatterlist *dst,
-			      struct scatterlist *src,
-			      unsigned int nbytes)
-{
-	struct crypto_tfm *tfm = desc->tfm;
-	unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
-	u8 *iv = desc->info;
-
-	if (unlikely(((unsigned long)iv & alignmask))) {
-		unsigned int ivsize = tfm->crt_cipher.cit_ivsize;
-		u8 buffer[ivsize + alignmask];
-		u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
-		int err;
-
-		desc->info = memcpy(tmp, iv, ivsize);
-		err = crypt(desc, dst, src, nbytes);
-		memcpy(iv, tmp, ivsize);
-
-		return err;
-	}
-
-	return crypt(desc, dst, src, nbytes);
-}
-
-static unsigned int cbc_process_encrypt(const struct cipher_desc *desc,
-					u8 *dst, const u8 *src,
-					unsigned int nbytes)
-{
-	struct crypto_tfm *tfm = desc->tfm;
-	void (*xor)(u8 *, const u8 *) = tfm->crt_u.cipher.cit_xor_block;
-	int bsize = crypto_tfm_alg_blocksize(tfm);
-
-	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn;
-	u8 *iv = desc->info;
-	unsigned int done = 0;
-
-	nbytes -= bsize;
-
-	do {
-		xor(iv, src);
-		fn(tfm, dst, iv);
-		memcpy(iv, dst, bsize);
-
-		src += bsize;
-		dst += bsize;
-	} while ((done += bsize) <= nbytes);
-
-	return done;
-}
-
-static unsigned int cbc_process_decrypt(const struct cipher_desc *desc,
-					u8 *dst, const u8 *src,
-					unsigned int nbytes)
-{
-	struct crypto_tfm *tfm = desc->tfm;
-	void (*xor)(u8 *, const u8 *) = tfm->crt_u.cipher.cit_xor_block;
-	int bsize = crypto_tfm_alg_blocksize(tfm);
-	unsigned long alignmask = crypto_tfm_alg_alignmask(desc->tfm);
-
-	u8 stack[src == dst ? bsize + alignmask : 0];
-	u8 *buf = (u8 *)ALIGN((unsigned long)stack, alignmask + 1);
-	u8 **dst_p = src == dst ? &buf : &dst;
-
-	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn;
-	u8 *iv = desc->info;
-	unsigned int done = 0;
-
-	nbytes -= bsize;
-
-	do {
-		u8 *tmp_dst = *dst_p;
-
-		fn(tfm, tmp_dst, src);
-		xor(tmp_dst, iv);
-		memcpy(iv, src, bsize);
-		if (tmp_dst != dst)
-			memcpy(dst, tmp_dst, bsize);
-
-		src += bsize;
-		dst += bsize;
-	} while ((done += bsize) <= nbytes);
-
-	return done;
-}
-
-static unsigned int ecb_process(const struct cipher_desc *desc, u8 *dst,
-				const u8 *src, unsigned int nbytes)
-{
-	struct crypto_tfm *tfm = desc->tfm;
-	int bsize = crypto_tfm_alg_blocksize(tfm);
-	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn;
-	unsigned int done = 0;
-
-	nbytes -= bsize;
-
-	do {
-		fn(tfm, dst, src);
-
-		src += bsize;
-		dst += bsize;
-	} while ((done += bsize) <= nbytes);
-
-	return done;
-}
 
 static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
 {
@@ -293,122 +32,6 @@
 		return cia->cia_setkey(tfm, key, keylen);
 }
 
-static int ecb_encrypt(struct crypto_tfm *tfm,
-		       struct scatterlist *dst,
-                       struct scatterlist *src, unsigned int nbytes)
-{
-	struct cipher_desc desc;
-	struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
-
-	desc.tfm = tfm;
-	desc.crfn = cipher->cia_encrypt;
-	desc.prfn = cipher->cia_encrypt_ecb ?: ecb_process;
-
-	return crypt(&desc, dst, src, nbytes);
-}
-
-static int ecb_decrypt(struct crypto_tfm *tfm,
-                       struct scatterlist *dst,
-                       struct scatterlist *src,
-		       unsigned int nbytes)
-{
-	struct cipher_desc desc;
-	struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
-
-	desc.tfm = tfm;
-	desc.crfn = cipher->cia_decrypt;
-	desc.prfn = cipher->cia_decrypt_ecb ?: ecb_process;
-
-	return crypt(&desc, dst, src, nbytes);
-}
-
-static int cbc_encrypt(struct crypto_tfm *tfm,
-                       struct scatterlist *dst,
-                       struct scatterlist *src,
-		       unsigned int nbytes)
-{
-	struct cipher_desc desc;
-	struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
-
-	desc.tfm = tfm;
-	desc.crfn = cipher->cia_encrypt;
-	desc.prfn = cipher->cia_encrypt_cbc ?: cbc_process_encrypt;
-	desc.info = tfm->crt_cipher.cit_iv;
-
-	return crypt(&desc, dst, src, nbytes);
-}
-
-static int cbc_encrypt_iv(struct crypto_tfm *tfm,
-                          struct scatterlist *dst,
-                          struct scatterlist *src,
-                          unsigned int nbytes, u8 *iv)
-{
-	struct cipher_desc desc;
-	struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
-
-	desc.tfm = tfm;
-	desc.crfn = cipher->cia_encrypt;
-	desc.prfn = cipher->cia_encrypt_cbc ?: cbc_process_encrypt;
-	desc.info = iv;
-
-	return crypt_iv_unaligned(&desc, dst, src, nbytes);
-}
-
-static int cbc_decrypt(struct crypto_tfm *tfm,
-                       struct scatterlist *dst,
-                       struct scatterlist *src,
-		       unsigned int nbytes)
-{
-	struct cipher_desc desc;
-	struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
-
-	desc.tfm = tfm;
-	desc.crfn = cipher->cia_decrypt;
-	desc.prfn = cipher->cia_decrypt_cbc ?: cbc_process_decrypt;
-	desc.info = tfm->crt_cipher.cit_iv;
-
-	return crypt(&desc, dst, src, nbytes);
-}
-
-static int cbc_decrypt_iv(struct crypto_tfm *tfm,
-                          struct scatterlist *dst,
-                          struct scatterlist *src,
-                          unsigned int nbytes, u8 *iv)
-{
-	struct cipher_desc desc;
-	struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
-
-	desc.tfm = tfm;
-	desc.crfn = cipher->cia_decrypt;
-	desc.prfn = cipher->cia_decrypt_cbc ?: cbc_process_decrypt;
-	desc.info = iv;
-
-	return crypt_iv_unaligned(&desc, dst, src, nbytes);
-}
-
-static int nocrypt(struct crypto_tfm *tfm,
-                   struct scatterlist *dst,
-                   struct scatterlist *src,
-		   unsigned int nbytes)
-{
-	return -ENOSYS;
-}
-
-static int nocrypt_iv(struct crypto_tfm *tfm,
-                      struct scatterlist *dst,
-                      struct scatterlist *src,
-                      unsigned int nbytes, u8 *iv)
-{
-	return -ENOSYS;
-}
-
-int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags)
-{
-	u32 mode = flags & CRYPTO_TFM_MODE_MASK;
-	tfm->crt_cipher.cit_mode = mode ? mode : CRYPTO_TFM_MODE_ECB;
-	return 0;
-}
-
 static void cipher_crypt_unaligned(void (*fn)(struct crypto_tfm *, u8 *,
 					      const u8 *),
 				   struct crypto_tfm *tfm,
@@ -454,7 +77,6 @@
 
 int crypto_init_cipher_ops(struct crypto_tfm *tfm)
 {
-	int ret = 0;
 	struct cipher_tfm *ops = &tfm->crt_cipher;
 	struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
 
@@ -464,70 +86,7 @@
 	ops->cit_decrypt_one = crypto_tfm_alg_alignmask(tfm) ?
 		cipher_decrypt_unaligned : cipher->cia_decrypt;
 
-	switch (tfm->crt_cipher.cit_mode) {
-	case CRYPTO_TFM_MODE_ECB:
-		ops->cit_encrypt = ecb_encrypt;
-		ops->cit_decrypt = ecb_decrypt;
-		ops->cit_encrypt_iv = nocrypt_iv;
-		ops->cit_decrypt_iv = nocrypt_iv;
-		break;
-		
-	case CRYPTO_TFM_MODE_CBC:
-		ops->cit_encrypt = cbc_encrypt;
-		ops->cit_decrypt = cbc_decrypt;
-		ops->cit_encrypt_iv = cbc_encrypt_iv;
-		ops->cit_decrypt_iv = cbc_decrypt_iv;
-		break;
-		
-	case CRYPTO_TFM_MODE_CFB:
-		ops->cit_encrypt = nocrypt;
-		ops->cit_decrypt = nocrypt;
-		ops->cit_encrypt_iv = nocrypt_iv;
-		ops->cit_decrypt_iv = nocrypt_iv;
-		break;
-	
-	case CRYPTO_TFM_MODE_CTR:
-		ops->cit_encrypt = nocrypt;
-		ops->cit_decrypt = nocrypt;
-		ops->cit_encrypt_iv = nocrypt_iv;
-		ops->cit_decrypt_iv = nocrypt_iv;
-		break;
-
-	default:
-		BUG();
-	}
-	
-	if (ops->cit_mode == CRYPTO_TFM_MODE_CBC) {
-		unsigned long align;
-		unsigned long addr;
-	    	
-	    	switch (crypto_tfm_alg_blocksize(tfm)) {
-	    	case 8:
-	    		ops->cit_xor_block = xor_64;
-	    		break;
-	    		
-	    	case 16:
-	    		ops->cit_xor_block = xor_128;
-	    		break;
-	    		
-	    	default:
-	    		printk(KERN_WARNING "%s: block size %u not supported\n",
-	    		       crypto_tfm_alg_name(tfm),
-	    		       crypto_tfm_alg_blocksize(tfm));
-	    		ret = -EINVAL;
-	    		goto out;
-	    	}
-	    	
-		ops->cit_ivsize = crypto_tfm_alg_blocksize(tfm);
-		align = crypto_tfm_alg_alignmask(tfm) + 1;
-		addr = (unsigned long)crypto_tfm_ctx(tfm);
-		addr = ALIGN(addr, align);
-		addr += ALIGN(tfm->__crt_alg->cra_ctxsize, align);
-		ops->cit_iv = (void *)addr;
-	}
-
-out:	
-	return ret;
+	return 0;
 }
 
 void crypto_exit_cipher_ops(struct crypto_tfm *tfm)
diff --git a/crypto/compress.c b/crypto/compress.c
index eca182a..0a65700 100644
--- a/crypto/compress.c
+++ b/crypto/compress.c
@@ -34,11 +34,6 @@
 	                                                   dlen);
 }
 
-int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags)
-{
-	return flags ? -EINVAL : 0;
-}
-
 int crypto_init_compress_ops(struct crypto_tfm *tfm)
 {
 	struct compress_tfm *ops = &tfm->crt_compress;
diff --git a/crypto/digest.c b/crypto/digest.c
index 8f45932..1bf7414 100644
--- a/crypto/digest.c
+++ b/crypto/digest.c
@@ -14,7 +14,9 @@
 
 #include <linux/mm.h>
 #include <linux/errno.h>
+#include <linux/hardirq.h>
 #include <linux/highmem.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/scatterlist.h>
 
@@ -29,8 +31,8 @@
 	return 0;
 }
 
-static int update(struct hash_desc *desc,
-		  struct scatterlist *sg, unsigned int nbytes)
+static int update2(struct hash_desc *desc,
+		   struct scatterlist *sg, unsigned int nbytes)
 {
 	struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
 	unsigned int alignmask = crypto_tfm_alg_alignmask(tfm);
@@ -81,6 +83,14 @@
 	return 0;
 }
 
+static int update(struct hash_desc *desc,
+		  struct scatterlist *sg, unsigned int nbytes)
+{
+	if (WARN_ON_ONCE(in_irq()))
+		return -EDEADLK;
+	return update2(desc, sg, nbytes);
+}
+
 static int final(struct hash_desc *desc, u8 *out)
 {
 	struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
@@ -118,14 +128,12 @@
 static int digest(struct hash_desc *desc,
 		  struct scatterlist *sg, unsigned int nbytes, u8 *out)
 {
-	init(desc);
-	update(desc, sg, nbytes);
-	return final(desc, out);
-}
+	if (WARN_ON_ONCE(in_irq()))
+		return -EDEADLK;
 
-int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags)
-{
-	return flags ? -EINVAL : 0;
+	init(desc);
+	update2(desc, sg, nbytes);
+	return final(desc, out);
 }
 
 int crypto_init_digest_ops(struct crypto_tfm *tfm)
diff --git a/crypto/ecb.c b/crypto/ecb.c
index f239aa9..839a0ae 100644
--- a/crypto/ecb.c
+++ b/crypto/ecb.c
@@ -99,12 +99,13 @@
 	struct crypto_instance *inst = (void *)tfm->__crt_alg;
 	struct crypto_spawn *spawn = crypto_instance_ctx(inst);
 	struct crypto_ecb_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_cipher *cipher;
 
-	tfm = crypto_spawn_tfm(spawn);
-	if (IS_ERR(tfm))
-		return PTR_ERR(tfm);
+	cipher = crypto_spawn_cipher(spawn);
+	if (IS_ERR(cipher))
+		return PTR_ERR(cipher);
 
-	ctx->child = crypto_cipher_cast(tfm);
+	ctx->child = cipher;
 	return 0;
 }
 
diff --git a/crypto/fcrypt.c b/crypto/fcrypt.c
new file mode 100644
index 0000000..9c2bb53
--- /dev/null
+++ b/crypto/fcrypt.c
@@ -0,0 +1,423 @@
+/* FCrypt encryption algorithm
+ *
+ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Based on code:
+ *
+ * Copyright (c) 1995 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <asm/byteorder.h>
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+
+#define ROUNDS 16
+
+struct fcrypt_ctx {
+	u32 sched[ROUNDS];
+};
+
+/* Rotate right two 32 bit numbers as a 56 bit number */
+#define ror56(hi, lo, n)					\
+do {								\
+	u32 t = lo & ((1 << n) - 1);				\
+	lo = (lo >> n) | ((hi & ((1 << n) - 1)) << (32 - n));	\
+	hi = (hi >> n) | (t << (24-n));				\
+} while(0)
+
+/* Rotate right one 64 bit number as a 56 bit number */
+#define ror56_64(k, n)						\
+do {								\
+	k = (k >> n) | ((k & ((1 << n) - 1)) << (56 - n));	\
+} while(0)
+
+/*
+ * Sboxes for Feistel network derived from
+ * /afs/transarc.com/public/afsps/afs.rel31b.export-src/rxkad/sboxes.h
+ */
+#undef Z
+#define Z(x) __constant_be32_to_cpu(x << 3)
+static const u32 sbox0[256] = {
+	Z(0xea), Z(0x7f), Z(0xb2), Z(0x64), Z(0x9d), Z(0xb0), Z(0xd9), Z(0x11),
+	Z(0xcd), Z(0x86), Z(0x86), Z(0x91), Z(0x0a), Z(0xb2), Z(0x93), Z(0x06),
+	Z(0x0e), Z(0x06), Z(0xd2), Z(0x65), Z(0x73), Z(0xc5), Z(0x28), Z(0x60),
+	Z(0xf2), Z(0x20), Z(0xb5), Z(0x38), Z(0x7e), Z(0xda), Z(0x9f), Z(0xe3),
+	Z(0xd2), Z(0xcf), Z(0xc4), Z(0x3c), Z(0x61), Z(0xff), Z(0x4a), Z(0x4a),
+	Z(0x35), Z(0xac), Z(0xaa), Z(0x5f), Z(0x2b), Z(0xbb), Z(0xbc), Z(0x53),
+	Z(0x4e), Z(0x9d), Z(0x78), Z(0xa3), Z(0xdc), Z(0x09), Z(0x32), Z(0x10),
+	Z(0xc6), Z(0x6f), Z(0x66), Z(0xd6), Z(0xab), Z(0xa9), Z(0xaf), Z(0xfd),
+	Z(0x3b), Z(0x95), Z(0xe8), Z(0x34), Z(0x9a), Z(0x81), Z(0x72), Z(0x80),
+	Z(0x9c), Z(0xf3), Z(0xec), Z(0xda), Z(0x9f), Z(0x26), Z(0x76), Z(0x15),
+	Z(0x3e), Z(0x55), Z(0x4d), Z(0xde), Z(0x84), Z(0xee), Z(0xad), Z(0xc7),
+	Z(0xf1), Z(0x6b), Z(0x3d), Z(0xd3), Z(0x04), Z(0x49), Z(0xaa), Z(0x24),
+	Z(0x0b), Z(0x8a), Z(0x83), Z(0xba), Z(0xfa), Z(0x85), Z(0xa0), Z(0xa8),
+	Z(0xb1), Z(0xd4), Z(0x01), Z(0xd8), Z(0x70), Z(0x64), Z(0xf0), Z(0x51),
+	Z(0xd2), Z(0xc3), Z(0xa7), Z(0x75), Z(0x8c), Z(0xa5), Z(0x64), Z(0xef),
+	Z(0x10), Z(0x4e), Z(0xb7), Z(0xc6), Z(0x61), Z(0x03), Z(0xeb), Z(0x44),
+	Z(0x3d), Z(0xe5), Z(0xb3), Z(0x5b), Z(0xae), Z(0xd5), Z(0xad), Z(0x1d),
+	Z(0xfa), Z(0x5a), Z(0x1e), Z(0x33), Z(0xab), Z(0x93), Z(0xa2), Z(0xb7),
+	Z(0xe7), Z(0xa8), Z(0x45), Z(0xa4), Z(0xcd), Z(0x29), Z(0x63), Z(0x44),
+	Z(0xb6), Z(0x69), Z(0x7e), Z(0x2e), Z(0x62), Z(0x03), Z(0xc8), Z(0xe0),
+	Z(0x17), Z(0xbb), Z(0xc7), Z(0xf3), Z(0x3f), Z(0x36), Z(0xba), Z(0x71),
+	Z(0x8e), Z(0x97), Z(0x65), Z(0x60), Z(0x69), Z(0xb6), Z(0xf6), Z(0xe6),
+	Z(0x6e), Z(0xe0), Z(0x81), Z(0x59), Z(0xe8), Z(0xaf), Z(0xdd), Z(0x95),
+	Z(0x22), Z(0x99), Z(0xfd), Z(0x63), Z(0x19), Z(0x74), Z(0x61), Z(0xb1),
+	Z(0xb6), Z(0x5b), Z(0xae), Z(0x54), Z(0xb3), Z(0x70), Z(0xff), Z(0xc6),
+	Z(0x3b), Z(0x3e), Z(0xc1), Z(0xd7), Z(0xe1), Z(0x0e), Z(0x76), Z(0xe5),
+	Z(0x36), Z(0x4f), Z(0x59), Z(0xc7), Z(0x08), Z(0x6e), Z(0x82), Z(0xa6),
+	Z(0x93), Z(0xc4), Z(0xaa), Z(0x26), Z(0x49), Z(0xe0), Z(0x21), Z(0x64),
+	Z(0x07), Z(0x9f), Z(0x64), Z(0x81), Z(0x9c), Z(0xbf), Z(0xf9), Z(0xd1),
+	Z(0x43), Z(0xf8), Z(0xb6), Z(0xb9), Z(0xf1), Z(0x24), Z(0x75), Z(0x03),
+	Z(0xe4), Z(0xb0), Z(0x99), Z(0x46), Z(0x3d), Z(0xf5), Z(0xd1), Z(0x39),
+	Z(0x72), Z(0x12), Z(0xf6), Z(0xba), Z(0x0c), Z(0x0d), Z(0x42), Z(0x2e)
+};
+
+#undef Z
+#define Z(x) __constant_be32_to_cpu((x << 27) | (x >> 5))
+static const u32 sbox1[256] = {
+	Z(0x77), Z(0x14), Z(0xa6), Z(0xfe), Z(0xb2), Z(0x5e), Z(0x8c), Z(0x3e),
+	Z(0x67), Z(0x6c), Z(0xa1), Z(0x0d), Z(0xc2), Z(0xa2), Z(0xc1), Z(0x85),
+	Z(0x6c), Z(0x7b), Z(0x67), Z(0xc6), Z(0x23), Z(0xe3), Z(0xf2), Z(0x89),
+	Z(0x50), Z(0x9c), Z(0x03), Z(0xb7), Z(0x73), Z(0xe6), Z(0xe1), Z(0x39),
+	Z(0x31), Z(0x2c), Z(0x27), Z(0x9f), Z(0xa5), Z(0x69), Z(0x44), Z(0xd6),
+	Z(0x23), Z(0x83), Z(0x98), Z(0x7d), Z(0x3c), Z(0xb4), Z(0x2d), Z(0x99),
+	Z(0x1c), Z(0x1f), Z(0x8c), Z(0x20), Z(0x03), Z(0x7c), Z(0x5f), Z(0xad),
+	Z(0xf4), Z(0xfa), Z(0x95), Z(0xca), Z(0x76), Z(0x44), Z(0xcd), Z(0xb6),
+	Z(0xb8), Z(0xa1), Z(0xa1), Z(0xbe), Z(0x9e), Z(0x54), Z(0x8f), Z(0x0b),
+	Z(0x16), Z(0x74), Z(0x31), Z(0x8a), Z(0x23), Z(0x17), Z(0x04), Z(0xfa),
+	Z(0x79), Z(0x84), Z(0xb1), Z(0xf5), Z(0x13), Z(0xab), Z(0xb5), Z(0x2e),
+	Z(0xaa), Z(0x0c), Z(0x60), Z(0x6b), Z(0x5b), Z(0xc4), Z(0x4b), Z(0xbc),
+	Z(0xe2), Z(0xaf), Z(0x45), Z(0x73), Z(0xfa), Z(0xc9), Z(0x49), Z(0xcd),
+	Z(0x00), Z(0x92), Z(0x7d), Z(0x97), Z(0x7a), Z(0x18), Z(0x60), Z(0x3d),
+	Z(0xcf), Z(0x5b), Z(0xde), Z(0xc6), Z(0xe2), Z(0xe6), Z(0xbb), Z(0x8b),
+	Z(0x06), Z(0xda), Z(0x08), Z(0x15), Z(0x1b), Z(0x88), Z(0x6a), Z(0x17),
+	Z(0x89), Z(0xd0), Z(0xa9), Z(0xc1), Z(0xc9), Z(0x70), Z(0x6b), Z(0xe5),
+	Z(0x43), Z(0xf4), Z(0x68), Z(0xc8), Z(0xd3), Z(0x84), Z(0x28), Z(0x0a),
+	Z(0x52), Z(0x66), Z(0xa3), Z(0xca), Z(0xf2), Z(0xe3), Z(0x7f), Z(0x7a),
+	Z(0x31), Z(0xf7), Z(0x88), Z(0x94), Z(0x5e), Z(0x9c), Z(0x63), Z(0xd5),
+	Z(0x24), Z(0x66), Z(0xfc), Z(0xb3), Z(0x57), Z(0x25), Z(0xbe), Z(0x89),
+	Z(0x44), Z(0xc4), Z(0xe0), Z(0x8f), Z(0x23), Z(0x3c), Z(0x12), Z(0x52),
+	Z(0xf5), Z(0x1e), Z(0xf4), Z(0xcb), Z(0x18), Z(0x33), Z(0x1f), Z(0xf8),
+	Z(0x69), Z(0x10), Z(0x9d), Z(0xd3), Z(0xf7), Z(0x28), Z(0xf8), Z(0x30),
+	Z(0x05), Z(0x5e), Z(0x32), Z(0xc0), Z(0xd5), Z(0x19), Z(0xbd), Z(0x45),
+	Z(0x8b), Z(0x5b), Z(0xfd), Z(0xbc), Z(0xe2), Z(0x5c), Z(0xa9), Z(0x96),
+	Z(0xef), Z(0x70), Z(0xcf), Z(0xc2), Z(0x2a), Z(0xb3), Z(0x61), Z(0xad),
+	Z(0x80), Z(0x48), Z(0x81), Z(0xb7), Z(0x1d), Z(0x43), Z(0xd9), Z(0xd7),
+	Z(0x45), Z(0xf0), Z(0xd8), Z(0x8a), Z(0x59), Z(0x7c), Z(0x57), Z(0xc1),
+	Z(0x79), Z(0xc7), Z(0x34), Z(0xd6), Z(0x43), Z(0xdf), Z(0xe4), Z(0x78),
+	Z(0x16), Z(0x06), Z(0xda), Z(0x92), Z(0x76), Z(0x51), Z(0xe1), Z(0xd4),
+	Z(0x70), Z(0x03), Z(0xe0), Z(0x2f), Z(0x96), Z(0x91), Z(0x82), Z(0x80)
+};
+
+#undef Z
+#define Z(x) __constant_be32_to_cpu(x << 11)
+static const u32 sbox2[256] = {
+	Z(0xf0), Z(0x37), Z(0x24), Z(0x53), Z(0x2a), Z(0x03), Z(0x83), Z(0x86),
+	Z(0xd1), Z(0xec), Z(0x50), Z(0xf0), Z(0x42), Z(0x78), Z(0x2f), Z(0x6d),
+	Z(0xbf), Z(0x80), Z(0x87), Z(0x27), Z(0x95), Z(0xe2), Z(0xc5), Z(0x5d),
+	Z(0xf9), Z(0x6f), Z(0xdb), Z(0xb4), Z(0x65), Z(0x6e), Z(0xe7), Z(0x24),
+	Z(0xc8), Z(0x1a), Z(0xbb), Z(0x49), Z(0xb5), Z(0x0a), Z(0x7d), Z(0xb9),
+	Z(0xe8), Z(0xdc), Z(0xb7), Z(0xd9), Z(0x45), Z(0x20), Z(0x1b), Z(0xce),
+	Z(0x59), Z(0x9d), Z(0x6b), Z(0xbd), Z(0x0e), Z(0x8f), Z(0xa3), Z(0xa9),
+	Z(0xbc), Z(0x74), Z(0xa6), Z(0xf6), Z(0x7f), Z(0x5f), Z(0xb1), Z(0x68),
+	Z(0x84), Z(0xbc), Z(0xa9), Z(0xfd), Z(0x55), Z(0x50), Z(0xe9), Z(0xb6),
+	Z(0x13), Z(0x5e), Z(0x07), Z(0xb8), Z(0x95), Z(0x02), Z(0xc0), Z(0xd0),
+	Z(0x6a), Z(0x1a), Z(0x85), Z(0xbd), Z(0xb6), Z(0xfd), Z(0xfe), Z(0x17),
+	Z(0x3f), Z(0x09), Z(0xa3), Z(0x8d), Z(0xfb), Z(0xed), Z(0xda), Z(0x1d),
+	Z(0x6d), Z(0x1c), Z(0x6c), Z(0x01), Z(0x5a), Z(0xe5), Z(0x71), Z(0x3e),
+	Z(0x8b), Z(0x6b), Z(0xbe), Z(0x29), Z(0xeb), Z(0x12), Z(0x19), Z(0x34),
+	Z(0xcd), Z(0xb3), Z(0xbd), Z(0x35), Z(0xea), Z(0x4b), Z(0xd5), Z(0xae),
+	Z(0x2a), Z(0x79), Z(0x5a), Z(0xa5), Z(0x32), Z(0x12), Z(0x7b), Z(0xdc),
+	Z(0x2c), Z(0xd0), Z(0x22), Z(0x4b), Z(0xb1), Z(0x85), Z(0x59), Z(0x80),
+	Z(0xc0), Z(0x30), Z(0x9f), Z(0x73), Z(0xd3), Z(0x14), Z(0x48), Z(0x40),
+	Z(0x07), Z(0x2d), Z(0x8f), Z(0x80), Z(0x0f), Z(0xce), Z(0x0b), Z(0x5e),
+	Z(0xb7), Z(0x5e), Z(0xac), Z(0x24), Z(0x94), Z(0x4a), Z(0x18), Z(0x15),
+	Z(0x05), Z(0xe8), Z(0x02), Z(0x77), Z(0xa9), Z(0xc7), Z(0x40), Z(0x45),
+	Z(0x89), Z(0xd1), Z(0xea), Z(0xde), Z(0x0c), Z(0x79), Z(0x2a), Z(0x99),
+	Z(0x6c), Z(0x3e), Z(0x95), Z(0xdd), Z(0x8c), Z(0x7d), Z(0xad), Z(0x6f),
+	Z(0xdc), Z(0xff), Z(0xfd), Z(0x62), Z(0x47), Z(0xb3), Z(0x21), Z(0x8a),
+	Z(0xec), Z(0x8e), Z(0x19), Z(0x18), Z(0xb4), Z(0x6e), Z(0x3d), Z(0xfd),
+	Z(0x74), Z(0x54), Z(0x1e), Z(0x04), Z(0x85), Z(0xd8), Z(0xbc), Z(0x1f),
+	Z(0x56), Z(0xe7), Z(0x3a), Z(0x56), Z(0x67), Z(0xd6), Z(0xc8), Z(0xa5),
+	Z(0xf3), Z(0x8e), Z(0xde), Z(0xae), Z(0x37), Z(0x49), Z(0xb7), Z(0xfa),
+	Z(0xc8), Z(0xf4), Z(0x1f), Z(0xe0), Z(0x2a), Z(0x9b), Z(0x15), Z(0xd1),
+	Z(0x34), Z(0x0e), Z(0xb5), Z(0xe0), Z(0x44), Z(0x78), Z(0x84), Z(0x59),
+	Z(0x56), Z(0x68), Z(0x77), Z(0xa5), Z(0x14), Z(0x06), Z(0xf5), Z(0x2f),
+	Z(0x8c), Z(0x8a), Z(0x73), Z(0x80), Z(0x76), Z(0xb4), Z(0x10), Z(0x86)
+};
+
+#undef Z
+#define Z(x) __constant_be32_to_cpu(x << 19)
+static const u32 sbox3[256] = {
+	Z(0xa9), Z(0x2a), Z(0x48), Z(0x51), Z(0x84), Z(0x7e), Z(0x49), Z(0xe2),
+	Z(0xb5), Z(0xb7), Z(0x42), Z(0x33), Z(0x7d), Z(0x5d), Z(0xa6), Z(0x12),
+	Z(0x44), Z(0x48), Z(0x6d), Z(0x28), Z(0xaa), Z(0x20), Z(0x6d), Z(0x57),
+	Z(0xd6), Z(0x6b), Z(0x5d), Z(0x72), Z(0xf0), Z(0x92), Z(0x5a), Z(0x1b),
+	Z(0x53), Z(0x80), Z(0x24), Z(0x70), Z(0x9a), Z(0xcc), Z(0xa7), Z(0x66),
+	Z(0xa1), Z(0x01), Z(0xa5), Z(0x41), Z(0x97), Z(0x41), Z(0x31), Z(0x82),
+	Z(0xf1), Z(0x14), Z(0xcf), Z(0x53), Z(0x0d), Z(0xa0), Z(0x10), Z(0xcc),
+	Z(0x2a), Z(0x7d), Z(0xd2), Z(0xbf), Z(0x4b), Z(0x1a), Z(0xdb), Z(0x16),
+	Z(0x47), Z(0xf6), Z(0x51), Z(0x36), Z(0xed), Z(0xf3), Z(0xb9), Z(0x1a),
+	Z(0xa7), Z(0xdf), Z(0x29), Z(0x43), Z(0x01), Z(0x54), Z(0x70), Z(0xa4),
+	Z(0xbf), Z(0xd4), Z(0x0b), Z(0x53), Z(0x44), Z(0x60), Z(0x9e), Z(0x23),
+	Z(0xa1), Z(0x18), Z(0x68), Z(0x4f), Z(0xf0), Z(0x2f), Z(0x82), Z(0xc2),
+	Z(0x2a), Z(0x41), Z(0xb2), Z(0x42), Z(0x0c), Z(0xed), Z(0x0c), Z(0x1d),
+	Z(0x13), Z(0x3a), Z(0x3c), Z(0x6e), Z(0x35), Z(0xdc), Z(0x60), Z(0x65),
+	Z(0x85), Z(0xe9), Z(0x64), Z(0x02), Z(0x9a), Z(0x3f), Z(0x9f), Z(0x87),
+	Z(0x96), Z(0xdf), Z(0xbe), Z(0xf2), Z(0xcb), Z(0xe5), Z(0x6c), Z(0xd4),
+	Z(0x5a), Z(0x83), Z(0xbf), Z(0x92), Z(0x1b), Z(0x94), Z(0x00), Z(0x42),
+	Z(0xcf), Z(0x4b), Z(0x00), Z(0x75), Z(0xba), Z(0x8f), Z(0x76), Z(0x5f),
+	Z(0x5d), Z(0x3a), Z(0x4d), Z(0x09), Z(0x12), Z(0x08), Z(0x38), Z(0x95),
+	Z(0x17), Z(0xe4), Z(0x01), Z(0x1d), Z(0x4c), Z(0xa9), Z(0xcc), Z(0x85),
+	Z(0x82), Z(0x4c), Z(0x9d), Z(0x2f), Z(0x3b), Z(0x66), Z(0xa1), Z(0x34),
+	Z(0x10), Z(0xcd), Z(0x59), Z(0x89), Z(0xa5), Z(0x31), Z(0xcf), Z(0x05),
+	Z(0xc8), Z(0x84), Z(0xfa), Z(0xc7), Z(0xba), Z(0x4e), Z(0x8b), Z(0x1a),
+	Z(0x19), Z(0xf1), Z(0xa1), Z(0x3b), Z(0x18), Z(0x12), Z(0x17), Z(0xb0),
+	Z(0x98), Z(0x8d), Z(0x0b), Z(0x23), Z(0xc3), Z(0x3a), Z(0x2d), Z(0x20),
+	Z(0xdf), Z(0x13), Z(0xa0), Z(0xa8), Z(0x4c), Z(0x0d), Z(0x6c), Z(0x2f),
+	Z(0x47), Z(0x13), Z(0x13), Z(0x52), Z(0x1f), Z(0x2d), Z(0xf5), Z(0x79),
+	Z(0x3d), Z(0xa2), Z(0x54), Z(0xbd), Z(0x69), Z(0xc8), Z(0x6b), Z(0xf3),
+	Z(0x05), Z(0x28), Z(0xf1), Z(0x16), Z(0x46), Z(0x40), Z(0xb0), Z(0x11),
+	Z(0xd3), Z(0xb7), Z(0x95), Z(0x49), Z(0xcf), Z(0xc3), Z(0x1d), Z(0x8f),
+	Z(0xd8), Z(0xe1), Z(0x73), Z(0xdb), Z(0xad), Z(0xc8), Z(0xc9), Z(0xa9),
+	Z(0xa1), Z(0xc2), Z(0xc5), Z(0xe3), Z(0xba), Z(0xfc), Z(0x0e), Z(0x25)
+};
+
+/*
+ * This is a 16 round Feistel network with permutation F_ENCRYPT
+ */
+#define F_ENCRYPT(R, L, sched)						\
+do {									\
+	union lc4 { u32 l; u8 c[4]; } u;				\
+	u.l = sched ^ R;						\
+	L ^= sbox0[u.c[0]] ^ sbox1[u.c[1]] ^ sbox2[u.c[2]] ^ sbox3[u.c[3]]; \
+} while(0)
+
+/*
+ * encryptor
+ */
+static void fcrypt_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+	const struct fcrypt_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct {
+		u32 l, r;
+	} X;
+
+	memcpy(&X, src, sizeof(X));
+
+	F_ENCRYPT(X.r, X.l, ctx->sched[0x0]);
+	F_ENCRYPT(X.l, X.r, ctx->sched[0x1]);
+	F_ENCRYPT(X.r, X.l, ctx->sched[0x2]);
+	F_ENCRYPT(X.l, X.r, ctx->sched[0x3]);
+	F_ENCRYPT(X.r, X.l, ctx->sched[0x4]);
+	F_ENCRYPT(X.l, X.r, ctx->sched[0x5]);
+	F_ENCRYPT(X.r, X.l, ctx->sched[0x6]);
+	F_ENCRYPT(X.l, X.r, ctx->sched[0x7]);
+	F_ENCRYPT(X.r, X.l, ctx->sched[0x8]);
+	F_ENCRYPT(X.l, X.r, ctx->sched[0x9]);
+	F_ENCRYPT(X.r, X.l, ctx->sched[0xa]);
+	F_ENCRYPT(X.l, X.r, ctx->sched[0xb]);
+	F_ENCRYPT(X.r, X.l, ctx->sched[0xc]);
+	F_ENCRYPT(X.l, X.r, ctx->sched[0xd]);
+	F_ENCRYPT(X.r, X.l, ctx->sched[0xe]);
+	F_ENCRYPT(X.l, X.r, ctx->sched[0xf]);
+
+	memcpy(dst, &X, sizeof(X));
+}
+
+/*
+ * decryptor
+ */
+static void fcrypt_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+	const struct fcrypt_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct {
+		u32 l, r;
+	} X;
+
+	memcpy(&X, src, sizeof(X));
+
+	F_ENCRYPT(X.l, X.r, ctx->sched[0xf]);
+	F_ENCRYPT(X.r, X.l, ctx->sched[0xe]);
+	F_ENCRYPT(X.l, X.r, ctx->sched[0xd]);
+	F_ENCRYPT(X.r, X.l, ctx->sched[0xc]);
+	F_ENCRYPT(X.l, X.r, ctx->sched[0xb]);
+	F_ENCRYPT(X.r, X.l, ctx->sched[0xa]);
+	F_ENCRYPT(X.l, X.r, ctx->sched[0x9]);
+	F_ENCRYPT(X.r, X.l, ctx->sched[0x8]);
+	F_ENCRYPT(X.l, X.r, ctx->sched[0x7]);
+	F_ENCRYPT(X.r, X.l, ctx->sched[0x6]);
+	F_ENCRYPT(X.l, X.r, ctx->sched[0x5]);
+	F_ENCRYPT(X.r, X.l, ctx->sched[0x4]);
+	F_ENCRYPT(X.l, X.r, ctx->sched[0x3]);
+	F_ENCRYPT(X.r, X.l, ctx->sched[0x2]);
+	F_ENCRYPT(X.l, X.r, ctx->sched[0x1]);
+	F_ENCRYPT(X.r, X.l, ctx->sched[0x0]);
+
+	memcpy(dst, &X, sizeof(X));
+}
+
+/*
+ * Generate a key schedule from key, the least significant bit in each key byte
+ * is parity and shall be ignored. This leaves 56 significant bits in the key
+ * to scatter over the 16 key schedules. For each schedule extract the low
+ * order 32 bits and use as schedule, then rotate right by 11 bits.
+ */
+static int fcrypt_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
+{
+	struct fcrypt_ctx *ctx = crypto_tfm_ctx(tfm);
+
+#if BITS_PER_LONG == 64  /* the 64-bit version can also be used for 32-bit
+			  * kernels - it seems to be faster but the code is
+			  * larger */
+
+	u64 k;	/* k holds all 56 non-parity bits */
+
+	/* discard the parity bits */
+	k = (*key++) >> 1;
+	k <<= 7;
+	k |= (*key++) >> 1;
+	k <<= 7;
+	k |= (*key++) >> 1;
+	k <<= 7;
+	k |= (*key++) >> 1;
+	k <<= 7;
+	k |= (*key++) >> 1;
+	k <<= 7;
+	k |= (*key++) >> 1;
+	k <<= 7;
+	k |= (*key++) >> 1;
+	k <<= 7;
+	k |= (*key) >> 1;
+
+	/* Use lower 32 bits for schedule, rotate by 11 each round (16 times) */
+	ctx->sched[0x0] = be32_to_cpu(k); ror56_64(k, 11);
+	ctx->sched[0x1] = be32_to_cpu(k); ror56_64(k, 11);
+	ctx->sched[0x2] = be32_to_cpu(k); ror56_64(k, 11);
+	ctx->sched[0x3] = be32_to_cpu(k); ror56_64(k, 11);
+	ctx->sched[0x4] = be32_to_cpu(k); ror56_64(k, 11);
+	ctx->sched[0x5] = be32_to_cpu(k); ror56_64(k, 11);
+	ctx->sched[0x6] = be32_to_cpu(k); ror56_64(k, 11);
+	ctx->sched[0x7] = be32_to_cpu(k); ror56_64(k, 11);
+	ctx->sched[0x8] = be32_to_cpu(k); ror56_64(k, 11);
+	ctx->sched[0x9] = be32_to_cpu(k); ror56_64(k, 11);
+	ctx->sched[0xa] = be32_to_cpu(k); ror56_64(k, 11);
+	ctx->sched[0xb] = be32_to_cpu(k); ror56_64(k, 11);
+	ctx->sched[0xc] = be32_to_cpu(k); ror56_64(k, 11);
+	ctx->sched[0xd] = be32_to_cpu(k); ror56_64(k, 11);
+	ctx->sched[0xe] = be32_to_cpu(k); ror56_64(k, 11);
+	ctx->sched[0xf] = be32_to_cpu(k);
+
+	return 0;
+#else
+	u32 hi, lo;		/* hi is upper 24 bits and lo lower 32, total 56 */
+
+	/* discard the parity bits */
+	lo = (*key++) >> 1;
+	lo <<= 7;
+	lo |= (*key++) >> 1;
+	lo <<= 7;
+	lo |= (*key++) >> 1;
+	lo <<= 7;
+	lo |= (*key++) >> 1;
+	hi = lo >> 4;
+	lo &= 0xf;
+	lo <<= 7;
+	lo |= (*key++) >> 1;
+	lo <<= 7;
+	lo |= (*key++) >> 1;
+	lo <<= 7;
+	lo |= (*key++) >> 1;
+	lo <<= 7;
+	lo |= (*key) >> 1;
+
+	/* Use lower 32 bits for schedule, rotate by 11 each round (16 times) */
+	ctx->sched[0x0] = be32_to_cpu(lo); ror56(hi, lo, 11);
+	ctx->sched[0x1] = be32_to_cpu(lo); ror56(hi, lo, 11);
+	ctx->sched[0x2] = be32_to_cpu(lo); ror56(hi, lo, 11);
+	ctx->sched[0x3] = be32_to_cpu(lo); ror56(hi, lo, 11);
+	ctx->sched[0x4] = be32_to_cpu(lo); ror56(hi, lo, 11);
+	ctx->sched[0x5] = be32_to_cpu(lo); ror56(hi, lo, 11);
+	ctx->sched[0x6] = be32_to_cpu(lo); ror56(hi, lo, 11);
+	ctx->sched[0x7] = be32_to_cpu(lo); ror56(hi, lo, 11);
+	ctx->sched[0x8] = be32_to_cpu(lo); ror56(hi, lo, 11);
+	ctx->sched[0x9] = be32_to_cpu(lo); ror56(hi, lo, 11);
+	ctx->sched[0xa] = be32_to_cpu(lo); ror56(hi, lo, 11);
+	ctx->sched[0xb] = be32_to_cpu(lo); ror56(hi, lo, 11);
+	ctx->sched[0xc] = be32_to_cpu(lo); ror56(hi, lo, 11);
+	ctx->sched[0xd] = be32_to_cpu(lo); ror56(hi, lo, 11);
+	ctx->sched[0xe] = be32_to_cpu(lo); ror56(hi, lo, 11);
+	ctx->sched[0xf] = be32_to_cpu(lo);
+	return 0;
+#endif
+}
+
+static struct crypto_alg fcrypt_alg = {
+	.cra_name		=	"fcrypt",
+	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize		=	8,
+	.cra_ctxsize		=	sizeof(struct fcrypt_ctx),
+	.cra_module		=	THIS_MODULE,
+	.cra_alignmask		=	3,
+	.cra_list		=	LIST_HEAD_INIT(fcrypt_alg.cra_list),
+	.cra_u			=	{ .cipher = {
+	.cia_min_keysize	=	8,
+	.cia_max_keysize	=	8,
+	.cia_setkey		=	fcrypt_setkey,
+	.cia_encrypt		=	fcrypt_encrypt,
+	.cia_decrypt		=	fcrypt_decrypt } }
+};
+
+static int __init init(void)
+{
+	return crypto_register_alg(&fcrypt_alg);
+}
+
+static void __exit fini(void)
+{
+	crypto_unregister_alg(&fcrypt_alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("FCrypt Cipher Algorithm");
+MODULE_AUTHOR("David Howells <dhowells@redhat.com>");
diff --git a/crypto/hash.c b/crypto/hash.c
index cdec23d..12c4514 100644
--- a/crypto/hash.c
+++ b/crypto/hash.c
@@ -16,12 +16,13 @@
 
 #include "internal.h"
 
-static unsigned int crypto_hash_ctxsize(struct crypto_alg *alg)
+static unsigned int crypto_hash_ctxsize(struct crypto_alg *alg, u32 type,
+					u32 mask)
 {
 	return alg->cra_ctxsize;
 }
 
-static int crypto_init_hash_ops(struct crypto_tfm *tfm)
+static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
 {
 	struct hash_tfm *crt = &tfm->crt_hash;
 	struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
diff --git a/crypto/hmac.c b/crypto/hmac.c
index b521bcd..44187c5 100644
--- a/crypto/hmac.c
+++ b/crypto/hmac.c
@@ -172,15 +172,16 @@
 
 static int hmac_init_tfm(struct crypto_tfm *tfm)
 {
+	struct crypto_hash *hash;
 	struct crypto_instance *inst = (void *)tfm->__crt_alg;
 	struct crypto_spawn *spawn = crypto_instance_ctx(inst);
 	struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm));
 
-	tfm = crypto_spawn_tfm(spawn);
-	if (IS_ERR(tfm))
-		return PTR_ERR(tfm);
+	hash = crypto_spawn_hash(spawn);
+	if (IS_ERR(hash))
+		return PTR_ERR(hash);
 
-	ctx->child = crypto_hash_cast(tfm);
+	ctx->child = hash;
 	return 0;
 }
 
diff --git a/crypto/internal.h b/crypto/internal.h
index 2da6ad4..60acad9 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -83,8 +83,7 @@
 { }
 #endif
 
-static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg,
-						 int flags)
+static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg)
 {
 	unsigned int len = alg->cra_ctxsize;
 
@@ -96,23 +95,12 @@
 	return len;
 }
 
-static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg,
-						 int flags)
+static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg)
 {
-	unsigned int len = alg->cra_ctxsize;
-	
-	switch (flags & CRYPTO_TFM_MODE_MASK) {
-	case CRYPTO_TFM_MODE_CBC:
-		len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1);
-		len += alg->cra_blocksize;
-		break;
-	}
-
-	return len;
+	return alg->cra_ctxsize;
 }
 
-static inline unsigned int crypto_compress_ctxsize(struct crypto_alg *alg,
-						   int flags)
+static inline unsigned int crypto_compress_ctxsize(struct crypto_alg *alg)
 {
 	return alg->cra_ctxsize;
 }
@@ -121,10 +109,6 @@
 struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, u32 mask);
 struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask);
 
-int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags);
-int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags);
-int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags);
-
 int crypto_init_digest_ops(struct crypto_tfm *tfm);
 int crypto_init_cipher_ops(struct crypto_tfm *tfm);
 int crypto_init_compress_ops(struct crypto_tfm *tfm);
@@ -136,7 +120,8 @@
 void crypto_larval_error(const char *name, u32 type, u32 mask);
 
 void crypto_shoot_alg(struct crypto_alg *alg);
-struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags);
+struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
+				      u32 mask);
 
 int crypto_register_instance(struct crypto_template *tmpl,
 			     struct crypto_instance *inst);
diff --git a/crypto/lrw.c b/crypto/lrw.c
index 5664258..b410508 100644
--- a/crypto/lrw.c
+++ b/crypto/lrw.c
@@ -201,21 +201,22 @@
 
 static int init_tfm(struct crypto_tfm *tfm)
 {
+	struct crypto_cipher *cipher;
 	struct crypto_instance *inst = (void *)tfm->__crt_alg;
 	struct crypto_spawn *spawn = crypto_instance_ctx(inst);
 	struct priv *ctx = crypto_tfm_ctx(tfm);
 	u32 *flags = &tfm->crt_flags;
 
-	tfm = crypto_spawn_tfm(spawn);
-	if (IS_ERR(tfm))
-		return PTR_ERR(tfm);
+	cipher = crypto_spawn_cipher(spawn);
+	if (IS_ERR(cipher))
+		return PTR_ERR(cipher);
 
-	if (crypto_tfm_alg_blocksize(tfm) != 16) {
+	if (crypto_cipher_blocksize(cipher) != 16) {
 		*flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
 		return -EINVAL;
 	}
 
-	ctx->child = crypto_cipher_cast(tfm);
+	ctx->child = cipher;
 	return 0;
 }
 
diff --git a/crypto/pcbc.c b/crypto/pcbc.c
new file mode 100644
index 0000000..5174d7f
--- /dev/null
+++ b/crypto/pcbc.c
@@ -0,0 +1,349 @@
+/*
+ * PCBC: Propagating Cipher Block Chaining mode
+ *
+ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * Derived from cbc.c
+ * - Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#include <crypto/algapi.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+
+struct crypto_pcbc_ctx {
+	struct crypto_cipher *child;
+	void (*xor)(u8 *dst, const u8 *src, unsigned int bs);
+};
+
+static int crypto_pcbc_setkey(struct crypto_tfm *parent, const u8 *key,
+			      unsigned int keylen)
+{
+	struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(parent);
+	struct crypto_cipher *child = ctx->child;
+	int err;
+
+	crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+	crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
+				CRYPTO_TFM_REQ_MASK);
+	err = crypto_cipher_setkey(child, key, keylen);
+	crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
+			     CRYPTO_TFM_RES_MASK);
+	return err;
+}
+
+static int crypto_pcbc_encrypt_segment(struct blkcipher_desc *desc,
+				       struct blkcipher_walk *walk,
+				       struct crypto_cipher *tfm,
+				       void (*xor)(u8 *, const u8 *,
+						   unsigned int))
+{
+	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
+		crypto_cipher_alg(tfm)->cia_encrypt;
+	int bsize = crypto_cipher_blocksize(tfm);
+	unsigned int nbytes = walk->nbytes;
+	u8 *src = walk->src.virt.addr;
+	u8 *dst = walk->dst.virt.addr;
+	u8 *iv = walk->iv;
+
+	do {
+		xor(iv, src, bsize);
+		fn(crypto_cipher_tfm(tfm), dst, iv);
+		memcpy(iv, dst, bsize);
+		xor(iv, src, bsize);
+
+		src += bsize;
+		dst += bsize;
+	} while ((nbytes -= bsize) >= bsize);
+
+	return nbytes;
+}
+
+static int crypto_pcbc_encrypt_inplace(struct blkcipher_desc *desc,
+				       struct blkcipher_walk *walk,
+				       struct crypto_cipher *tfm,
+				       void (*xor)(u8 *, const u8 *,
+						   unsigned int))
+{
+	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
+		crypto_cipher_alg(tfm)->cia_encrypt;
+	int bsize = crypto_cipher_blocksize(tfm);
+	unsigned int nbytes = walk->nbytes;
+	u8 *src = walk->src.virt.addr;
+	u8 *iv = walk->iv;
+	u8 tmpbuf[bsize];
+
+	do {
+		memcpy(tmpbuf, src, bsize);
+		xor(iv, tmpbuf, bsize);
+		fn(crypto_cipher_tfm(tfm), src, iv);
+		memcpy(iv, src, bsize);
+		xor(iv, tmpbuf, bsize);
+
+		src += bsize;
+	} while ((nbytes -= bsize) >= bsize);
+
+	memcpy(walk->iv, iv, bsize);
+
+	return nbytes;
+}
+
+static int crypto_pcbc_encrypt(struct blkcipher_desc *desc,
+			       struct scatterlist *dst, struct scatterlist *src,
+			       unsigned int nbytes)
+{
+	struct blkcipher_walk walk;
+	struct crypto_blkcipher *tfm = desc->tfm;
+	struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
+	struct crypto_cipher *child = ctx->child;
+	void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor;
+	int err;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	err = blkcipher_walk_virt(desc, &walk);
+
+	while ((nbytes = walk.nbytes)) {
+		if (walk.src.virt.addr == walk.dst.virt.addr)
+			nbytes = crypto_pcbc_encrypt_inplace(desc, &walk, child,
+							     xor);
+		else
+			nbytes = crypto_pcbc_encrypt_segment(desc, &walk, child,
+							     xor);
+		err = blkcipher_walk_done(desc, &walk, nbytes);
+	}
+
+	return err;
+}
+
+static int crypto_pcbc_decrypt_segment(struct blkcipher_desc *desc,
+				       struct blkcipher_walk *walk,
+				       struct crypto_cipher *tfm,
+				       void (*xor)(u8 *, const u8 *,
+						   unsigned int))
+{
+	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
+		crypto_cipher_alg(tfm)->cia_decrypt;
+	int bsize = crypto_cipher_blocksize(tfm);
+	unsigned int nbytes = walk->nbytes;
+	u8 *src = walk->src.virt.addr;
+	u8 *dst = walk->dst.virt.addr;
+	u8 *iv = walk->iv;
+
+	do {
+		fn(crypto_cipher_tfm(tfm), dst, src);
+		xor(dst, iv, bsize);
+		memcpy(iv, src, bsize);
+		xor(iv, dst, bsize);
+
+		src += bsize;
+		dst += bsize;
+	} while ((nbytes -= bsize) >= bsize);
+
+	memcpy(walk->iv, iv, bsize);
+
+	return nbytes;
+}
+
+static int crypto_pcbc_decrypt_inplace(struct blkcipher_desc *desc,
+				       struct blkcipher_walk *walk,
+				       struct crypto_cipher *tfm,
+				       void (*xor)(u8 *, const u8 *,
+						   unsigned int))
+{
+	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
+		crypto_cipher_alg(tfm)->cia_decrypt;
+	int bsize = crypto_cipher_blocksize(tfm);
+	unsigned int nbytes = walk->nbytes;
+	u8 *src = walk->src.virt.addr;
+	u8 *iv = walk->iv;
+	u8 tmpbuf[bsize];
+
+	do {
+		memcpy(tmpbuf, src, bsize);
+		fn(crypto_cipher_tfm(tfm), src, src);
+		xor(src, iv, bsize);
+		memcpy(iv, tmpbuf, bsize);
+		xor(iv, src, bsize);
+
+		src += bsize;
+	} while ((nbytes -= bsize) >= bsize);
+
+	memcpy(walk->iv, iv, bsize);
+
+	return nbytes;
+}
+
+static int crypto_pcbc_decrypt(struct blkcipher_desc *desc,
+			       struct scatterlist *dst, struct scatterlist *src,
+			       unsigned int nbytes)
+{
+	struct blkcipher_walk walk;
+	struct crypto_blkcipher *tfm = desc->tfm;
+	struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
+	struct crypto_cipher *child = ctx->child;
+	void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor;
+	int err;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	err = blkcipher_walk_virt(desc, &walk);
+
+	while ((nbytes = walk.nbytes)) {
+		if (walk.src.virt.addr == walk.dst.virt.addr)
+			nbytes = crypto_pcbc_decrypt_inplace(desc, &walk, child,
+							     xor);
+		else
+			nbytes = crypto_pcbc_decrypt_segment(desc, &walk, child,
+							     xor);
+		err = blkcipher_walk_done(desc, &walk, nbytes);
+	}
+
+	return err;
+}
+
+static void xor_byte(u8 *a, const u8 *b, unsigned int bs)
+{
+	do {
+		*a++ ^= *b++;
+	} while (--bs);
+}
+
+static void xor_quad(u8 *dst, const u8 *src, unsigned int bs)
+{
+	u32 *a = (u32 *)dst;
+	u32 *b = (u32 *)src;
+
+	do {
+		*a++ ^= *b++;
+	} while ((bs -= 4));
+}
+
+static void xor_64(u8 *a, const u8 *b, unsigned int bs)
+{
+	((u32 *)a)[0] ^= ((u32 *)b)[0];
+	((u32 *)a)[1] ^= ((u32 *)b)[1];
+}
+
+static void xor_128(u8 *a, const u8 *b, unsigned int bs)
+{
+	((u32 *)a)[0] ^= ((u32 *)b)[0];
+	((u32 *)a)[1] ^= ((u32 *)b)[1];
+	((u32 *)a)[2] ^= ((u32 *)b)[2];
+	((u32 *)a)[3] ^= ((u32 *)b)[3];
+}
+
+static int crypto_pcbc_init_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = (void *)tfm->__crt_alg;
+	struct crypto_spawn *spawn = crypto_instance_ctx(inst);
+	struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_cipher *cipher;
+
+	switch (crypto_tfm_alg_blocksize(tfm)) {
+	case 8:
+		ctx->xor = xor_64;
+		break;
+
+	case 16:
+		ctx->xor = xor_128;
+		break;
+
+	default:
+		if (crypto_tfm_alg_blocksize(tfm) % 4)
+			ctx->xor = xor_byte;
+		else
+			ctx->xor = xor_quad;
+	}
+
+	cipher = crypto_spawn_cipher(spawn);
+	if (IS_ERR(cipher))
+		return PTR_ERR(cipher);
+
+	ctx->child = cipher;
+	return 0;
+}
+
+static void crypto_pcbc_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(tfm);
+	crypto_free_cipher(ctx->child);
+}
+
+static struct crypto_instance *crypto_pcbc_alloc(void *param, unsigned int len)
+{
+	struct crypto_instance *inst;
+	struct crypto_alg *alg;
+
+	alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER,
+				  CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+	if (IS_ERR(alg))
+		return ERR_PTR(PTR_ERR(alg));
+
+	inst = crypto_alloc_instance("pcbc", alg);
+	if (IS_ERR(inst))
+		goto out_put_alg;
+
+	inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
+	inst->alg.cra_priority = alg->cra_priority;
+	inst->alg.cra_blocksize = alg->cra_blocksize;
+	inst->alg.cra_alignmask = alg->cra_alignmask;
+	inst->alg.cra_type = &crypto_blkcipher_type;
+
+	if (!(alg->cra_blocksize % 4))
+		inst->alg.cra_alignmask |= 3;
+	inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
+	inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
+	inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize;
+
+	inst->alg.cra_ctxsize = sizeof(struct crypto_pcbc_ctx);
+
+	inst->alg.cra_init = crypto_pcbc_init_tfm;
+	inst->alg.cra_exit = crypto_pcbc_exit_tfm;
+
+	inst->alg.cra_blkcipher.setkey = crypto_pcbc_setkey;
+	inst->alg.cra_blkcipher.encrypt = crypto_pcbc_encrypt;
+	inst->alg.cra_blkcipher.decrypt = crypto_pcbc_decrypt;
+
+out_put_alg:
+	crypto_mod_put(alg);
+	return inst;
+}
+
+static void crypto_pcbc_free(struct crypto_instance *inst)
+{
+	crypto_drop_spawn(crypto_instance_ctx(inst));
+	kfree(inst);
+}
+
+static struct crypto_template crypto_pcbc_tmpl = {
+	.name = "pcbc",
+	.alloc = crypto_pcbc_alloc,
+	.free = crypto_pcbc_free,
+	.module = THIS_MODULE,
+};
+
+static int __init crypto_pcbc_module_init(void)
+{
+	return crypto_register_template(&crypto_pcbc_tmpl);
+}
+
+static void __exit crypto_pcbc_module_exit(void)
+{
+	crypto_unregister_template(&crypto_pcbc_tmpl);
+}
+
+module_init(crypto_pcbc_module_init);
+module_exit(crypto_pcbc_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PCBC block cipher algorithm");
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index d671e89..f5e9da3 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -12,6 +12,7 @@
  * Software Foundation; either version 2 of the License, or (at your option)
  * any later version.
  *
+ * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests
  * 2004-08-09 Added cipher speed tests (Reyk Floeter <reyk@vantronix.net>)
  * 2003-09-14 Rewritten by Kartikey Mahendra Bhatt
  *
@@ -71,7 +72,8 @@
 	"des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish",
 	"twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6",
 	"arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",
-	"khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", NULL
+	"khazad", "wp512", "wp384", "wp256", "tnepres", "xeta",  "fcrypt",
+	"camellia", NULL
 };
 
 static void hexdump(unsigned char *buf, unsigned int len)
@@ -765,7 +767,7 @@
 	memcpy(tvmem, deflate_comp_tv_template, tsize);
 	tv = (void *)tvmem;
 
-	tfm = crypto_alloc_tfm("deflate", 0);
+	tfm = crypto_alloc_comp("deflate", 0, CRYPTO_ALG_ASYNC);
 	if (tfm == NULL) {
 		printk("failed to load transform for deflate\n");
 		return;
@@ -964,6 +966,26 @@
 		test_cipher("ecb(xeta)", DECRYPT, xeta_dec_tv_template,
 			    XETA_DEC_TEST_VECTORS);
 
+		//FCrypt
+		test_cipher("pcbc(fcrypt)", ENCRYPT, fcrypt_pcbc_enc_tv_template,
+			    FCRYPT_ENC_TEST_VECTORS);
+		test_cipher("pcbc(fcrypt)", DECRYPT, fcrypt_pcbc_dec_tv_template,
+			    FCRYPT_DEC_TEST_VECTORS);
+
+		//CAMELLIA
+		test_cipher("ecb(camellia)", ENCRYPT,
+			    camellia_enc_tv_template,
+			    CAMELLIA_ENC_TEST_VECTORS);
+		test_cipher("ecb(camellia)", DECRYPT,
+			    camellia_dec_tv_template,
+			    CAMELLIA_DEC_TEST_VECTORS);
+		test_cipher("cbc(camellia)", ENCRYPT,
+			    camellia_cbc_enc_tv_template,
+			    CAMELLIA_CBC_ENC_TEST_VECTORS);
+		test_cipher("cbc(camellia)", DECRYPT,
+			    camellia_cbc_dec_tv_template,
+			    CAMELLIA_CBC_DEC_TEST_VECTORS);
+
 		test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS);
 		test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS);
 		test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS);
@@ -980,6 +1002,10 @@
 			  HMAC_SHA1_TEST_VECTORS);
 		test_hash("hmac(sha256)", hmac_sha256_tv_template,
 			  HMAC_SHA256_TEST_VECTORS);
+		test_hash("hmac(sha384)", hmac_sha384_tv_template,
+			  HMAC_SHA384_TEST_VECTORS);
+		test_hash("hmac(sha512)", hmac_sha512_tv_template,
+			  HMAC_SHA512_TEST_VECTORS);
 
 		test_hash("xcbc(aes)", aes_xcbc128_tv_template,
 			  XCBC_AES_TEST_VECTORS);
@@ -1177,6 +1203,28 @@
 			    XETA_DEC_TEST_VECTORS);
 		break;
 
+	case 31:
+		test_cipher("pcbc(fcrypt)", ENCRYPT, fcrypt_pcbc_enc_tv_template,
+			    FCRYPT_ENC_TEST_VECTORS);
+		test_cipher("pcbc(fcrypt)", DECRYPT, fcrypt_pcbc_dec_tv_template,
+			    FCRYPT_DEC_TEST_VECTORS);
+		break;
+
+	case 32:
+		test_cipher("ecb(camellia)", ENCRYPT,
+			    camellia_enc_tv_template,
+			    CAMELLIA_ENC_TEST_VECTORS);
+		test_cipher("ecb(camellia)", DECRYPT,
+			    camellia_dec_tv_template,
+			    CAMELLIA_DEC_TEST_VECTORS);
+		test_cipher("cbc(camellia)", ENCRYPT,
+			    camellia_cbc_enc_tv_template,
+			    CAMELLIA_CBC_ENC_TEST_VECTORS);
+		test_cipher("cbc(camellia)", DECRYPT,
+			    camellia_cbc_dec_tv_template,
+			    CAMELLIA_CBC_DEC_TEST_VECTORS);
+		break;
+
 	case 100:
 		test_hash("hmac(md5)", hmac_md5_tv_template,
 			  HMAC_MD5_TEST_VECTORS);
@@ -1192,6 +1240,16 @@
 			  HMAC_SHA256_TEST_VECTORS);
 		break;
 
+	case 103:
+		test_hash("hmac(sha384)", hmac_sha384_tv_template,
+			  HMAC_SHA384_TEST_VECTORS);
+		break;
+
+	case 104:
+		test_hash("hmac(sha512)", hmac_sha512_tv_template,
+			  HMAC_SHA512_TEST_VECTORS);
+		break;
+
 
 	case 200:
 		test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0,
@@ -1260,6 +1318,17 @@
 				  des_speed_template);
 		break;
 
+	case 205:
+		test_cipher_speed("ecb(camellia)", ENCRYPT, sec, NULL, 0,
+				camellia_speed_template);
+		test_cipher_speed("ecb(camellia)", DECRYPT, sec, NULL, 0,
+				camellia_speed_template);
+		test_cipher_speed("cbc(camellia)", ENCRYPT, sec, NULL, 0,
+				camellia_speed_template);
+		test_cipher_speed("cbc(camellia)", DECRYPT, sec, NULL, 0,
+				camellia_speed_template);
+		break;
+
 	case 300:
 		/* fall through */
 
diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h
index 48a8136..887527b 100644
--- a/crypto/tcrypt.h
+++ b/crypto/tcrypt.h
@@ -12,6 +12,7 @@
  * Software Foundation; either version 2 of the License, or (at your option)
  * any later version.
  *
+ * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests
  * 2004-08-09 Cipher speed tests by Reyk Floeter <reyk@vantronix.net>
  * 2003-09-14 Changes by Kartikey Mahendra Bhatt
  *
@@ -27,7 +28,7 @@
 
 struct hash_testvec {
 	/* only used with keyed hash algorithms */
-	char key[128] __attribute__ ((__aligned__(4)));
+	char key[132] __attribute__ ((__aligned__(4)));
 	char plaintext[240];
 	char digest[MAX_DIGEST_SIZE];
 	unsigned char tap[MAX_TAP];
@@ -1002,6 +1003,248 @@
 };
 
 /*
+ * SHA384 HMAC test vectors from RFC4231
+ */
+
+#define HMAC_SHA384_TEST_VECTORS	4
+
+static struct hash_testvec hmac_sha384_tv_template[] = {
+	{
+		.key	= { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+			    0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+			    0x0b, 0x0b, 0x0b, 0x0b }, // (20 bytes)
+		.ksize	= 20,
+		.plaintext = { 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 }, // ("Hi There")
+		.psize	= 8,
+		.digest	= { 0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62,
+			    0x6b, 0x08, 0x25, 0xf4, 0xab, 0x46, 0x90, 0x7f,
+			    0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6,
+			    0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c,
+			    0xfa, 0xea, 0x9e, 0xa9, 0x07, 0x6e, 0xde, 0x7f,
+			    0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6 },
+	}, {
+		.key	= { 0x4a, 0x65, 0x66, 0x65 }, // ("Jefe")
+		.ksize	= 4,
+		.plaintext = { 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20,
+			       0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, // ("what do ya want ")
+			       0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68,
+			       0x69, 0x6e, 0x67, 0x3f }, // ("for nothing?")
+		.psize	= 28,
+		.digest	= { 0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31,
+			    0x61, 0x7f, 0x78, 0xd2, 0xb5, 0x8a, 0x6b, 0x1b,
+			    0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47,
+			    0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e,
+			    0x8e, 0x22, 0x40, 0xca, 0x5e, 0x69, 0xe2, 0xc7,
+			    0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49 },
+		.np	= 4,
+		.tap	= { 7, 7, 7, 7 }
+	}, {
+		.key	= { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa }, // (131 bytes)
+		.ksize	= 131,
+		.plaintext = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69,
+			       0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, // ("Test Using Large")
+			       0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42,
+			       0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, // ("r Than Block-Siz")
+			       0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20,
+			       0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, // ("e Key - Hash Key")
+			       0x20, 0x46, 0x69, 0x72, 0x73, 0x74 }, // (" First")
+		.psize	= 54,
+		.digest	= { 0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90,
+			    0x88, 0xd2, 0xc6, 0x3a, 0x04, 0x1b, 0xc5, 0xb4,
+			    0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f,
+			    0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6,
+			    0x0c, 0x2e, 0xf6, 0xab, 0x40, 0x30, 0xfe, 0x82,
+			    0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52 },
+	}, {
+		.key	= { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa }, // (131 bytes)
+		.ksize	= 131,
+		.plaintext = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
+			       0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75, // ("This is a test u")
+			       0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c,
+			       0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, // ("sing a larger th")
+			       0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
+			       0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65, // ("an block-size ke")
+			       0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20,
+			       0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, // ("y and a larger t")
+			       0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63,
+			       0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64, // ("han block-size d")
+			       0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65,
+			       0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65, // ("ata. The key nee")
+			       0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65,
+			       0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, // ("ds to be hashed ")
+			       0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62,
+			       0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, // ("before being use")
+			       0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65,
+			       0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c, // ("d by the HMAC al")
+			       0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e }, // ("gorithm.")
+		.psize	= 152,
+		.digest	= { 0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d,
+			    0x35, 0x1e, 0x2f, 0x25, 0x4e, 0x8f, 0xd3, 0x2c,
+			    0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a,
+			    0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5,
+			    0xa6, 0x78, 0xcc, 0x31, 0xe7, 0x99, 0x17, 0x6d,
+			    0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e },
+	},
+};
+
+/*
+ * SHA512 HMAC test vectors from RFC4231
+ */
+
+#define HMAC_SHA512_TEST_VECTORS	4
+
+static struct hash_testvec hmac_sha512_tv_template[] = {
+	{
+		.key	= { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+			    0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+			    0x0b, 0x0b, 0x0b, 0x0b }, // (20 bytes)
+		.ksize	= 20,
+		.plaintext = { 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 }, // ("Hi There")
+		.psize	= 8,
+		.digest	= { 0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d,
+			    0x4f, 0xf0, 0xb4, 0x24, 0x1a, 0x1d, 0x6c, 0xb0,
+			    0x23, 0x79, 0xf4, 0xe2, 0xce, 0x4e, 0xc2, 0x78,
+			    0x7a, 0xd0, 0xb3, 0x05, 0x45, 0xe1, 0x7c, 0xde,
+			    0xda, 0xa8, 0x33, 0xb7, 0xd6, 0xb8, 0xa7, 0x02,
+			    0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4,
+			    0xbe, 0x9d, 0x91, 0x4e, 0xeb, 0x61, 0xf1, 0x70,
+			    0x2e, 0x69, 0x6c, 0x20, 0x3a, 0x12, 0x68, 0x54 },
+	}, {
+		.key	= { 0x4a, 0x65, 0x66, 0x65 }, // ("Jefe")
+		.ksize	= 4,
+		.plaintext = { 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20,
+			       0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, // ("what do ya want ")
+			       0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68,
+			       0x69, 0x6e, 0x67, 0x3f }, // ("for nothing?")
+		.psize	= 28,
+		.digest	= { 0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2,
+			    0xe3, 0x95, 0xfb, 0xe7, 0x3b, 0x56, 0xe0, 0xa3,
+			    0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6,
+			    0x10, 0x27, 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54,
+			    0x97, 0x58, 0xbf, 0x75, 0xc0, 0x5a, 0x99, 0x4a,
+			    0x6d, 0x03, 0x4f, 0x65, 0xf8, 0xf0, 0xe6, 0xfd,
+			    0xca, 0xea, 0xb1, 0xa3, 0x4d, 0x4a, 0x6b, 0x4b,
+			    0x63, 0x6e, 0x07, 0x0a, 0x38, 0xbc, 0xe7, 0x37 },
+		.np	= 4,
+		.tap	= { 7, 7, 7, 7 }
+	}, {
+		.key	= { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa }, // (131 bytes)
+		.ksize	= 131,
+		.plaintext = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69,
+			       0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, // ("Test Using Large")
+			       0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42,
+			       0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, // ("r Than Block-Siz")
+			       0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20,
+			       0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, // ("e Key - Hash Key")
+			       0x20, 0x46, 0x69, 0x72, 0x73, 0x74 }, // (" First")
+		.psize	= 54,
+		.digest	= { 0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb,
+			    0xb7, 0x14, 0x93, 0xc1, 0xdd, 0x7b, 0xe8, 0xb4,
+			    0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1,
+			    0x12, 0x1b, 0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52,
+			    0x6b, 0x56, 0xd0, 0x37, 0xe0, 0x5f, 0x25, 0x98,
+			    0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52,
+			    0x95, 0xe6, 0x4f, 0x73, 0xf6, 0x3f, 0x0a, 0xec,
+			    0x8b, 0x91, 0x5a, 0x98, 0x5d, 0x78, 0x65, 0x98 },
+	}, {
+		.key	= { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+			    0xaa, 0xaa, 0xaa }, // (131 bytes)
+		.ksize	= 131,
+		.plaintext = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
+			       0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75, // ("This is a test u")
+			       0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c,
+			       0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, // ("sing a larger th")
+			       0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
+			       0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65, // ("an block-size ke")
+			       0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20,
+			       0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, // ("y and a larger t")
+			       0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63,
+			       0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64, // ("han block-size d")
+			       0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65,
+			       0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65, // ("ata. The key nee")
+			       0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65,
+			       0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, // ("ds to be hashed ")
+			       0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62,
+			       0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, // ("before being use")
+			       0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65,
+			       0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c, // ("d by the HMAC al")
+			       0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e }, // ("gorithm.")
+		.psize	= 152,
+		.digest	= { 0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba,
+			    0xa4, 0xdf, 0xa9, 0xf9, 0x6e, 0x5e, 0x3f, 0xfd,
+			    0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86,
+			    0x5d, 0xf5, 0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44,
+			    0xb6, 0x02, 0x2c, 0xac, 0x3c, 0x49, 0x82, 0xb1,
+			    0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15,
+			    0x13, 0x46, 0x76, 0xfb, 0x6d, 0xe0, 0x44, 0x60,
+			    0x65, 0xc9, 0x74, 0x40, 0xfa, 0x8c, 0x6a, 0x58 },
+	},
+};
+
+/*
  * DES test vectors.
  */
 #define DES_ENC_TEST_VECTORS		10
@@ -3316,6 +3559,278 @@
 	}
 };
 
+/* 
+ * FCrypt test vectors 
+ */
+#define FCRYPT_ENC_TEST_VECTORS	ARRAY_SIZE(fcrypt_pcbc_enc_tv_template)
+#define FCRYPT_DEC_TEST_VECTORS	ARRAY_SIZE(fcrypt_pcbc_dec_tv_template)
+
+static struct cipher_testvec fcrypt_pcbc_enc_tv_template[] = {
+	{ /* http://www.openafs.org/pipermail/openafs-devel/2000-December/005320.html */
+		.key	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.klen	= 8,
+		.iv	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.input	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.ilen	= 8,
+		.result	= { 0x0E, 0x09, 0x00, 0xC7, 0x3E, 0xF7, 0xED, 0x41 },
+		.rlen	= 8,
+	}, {
+		.key	= { 0x11, 0x44, 0x77, 0xAA, 0xDD, 0x00, 0x33, 0x66 },
+		.klen	= 8,
+		.iv	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.input	= { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 },
+		.ilen	= 8,
+		.result	= { 0xD8, 0xED, 0x78, 0x74, 0x77, 0xEC, 0x06, 0x80 },
+		.rlen	= 8,
+	}, { /* From Arla */
+		.key	= { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 },
+		.klen	= 8,
+		.iv	= { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		.input	= "The quick brown fox jumps over the lazy dogs.\0\0",
+		.ilen	= 48,
+		.result	= { 0x00, 0xf0, 0xe,  0x11, 0x75, 0xe6, 0x23, 0x82,
+			    0xee, 0xac, 0x98, 0x62, 0x44, 0x51, 0xe4, 0x84,
+			    0xc3, 0x59, 0xd8, 0xaa, 0x64, 0x60, 0xae, 0xf7,
+			    0xd2, 0xd9, 0x13, 0x79, 0x72, 0xa3, 0x45, 0x03,
+			    0x23, 0xb5, 0x62, 0xd7, 0x0c, 0xf5, 0x27, 0xd1,
+			    0xf8, 0x91, 0x3c, 0xac, 0x44, 0x22, 0x92, 0xef },
+		.rlen	= 48,
+	}, {
+		.key	= { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		.klen	= 8,
+		.iv	= { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 },
+		.input	= "The quick brown fox jumps over the lazy dogs.\0\0",
+		.ilen	= 48,
+		.result	= { 0xca, 0x90, 0xf5, 0x9d, 0xcb, 0xd4, 0xd2, 0x3c,
+			    0x01, 0x88, 0x7f, 0x3e, 0x31, 0x6e, 0x62, 0x9d,
+			    0xd8, 0xe0, 0x57, 0xa3, 0x06, 0x3a, 0x42, 0x58,
+			    0x2a, 0x28, 0xfe, 0x72, 0x52, 0x2f, 0xdd, 0xe0,
+			    0x19, 0x89, 0x09, 0x1c, 0x2a, 0x8e, 0x8c, 0x94,
+			    0xfc, 0xc7, 0x68, 0xe4, 0x88, 0xaa, 0xde, 0x0f },
+		.rlen	= 48,
+	}, { /* split-page version */
+		.key	= { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		.klen	= 8,
+		.iv	= { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 },
+		.input	= "The quick brown fox jumps over the lazy dogs.\0\0",
+		.ilen	= 48,
+		.result	= { 0xca, 0x90, 0xf5, 0x9d, 0xcb, 0xd4, 0xd2, 0x3c,
+			    0x01, 0x88, 0x7f, 0x3e, 0x31, 0x6e, 0x62, 0x9d,
+			    0xd8, 0xe0, 0x57, 0xa3, 0x06, 0x3a, 0x42, 0x58,
+			    0x2a, 0x28, 0xfe, 0x72, 0x52, 0x2f, 0xdd, 0xe0,
+			    0x19, 0x89, 0x09, 0x1c, 0x2a, 0x8e, 0x8c, 0x94,
+			    0xfc, 0xc7, 0x68, 0xe4, 0x88, 0xaa, 0xde, 0x0f },
+		.rlen	= 48,
+		.np	= 2,
+		.tap	= { 20, 28 },
+	}
+};
+
+static struct cipher_testvec fcrypt_pcbc_dec_tv_template[] = {
+	{ /* http://www.openafs.org/pipermail/openafs-devel/2000-December/005320.html */
+		.key	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.klen	= 8,
+		.iv	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.input	= { 0x0E, 0x09, 0x00, 0xC7, 0x3E, 0xF7, 0xED, 0x41 },
+		.ilen	= 8,
+		.result	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.rlen	= 8,
+	}, {
+		.key	= { 0x11, 0x44, 0x77, 0xAA, 0xDD, 0x00, 0x33, 0x66 },
+		.klen	= 8,
+		.iv	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.input	= { 0xD8, 0xED, 0x78, 0x74, 0x77, 0xEC, 0x06, 0x80 },
+		.ilen	= 8,
+		.result	= { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 },
+		.rlen	= 8,
+	}, { /* From Arla */
+		.key	= { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 },
+		.klen	= 8,
+		.iv	= { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		.input	= { 0x00, 0xf0, 0xe,  0x11, 0x75, 0xe6, 0x23, 0x82,
+			    0xee, 0xac, 0x98, 0x62, 0x44, 0x51, 0xe4, 0x84,
+			    0xc3, 0x59, 0xd8, 0xaa, 0x64, 0x60, 0xae, 0xf7,
+			    0xd2, 0xd9, 0x13, 0x79, 0x72, 0xa3, 0x45, 0x03,
+			    0x23, 0xb5, 0x62, 0xd7, 0x0c, 0xf5, 0x27, 0xd1,
+			    0xf8, 0x91, 0x3c, 0xac, 0x44, 0x22, 0x92, 0xef },
+		.ilen	= 48,
+		.result	= "The quick brown fox jumps over the lazy dogs.\0\0",
+		.rlen	= 48,
+	}, {
+		.key	= { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		.klen	= 8,
+		.iv	= { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 },
+		.input	= { 0xca, 0x90, 0xf5, 0x9d, 0xcb, 0xd4, 0xd2, 0x3c,
+			    0x01, 0x88, 0x7f, 0x3e, 0x31, 0x6e, 0x62, 0x9d,
+			    0xd8, 0xe0, 0x57, 0xa3, 0x06, 0x3a, 0x42, 0x58,
+			    0x2a, 0x28, 0xfe, 0x72, 0x52, 0x2f, 0xdd, 0xe0,
+			    0x19, 0x89, 0x09, 0x1c, 0x2a, 0x8e, 0x8c, 0x94,
+			    0xfc, 0xc7, 0x68, 0xe4, 0x88, 0xaa, 0xde, 0x0f },
+		.ilen	= 48,
+		.result	= "The quick brown fox jumps over the lazy dogs.\0\0",
+		.rlen	= 48,
+	}, { /* split-page version */
+		.key	= { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		.klen	= 8,
+		.iv	= { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 },
+		.input	= { 0xca, 0x90, 0xf5, 0x9d, 0xcb, 0xd4, 0xd2, 0x3c,
+			    0x01, 0x88, 0x7f, 0x3e, 0x31, 0x6e, 0x62, 0x9d,
+			    0xd8, 0xe0, 0x57, 0xa3, 0x06, 0x3a, 0x42, 0x58,
+			    0x2a, 0x28, 0xfe, 0x72, 0x52, 0x2f, 0xdd, 0xe0,
+			    0x19, 0x89, 0x09, 0x1c, 0x2a, 0x8e, 0x8c, 0x94,
+			    0xfc, 0xc7, 0x68, 0xe4, 0x88, 0xaa, 0xde, 0x0f },
+		.ilen	= 48,
+		.result	= "The quick brown fox jumps over the lazy dogs.\0\0",
+		.rlen	= 48,
+		.np	= 2,
+		.tap	= { 20, 28 },
+	}
+};
+
+/*
+ * CAMELLIA test vectors.
+ */
+#define CAMELLIA_ENC_TEST_VECTORS 3
+#define CAMELLIA_DEC_TEST_VECTORS 3
+#define CAMELLIA_CBC_ENC_TEST_VECTORS 2
+#define CAMELLIA_CBC_DEC_TEST_VECTORS 2
+
+static struct cipher_testvec camellia_enc_tv_template[] = {
+	{
+		.key	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+			    0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		.klen	= 16,
+		.input	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+			    0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		.ilen	= 16,
+		.result	= { 0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73,
+			    0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43 },
+		.rlen	= 16,
+	}, {
+		.key	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+			    0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
+			    0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 },
+		.klen	= 24,
+		.input	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+			    0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		.ilen	= 16,
+		.result	= { 0xb4, 0x99, 0x34, 0x01, 0xb3, 0xe9, 0x96, 0xf8,
+			    0x4e, 0xe5, 0xce, 0xe7, 0xd7, 0x9b, 0x09, 0xb9 },
+		.rlen	= 16,
+	}, {
+		.key	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+			    0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
+			    0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+			    0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
+		.klen	= 32,
+		.input	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+			    0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		.ilen	= 16,
+		.result	= { 0x9a, 0xcc, 0x23, 0x7d, 0xff, 0x16, 0xd7, 0x6c,
+			    0x20, 0xef, 0x7c, 0x91, 0x9e, 0x3a, 0x75, 0x09 },
+		.rlen	= 16,
+	},
+};
+
+static struct cipher_testvec camellia_dec_tv_template[] = {
+	{
+		.key	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+			    0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		.klen	= 16,
+		.input	= { 0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73,
+			    0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43 },
+		.ilen	= 16,
+		.result	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+			    0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		.rlen	= 16,
+	}, {
+		.key	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+			    0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
+			    0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 },
+		.klen	= 24,
+		.input	= { 0xb4, 0x99, 0x34, 0x01, 0xb3, 0xe9, 0x96, 0xf8,
+			    0x4e, 0xe5, 0xce, 0xe7, 0xd7, 0x9b, 0x09, 0xb9 },
+		.ilen	= 16,
+		.result	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+			    0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		.rlen	= 16,
+	}, {
+		.key	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+			    0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
+			    0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+			    0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
+		.klen	= 32,
+		.input	= { 0x9a, 0xcc, 0x23, 0x7d, 0xff, 0x16, 0xd7, 0x6c,
+			    0x20, 0xef, 0x7c, 0x91, 0x9e, 0x3a, 0x75, 0x09 },
+		.ilen	= 16,
+		.result	= { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+			    0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		.rlen	= 16,
+	},
+};
+
+static struct cipher_testvec camellia_cbc_enc_tv_template[] = {
+	{
+		.key    = { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
+			    0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 },
+		.klen   = 16,
+		.iv	= { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
+			    0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 },
+		.input	= { "Single block msg" },
+		.ilen   = 16,
+		.result = { 0xea, 0x32, 0x12, 0x76, 0x3b, 0x50, 0x10, 0xe7,
+			    0x18, 0xf6, 0xfd, 0x5d, 0xf6, 0x8f, 0x13, 0x51 },
+		.rlen   = 16,
+	}, {
+		.key    = { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0,
+			    0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a },
+		.klen   = 16,
+		.iv     = { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28,
+			    0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 },
+		.input  = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+			    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+			    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+			    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
+		.ilen   = 32,
+		.result = { 0xa5, 0xdf, 0x6e, 0x50, 0xda, 0x70, 0x6c, 0x01,
+			    0x4a, 0xab, 0xf3, 0xf2, 0xd6, 0xfc, 0x6c, 0xfd,
+			    0x19, 0xb4, 0x3e, 0x57, 0x1c, 0x02, 0x5e, 0xa0,
+			    0x15, 0x78, 0xe0, 0x5e, 0xf2, 0xcb, 0x87, 0x16 },
+		.rlen   = 32,
+	},
+};
+
+static struct cipher_testvec camellia_cbc_dec_tv_template[] = {
+	{
+		.key    = { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
+			    0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 },
+		.klen   = 16,
+		.iv	= { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
+			    0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 },
+		.input	= { 0xea, 0x32, 0x12, 0x76, 0x3b, 0x50, 0x10, 0xe7,
+			    0x18, 0xf6, 0xfd, 0x5d, 0xf6, 0x8f, 0x13, 0x51 },
+		.ilen   = 16,
+		.result = { "Single block msg" },
+		.rlen   = 16,
+	}, {
+		.key    = { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0,
+			    0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a },
+		.klen   = 16,
+		.iv     = { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28,
+			    0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 },
+		.input = { 0xa5, 0xdf, 0x6e, 0x50, 0xda, 0x70, 0x6c, 0x01,
+			    0x4a, 0xab, 0xf3, 0xf2, 0xd6, 0xfc, 0x6c, 0xfd,
+			    0x19, 0xb4, 0x3e, 0x57, 0x1c, 0x02, 0x5e, 0xa0,
+			    0x15, 0x78, 0xe0, 0x5e, 0xf2, 0xcb, 0x87, 0x16 },
+		.ilen   = 32,
+		.result = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+			    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+			    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+			    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
+		.rlen   = 32,
+	},
+};
+
 /*
  * Compression stuff.
  */
@@ -3769,4 +4284,25 @@
 	{  .blen = 0,	.plen = 0, }
 };
 
+static struct cipher_speed camellia_speed_template[] = {
+      { .klen = 16, .blen = 16, },
+      { .klen = 16, .blen = 64, },
+      { .klen = 16, .blen = 256, },
+      { .klen = 16, .blen = 1024, },
+      { .klen = 16, .blen = 8192, },
+      { .klen = 24, .blen = 16, },
+      { .klen = 24, .blen = 64, },
+      { .klen = 24, .blen = 256, },
+      { .klen = 24, .blen = 1024, },
+      { .klen = 24, .blen = 8192, },
+      { .klen = 32, .blen = 16, },
+      { .klen = 32, .blen = 64, },
+      { .klen = 32, .blen = 256, },
+      { .klen = 32, .blen = 1024, },
+      { .klen = 32, .blen = 8192, },
+
+      /* End marker */
+      {  .klen = 0, .blen = 0, }
+};
+
 #endif	/* _CRYPTO_TCRYPT_H */
diff --git a/crypto/xcbc.c b/crypto/xcbc.c
index 9347eb6..53e8ccb 100644
--- a/crypto/xcbc.c
+++ b/crypto/xcbc.c
@@ -21,6 +21,7 @@
 
 #include <linux/crypto.h>
 #include <linux/err.h>
+#include <linux/hardirq.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/rtnetlink.h>
@@ -47,7 +48,7 @@
  * +------------------------
  */
 struct crypto_xcbc_ctx {
-	struct crypto_tfm *child;
+	struct crypto_cipher *child;
 	u8 *odds;
 	u8 *prev;
 	u8 *key;
@@ -75,8 +76,7 @@
 	if ((err = crypto_cipher_setkey(ctx->child, ctx->key, ctx->keylen)))
 	    return err;
 
-	ctx->child->__crt_alg->cra_cipher.cia_encrypt(ctx->child, key1,
-			ctx->consts);
+	crypto_cipher_encrypt_one(ctx->child, key1, ctx->consts);
 
 	return crypto_cipher_setkey(ctx->child, key1, bs);
 }
@@ -86,7 +86,7 @@
 {
 	struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent);
 
-	if (keylen != crypto_tfm_alg_blocksize(ctx->child))
+	if (keylen != crypto_cipher_blocksize(ctx->child))
 		return -EINVAL;
 
 	ctx->keylen = keylen;
@@ -108,13 +108,13 @@
 	return 0;
 }
 
-static int crypto_xcbc_digest_update(struct hash_desc *pdesc,
-				     struct scatterlist *sg,
-				     unsigned int nbytes)
+static int crypto_xcbc_digest_update2(struct hash_desc *pdesc,
+				      struct scatterlist *sg,
+				      unsigned int nbytes)
 {
 	struct crypto_hash *parent = pdesc->tfm;
 	struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent);
-	struct crypto_tfm *tfm = ctx->child;
+	struct crypto_cipher *tfm = ctx->child;
 	int bs = crypto_hash_blocksize(parent);
 	unsigned int i = 0;
 
@@ -142,7 +142,7 @@
 					offset += len;
 
 				crypto_kunmap(p, 0);
-				crypto_yield(tfm->crt_flags);
+				crypto_yield(pdesc->flags);
 				continue;
 			}
 
@@ -152,7 +152,7 @@
 			p += bs - ctx->len;
 
 			ctx->xor(ctx->prev, ctx->odds, bs);
-			tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, ctx->prev, ctx->prev);
+			crypto_cipher_encrypt_one(tfm, ctx->prev, ctx->prev);
 
 			/* clearing the length */
 			ctx->len = 0;
@@ -160,7 +160,8 @@
 			/* encrypting the rest of data */
 			while (len > bs) {
 				ctx->xor(ctx->prev, p, bs);
-				tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, ctx->prev, ctx->prev);
+				crypto_cipher_encrypt_one(tfm, ctx->prev,
+							  ctx->prev);
 				p += bs;
 				len -= bs;
 			}
@@ -171,7 +172,7 @@
 				ctx->len = len;
 			}
 			crypto_kunmap(p, 0);
-			crypto_yield(tfm->crt_flags);
+			crypto_yield(pdesc->flags);
 			slen -= min(slen, ((unsigned int)(PAGE_SIZE)) - offset);
 			offset = 0;
 			pg++;
@@ -183,11 +184,20 @@
 	return 0;
 }
 
+static int crypto_xcbc_digest_update(struct hash_desc *pdesc,
+				     struct scatterlist *sg,
+				     unsigned int nbytes)
+{
+	if (WARN_ON_ONCE(in_irq()))
+		return -EDEADLK;
+	return crypto_xcbc_digest_update2(pdesc, sg, nbytes);
+}
+
 static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out)
 {
 	struct crypto_hash *parent = pdesc->tfm;
 	struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent);
-	struct crypto_tfm *tfm = ctx->child;
+	struct crypto_cipher *tfm = ctx->child;
 	int bs = crypto_hash_blocksize(parent);
 	int err = 0;
 
@@ -197,13 +207,14 @@
 		if ((err = crypto_cipher_setkey(tfm, ctx->key, ctx->keylen)) != 0)
 			return err;
 
-		tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, key2, (const u8*)(ctx->consts+bs));
+		crypto_cipher_encrypt_one(tfm, key2,
+					  (u8 *)(ctx->consts + bs));
 
 		ctx->xor(ctx->prev, ctx->odds, bs);
 		ctx->xor(ctx->prev, key2, bs);
 		_crypto_xcbc_digest_setkey(parent, ctx);
 
-		tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, out, ctx->prev);
+		crypto_cipher_encrypt_one(tfm, out, ctx->prev);
 	} else {
 		u8 key3[bs];
 		unsigned int rlen;
@@ -218,14 +229,15 @@
 		if ((err = crypto_cipher_setkey(tfm, ctx->key, ctx->keylen)) != 0)
 			return err;
 
-		tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, key3, (const u8*)(ctx->consts+bs*2));
+		crypto_cipher_encrypt_one(tfm, key3,
+					  (u8 *)(ctx->consts + bs * 2));
 
 		ctx->xor(ctx->prev, ctx->odds, bs);
 		ctx->xor(ctx->prev, key3, bs);
 
 		_crypto_xcbc_digest_setkey(parent, ctx);
 
-		tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, out, ctx->prev);
+		crypto_cipher_encrypt_one(tfm, out, ctx->prev);
 	}
 
 	return 0;
@@ -234,21 +246,25 @@
 static int crypto_xcbc_digest(struct hash_desc *pdesc,
 		  struct scatterlist *sg, unsigned int nbytes, u8 *out)
 {
+	if (WARN_ON_ONCE(in_irq()))
+		return -EDEADLK;
+
 	crypto_xcbc_digest_init(pdesc);
-	crypto_xcbc_digest_update(pdesc, sg, nbytes);
+	crypto_xcbc_digest_update2(pdesc, sg, nbytes);
 	return crypto_xcbc_digest_final(pdesc, out);
 }
 
 static int xcbc_init_tfm(struct crypto_tfm *tfm)
 {
+	struct crypto_cipher *cipher;
 	struct crypto_instance *inst = (void *)tfm->__crt_alg;
 	struct crypto_spawn *spawn = crypto_instance_ctx(inst);
 	struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(__crypto_hash_cast(tfm));
 	int bs = crypto_hash_blocksize(__crypto_hash_cast(tfm));
 
-	tfm = crypto_spawn_tfm(spawn);
-	if (IS_ERR(tfm))
-		return PTR_ERR(tfm);
+	cipher = crypto_spawn_cipher(spawn);
+	if (IS_ERR(cipher))
+		return PTR_ERR(cipher);
 
 	switch(bs) {
 	case 16:
@@ -258,7 +274,7 @@
 		return -EINVAL;
 	}
 
-	ctx->child = crypto_cipher_cast(tfm);
+	ctx->child = cipher;
 	ctx->odds = (u8*)(ctx+1);
 	ctx->prev = ctx->odds + bs;
 	ctx->key = ctx->prev + bs;
diff --git a/drivers/Makefile b/drivers/Makefile
index 0dd96d1..f28dcb4 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -30,7 +30,7 @@
 obj-y				+= base/ block/ misc/ mfd/ net/ media/
 obj-$(CONFIG_NUBUS)		+= nubus/
 obj-$(CONFIG_ATM)		+= atm/
-obj-$(CONFIG_PPC_PMAC)		+= macintosh/
+obj-y				+= macintosh/
 obj-$(CONFIG_IDE)		+= ide/
 obj-$(CONFIG_FC4)		+= fc4/
 obj-$(CONFIG_SCSI)		+= scsi/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index f4f000a..20eacc2 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -3,6 +3,7 @@
 #
 
 menu "ACPI (Advanced Configuration and Power Interface) Support"
+	depends on !X86_NUMAQ
 	depends on !X86_VISWS
 	depends on !IA64_HP_SIM
 	depends on IA64 || X86
@@ -77,6 +78,20 @@
 	  Create /proc/acpi/sleep
 	  Deprecated by /sys/power/state
 
+config ACPI_PROCFS
+	bool "Procfs interface (deprecated)"
+	depends on ACPI
+	default y
+	---help---
+	  Procfs interface for ACPI is made optional for back-compatible.
+	  As the same functions are duplicated in sysfs interface
+	  and this proc interface will be removed some time later,
+	  it's marked as deprecated.
+	  ( /proc/acpi/debug_layer && debug_level are deprecated by
+	    /sys/module/acpi/parameters/debug_layer && debug_level.
+	    /proc/acpi/info is deprecated by
+	    /sys/module/acpi/parameters/acpica_version )
+
 config ACPI_AC
 	tristate "AC Adapter"
 	depends on X86
@@ -107,7 +122,7 @@
 
 config ACPI_VIDEO
 	tristate "Video"
-	depends on X86
+	depends on X86 && BACKLIGHT_CLASS_DEVICE
 	help
 	  This driver implement the ACPI Extensions For Display Adapters
 	  for integrated graphics devices on motherboard, as specified in
@@ -139,6 +154,13 @@
 	help
 	  This driver adds support for ACPI controlled docking stations
 
+config ACPI_BAY
+	tristate "Removable Drive Bay (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	help
+	  This driver adds support for ACPI controlled removable drive
+	  bays such as the IBM ultrabay or the Dell Module Bay.
+
 config ACPI_PROCESSOR
 	tristate "Processor"
 	default y
@@ -186,19 +208,22 @@
 
 	  Note: display switching code is currently considered EXPERIMENTAL,
 	  toying with these values may even lock your machine.
-          
+
           All settings are changed via /proc/acpi/asus directory entries. Owner
           and group for these entries can be set with asus_uid and asus_gid
           parameters.
-          
+
           More information and a userspace daemon for handling the extra buttons
           at <http://sourceforge.net/projects/acpi4asus/>.
-          
+
           If you have an ACPI-compatible ASUS laptop, say Y or M here. This
           driver is still under development, so if your laptop is unsupported or
           something works not quite as expected, please use the mailing list
-          available on the above page (acpi4asus-user@lists.sourceforge.net)
-          
+          available on the above page (acpi4asus-user@lists.sourceforge.net).
+
+	  NOTE: This driver is deprecated and will probably be removed soon,
+	  use asus-laptop instead.
+
 config ACPI_IBM
 	tristate "IBM ThinkPad Laptop Extras"
 	depends on X86
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index bce7ca2..856c32b 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -37,13 +37,15 @@
 
 obj-y				+= sleep/
 obj-y				+= bus.o glue.o
+obj-y				+= scan.o
 obj-$(CONFIG_ACPI_AC) 		+= ac.o
 obj-$(CONFIG_ACPI_BATTERY)	+= battery.o
 obj-$(CONFIG_ACPI_BUTTON)	+= button.o
 obj-$(CONFIG_ACPI_EC)		+= ec.o
 obj-$(CONFIG_ACPI_FAN)		+= fan.o
 obj-$(CONFIG_ACPI_DOCK)		+= dock.o
-obj-$(CONFIG_ACPI_VIDEO)	+= video.o 
+obj-$(CONFIG_ACPI_BAY)		+= bay.o
+obj-$(CONFIG_ACPI_VIDEO)	+= video.o
 obj-$(CONFIG_ACPI_HOTKEY)	+= hotkey.o
 obj-y				+= pci_root.o pci_link.o pci_irq.o pci_bind.o
 obj-$(CONFIG_ACPI_POWER)	+= power.o
@@ -56,7 +58,6 @@
 obj-$(CONFIG_ACPI_ASUS)		+= asus_acpi.o
 obj-$(CONFIG_ACPI_IBM)		+= ibm_acpi.o
 obj-$(CONFIG_ACPI_TOSHIBA)	+= toshiba_acpi.o
-obj-y				+= scan.o motherboard.o
 obj-$(CONFIG_ACPI_HOTPLUG_MEMORY)	+= acpi_memhotplug.o
 obj-y				+= cm_sbs.o
 obj-$(CONFIG_ACPI_SBS)		+= i2c_ec.o sbs.o
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index 396140b..31ad70a 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -26,7 +26,7 @@
  *  Pontus Fuchs   - Helper functions, cleanup
  *  Johann Wiesner - Small compile fixes
  *  John Belmonte  - ACPI code for Toshiba laptop was a good starting point.
- *  Éric Burghard  - LED display support for W1N
+ *  �ic Burghard  - LED display support for W1N
  *
  */
 
@@ -1128,7 +1128,6 @@
 static int asus_hotk_get_info(void)
 {
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-	struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
 	union acpi_object *model = NULL;
 	int bsts_result;
 	char *string = NULL;
@@ -1142,11 +1141,9 @@
 	 * HID), this bit will be moved. A global variable asus_info contains
 	 * the DSDT header.
 	 */
-	status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt);
+	status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
 	if (ACPI_FAILURE(status))
 		printk(KERN_WARNING "  Couldn't get the DSDT table header\n");
-	else
-		asus_info = dsdt.pointer;
 
 	/* We have to write 0 on init this far for all ASUS models */
 	if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
@@ -1358,8 +1355,6 @@
 	acpi_bus_unregister_driver(&asus_hotk_driver);
 	remove_proc_entry(PROC_ASUS, acpi_root_dir);
 
-	kfree(asus_info);
-
 	return;
 }
 
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 5f43e0d..2f4521a 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -64,7 +64,7 @@
 
 static int acpi_battery_add(struct acpi_device *device);
 static int acpi_battery_remove(struct acpi_device *device, int type);
-static int acpi_battery_resume(struct acpi_device *device, int status);
+static int acpi_battery_resume(struct acpi_device *device);
 
 static struct acpi_driver acpi_battery_driver = {
 	.name = ACPI_BATTERY_DRIVER_NAME,
@@ -753,7 +753,7 @@
 }
 
 /* this is needed to learn about changes made in suspended state */
-static int acpi_battery_resume(struct acpi_device *device, int state)
+static int acpi_battery_resume(struct acpi_device *device)
 {
 	struct acpi_battery *battery;
 
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
new file mode 100644
index 0000000..91082ce
--- /dev/null
+++ b/drivers/acpi/bay.c
@@ -0,0 +1,490 @@
+/*
+ *  bay.c - ACPI removable drive bay driver
+ *
+ *  Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or (at
+ *  your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/notifier.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+#include <linux/platform_device.h>
+
+#define ACPI_BAY_DRIVER_NAME "ACPI Removable Drive Bay Driver"
+
+ACPI_MODULE_NAME("bay")
+MODULE_AUTHOR("Kristen Carlson Accardi");
+MODULE_DESCRIPTION(ACPI_BAY_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+#define ACPI_BAY_CLASS "bay"
+#define ACPI_BAY_COMPONENT	0x10000000
+#define _COMPONENT ACPI_BAY_COMPONENT
+#define bay_dprintk(h,s) {\
+	char prefix[80] = {'\0'};\
+	struct acpi_buffer buffer = {sizeof(prefix), prefix};\
+	acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\
+	printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); }
+static void bay_notify(acpi_handle handle, u32 event, void *data);
+static int acpi_bay_add(struct acpi_device *device);
+static int acpi_bay_remove(struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_bay_driver = {
+	.name = ACPI_BAY_DRIVER_NAME,
+	.class = ACPI_BAY_CLASS,
+	.ids = ACPI_BAY_HID,
+	.ops = {
+		.add = acpi_bay_add,
+		.remove = acpi_bay_remove,
+		},
+};
+
+struct bay {
+	acpi_handle handle;
+	char *name;
+	struct list_head list;
+	struct platform_device *pdev;
+};
+
+static LIST_HEAD(drive_bays);
+
+
+/*****************************************************************************
+ *                         Drive Bay functions                               *
+ *****************************************************************************/
+/**
+ * is_ejectable - see if a device is ejectable
+ * @handle: acpi handle of the device
+ *
+ * If an acpi object has a _EJ0 method, then it is ejectable
+ */
+static int is_ejectable(acpi_handle handle)
+{
+	acpi_status status;
+	acpi_handle tmp;
+
+	status = acpi_get_handle(handle, "_EJ0", &tmp);
+	if (ACPI_FAILURE(status))
+		return 0;
+	return 1;
+}
+
+/**
+ * bay_present - see if the bay device is present
+ * @bay: the drive bay
+ *
+ * execute the _STA method.
+ */
+static int bay_present(struct bay *bay)
+{
+	unsigned long sta;
+	acpi_status status;
+
+	if (bay) {
+		status = acpi_evaluate_integer(bay->handle, "_STA", NULL, &sta);
+		if (ACPI_SUCCESS(status) && sta)
+			return 1;
+	}
+	return 0;
+}
+
+/**
+ * eject_device - respond to an eject request
+ * @handle - the device to eject
+ *
+ * Call this devices _EJ0 method.
+ */
+static void eject_device(acpi_handle handle)
+{
+	struct acpi_object_list arg_list;
+	union acpi_object arg;
+
+	bay_dprintk(handle, "Ejecting device");
+
+	arg_list.count = 1;
+	arg_list.pointer = &arg;
+	arg.type = ACPI_TYPE_INTEGER;
+	arg.integer.value = 1;
+
+	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
+					      &arg_list, NULL)))
+		pr_debug("Failed to evaluate _EJ0!\n");
+}
+
+/*
+ * show_present - read method for "present" file in sysfs
+ */
+static ssize_t show_present(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct bay *bay = dev_get_drvdata(dev);
+	return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay));
+
+}
+DEVICE_ATTR(present, S_IRUGO, show_present, NULL);
+
+/*
+ * write_eject - write method for "eject" file in sysfs
+ */
+static ssize_t write_eject(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct bay *bay = dev_get_drvdata(dev);
+
+	if (!count)
+		return -EINVAL;
+
+	eject_device(bay->handle);
+	return count;
+}
+DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject);
+
+/**
+ * is_ata - see if a device is an ata device
+ * @handle: acpi handle of the device
+ *
+ * If an acpi object has one of 4 ATA ACPI methods defined,
+ * then it is an ATA device
+ */
+static int is_ata(acpi_handle handle)
+{
+	acpi_handle tmp;
+
+	if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
+	   (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
+	   (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
+	   (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
+		return 1;
+
+	return 0;
+}
+
+/**
+ * parent_is_ata(acpi_handle handle)
+ *
+ */
+static int parent_is_ata(acpi_handle handle)
+{
+	acpi_handle phandle;
+
+	if (acpi_get_parent(handle, &phandle))
+		return 0;
+
+	return is_ata(phandle);
+}
+
+/**
+ * is_ejectable_bay - see if a device is an ejectable drive bay
+ * @handle: acpi handle of the device
+ *
+ * If an acpi object is ejectable and has one of the ACPI ATA
+ * methods defined, then we can safely call it an ejectable
+ * drive bay
+ */
+static int is_ejectable_bay(acpi_handle handle)
+{
+	if ((is_ata(handle) || parent_is_ata(handle)) && is_ejectable(handle))
+		return 1;
+	return 0;
+}
+
+/**
+ * eject_removable_drive - try to eject this drive
+ * @dev : the device structure of the drive
+ *
+ * If a device is a removable drive that requires an _EJ0 method
+ * to be executed in order to safely remove from the system, do
+ * it.  ATM - always returns success
+ */
+int eject_removable_drive(struct device *dev)
+{
+	acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
+
+	if (handle) {
+		bay_dprintk(handle, "Got device handle");
+		if (is_ejectable_bay(handle))
+			eject_device(handle);
+	} else {
+		printk("No acpi handle for device\n");
+	}
+
+	/* should I return an error code? */
+	return 0;
+}
+EXPORT_SYMBOL_GPL(eject_removable_drive);
+
+static int acpi_bay_add(struct acpi_device *device)
+{
+	bay_dprintk(device->handle, "adding bay device");
+	strcpy(acpi_device_name(device), "Dockable Bay");
+	strcpy(acpi_device_class(device), "bay");
+	return 0;
+}
+
+static int acpi_bay_add_fs(struct bay *bay)
+{
+	int ret;
+	struct device *dev = &bay->pdev->dev;
+
+	ret = device_create_file(dev, &dev_attr_present);
+	if (ret)
+		goto add_fs_err;
+	ret = device_create_file(dev, &dev_attr_eject);
+	if (ret) {
+		device_remove_file(dev, &dev_attr_present);
+		goto add_fs_err;
+	}
+	return 0;
+
+ add_fs_err:
+	bay_dprintk(bay->handle, "Error adding sysfs files\n");
+	return ret;
+}
+
+static void acpi_bay_remove_fs(struct bay *bay)
+{
+	struct device *dev = &bay->pdev->dev;
+
+	/* cleanup sysfs */
+	device_remove_file(dev, &dev_attr_present);
+	device_remove_file(dev, &dev_attr_eject);
+}
+
+static int bay_is_dock_device(acpi_handle handle)
+{
+	acpi_handle parent;
+
+	acpi_get_parent(handle, &parent);
+
+	/* if the device or it's parent is dependent on the
+	 * dock, then we are a dock device
+	 */
+	return (is_dock_device(handle) || is_dock_device(parent));
+}
+
+static int bay_add(acpi_handle handle, int id)
+{
+	acpi_status status;
+	struct bay *new_bay;
+	struct platform_device *pdev;
+	struct acpi_buffer nbuffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	acpi_get_name(handle, ACPI_FULL_PATHNAME, &nbuffer);
+
+	bay_dprintk(handle, "Adding notify handler");
+
+	/*
+	 * Initialize bay device structure
+	 */
+	new_bay = kzalloc(sizeof(*new_bay), GFP_ATOMIC);
+	INIT_LIST_HEAD(&new_bay->list);
+	new_bay->handle = handle;
+	new_bay->name = (char *)nbuffer.pointer;
+
+	/* initialize platform device stuff */
+	pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0);
+	if (pdev == NULL) {
+		printk(KERN_ERR PREFIX "Error registering bay device\n");
+		goto bay_add_err;
+	}
+	new_bay->pdev = pdev;
+	platform_set_drvdata(pdev, new_bay);
+
+	if (acpi_bay_add_fs(new_bay)) {
+		platform_device_unregister(new_bay->pdev);
+		goto bay_add_err;
+	}
+
+	/* register for events on this device */
+	status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+			bay_notify, new_bay);
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_ERR PREFIX "Error installing bay notify handler\n");
+	}
+
+	/* if we are on a dock station, we should register for dock
+	 * notifications.
+	 */
+	if (bay_is_dock_device(handle)) {
+		bay_dprintk(handle, "Is dependent on dock\n");
+		register_hotplug_dock_device(handle, bay_notify, new_bay);
+	}
+	list_add(&new_bay->list, &drive_bays);
+	printk(KERN_INFO PREFIX "Bay [%s] Added\n", new_bay->name);
+	return 0;
+
+bay_add_err:
+	kfree(new_bay->name);
+	kfree(new_bay);
+	return -ENODEV;
+}
+
+static int acpi_bay_remove(struct acpi_device *device, int type)
+{
+	/*** FIXME: do something here */
+	return 0;
+}
+
+/**
+ * bay_create_acpi_device - add new devices to acpi
+ * @handle - handle of the device to add
+ *
+ *  This function will create a new acpi_device for the given
+ *  handle if one does not exist already.  This should cause
+ *  acpi to scan for drivers for the given devices, and call
+ *  matching driver's add routine.
+ *
+ *  Returns a pointer to the acpi_device corresponding to the handle.
+ */
+static struct acpi_device * bay_create_acpi_device(acpi_handle handle)
+{
+	struct acpi_device *device = NULL;
+	struct acpi_device *parent_device;
+	acpi_handle parent;
+	int ret;
+
+	bay_dprintk(handle, "Trying to get device");
+	if (acpi_bus_get_device(handle, &device)) {
+		/*
+		 * no device created for this object,
+		 * so we should create one.
+		 */
+		bay_dprintk(handle, "No device for handle");
+		acpi_get_parent(handle, &parent);
+		if (acpi_bus_get_device(parent, &parent_device))
+			parent_device = NULL;
+
+		ret = acpi_bus_add(&device, parent_device, handle,
+			ACPI_BUS_TYPE_DEVICE);
+		if (ret) {
+			pr_debug("error adding bus, %x\n",
+				-ret);
+			return NULL;
+		}
+	}
+	return device;
+}
+
+/**
+ * bay_notify - act upon an acpi bay notification
+ * @handle: the bay handle
+ * @event: the acpi event
+ * @data: our driver data struct
+ *
+ */
+static void bay_notify(acpi_handle handle, u32 event, void *data)
+{
+	struct acpi_device *dev;
+
+	bay_dprintk(handle, "Bay event");
+
+	switch(event) {
+	case ACPI_NOTIFY_BUS_CHECK:
+		printk("Bus Check\n");
+	case ACPI_NOTIFY_DEVICE_CHECK:
+		printk("Device Check\n");
+		dev = bay_create_acpi_device(handle);
+		if (dev)
+			acpi_bus_generate_event(dev, event, 0);
+		else
+			printk("No device for generating event\n");
+		/* wouldn't it be a good idea to just rescan SATA
+		 * right here?
+		 */
+		break;
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		printk("Eject request\n");
+		dev = bay_create_acpi_device(handle);
+		if (dev)
+			acpi_bus_generate_event(dev, event, 0);
+		else
+			printk("No device for generating eventn");
+
+		/* wouldn't it be a good idea to just call the
+		 * eject_device here if we were a SATA device?
+		 */
+		break;
+	default:
+		printk("unknown event %d\n", event);
+	}
+}
+
+static acpi_status
+find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+	int *count = (int *)context;
+
+	/*
+	 * there could be more than one ejectable bay.
+	 * so, just return AE_OK always so that every object
+	 * will be checked.
+	 */
+	if (is_ejectable_bay(handle)) {
+		bay_dprintk(handle, "found ejectable bay");
+		if (!bay_add(handle, *count))
+			(*count)++;
+	}
+	return AE_OK;
+}
+
+static int __init bay_init(void)
+{
+	int bays = 0;
+
+	INIT_LIST_HEAD(&drive_bays);
+
+	/* look for dockable drive bays */
+	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+		ACPI_UINT32_MAX, find_bay, &bays, NULL);
+
+	if (bays)
+		if ((acpi_bus_register_driver(&acpi_bay_driver) < 0))
+			printk(KERN_ERR "Unable to register bay driver\n");
+
+	if (!bays)
+		return -ENODEV;
+
+	return 0;
+}
+
+static void __exit bay_exit(void)
+{
+	struct bay *bay, *tmp;
+
+	list_for_each_entry_safe(bay, tmp, &drive_bays, list) {
+		if (is_dock_device(bay->handle))
+			unregister_hotplug_dock_device(bay->handle);
+		acpi_bay_remove_fs(bay);
+		acpi_remove_notify_handler(bay->handle, ACPI_SYSTEM_NOTIFY,
+			bay_notify);
+		platform_device_unregister(bay->pdev);
+		kfree(bay->name);
+		kfree(bay);
+	}
+
+	acpi_bus_unregister_driver(&acpi_bay_driver);
+}
+
+postcore_initcall(bay_init);
+module_exit(bay_exit);
+
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index f9c972b..f289fd4 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -44,7 +44,7 @@
 	char oem_id[7];
 	char oem_table_id[9];
 	u32 oem_revision;
-	acpi_table_type table;
+	char *table;
 	enum acpi_blacklist_predicates oem_revision_predicate;
 	char *reason;
 	u32 is_critical_error;
@@ -56,18 +56,18 @@
  */
 static struct acpi_blacklist_item acpi_blacklist[] __initdata = {
 	/* Compaq Presario 1700 */
-	{"PTLTD ", "  DSDT  ", 0x06040000, ACPI_DSDT, less_than_or_equal,
+	{"PTLTD ", "  DSDT  ", 0x06040000, ACPI_SIG_DSDT, less_than_or_equal,
 	 "Multiple problems", 1},
 	/* Sony FX120, FX140, FX150? */
-	{"SONY  ", "U0      ", 0x20010313, ACPI_DSDT, less_than_or_equal,
+	{"SONY  ", "U0      ", 0x20010313, ACPI_SIG_DSDT, less_than_or_equal,
 	 "ACPI driver problem", 1},
 	/* Compaq Presario 800, Insyde BIOS */
-	{"INT440", "SYSFexxx", 0x00001001, ACPI_DSDT, less_than_or_equal,
+	{"INT440", "SYSFexxx", 0x00001001, ACPI_SIG_DSDT, less_than_or_equal,
 	 "Does not use _REG to protect EC OpRegions", 1},
 	/* IBM 600E - _ADR should return 7, but it returns 1 */
-	{"IBM   ", "TP600E  ", 0x00000105, ACPI_DSDT, less_than_or_equal,
+	{"IBM   ", "TP600E  ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal,
 	 "Incorrect _ADR", 1},
-	{"ASUS\0\0", "P2B-S   ", 0, ACPI_DSDT, all_versions,
+	{"ASUS\0\0", "P2B-S   ", 0, ACPI_SIG_DSDT, all_versions,
 	 "Bogus PCI routing", 1},
 
 	{""}
@@ -79,7 +79,7 @@
 {
 	int year = dmi_get_year(DMI_BIOS_DATE);
 	/* Doesn't exist? Likely an old system */
-	if (year == -1) 
+	if (year == -1)
 		return 1;
 	/* 0? Likely a buggy new BIOS */
 	if (year == 0)
@@ -103,22 +103,21 @@
 {
 	int i = 0;
 	int blacklisted = 0;
-	struct acpi_table_header *table_header;
+	struct acpi_table_header table_header;
 
 	while (acpi_blacklist[i].oem_id[0] != '\0') {
-		if (acpi_get_table_header_early
-		    (acpi_blacklist[i].table, &table_header)) {
+		if (acpi_get_table_header(acpi_blacklist[i].table, 0, &table_header)) {
 			i++;
 			continue;
 		}
 
-		if (strncmp(acpi_blacklist[i].oem_id, table_header->oem_id, 6)) {
+		if (strncmp(acpi_blacklist[i].oem_id, table_header.oem_id, 6)) {
 			i++;
 			continue;
 		}
 
 		if (strncmp
-		    (acpi_blacklist[i].oem_table_id, table_header->oem_table_id,
+		    (acpi_blacklist[i].oem_table_id, table_header.oem_table_id,
 		     8)) {
 			i++;
 			continue;
@@ -127,14 +126,14 @@
 		if ((acpi_blacklist[i].oem_revision_predicate == all_versions)
 		    || (acpi_blacklist[i].oem_revision_predicate ==
 			less_than_or_equal
-			&& table_header->oem_revision <=
+			&& table_header.oem_revision <=
 			acpi_blacklist[i].oem_revision)
 		    || (acpi_blacklist[i].oem_revision_predicate ==
 			greater_than_or_equal
-			&& table_header->oem_revision >=
+			&& table_header.oem_revision >=
 			acpi_blacklist[i].oem_revision)
 		    || (acpi_blacklist[i].oem_revision_predicate == equal
-			&& table_header->oem_revision ==
+			&& table_header.oem_revision ==
 			acpi_blacklist[i].oem_revision)) {
 
 			printk(KERN_ERR PREFIX
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 766332e..c26468d 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -44,9 +44,6 @@
 extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger);
 #endif
 
-struct fadt_descriptor acpi_fadt;
-EXPORT_SYMBOL(acpi_fadt);
-
 struct acpi_device *acpi_root;
 struct proc_dir_entry *acpi_root_dir;
 EXPORT_SYMBOL(acpi_root_dir);
@@ -195,7 +192,7 @@
 
 	if (!device->flags.power_manageable) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
-				device->kobj.name));
+				device->dev.kobj.name));
 		return -ENODEV;
 	}
 	/*
@@ -582,11 +579,12 @@
 	return 0;
 }
 
+acpi_native_uint acpi_gbl_permanent_mmap;
+
+
 void __init acpi_early_init(void)
 {
 	acpi_status status = AE_OK;
-	struct acpi_buffer buffer = { sizeof(acpi_fadt), &acpi_fadt };
-
 
 	if (acpi_disabled)
 		return;
@@ -597,6 +595,15 @@
 	if (!acpi_strict)
 		acpi_gbl_enable_interpreter_slack = TRUE;
 
+	acpi_gbl_permanent_mmap = 1;
+
+	status = acpi_reallocate_root_table();
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_ERR PREFIX
+		       "Unable to reallocate ACPI tables\n");
+		goto error0;
+	}
+
 	status = acpi_initialize_subsystem();
 	if (ACPI_FAILURE(status)) {
 		printk(KERN_ERR PREFIX
@@ -611,32 +618,25 @@
 		goto error0;
 	}
 
-	/*
-	 * Get a separate copy of the FADT for use by other drivers.
-	 */
-	status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &buffer);
-	if (ACPI_FAILURE(status)) {
-		printk(KERN_ERR PREFIX "Unable to get the FADT\n");
-		goto error0;
-	}
 #ifdef CONFIG_X86
 	if (!acpi_ioapic) {
-		extern acpi_interrupt_flags acpi_sci_flags;
+		extern u8 acpi_sci_flags;
 
 		/* compatible (0) means level (3) */
-		if (acpi_sci_flags.trigger == 0)
-			acpi_sci_flags.trigger = 3;
-
+		if (!(acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)) {
+			acpi_sci_flags &= ~ACPI_MADT_TRIGGER_MASK;
+			acpi_sci_flags |= ACPI_MADT_TRIGGER_LEVEL;
+		}
 		/* Set PIC-mode SCI trigger type */
-		acpi_pic_sci_set_trigger(acpi_fadt.sci_int,
-					 acpi_sci_flags.trigger);
+		acpi_pic_sci_set_trigger(acpi_gbl_FADT.sci_interrupt,
+					 (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2);
 	} else {
 		extern int acpi_sci_override_gsi;
 		/*
-		 * now that acpi_fadt is initialized,
+		 * now that acpi_gbl_FADT is initialized,
 		 * update it with result from INT_SRC_OVR parsing
 		 */
-		acpi_fadt.sci_int = acpi_sci_override_gsi;
+		acpi_gbl_FADT.sci_interrupt = acpi_sci_override_gsi;
 	}
 #endif
 
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index ac86058..c726612 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -75,7 +75,7 @@
 static struct acpi_driver acpi_button_driver = {
 	.name = ACPI_BUTTON_DRIVER_NAME,
 	.class = ACPI_BUTTON_CLASS,
-	.ids = "ACPI_FPB,ACPI_FSB,PNP0C0D,PNP0C0C,PNP0C0E",
+	.ids = "button_power,button_sleep,PNP0C0D,PNP0C0C,PNP0C0E",
 	.ops = {
 		.add = acpi_button_add,
 		.remove = acpi_button_remove,
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 0a1863e..69a68fd 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -167,7 +167,7 @@
 			if (ACPI_FAILURE(status) || !device) {
 				result = container_device_add(&device, handle);
 				if (!result)
-					kobject_uevent(&device->kobj,
+					kobject_uevent(&device->dev.kobj,
 						       KOBJ_ONLINE);
 				else
 					printk("Failed to add container\n");
@@ -175,13 +175,13 @@
 		} else {
 			if (ACPI_SUCCESS(status)) {
 				/* device exist and this is a remove request */
-				kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+				kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
 			}
 		}
 		break;
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		if (!acpi_bus_get_device(handle, &device) && device) {
-			kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+			kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
 		}
 		break;
 	default:
diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c
index 35c6af8..d48f65a 100644
--- a/drivers/acpi/debug.c
+++ b/drivers/acpi/debug.c
@@ -13,14 +13,11 @@
 
 #define _COMPONENT		ACPI_SYSTEM_COMPONENT
 ACPI_MODULE_NAME("debug")
-#define ACPI_SYSTEM_FILE_DEBUG_LAYER	"debug_layer"
-#define ACPI_SYSTEM_FILE_DEBUG_LEVEL	"debug_level"
+
 #ifdef MODULE_PARAM_PREFIX
 #undef MODULE_PARAM_PREFIX
 #endif
-#define MODULE_PARAM_PREFIX
-    module_param(acpi_dbg_layer, uint, 0400);
-module_param(acpi_dbg_level, uint, 0400);
+#define MODULE_PARAM_PREFIX "acpi."
 
 struct acpi_dlayer {
 	const char *name;
@@ -86,6 +83,60 @@
 	ACPI_DEBUG_INIT(ACPI_LV_EVENTS),
 };
 
+/* --------------------------------------------------------------------------
+                              FS Interface (/sys)
+   -------------------------------------------------------------------------- */
+static int param_get_debug_layer(char *buffer, struct kernel_param *kp) {
+	int result = 0;
+	int i;
+
+	result = sprintf(buffer, "%-25s\tHex        SET\n", "Description");
+
+	for(i = 0; i <ARRAY_SIZE(acpi_debug_layers); i++) {
+		result += sprintf(buffer+result, "%-25s\t0x%08lX [%c]\n",
+					acpi_debug_layers[i].name,
+					acpi_debug_layers[i].value,
+					(acpi_dbg_layer & acpi_debug_layers[i].value) ? '*' : ' ');
+	}
+	result += sprintf(buffer+result, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS",
+					ACPI_ALL_DRIVERS,
+					(acpi_dbg_layer & ACPI_ALL_DRIVERS) ==
+					ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer &
+					ACPI_ALL_DRIVERS) == 0 ? ' ' : '-');
+	result += sprintf(buffer+result, "--\ndebug_layer = 0x%08X ( * = enabled)\n", acpi_dbg_layer);
+
+	return result;
+}
+
+static int param_get_debug_level(char *buffer, struct kernel_param *kp) {
+	int result = 0;
+	int i;
+
+	result = sprintf(buffer, "%-25s\tHex        SET\n", "Description");
+
+	for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) {
+		result += sprintf(buffer+result, "%-25s\t0x%08lX [%c]\n",
+				     acpi_debug_levels[i].name,
+				     acpi_debug_levels[i].value,
+				     (acpi_dbg_level & acpi_debug_levels[i].
+				      value) ? '*' : ' ');
+	}
+	result += sprintf(buffer+result, "--\ndebug_level = 0x%08X (* = enabled)\n",
+			     acpi_dbg_level);
+
+	return result;
+}
+
+module_param_call(debug_layer, param_set_uint, param_get_debug_layer, &acpi_dbg_layer, 0644);
+module_param_call(debug_level, param_set_uint, param_get_debug_level, &acpi_dbg_level, 0644);
+
+/* --------------------------------------------------------------------------
+                              FS Interface (/proc)
+   -------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROCFS
+#define ACPI_SYSTEM_FILE_DEBUG_LAYER	"debug_layer"
+#define ACPI_SYSTEM_FILE_DEBUG_LEVEL		"debug_level"
+
 static int
 acpi_system_read_debug(char *page,
 		       char **start, off_t off, int count, int *eof, void *data)
@@ -221,3 +272,4 @@
 }
 
 subsys_initcall(acpi_debug_init);
+#endif
diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c
index a6d77ef..f049639 100644
--- a/drivers/acpi/dispatcher/dsfield.c
+++ b/drivers/acpi/dispatcher/dsfield.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -133,7 +133,8 @@
 		}
 	}
 
-	/* We could put the returned object (Node) on the object stack for later,
+	/*
+	 * We could put the returned object (Node) on the object stack for later,
 	 * but for now, we will put it in the "op" object that the parser uses,
 	 * so we can get it again at the end of this scope
 	 */
@@ -514,8 +515,33 @@
 
 	/* Third arg is the bank_value */
 
+	/* TBD: This arg is a term_arg, not a constant, and must be evaluated */
+
 	arg = arg->common.next;
-	info.bank_value = (u32) arg->common.value.integer;
+
+	/* Currently, only the following constants are supported */
+
+	switch (arg->common.aml_opcode) {
+	case AML_ZERO_OP:
+		info.bank_value = 0;
+		break;
+
+	case AML_ONE_OP:
+		info.bank_value = 1;
+		break;
+
+	case AML_BYTE_OP:
+	case AML_WORD_OP:
+	case AML_DWORD_OP:
+	case AML_QWORD_OP:
+		info.bank_value = (u32) arg->common.value.integer;
+		break;
+
+	default:
+		info.bank_value = 0;
+		ACPI_ERROR((AE_INFO,
+			    "Non-constant BankValue for BankField is not implemented"));
+	}
 
 	/* Fourth arg is the field flags */
 
diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c
index 1888c05..af923c3 100644
--- a/drivers/acpi/dispatcher/dsinit.c
+++ b/drivers/acpi/dispatcher/dsinit.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
 #include <acpi/acpi.h>
 #include <acpi/acdispat.h>
 #include <acpi/acnamesp.h>
+#include <acpi/actables.h>
 
 #define _COMPONENT          ACPI_DISPATCHER
 ACPI_MODULE_NAME("dsinit")
@@ -90,7 +91,7 @@
 	 * We are only interested in NS nodes owned by the table that
 	 * was just loaded
 	 */
-	if (node->owner_id != info->table_desc->owner_id) {
+	if (node->owner_id != info->owner_id) {
 		return (AE_OK);
 	}
 
@@ -150,14 +151,21 @@
  ******************************************************************************/
 
 acpi_status
-acpi_ds_initialize_objects(struct acpi_table_desc * table_desc,
+acpi_ds_initialize_objects(acpi_native_uint table_index,
 			   struct acpi_namespace_node * start_node)
 {
 	acpi_status status;
 	struct acpi_init_walk_info info;
+	struct acpi_table_header *table;
+	acpi_owner_id owner_id;
 
 	ACPI_FUNCTION_TRACE(ds_initialize_objects);
 
+	status = acpi_tb_get_owner_id(table_index, &owner_id);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
 	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
 			  "**** Starting initialization of namespace objects ****\n"));
 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "Parsing all Control Methods:"));
@@ -166,7 +174,8 @@
 	info.op_region_count = 0;
 	info.object_count = 0;
 	info.device_count = 0;
-	info.table_desc = table_desc;
+	info.table_index = table_index;
+	info.owner_id = owner_id;
 
 	/* Walk entire namespace from the supplied root */
 
@@ -176,10 +185,14 @@
 		ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace"));
 	}
 
+	status = acpi_get_table_by_index(table_index, &table);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
 			      "\nTable [%4.4s](id %4.4X) - %hd Objects with %hd Devices %hd Methods %hd Regions\n",
-			      table_desc->pointer->signature,
-			      table_desc->owner_id, info.object_count,
+			      table->signature, owner_id, info.object_count,
 			      info.device_count, info.method_count,
 			      info.op_region_count));
 
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
index cf888ad..1cbe619 100644
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -327,7 +327,7 @@
 	ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state);
 
 	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
-			  "Execute method %p, currentstate=%p\n",
+			  "Calling method %p, currentstate=%p\n",
 			  this_walk_state->prev_op, this_walk_state));
 
 	/*
@@ -351,49 +351,7 @@
 		return_ACPI_STATUS(status);
 	}
 
-	/*
-	 * 1) Parse the method. All "normal" methods are parsed for each execution.
-	 * Internal methods (_OSI, etc.) do not require parsing.
-	 */
-	if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) {
-
-		/* Create a new walk state for the parse */
-
-		next_walk_state =
-		    acpi_ds_create_walk_state(obj_desc->method.owner_id, op,
-					      obj_desc, NULL);
-		if (!next_walk_state) {
-			status = AE_NO_MEMORY;
-			goto cleanup;
-		}
-
-		/* Create and init a parse tree root */
-
-		op = acpi_ps_create_scope_op();
-		if (!op) {
-			status = AE_NO_MEMORY;
-			goto cleanup;
-		}
-
-		status = acpi_ds_init_aml_walk(next_walk_state, op, method_node,
-					       obj_desc->method.aml_start,
-					       obj_desc->method.aml_length,
-					       NULL, 1);
-		if (ACPI_FAILURE(status)) {
-			acpi_ps_delete_parse_tree(op);
-			goto cleanup;
-		}
-
-		/* Begin AML parse (deletes next_walk_state) */
-
-		status = acpi_ps_parse_aml(next_walk_state);
-		acpi_ps_delete_parse_tree(op);
-		if (ACPI_FAILURE(status)) {
-			goto cleanup;
-		}
-	}
-
-	/* 2) Begin method execution. Create a new walk state */
+	/* Begin method parse/execution. Create a new walk state */
 
 	next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id,
 						    NULL, obj_desc, thread);
@@ -424,7 +382,8 @@
 
 	status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node,
 				       obj_desc->method.aml_start,
-				       obj_desc->method.aml_length, info, 3);
+				       obj_desc->method.aml_length, info,
+				       ACPI_IMODE_EXECUTE);
 
 	ACPI_FREE(info);
 	if (ACPI_FAILURE(status)) {
@@ -445,8 +404,8 @@
 	this_walk_state->num_operands = 0;
 
 	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
-			  "Starting nested execution, newstate=%p\n",
-			  next_walk_state));
+			  "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
+			  method_node->name.ascii, next_walk_state));
 
 	/* Invoke an internal method if necessary */
 
diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c
index 459160f..ba4626e 100644
--- a/drivers/acpi/dispatcher/dsmthdat.c
+++ b/drivers/acpi/dispatcher/dsmthdat.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
index 72190ab..a474ca2 100644
--- a/drivers/acpi/dispatcher/dsobject.c
+++ b/drivers/acpi/dispatcher/dsobject.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -260,7 +260,7 @@
 	}
 
 	obj_desc->buffer.flags |= AOPOBJ_DATA_VALID;
-	op->common.node = (struct acpi_namespace_node *)obj_desc;
+	op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc);
 	return_ACPI_STATUS(AE_OK);
 }
 
@@ -270,7 +270,8 @@
  *
  * PARAMETERS:  walk_state      - Current walk state
  *              Op              - Parser object to be translated
- *              package_length  - Number of elements in the package
+ *              element_count   - Number of elements in the package - this is
+ *                                the num_elements argument to Package()
  *              obj_desc_ptr    - Where the ACPI internal object is returned
  *
  * RETURN:      Status
@@ -278,18 +279,29 @@
  * DESCRIPTION: Translate a parser Op package object to the equivalent
  *              namespace object
  *
+ * NOTE: The number of elements in the package will be always be the num_elements
+ * count, regardless of the number of elements in the package list. If
+ * num_elements is smaller, only that many package list elements are used.
+ * if num_elements is larger, the Package object is padded out with
+ * objects of type Uninitialized (as per ACPI spec.)
+ *
+ * Even though the ASL compilers do not allow num_elements to be smaller
+ * than the Package list length (for the fixed length package opcode), some
+ * BIOS code modifies the AML on the fly to adjust the num_elements, and
+ * this code compensates for that. This also provides compatibility with
+ * other AML interpreters.
+ *
  ******************************************************************************/
 
 acpi_status
 acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
 				   union acpi_parse_object *op,
-				   u32 package_length,
+				   u32 element_count,
 				   union acpi_operand_object **obj_desc_ptr)
 {
 	union acpi_parse_object *arg;
 	union acpi_parse_object *parent;
 	union acpi_operand_object *obj_desc = NULL;
-	u32 package_list_length;
 	acpi_status status = AE_OK;
 	acpi_native_uint i;
 
@@ -318,32 +330,13 @@
 		obj_desc->package.node = parent->common.node;
 	}
 
-	obj_desc->package.count = package_length;
-
-	/* Count the number of items in the package list */
-
-	arg = op->common.value.arg;
-	arg = arg->common.next;
-	for (package_list_length = 0; arg; package_list_length++) {
-		arg = arg->common.next;
-	}
-
 	/*
-	 * The package length (number of elements) will be the greater
-	 * of the specified length and the length of the initializer list
-	 */
-	if (package_list_length > package_length) {
-		obj_desc->package.count = package_list_length;
-	}
-
-	/*
-	 * Allocate the pointer array (array of pointers to the
-	 * individual objects). Add an extra pointer slot so
-	 * that the list is always null terminated.
+	 * Allocate the element array (array of pointers to the individual
+	 * objects) based on the num_elements parameter. Add an extra pointer slot
+	 * so that the list is always null terminated.
 	 */
 	obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size)
-							   obj_desc->package.
-							   count +
+							   element_count +
 							   1) * sizeof(void *));
 
 	if (!obj_desc->package.elements) {
@@ -351,15 +344,20 @@
 		return_ACPI_STATUS(AE_NO_MEMORY);
 	}
 
+	obj_desc->package.count = element_count;
+
 	/*
-	 * Initialize all elements of the package
+	 * Initialize the elements of the package, up to the num_elements count.
+	 * Package is automatically padded with uninitialized (NULL) elements
+	 * if num_elements is greater than the package list length. Likewise,
+	 * Package is truncated if num_elements is less than the list length.
 	 */
 	arg = op->common.value.arg;
 	arg = arg->common.next;
-	for (i = 0; arg; i++) {
+	for (i = 0; arg && (i < element_count); i++) {
 		if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {
 
-			/* Object (package or buffer) is already built */
+			/* This package element is already built, just get it */
 
 			obj_desc->package.elements[i] =
 			    ACPI_CAST_PTR(union acpi_operand_object,
@@ -373,8 +371,14 @@
 		arg = arg->common.next;
 	}
 
+	if (!arg) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				  "Package List length larger than NumElements count (%X), truncated\n",
+				  element_count));
+	}
+
 	obj_desc->package.flags |= AOPOBJ_DATA_VALID;
-	op->common.node = (struct acpi_namespace_node *)obj_desc;
+	op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc);
 	return_ACPI_STATUS(status);
 }
 
@@ -488,8 +492,9 @@
 		/*
 		 * Defer evaluation of Buffer term_arg operand
 		 */
-		obj_desc->buffer.node = (struct acpi_namespace_node *)
-		    walk_state->operands[0];
+		obj_desc->buffer.node =
+		    ACPI_CAST_PTR(struct acpi_namespace_node,
+				  walk_state->operands[0]);
 		obj_desc->buffer.aml_start = op->named.data;
 		obj_desc->buffer.aml_length = op->named.length;
 		break;
@@ -499,8 +504,9 @@
 		/*
 		 * Defer evaluation of Package term_arg operand
 		 */
-		obj_desc->package.node = (struct acpi_namespace_node *)
-		    walk_state->operands[0];
+		obj_desc->package.node =
+		    ACPI_CAST_PTR(struct acpi_namespace_node,
+				  walk_state->operands[0]);
 		obj_desc->package.aml_start = op->named.data;
 		obj_desc->package.aml_length = op->named.length;
 		break;
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
index 5b974a8..6c6104a 100644
--- a/drivers/acpi/dispatcher/dsopcode.c
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -114,7 +114,7 @@
 	}
 
 	status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start,
-				       aml_length, NULL, 1);
+				       aml_length, NULL, ACPI_IMODE_LOAD_PASS1);
 	if (ACPI_FAILURE(status)) {
 		acpi_ds_delete_walk_state(walk_state);
 		goto cleanup;
@@ -157,7 +157,7 @@
 	/* Execute the opcode and arguments */
 
 	status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start,
-				       aml_length, NULL, 3);
+				       aml_length, NULL, ACPI_IMODE_EXECUTE);
 	if (ACPI_FAILURE(status)) {
 		acpi_ds_delete_walk_state(walk_state);
 		goto cleanup;
diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c
index 05230ba..e4073e0 100644
--- a/drivers/acpi/dispatcher/dsutils.c
+++ b/drivers/acpi/dispatcher/dsutils.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
index d7a616c..69693fa 100644
--- a/drivers/acpi/dispatcher/dswexec.c
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -219,7 +219,7 @@
 	if (!op) {
 		status = acpi_ds_load2_begin_op(walk_state, out_op);
 		if (ACPI_FAILURE(status)) {
-			return_ACPI_STATUS(status);
+			goto error_exit;
 		}
 
 		op = *out_op;
@@ -238,7 +238,7 @@
 
 			status = acpi_ds_scope_stack_pop(walk_state);
 			if (ACPI_FAILURE(status)) {
-				return_ACPI_STATUS(status);
+				goto error_exit;
 			}
 		}
 	}
@@ -287,7 +287,7 @@
 
 		status = acpi_ds_result_stack_push(walk_state);
 		if (ACPI_FAILURE(status)) {
-			return_ACPI_STATUS(status);
+			goto error_exit;
 		}
 
 		status = acpi_ds_exec_begin_control_op(walk_state, op);
@@ -328,6 +328,10 @@
 	/* Nothing to do here during method execution */
 
 	return_ACPI_STATUS(status);
+
+      error_exit:
+	status = acpi_ds_method_error(status, walk_state);
+	return_ACPI_STATUS(status);
 }
 
 /*****************************************************************************
diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
index e3ca7f6..8ab9d1b 100644
--- a/drivers/acpi/dispatcher/dswload.c
+++ b/drivers/acpi/dispatcher/dswload.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -196,6 +196,7 @@
 		 * one of the opcodes that actually opens a scope
 		 */
 		switch (node->type) {
+		case ACPI_TYPE_ANY:
 		case ACPI_TYPE_LOCAL_SCOPE:	/* Scope  */
 		case ACPI_TYPE_DEVICE:
 		case ACPI_TYPE_POWER:
@@ -546,6 +547,7 @@
 	acpi_status status;
 	acpi_object_type object_type;
 	char *buffer_ptr;
+	u32 flags;
 
 	ACPI_FUNCTION_TRACE(ds_load2_begin_op);
 
@@ -669,6 +671,7 @@
 		 * one of the opcodes that actually opens a scope
 		 */
 		switch (node->type) {
+		case ACPI_TYPE_ANY:
 		case ACPI_TYPE_LOCAL_SCOPE:	/* Scope */
 		case ACPI_TYPE_DEVICE:
 		case ACPI_TYPE_POWER:
@@ -750,12 +753,20 @@
 			break;
 		}
 
-		/* Add new entry into namespace */
+		flags = ACPI_NS_NO_UPSEARCH;
+		if (walk_state->pass_number == ACPI_IMODE_EXECUTE) {
+
+			/* Execution mode, node cannot already exist, node is temporary */
+
+			flags |= (ACPI_NS_ERROR_IF_FOUND | ACPI_NS_TEMPORARY);
+		}
+
+		/* Add new entry or lookup existing entry */
 
 		status =
 		    acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
-				   object_type, ACPI_IMODE_LOAD_PASS2,
-				   ACPI_NS_NO_UPSEARCH, walk_state, &(node));
+				   object_type, ACPI_IMODE_LOAD_PASS2, flags,
+				   walk_state, &node);
 		break;
 	}
 
diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c
index c922897..3927c49 100644
--- a/drivers/acpi/dispatcher/dswscope.c
+++ b/drivers/acpi/dispatcher/dswscope.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c
index 7817e55..16c8e38 100644
--- a/drivers/acpi/dispatcher/dswstate.c
+++ b/drivers/acpi/dispatcher/dswstate.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 90990a4..688e83a 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -615,20 +615,28 @@
 find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
 	acpi_status status;
-	acpi_handle tmp;
+	acpi_handle tmp, parent;
 	struct dock_station *ds = context;
 	struct dock_dependent_device *dd;
 
 	status = acpi_bus_get_ejd(handle, &tmp);
-	if (ACPI_FAILURE(status))
-		return AE_OK;
+	if (ACPI_FAILURE(status)) {
+		/* try the parent device as well */
+		status = acpi_get_parent(handle, &parent);
+		if (ACPI_FAILURE(status))
+			goto fdd_out;
+		/* see if parent is dependent on dock */
+		status = acpi_bus_get_ejd(parent, &tmp);
+		if (ACPI_FAILURE(status))
+			goto fdd_out;
+	}
 
 	if (tmp == ds->handle) {
 		dd = alloc_dock_dependent_device(handle);
 		if (dd)
 			add_dock_dependent_device(ds, dd);
 	}
-
+fdd_out:
 	return AE_OK;
 }
 
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index cbdf031..743ce27 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -872,9 +872,8 @@
 	acpi_status status;
 	struct acpi_table_ecdt *ecdt_ptr;
 
-	status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
-					 (struct acpi_table_header **)
-					 &ecdt_ptr);
+	status = acpi_get_table(ACPI_SIG_ECDT, 1,
+				(struct acpi_table_header **)&ecdt_ptr);
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
@@ -891,14 +890,14 @@
 	if (acpi_ec_mode == EC_INTR) {
 		init_waitqueue_head(&ec_ecdt->wait);
 	}
-	ec_ecdt->command_addr = ecdt_ptr->ec_control.address;
-	ec_ecdt->data_addr = ecdt_ptr->ec_data.address;
-	ec_ecdt->gpe = ecdt_ptr->gpe_bit;
+	ec_ecdt->command_addr = ecdt_ptr->control.address;
+	ec_ecdt->data_addr = ecdt_ptr->data.address;
+	ec_ecdt->gpe = ecdt_ptr->gpe;
 	/* use the GL just to be safe */
 	ec_ecdt->global_lock = TRUE;
 	ec_ecdt->uid = ecdt_ptr->uid;
 
-	status = acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle);
+	status = acpi_get_handle(NULL, ecdt_ptr->id, &ec_ecdt->handle);
 	if (ACPI_FAILURE(status)) {
 		goto error;
 	}
diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
index 919037d..a1f87b5 100644
--- a/drivers/acpi/events/evevent.c
+++ b/drivers/acpi/events/evevent.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -70,13 +70,6 @@
 
 	ACPI_FUNCTION_TRACE(ev_initialize_events);
 
-	/* Make sure we have ACPI tables */
-
-	if (!acpi_gbl_DSDT) {
-		ACPI_WARNING((AE_INFO, "No ACPI tables present!"));
-		return_ACPI_STATUS(AE_NO_ACPI_TABLES);
-	}
-
 	/*
 	 * Initialize the Fixed and General Purpose Events. This is done prior to
 	 * enabling SCIs to prevent interrupts from occurring before the handlers are
@@ -211,8 +204,7 @@
 		if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) {
 			status =
 			    acpi_set_register(acpi_gbl_fixed_event_info[i].
-					      enable_register_id, 0,
-					      ACPI_MTX_LOCK);
+					      enable_register_id, 0);
 			if (ACPI_FAILURE(status)) {
 				return (status);
 			}
@@ -298,7 +290,7 @@
 	/* Clear the status bit */
 
 	(void)acpi_set_register(acpi_gbl_fixed_event_info[event].
-				status_register_id, 1, ACPI_MTX_DO_NOT_LOCK);
+				status_register_id, 1);
 
 	/*
 	 * Make sure we've got a handler.  If not, report an error.
@@ -306,8 +298,7 @@
 	 */
 	if (NULL == acpi_gbl_fixed_event_handlers[event].handler) {
 		(void)acpi_set_register(acpi_gbl_fixed_event_info[event].
-					enable_register_id, 0,
-					ACPI_MTX_DO_NOT_LOCK);
+					enable_register_id, 0);
 
 		ACPI_ERROR((AE_INFO,
 			    "No installed handler for fixed event [%08X]",
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
index c76c058..dfac3ec 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/events/evgpe.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -121,7 +121,9 @@
 	if (!gpe_register_info) {
 		return_ACPI_STATUS(AE_NOT_EXIST);
 	}
-	register_bit = gpe_event_info->register_bit;
+	register_bit = (u8)
+	    (1 <<
+	     (gpe_event_info->gpe_number - gpe_register_info->base_gpe_number));
 
 	/* 1) Disable case.  Simply clear all enable bits */
 
@@ -458,8 +460,7 @@
 
 				/* Examine one GPE bit */
 
-				if (enabled_status_byte &
-				    acpi_gbl_decode_to8bit[j]) {
+				if (enabled_status_byte & (1 << j)) {
 					/*
 					 * Found an active GPE. Dispatch the event to a handler
 					 * or method.
@@ -570,7 +571,7 @@
 
 		if (ACPI_FAILURE(status)) {
 			ACPI_EXCEPTION((AE_INFO, status,
-					"While evaluating GPE method [%4.4s]",
+					"while evaluating GPE method [%4.4s]",
 					acpi_ut_get_node_name
 					(local_gpe_event_info.dispatch.
 					 method_node)));
@@ -618,6 +619,8 @@
 
 	ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
 
+	acpi_gpe_count++;
+
 	/*
 	 * If edge-triggered, clear the GPE status bit now.  Note that
 	 * level-triggered events are cleared after the GPE is serviced.
@@ -633,20 +636,23 @@
 		}
 	}
 
-	/* Save current system state */
-
-	if (acpi_gbl_system_awake_and_running) {
-		ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING);
-	} else {
-		ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING);
+	if (!acpi_gbl_system_awake_and_running) {
+		/*
+		 * We just woke up because of a wake GPE. Disable any further GPEs
+		 * until we are fully up and running (Only wake GPEs should be enabled
+		 * at this time, but we just brute-force disable them all.)
+		 * 1) We must disable this particular wake GPE so it won't fire again
+		 * 2) We want to disable all wake GPEs, since we are now awake
+		 */
+		(void)acpi_hw_disable_all_gpes();
 	}
 
 	/*
-	 * Dispatch the GPE to either an installed handler, or the control
-	 * method associated with this GPE (_Lxx or _Exx).
-	 * If a handler exists, we invoke it and do not attempt to run the method.
-	 * If there is neither a handler nor a method, we disable the level to
-	 * prevent further events from coming in here.
+	 * Dispatch the GPE to either an installed handler, or the control method
+	 * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke
+	 * it and do not attempt to run the method. If there is neither a handler
+	 * nor a method, we disable this GPE to prevent further such pointless
+	 * events from firing.
 	 */
 	switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
 	case ACPI_GPE_DISPATCH_HANDLER:
@@ -677,8 +683,8 @@
 	case ACPI_GPE_DISPATCH_METHOD:
 
 		/*
-		 * Disable GPE, so it doesn't keep firing before the method has a
-		 * chance to run.
+		 * Disable the GPE, so it doesn't keep firing before the method has a
+		 * chance to run (it runs asynchronously with interrupts enabled).
 		 */
 		status = acpi_ev_disable_gpe(gpe_event_info);
 		if (ACPI_FAILURE(status)) {
@@ -711,7 +717,7 @@
 			    gpe_number));
 
 		/*
-		 * Disable the GPE.  The GPE will remain disabled until the ACPI
+		 * Disable the GPE. The GPE will remain disabled until the ACPI
 		 * Core Subsystem is restarted, or a handler is installed.
 		 */
 		status = acpi_ev_disable_gpe(gpe_event_info);
@@ -726,50 +732,3 @@
 
 	return_UINT32(ACPI_INTERRUPT_HANDLED);
 }
-
-#ifdef ACPI_GPE_NOTIFY_CHECK
-/*******************************************************************************
- * TBD: NOT USED, PROTOTYPE ONLY AND WILL PROBABLY BE REMOVED
- *
- * FUNCTION:    acpi_ev_check_for_wake_only_gpe
- *
- * PARAMETERS:  gpe_event_info  - info for this GPE
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Determine if a a GPE is "wake-only".
- *
- *              Called from Notify() code in interpreter when a "DeviceWake"
- *              Notify comes in.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ev_check_for_wake_only_gpe(struct acpi_gpe_event_info *gpe_event_info)
-{
-	acpi_status status;
-
-	ACPI_FUNCTION_TRACE(ev_check_for_wake_only_gpe);
-
-	if ((gpe_event_info) &&	/* Only >0 for _Lxx/_Exx */
-	    ((gpe_event_info->flags & ACPI_GPE_SYSTEM_MASK) == ACPI_GPE_SYSTEM_RUNNING)) {	/* System state at GPE time */
-		/* This must be a wake-only GPE, disable it */
-
-		status = acpi_ev_disable_gpe(gpe_event_info);
-
-		/* Set GPE to wake-only.  Do not change wake disabled/enabled status */
-
-		acpi_ev_set_gpe_type(gpe_event_info, ACPI_GPE_TYPE_WAKE);
-
-		ACPI_INFO((AE_INFO,
-			   "GPE %p was updated from wake/run to wake-only",
-			   gpe_event_info));
-
-		/* This was a wake-only GPE */
-
-		return_ACPI_STATUS(AE_WAKE_ONLY_GPE);
-	}
-
-	return_ACPI_STATUS(AE_OK);
-}
-#endif
diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c
index 95ddeb4..ad5bc76 100644
--- a/drivers/acpi/events/evgpeblk.c
+++ b/drivers/acpi/events/evgpeblk.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -529,7 +529,7 @@
 
 	/* Install new interrupt handler if not SCI_INT */
 
-	if (interrupt_number != acpi_gbl_FADT->sci_int) {
+	if (interrupt_number != acpi_gbl_FADT.sci_interrupt) {
 		status = acpi_os_install_interrupt_handler(interrupt_number,
 							   acpi_ev_gpe_xrupt_handler,
 							   gpe_xrupt);
@@ -567,7 +567,7 @@
 
 	/* We never want to remove the SCI interrupt handler */
 
-	if (gpe_xrupt->interrupt_number == acpi_gbl_FADT->sci_int) {
+	if (gpe_xrupt->interrupt_number == acpi_gbl_FADT.sci_interrupt) {
 		gpe_xrupt->gpe_block_list_head = NULL;
 		return_ACPI_STATUS(AE_OK);
 	}
@@ -796,30 +796,31 @@
 		    (u8) (gpe_block->block_base_number +
 			  (i * ACPI_GPE_REGISTER_WIDTH));
 
-		ACPI_STORE_ADDRESS(this_register->status_address.address,
-				   (gpe_block->block_address.address + i));
+		this_register->status_address.address =
+		    gpe_block->block_address.address + i;
 
-		ACPI_STORE_ADDRESS(this_register->enable_address.address,
-				   (gpe_block->block_address.address
-				    + i + gpe_block->register_count));
+		this_register->enable_address.address =
+		    gpe_block->block_address.address + i +
+		    gpe_block->register_count;
 
-		this_register->status_address.address_space_id =
-		    gpe_block->block_address.address_space_id;
-		this_register->enable_address.address_space_id =
-		    gpe_block->block_address.address_space_id;
-		this_register->status_address.register_bit_width =
+		this_register->status_address.space_id =
+		    gpe_block->block_address.space_id;
+		this_register->enable_address.space_id =
+		    gpe_block->block_address.space_id;
+		this_register->status_address.bit_width =
 		    ACPI_GPE_REGISTER_WIDTH;
-		this_register->enable_address.register_bit_width =
+		this_register->enable_address.bit_width =
 		    ACPI_GPE_REGISTER_WIDTH;
-		this_register->status_address.register_bit_offset =
+		this_register->status_address.bit_offset =
 		    ACPI_GPE_REGISTER_WIDTH;
-		this_register->enable_address.register_bit_offset =
+		this_register->enable_address.bit_offset =
 		    ACPI_GPE_REGISTER_WIDTH;
 
 		/* Init the event_info for each GPE within this register */
 
 		for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
-			this_event->register_bit = acpi_gbl_decode_to8bit[j];
+			this_event->gpe_number =
+			    (u8) (this_register->base_gpe_number + j);
 			this_event->register_info = this_register;
 			this_event++;
 		}
@@ -1109,11 +1110,12 @@
 	 * If EITHER the register length OR the block address are zero, then that
 	 * particular block is not supported.
 	 */
-	if (acpi_gbl_FADT->gpe0_blk_len && acpi_gbl_FADT->xgpe0_blk.address) {
+	if (acpi_gbl_FADT.gpe0_block_length &&
+	    acpi_gbl_FADT.xgpe0_block.address) {
 
 		/* GPE block 0 exists (has both length and address > 0) */
 
-		register_count0 = (u16) (acpi_gbl_FADT->gpe0_blk_len / 2);
+		register_count0 = (u16) (acpi_gbl_FADT.gpe0_block_length / 2);
 
 		gpe_number_max =
 		    (register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1;
@@ -1121,9 +1123,9 @@
 		/* Install GPE Block 0 */
 
 		status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
-						  &acpi_gbl_FADT->xgpe0_blk,
+						  &acpi_gbl_FADT.xgpe0_block,
 						  register_count0, 0,
-						  acpi_gbl_FADT->sci_int,
+						  acpi_gbl_FADT.sci_interrupt,
 						  &acpi_gbl_gpe_fadt_blocks[0]);
 
 		if (ACPI_FAILURE(status)) {
@@ -1132,20 +1134,21 @@
 		}
 	}
 
-	if (acpi_gbl_FADT->gpe1_blk_len && acpi_gbl_FADT->xgpe1_blk.address) {
+	if (acpi_gbl_FADT.gpe1_block_length &&
+	    acpi_gbl_FADT.xgpe1_block.address) {
 
 		/* GPE block 1 exists (has both length and address > 0) */
 
-		register_count1 = (u16) (acpi_gbl_FADT->gpe1_blk_len / 2);
+		register_count1 = (u16) (acpi_gbl_FADT.gpe1_block_length / 2);
 
 		/* Check for GPE0/GPE1 overlap (if both banks exist) */
 
 		if ((register_count0) &&
-		    (gpe_number_max >= acpi_gbl_FADT->gpe1_base)) {
+		    (gpe_number_max >= acpi_gbl_FADT.gpe1_base)) {
 			ACPI_ERROR((AE_INFO,
 				    "GPE0 block (GPE 0 to %d) overlaps the GPE1 block (GPE %d to %d) - Ignoring GPE1",
-				    gpe_number_max, acpi_gbl_FADT->gpe1_base,
-				    acpi_gbl_FADT->gpe1_base +
+				    gpe_number_max, acpi_gbl_FADT.gpe1_base,
+				    acpi_gbl_FADT.gpe1_base +
 				    ((register_count1 *
 				      ACPI_GPE_REGISTER_WIDTH) - 1)));
 
@@ -1157,10 +1160,11 @@
 
 			status =
 			    acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
-						     &acpi_gbl_FADT->xgpe1_blk,
+						     &acpi_gbl_FADT.xgpe1_block,
 						     register_count1,
-						     acpi_gbl_FADT->gpe1_base,
-						     acpi_gbl_FADT->sci_int,
+						     acpi_gbl_FADT.gpe1_base,
+						     acpi_gbl_FADT.
+						     sci_interrupt,
 						     &acpi_gbl_gpe_fadt_blocks
 						     [1]);
 
@@ -1173,7 +1177,7 @@
 			 * GPE0 and GPE1 do not have to be contiguous in the GPE number
 			 * space. However, GPE0 always starts at GPE number zero.
 			 */
-			gpe_number_max = acpi_gbl_FADT->gpe1_base +
+			gpe_number_max = acpi_gbl_FADT.gpe1_base +
 			    ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1);
 		}
 	}
diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
index bf63edc..1b784ffe 100644
--- a/drivers/acpi/events/evmisc.c
+++ b/drivers/acpi/events/evmisc.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -63,14 +63,18 @@
 };
 #endif
 
+/* Pointer to FACS needed for the Global Lock */
+
+static struct acpi_table_facs *facs = NULL;
+
 /* Local prototypes */
 
 static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context);
 
-static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context);
-
 static u32 acpi_ev_global_lock_handler(void *context);
 
+static acpi_status acpi_ev_remove_global_lock_handler(void);
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ev_is_notify_object
@@ -282,49 +286,19 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ev_global_lock_thread
- *
- * PARAMETERS:  Context         - From thread interface, not used
- *
- * RETURN:      None
- *
- * DESCRIPTION: Invoked by SCI interrupt handler upon acquisition of the
- *              Global Lock.  Simply signal all threads that are waiting
- *              for the lock.
- *
- ******************************************************************************/
-
-static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context)
-{
-	acpi_status status;
-
-	/* Signal threads that are waiting for the lock */
-
-	if (acpi_gbl_global_lock_thread_count) {
-
-		/* Send sufficient units to the semaphore */
-
-		status =
-		    acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore,
-					     acpi_gbl_global_lock_thread_count);
-		if (ACPI_FAILURE(status)) {
-			ACPI_ERROR((AE_INFO,
-				    "Could not signal Global Lock semaphore"));
-		}
-	}
-}
-
-/*******************************************************************************
- *
  * FUNCTION:    acpi_ev_global_lock_handler
  *
  * PARAMETERS:  Context         - From thread interface, not used
  *
- * RETURN:      ACPI_INTERRUPT_HANDLED or ACPI_INTERRUPT_NOT_HANDLED
+ * RETURN:      ACPI_INTERRUPT_HANDLED
  *
  * DESCRIPTION: Invoked directly from the SCI handler when a global lock
- *              release interrupt occurs.  Grab the global lock and queue
- *              the global lock thread for execution
+ *              release interrupt occurs. Attempt to acquire the global lock,
+ *              if successful, signal the thread waiting for the lock.
+ *
+ * NOTE: Assumes that the semaphore can be signaled from interrupt level. If
+ * this is not possible for some reason, a separate thread will have to be
+ * scheduled to do this.
  *
  ******************************************************************************/
 
@@ -333,16 +307,24 @@
 	u8 acquired = FALSE;
 
 	/*
-	 * Attempt to get the lock
+	 * Attempt to get the lock.
+	 *
 	 * If we don't get it now, it will be marked pending and we will
 	 * take another interrupt when it becomes free.
 	 */
-	ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired);
+	ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired);
 	if (acquired) {
 
 		/* Got the lock, now wake all threads waiting for it */
+
 		acpi_gbl_global_lock_acquired = TRUE;
-		acpi_ev_global_lock_thread(context);
+		/* Send a unit to the semaphore */
+
+		if (ACPI_FAILURE(acpi_os_signal_semaphore(
+			acpi_gbl_global_lock_semaphore, 1))) {
+			ACPI_ERROR((AE_INFO,
+				    "Could not signal Global Lock semaphore"));
+		}
 	}
 
 	return (ACPI_INTERRUPT_HANDLED);
@@ -366,6 +348,13 @@
 
 	ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);
 
+	status =
+	    acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+				    (struct acpi_table_header **)&facs);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
 	acpi_gbl_global_lock_present = TRUE;
 	status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL,
 						  acpi_ev_global_lock_handler,
@@ -389,6 +378,31 @@
 	return_ACPI_STATUS(status);
 }
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ev_remove_global_lock_handler
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Remove the handler for the Global Lock
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_ev_remove_global_lock_handler(void)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(ev_remove_global_lock_handler);
+
+	acpi_gbl_global_lock_present = FALSE;
+	status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL,
+						 acpi_ev_global_lock_handler);
+
+	return_ACPI_STATUS(status);
+}
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_ev_acquire_global_lock
@@ -399,6 +413,16 @@
  *
  * DESCRIPTION: Attempt to gain ownership of the Global Lock.
  *
+ * MUTEX:       Interpreter must be locked
+ *
+ * Note: The original implementation allowed multiple threads to "acquire" the
+ * Global Lock, and the OS would hold the lock until the last thread had
+ * released it. However, this could potentially starve the BIOS out of the
+ * lock, especially in the case where there is a tight handshake between the
+ * Embedded Controller driver and the BIOS. Therefore, this implementation
+ * allows only one thread to acquire the HW Global Lock at a time, and makes
+ * the global lock appear as a standard mutex on the OS side.
+ *
  *****************************************************************************/
 
 acpi_status acpi_ev_acquire_global_lock(u16 timeout)
@@ -408,53 +432,51 @@
 
 	ACPI_FUNCTION_TRACE(ev_acquire_global_lock);
 
-#ifndef ACPI_APPLICATION
-	/* Make sure that we actually have a global lock */
-
-	if (!acpi_gbl_global_lock_present) {
-		return_ACPI_STATUS(AE_NO_GLOBAL_LOCK);
+	/*
+	 * Only one thread can acquire the GL at a time, the global_lock_mutex
+	 * enforces this. This interface releases the interpreter if we must wait.
+	 */
+	status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, timeout);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
 	}
-#endif
-
-	/* One more thread wants the global lock */
-
-	acpi_gbl_global_lock_thread_count++;
 
 	/*
-	 * If we (OS side vs. BIOS side) have the hardware lock already,
-	 * we are done
+	 * Make sure that a global lock actually exists. If not, just treat
+	 * the lock as a standard mutex.
 	 */
-	if (acpi_gbl_global_lock_acquired) {
+	if (!acpi_gbl_global_lock_present) {
+		acpi_gbl_global_lock_acquired = TRUE;
 		return_ACPI_STATUS(AE_OK);
 	}
 
-	/* We must acquire the actual hardware lock */
+	/* Attempt to acquire the actual hardware lock */
 
-	ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired);
+	ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired);
 	if (acquired) {
 
 		/* We got the lock */
 
 		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-				  "Acquired the HW Global Lock\n"));
+				  "Acquired hardware Global Lock\n"));
 
 		acpi_gbl_global_lock_acquired = TRUE;
 		return_ACPI_STATUS(AE_OK);
 	}
 
 	/*
-	 * Did not get the lock.  The pending bit was set above, and we must now
+	 * Did not get the lock. The pending bit was set above, and we must now
 	 * wait until we get the global lock released interrupt.
 	 */
-	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for the HW Global Lock\n"));
+	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for hardware Global Lock\n"));
 
 	/*
-	 * Acquire the global lock semaphore first.
-	 * Since this wait will block, we must release the interpreter
+	 * Wait for handshake with the global lock interrupt handler.
+	 * This interface releases the interpreter if we must wait.
 	 */
-	status =
-	    acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
-					  timeout);
+	status = acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
+					       ACPI_WAIT_FOREVER);
+
 	return_ACPI_STATUS(status);
 }
 
@@ -477,38 +499,39 @@
 
 	ACPI_FUNCTION_TRACE(ev_release_global_lock);
 
-	if (!acpi_gbl_global_lock_thread_count) {
+	/* Lock must be already acquired */
+
+	if (!acpi_gbl_global_lock_acquired) {
 		ACPI_WARNING((AE_INFO,
-			      "Cannot release HW Global Lock, it has not been acquired"));
+			      "Cannot release the ACPI Global Lock, it has not been acquired"));
 		return_ACPI_STATUS(AE_NOT_ACQUIRED);
 	}
 
-	/* One fewer thread has the global lock */
+	if (acpi_gbl_global_lock_present) {
 
-	acpi_gbl_global_lock_thread_count--;
-	if (acpi_gbl_global_lock_thread_count) {
+		/* Allow any thread to release the lock */
 
-		/* There are still some threads holding the lock, cannot release */
+		ACPI_RELEASE_GLOBAL_LOCK(facs, pending);
 
-		return_ACPI_STATUS(AE_OK);
+		/*
+		 * If the pending bit was set, we must write GBL_RLS to the control
+		 * register
+		 */
+		if (pending) {
+			status =
+			    acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE,
+					      1);
+		}
+
+		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+				  "Released hardware Global Lock\n"));
 	}
 
-	/*
-	 * No more threads holding lock, we can do the actual hardware
-	 * release
-	 */
-	ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, pending);
 	acpi_gbl_global_lock_acquired = FALSE;
 
-	/*
-	 * If the pending bit was set, we must write GBL_RLS to the control
-	 * register
-	 */
-	if (pending) {
-		status = acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE,
-					   1, ACPI_MTX_LOCK);
-	}
+	/* Release the local GL mutex */
 
+	acpi_os_release_mutex(acpi_gbl_global_lock_mutex);
 	return_ACPI_STATUS(status);
 }
 
@@ -558,6 +581,12 @@
 		if (ACPI_FAILURE(status)) {
 			ACPI_ERROR((AE_INFO, "Could not remove SCI handler"));
 		}
+
+		status = acpi_ev_remove_global_lock_handler();
+		if (ACPI_FAILURE(status)) {
+			ACPI_ERROR((AE_INFO,
+				    "Could not remove Global Lock handler"));
+		}
 	}
 
 	/* Deallocate all handler objects installed within GPE info structs */
diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c
index 21caae0..e99f0c4 100644
--- a/drivers/acpi/events/evregion.c
+++ b/drivers/acpi/events/evregion.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -291,7 +291,6 @@
 			       u32 bit_width, acpi_integer * value)
 {
 	acpi_status status;
-	acpi_status status2;
 	acpi_adr_space_handler handler;
 	acpi_adr_space_setup region_setup;
 	union acpi_operand_object *handler_desc;
@@ -345,7 +344,7 @@
 		 * setup will potentially execute control methods
 		 * (e.g., _REG method for this region)
 		 */
-		acpi_ex_exit_interpreter();
+		acpi_ex_relinquish_interpreter();
 
 		status = region_setup(region_obj, ACPI_REGION_ACTIVATE,
 				      handler_desc->address_space.context,
@@ -353,10 +352,7 @@
 
 		/* Re-enter the interpreter */
 
-		status2 = acpi_ex_enter_interpreter();
-		if (ACPI_FAILURE(status2)) {
-			return_ACPI_STATUS(status2);
-		}
+		acpi_ex_reacquire_interpreter();
 
 		/* Check for failure of the Region Setup */
 
@@ -409,7 +405,7 @@
 		 * exit the interpreter because the handler *might* block -- we don't
 		 * know what it will do, so we can't hold the lock on the intepreter.
 		 */
-		acpi_ex_exit_interpreter();
+		acpi_ex_relinquish_interpreter();
 	}
 
 	/* Call the handler */
@@ -430,10 +426,7 @@
 		 * We just returned from a non-default handler, we must re-enter the
 		 * interpreter
 		 */
-		status2 = acpi_ex_enter_interpreter();
-		if (ACPI_FAILURE(status2)) {
-			return_ACPI_STATUS(status2);
-		}
+		acpi_ex_reacquire_interpreter();
 	}
 
 	return_ACPI_STATUS(status);
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
index 203d135..a4fa7e6 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/events/evrgnini.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,6 +48,11 @@
 #define _COMPONENT          ACPI_EVENTS
 ACPI_MODULE_NAME("evrgnini")
 
+/* Local prototypes */
+static u8 acpi_ev_match_pci_root_bridge(char *id);
+
+static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node);
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ev_system_memory_region_setup
@@ -62,6 +67,7 @@
  * DESCRIPTION: Setup a system_memory operation region
  *
  ******************************************************************************/
+
 acpi_status
 acpi_ev_system_memory_region_setup(acpi_handle handle,
 				   u32 function,
@@ -168,9 +174,9 @@
 	union acpi_operand_object *handler_obj;
 	struct acpi_namespace_node *parent_node;
 	struct acpi_namespace_node *pci_root_node;
+	struct acpi_namespace_node *pci_device_node;
 	union acpi_operand_object *region_obj =
 	    (union acpi_operand_object *)handle;
-	struct acpi_device_id object_hID;
 
 	ACPI_FUNCTION_TRACE(ev_pci_config_region_setup);
 
@@ -215,45 +221,30 @@
 
 		pci_root_node = parent_node;
 		while (pci_root_node != acpi_gbl_root_node) {
-			status =
-			    acpi_ut_execute_HID(pci_root_node, &object_hID);
-			if (ACPI_SUCCESS(status)) {
-				/*
-				 * Got a valid _HID string, check if this is a PCI root.
-				 * New for ACPI 3.0: check for a PCI Express root also.
-				 */
-				if (!
-				    (ACPI_STRNCMP
-				     (object_hID.value, PCI_ROOT_HID_STRING,
-				      sizeof(PCI_ROOT_HID_STRING)))
-				    ||
-				    !(ACPI_STRNCMP
-				      (object_hID.value,
-				       PCI_EXPRESS_ROOT_HID_STRING,
-				       sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) {
 
-					/* Install a handler for this PCI root bridge */
+			/* Get the _HID/_CID in order to detect a root_bridge */
 
-					status =
-					    acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
-					if (ACPI_FAILURE(status)) {
-						if (status == AE_SAME_HANDLER) {
-							/*
-							 * It is OK if the handler is already installed on the root
-							 * bridge.  Still need to return a context object for the
-							 * new PCI_Config operation region, however.
-							 */
-							status = AE_OK;
-						} else {
-							ACPI_EXCEPTION((AE_INFO,
-									status,
-									"Could not install PciConfig handler for Root Bridge %4.4s",
-									acpi_ut_get_node_name
-									(pci_root_node)));
-						}
+			if (acpi_ev_is_pci_root_bridge(pci_root_node)) {
+
+				/* Install a handler for this PCI root bridge */
+
+				status = acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
+				if (ACPI_FAILURE(status)) {
+					if (status == AE_SAME_HANDLER) {
+						/*
+						 * It is OK if the handler is already installed on the root
+						 * bridge.  Still need to return a context object for the
+						 * new PCI_Config operation region, however.
+						 */
+						status = AE_OK;
+					} else {
+						ACPI_EXCEPTION((AE_INFO, status,
+								"Could not install PciConfig handler for Root Bridge %4.4s",
+								acpi_ut_get_node_name
+								(pci_root_node)));
 					}
-					break;
 				}
+				break;
 			}
 
 			pci_root_node = acpi_ns_get_parent_node(pci_root_node);
@@ -282,14 +273,25 @@
 	/*
 	 * For PCI_Config space access, we need the segment, bus,
 	 * device and function numbers.  Acquire them here.
+	 *
+	 * Find the parent device object. (This allows the operation region to be
+	 * within a subscope under the device, such as a control method.)
 	 */
+	pci_device_node = region_obj->region.node;
+	while (pci_device_node && (pci_device_node->type != ACPI_TYPE_DEVICE)) {
+		pci_device_node = acpi_ns_get_parent_node(pci_device_node);
+	}
+
+	if (!pci_device_node) {
+		return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
+	}
 
 	/*
 	 * Get the PCI device and function numbers from the _ADR object
 	 * contained in the parent's scope.
 	 */
 	status =
-	    acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, parent_node,
+	    acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, pci_device_node,
 					    &pci_value);
 
 	/*
@@ -329,6 +331,91 @@
 
 /*******************************************************************************
  *
+ * FUNCTION:    acpi_ev_match_pci_root_bridge
+ *
+ * PARAMETERS:  Id              - The HID/CID in string format
+ *
+ * RETURN:      TRUE if the Id is a match for a PCI/PCI-Express Root Bridge
+ *
+ * DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID.
+ *
+ ******************************************************************************/
+
+static u8 acpi_ev_match_pci_root_bridge(char *id)
+{
+
+	/*
+	 * Check if this is a PCI root.
+	 * ACPI 3.0+: check for a PCI Express root also.
+	 */
+	if (!(ACPI_STRNCMP(id,
+			   PCI_ROOT_HID_STRING,
+			   sizeof(PCI_ROOT_HID_STRING))) ||
+	    !(ACPI_STRNCMP(id,
+			   PCI_EXPRESS_ROOT_HID_STRING,
+			   sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) {
+		return (TRUE);
+	}
+
+	return (FALSE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ev_is_pci_root_bridge
+ *
+ * PARAMETERS:  Node            - Device node being examined
+ *
+ * RETURN:      TRUE if device is a PCI/PCI-Express Root Bridge
+ *
+ * DESCRIPTION: Determine if the input device represents a PCI Root Bridge by
+ *              examining the _HID and _CID for the device.
+ *
+ ******************************************************************************/
+
+static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
+{
+	acpi_status status;
+	struct acpi_device_id hid;
+	struct acpi_compatible_id_list *cid;
+	acpi_native_uint i;
+
+	/*
+	 * Get the _HID and check for a PCI Root Bridge
+	 */
+	status = acpi_ut_execute_HID(node, &hid);
+	if (ACPI_FAILURE(status)) {
+		return (FALSE);
+	}
+
+	if (acpi_ev_match_pci_root_bridge(hid.value)) {
+		return (TRUE);
+	}
+
+	/*
+	 * The _HID did not match.
+	 * Get the _CID and check for a PCI Root Bridge
+	 */
+	status = acpi_ut_execute_CID(node, &cid);
+	if (ACPI_FAILURE(status)) {
+		return (FALSE);
+	}
+
+	/* Check all _CIDs in the returned list */
+
+	for (i = 0; i < cid->count; i++) {
+		if (acpi_ev_match_pci_root_bridge(cid->id[i].value)) {
+			ACPI_FREE(cid);
+			return (TRUE);
+		}
+	}
+
+	ACPI_FREE(cid);
+	return (FALSE);
+}
+
+/*******************************************************************************
+ *
  * FUNCTION:    acpi_ev_pci_bar_region_setup
  *
  * PARAMETERS:  Handle              - Region we are interested in
@@ -432,6 +519,9 @@
  *              a PCI address in the scope of the definition.  This address is
  *              required to perform an access to PCI config space.
  *
+ * MUTEX:       Interpreter should be unlocked, because we may run the _REG
+ *              method for this region.
+ *
  ******************************************************************************/
 
 acpi_status
diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c
index 8106215..7e5d15c 100644
--- a/drivers/acpi/events/evsci.c
+++ b/drivers/acpi/events/evsci.c
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -142,9 +142,10 @@
 
 	ACPI_FUNCTION_TRACE(ev_install_sci_handler);
 
-	status = acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT->sci_int,
-						   acpi_ev_sci_xrupt_handler,
-						   acpi_gbl_gpe_xrupt_list_head);
+	status =
+	    acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt,
+					      acpi_ev_sci_xrupt_handler,
+					      acpi_gbl_gpe_xrupt_list_head);
 	return_ACPI_STATUS(status);
 }
 
@@ -175,8 +176,9 @@
 
 	/* Just let the OS remove the handler and disable the level */
 
-	status = acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT->sci_int,
-						  acpi_ev_sci_xrupt_handler);
+	status =
+	    acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt,
+					     acpi_ev_sci_xrupt_handler);
 
 	return_ACPI_STATUS(status);
 }
diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c
index 923fd2b..685a103 100644
--- a/drivers/acpi/events/evxface.c
+++ b/drivers/acpi/events/evxface.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -768,11 +768,9 @@
 		return (AE_BAD_PARAMETER);
 	}
 
-	status = acpi_ex_enter_interpreter();
-	if (ACPI_FAILURE(status)) {
-		return (status);
-	}
+	/* Must lock interpreter to prevent race conditions */
 
+	acpi_ex_enter_interpreter();
 	status = acpi_ev_acquire_global_lock(timeout);
 	acpi_ex_exit_interpreter();
 
diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c
index 7ebc2ef..17065e9 100644
--- a/drivers/acpi/events/evxfevnt.c
+++ b/drivers/acpi/events/evxfevnt.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
 #include <acpi/acpi.h>
 #include <acpi/acevents.h>
 #include <acpi/acnamesp.h>
+#include <acpi/actables.h>
 
 #define _COMPONENT          ACPI_EVENTS
 ACPI_MODULE_NAME("evxfevnt")
@@ -65,13 +66,14 @@
 
 	ACPI_FUNCTION_TRACE(acpi_enable);
 
-	/* Make sure we have the FADT */
+	/* ACPI tables must be present */
 
-	if (!acpi_gbl_FADT) {
-		ACPI_WARNING((AE_INFO, "No FADT information present!"));
+	if (!acpi_tb_tables_loaded()) {
 		return_ACPI_STATUS(AE_NO_ACPI_TABLES);
 	}
 
+	/* Check current mode */
+
 	if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INIT,
 				  "System is already in ACPI mode\n"));
@@ -111,11 +113,6 @@
 
 	ACPI_FUNCTION_TRACE(acpi_disable);
 
-	if (!acpi_gbl_FADT) {
-		ACPI_WARNING((AE_INFO, "No FADT information present!"));
-		return_ACPI_STATUS(AE_NO_ACPI_TABLES);
-	}
-
 	if (acpi_hw_get_mode() == ACPI_SYS_MODE_LEGACY) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INIT,
 				  "System is already in legacy (non-ACPI) mode\n"));
@@ -169,7 +166,7 @@
 	 */
 	status =
 	    acpi_set_register(acpi_gbl_fixed_event_info[event].
-			      enable_register_id, 1, ACPI_MTX_LOCK);
+			      enable_register_id, 1);
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
@@ -178,7 +175,7 @@
 
 	status =
 	    acpi_get_register(acpi_gbl_fixed_event_info[event].
-			      enable_register_id, &value, ACPI_MTX_LOCK);
+			      enable_register_id, &value);
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
@@ -368,14 +365,14 @@
 	 */
 	status =
 	    acpi_set_register(acpi_gbl_fixed_event_info[event].
-			      enable_register_id, 0, ACPI_MTX_LOCK);
+			      enable_register_id, 0);
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
 
 	status =
 	    acpi_get_register(acpi_gbl_fixed_event_info[event].
-			      enable_register_id, &value, ACPI_MTX_LOCK);
+			      enable_register_id, &value);
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
@@ -421,7 +418,7 @@
 	 */
 	status =
 	    acpi_set_register(acpi_gbl_fixed_event_info[event].
-			      status_register_id, 1, ACPI_MTX_LOCK);
+			      status_register_id, 1);
 
 	return_ACPI_STATUS(status);
 }
@@ -510,7 +507,7 @@
 
 	status =
 	    acpi_get_register(acpi_gbl_fixed_event_info[event].
-			      status_register_id, event_status, ACPI_MTX_LOCK);
+			      status_register_id, event_status);
 
 	return_ACPI_STATUS(status);
 }
diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c
index 83b12a9..7bf09c5 100644
--- a/drivers/acpi/events/evxfregn.c
+++ b/drivers/acpi/events/evxfregn.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c
index c8341fa..25802f3 100644
--- a/drivers/acpi/executer/exconfig.c
+++ b/drivers/acpi/executer/exconfig.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -54,7 +54,7 @@
 
 /* Local prototypes */
 static acpi_status
-acpi_ex_add_table(struct acpi_table_header *table,
+acpi_ex_add_table(acpi_native_uint table_index,
 		  struct acpi_namespace_node *parent_node,
 		  union acpi_operand_object **ddb_handle);
 
@@ -74,12 +74,11 @@
  ******************************************************************************/
 
 static acpi_status
-acpi_ex_add_table(struct acpi_table_header *table,
+acpi_ex_add_table(acpi_native_uint table_index,
 		  struct acpi_namespace_node *parent_node,
 		  union acpi_operand_object **ddb_handle)
 {
 	acpi_status status;
-	struct acpi_table_desc table_info;
 	union acpi_operand_object *obj_desc;
 
 	ACPI_FUNCTION_TRACE(ex_add_table);
@@ -98,42 +97,16 @@
 
 	/* Install the new table into the local data structures */
 
-	ACPI_MEMSET(&table_info, 0, sizeof(struct acpi_table_desc));
-
-	table_info.type = ACPI_TABLE_ID_SSDT;
-	table_info.pointer = table;
-	table_info.length = (acpi_size) table->length;
-	table_info.allocation = ACPI_MEM_ALLOCATED;
-
-	status = acpi_tb_install_table(&table_info);
-	obj_desc->reference.object = table_info.installed_desc;
-
-	if (ACPI_FAILURE(status)) {
-		if (status == AE_ALREADY_EXISTS) {
-
-			/* Table already exists, just return the handle */
-
-			return_ACPI_STATUS(AE_OK);
-		}
-		goto cleanup;
-	}
+	obj_desc->reference.object = ACPI_CAST_PTR(void, table_index);
 
 	/* Add the table to the namespace */
 
-	status = acpi_ns_load_table(table_info.installed_desc, parent_node);
+	status = acpi_ns_load_table(table_index, parent_node);
 	if (ACPI_FAILURE(status)) {
-
-		/* Uninstall table on error */
-
-		(void)acpi_tb_uninstall_table(table_info.installed_desc);
-		goto cleanup;
+		acpi_ut_remove_reference(obj_desc);
+		*ddb_handle = NULL;
 	}
 
-	return_ACPI_STATUS(AE_OK);
-
-      cleanup:
-	acpi_ut_remove_reference(obj_desc);
-	*ddb_handle = NULL;
 	return_ACPI_STATUS(status);
 }
 
@@ -146,7 +119,7 @@
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Load an ACPI table
+ * DESCRIPTION: Load an ACPI table from the RSDT/XSDT
  *
  ******************************************************************************/
 
@@ -156,33 +129,20 @@
 {
 	acpi_status status;
 	union acpi_operand_object **operand = &walk_state->operands[0];
-	struct acpi_table_header *table;
+	acpi_native_uint table_index;
 	struct acpi_namespace_node *parent_node;
 	struct acpi_namespace_node *start_node;
 	struct acpi_namespace_node *parameter_node = NULL;
 	union acpi_operand_object *ddb_handle;
+	struct acpi_table_header *table;
 
 	ACPI_FUNCTION_TRACE(ex_load_table_op);
 
-#if 0
-	/*
-	 * Make sure that the signature does not match one of the tables that
-	 * is already loaded.
-	 */
-	status = acpi_tb_match_signature(operand[0]->string.pointer, NULL);
-	if (status == AE_OK) {
-
-		/* Signature matched -- don't allow override */
-
-		return_ACPI_STATUS(AE_ALREADY_EXISTS);
-	}
-#endif
-
-	/* Find the ACPI table */
+	/* Find the ACPI table in the RSDT/XSDT */
 
 	status = acpi_tb_find_table(operand[0]->string.pointer,
 				    operand[1]->string.pointer,
-				    operand[2]->string.pointer, &table);
+				    operand[2]->string.pointer, &table_index);
 	if (ACPI_FAILURE(status)) {
 		if (status != AE_NOT_FOUND) {
 			return_ACPI_STATUS(status);
@@ -245,7 +205,7 @@
 
 	/* Load the table into the namespace */
 
-	status = acpi_ex_add_table(table, parent_node, &ddb_handle);
+	status = acpi_ex_add_table(table_index, parent_node, &ddb_handle);
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
@@ -266,9 +226,13 @@
 		}
 	}
 
-	ACPI_INFO((AE_INFO,
-		   "Dynamic OEM Table Load - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]",
-		   table->signature, table->oem_id, table->oem_table_id));
+	status = acpi_get_table_by_index(table_index, &table);
+	if (ACPI_SUCCESS(status)) {
+		ACPI_INFO((AE_INFO,
+			   "Dynamic OEM Table Load - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]",
+			   table->signature, table->oem_id,
+			   table->oem_table_id));
+	}
 
 	*return_desc = ddb_handle;
 	return_ACPI_STATUS(status);
@@ -278,7 +242,7 @@
  *
  * FUNCTION:    acpi_ex_load_op
  *
- * PARAMETERS:  obj_desc        - Region or Field where the table will be
+ * PARAMETERS:  obj_desc        - Region or Buffer/Field where the table will be
  *                                obtained
  *              Target          - Where a handle to the table will be stored
  *              walk_state      - Current state
@@ -287,6 +251,12 @@
  *
  * DESCRIPTION: Load an ACPI table from a field or operation region
  *
+ * NOTE: Region Fields (Field, bank_field, index_fields) are resolved to buffer
+ *       objects before this code is reached.
+ *
+ *       If source is an operation region, it must refer to system_memory, as
+ *       per the ACPI specification.
+ *
  ******************************************************************************/
 
 acpi_status
@@ -294,22 +264,26 @@
 		union acpi_operand_object *target,
 		struct acpi_walk_state *walk_state)
 {
-	acpi_status status;
 	union acpi_operand_object *ddb_handle;
-	union acpi_operand_object *buffer_desc = NULL;
-	struct acpi_table_header *table_ptr = NULL;
-	acpi_physical_address address;
-	struct acpi_table_header table_header;
-	acpi_integer temp;
-	u32 i;
+	struct acpi_table_desc table_desc;
+	acpi_native_uint table_index;
+	acpi_status status;
 
 	ACPI_FUNCTION_TRACE(ex_load_op);
 
-	/* Object can be either an op_region or a Field */
+	ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc));
+
+	/* Source Object can be either an op_region or a Buffer/Field */
 
 	switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
 	case ACPI_TYPE_REGION:
 
+		/* Region must be system_memory (from ACPI spec) */
+
+		if (obj_desc->region.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+			return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
+		}
+
 		ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n",
 				  obj_desc,
 				  acpi_ut_get_object_type_name(obj_desc)));
@@ -325,113 +299,41 @@
 			}
 		}
 
-		/* Get the base physical address of the region */
-
-		address = obj_desc->region.address;
-
-		/* Get part of the table header to get the table length */
-
-		table_header.length = 0;
-		for (i = 0; i < 8; i++) {
-			status =
-			    acpi_ev_address_space_dispatch(obj_desc, ACPI_READ,
-							   (acpi_physical_address)
-							   (i + address), 8,
-							   &temp);
-			if (ACPI_FAILURE(status)) {
-				return_ACPI_STATUS(status);
-			}
-
-			/* Get the one valid byte of the returned 64-bit value */
-
-			ACPI_CAST_PTR(u8, &table_header)[i] = (u8) temp;
-		}
-
-		/* Sanity check the table length */
-
-		if (table_header.length < sizeof(struct acpi_table_header)) {
-			return_ACPI_STATUS(AE_BAD_HEADER);
-		}
-
-		/* Allocate a buffer for the entire table */
-
-		table_ptr = ACPI_ALLOCATE(table_header.length);
-		if (!table_ptr) {
-			return_ACPI_STATUS(AE_NO_MEMORY);
-		}
-
-		/* Get the entire table from the op region */
-
-		for (i = 0; i < table_header.length; i++) {
-			status =
-			    acpi_ev_address_space_dispatch(obj_desc, ACPI_READ,
-							   (acpi_physical_address)
-							   (i + address), 8,
-							   &temp);
-			if (ACPI_FAILURE(status)) {
-				goto cleanup;
-			}
-
-			/* Get the one valid byte of the returned 64-bit value */
-
-			ACPI_CAST_PTR(u8, table_ptr)[i] = (u8) temp;
-		}
+		table_desc.address = obj_desc->region.address;
+		table_desc.length = obj_desc->region.length;
+		table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED;
 		break;
 
-	case ACPI_TYPE_LOCAL_REGION_FIELD:
-	case ACPI_TYPE_LOCAL_BANK_FIELD:
-	case ACPI_TYPE_LOCAL_INDEX_FIELD:
+	case ACPI_TYPE_BUFFER:	/* Buffer or resolved region_field */
 
-		ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Field %p %s\n",
-				  obj_desc,
+		/* Simply extract the buffer from the buffer object */
+
+		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+				  "Load from Buffer or Field %p %s\n", obj_desc,
 				  acpi_ut_get_object_type_name(obj_desc)));
 
-		/*
-		 * The length of the field must be at least as large as the table.
-		 * Read the entire field and thus the entire table.  Buffer is
-		 * allocated during the read.
-		 */
-		status =
-		    acpi_ex_read_data_from_field(walk_state, obj_desc,
-						 &buffer_desc);
-		if (ACPI_FAILURE(status)) {
-			return_ACPI_STATUS(status);
-		}
+		table_desc.pointer = ACPI_CAST_PTR(struct acpi_table_header,
+						   obj_desc->buffer.pointer);
+		table_desc.length = table_desc.pointer->length;
+		table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
 
-		table_ptr = ACPI_CAST_PTR(struct acpi_table_header,
-					  buffer_desc->buffer.pointer);
-
-		/* All done with the buffer_desc, delete it */
-
-		buffer_desc->buffer.pointer = NULL;
-		acpi_ut_remove_reference(buffer_desc);
-
-		/* Sanity check the table length */
-
-		if (table_ptr->length < sizeof(struct acpi_table_header)) {
-			status = AE_BAD_HEADER;
-			goto cleanup;
-		}
+		obj_desc->buffer.pointer = NULL;
 		break;
 
 	default:
 		return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
 	}
 
-	/* The table must be either an SSDT or a PSDT */
-
-	if ((!ACPI_COMPARE_NAME(table_ptr->signature, PSDT_SIG)) &&
-	    (!ACPI_COMPARE_NAME(table_ptr->signature, SSDT_SIG))) {
-		ACPI_ERROR((AE_INFO,
-			    "Table has invalid signature [%4.4s], must be SSDT or PSDT",
-			    table_ptr->signature));
-		status = AE_BAD_SIGNATURE;
+	/*
+	 * Install the new table into the local data structures
+	 */
+	status = acpi_tb_add_table(&table_desc, &table_index);
+	if (ACPI_FAILURE(status)) {
 		goto cleanup;
 	}
 
-	/* Install the new table into the local data structures */
-
-	status = acpi_ex_add_table(table_ptr, acpi_gbl_root_node, &ddb_handle);
+	status =
+	    acpi_ex_add_table(table_index, acpi_gbl_root_node, &ddb_handle);
 	if (ACPI_FAILURE(status)) {
 
 		/* On error, table_ptr was deallocated above */
@@ -450,13 +352,9 @@
 		return_ACPI_STATUS(status);
 	}
 
-	ACPI_INFO((AE_INFO,
-		   "Dynamic SSDT Load - OemId [%6.6s] OemTableId [%8.8s]",
-		   table_ptr->oem_id, table_ptr->oem_table_id));
-
       cleanup:
 	if (ACPI_FAILURE(status)) {
-		ACPI_FREE(table_ptr);
+		acpi_tb_delete_table(&table_desc);
 	}
 	return_ACPI_STATUS(status);
 }
@@ -477,7 +375,7 @@
 {
 	acpi_status status = AE_OK;
 	union acpi_operand_object *table_desc = ddb_handle;
-	struct acpi_table_desc *table_info;
+	acpi_native_uint table_index;
 
 	ACPI_FUNCTION_TRACE(ex_unload_table);
 
@@ -493,19 +391,18 @@
 		return_ACPI_STATUS(AE_BAD_PARAMETER);
 	}
 
-	/* Get the actual table descriptor from the ddb_handle */
+	/* Get the table index from the ddb_handle */
 
-	table_info = (struct acpi_table_desc *)table_desc->reference.object;
+	table_index = (acpi_native_uint) table_desc->reference.object;
 
 	/*
 	 * Delete the entire namespace under this table Node
 	 * (Offset contains the table_id)
 	 */
-	acpi_ns_delete_namespace_by_owner(table_info->owner_id);
+	acpi_tb_delete_namespace_by_owner(table_index);
+	acpi_tb_release_owner_id(table_index);
 
-	/* Delete the table itself */
-
-	(void)acpi_tb_uninstall_table(table_info->installed_desc);
+	acpi_tb_set_table_loaded_flag(table_index, FALSE);
 
 	/* Delete the table descriptor (ddb_handle) */
 
diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c
index 544e81a..d470e8b 100644
--- a/drivers/acpi/executer/exconvrt.c
+++ b/drivers/acpi/executer/exconvrt.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c
index 34eec82..7c38528 100644
--- a/drivers/acpi/executer/excreate.c
+++ b/drivers/acpi/executer/excreate.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -359,8 +359,9 @@
 	union acpi_operand_object **operand = &walk_state->operands[0];
 	union acpi_operand_object *obj_desc;
 	struct acpi_namespace_node *node;
-	struct acpi_table_header *table;
 	union acpi_operand_object *region_obj2;
+	acpi_native_uint table_index;
+	struct acpi_table_header *table;
 
 	ACPI_FUNCTION_TRACE(ex_create_table_region);
 
@@ -380,7 +381,7 @@
 
 	status = acpi_tb_find_table(operand[1]->string.pointer,
 				    operand[2]->string.pointer,
-				    operand[3]->string.pointer, &table);
+				    operand[3]->string.pointer, &table_index);
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
@@ -395,6 +396,11 @@
 	region_obj2 = obj_desc->common.next_object;
 	region_obj2->extra.region_context = NULL;
 
+	status = acpi_get_table_by_index(table_index, &table);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
 	/* Init the region from the operands */
 
 	obj_desc->region.space_id = REGION_DATA_TABLE;
@@ -553,7 +559,8 @@
 
 	obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
 	if (!obj_desc) {
-		return_ACPI_STATUS(AE_NO_MEMORY);
+		status = AE_NO_MEMORY;
+		goto exit;
 	}
 
 	/* Save the method's AML pointer and length  */
@@ -576,10 +583,7 @@
 	 * Get the sync_level. If method is serialized, a mutex will be
 	 * created for this method when it is parsed.
 	 */
-	if (acpi_gbl_all_methods_serialized) {
-		obj_desc->method.sync_level = 0;
-		obj_desc->method.method_flags |= AML_METHOD_SERIALIZED;
-	} else if (method_flags & AML_METHOD_SERIALIZED) {
+	if (method_flags & AML_METHOD_SERIALIZED) {
 		/*
 		 * ACPI 1.0: sync_level = 0
 		 * ACPI 2.0: sync_level = sync_level in method declaration
@@ -597,6 +601,7 @@
 
 	acpi_ut_remove_reference(obj_desc);
 
+      exit:
 	/* Remove a reference to the operand */
 
 	acpi_ut_remove_reference(operand[1]);
diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
index 2450943..68d283f 100644
--- a/drivers/acpi/executer/exdump.c
+++ b/drivers/acpi/executer/exdump.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -59,8 +59,6 @@
 
 static void acpi_ex_out_pointer(char *title, void *value);
 
-static void acpi_ex_out_address(char *title, acpi_physical_address value);
-
 static void
 acpi_ex_dump_object(union acpi_operand_object *obj_desc,
 		    struct acpi_exdump_info *info);
@@ -92,10 +90,11 @@
 	{ACPI_EXD_STRING, 0, NULL}
 };
 
-static struct acpi_exdump_info acpi_ex_dump_buffer[4] = {
+static struct acpi_exdump_info acpi_ex_dump_buffer[5] = {
 	{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_buffer), NULL},
 	{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(buffer.length), "Length"},
 	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.pointer), "Pointer"},
+	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.node), "Parent Node"},
 	{ACPI_EXD_BUFFER, 0, NULL}
 };
 
@@ -165,8 +164,8 @@
 
 static struct acpi_exdump_info acpi_ex_dump_processor[7] = {
 	{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_processor), NULL},
-	{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"},
-	{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(processor.length), "Length"},
+	{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"},
+	{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.length), "Length"},
 	{ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET(processor.address), "Address"},
 	{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.system_notify),
 	 "System Notify"},
@@ -379,18 +378,12 @@
 			break;
 
 		case ACPI_EXD_POINTER:
+		case ACPI_EXD_ADDRESS:
 
 			acpi_ex_out_pointer(name,
 					    *ACPI_CAST_PTR(void *, target));
 			break;
 
-		case ACPI_EXD_ADDRESS:
-
-			acpi_ex_out_address(name,
-					    *ACPI_CAST_PTR
-					    (acpi_physical_address, target));
-			break;
-
 		case ACPI_EXD_STRING:
 
 			acpi_ut_print_string(obj_desc->string.pointer,
@@ -834,16 +827,6 @@
 	acpi_os_printf("%20s : %p\n", title, value);
 }
 
-static void acpi_ex_out_address(char *title, acpi_physical_address value)
-{
-
-#if ACPI_MACHINE_WIDTH == 16
-	acpi_os_printf("%20s : %p\n", title, value);
-#else
-	acpi_os_printf("%20s : %8.8X%8.8X\n", title, ACPI_FORMAT_UINT64(value));
-#endif
-}
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ex_dump_namespace_node
diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c
index 9ea9c3a..2d88a3d 100644
--- a/drivers/acpi/executer/exfield.c
+++ b/drivers/acpi/executer/exfield.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c
index 40f0bee..65a48b6 100644
--- a/drivers/acpi/executer/exfldio.c
+++ b/drivers/acpi/executer/exfldio.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -257,14 +257,13 @@
 	}
 
 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_BFIELD,
-			      " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",
+			      " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n",
 			      acpi_ut_get_region_name(rgn_desc->region.
 						      space_id),
 			      rgn_desc->region.space_id,
 			      obj_desc->common_field.access_byte_width,
 			      obj_desc->common_field.base_byte_offset,
-			      field_datum_byte_offset,
-			      ACPI_FORMAT_UINT64(address)));
+			      field_datum_byte_offset, (void *)address));
 
 	/* Invoke the appropriate address_space/op_region handler */
 
diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c
index bd98aab..f13d1ce 100644
--- a/drivers/acpi/executer/exmisc.c
+++ b/drivers/acpi/executer/exmisc.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c
index bf90f04..5101bad 100644
--- a/drivers/acpi/executer/exmutex.c
+++ b/drivers/acpi/executer/exmutex.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
 
 #include <acpi/acpi.h>
 #include <acpi/acinterp.h>
+#include <acpi/acevents.h>
 
 #define _COMPONENT          ACPI_EXECUTER
 ACPI_MODULE_NAME("exmutex")
@@ -150,7 +151,7 @@
 		return_ACPI_STATUS(AE_BAD_PARAMETER);
 	}
 
-	/* Sanity check -- we must have a valid thread ID */
+	/* Sanity check: we must have a valid thread ID */
 
 	if (!walk_state->thread) {
 		ACPI_ERROR((AE_INFO,
@@ -174,24 +175,28 @@
 	/* Support for multiple acquires by the owning thread */
 
 	if (obj_desc->mutex.owner_thread) {
-
-		/* Special case for Global Lock, allow all threads */
-
-		if ((obj_desc->mutex.owner_thread->thread_id ==
-		     walk_state->thread->thread_id) ||
-		    (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK)) {
+		if (obj_desc->mutex.owner_thread->thread_id ==
+		    walk_state->thread->thread_id) {
 			/*
-			 * The mutex is already owned by this thread,
-			 * just increment the acquisition depth
+			 * The mutex is already owned by this thread, just increment the
+			 * acquisition depth
 			 */
 			obj_desc->mutex.acquisition_depth++;
 			return_ACPI_STATUS(AE_OK);
 		}
 	}
 
-	/* Acquire the mutex, wait if necessary */
+	/* Acquire the mutex, wait if necessary. Special case for Global Lock */
 
-	status = acpi_ex_system_acquire_mutex(time_desc, obj_desc);
+	if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+		status =
+		    acpi_ev_acquire_global_lock((u16) time_desc->integer.value);
+	} else {
+		status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
+						   (u16) time_desc->integer.
+						   value);
+	}
+
 	if (ACPI_FAILURE(status)) {
 
 		/* Includes failure from a timeout on time_desc */
@@ -211,7 +216,6 @@
 	/* Link the mutex to the current thread for force-unlock at method exit */
 
 	acpi_ex_link_mutex(obj_desc, walk_state->thread);
-
 	return_ACPI_STATUS(AE_OK);
 }
 
@@ -232,7 +236,7 @@
 acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
 		      struct acpi_walk_state *walk_state)
 {
-	acpi_status status;
+	acpi_status status = AE_OK;
 
 	ACPI_FUNCTION_TRACE(ex_release_mutex);
 
@@ -249,7 +253,7 @@
 		return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED);
 	}
 
-	/* Sanity check -- we must have a valid thread ID */
+	/* Sanity check: we must have a valid thread ID */
 
 	if (!walk_state->thread) {
 		ACPI_ERROR((AE_INFO,
@@ -264,7 +268,7 @@
 	 */
 	if ((obj_desc->mutex.owner_thread->thread_id !=
 	     walk_state->thread->thread_id)
-	    && (obj_desc->mutex.os_mutex != ACPI_GLOBAL_LOCK)) {
+	    && (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) {
 		ACPI_ERROR((AE_INFO,
 			    "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX",
 			    (unsigned long)walk_state->thread->thread_id,
@@ -274,8 +278,8 @@
 	}
 
 	/*
-	 * The sync level of the mutex must be less than or
-	 * equal to the current sync level
+	 * The sync level of the mutex must be less than or equal to the current
+	 * sync level
 	 */
 	if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) {
 		ACPI_ERROR((AE_INFO,
@@ -298,11 +302,15 @@
 
 	acpi_ex_unlink_mutex(obj_desc);
 
-	/* Release the mutex */
+	/* Release the mutex, special case for Global Lock */
 
-	status = acpi_ex_system_release_mutex(obj_desc);
+	if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+		status = acpi_ev_release_global_lock();
+	} else {
+		acpi_os_release_mutex(obj_desc->mutex.os_mutex);
+	}
 
-	/* Update the mutex and walk state, restore sync_level before acquire */
+	/* Update the mutex and restore sync_level */
 
 	obj_desc->mutex.owner_thread = NULL;
 	walk_state->thread->current_sync_level =
@@ -321,39 +329,49 @@
  *
  * DESCRIPTION: Release all mutexes held by this thread
  *
+ * NOTE: This function is called as the thread is exiting the interpreter.
+ * Mutexes are not released when an individual control method is exited, but
+ * only when the parent thread actually exits the interpreter. This allows one
+ * method to acquire a mutex, and a different method to release it, as long as
+ * this is performed underneath a single parent control method.
+ *
  ******************************************************************************/
 
 void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread)
 {
 	union acpi_operand_object *next = thread->acquired_mutex_list;
-	union acpi_operand_object *this;
-	acpi_status status;
+	union acpi_operand_object *obj_desc;
 
 	ACPI_FUNCTION_ENTRY();
 
 	/* Traverse the list of owned mutexes, releasing each one */
 
 	while (next) {
-		this = next;
-		next = this->mutex.next;
+		obj_desc = next;
+		next = obj_desc->mutex.next;
 
-		this->mutex.acquisition_depth = 1;
-		this->mutex.prev = NULL;
-		this->mutex.next = NULL;
+		obj_desc->mutex.prev = NULL;
+		obj_desc->mutex.next = NULL;
+		obj_desc->mutex.acquisition_depth = 0;
 
-		/* Release the mutex */
+		/* Release the mutex, special case for Global Lock */
 
-		status = acpi_ex_system_release_mutex(this);
-		if (ACPI_FAILURE(status)) {
-			continue;
+		if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+
+			/* Ignore errors */
+
+			(void)acpi_ev_release_global_lock();
+		} else {
+			acpi_os_release_mutex(obj_desc->mutex.os_mutex);
 		}
 
 		/* Mark mutex unowned */
 
-		this->mutex.owner_thread = NULL;
+		obj_desc->mutex.owner_thread = NULL;
 
 		/* Update Thread sync_level (Last mutex is the important one) */
 
-		thread->current_sync_level = this->mutex.original_sync_level;
+		thread->current_sync_level =
+		    obj_desc->mutex.original_sync_level;
 	}
 }
diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c
index d3d7036..1ee4fb1 100644
--- a/drivers/acpi/executer/exnames.c
+++ b/drivers/acpi/executer/exnames.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c
index 6374d8b..252f10a 100644
--- a/drivers/acpi/executer/exoparg1.c
+++ b/drivers/acpi/executer/exoparg1.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -104,9 +104,7 @@
 			status = AE_NO_MEMORY;
 			goto cleanup;
 		}
-#if ACPI_MACHINE_WIDTH != 16
 		return_desc->integer.value = acpi_os_get_timer();
-#endif
 		break;
 
 	default:		/*  Unknown opcode  */
diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c
index 7d2cbc1..17e652e 100644
--- a/drivers/acpi/executer/exoparg2.c
+++ b/drivers/acpi/executer/exoparg2.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c
index e2d945d..7fe67cf 100644
--- a/drivers/acpi/executer/exoparg3.c
+++ b/drivers/acpi/executer/exoparg3.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/executer/exoparg6.c
index f0c0ba6..bd80a9c 100644
--- a/drivers/acpi/executer/exoparg6.c
+++ b/drivers/acpi/executer/exoparg6.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c
index 44d064f..a669662 100644
--- a/drivers/acpi/executer/exprep.c
+++ b/drivers/acpi/executer/exprep.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c
index 3cc97ba..2e9ce94 100644
--- a/drivers/acpi/executer/exregion.c
+++ b/drivers/acpi/executer/exregion.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -155,16 +155,15 @@
 
 		/* Create a new mapping starting at the address given */
 
-		status = acpi_os_map_memory(address, window_size,
-					    (void **)&mem_info->
-					    mapped_logical_address);
-		if (ACPI_FAILURE(status)) {
+		mem_info->mapped_logical_address =
+		    acpi_os_map_memory((acpi_native_uint) address, window_size);
+		if (!mem_info->mapped_logical_address) {
 			ACPI_ERROR((AE_INFO,
 				    "Could not map memory at %8.8X%8.8X, size %X",
 				    ACPI_FORMAT_UINT64(address),
 				    (u32) window_size));
 			mem_info->mapped_length = 0;
-			return_ACPI_STATUS(status);
+			return_ACPI_STATUS(AE_NO_MEMORY);
 		}
 
 		/* Save the physical address and mapping size */
@@ -210,11 +209,10 @@
 			*value = (acpi_integer) ACPI_GET32(logical_addr_ptr);
 			break;
 
-#if ACPI_MACHINE_WIDTH != 16
 		case 64:
 			*value = (acpi_integer) ACPI_GET64(logical_addr_ptr);
 			break;
-#endif
+
 		default:
 			/* bit_width was already validated */
 			break;
@@ -236,11 +234,9 @@
 			ACPI_SET32(logical_addr_ptr) = (u32) * value;
 			break;
 
-#if ACPI_MACHINE_WIDTH != 16
 		case 64:
 			ACPI_SET64(logical_addr_ptr) = (u64) * value;
 			break;
-#endif
 
 		default:
 			/* bit_width was already validated */
diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c
index 3089b05..2b3a01c 100644
--- a/drivers/acpi/executer/exresnte.c
+++ b/drivers/acpi/executer/exresnte.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c
index 6499de8..6c64e55 100644
--- a/drivers/acpi/executer/exresolv.c
+++ b/drivers/acpi/executer/exresolv.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -141,7 +141,7 @@
 	acpi_status status = AE_OK;
 	union acpi_operand_object *stack_desc;
 	void *temp_node;
-	union acpi_operand_object *obj_desc;
+	union acpi_operand_object *obj_desc = NULL;
 	u16 opcode;
 
 	ACPI_FUNCTION_TRACE(ex_resolve_object_to_value);
@@ -299,8 +299,6 @@
 		status = acpi_ds_get_package_arguments(stack_desc);
 		break;
 
-		/* These cases may never happen here, but just in case.. */
-
 	case ACPI_TYPE_BUFFER_FIELD:
 	case ACPI_TYPE_LOCAL_REGION_FIELD:
 	case ACPI_TYPE_LOCAL_BANK_FIELD:
@@ -314,6 +312,10 @@
 		status =
 		    acpi_ex_read_data_from_field(walk_state, stack_desc,
 						 &obj_desc);
+
+		/* Remove a reference to the original operand, then override */
+
+		acpi_ut_remove_reference(*stack_ptr);
 		*stack_ptr = (void *)obj_desc;
 		break;
 
diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c
index 4c93d09..ba76186 100644
--- a/drivers/acpi/executer/exresop.c
+++ b/drivers/acpi/executer/exresop.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -611,22 +611,20 @@
 			}
 			goto next_operand;
 
-		case ARGI_REGION_OR_FIELD:
+		case ARGI_REGION_OR_BUFFER:	/* Used by Load() only */
 
-			/* Need an operand of type REGION or a FIELD in a region */
+			/* Need an operand of type REGION or a BUFFER (which could be a resolved region field) */
 
 			switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
+			case ACPI_TYPE_BUFFER:
 			case ACPI_TYPE_REGION:
-			case ACPI_TYPE_LOCAL_REGION_FIELD:
-			case ACPI_TYPE_LOCAL_BANK_FIELD:
-			case ACPI_TYPE_LOCAL_INDEX_FIELD:
 
 				/* Valid operand */
 				break;
 
 			default:
 				ACPI_ERROR((AE_INFO,
-					    "Needed [Region/RegionField], found [%s] %p",
+					    "Needed [Region/Buffer], found [%s] %p",
 					    acpi_ut_get_object_type_name
 					    (obj_desc), obj_desc));
 
diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c
index 0456405..f4b69a6 100644
--- a/drivers/acpi/executer/exstore.c
+++ b/drivers/acpi/executer/exstore.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c
index 591aaf0..1d622c6 100644
--- a/drivers/acpi/executer/exstoren.c
+++ b/drivers/acpi/executer/exstoren.c
@@ -7,7 +7,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c
index 99ebe5a..8233d40 100644
--- a/drivers/acpi/executer/exstorob.c
+++ b/drivers/acpi/executer/exstorob.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c
index 28aef3e..9460baf 100644
--- a/drivers/acpi/executer/exsystem.c
+++ b/drivers/acpi/executer/exsystem.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -66,7 +66,6 @@
 acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
 {
 	acpi_status status;
-	acpi_status status2;
 
 	ACPI_FUNCTION_TRACE(ex_system_wait_semaphore);
 
@@ -79,7 +78,7 @@
 
 		/* We must wait, so unlock the interpreter */
 
-		acpi_ex_exit_interpreter();
+		acpi_ex_relinquish_interpreter();
 
 		status = acpi_os_wait_semaphore(semaphore, 1, timeout);
 
@@ -89,13 +88,7 @@
 
 		/* Reacquire the interpreter */
 
-		status2 = acpi_ex_enter_interpreter();
-		if (ACPI_FAILURE(status2)) {
-
-			/* Report fatal error, could not acquire interpreter */
-
-			return_ACPI_STATUS(status2);
-		}
+		acpi_ex_reacquire_interpreter();
 	}
 
 	return_ACPI_STATUS(status);
@@ -119,7 +112,6 @@
 acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
 {
 	acpi_status status;
-	acpi_status status2;
 
 	ACPI_FUNCTION_TRACE(ex_system_wait_mutex);
 
@@ -132,7 +124,7 @@
 
 		/* We must wait, so unlock the interpreter */
 
-		acpi_ex_exit_interpreter();
+		acpi_ex_relinquish_interpreter();
 
 		status = acpi_os_acquire_mutex(mutex, timeout);
 
@@ -142,13 +134,7 @@
 
 		/* Reacquire the interpreter */
 
-		status2 = acpi_ex_enter_interpreter();
-		if (ACPI_FAILURE(status2)) {
-
-			/* Report fatal error, could not acquire interpreter */
-
-			return_ACPI_STATUS(status2);
-		}
+		acpi_ex_reacquire_interpreter();
 	}
 
 	return_ACPI_STATUS(status);
@@ -209,96 +195,18 @@
 
 acpi_status acpi_ex_system_do_suspend(acpi_integer how_long)
 {
-	acpi_status status;
-
 	ACPI_FUNCTION_ENTRY();
 
 	/* Since this thread will sleep, we must release the interpreter */
 
-	acpi_ex_exit_interpreter();
+	acpi_ex_relinquish_interpreter();
 
 	acpi_os_sleep(how_long);
 
 	/* And now we must get the interpreter again */
 
-	status = acpi_ex_enter_interpreter();
-	return (status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ex_system_acquire_mutex
- *
- * PARAMETERS:  time_desc       - Maximum time to wait for the mutex
- *              obj_desc        - The object descriptor for this op
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Provides an access point to perform synchronization operations
- *              within the AML.  This function will cause a lock to be generated
- *              for the Mutex pointed to by obj_desc.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ex_system_acquire_mutex(union acpi_operand_object * time_desc,
-			     union acpi_operand_object * obj_desc)
-{
-	acpi_status status = AE_OK;
-
-	ACPI_FUNCTION_TRACE_PTR(ex_system_acquire_mutex, obj_desc);
-
-	if (!obj_desc) {
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-	}
-
-	/* Support for the _GL_ Mutex object -- go get the global lock */
-
-	if (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK) {
-		status =
-		    acpi_ev_acquire_global_lock((u16) time_desc->integer.value);
-		return_ACPI_STATUS(status);
-	}
-
-	status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
-					   (u16) time_desc->integer.value);
-	return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ex_system_release_mutex
- *
- * PARAMETERS:  obj_desc        - The object descriptor for this op
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Provides an access point to perform synchronization operations
- *              within the AML.  This operation is a request to release a
- *              previously acquired Mutex.  If the Mutex variable is set then
- *              it will be decremented.
- *
- ******************************************************************************/
-
-acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc)
-{
-	acpi_status status = AE_OK;
-
-	ACPI_FUNCTION_TRACE(ex_system_release_mutex);
-
-	if (!obj_desc) {
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-	}
-
-	/* Support for the _GL_ Mutex object -- release the global lock */
-
-	if (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK) {
-		status = acpi_ev_release_global_lock();
-		return_ACPI_STATUS(status);
-	}
-
-	acpi_os_release_mutex(obj_desc->mutex.os_mutex);
-	return_ACPI_STATUS(AE_OK);
+	acpi_ex_reacquire_interpreter();
+	return (AE_OK);
 }
 
 /*******************************************************************************
@@ -314,7 +222,7 @@
  *
  ******************************************************************************/
 
-acpi_status acpi_ex_system_signal_event(union acpi_operand_object *obj_desc)
+acpi_status acpi_ex_system_signal_event(union acpi_operand_object * obj_desc)
 {
 	acpi_status status = AE_OK;
 
diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c
index 982c8b6..6b0aecc 100644
--- a/drivers/acpi/executer/exutils.c
+++ b/drivers/acpi/executer/exutils.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -76,14 +76,15 @@
  *
  * PARAMETERS:  None
  *
- * RETURN:      Status
+ * RETURN:      None
  *
- * DESCRIPTION: Enter the interpreter execution region.  Failure to enter
- *              the interpreter region is a fatal system error
+ * DESCRIPTION: Enter the interpreter execution region. Failure to enter
+ *              the interpreter region is a fatal system error. Used in
+ *              conjunction with exit_interpreter.
  *
  ******************************************************************************/
 
-acpi_status acpi_ex_enter_interpreter(void)
+void acpi_ex_enter_interpreter(void)
 {
 	acpi_status status;
 
@@ -91,10 +92,42 @@
 
 	status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER);
 	if (ACPI_FAILURE(status)) {
-		ACPI_ERROR((AE_INFO, "Could not acquire interpreter mutex"));
+		ACPI_ERROR((AE_INFO,
+			    "Could not acquire AML Interpreter mutex"));
 	}
 
-	return_ACPI_STATUS(status);
+	return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ex_reacquire_interpreter
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Reacquire the interpreter execution region from within the
+ *              interpreter code. Failure to enter the interpreter region is a
+ *              fatal system error. Used in  conjuction with
+ *              relinquish_interpreter
+ *
+ ******************************************************************************/
+
+void acpi_ex_reacquire_interpreter(void)
+{
+	ACPI_FUNCTION_TRACE(ex_reacquire_interpreter);
+
+	/*
+	 * If the global serialized flag is set, do not release the interpreter,
+	 * since it was not actually released by acpi_ex_relinquish_interpreter.
+	 * This forces the interpreter to be single threaded.
+	 */
+	if (!acpi_gbl_all_methods_serialized) {
+		acpi_ex_enter_interpreter();
+	}
+
+	return_VOID;
 }
 
 /*******************************************************************************
@@ -105,17 +138,9 @@
  *
  * RETURN:      None
  *
- * DESCRIPTION: Exit the interpreter execution region
- *
- * Cases where the interpreter is unlocked:
- *      1) Completion of the execution of a control method
- *      2) Method blocked on a Sleep() AML opcode
- *      3) Method blocked on an Acquire() AML opcode
- *      4) Method blocked on a Wait() AML opcode
- *      5) Method blocked to acquire the global lock
- *      6) Method blocked to execute a serialized control method that is
- *          already executing
- *      7) About to invoke a user-installed opregion handler
+ * DESCRIPTION: Exit the interpreter execution region. This is the top level
+ *              routine used to exit the interpreter when all processing has
+ *              been completed.
  *
  ******************************************************************************/
 
@@ -127,7 +152,46 @@
 
 	status = acpi_ut_release_mutex(ACPI_MTX_INTERPRETER);
 	if (ACPI_FAILURE(status)) {
-		ACPI_ERROR((AE_INFO, "Could not release interpreter mutex"));
+		ACPI_ERROR((AE_INFO,
+			    "Could not release AML Interpreter mutex"));
+	}
+
+	return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ex_relinquish_interpreter
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Exit the interpreter execution region, from within the
+ *              interpreter - before attempting an operation that will possibly
+ *              block the running thread.
+ *
+ * Cases where the interpreter is unlocked internally
+ *      1) Method to be blocked on a Sleep() AML opcode
+ *      2) Method to be blocked on an Acquire() AML opcode
+ *      3) Method to be blocked on a Wait() AML opcode
+ *      4) Method to be blocked to acquire the global lock
+ *      5) Method to be blocked waiting to execute a serialized control method
+ *          that is currently executing
+ *      6) About to invoke a user-installed opregion handler
+ *
+ ******************************************************************************/
+
+void acpi_ex_relinquish_interpreter(void)
+{
+	ACPI_FUNCTION_TRACE(ex_relinquish_interpreter);
+
+	/*
+	 * If the global serialized flag is set, do not release the interpreter.
+	 * This forces the interpreter to be single threaded.
+	 */
+	if (!acpi_gbl_all_methods_serialized) {
+		acpi_ex_exit_interpreter();
 	}
 
 	return_VOID;
@@ -141,8 +205,8 @@
  *
  * RETURN:      none
  *
- * DESCRIPTION: Truncate a number to 32-bits if the currently executing method
- *              belongs to a 32-bit ACPI table.
+ * DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is
+ *              32-bit, as determined by the revision of the DSDT.
  *
  ******************************************************************************/
 
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index f305a82..af22fdf 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -48,8 +48,8 @@
 
 static int acpi_fan_add(struct acpi_device *device);
 static int acpi_fan_remove(struct acpi_device *device, int type);
-static int acpi_fan_suspend(struct acpi_device *device, int state);
-static int acpi_fan_resume(struct acpi_device *device, int state);
+static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state);
+static int acpi_fan_resume(struct acpi_device *device);
 
 static struct acpi_driver acpi_fan_driver = {
 	.name = ACPI_FAN_DRIVER_NAME,
@@ -237,7 +237,7 @@
 	return 0;
 }
 
-static int acpi_fan_suspend(struct acpi_device *device, int state)
+static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state)
 {
 	if (!device)
 		return -EINVAL;
@@ -247,7 +247,7 @@
 	return AE_OK;
 }
 
-static int acpi_fan_resume(struct acpi_device *device, int state)
+static int acpi_fan_resume(struct acpi_device *device)
 {
 	int result = 0;
 	int power_state = 0;
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 8a0324b..7b6c9ff 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -86,129 +86,6 @@
 	return ret;
 }
 
-/* Get PCI root bridge's handle from its segment and bus number */
-struct acpi_find_pci_root {
-	unsigned int seg;
-	unsigned int bus;
-	acpi_handle handle;
-};
-
-static acpi_status
-do_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
-{
-	unsigned long *busnr = data;
-	struct acpi_resource_address64 address;
-
-	if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 &&
-	    resource->type != ACPI_RESOURCE_TYPE_ADDRESS32 &&
-	    resource->type != ACPI_RESOURCE_TYPE_ADDRESS64)
-		return AE_OK;
-
-	acpi_resource_to_address64(resource, &address);
-	if ((address.address_length > 0) &&
-	    (address.resource_type == ACPI_BUS_NUMBER_RANGE))
-		*busnr = address.minimum;
-
-	return AE_OK;
-}
-
-static int get_root_bridge_busnr(acpi_handle handle)
-{
-	acpi_status status;
-	unsigned long bus, bbn;
-	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-
-	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-
-	status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL,
-				       &bbn);
-	if (status == AE_NOT_FOUND) {
-		/* Assume bus = 0 */
-		printk(KERN_INFO PREFIX
-		       "Assume root bridge [%s] bus is 0\n",
-		       (char *)buffer.pointer);
-		status = AE_OK;
-		bbn = 0;
-	}
-	if (ACPI_FAILURE(status)) {
-		bbn = -ENODEV;
-		goto exit;
-	}
-	if (bbn > 0)
-		goto exit;
-
-	/* _BBN in some systems return 0 for all root bridges */
-	bus = -1;
-	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
-				     do_root_bridge_busnr_callback, &bus);
-	/* If _CRS failed, we just use _BBN */
-	if (ACPI_FAILURE(status) || (bus == -1))
-		goto exit;
-	/* We select _CRS */
-	if (bbn != bus) {
-		printk(KERN_INFO PREFIX
-		       "_BBN and _CRS returns different value for %s. Select _CRS\n",
-		       (char *)buffer.pointer);
-		bbn = bus;
-	}
-      exit:
-	kfree(buffer.pointer);
-	return (int)bbn;
-}
-
-static acpi_status
-find_pci_rootbridge(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-	struct acpi_find_pci_root *find = (struct acpi_find_pci_root *)context;
-	unsigned long seg, bus;
-	acpi_status status;
-	int tmp;
-	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-
-	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-
-	status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &seg);
-	if (status == AE_NOT_FOUND) {
-		/* Assume seg = 0 */
-		status = AE_OK;
-		seg = 0;
-	}
-	if (ACPI_FAILURE(status)) {
-		status = AE_CTRL_DEPTH;
-		goto exit;
-	}
-
-	tmp = get_root_bridge_busnr(handle);
-	if (tmp < 0) {
-		printk(KERN_ERR PREFIX
-		       "Find root bridge failed for %s\n",
-		       (char *)buffer.pointer);
-		status = AE_CTRL_DEPTH;
-		goto exit;
-	}
-	bus = tmp;
-
-	if (seg == find->seg && bus == find->bus)
-	{
-		find->handle = handle;
-		status = AE_CTRL_TERMINATE;
-	}
-	else
-		status = AE_OK;
-      exit:
-	kfree(buffer.pointer);
-	return status;
-}
-
-acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
-{
-	struct acpi_find_pci_root find = { seg, bus, NULL };
-
-	acpi_get_devices(PCI_ROOT_HID_STRING, find_pci_rootbridge, &find, NULL);
-	return find.handle;
-}
-EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
-
 /* Get device's handler per its address under its parent */
 struct acpi_find_child {
 	acpi_handle handle;
diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c
index de50fab..6031ca1 100644
--- a/drivers/acpi/hardware/hwacpi.c
+++ b/drivers/acpi/hardware/hwacpi.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -49,41 +49,6 @@
 
 /******************************************************************************
  *
- * FUNCTION:    acpi_hw_initialize
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Initialize and validate the various ACPI registers defined in
- *              the FADT.
- *
- ******************************************************************************/
-acpi_status acpi_hw_initialize(void)
-{
-	acpi_status status;
-
-	ACPI_FUNCTION_TRACE(hw_initialize);
-
-	/* We must have the ACPI tables by the time we get here */
-
-	if (!acpi_gbl_FADT) {
-		ACPI_ERROR((AE_INFO, "No FADT is present"));
-		return_ACPI_STATUS(AE_NO_ACPI_TABLES);
-	}
-
-	/* Sanity check the FADT for valid values */
-
-	status = acpi_ut_validate_fadt();
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	return_ACPI_STATUS(AE_OK);
-}
-
-/******************************************************************************
- *
  * FUNCTION:    acpi_hw_set_mode
  *
  * PARAMETERS:  Mode            - SYS_MODE_ACPI or SYS_MODE_LEGACY
@@ -93,7 +58,6 @@
  * DESCRIPTION: Transitions the system into the requested mode.
  *
  ******************************************************************************/
-
 acpi_status acpi_hw_set_mode(u32 mode)
 {
 
@@ -106,7 +70,7 @@
 	 * ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
 	 * system does not support mode transition.
 	 */
-	if (!acpi_gbl_FADT->smi_cmd) {
+	if (!acpi_gbl_FADT.smi_command) {
 		ACPI_ERROR((AE_INFO,
 			    "No SMI_CMD in FADT, mode transition failed"));
 		return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
@@ -119,7 +83,7 @@
 	 * we make sure both the numbers are zero to determine these
 	 * transitions are not supported.
 	 */
-	if (!acpi_gbl_FADT->acpi_enable && !acpi_gbl_FADT->acpi_disable) {
+	if (!acpi_gbl_FADT.acpi_enable && !acpi_gbl_FADT.acpi_disable) {
 		ACPI_ERROR((AE_INFO,
 			    "No ACPI mode transition supported in this system (enable/disable both zero)"));
 		return_ACPI_STATUS(AE_OK);
@@ -130,9 +94,8 @@
 
 		/* BIOS should have disabled ALL fixed and GP events */
 
-		status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd,
-					    (u32) acpi_gbl_FADT->acpi_enable,
-					    8);
+		status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+					    (u32) acpi_gbl_FADT.acpi_enable, 8);
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Attempting to enable ACPI mode\n"));
 		break;
@@ -143,8 +106,8 @@
 		 * BIOS should clear all fixed status bits and restore fixed event
 		 * enable bits to default
 		 */
-		status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd,
-					    (u32) acpi_gbl_FADT->acpi_disable,
+		status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+					    (u32) acpi_gbl_FADT.acpi_disable,
 					    8);
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Attempting to enable Legacy (non-ACPI) mode\n"));
@@ -204,12 +167,11 @@
 	 * ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
 	 * system does not support mode transition.
 	 */
-	if (!acpi_gbl_FADT->smi_cmd) {
+	if (!acpi_gbl_FADT.smi_command) {
 		return_UINT32(ACPI_SYS_MODE_ACPI);
 	}
 
-	status =
-	    acpi_get_register(ACPI_BITREG_SCI_ENABLE, &value, ACPI_MTX_LOCK);
+	status = acpi_get_register(ACPI_BITREG_SCI_ENABLE, &value);
 	if (ACPI_FAILURE(status)) {
 		return_UINT32(ACPI_SYS_MODE_LEGACY);
 	}
diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c
index 608a3a6..117a05c 100644
--- a/drivers/acpi/hardware/hwgpe.c
+++ b/drivers/acpi/hardware/hwgpe.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -105,14 +105,20 @@
 acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
 {
 	acpi_status status;
+	u8 register_bit;
 
 	ACPI_FUNCTION_ENTRY();
 
+	register_bit = (u8)
+	    (1 <<
+	     (gpe_event_info->gpe_number -
+	      gpe_event_info->register_info->base_gpe_number));
+
 	/*
 	 * Write a one to the appropriate bit in the status register to
 	 * clear this GPE.
 	 */
-	status = acpi_hw_low_level_write(8, gpe_event_info->register_bit,
+	status = acpi_hw_low_level_write(8, register_bit,
 					 &gpe_event_info->register_info->
 					 status_address);
 
@@ -155,7 +161,10 @@
 
 	/* Get the register bitmask for this GPE */
 
-	register_bit = gpe_event_info->register_bit;
+	register_bit = (u8)
+	    (1 <<
+	     (gpe_event_info->gpe_number -
+	      gpe_event_info->register_info->base_gpe_number));
 
 	/* GPE currently enabled? (enabled for runtime?) */
 
diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c
index fa58c1e..1d371fa 100644
--- a/drivers/acpi/hardware/hwregs.c
+++ b/drivers/acpi/hardware/hwregs.c
@@ -7,7 +7,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -54,17 +54,15 @@
  *
  * FUNCTION:    acpi_hw_clear_acpi_status
  *
- * PARAMETERS:  Flags           - Lock the hardware or not
+ * PARAMETERS:  None
  *
- * RETURN:      none
+ * RETURN:      None
  *
  * DESCRIPTION: Clears all fixed and general purpose status bits
  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
  *
- * NOTE: TBD: Flags parameter is obsolete, to be removed
- *
  ******************************************************************************/
-acpi_status acpi_hw_clear_acpi_status(u32 flags)
+acpi_status acpi_hw_clear_acpi_status(void)
 {
 	acpi_status status;
 	acpi_cpu_flags lock_flags = 0;
@@ -73,7 +71,7 @@
 
 	ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %04X\n",
 			  ACPI_BITMASK_ALL_FIXED_STATUS,
-			  (u16) acpi_gbl_FADT->xpm1a_evt_blk.address));
+			  (u16) acpi_gbl_FADT.xpm1a_event_block.address));
 
 	lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
 
@@ -86,10 +84,10 @@
 
 	/* Clear the fixed events */
 
-	if (acpi_gbl_FADT->xpm1b_evt_blk.address) {
+	if (acpi_gbl_FADT.xpm1b_event_block.address) {
 		status =
 		    acpi_hw_low_level_write(16, ACPI_BITMASK_ALL_FIXED_STATUS,
-					    &acpi_gbl_FADT->xpm1b_evt_blk);
+					    &acpi_gbl_FADT.xpm1b_event_block);
 		if (ACPI_FAILURE(status)) {
 			goto unlock_and_exit;
 		}
@@ -253,18 +251,15 @@
  *
  * PARAMETERS:  register_id     - ID of ACPI bit_register to access
  *              return_value    - Value that was read from the register
- *              Flags           - Lock the hardware or not
  *
  * RETURN:      Status and the value read from specified Register. Value
  *              returned is normalized to bit0 (is shifted all the way right)
  *
  * DESCRIPTION: ACPI bit_register read function.
  *
- * NOTE: TBD: Flags parameter is obsolete, to be removed
- *
  ******************************************************************************/
 
-acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags)
+acpi_status acpi_get_register(u32 register_id, u32 * return_value)
 {
 	u32 register_value = 0;
 	struct acpi_bit_register_info *bit_reg_info;
@@ -312,16 +307,13 @@
  * PARAMETERS:  register_id     - ID of ACPI bit_register to access
  *              Value           - (only used on write) value to write to the
  *                                Register, NOT pre-normalized to the bit pos
- *              Flags           - Lock the hardware or not
  *
  * RETURN:      Status
  *
  * DESCRIPTION: ACPI Bit Register write function.
  *
- * NOTE: TBD: Flags parameter is obsolete, to be removed
- *
  ******************************************************************************/
-acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags)
+acpi_status acpi_set_register(u32 register_id, u32 value)
 {
 	u32 register_value = 0;
 	struct acpi_bit_register_info *bit_reg_info;
@@ -422,8 +414,9 @@
 		ACPI_DEBUG_PRINT((ACPI_DB_IO,
 				  "PM2 control: Read %X from %8.8X%8.8X\n",
 				  register_value,
-				  ACPI_FORMAT_UINT64(acpi_gbl_FADT->
-						     xpm2_cnt_blk.address)));
+				  ACPI_FORMAT_UINT64(acpi_gbl_FADT.
+						     xpm2_control_block.
+						     address)));
 
 		ACPI_REGISTER_INSERT_VALUE(register_value,
 					   bit_reg_info->bit_position,
@@ -433,8 +426,9 @@
 		ACPI_DEBUG_PRINT((ACPI_DB_IO,
 				  "About to write %4.4X to %8.8X%8.8X\n",
 				  register_value,
-				  ACPI_FORMAT_UINT64(acpi_gbl_FADT->
-						     xpm2_cnt_blk.address)));
+				  ACPI_FORMAT_UINT64(acpi_gbl_FADT.
+						     xpm2_control_block.
+						     address)));
 
 		status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
 						ACPI_REGISTER_PM2_CONTROL,
@@ -495,7 +489,7 @@
 
 		status =
 		    acpi_hw_low_level_read(16, &value1,
-					   &acpi_gbl_FADT->xpm1a_evt_blk);
+					   &acpi_gbl_FADT.xpm1a_event_block);
 		if (ACPI_FAILURE(status)) {
 			goto unlock_and_exit;
 		}
@@ -504,7 +498,7 @@
 
 		status =
 		    acpi_hw_low_level_read(16, &value2,
-					   &acpi_gbl_FADT->xpm1b_evt_blk);
+					   &acpi_gbl_FADT.xpm1b_event_block);
 		value1 |= value2;
 		break;
 
@@ -527,14 +521,14 @@
 
 		status =
 		    acpi_hw_low_level_read(16, &value1,
-					   &acpi_gbl_FADT->xpm1a_cnt_blk);
+					   &acpi_gbl_FADT.xpm1a_control_block);
 		if (ACPI_FAILURE(status)) {
 			goto unlock_and_exit;
 		}
 
 		status =
 		    acpi_hw_low_level_read(16, &value2,
-					   &acpi_gbl_FADT->xpm1b_cnt_blk);
+					   &acpi_gbl_FADT.xpm1b_control_block);
 		value1 |= value2;
 		break;
 
@@ -542,19 +536,20 @@
 
 		status =
 		    acpi_hw_low_level_read(8, &value1,
-					   &acpi_gbl_FADT->xpm2_cnt_blk);
+					   &acpi_gbl_FADT.xpm2_control_block);
 		break;
 
 	case ACPI_REGISTER_PM_TIMER:	/* 32-bit access */
 
 		status =
 		    acpi_hw_low_level_read(32, &value1,
-					   &acpi_gbl_FADT->xpm_tmr_blk);
+					   &acpi_gbl_FADT.xpm_timer_block);
 		break;
 
 	case ACPI_REGISTER_SMI_COMMAND_BLOCK:	/* 8-bit access */
 
-		status = acpi_os_read_port(acpi_gbl_FADT->smi_cmd, &value1, 8);
+		status =
+		    acpi_os_read_port(acpi_gbl_FADT.smi_command, &value1, 8);
 		break;
 
 	default:
@@ -635,7 +630,7 @@
 
 		status =
 		    acpi_hw_low_level_write(16, value,
-					    &acpi_gbl_FADT->xpm1a_evt_blk);
+					    &acpi_gbl_FADT.xpm1a_event_block);
 		if (ACPI_FAILURE(status)) {
 			goto unlock_and_exit;
 		}
@@ -644,7 +639,7 @@
 
 		status =
 		    acpi_hw_low_level_write(16, value,
-					    &acpi_gbl_FADT->xpm1b_evt_blk);
+					    &acpi_gbl_FADT.xpm1b_event_block);
 		break;
 
 	case ACPI_REGISTER_PM1_ENABLE:	/* 16-bit access */
@@ -682,49 +677,50 @@
 
 		status =
 		    acpi_hw_low_level_write(16, value,
-					    &acpi_gbl_FADT->xpm1a_cnt_blk);
+					    &acpi_gbl_FADT.xpm1a_control_block);
 		if (ACPI_FAILURE(status)) {
 			goto unlock_and_exit;
 		}
 
 		status =
 		    acpi_hw_low_level_write(16, value,
-					    &acpi_gbl_FADT->xpm1b_cnt_blk);
+					    &acpi_gbl_FADT.xpm1b_control_block);
 		break;
 
 	case ACPI_REGISTER_PM1A_CONTROL:	/* 16-bit access */
 
 		status =
 		    acpi_hw_low_level_write(16, value,
-					    &acpi_gbl_FADT->xpm1a_cnt_blk);
+					    &acpi_gbl_FADT.xpm1a_control_block);
 		break;
 
 	case ACPI_REGISTER_PM1B_CONTROL:	/* 16-bit access */
 
 		status =
 		    acpi_hw_low_level_write(16, value,
-					    &acpi_gbl_FADT->xpm1b_cnt_blk);
+					    &acpi_gbl_FADT.xpm1b_control_block);
 		break;
 
 	case ACPI_REGISTER_PM2_CONTROL:	/* 8-bit access */
 
 		status =
 		    acpi_hw_low_level_write(8, value,
-					    &acpi_gbl_FADT->xpm2_cnt_blk);
+					    &acpi_gbl_FADT.xpm2_control_block);
 		break;
 
 	case ACPI_REGISTER_PM_TIMER:	/* 32-bit access */
 
 		status =
 		    acpi_hw_low_level_write(32, value,
-					    &acpi_gbl_FADT->xpm_tmr_blk);
+					    &acpi_gbl_FADT.xpm_timer_block);
 		break;
 
 	case ACPI_REGISTER_SMI_COMMAND_BLOCK:	/* 8-bit access */
 
 		/* SMI_CMD is currently always in IO space */
 
-		status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd, value, 8);
+		status =
+		    acpi_os_write_port(acpi_gbl_FADT.smi_command, value, 8);
 		break;
 
 	default:
@@ -783,7 +779,7 @@
 	 * Two address spaces supported: Memory or IO.
 	 * PCI_Config is not supported here because the GAS struct is insufficient
 	 */
-	switch (reg->address_space_id) {
+	switch (reg->space_id) {
 	case ACPI_ADR_SPACE_SYSTEM_MEMORY:
 
 		status = acpi_os_read_memory((acpi_physical_address) address,
@@ -792,22 +788,20 @@
 
 	case ACPI_ADR_SPACE_SYSTEM_IO:
 
-		status = acpi_os_read_port((acpi_io_address) address,
-					   value, width);
+		status =
+		    acpi_os_read_port((acpi_io_address) address, value, width);
 		break;
 
 	default:
 		ACPI_ERROR((AE_INFO,
-			    "Unsupported address space: %X",
-			    reg->address_space_id));
+			    "Unsupported address space: %X", reg->space_id));
 		return (AE_BAD_PARAMETER);
 	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_IO,
 			  "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
-			  *value, width,
-			  ACPI_FORMAT_UINT64(address),
-			  acpi_ut_get_region_name(reg->address_space_id)));
+			  *value, width, ACPI_FORMAT_UINT64(address),
+			  acpi_ut_get_region_name(reg->space_id)));
 
 	return (status);
 }
@@ -854,7 +848,7 @@
 	 * Two address spaces supported: Memory or IO.
 	 * PCI_Config is not supported here because the GAS struct is insufficient
 	 */
-	switch (reg->address_space_id) {
+	switch (reg->space_id) {
 	case ACPI_ADR_SPACE_SYSTEM_MEMORY:
 
 		status = acpi_os_write_memory((acpi_physical_address) address,
@@ -863,22 +857,20 @@
 
 	case ACPI_ADR_SPACE_SYSTEM_IO:
 
-		status = acpi_os_write_port((acpi_io_address) address,
-					    value, width);
+		status = acpi_os_write_port((acpi_io_address) address, value,
+					    width);
 		break;
 
 	default:
 		ACPI_ERROR((AE_INFO,
-			    "Unsupported address space: %X",
-			    reg->address_space_id));
+			    "Unsupported address space: %X", reg->space_id));
 		return (AE_BAD_PARAMETER);
 	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_IO,
 			  "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
-			  value, width,
-			  ACPI_FORMAT_UINT64(address),
-			  acpi_ut_get_region_name(reg->address_space_id)));
+			  value, width, ACPI_FORMAT_UINT64(address),
+			  acpi_ut_get_region_name(reg->space_id)));
 
 	return (status);
 }
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index 8bb43ca..57901ca 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,6 +43,7 @@
  */
 
 #include <acpi/acpi.h>
+#include <acpi/actables.h>
 
 #define _COMPONENT          ACPI_HARDWARE
 ACPI_MODULE_NAME("hwsleep")
@@ -62,17 +63,32 @@
 acpi_status
 acpi_set_firmware_waking_vector(acpi_physical_address physical_address)
 {
+	struct acpi_table_facs *facs;
+	acpi_status status;
 
 	ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector);
 
+	/* Get the FACS */
+
+	status =
+	    acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+				    (struct acpi_table_header **)&facs);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
 	/* Set the vector */
 
-	if (acpi_gbl_common_fACS.vector_width == 32) {
-		*(ACPI_CAST_PTR
-		  (u32, acpi_gbl_common_fACS.firmware_waking_vector))
-		    = (u32) physical_address;
+	if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) {
+		/*
+		 * ACPI 1.0 FACS or short table or optional X_ field is zero
+		 */
+		facs->firmware_waking_vector = (u32) physical_address;
 	} else {
-		*acpi_gbl_common_fACS.firmware_waking_vector = physical_address;
+		/*
+		 * ACPI 2.0 FACS with valid X_ field
+		 */
+		facs->xfirmware_waking_vector = physical_address;
 	}
 
 	return_ACPI_STATUS(AE_OK);
@@ -97,6 +113,8 @@
 acpi_status
 acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
 {
+	struct acpi_table_facs *facs;
+	acpi_status status;
 
 	ACPI_FUNCTION_TRACE(acpi_get_firmware_waking_vector);
 
@@ -104,16 +122,29 @@
 		return_ACPI_STATUS(AE_BAD_PARAMETER);
 	}
 
+	/* Get the FACS */
+
+	status =
+	    acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+				    (struct acpi_table_header **)&facs);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
 	/* Get the vector */
 
-	if (acpi_gbl_common_fACS.vector_width == 32) {
-		*physical_address = (acpi_physical_address)
-		    *
-		    (ACPI_CAST_PTR
-		     (u32, acpi_gbl_common_fACS.firmware_waking_vector));
-	} else {
+	if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) {
+		/*
+		 * ACPI 1.0 FACS or short table or optional X_ field is zero
+		 */
 		*physical_address =
-		    *acpi_gbl_common_fACS.firmware_waking_vector;
+		    (acpi_physical_address) facs->firmware_waking_vector;
+	} else {
+		/*
+		 * ACPI 2.0 FACS with valid X_ field
+		 */
+		*physical_address =
+		    (acpi_physical_address) facs->xfirmware_waking_vector;
 	}
 
 	return_ACPI_STATUS(AE_OK);
@@ -246,15 +277,14 @@
 
 	/* Clear wake status */
 
-	status =
-	    acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
+	status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1);
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
 
 	/* Clear all fixed and general purpose status bits */
 
-	status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK);
+	status = acpi_hw_clear_acpi_status();
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
@@ -367,8 +397,7 @@
 	/* Wait until we enter sleep state */
 
 	do {
-		status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value,
-					   ACPI_MTX_DO_NOT_LOCK);
+		status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value);
 		if (ACPI_FAILURE(status)) {
 			return_ACPI_STATUS(status);
 		}
@@ -401,13 +430,12 @@
 
 	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios);
 
-	status =
-	    acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
+	status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1);
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
 
-	status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK);
+	status = acpi_hw_clear_acpi_status();
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
@@ -429,13 +457,12 @@
 
 	ACPI_FLUSH_CPU_CACHE();
 
-	status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd,
-				    (u32) acpi_gbl_FADT->S4bios_req, 8);
+	status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+				    (u32) acpi_gbl_FADT.S4bios_request, 8);
 
 	do {
 		acpi_os_stall(1000);
-		status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value,
-					   ACPI_MTX_DO_NOT_LOCK);
+		status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value);
 		if (ACPI_FAILURE(status)) {
 			return_ACPI_STATUS(status);
 		}
@@ -568,13 +595,11 @@
 
 	(void)
 	    acpi_set_register(acpi_gbl_fixed_event_info
-			      [ACPI_EVENT_POWER_BUTTON].enable_register_id, 1,
-			      ACPI_MTX_DO_NOT_LOCK);
+			      [ACPI_EVENT_POWER_BUTTON].enable_register_id, 1);
 
 	(void)
 	    acpi_set_register(acpi_gbl_fixed_event_info
-			      [ACPI_EVENT_POWER_BUTTON].status_register_id, 1,
-			      ACPI_MTX_DO_NOT_LOCK);
+			      [ACPI_EVENT_POWER_BUTTON].status_register_id, 1);
 
 	arg.integer.value = ACPI_SST_WORKING;
 	status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c
index c4ec47c..c32eab6 100644
--- a/drivers/acpi/hardware/hwtimer.c
+++ b/drivers/acpi/hardware/hwtimer.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -66,7 +66,7 @@
 		return_ACPI_STATUS(AE_BAD_PARAMETER);
 	}
 
-	if (acpi_gbl_FADT->tmr_val_ext == 0) {
+	if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) {
 		*resolution = 24;
 	} else {
 		*resolution = 32;
@@ -98,7 +98,8 @@
 		return_ACPI_STATUS(AE_BAD_PARAMETER);
 	}
 
-	status = acpi_hw_low_level_read(32, ticks, &acpi_gbl_FADT->xpm_tmr_blk);
+	status =
+	    acpi_hw_low_level_read(32, ticks, &acpi_gbl_FADT.xpm_timer_block);
 
 	return_ACPI_STATUS(status);
 }
@@ -153,7 +154,7 @@
 	if (start_ticks < end_ticks) {
 		delta_ticks = end_ticks - start_ticks;
 	} else if (start_ticks > end_ticks) {
-		if (acpi_gbl_FADT->tmr_val_ext == 0) {
+		if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) {
 
 			/* 24-bit Timer */
 
diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c
deleted file mode 100644
index 2e17ec7..0000000
--- a/drivers/acpi/motherboard.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/* 
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *  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.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-/* Purpose: Prevent PCMCIA cards from using motherboard resources. */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <asm/io.h>
-
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
-
-#define _COMPONENT		ACPI_SYSTEM_COMPONENT
-ACPI_MODULE_NAME("acpi_motherboard")
-
-/* Dell use PNP0C01 instead of PNP0C02 */
-#define ACPI_MB_HID1			"PNP0C01"
-#define ACPI_MB_HID2			"PNP0C02"
-/**
- * Doesn't care about legacy IO ports, only IO ports beyond 0x1000 are reserved
- * Doesn't care about the failure of 'request_region', since other may reserve
- * the io ports as well
- */
-#define IS_RESERVED_ADDR(base, len) \
-	(((len) > 0) && ((base) > 0) && ((base) + (len) < IO_SPACE_LIMIT) \
-	&& ((base) + (len) > PCIBIOS_MIN_IO))
-/*
- * Clearing the flag (IORESOURCE_BUSY) allows drivers to use
- * the io ports if they really know they can use it, while
- * still preventing hotplug PCI devices from using it.
- */
-
-/*
- * When CONFIG_PNP is enabled, pnp/system.c binds to PNP0C01
- * and PNP0C02, redundant with acpi_reserve_io_ranges().
- * But acpi_reserve_io_ranges() is necessary for !CONFIG_PNP.
- */
-static acpi_status acpi_reserve_io_ranges(struct acpi_resource *res, void *data)
-{
-	struct resource *requested_res = NULL;
-
-
-	if (res->type == ACPI_RESOURCE_TYPE_IO) {
-		struct acpi_resource_io *io_res = &res->data.io;
-
-		if (io_res->minimum != io_res->maximum)
-			return AE_OK;
-		if (IS_RESERVED_ADDR
-		    (io_res->minimum, io_res->address_length)) {
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-					  "Motherboard resources 0x%08x - 0x%08x\n",
-					  io_res->minimum,
-					  io_res->minimum +
-					  io_res->address_length));
-			requested_res =
-			    request_region(io_res->minimum,
-					   io_res->address_length, "motherboard");
-		}
-	} else if (res->type == ACPI_RESOURCE_TYPE_FIXED_IO) {
-		struct acpi_resource_fixed_io *fixed_io_res =
-		    &res->data.fixed_io;
-
-		if (IS_RESERVED_ADDR
-		    (fixed_io_res->address, fixed_io_res->address_length)) {
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-					  "Motherboard resources 0x%08x - 0x%08x\n",
-					  fixed_io_res->address,
-					  fixed_io_res->address +
-					  fixed_io_res->address_length));
-			requested_res =
-			    request_region(fixed_io_res->address,
-					   fixed_io_res->address_length,
-					   "motherboard");
-		}
-	} else {
-		/* Memory mapped IO? */
-	}
-
-	if (requested_res)
-		requested_res->flags &= ~IORESOURCE_BUSY;
-	return AE_OK;
-}
-
-static int acpi_motherboard_add(struct acpi_device *device)
-{
-	if (!device)
-		return -EINVAL;
-	acpi_walk_resources(device->handle, METHOD_NAME__CRS,
-			    acpi_reserve_io_ranges, NULL);
-
-	return 0;
-}
-
-static struct acpi_driver acpi_motherboard_driver1 = {
-	.name = "motherboard",
-	.class = "",
-	.ids = ACPI_MB_HID1,
-	.ops = {
-		.add = acpi_motherboard_add,
-		},
-};
-
-static struct acpi_driver acpi_motherboard_driver2 = {
-	.name = "motherboard",
-	.class = "",
-	.ids = ACPI_MB_HID2,
-	.ops = {
-		.add = acpi_motherboard_add,
-		},
-};
-
-static void __init acpi_request_region (struct acpi_generic_address *addr,
-	unsigned int length, char *desc)
-{
-	if (!addr->address || !length)
-		return;
-
-	if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_IO)
-		request_region(addr->address, length, desc);
-	else if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
-		request_mem_region(addr->address, length, desc);
-}
-
-static void __init acpi_reserve_resources(void)
-{
-	acpi_request_region(&acpi_gbl_FADT->xpm1a_evt_blk,
-			       acpi_gbl_FADT->pm1_evt_len, "ACPI PM1a_EVT_BLK");
-
-	acpi_request_region(&acpi_gbl_FADT->xpm1b_evt_blk,
-			       acpi_gbl_FADT->pm1_evt_len, "ACPI PM1b_EVT_BLK");
-
-	acpi_request_region(&acpi_gbl_FADT->xpm1a_cnt_blk,
-			       acpi_gbl_FADT->pm1_cnt_len, "ACPI PM1a_CNT_BLK");
-
-	acpi_request_region(&acpi_gbl_FADT->xpm1b_cnt_blk,
-			       acpi_gbl_FADT->pm1_cnt_len, "ACPI PM1b_CNT_BLK");
-
-	if (acpi_gbl_FADT->pm_tm_len == 4)
-		acpi_request_region(&acpi_gbl_FADT->xpm_tmr_blk, 4, "ACPI PM_TMR");
-
-	acpi_request_region(&acpi_gbl_FADT->xpm2_cnt_blk,
-			       acpi_gbl_FADT->pm2_cnt_len, "ACPI PM2_CNT_BLK");
-
-	/* Length of GPE blocks must be a non-negative multiple of 2 */
-
-	if (!(acpi_gbl_FADT->gpe0_blk_len & 0x1))
-		acpi_request_region(&acpi_gbl_FADT->xgpe0_blk,
-			       acpi_gbl_FADT->gpe0_blk_len, "ACPI GPE0_BLK");
-
-	if (!(acpi_gbl_FADT->gpe1_blk_len & 0x1))
-		acpi_request_region(&acpi_gbl_FADT->xgpe1_blk,
-			       acpi_gbl_FADT->gpe1_blk_len, "ACPI GPE1_BLK");
-}
-
-static int __init acpi_motherboard_init(void)
-{
-	acpi_bus_register_driver(&acpi_motherboard_driver1);
-	acpi_bus_register_driver(&acpi_motherboard_driver2);
-	/*
-	 * Guarantee motherboard IO reservation first
-	 * This module must run after scan.c
-	 */
-	if (!acpi_disabled)
-		acpi_reserve_resources();
-	return 0;
-}
-
-/**
- * Reserve motherboard resources after PCI claim BARs,
- * but before PCI assign resources for uninitialized PCI devices
- */
-fs_initcall(acpi_motherboard_init);
diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c
index c1c6c23..57faf59 100644
--- a/drivers/acpi/namespace/nsaccess.c
+++ b/drivers/acpi/namespace/nsaccess.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -195,31 +195,27 @@
 				obj_desc->mutex.sync_level =
 				    (u8) (ACPI_TO_INTEGER(val) - 1);
 
+				/* Create a mutex */
+
+				status =
+				    acpi_os_create_mutex(&obj_desc->mutex.
+							 os_mutex);
+				if (ACPI_FAILURE(status)) {
+					acpi_ut_remove_reference(obj_desc);
+					goto unlock_and_exit;
+				}
+
+				/* Special case for ACPI Global Lock */
+
 				if (ACPI_STRCMP(init_val->name, "_GL_") == 0) {
+					acpi_gbl_global_lock_mutex =
+					    obj_desc->mutex.os_mutex;
 
-					/* Create a counting semaphore for the global lock */
+					/* Create additional counting semaphore for global lock */
 
 					status =
-					    acpi_os_create_semaphore
-					    (ACPI_NO_UNIT_LIMIT, 1,
-					     &acpi_gbl_global_lock_semaphore);
-					if (ACPI_FAILURE(status)) {
-						acpi_ut_remove_reference
-						    (obj_desc);
-						goto unlock_and_exit;
-					}
-
-					/* Mark this mutex as very special */
-
-					obj_desc->mutex.os_mutex =
-					    ACPI_GLOBAL_LOCK;
-				} else {
-					/* Create a mutex */
-
-					status =
-					    acpi_os_create_mutex(&obj_desc->
-								 mutex.
-								 os_mutex);
+					    acpi_os_create_semaphore(1, 0,
+								     &acpi_gbl_global_lock_semaphore);
 					if (ACPI_FAILURE(status)) {
 						acpi_ut_remove_reference
 						    (obj_desc);
diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c
index 55b407a..1d693d8 100644
--- a/drivers/acpi/namespace/nsalloc.c
+++ b/drivers/acpi/namespace/nsalloc.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -61,6 +61,9 @@
 struct acpi_namespace_node *acpi_ns_create_node(u32 name)
 {
 	struct acpi_namespace_node *node;
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+	u32 temp;
+#endif
 
 	ACPI_FUNCTION_TRACE(ns_create_node);
 
@@ -71,6 +74,15 @@
 
 	ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_allocated++);
 
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+	temp =
+	    acpi_gbl_ns_node_list->total_allocated -
+	    acpi_gbl_ns_node_list->total_freed;
+	if (temp > acpi_gbl_ns_node_list->max_occupied) {
+		acpi_gbl_ns_node_list->max_occupied = temp;
+	}
+#endif
+
 	node->name.integer = name;
 	ACPI_SET_DESCRIPTOR_TYPE(node, ACPI_DESC_TYPE_NAMED);
 	return_PTR(node);
diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c
index d72df66..1fc4f86 100644
--- a/drivers/acpi/namespace/nsdump.c
+++ b/drivers/acpi/namespace/nsdump.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -205,7 +205,7 @@
 
 		if (!acpi_ut_valid_acpi_name(this_node->name.integer)) {
 			this_node->name.integer =
-			    acpi_ut_repair_name(this_node->name.integer);
+			    acpi_ut_repair_name(this_node->name.ascii);
 
 			ACPI_WARNING((AE_INFO, "Invalid ACPI Name %08X",
 				      this_node->name.integer));
@@ -226,6 +226,12 @@
 	obj_desc = acpi_ns_get_attached_object(this_node);
 	acpi_dbg_level = dbg_level;
 
+	/* Temp nodes are those nodes created by a control method */
+
+	if (this_node->flags & ANOBJ_TEMPORARY) {
+		acpi_os_printf("(T) ");
+	}
+
 	switch (info->display_type & ACPI_DISPLAY_MASK) {
 	case ACPI_DISPLAY_SUMMARY:
 
@@ -623,7 +629,8 @@
 	info.display_type = display_type;
 
 	(void)acpi_ns_walk_namespace(type, start_handle, max_depth,
-				     ACPI_NS_WALK_NO_UNLOCK,
+				     ACPI_NS_WALK_NO_UNLOCK |
+				     ACPI_NS_WALK_TEMP_NODES,
 				     acpi_ns_dump_one_object, (void *)&info,
 				     NULL);
 }
diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c
index c6bf5d3..5097e16 100644
--- a/drivers/acpi/namespace/nsdumpdv.c
+++ b/drivers/acpi/namespace/nsdumpdv.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c
index 4b0a4a8..aa6370c 100644
--- a/drivers/acpi/namespace/nseval.c
+++ b/drivers/acpi/namespace/nseval.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -154,11 +154,7 @@
 		 * Execute the method via the interpreter. The interpreter is locked
 		 * here before calling into the AML parser
 		 */
-		status = acpi_ex_enter_interpreter();
-		if (ACPI_FAILURE(status)) {
-			return_ACPI_STATUS(status);
-		}
-
+		acpi_ex_enter_interpreter();
 		status = acpi_ps_execute_method(info);
 		acpi_ex_exit_interpreter();
 	} else {
@@ -182,10 +178,7 @@
 		 * resolution, we must lock it because we could access an opregion.
 		 * The opregion access code assumes that the interpreter is locked.
 		 */
-		status = acpi_ex_enter_interpreter();
-		if (ACPI_FAILURE(status)) {
-			return_ACPI_STATUS(status);
-		}
+		acpi_ex_enter_interpreter();
 
 		/* Function has a strange interface */
 
diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c
index aec8488..326af8f 100644
--- a/drivers/acpi/namespace/nsinit.c
+++ b/drivers/acpi/namespace/nsinit.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -213,7 +213,7 @@
 			u32 level, void *context, void **return_value)
 {
 	acpi_object_type type;
-	acpi_status status;
+	acpi_status status = AE_OK;
 	struct acpi_init_walk_info *info =
 	    (struct acpi_init_walk_info *)context;
 	struct acpi_namespace_node *node =
@@ -267,10 +267,7 @@
 	/*
 	 * Must lock the interpreter before executing AML code
 	 */
-	status = acpi_ex_enter_interpreter();
-	if (ACPI_FAILURE(status)) {
-		return (status);
-	}
+	acpi_ex_enter_interpreter();
 
 	/*
 	 * Each of these types can contain executable AML code within the
diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c
index fe75d88..d4f9654 100644
--- a/drivers/acpi/namespace/nsload.c
+++ b/drivers/acpi/namespace/nsload.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,13 +44,12 @@
 #include <acpi/acpi.h>
 #include <acpi/acnamesp.h>
 #include <acpi/acdispat.h>
+#include <acpi/actables.h>
 
 #define _COMPONENT          ACPI_NAMESPACE
 ACPI_MODULE_NAME("nsload")
 
 /* Local prototypes */
-static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type);
-
 #ifdef ACPI_FUTURE_IMPLEMENTATION
 acpi_status acpi_ns_unload_namespace(acpi_handle handle);
 
@@ -62,7 +61,7 @@
  *
  * FUNCTION:    acpi_ns_load_table
  *
- * PARAMETERS:  table_desc      - Descriptor for table to be loaded
+ * PARAMETERS:  table_index     - Index for table to be loaded
  *              Node            - Owning NS node
  *
  * RETURN:      Status
@@ -72,42 +71,13 @@
  ******************************************************************************/
 
 acpi_status
-acpi_ns_load_table(struct acpi_table_desc *table_desc,
+acpi_ns_load_table(acpi_native_uint table_index,
 		   struct acpi_namespace_node *node)
 {
 	acpi_status status;
 
 	ACPI_FUNCTION_TRACE(ns_load_table);
 
-	/* Check if table contains valid AML (must be DSDT, PSDT, SSDT, etc.) */
-
-	if (!
-	    (acpi_gbl_table_data[table_desc->type].
-	     flags & ACPI_TABLE_EXECUTABLE)) {
-
-		/* Just ignore this table */
-
-		return_ACPI_STATUS(AE_OK);
-	}
-
-	/* Check validity of the AML start and length */
-
-	if (!table_desc->aml_start) {
-		ACPI_ERROR((AE_INFO, "Null AML pointer"));
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-	}
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AML block at %p\n",
-			  table_desc->aml_start));
-
-	/* Ignore table if there is no AML contained within */
-
-	if (!table_desc->aml_length) {
-		ACPI_WARNING((AE_INFO, "Zero-length AML block in table [%4.4s]",
-			      table_desc->pointer->signature));
-		return_ACPI_STATUS(AE_OK);
-	}
-
 	/*
 	 * Parse the table and load the namespace with all named
 	 * objects found within.  Control methods are NOT parsed
@@ -117,15 +87,34 @@
 	 * to another control method, we can't continue parsing
 	 * because we don't know how many arguments to parse next!
 	 */
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-			  "**** Loading table into namespace ****\n"));
-
 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
 
-	status = acpi_ns_parse_table(table_desc, node->child);
+	/* If table already loaded into namespace, just return */
+
+	if (acpi_tb_is_table_loaded(table_index)) {
+		status = AE_ALREADY_EXISTS;
+		goto unlock;
+	}
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+			  "**** Loading table into namespace ****\n"));
+
+	status = acpi_tb_allocate_owner_id(table_index);
+	if (ACPI_FAILURE(status)) {
+		goto unlock;
+	}
+
+	status = acpi_ns_parse_table(table_index, node->child);
+	if (ACPI_SUCCESS(status)) {
+		acpi_tb_set_table_loaded_flag(table_index, TRUE);
+	} else {
+		acpi_tb_release_owner_id(table_index);
+	}
+
+      unlock:
 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 
 	if (ACPI_FAILURE(status)) {
@@ -141,7 +130,7 @@
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 			  "**** Begin Table Method Parsing and Object Initialization ****\n"));
 
-	status = acpi_ds_initialize_objects(table_desc, node);
+	status = acpi_ds_initialize_objects(table_index, node);
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 			  "**** Completed Table Method Parsing and Object Initialization ****\n"));
@@ -149,99 +138,7 @@
 	return_ACPI_STATUS(status);
 }
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ns_load_table_by_type
- *
- * PARAMETERS:  table_type          - Id of the table type to load
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Load an ACPI table or tables into the namespace.  All tables
- *              of the given type are loaded.  The mechanism allows this
- *              routine to be called repeatedly.
- *
- ******************************************************************************/
-
-static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type)
-{
-	u32 i;
-	acpi_status status;
-	struct acpi_table_desc *table_desc;
-
-	ACPI_FUNCTION_TRACE(ns_load_table_by_type);
-
-	status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/*
-	 * Table types supported are:
-	 * DSDT (one), SSDT/PSDT (multiple)
-	 */
-	switch (table_type) {
-	case ACPI_TABLE_ID_DSDT:
-
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace load: DSDT\n"));
-
-		table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_DSDT].next;
-
-		/* If table already loaded into namespace, just return */
-
-		if (table_desc->loaded_into_namespace) {
-			goto unlock_and_exit;
-		}
-
-		/* Now load the single DSDT */
-
-		status = acpi_ns_load_table(table_desc, acpi_gbl_root_node);
-		if (ACPI_SUCCESS(status)) {
-			table_desc->loaded_into_namespace = TRUE;
-		}
-		break;
-
-	case ACPI_TABLE_ID_SSDT:
-	case ACPI_TABLE_ID_PSDT:
-
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				  "Namespace load: %d SSDT or PSDTs\n",
-				  acpi_gbl_table_lists[table_type].count));
-
-		/*
-		 * Traverse list of SSDT or PSDT tables
-		 */
-		table_desc = acpi_gbl_table_lists[table_type].next;
-		for (i = 0; i < acpi_gbl_table_lists[table_type].count; i++) {
-			/*
-			 * Only attempt to load table into namespace if it is not
-			 * already loaded!
-			 */
-			if (!table_desc->loaded_into_namespace) {
-				status =
-				    acpi_ns_load_table(table_desc,
-						       acpi_gbl_root_node);
-				if (ACPI_FAILURE(status)) {
-					break;
-				}
-
-				table_desc->loaded_into_namespace = TRUE;
-			}
-
-			table_desc = table_desc->next;
-		}
-		break;
-
-	default:
-		status = AE_SUPPORT;
-		break;
-	}
-
-      unlock_and_exit:
-	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
-	return_ACPI_STATUS(status);
-}
-
+#ifdef ACPI_OBSOLETE_FUNCTIONS
 /*******************************************************************************
  *
  * FUNCTION:    acpi_load_namespace
@@ -288,6 +185,7 @@
 
 	return_ACPI_STATUS(status);
 }
+#endif
 
 #ifdef ACPI_FUTURE_IMPLEMENTATION
 /*******************************************************************************
diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c
index 97b8332..cbd94af 100644
--- a/drivers/acpi/namespace/nsnames.c
+++ b/drivers/acpi/namespace/nsnames.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c
index aabe879..d9d7377 100644
--- a/drivers/acpi/namespace/nsobject.c
+++ b/drivers/acpi/namespace/nsobject.c
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/namespace/nsparse.c
index 155505a..e696aa8 100644
--- a/drivers/acpi/namespace/nsparse.c
+++ b/drivers/acpi/namespace/nsparse.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -45,6 +45,7 @@
 #include <acpi/acnamesp.h>
 #include <acpi/acparser.h>
 #include <acpi/acdispat.h>
+#include <acpi/actables.h>
 
 #define _COMPONENT          ACPI_NAMESPACE
 ACPI_MODULE_NAME("nsparse")
@@ -62,14 +63,24 @@
  *
  ******************************************************************************/
 acpi_status
-acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc)
+acpi_ns_one_complete_parse(acpi_native_uint pass_number,
+			   acpi_native_uint table_index)
 {
 	union acpi_parse_object *parse_root;
 	acpi_status status;
+	acpi_native_uint aml_length;
+	u8 *aml_start;
 	struct acpi_walk_state *walk_state;
+	struct acpi_table_header *table;
+	acpi_owner_id owner_id;
 
 	ACPI_FUNCTION_TRACE(ns_one_complete_parse);
 
+	status = acpi_tb_get_owner_id(table_index, &owner_id);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
 	/* Create and init a Root Node */
 
 	parse_root = acpi_ps_create_scope_op();
@@ -79,26 +90,41 @@
 
 	/* Create and initialize a new walk state */
 
-	walk_state = acpi_ds_create_walk_state(table_desc->owner_id,
-					       NULL, NULL, NULL);
+	walk_state = acpi_ds_create_walk_state(owner_id, NULL, NULL, NULL);
 	if (!walk_state) {
 		acpi_ps_free_op(parse_root);
 		return_ACPI_STATUS(AE_NO_MEMORY);
 	}
 
-	status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
-				       table_desc->aml_start,
-				       table_desc->aml_length, NULL,
-				       pass_number);
+	status = acpi_get_table_by_index(table_index, &table);
 	if (ACPI_FAILURE(status)) {
 		acpi_ds_delete_walk_state(walk_state);
+		acpi_ps_free_op(parse_root);
+		return_ACPI_STATUS(status);
+	}
+
+	/* Table must consist of at least a complete header */
+
+	if (table->length < sizeof(struct acpi_table_header)) {
+		status = AE_BAD_HEADER;
+	} else {
+		aml_start = (u8 *) table + sizeof(struct acpi_table_header);
+		aml_length = table->length - sizeof(struct acpi_table_header);
+		status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
+					       aml_start, aml_length, NULL,
+					       (u8) pass_number);
+	}
+
+	if (ACPI_FAILURE(status)) {
+		acpi_ds_delete_walk_state(walk_state);
+		acpi_ps_delete_parse_tree(parse_root);
 		return_ACPI_STATUS(status);
 	}
 
 	/* Parse the AML */
 
 	ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "*PARSE* pass %d parse\n",
-			  pass_number));
+			  (unsigned)pass_number));
 	status = acpi_ps_parse_aml(walk_state);
 
 	acpi_ps_delete_parse_tree(parse_root);
@@ -119,7 +145,7 @@
  ******************************************************************************/
 
 acpi_status
-acpi_ns_parse_table(struct acpi_table_desc *table_desc,
+acpi_ns_parse_table(acpi_native_uint table_index,
 		    struct acpi_namespace_node *start_node)
 {
 	acpi_status status;
@@ -134,10 +160,10 @@
 	 * each Parser Op subtree is deleted when it is finished.  This saves
 	 * a great deal of memory, and allows a small cache of parse objects
 	 * to service the entire parse.  The second pass of the parse then
-	 * performs another complete parse of the AML..
+	 * performs another complete parse of the AML.
 	 */
 	ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 1\n"));
-	status = acpi_ns_one_complete_parse(1, table_desc);
+	status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index);
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
@@ -152,7 +178,7 @@
 	 * parse objects are all cached.
 	 */
 	ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 2\n"));
-	status = acpi_ns_one_complete_parse(2, table_desc);
+	status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index);
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c
index 500e2bb..e863be6 100644
--- a/drivers/acpi/namespace/nssearch.c
+++ b/drivers/acpi/namespace/nssearch.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -321,7 +321,8 @@
 	 * even though there are a few bad names.
 	 */
 	if (!acpi_ut_valid_acpi_name(target_name)) {
-		target_name = acpi_ut_repair_name(target_name);
+		target_name =
+		    acpi_ut_repair_name(ACPI_CAST_PTR(char, &target_name));
 
 		/* Report warning only if in strict mode or debug mode */
 
@@ -401,6 +402,10 @@
 	}
 #endif
 
+	if (flags & ACPI_NS_TEMPORARY) {
+		new_node->flags |= ANOBJ_TEMPORARY;
+	}
+
 	/* Install the new object into the parent's list of children */
 
 	acpi_ns_install_node(walk_state, node, new_node, type);
diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c
index aa4e799..90fd059 100644
--- a/drivers/acpi/namespace/nsutils.c
+++ b/drivers/acpi/namespace/nsutils.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -770,13 +770,6 @@
 	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace freed\n"));
-
-	/*
-	 * 2) Now we can delete the ACPI tables
-	 */
-	acpi_tb_delete_all_tables();
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n"));
-
 	return_VOID;
 }
 
diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c
index c8f6bef..94eb8f3 100644
--- a/drivers/acpi/namespace/nswalk.c
+++ b/drivers/acpi/namespace/nswalk.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -126,7 +126,7 @@
  * PARAMETERS:  Type                - acpi_object_type to search for
  *              start_node          - Handle in namespace where search begins
  *              max_depth           - Depth to which search is to reach
- *              unlock_before_callback- Whether to unlock the NS before invoking
+ *              Flags               - Whether to unlock the NS before invoking
  *                                    the callback routine
  *              user_function       - Called when an object of "Type" is found
  *              Context             - Passed to user function
@@ -153,7 +153,7 @@
 acpi_ns_walk_namespace(acpi_object_type type,
 		       acpi_handle start_node,
 		       u32 max_depth,
-		       u8 unlock_before_callback,
+		       u32 flags,
 		       acpi_walk_callback user_function,
 		       void *context, void **return_value)
 {
@@ -193,20 +193,34 @@
 		    acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
 					  child_node);
 		if (child_node) {
-			/*
-			 * Found node, Get the type if we are not
-			 * searching for ANY
-			 */
+
+			/* Found next child, get the type if we are not searching for ANY */
+
 			if (type != ACPI_TYPE_ANY) {
 				child_type = child_node->type;
 			}
 
-			if (child_type == type) {
+			/*
+			 * Ignore all temporary namespace nodes (created during control
+			 * method execution) unless told otherwise. These temporary nodes
+			 * can cause a race condition because they can be deleted during the
+			 * execution of the user function (if the namespace is unlocked before
+			 * invocation of the user function.) Only the debugger namespace dump
+			 * will examine the temporary nodes.
+			 */
+			if ((child_node->flags & ANOBJ_TEMPORARY) &&
+			    !(flags & ACPI_NS_WALK_TEMP_NODES)) {
+				status = AE_CTRL_DEPTH;
+			}
+
+			/* Type must match requested type */
+
+			else if (child_type == type) {
 				/*
-				 * Found a matching node, invoke the user
-				 * callback function
+				 * Found a matching node, invoke the user callback function.
+				 * Unlock the namespace if flag is set.
 				 */
-				if (unlock_before_callback) {
+				if (flags & ACPI_NS_WALK_UNLOCK) {
 					mutex_status =
 					    acpi_ut_release_mutex
 					    (ACPI_MTX_NAMESPACE);
@@ -216,10 +230,11 @@
 					}
 				}
 
-				status = user_function(child_node, level,
-						       context, return_value);
+				status =
+				    user_function(child_node, level, context,
+						  return_value);
 
-				if (unlock_before_callback) {
+				if (flags & ACPI_NS_WALK_UNLOCK) {
 					mutex_status =
 					    acpi_ut_acquire_mutex
 					    (ACPI_MTX_NAMESPACE);
@@ -251,20 +266,17 @@
 			}
 
 			/*
-			 * Depth first search:
-			 * Attempt to go down another level in the namespace
-			 * if we are allowed to.  Don't go any further if we
-			 * have reached the caller specified maximum depth
-			 * or if the user function has specified that the
-			 * maximum depth has been reached.
+			 * Depth first search: Attempt to go down another level in the
+			 * namespace if we are allowed to.  Don't go any further if we have
+			 * reached the caller specified maximum depth or if the user
+			 * function has specified that the maximum depth has been reached.
 			 */
 			if ((level < max_depth) && (status != AE_CTRL_DEPTH)) {
 				if (acpi_ns_get_next_node
 				    (ACPI_TYPE_ANY, child_node, NULL)) {
-					/*
-					 * There is at least one child of this
-					 * node, visit the onde
-					 */
+
+					/* There is at least one child of this node, visit it */
+
 					level++;
 					parent_node = child_node;
 					child_node = NULL;
@@ -272,9 +284,8 @@
 			}
 		} else {
 			/*
-			 * No more children of this node (acpi_ns_get_next_node
-			 * failed), go back upwards in the namespace tree to
-			 * the node's parent.
+			 * No more children of this node (acpi_ns_get_next_node failed), go
+			 * back upwards in the namespace tree to the node's parent.
 			 */
 			level--;
 			child_node = parent_node;
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index dca6799..7ac6ace 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -170,7 +170,6 @@
 		     struct acpi_buffer *return_buffer)
 {
 	acpi_status status;
-	acpi_status status2;
 	struct acpi_evaluate_info *info;
 	acpi_size buffer_space_needed;
 	u32 i;
@@ -329,14 +328,12 @@
 		 * Delete the internal return object. NOTE: Interpreter must be
 		 * locked to avoid race condition.
 		 */
-		status2 = acpi_ex_enter_interpreter();
-		if (ACPI_SUCCESS(status2)) {
+		acpi_ex_enter_interpreter();
 
-			/* Remove one reference on the return object (should delete it) */
+		/* Remove one reference on the return object (should delete it) */
 
-			acpi_ut_remove_reference(info->return_object);
-			acpi_ex_exit_interpreter();
-		}
+		acpi_ut_remove_reference(info->return_object);
+		acpi_ex_exit_interpreter();
 	}
 
       cleanup:
diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c
index 978213a..b489781 100644
--- a/drivers/acpi/namespace/nsxfname.c
+++ b/drivers/acpi/namespace/nsxfname.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -84,38 +84,41 @@
 	/* Convert a parent handle to a prefix node */
 
 	if (parent) {
-		status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
-		if (ACPI_FAILURE(status)) {
-			return (status);
-		}
-
 		prefix_node = acpi_ns_map_handle_to_node(parent);
 		if (!prefix_node) {
-			(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 			return (AE_BAD_PARAMETER);
 		}
-
-		status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
-		if (ACPI_FAILURE(status)) {
-			return (status);
-		}
-	}
-
-	/* Special case for root, since we can't search for it */
-
-	if (ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH) == 0) {
-		*ret_handle =
-		    acpi_ns_convert_entry_to_handle(acpi_gbl_root_node);
-		return (AE_OK);
 	}
 
 	/*
-	 *  Find the Node and convert to a handle
+	 * Valid cases are:
+	 * 1) Fully qualified pathname
+	 * 2) Parent + Relative pathname
+	 *
+	 * Error for <null Parent + relative path>
 	 */
-	status = acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH,
-				  &node);
+	if (acpi_ns_valid_root_prefix(pathname[0])) {
 
-	*ret_handle = NULL;
+		/* Pathname is fully qualified (starts with '\') */
+
+		/* Special case for root-only, since we can't search for it */
+
+		if (!ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH)) {
+			*ret_handle =
+			    acpi_ns_convert_entry_to_handle(acpi_gbl_root_node);
+			return (AE_OK);
+		}
+	} else if (!prefix_node) {
+
+		/* Relative path with null prefix is disallowed */
+
+		return (AE_BAD_PARAMETER);
+	}
+
+	/* Find the Node and convert to a handle */
+
+	status =
+	    acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node);
 	if (ACPI_SUCCESS(status)) {
 		*ret_handle = acpi_ns_convert_entry_to_handle(node);
 	}
diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c
index a18b1c2..faa3758 100644
--- a/drivers/acpi/namespace/nsxfobj.c
+++ b/drivers/acpi/namespace/nsxfobj.c
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index bd96a70..4a9faff 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -45,7 +45,7 @@
 int __cpuinitdata node_to_pxm_map[MAX_NUMNODES]
 				= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
 
-extern int __init acpi_table_parse_madt_family(enum acpi_table_id id,
+extern int __init acpi_table_parse_madt_family(char *id,
 					       unsigned long madt_size,
 					       int entry_id,
 					       acpi_madt_entry_handler handler,
@@ -89,7 +89,7 @@
 	node_clear(node, nodes_found_map);
 }
 
-void __init acpi_table_print_srat_entry(acpi_table_entry_header * header)
+void __init acpi_table_print_srat_entry(struct acpi_subtable_header * header)
 {
 
 	ACPI_FUNCTION_NAME("acpi_table_print_srat_entry");
@@ -99,36 +99,35 @@
 
 	switch (header->type) {
 
-	case ACPI_SRAT_PROCESSOR_AFFINITY:
+	case ACPI_SRAT_TYPE_CPU_AFFINITY:
 #ifdef ACPI_DEBUG_OUTPUT
 		{
-			struct acpi_table_processor_affinity *p =
-			    (struct acpi_table_processor_affinity *)header;
+			struct acpi_srat_cpu_affinity *p =
+			    (struct acpi_srat_cpu_affinity *)header;
 			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 					  "SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n",
-					  p->apic_id, p->lsapic_eid,
-					  p->proximity_domain,
-					  p->flags.
-					  enabled ? "enabled" : "disabled"));
+					  p->apic_id, p->local_sapic_eid,
+					  p->proximity_domain_lo,
+					  (p->flags & ACPI_SRAT_CPU_ENABLED)?
+					  "enabled" : "disabled"));
 		}
 #endif				/* ACPI_DEBUG_OUTPUT */
 		break;
 
-	case ACPI_SRAT_MEMORY_AFFINITY:
+	case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
 #ifdef ACPI_DEBUG_OUTPUT
 		{
-			struct acpi_table_memory_affinity *p =
-			    (struct acpi_table_memory_affinity *)header;
+			struct acpi_srat_mem_affinity *p =
+			    (struct acpi_srat_mem_affinity *)header;
 			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-					  "SRAT Memory (0x%08x%08x length 0x%08x%08x type 0x%x) in proximity domain %d %s%s\n",
-					  p->base_addr_hi, p->base_addr_lo,
-					  p->length_hi, p->length_lo,
+					  "SRAT Memory (0x%lx length 0x%lx type 0x%x) in proximity domain %d %s%s\n",
+					  (unsigned long)p->base_address,
+					  (unsigned long)p->length,
 					  p->memory_type, p->proximity_domain,
-					  p->flags.
-					  enabled ? "enabled" : "disabled",
-					  p->flags.
-					  hot_pluggable ? " hot-pluggable" :
-					  ""));
+					  (p->flags & ACPI_SRAT_MEM_ENABLED)?
+					  "enabled" : "disabled",
+					  (p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)?
+					  " hot-pluggable" : ""));
 		}
 #endif				/* ACPI_DEBUG_OUTPUT */
 		break;
@@ -141,18 +140,18 @@
 	}
 }
 
-static int __init acpi_parse_slit(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_slit(struct acpi_table_header *table)
 {
 	struct acpi_table_slit *slit;
 	u32 localities;
 
-	if (!phys_addr || !size)
+	if (!table)
 		return -EINVAL;
 
-	slit = (struct acpi_table_slit *)__va(phys_addr);
+	slit = (struct acpi_table_slit *)table;
 
 	/* downcast just for %llu vs %lu for i386/ia64  */
-	localities = (u32) slit->localities;
+	localities = (u32) slit->locality_count;
 
 	acpi_numa_slit_init(slit);
 
@@ -160,12 +159,12 @@
 }
 
 static int __init
-acpi_parse_processor_affinity(acpi_table_entry_header * header,
+acpi_parse_processor_affinity(struct acpi_subtable_header * header,
 			      const unsigned long end)
 {
-	struct acpi_table_processor_affinity *processor_affinity;
+	struct acpi_srat_cpu_affinity *processor_affinity;
 
-	processor_affinity = (struct acpi_table_processor_affinity *)header;
+	processor_affinity = (struct acpi_srat_cpu_affinity *)header;
 	if (!processor_affinity)
 		return -EINVAL;
 
@@ -178,12 +177,12 @@
 }
 
 static int __init
-acpi_parse_memory_affinity(acpi_table_entry_header * header,
+acpi_parse_memory_affinity(struct acpi_subtable_header * header,
 			   const unsigned long end)
 {
-	struct acpi_table_memory_affinity *memory_affinity;
+	struct acpi_srat_mem_affinity *memory_affinity;
 
-	memory_affinity = (struct acpi_table_memory_affinity *)header;
+	memory_affinity = (struct acpi_srat_mem_affinity *)header;
 	if (!memory_affinity)
 		return -EINVAL;
 
@@ -195,23 +194,23 @@
 	return 0;
 }
 
-static int __init acpi_parse_srat(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_srat(struct acpi_table_header *table)
 {
 	struct acpi_table_srat *srat;
 
-	if (!phys_addr || !size)
+	if (!table)
 		return -EINVAL;
 
-	srat = (struct acpi_table_srat *)__va(phys_addr);
+	srat = (struct acpi_table_srat *)table;
 
 	return 0;
 }
 
 int __init
-acpi_table_parse_srat(enum acpi_srat_entry_id id,
+acpi_table_parse_srat(enum acpi_srat_type id,
 		      acpi_madt_entry_handler handler, unsigned int max_entries)
 {
-	return acpi_table_parse_madt_family(ACPI_SRAT,
+	return acpi_table_parse_madt_family(ACPI_SIG_SRAT,
 					    sizeof(struct acpi_table_srat), id,
 					    handler, max_entries);
 }
@@ -221,17 +220,17 @@
 	int result;
 
 	/* SRAT: Static Resource Affinity Table */
-	result = acpi_table_parse(ACPI_SRAT, acpi_parse_srat);
+	result = acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat);
 
 	if (result > 0) {
-		result = acpi_table_parse_srat(ACPI_SRAT_PROCESSOR_AFFINITY,
+		result = acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
 					       acpi_parse_processor_affinity,
 					       NR_CPUS);
-		result = acpi_table_parse_srat(ACPI_SRAT_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS);	// IA64 specific
+		result = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS);	// IA64 specific
 	}
 
 	/* SLIT: System Locality Information Table */
-	result = acpi_table_parse(ACPI_SLIT, acpi_parse_slit);
+	result = acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit);
 
 	acpi_numa_arch_fixup();
 	return 0;
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 57ae1e5..0f6f3bc 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -36,6 +36,7 @@
 #include <linux/delay.h>
 #include <linux/workqueue.h>
 #include <linux/nmi.h>
+#include <linux/acpi.h>
 #include <acpi/acpi.h>
 #include <asm/io.h>
 #include <acpi/acpi_bus.h>
@@ -75,6 +76,54 @@
 static void *acpi_irq_context;
 static struct workqueue_struct *kacpid_wq;
 
+static void __init acpi_request_region (struct acpi_generic_address *addr,
+	unsigned int length, char *desc)
+{
+	struct resource *res;
+
+	if (!addr->address || !length)
+		return;
+
+	if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO)
+		res = request_region(addr->address, length, desc);
+	else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+		res = request_mem_region(addr->address, length, desc);
+}
+
+static int __init acpi_reserve_resources(void)
+{
+	acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length,
+		"ACPI PM1a_EVT_BLK");
+
+	acpi_request_region(&acpi_gbl_FADT.xpm1b_event_block, acpi_gbl_FADT.pm1_event_length,
+		"ACPI PM1b_EVT_BLK");
+
+	acpi_request_region(&acpi_gbl_FADT.xpm1a_control_block, acpi_gbl_FADT.pm1_control_length,
+		"ACPI PM1a_CNT_BLK");
+
+	acpi_request_region(&acpi_gbl_FADT.xpm1b_control_block, acpi_gbl_FADT.pm1_control_length,
+		"ACPI PM1b_CNT_BLK");
+
+	if (acpi_gbl_FADT.pm_timer_length == 4)
+		acpi_request_region(&acpi_gbl_FADT.xpm_timer_block, 4, "ACPI PM_TMR");
+
+	acpi_request_region(&acpi_gbl_FADT.xpm2_control_block, acpi_gbl_FADT.pm2_control_length,
+		"ACPI PM2_CNT_BLK");
+
+	/* Length of GPE blocks must be a non-negative multiple of 2 */
+
+	if (!(acpi_gbl_FADT.gpe0_block_length & 0x1))
+		acpi_request_region(&acpi_gbl_FADT.xgpe0_block,
+			       acpi_gbl_FADT.gpe0_block_length, "ACPI GPE0_BLK");
+
+	if (!(acpi_gbl_FADT.gpe1_block_length & 0x1))
+		acpi_request_region(&acpi_gbl_FADT.xgpe1_block,
+			       acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK");
+
+	return 0;
+}
+device_initcall(acpi_reserve_resources);
+
 acpi_status acpi_os_initialize(void)
 {
 	return AE_OK;
@@ -136,53 +185,43 @@
 #endif
 }
 
-acpi_status acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *addr)
+acpi_physical_address __init acpi_os_get_root_pointer(void)
 {
 	if (efi_enabled) {
-		addr->pointer_type = ACPI_PHYSICAL_POINTER;
 		if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
-			addr->pointer.physical = efi.acpi20;
+			return efi.acpi20;
 		else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
-			addr->pointer.physical = efi.acpi;
+			return efi.acpi;
 		else {
 			printk(KERN_ERR PREFIX
 			       "System description tables not found\n");
-			return AE_NOT_FOUND;
+			return 0;
 		}
-	} else {
-		if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) {
-			printk(KERN_ERR PREFIX
-			       "System description tables not found\n");
-			return AE_NOT_FOUND;
-		}
-	}
-
-	return AE_OK;
+	} else
+		return acpi_find_rsdp();
 }
 
-acpi_status
-acpi_os_map_memory(acpi_physical_address phys, acpi_size size,
-		   void __iomem ** virt)
+void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
 {
 	if (phys > ULONG_MAX) {
 		printk(KERN_ERR PREFIX "Cannot map memory that high\n");
-		return AE_BAD_PARAMETER;
+		return 0;
 	}
-	/*
-	 * ioremap checks to ensure this is in reserved space
-	 */
-	*virt = ioremap((unsigned long)phys, size);
-
-	if (!*virt)
-		return AE_NO_MEMORY;
-
-	return AE_OK;
+	if (acpi_gbl_permanent_mmap)
+		/*
+		* ioremap checks to ensure this is in reserved space
+		*/
+		return ioremap((unsigned long)phys, size);
+	else
+		return __acpi_map_table((unsigned long)phys, size);
 }
 EXPORT_SYMBOL_GPL(acpi_os_map_memory);
 
 void acpi_os_unmap_memory(void __iomem * virt, acpi_size size)
 {
-	iounmap(virt);
+	if (acpi_gbl_permanent_mmap) {
+		iounmap(virt);
+	}
 }
 EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
 
@@ -254,7 +293,7 @@
 	 * FADT. It may not be the same if an interrupt source override exists
 	 * for the SCI.
 	 */
-	gsi = acpi_fadt.sci_int;
+	gsi = acpi_gbl_FADT.sci_interrupt;
 	if (acpi_gsi_to_irq(gsi, &irq) < 0) {
 		printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n",
 		       gsi);
diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c
index bf88e07..c2b9835 100644
--- a/drivers/acpi/parser/psargs.c
+++ b/drivers/acpi/parser/psargs.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/parser/psloop.c
index e1541db..773aee8 100644
--- a/drivers/acpi/parser/psloop.c
+++ b/drivers/acpi/parser/psloop.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,12 +42,11 @@
  */
 
 /*
- * Parse the AML and build an operation tree as most interpreters,
- * like Perl, do.  Parsing is done by hand rather than with a YACC
- * generated parser to tightly constrain stack and dynamic memory
- * usage.  At the same time, parsing is kept flexible and the code
- * fairly compact by parsing based on a list of AML opcode
- * templates in aml_op_info[]
+ * Parse the AML and build an operation tree as most interpreters, (such as
+ * Perl) do. Parsing is done by hand rather than with a YACC generated parser
+ * to tightly constrain stack and dynamic memory usage. Parsing is kept
+ * flexible and the code fairly compact by parsing based on a list of AML
+ * opcode templates in aml_op_info[].
  */
 
 #include <acpi/acpi.h>
@@ -60,6 +59,761 @@
 
 static u32 acpi_gbl_depth = 0;
 
+/* Local prototypes */
+
+static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state);
+
+static acpi_status
+acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
+		       u8 * aml_op_start,
+		       union acpi_parse_object *unnamed_op,
+		       union acpi_parse_object **op);
+
+static acpi_status
+acpi_ps_create_op(struct acpi_walk_state *walk_state,
+		  u8 * aml_op_start, union acpi_parse_object **new_op);
+
+static acpi_status
+acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
+		      u8 * aml_op_start, union acpi_parse_object *op);
+
+static acpi_status
+acpi_ps_complete_op(struct acpi_walk_state *walk_state,
+		    union acpi_parse_object **op, acpi_status status);
+
+static acpi_status
+acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
+			  union acpi_parse_object *op, acpi_status status);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_get_aml_opcode
+ *
+ * PARAMETERS:  walk_state          - Current state
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Extract the next AML opcode from the input stream.
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state)
+{
+
+	ACPI_FUNCTION_TRACE_PTR(ps_get_aml_opcode, walk_state);
+
+	walk_state->aml_offset =
+	    (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml,
+				walk_state->parser_state.aml_start);
+	walk_state->opcode = acpi_ps_peek_opcode(&(walk_state->parser_state));
+
+	/*
+	 * First cut to determine what we have found:
+	 * 1) A valid AML opcode
+	 * 2) A name string
+	 * 3) An unknown/invalid opcode
+	 */
+	walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
+
+	switch (walk_state->op_info->class) {
+	case AML_CLASS_ASCII:
+	case AML_CLASS_PREFIX:
+		/*
+		 * Starts with a valid prefix or ASCII char, this is a name
+		 * string. Convert the bare name string to a namepath.
+		 */
+		walk_state->opcode = AML_INT_NAMEPATH_OP;
+		walk_state->arg_types = ARGP_NAMESTRING;
+		break;
+
+	case AML_CLASS_UNKNOWN:
+
+		/* The opcode is unrecognized. Just skip unknown opcodes */
+
+		ACPI_ERROR((AE_INFO,
+			    "Found unknown opcode %X at AML address %p offset %X, ignoring",
+			    walk_state->opcode, walk_state->parser_state.aml,
+			    walk_state->aml_offset));
+
+		ACPI_DUMP_BUFFER(walk_state->parser_state.aml, 128);
+
+		/* Assume one-byte bad opcode */
+
+		walk_state->parser_state.aml++;
+		return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
+
+	default:
+
+		/* Found opcode info, this is a normal opcode */
+
+		walk_state->parser_state.aml +=
+		    acpi_ps_get_opcode_size(walk_state->opcode);
+		walk_state->arg_types = walk_state->op_info->parse_args;
+		break;
+	}
+
+	return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_build_named_op
+ *
+ * PARAMETERS:  walk_state          - Current state
+ *              aml_op_start        - Begin of named Op in AML
+ *              unnamed_op          - Early Op (not a named Op)
+ *              Op                  - Returned Op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Parse a named Op
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
+		       u8 * aml_op_start,
+		       union acpi_parse_object *unnamed_op,
+		       union acpi_parse_object **op)
+{
+	acpi_status status = AE_OK;
+	union acpi_parse_object *arg = NULL;
+
+	ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state);
+
+	unnamed_op->common.value.arg = NULL;
+	unnamed_op->common.aml_opcode = walk_state->opcode;
+
+	/*
+	 * Get and append arguments until we find the node that contains
+	 * the name (the type ARGP_NAME).
+	 */
+	while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) &&
+	       (GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) {
+		status =
+		    acpi_ps_get_next_arg(walk_state,
+					 &(walk_state->parser_state),
+					 GET_CURRENT_ARG_TYPE(walk_state->
+							      arg_types), &arg);
+		if (ACPI_FAILURE(status)) {
+			return_ACPI_STATUS(status);
+		}
+
+		acpi_ps_append_arg(unnamed_op, arg);
+		INCREMENT_ARG_LIST(walk_state->arg_types);
+	}
+
+	/*
+	 * Make sure that we found a NAME and didn't run out of arguments
+	 */
+	if (!GET_CURRENT_ARG_TYPE(walk_state->arg_types)) {
+		return_ACPI_STATUS(AE_AML_NO_OPERAND);
+	}
+
+	/* We know that this arg is a name, move to next arg */
+
+	INCREMENT_ARG_LIST(walk_state->arg_types);
+
+	/*
+	 * Find the object. This will either insert the object into
+	 * the namespace or simply look it up
+	 */
+	walk_state->op = NULL;
+
+	status = walk_state->descending_callback(walk_state, op);
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "During name lookup/catalog"));
+		return_ACPI_STATUS(status);
+	}
+
+	if (!*op) {
+		return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
+	}
+
+	status = acpi_ps_next_parse_state(walk_state, *op, status);
+	if (ACPI_FAILURE(status)) {
+		if (status == AE_CTRL_PENDING) {
+			return_ACPI_STATUS(AE_CTRL_PARSE_PENDING);
+		}
+		return_ACPI_STATUS(status);
+	}
+
+	acpi_ps_append_arg(*op, unnamed_op->common.value.arg);
+	acpi_gbl_depth++;
+
+	if ((*op)->common.aml_opcode == AML_REGION_OP) {
+		/*
+		 * Defer final parsing of an operation_region body, because we don't
+		 * have enough info in the first pass to parse it correctly (i.e.,
+		 * there may be method calls within the term_arg elements of the body.)
+		 *
+		 * However, we must continue parsing because the opregion is not a
+		 * standalone package -- we don't know where the end is at this point.
+		 *
+		 * (Length is unknown until parse of the body complete)
+		 */
+		(*op)->named.data = aml_op_start;
+		(*op)->named.length = 0;
+	}
+
+	return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_create_op
+ *
+ * PARAMETERS:  walk_state          - Current state
+ *              aml_op_start        - Op start in AML
+ *              new_op              - Returned Op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Get Op from AML
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ps_create_op(struct acpi_walk_state *walk_state,
+		  u8 * aml_op_start, union acpi_parse_object **new_op)
+{
+	acpi_status status = AE_OK;
+	union acpi_parse_object *op;
+	union acpi_parse_object *named_op = NULL;
+
+	ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state);
+
+	status = acpi_ps_get_aml_opcode(walk_state);
+	if (status == AE_CTRL_PARSE_CONTINUE) {
+		return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
+	}
+
+	/* Create Op structure and append to parent's argument list */
+
+	walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
+	op = acpi_ps_alloc_op(walk_state->opcode);
+	if (!op) {
+		return_ACPI_STATUS(AE_NO_MEMORY);
+	}
+
+	if (walk_state->op_info->flags & AML_NAMED) {
+		status =
+		    acpi_ps_build_named_op(walk_state, aml_op_start, op,
+					   &named_op);
+		acpi_ps_free_op(op);
+		if (ACPI_FAILURE(status)) {
+			return_ACPI_STATUS(status);
+		}
+
+		*new_op = named_op;
+		return_ACPI_STATUS(AE_OK);
+	}
+
+	/* Not a named opcode, just allocate Op and append to parent */
+
+	if (walk_state->op_info->flags & AML_CREATE) {
+		/*
+		 * Backup to beginning of create_xXXfield declaration
+		 * body_length is unknown until we parse the body
+		 */
+		op->named.data = aml_op_start;
+		op->named.length = 0;
+	}
+
+	acpi_ps_append_arg(acpi_ps_get_parent_scope
+			   (&(walk_state->parser_state)), op);
+
+	if (walk_state->descending_callback != NULL) {
+		/*
+		 * Find the object. This will either insert the object into
+		 * the namespace or simply look it up
+		 */
+		walk_state->op = *new_op = op;
+
+		status = walk_state->descending_callback(walk_state, &op);
+		status = acpi_ps_next_parse_state(walk_state, op, status);
+		if (status == AE_CTRL_PENDING) {
+			status = AE_CTRL_PARSE_PENDING;
+		}
+	}
+
+	return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_get_arguments
+ *
+ * PARAMETERS:  walk_state          - Current state
+ *              aml_op_start        - Op start in AML
+ *              Op                  - Current Op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Get arguments for passed Op.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
+		      u8 * aml_op_start, union acpi_parse_object *op)
+{
+	acpi_status status = AE_OK;
+	union acpi_parse_object *arg = NULL;
+
+	ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state);
+
+	switch (op->common.aml_opcode) {
+	case AML_BYTE_OP:	/* AML_BYTEDATA_ARG */
+	case AML_WORD_OP:	/* AML_WORDDATA_ARG */
+	case AML_DWORD_OP:	/* AML_DWORDATA_ARG */
+	case AML_QWORD_OP:	/* AML_QWORDATA_ARG */
+	case AML_STRING_OP:	/* AML_ASCIICHARLIST_ARG */
+
+		/* Fill in constant or string argument directly */
+
+		acpi_ps_get_next_simple_arg(&(walk_state->parser_state),
+					    GET_CURRENT_ARG_TYPE(walk_state->
+								 arg_types),
+					    op);
+		break;
+
+	case AML_INT_NAMEPATH_OP:	/* AML_NAMESTRING_ARG */
+
+		status =
+		    acpi_ps_get_next_namepath(walk_state,
+					      &(walk_state->parser_state), op,
+					      1);
+		if (ACPI_FAILURE(status)) {
+			return_ACPI_STATUS(status);
+		}
+
+		walk_state->arg_types = 0;
+		break;
+
+	default:
+		/*
+		 * Op is not a constant or string, append each argument to the Op
+		 */
+		while (GET_CURRENT_ARG_TYPE(walk_state->arg_types)
+		       && !walk_state->arg_count) {
+			walk_state->aml_offset =
+			    (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml,
+						walk_state->parser_state.
+						aml_start);
+
+			status =
+			    acpi_ps_get_next_arg(walk_state,
+						 &(walk_state->parser_state),
+						 GET_CURRENT_ARG_TYPE
+						 (walk_state->arg_types), &arg);
+			if (ACPI_FAILURE(status)) {
+				return_ACPI_STATUS(status);
+			}
+
+			if (arg) {
+				arg->common.aml_offset = walk_state->aml_offset;
+				acpi_ps_append_arg(op, arg);
+			}
+
+			INCREMENT_ARG_LIST(walk_state->arg_types);
+		}
+
+		/* Special processing for certain opcodes */
+
+		/* TBD (remove): Temporary mechanism to disable this code if needed */
+
+#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE
+
+		if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS1) &&
+		    ((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) {
+			/*
+			 * We want to skip If/Else/While constructs during Pass1 because we
+			 * want to actually conditionally execute the code during Pass2.
+			 *
+			 * Except for disassembly, where we always want to walk the
+			 * If/Else/While packages
+			 */
+			switch (op->common.aml_opcode) {
+			case AML_IF_OP:
+			case AML_ELSE_OP:
+			case AML_WHILE_OP:
+
+				ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+						  "Pass1: Skipping an If/Else/While body\n"));
+
+				/* Skip body of if/else/while in pass 1 */
+
+				walk_state->parser_state.aml =
+				    walk_state->parser_state.pkg_end;
+				walk_state->arg_count = 0;
+				break;
+
+			default:
+				break;
+			}
+		}
+#endif
+
+		switch (op->common.aml_opcode) {
+		case AML_METHOD_OP:
+			/*
+			 * Skip parsing of control method because we don't have enough
+			 * info in the first pass to parse it correctly.
+			 *
+			 * Save the length and address of the body
+			 */
+			op->named.data = walk_state->parser_state.aml;
+			op->named.length = (u32)
+			    (walk_state->parser_state.pkg_end -
+			     walk_state->parser_state.aml);
+
+			/* Skip body of method */
+
+			walk_state->parser_state.aml =
+			    walk_state->parser_state.pkg_end;
+			walk_state->arg_count = 0;
+			break;
+
+		case AML_BUFFER_OP:
+		case AML_PACKAGE_OP:
+		case AML_VAR_PACKAGE_OP:
+
+			if ((op->common.parent) &&
+			    (op->common.parent->common.aml_opcode ==
+			     AML_NAME_OP)
+			    && (walk_state->pass_number <=
+				ACPI_IMODE_LOAD_PASS2)) {
+				/*
+				 * Skip parsing of Buffers and Packages because we don't have
+				 * enough info in the first pass to parse them correctly.
+				 */
+				op->named.data = aml_op_start;
+				op->named.length = (u32)
+				    (walk_state->parser_state.pkg_end -
+				     aml_op_start);
+
+				/* Skip body */
+
+				walk_state->parser_state.aml =
+				    walk_state->parser_state.pkg_end;
+				walk_state->arg_count = 0;
+			}
+			break;
+
+		case AML_WHILE_OP:
+
+			if (walk_state->control_state) {
+				walk_state->control_state->control.package_end =
+				    walk_state->parser_state.pkg_end;
+			}
+			break;
+
+		default:
+
+			/* No action for all other opcodes */
+			break;
+		}
+
+		break;
+	}
+
+	return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_complete_op
+ *
+ * PARAMETERS:  walk_state          - Current state
+ *              Op                  - Returned Op
+ *              Status              - Parse status before complete Op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Complete Op
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ps_complete_op(struct acpi_walk_state *walk_state,
+		    union acpi_parse_object **op, acpi_status status)
+{
+	acpi_status status2;
+
+	ACPI_FUNCTION_TRACE_PTR(ps_complete_op, walk_state);
+
+	/*
+	 * Finished one argument of the containing scope
+	 */
+	walk_state->parser_state.scope->parse_scope.arg_count--;
+
+	/* Close this Op (will result in parse subtree deletion) */
+
+	status2 = acpi_ps_complete_this_op(walk_state, *op);
+	if (ACPI_FAILURE(status2)) {
+		return_ACPI_STATUS(status2);
+	}
+
+	*op = NULL;
+
+	switch (status) {
+	case AE_OK:
+		break;
+
+	case AE_CTRL_TRANSFER:
+
+		/* We are about to transfer to a called method */
+
+		walk_state->prev_op = NULL;
+		walk_state->prev_arg_types = walk_state->arg_types;
+		return_ACPI_STATUS(status);
+
+	case AE_CTRL_END:
+
+		acpi_ps_pop_scope(&(walk_state->parser_state), op,
+				  &walk_state->arg_types,
+				  &walk_state->arg_count);
+
+		if (*op) {
+			walk_state->op = *op;
+			walk_state->op_info =
+			    acpi_ps_get_opcode_info((*op)->common.aml_opcode);
+			walk_state->opcode = (*op)->common.aml_opcode;
+
+			status = walk_state->ascending_callback(walk_state);
+			status =
+			    acpi_ps_next_parse_state(walk_state, *op, status);
+
+			status2 = acpi_ps_complete_this_op(walk_state, *op);
+			if (ACPI_FAILURE(status2)) {
+				return_ACPI_STATUS(status2);
+			}
+		}
+
+		status = AE_OK;
+		break;
+
+	case AE_CTRL_BREAK:
+	case AE_CTRL_CONTINUE:
+
+		/* Pop off scopes until we find the While */
+
+		while (!(*op) || ((*op)->common.aml_opcode != AML_WHILE_OP)) {
+			acpi_ps_pop_scope(&(walk_state->parser_state), op,
+					  &walk_state->arg_types,
+					  &walk_state->arg_count);
+
+			if ((*op)->common.aml_opcode != AML_WHILE_OP) {
+				status2 = acpi_ds_result_stack_pop(walk_state);
+				if (ACPI_FAILURE(status2)) {
+					return_ACPI_STATUS(status2);
+				}
+			}
+		}
+
+		/* Close this iteration of the While loop */
+
+		walk_state->op = *op;
+		walk_state->op_info =
+		    acpi_ps_get_opcode_info((*op)->common.aml_opcode);
+		walk_state->opcode = (*op)->common.aml_opcode;
+
+		status = walk_state->ascending_callback(walk_state);
+		status = acpi_ps_next_parse_state(walk_state, *op, status);
+
+		status2 = acpi_ps_complete_this_op(walk_state, *op);
+		if (ACPI_FAILURE(status2)) {
+			return_ACPI_STATUS(status2);
+		}
+
+		status = AE_OK;
+		break;
+
+	case AE_CTRL_TERMINATE:
+
+		/* Clean up */
+		do {
+			if (*op) {
+				status2 =
+				    acpi_ps_complete_this_op(walk_state, *op);
+				if (ACPI_FAILURE(status2)) {
+					return_ACPI_STATUS(status2);
+				}
+				status2 = acpi_ds_result_stack_pop(walk_state);
+				if (ACPI_FAILURE(status2)) {
+					return_ACPI_STATUS(status2);
+				}
+
+				acpi_ut_delete_generic_state
+				    (acpi_ut_pop_generic_state
+				     (&walk_state->control_state));
+			}
+
+			acpi_ps_pop_scope(&(walk_state->parser_state), op,
+					  &walk_state->arg_types,
+					  &walk_state->arg_count);
+
+		} while (*op);
+
+		return_ACPI_STATUS(AE_OK);
+
+	default:		/* All other non-AE_OK status */
+
+		do {
+			if (*op) {
+				status2 =
+				    acpi_ps_complete_this_op(walk_state, *op);
+				if (ACPI_FAILURE(status2)) {
+					return_ACPI_STATUS(status2);
+				}
+			}
+
+			acpi_ps_pop_scope(&(walk_state->parser_state), op,
+					  &walk_state->arg_types,
+					  &walk_state->arg_count);
+
+		} while (*op);
+
+#if 0
+		/*
+		 * TBD: Cleanup parse ops on error
+		 */
+		if (*op == NULL) {
+			acpi_ps_pop_scope(parser_state, op,
+					  &walk_state->arg_types,
+					  &walk_state->arg_count);
+		}
+#endif
+		walk_state->prev_op = NULL;
+		walk_state->prev_arg_types = walk_state->arg_types;
+		return_ACPI_STATUS(status);
+	}
+
+	/* This scope complete? */
+
+	if (acpi_ps_has_completed_scope(&(walk_state->parser_state))) {
+		acpi_ps_pop_scope(&(walk_state->parser_state), op,
+				  &walk_state->arg_types,
+				  &walk_state->arg_count);
+		ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *op));
+	} else {
+		*op = NULL;
+	}
+
+	return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_complete_final_op
+ *
+ * PARAMETERS:  walk_state          - Current state
+ *              Op                  - Current Op
+ *              Status              - Current parse status before complete last
+ *                                    Op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Complete last Op.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
+			  union acpi_parse_object *op, acpi_status status)
+{
+	acpi_status status2;
+
+	ACPI_FUNCTION_TRACE_PTR(ps_complete_final_op, walk_state);
+
+	/*
+	 * Complete the last Op (if not completed), and clear the scope stack.
+	 * It is easily possible to end an AML "package" with an unbounded number
+	 * of open scopes (such as when several ASL blocks are closed with
+	 * sequential closing braces). We want to terminate each one cleanly.
+	 */
+	ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n",
+			  op));
+	do {
+		if (op) {
+			if (walk_state->ascending_callback != NULL) {
+				walk_state->op = op;
+				walk_state->op_info =
+				    acpi_ps_get_opcode_info(op->common.
+							    aml_opcode);
+				walk_state->opcode = op->common.aml_opcode;
+
+				status =
+				    walk_state->ascending_callback(walk_state);
+				status =
+				    acpi_ps_next_parse_state(walk_state, op,
+							     status);
+				if (status == AE_CTRL_PENDING) {
+					status =
+					    acpi_ps_complete_op(walk_state, &op,
+								AE_OK);
+					if (ACPI_FAILURE(status)) {
+						return_ACPI_STATUS(status);
+					}
+				}
+
+				if (status == AE_CTRL_TERMINATE) {
+					status = AE_OK;
+
+					/* Clean up */
+					do {
+						if (op) {
+							status2 =
+							    acpi_ps_complete_this_op
+							    (walk_state, op);
+							if (ACPI_FAILURE
+							    (status2)) {
+								return_ACPI_STATUS
+								    (status2);
+							}
+						}
+
+						acpi_ps_pop_scope(&
+								  (walk_state->
+								   parser_state),
+								  &op,
+								  &walk_state->
+								  arg_types,
+								  &walk_state->
+								  arg_count);
+
+					} while (op);
+
+					return_ACPI_STATUS(status);
+				}
+
+				else if (ACPI_FAILURE(status)) {
+
+					/* First error is most important */
+
+					(void)
+					    acpi_ps_complete_this_op(walk_state,
+								     op);
+					return_ACPI_STATUS(status);
+				}
+			}
+
+			status2 = acpi_ps_complete_this_op(walk_state, op);
+			if (ACPI_FAILURE(status2)) {
+				return_ACPI_STATUS(status2);
+			}
+		}
+
+		acpi_ps_pop_scope(&(walk_state->parser_state), &op,
+				  &walk_state->arg_types,
+				  &walk_state->arg_count);
+
+	} while (op);
+
+	return_ACPI_STATUS(status);
+}
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ps_parse_loop
@@ -76,10 +830,7 @@
 acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
 {
 	acpi_status status = AE_OK;
-	acpi_status status2;
 	union acpi_parse_object *op = NULL;	/* current op */
-	union acpi_parse_object *arg = NULL;
-	union acpi_parse_object *pre_op = NULL;
 	struct acpi_parse_state *parser_state;
 	u8 *aml_op_start = NULL;
 
@@ -128,6 +879,7 @@
 								"Invoked method did not return a value"));
 
 					}
+
 					ACPI_EXCEPTION((AE_INFO, status,
 							"GetPredicate Failed"));
 					return_ACPI_STATUS(status);
@@ -158,217 +910,25 @@
 	while ((parser_state->aml < parser_state->aml_end) || (op)) {
 		aml_op_start = parser_state->aml;
 		if (!op) {
-
-			/* Get the next opcode from the AML stream */
-
-			walk_state->aml_offset =
-			    (u32) ACPI_PTR_DIFF(parser_state->aml,
-						parser_state->aml_start);
-			walk_state->opcode = acpi_ps_peek_opcode(parser_state);
-
-			/*
-			 * First cut to determine what we have found:
-			 * 1) A valid AML opcode
-			 * 2) A name string
-			 * 3) An unknown/invalid opcode
-			 */
-			walk_state->op_info =
-			    acpi_ps_get_opcode_info(walk_state->opcode);
-			switch (walk_state->op_info->class) {
-			case AML_CLASS_ASCII:
-			case AML_CLASS_PREFIX:
-				/*
-				 * Starts with a valid prefix or ASCII char, this is a name
-				 * string.  Convert the bare name string to a namepath.
-				 */
-				walk_state->opcode = AML_INT_NAMEPATH_OP;
-				walk_state->arg_types = ARGP_NAMESTRING;
-				break;
-
-			case AML_CLASS_UNKNOWN:
-
-				/* The opcode is unrecognized.  Just skip unknown opcodes */
-
-				ACPI_ERROR((AE_INFO,
-					    "Found unknown opcode %X at AML address %p offset %X, ignoring",
-					    walk_state->opcode,
-					    parser_state->aml,
-					    walk_state->aml_offset));
-
-				ACPI_DUMP_BUFFER(parser_state->aml, 128);
-
-				/* Assume one-byte bad opcode */
-
-				parser_state->aml++;
-				continue;
-
-			default:
-
-				/* Found opcode info, this is a normal opcode */
-
-				parser_state->aml +=
-				    acpi_ps_get_opcode_size(walk_state->opcode);
-				walk_state->arg_types =
-				    walk_state->op_info->parse_args;
-				break;
-			}
-
-			/* Create Op structure and append to parent's argument list */
-
-			if (walk_state->op_info->flags & AML_NAMED) {
-
-				/* Allocate a new pre_op if necessary */
-
-				if (!pre_op) {
-					pre_op =
-					    acpi_ps_alloc_op(walk_state->
-							     opcode);
-					if (!pre_op) {
-						status = AE_NO_MEMORY;
-						goto close_this_op;
-					}
-				}
-
-				pre_op->common.value.arg = NULL;
-				pre_op->common.aml_opcode = walk_state->opcode;
-
-				/*
-				 * Get and append arguments until we find the node that contains
-				 * the name (the type ARGP_NAME).
-				 */
-				while (GET_CURRENT_ARG_TYPE
-				       (walk_state->arg_types)
-				       &&
-				       (GET_CURRENT_ARG_TYPE
-					(walk_state->arg_types) != ARGP_NAME)) {
-					status =
-					    acpi_ps_get_next_arg(walk_state,
-								 parser_state,
-								 GET_CURRENT_ARG_TYPE
-								 (walk_state->
-								  arg_types),
-								 &arg);
-					if (ACPI_FAILURE(status)) {
-						goto close_this_op;
-					}
-
-					acpi_ps_append_arg(pre_op, arg);
-					INCREMENT_ARG_LIST(walk_state->
-							   arg_types);
-				}
-
-				/*
-				 * Make sure that we found a NAME and didn't run out of
-				 * arguments
-				 */
-				if (!GET_CURRENT_ARG_TYPE
-				    (walk_state->arg_types)) {
-					status = AE_AML_NO_OPERAND;
-					goto close_this_op;
-				}
-
-				/* We know that this arg is a name, move to next arg */
-
-				INCREMENT_ARG_LIST(walk_state->arg_types);
-
-				/*
-				 * Find the object.  This will either insert the object into
-				 * the namespace or simply look it up
-				 */
-				walk_state->op = NULL;
-
-				status =
-				    walk_state->descending_callback(walk_state,
-								    &op);
-				if (ACPI_FAILURE(status)) {
-					ACPI_EXCEPTION((AE_INFO, status,
-							"During name lookup/catalog"));
-					goto close_this_op;
-				}
-
-				if (!op) {
+			status =
+			    acpi_ps_create_op(walk_state, aml_op_start, &op);
+			if (ACPI_FAILURE(status)) {
+				if (status == AE_CTRL_PARSE_CONTINUE) {
 					continue;
 				}
 
-				status =
-				    acpi_ps_next_parse_state(walk_state, op,
-							     status);
-				if (status == AE_CTRL_PENDING) {
+				if (status == AE_CTRL_PARSE_PENDING) {
 					status = AE_OK;
-					goto close_this_op;
 				}
 
+				status =
+				    acpi_ps_complete_op(walk_state, &op,
+							status);
 				if (ACPI_FAILURE(status)) {
-					goto close_this_op;
+					return_ACPI_STATUS(status);
 				}
 
-				acpi_ps_append_arg(op,
-						   pre_op->common.value.arg);
-				acpi_gbl_depth++;
-
-				if (op->common.aml_opcode == AML_REGION_OP) {
-					/*
-					 * Defer final parsing of an operation_region body,
-					 * because we don't have enough info in the first pass
-					 * to parse it correctly (i.e., there may be method
-					 * calls within the term_arg elements of the body.)
-					 *
-					 * However, we must continue parsing because
-					 * the opregion is not a standalone package --
-					 * we don't know where the end is at this point.
-					 *
-					 * (Length is unknown until parse of the body complete)
-					 */
-					op->named.data = aml_op_start;
-					op->named.length = 0;
-				}
-			} else {
-				/* Not a named opcode, just allocate Op and append to parent */
-
-				walk_state->op_info =
-				    acpi_ps_get_opcode_info(walk_state->opcode);
-				op = acpi_ps_alloc_op(walk_state->opcode);
-				if (!op) {
-					status = AE_NO_MEMORY;
-					goto close_this_op;
-				}
-
-				if (walk_state->op_info->flags & AML_CREATE) {
-					/*
-					 * Backup to beginning of create_xXXfield declaration
-					 * body_length is unknown until we parse the body
-					 */
-					op->named.data = aml_op_start;
-					op->named.length = 0;
-				}
-
-				acpi_ps_append_arg(acpi_ps_get_parent_scope
-						   (parser_state), op);
-
-				if ((walk_state->descending_callback != NULL)) {
-					/*
-					 * Find the object. This will either insert the object into
-					 * the namespace or simply look it up
-					 */
-					walk_state->op = op;
-
-					status =
-					    walk_state->
-					    descending_callback(walk_state,
-								&op);
-					status =
-					    acpi_ps_next_parse_state(walk_state,
-								     op,
-								     status);
-					if (status == AE_CTRL_PENDING) {
-						status = AE_OK;
-						goto close_this_op;
-					}
-
-					if (ACPI_FAILURE(status)) {
-						goto close_this_op;
-					}
-				}
+				continue;
 			}
 
 			op->common.aml_offset = walk_state->aml_offset;
@@ -395,172 +955,17 @@
 
 			/* Get arguments */
 
-			switch (op->common.aml_opcode) {
-			case AML_BYTE_OP:	/* AML_BYTEDATA_ARG */
-			case AML_WORD_OP:	/* AML_WORDDATA_ARG */
-			case AML_DWORD_OP:	/* AML_DWORDATA_ARG */
-			case AML_QWORD_OP:	/* AML_QWORDATA_ARG */
-			case AML_STRING_OP:	/* AML_ASCIICHARLIST_ARG */
-
-				/* Fill in constant or string argument directly */
-
-				acpi_ps_get_next_simple_arg(parser_state,
-							    GET_CURRENT_ARG_TYPE
-							    (walk_state->
-							     arg_types), op);
-				break;
-
-			case AML_INT_NAMEPATH_OP:	/* AML_NAMESTRING_ARG */
-
+			status =
+			    acpi_ps_get_arguments(walk_state, aml_op_start, op);
+			if (ACPI_FAILURE(status)) {
 				status =
-				    acpi_ps_get_next_namepath(walk_state,
-							      parser_state, op,
-							      1);
+				    acpi_ps_complete_op(walk_state, &op,
+							status);
 				if (ACPI_FAILURE(status)) {
-					goto close_this_op;
+					return_ACPI_STATUS(status);
 				}
 
-				walk_state->arg_types = 0;
-				break;
-
-			default:
-				/*
-				 * Op is not a constant or string, append each argument
-				 * to the Op
-				 */
-				while (GET_CURRENT_ARG_TYPE
-				       (walk_state->arg_types)
-				       && !walk_state->arg_count) {
-					walk_state->aml_offset = (u32)
-					    ACPI_PTR_DIFF(parser_state->aml,
-							  parser_state->
-							  aml_start);
-
-					status =
-					    acpi_ps_get_next_arg(walk_state,
-								 parser_state,
-								 GET_CURRENT_ARG_TYPE
-								 (walk_state->
-								  arg_types),
-								 &arg);
-					if (ACPI_FAILURE(status)) {
-						goto close_this_op;
-					}
-
-					if (arg) {
-						arg->common.aml_offset =
-						    walk_state->aml_offset;
-						acpi_ps_append_arg(op, arg);
-					}
-					INCREMENT_ARG_LIST(walk_state->
-							   arg_types);
-				}
-
-				/* Special processing for certain opcodes */
-
-				/* TBD (remove): Temporary mechanism to disable this code if needed */
-
-#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE
-
-				if ((walk_state->pass_number <=
-				     ACPI_IMODE_LOAD_PASS1)
-				    &&
-				    ((walk_state->
-				      parse_flags & ACPI_PARSE_DISASSEMBLE) ==
-				     0)) {
-					/*
-					 * We want to skip If/Else/While constructs during Pass1
-					 * because we want to actually conditionally execute the
-					 * code during Pass2.
-					 *
-					 * Except for disassembly, where we always want to
-					 * walk the If/Else/While packages
-					 */
-					switch (op->common.aml_opcode) {
-					case AML_IF_OP:
-					case AML_ELSE_OP:
-					case AML_WHILE_OP:
-
-						ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
-								  "Pass1: Skipping an If/Else/While body\n"));
-
-						/* Skip body of if/else/while in pass 1 */
-
-						parser_state->aml =
-						    parser_state->pkg_end;
-						walk_state->arg_count = 0;
-						break;
-
-					default:
-						break;
-					}
-				}
-#endif
-				switch (op->common.aml_opcode) {
-				case AML_METHOD_OP:
-
-					/*
-					 * Skip parsing of control method
-					 * because we don't have enough info in the first pass
-					 * to parse it correctly.
-					 *
-					 * Save the length and address of the body
-					 */
-					op->named.data = parser_state->aml;
-					op->named.length =
-					    (u32) (parser_state->pkg_end -
-						   parser_state->aml);
-
-					/* Skip body of method */
-
-					parser_state->aml =
-					    parser_state->pkg_end;
-					walk_state->arg_count = 0;
-					break;
-
-				case AML_BUFFER_OP:
-				case AML_PACKAGE_OP:
-				case AML_VAR_PACKAGE_OP:
-
-					if ((op->common.parent) &&
-					    (op->common.parent->common.
-					     aml_opcode == AML_NAME_OP)
-					    && (walk_state->pass_number <=
-						ACPI_IMODE_LOAD_PASS2)) {
-						/*
-						 * Skip parsing of Buffers and Packages
-						 * because we don't have enough info in the first pass
-						 * to parse them correctly.
-						 */
-						op->named.data = aml_op_start;
-						op->named.length =
-						    (u32) (parser_state->
-							   pkg_end -
-							   aml_op_start);
-
-						/* Skip body */
-
-						parser_state->aml =
-						    parser_state->pkg_end;
-						walk_state->arg_count = 0;
-					}
-					break;
-
-				case AML_WHILE_OP:
-
-					if (walk_state->control_state) {
-						walk_state->control_state->
-						    control.package_end =
-						    parser_state->pkg_end;
-					}
-					break;
-
-				default:
-
-					/* No action for all other opcodes */
-					break;
-				}
-				break;
+				continue;
 			}
 		}
 
@@ -575,8 +980,16 @@
 						    walk_state->arg_types,
 						    walk_state->arg_count);
 			if (ACPI_FAILURE(status)) {
-				goto close_this_op;
+				status =
+				    acpi_ps_complete_op(walk_state, &op,
+							status);
+				if (ACPI_FAILURE(status)) {
+					return_ACPI_STATUS(status);
+				}
+
+				continue;
 			}
+
 			op = NULL;
 			continue;
 		}
@@ -628,269 +1041,16 @@
 			    acpi_ps_next_parse_state(walk_state, op, status);
 			if (status == AE_CTRL_PENDING) {
 				status = AE_OK;
-				goto close_this_op;
 			}
 		}
 
-	      close_this_op:
-		/*
-		 * Finished one argument of the containing scope
-		 */
-		parser_state->scope->parse_scope.arg_count--;
-
-		/* Finished with pre_op */
-
-		if (pre_op) {
-			acpi_ps_free_op(pre_op);
-			pre_op = NULL;
-		}
-
-		/* Close this Op (will result in parse subtree deletion) */
-
-		status2 = acpi_ps_complete_this_op(walk_state, op);
-		if (ACPI_FAILURE(status2)) {
-			return_ACPI_STATUS(status2);
-		}
-		op = NULL;
-
-		switch (status) {
-		case AE_OK:
-			break;
-
-		case AE_CTRL_TRANSFER:
-
-			/* We are about to transfer to a called method. */
-
-			walk_state->prev_op = op;
-			walk_state->prev_arg_types = walk_state->arg_types;
+		status = acpi_ps_complete_op(walk_state, &op, status);
+		if (ACPI_FAILURE(status)) {
 			return_ACPI_STATUS(status);
-
-		case AE_CTRL_END:
-
-			acpi_ps_pop_scope(parser_state, &op,
-					  &walk_state->arg_types,
-					  &walk_state->arg_count);
-
-			if (op) {
-				walk_state->op = op;
-				walk_state->op_info =
-				    acpi_ps_get_opcode_info(op->common.
-							    aml_opcode);
-				walk_state->opcode = op->common.aml_opcode;
-
-				status =
-				    walk_state->ascending_callback(walk_state);
-				status =
-				    acpi_ps_next_parse_state(walk_state, op,
-							     status);
-
-				status2 =
-				    acpi_ps_complete_this_op(walk_state, op);
-				if (ACPI_FAILURE(status2)) {
-					return_ACPI_STATUS(status2);
-				}
-				op = NULL;
-			}
-			status = AE_OK;
-			break;
-
-		case AE_CTRL_BREAK:
-		case AE_CTRL_CONTINUE:
-
-			/* Pop off scopes until we find the While */
-
-			while (!op || (op->common.aml_opcode != AML_WHILE_OP)) {
-				acpi_ps_pop_scope(parser_state, &op,
-						  &walk_state->arg_types,
-						  &walk_state->arg_count);
-
-				if (op->common.aml_opcode != AML_WHILE_OP) {
-					status2 =
-					    acpi_ds_result_stack_pop
-					    (walk_state);
-					if (ACPI_FAILURE(status2)) {
-						return_ACPI_STATUS(status2);
-					}
-				}
-			}
-
-			/* Close this iteration of the While loop */
-
-			walk_state->op = op;
-			walk_state->op_info =
-			    acpi_ps_get_opcode_info(op->common.aml_opcode);
-			walk_state->opcode = op->common.aml_opcode;
-
-			status = walk_state->ascending_callback(walk_state);
-			status =
-			    acpi_ps_next_parse_state(walk_state, op, status);
-
-			status2 = acpi_ps_complete_this_op(walk_state, op);
-			if (ACPI_FAILURE(status2)) {
-				return_ACPI_STATUS(status2);
-			}
-			op = NULL;
-
-			status = AE_OK;
-			break;
-
-		case AE_CTRL_TERMINATE:
-
-			status = AE_OK;
-
-			/* Clean up */
-			do {
-				if (op) {
-					status2 =
-					    acpi_ps_complete_this_op(walk_state,
-								     op);
-					if (ACPI_FAILURE(status2)) {
-						return_ACPI_STATUS(status2);
-					}
-
-					status2 =
-					    acpi_ds_result_stack_pop
-					    (walk_state);
-					if (ACPI_FAILURE(status2)) {
-						return_ACPI_STATUS(status2);
-					}
-
-					acpi_ut_delete_generic_state
-					    (acpi_ut_pop_generic_state
-					     (&walk_state->control_state));
-				}
-
-				acpi_ps_pop_scope(parser_state, &op,
-						  &walk_state->arg_types,
-						  &walk_state->arg_count);
-
-			} while (op);
-
-			return_ACPI_STATUS(status);
-
-		default:	/* All other non-AE_OK status */
-
-			do {
-				if (op) {
-					status2 =
-					    acpi_ps_complete_this_op(walk_state,
-								     op);
-					if (ACPI_FAILURE(status2)) {
-						return_ACPI_STATUS(status2);
-					}
-				}
-
-				acpi_ps_pop_scope(parser_state, &op,
-						  &walk_state->arg_types,
-						  &walk_state->arg_count);
-
-			} while (op);
-
-			/*
-			 * TBD: Cleanup parse ops on error
-			 */
-#if 0
-			if (op == NULL) {
-				acpi_ps_pop_scope(parser_state, &op,
-						  &walk_state->arg_types,
-						  &walk_state->arg_count);
-			}
-#endif
-			walk_state->prev_op = op;
-			walk_state->prev_arg_types = walk_state->arg_types;
-			return_ACPI_STATUS(status);
-		}
-
-		/* This scope complete? */
-
-		if (acpi_ps_has_completed_scope(parser_state)) {
-			acpi_ps_pop_scope(parser_state, &op,
-					  &walk_state->arg_types,
-					  &walk_state->arg_count);
-			ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
-					  "Popped scope, Op=%p\n", op));
-		} else {
-			op = NULL;
 		}
 
 	}			/* while parser_state->Aml */
 
-	/*
-	 * Complete the last Op (if not completed), and clear the scope stack.
-	 * It is easily possible to end an AML "package" with an unbounded number
-	 * of open scopes (such as when several ASL blocks are closed with
-	 * sequential closing braces).  We want to terminate each one cleanly.
-	 */
-	ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n",
-			  op));
-	do {
-		if (op) {
-			if (walk_state->ascending_callback != NULL) {
-				walk_state->op = op;
-				walk_state->op_info =
-				    acpi_ps_get_opcode_info(op->common.
-							    aml_opcode);
-				walk_state->opcode = op->common.aml_opcode;
-
-				status =
-				    walk_state->ascending_callback(walk_state);
-				status =
-				    acpi_ps_next_parse_state(walk_state, op,
-							     status);
-				if (status == AE_CTRL_PENDING) {
-					status = AE_OK;
-					goto close_this_op;
-				}
-
-				if (status == AE_CTRL_TERMINATE) {
-					status = AE_OK;
-
-					/* Clean up */
-					do {
-						if (op) {
-							status2 =
-							    acpi_ps_complete_this_op
-							    (walk_state, op);
-							if (ACPI_FAILURE
-							    (status2)) {
-								return_ACPI_STATUS
-								    (status2);
-							}
-						}
-
-						acpi_ps_pop_scope(parser_state,
-								  &op,
-								  &walk_state->
-								  arg_types,
-								  &walk_state->
-								  arg_count);
-
-					} while (op);
-
-					return_ACPI_STATUS(status);
-				}
-
-				else if (ACPI_FAILURE(status)) {
-
-					/* First error is most important */
-
-					(void)
-					    acpi_ps_complete_this_op(walk_state,
-								     op);
-					return_ACPI_STATUS(status);
-				}
-			}
-
-			status2 = acpi_ps_complete_this_op(walk_state, op);
-			if (ACPI_FAILURE(status2)) {
-				return_ACPI_STATUS(status2);
-			}
-		}
-
-		acpi_ps_pop_scope(parser_state, &op, &walk_state->arg_types,
-				  &walk_state->arg_count);
-
-	} while (op);
-
+	status = acpi_ps_complete_final_op(walk_state, op, status);
 	return_ACPI_STATUS(status);
 }
diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c
index 4bd25e3..16d8b6cc 100644
--- a/drivers/acpi/parser/psopcode.c
+++ b/drivers/acpi/parser/psopcode.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c
index a02aa62..5d63f48 100644
--- a/drivers/acpi/parser/psparse.c
+++ b/drivers/acpi/parser/psparse.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -540,6 +540,11 @@
 
 			if ((status == AE_ALREADY_EXISTS) &&
 			    (!walk_state->method_desc->method.mutex)) {
+				ACPI_INFO((AE_INFO,
+					   "Marking method %4.4s as Serialized",
+					   walk_state->method_node->name.
+					   ascii));
+
 				/*
 				 * Method tried to create an object twice. The probable cause is
 				 * that the method cannot handle reentrancy.
diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c
index a3e0314d..77cfa4e 100644
--- a/drivers/acpi/parser/psscope.c
+++ b/drivers/acpi/parser/psscope.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c
index 0015717..966e7ea 100644
--- a/drivers/acpi/parser/pstree.c
+++ b/drivers/acpi/parser/pstree.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c
index d405387..8ca5200 100644
--- a/drivers/acpi/parser/psutils.c
+++ b/drivers/acpi/parser/psutils.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c
index a84a547..49f9757 100644
--- a/drivers/acpi/parser/pswalk.c
+++ b/drivers/acpi/parser/pswalk.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c
index 5d996c1..94103bc 100644
--- a/drivers/acpi/parser/psxface.c
+++ b/drivers/acpi/parser/psxface.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -54,8 +54,6 @@
 
 static void acpi_ps_stop_trace(struct acpi_evaluate_info *info);
 
-static acpi_status acpi_ps_execute_pass(struct acpi_evaluate_info *info);
-
 static void
 acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action);
 
@@ -215,6 +213,8 @@
 acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
 {
 	acpi_status status;
+	union acpi_parse_object *op;
+	struct acpi_walk_state *walk_state;
 
 	ACPI_FUNCTION_TRACE(ps_execute_method);
 
@@ -234,8 +234,7 @@
 	}
 
 	/*
-	 * The caller "owns" the parameters, so give each one an extra
-	 * reference
+	 * The caller "owns" the parameters, so give each one an extra reference
 	 */
 	acpi_ps_update_parameter_list(info, REF_INCREMENT);
 
@@ -244,30 +243,50 @@
 	acpi_ps_start_trace(info);
 
 	/*
-	 * 1) Perform the first pass parse of the method to enter any
-	 *    named objects that it creates into the namespace
+	 * Execute the method. Performs parse simultaneously
 	 */
 	ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
-			  "**** Begin Method Parse **** Entry=%p obj=%p\n",
-			  info->resolved_node, info->obj_desc));
+			  "**** Begin Method Parse/Execute [%4.4s] **** Node=%p Obj=%p\n",
+			  info->resolved_node->name.ascii, info->resolved_node,
+			  info->obj_desc));
 
-	info->pass_number = 1;
-	status = acpi_ps_execute_pass(info);
-	if (ACPI_FAILURE(status)) {
+	/* Create and init a Root Node */
+
+	op = acpi_ps_create_scope_op();
+	if (!op) {
+		status = AE_NO_MEMORY;
 		goto cleanup;
 	}
 
-	/*
-	 * 2) Execute the method. Performs second pass parse simultaneously
-	 */
-	ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
-			  "**** Begin Method Execution **** Entry=%p obj=%p\n",
-			  info->resolved_node, info->obj_desc));
+	/* Create and initialize a new walk state */
 
-	info->pass_number = 3;
-	status = acpi_ps_execute_pass(info);
+	info->pass_number = ACPI_IMODE_EXECUTE;
+	walk_state =
+	    acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL,
+				      NULL, NULL);
+	if (!walk_state) {
+		status = AE_NO_MEMORY;
+		goto cleanup;
+	}
+
+	status = acpi_ds_init_aml_walk(walk_state, op, info->resolved_node,
+				       info->obj_desc->method.aml_start,
+				       info->obj_desc->method.aml_length, info,
+				       info->pass_number);
+	if (ACPI_FAILURE(status)) {
+		acpi_ds_delete_walk_state(walk_state);
+		goto cleanup;
+	}
+
+	/* Parse the AML */
+
+	status = acpi_ps_parse_aml(walk_state);
+
+	/* walk_state was deleted by parse_aml */
 
       cleanup:
+	acpi_ps_delete_parse_tree(op);
+
 	/* End optional tracing */
 
 	acpi_ps_stop_trace(info);
@@ -330,62 +349,3 @@
 		}
 	}
 }
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ps_execute_pass
- *
- * PARAMETERS:  Info            - See struct acpi_evaluate_info
- *                                (Used: pass_number, Node, and obj_desc)
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Single AML pass: Parse or Execute a control method
- *
- ******************************************************************************/
-
-static acpi_status acpi_ps_execute_pass(struct acpi_evaluate_info *info)
-{
-	acpi_status status;
-	union acpi_parse_object *op;
-	struct acpi_walk_state *walk_state;
-
-	ACPI_FUNCTION_TRACE(ps_execute_pass);
-
-	/* Create and init a Root Node */
-
-	op = acpi_ps_create_scope_op();
-	if (!op) {
-		return_ACPI_STATUS(AE_NO_MEMORY);
-	}
-
-	/* Create and initialize a new walk state */
-
-	walk_state =
-	    acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL,
-				      NULL, NULL);
-	if (!walk_state) {
-		status = AE_NO_MEMORY;
-		goto cleanup;
-	}
-
-	status = acpi_ds_init_aml_walk(walk_state, op, info->resolved_node,
-				       info->obj_desc->method.aml_start,
-				       info->obj_desc->method.aml_length,
-				       info->pass_number == 1 ? NULL : info,
-				       info->pass_number);
-	if (ACPI_FAILURE(status)) {
-		acpi_ds_delete_walk_state(walk_state);
-		goto cleanup;
-	}
-
-	/* Parse the AML */
-
-	status = acpi_ps_parse_aml(walk_state);
-
-	/* Walk state was deleted by parse_aml */
-
-      cleanup:
-	acpi_ps_delete_parse_tree(op);
-	return_ACPI_STATUS(status);
-}
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 481e633..0f683c8 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -513,7 +513,7 @@
 		}
 	}
 	/* Add a penalty for the SCI */
-	acpi_irq_penalty[acpi_fadt.sci_int] += PIRQ_PENALTY_PCI_USING;
+	acpi_irq_penalty[acpi_gbl_FADT.sci_interrupt] += PIRQ_PENALTY_PCI_USING;
 
 	return 0;
 }
@@ -785,7 +785,7 @@
 
 
 	/* Make sure SCI is enabled again (Apple firmware bug?) */
-	acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1, ACPI_MTX_DO_NOT_LOCK);
+	acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1);
 
 	list_for_each(node, &acpi_link.entries) {
 		link = list_entry(node, struct acpi_pci_link, node);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index a860efa..4ecf701 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -117,6 +117,19 @@
 
 EXPORT_SYMBOL(acpi_pci_unregister_driver);
 
+acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
+{
+	struct acpi_pci_root *tmp;
+	
+	list_for_each_entry(tmp, &acpi_pci_roots, node) {
+		if ((tmp->id.segment == (u16) seg) && (tmp->id.bus == (u16) bus))
+			return tmp->device->handle;
+	}
+	return NULL;		
+}
+
+EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
+
 static acpi_status
 get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
 {
@@ -152,6 +165,21 @@
 	return AE_OK;
 }
 
+static void acpi_pci_bridge_scan(struct acpi_device *device)
+{
+	int status;
+	struct acpi_device *child = NULL;
+
+	if (device->flags.bus_address)
+		if (device->parent && device->parent->ops.bind) {
+			status = device->parent->ops.bind(device);
+			if (!status) {
+				list_for_each_entry(child, &device->children, node)
+					acpi_pci_bridge_scan(child);
+			}
+		}
+}
+
 static int acpi_pci_root_add(struct acpi_device *device)
 {
 	int result = 0;
@@ -160,6 +188,7 @@
 	acpi_status status = AE_OK;
 	unsigned long value = 0;
 	acpi_handle handle = NULL;
+	struct acpi_device *child;
 
 
 	if (!device)
@@ -175,9 +204,6 @@
 	strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
 	acpi_driver_data(device) = root;
 
-	/*
-	 * TBD: Doesn't the bus driver automatically set this?
-	 */
 	device->ops.bind = acpi_pci_bind;
 
 	/* 
@@ -299,6 +325,12 @@
 		result = acpi_pci_irq_add_prt(device->handle, root->id.segment,
 					      root->id.bus);
 
+	/*
+	 * Scan and bind all _ADR-Based Devices
+	 */
+	list_for_each_entry(child, &device->children, node)
+		acpi_pci_bridge_scan(child);
+
       end:
 	if (result) {
 		if (!list_empty(&root->node))
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 5f9496d..0079bc5 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -375,30 +375,126 @@
 }
 
 /* Use the acpiid in MADT to map cpus in case of SMP */
+
 #ifndef CONFIG_SMP
-#define convert_acpiid_to_cpu(acpi_id) (-1)
+static int get_cpu_id(acpi_handle handle, u32 acpi_id) {return -1;}
 #else
 
+static struct acpi_table_madt *madt;
+
+static int map_lapic_id(struct acpi_subtable_header *entry,
+		 u32 acpi_id, int *apic_id)
+{
+	struct acpi_madt_local_apic *lapic =
+		(struct acpi_madt_local_apic *)entry;
+	if ((lapic->lapic_flags & ACPI_MADT_ENABLED) &&
+	    lapic->processor_id == acpi_id) {
+		*apic_id = lapic->id;
+		return 1;
+	}
+	return 0;
+}
+
+static int map_lsapic_id(struct acpi_subtable_header *entry,
+		  u32 acpi_id, int *apic_id)
+{
+	struct acpi_madt_local_sapic *lsapic =
+		(struct acpi_madt_local_sapic *)entry;
+	/* Only check enabled APICs*/
+	if (lsapic->lapic_flags & ACPI_MADT_ENABLED) {
+		/* First check against id */
+		if (lsapic->processor_id == acpi_id) {
+			*apic_id = lsapic->id;
+			return 1;
+		/* Check against optional uid */
+		} else if (entry->length >= 16 &&
+			lsapic->uid == acpi_id) {
+			*apic_id = lsapic->uid;
+			return 1;
+		}
+	}
+	return 0;
+}
+
 #ifdef CONFIG_IA64
-#define arch_acpiid_to_apicid 	ia64_acpiid_to_sapicid
 #define arch_cpu_to_apicid 	ia64_cpu_to_sapicid
-#define ARCH_BAD_APICID		(0xffff)
 #else
-#define arch_acpiid_to_apicid 	x86_acpiid_to_apicid
 #define arch_cpu_to_apicid 	x86_cpu_to_apicid
-#define ARCH_BAD_APICID		(0xff)
 #endif
 
-static int convert_acpiid_to_cpu(u8 acpi_id)
+static int map_madt_entry(u32 acpi_id)
 {
-	u16 apic_id;
+	unsigned long madt_end, entry;
+	int apic_id = -1;
+
+	if (!madt)
+		return apic_id;
+
+	entry = (unsigned long)madt;
+	madt_end = entry + madt->header.length;
+
+	/* Parse all entries looking for a match. */
+
+	entry += sizeof(struct acpi_table_madt);
+	while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
+		struct acpi_subtable_header *header =
+			(struct acpi_subtable_header *)entry;
+		if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
+			if (map_lapic_id(header, acpi_id, &apic_id))
+				break;
+		} else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
+			if (map_lsapic_id(header, acpi_id, &apic_id))
+				break;
+		}
+		entry += header->length;
+	}
+	return apic_id;
+}
+
+static int map_mat_entry(acpi_handle handle, u32 acpi_id)
+{
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *obj;
+	struct acpi_subtable_header *header;
+	int apic_id = -1;
+
+	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
+		goto exit;
+
+	if (!buffer.length || !buffer.pointer)
+		goto exit;
+
+	obj = buffer.pointer;
+	if (obj->type != ACPI_TYPE_BUFFER ||
+	    obj->buffer.length < sizeof(struct acpi_subtable_header)) {
+		goto exit;
+	}
+
+	header = (struct acpi_subtable_header *)obj->buffer.pointer;
+	if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
+		map_lapic_id(header, acpi_id, &apic_id);
+	} else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
+		map_lsapic_id(header, acpi_id, &apic_id);
+	}
+
+exit:
+	if (buffer.pointer)
+		kfree(buffer.pointer);
+	return apic_id;
+}
+
+static int get_cpu_id(acpi_handle handle, u32 acpi_id)
+{
 	int i;
+	int apic_id = -1;
 
-	apic_id = arch_acpiid_to_apicid[acpi_id];
-	if (apic_id == ARCH_BAD_APICID)
-		return -1;
+	apic_id = map_mat_entry(handle, acpi_id);
+	if (apic_id == -1)
+		apic_id = map_madt_entry(acpi_id);
+	if (apic_id == -1)
+		return apic_id;
 
-	for (i = 0; i < NR_CPUS; i++) {
+	for (i = 0; i < NR_CPUS; ++i) {
 		if (arch_cpu_to_apicid[i] == apic_id)
 			return i;
 	}
@@ -410,7 +506,7 @@
                                  Driver Interface
    -------------------------------------------------------------------------- */
 
-static int acpi_processor_get_info(struct acpi_processor *pr)
+static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid)
 {
 	acpi_status status = 0;
 	union acpi_object object = { 0 };
@@ -431,7 +527,7 @@
 	 * Check to see if we have bus mastering arbitration control.  This
 	 * is required for proper C3 usage (to maintain cache coherency).
 	 */
-	if (acpi_fadt.V1_pm2_cnt_blk && acpi_fadt.pm2_cnt_len) {
+	if (acpi_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) {
 		pr->flags.bm_control = 1;
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Bus mastering arbitration control present\n"));
@@ -439,24 +535,35 @@
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "No bus mastering arbitration control\n"));
 
-	/*
-	 * Evalute the processor object.  Note that it is common on SMP to
-	 * have the first (boot) processor with a valid PBLK address while
-	 * all others have a NULL address.
-	 */
-	status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
-	if (ACPI_FAILURE(status)) {
-		printk(KERN_ERR PREFIX "Evaluating processor object\n");
-		return -ENODEV;
+	/* Check if it is a Device with HID and UID */
+	if (has_uid) {
+		unsigned long value;
+		status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
+						NULL, &value);
+		if (ACPI_FAILURE(status)) {
+			printk(KERN_ERR PREFIX "Evaluating processor _UID\n");
+			return -ENODEV;
+		}
+		pr->acpi_id = value;
+	} else {
+		/*
+		* Evalute the processor object.  Note that it is common on SMP to
+		* have the first (boot) processor with a valid PBLK address while
+		* all others have a NULL address.
+		*/
+		status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
+		if (ACPI_FAILURE(status)) {
+			printk(KERN_ERR PREFIX "Evaluating processor object\n");
+			return -ENODEV;
+		}
+
+		/*
+		* TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
+		*      >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c
+		*/
+		pr->acpi_id = object.processor.proc_id;
 	}
-
-	/*
-	 * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
-	 *      >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c
-	 */
-	pr->acpi_id = object.processor.proc_id;
-
-	cpu_index = convert_acpiid_to_cpu(pr->acpi_id);
+	cpu_index = get_cpu_id(pr->handle, pr->acpi_id);
 
 	/* Handle UP system running SMP kernel, with no LAPIC in MADT */
 	if (!cpu0_initialized && (cpu_index == -1) &&
@@ -473,7 +580,7 @@
 	 *  less than the max # of CPUs. They should be ignored _iff
 	 *  they are physically not present.
 	 */
-	if (cpu_index == -1) {
+	if (pr->id == -1) {
 		if (ACPI_FAILURE
 		    (acpi_processor_hotadd_init(pr->handle, &pr->id))) {
 			return -ENODEV;
@@ -490,8 +597,8 @@
 			    object.processor.pblk_length);
 	else {
 		pr->throttling.address = object.processor.pblk_address;
-		pr->throttling.duty_offset = acpi_fadt.duty_offset;
-		pr->throttling.duty_width = acpi_fadt.duty_width;
+		pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset;
+		pr->throttling.duty_width = acpi_gbl_FADT.duty_width;
 
 		pr->pblk = object.processor.pblk_address;
 
@@ -525,7 +632,7 @@
 
 	pr = acpi_driver_data(device);
 
-	result = acpi_processor_get_info(pr);
+	result = acpi_processor_get_info(pr, device->flags.unique_id);
 	if (result) {
 		/* Processor is physically not present */
 		return 0;
@@ -707,7 +814,7 @@
 		return -ENODEV;
 
 	if ((pr->id >= 0) && (pr->id < NR_CPUS)) {
-		kobject_uevent(&(*device)->kobj, KOBJ_ONLINE);
+		kobject_uevent(&(*device)->dev.kobj, KOBJ_ONLINE);
 	}
 	return 0;
 }
@@ -745,13 +852,13 @@
 		}
 
 		if (pr->id >= 0 && (pr->id < NR_CPUS)) {
-			kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+			kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
 			break;
 		}
 
 		result = acpi_processor_start(device);
 		if ((!result) && ((pr->id >= 0) && (pr->id < NR_CPUS))) {
-			kobject_uevent(&device->kobj, KOBJ_ONLINE);
+			kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
 		} else {
 			printk(KERN_ERR PREFIX "Device [%s] failed to start\n",
 				    acpi_device_bid(device));
@@ -774,7 +881,7 @@
 		}
 
 		if ((pr->id < NR_CPUS) && (cpu_present(pr->id)))
-			kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+			kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
 		break;
 	default:
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -895,6 +1002,12 @@
 	memset(&processors, 0, sizeof(processors));
 	memset(&errata, 0, sizeof(errata));
 
+#ifdef CONFIG_SMP
+	if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
+				(struct acpi_table_header **)&madt)))
+		madt = 0;
+#endif
+
 	acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
 	if (!acpi_processor_dir)
 		return -ENOMEM;
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 3f30af2..6c6751b 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -160,7 +160,7 @@
 {
 	if (t2 >= t1)
 		return (t2 - t1);
-	else if (!acpi_fadt.tmr_val_ext)
+	else if (!(acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER))
 		return (((0x00FFFFFF - t1) + t2) & 0x00FFFFFF);
 	else
 		return ((0xFFFFFFFF - t1) + t2);
@@ -187,8 +187,7 @@
 		case ACPI_STATE_C3:
 			/* Disable bus master reload */
 			if (new->type != ACPI_STATE_C3 && pr->flags.bm_check)
-				acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0,
-						  ACPI_MTX_DO_NOT_LOCK);
+				acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
 			break;
 		}
 	}
@@ -198,8 +197,7 @@
 	case ACPI_STATE_C3:
 		/* Enable bus master reload */
 		if (old->type != ACPI_STATE_C3 && pr->flags.bm_check)
-			acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1,
-					  ACPI_MTX_DO_NOT_LOCK);
+			acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1);
 		break;
 	}
 
@@ -236,7 +234,7 @@
 		/* Dummy wait op - must do something useless after P_LVL2 read
 		   because chipsets cannot guarantee that STPCLK# signal
 		   gets asserted in time to freeze execution properly. */
-		unused = inl(acpi_fadt.xpm_tmr_blk.address);
+		unused = inl(acpi_gbl_FADT.xpm_timer_block.address);
 	}
 }
 
@@ -291,12 +289,10 @@
 
 		pr->power.bm_activity <<= diff;
 
-		acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS,
-				  &bm_status, ACPI_MTX_DO_NOT_LOCK);
+		acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status);
 		if (bm_status) {
 			pr->power.bm_activity |= 0x1;
-			acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS,
-					  1, ACPI_MTX_DO_NOT_LOCK);
+			acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, 1);
 		}
 		/*
 		 * PIIX4 Erratum #18: Note that BM_STS doesn't always reflect
@@ -338,7 +334,7 @@
 	 * detection phase, to work cleanly with logical CPU hotplug.
 	 */
 	if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && 
-	    !pr->flags.has_cst && !acpi_fadt.plvl2_up)
+	    !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
 		cx = &pr->power.states[ACPI_STATE_C1];
 #endif
 
@@ -384,11 +380,11 @@
 
 	case ACPI_STATE_C2:
 		/* Get start time (ticks) */
-		t1 = inl(acpi_fadt.xpm_tmr_blk.address);
+		t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
 		/* Invoke C2 */
 		acpi_cstate_enter(cx);
 		/* Get end time (ticks) */
-		t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+		t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
 
 #ifdef CONFIG_GENERIC_TIME
 		/* TSC halts in C2, so notify users */
@@ -411,8 +407,7 @@
 				 * All CPUs are trying to go to C3
 				 * Disable bus master arbitration
 				 */
-				acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1,
-						  ACPI_MTX_DO_NOT_LOCK);
+				acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
 			}
 		} else {
 			/* SMP with no shared cache... Invalidate cache  */
@@ -420,16 +415,15 @@
 		}
 
 		/* Get start time (ticks) */
-		t1 = inl(acpi_fadt.xpm_tmr_blk.address);
+		t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
 		/* Invoke C3 */
 		acpi_cstate_enter(cx);
 		/* Get end time (ticks) */
-		t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+		t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
 		if (pr->flags.bm_check) {
 			/* Enable bus master arbitration */
 			atomic_dec(&c3_cpu_count);
-			acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0,
-					  ACPI_MTX_DO_NOT_LOCK);
+			acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
 		}
 
 #ifdef CONFIG_GENERIC_TIME
@@ -457,7 +451,7 @@
 #ifdef CONFIG_HOTPLUG_CPU
 	/* Don't do promotion/demotion */
 	if ((cx->type == ACPI_STATE_C1) && (num_online_cpus() > 1) &&
-	    !pr->flags.has_cst && !acpi_fadt.plvl2_up) {
+	    !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) {
 		next_state = cx;
 		goto end;
 	}
@@ -627,7 +621,8 @@
 	 * Check for P_LVL2_UP flag before entering C2 and above on
 	 * an SMP system. 
 	 */
-	if ((num_online_cpus() > 1) && !acpi_fadt.plvl2_up)
+	if ((num_online_cpus() > 1) &&
+	    !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
 		return -ENODEV;
 #endif
 
@@ -636,8 +631,8 @@
 	pr->power.states[ACPI_STATE_C3].address = pr->pblk + 5;
 
 	/* determine latencies from FADT */
-	pr->power.states[ACPI_STATE_C2].latency = acpi_fadt.plvl2_lat;
-	pr->power.states[ACPI_STATE_C3].latency = acpi_fadt.plvl3_lat;
+	pr->power.states[ACPI_STATE_C2].latency = acpi_gbl_FADT.C2latency;
+	pr->power.states[ACPI_STATE_C3].latency = acpi_gbl_FADT.C3latency;
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 			  "lvl2[0x%08x] lvl3[0x%08x]\n",
@@ -883,14 +878,13 @@
 		 * WBINVD should be set in fadt, for C3 state to be
 		 * supported on when bm_check is not required.
 		 */
-		if (acpi_fadt.wb_invd != 1) {
+		if (!(acpi_gbl_FADT.flags & ACPI_FADT_WBINVD)) {
 			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 					  "Cache invalidation should work properly"
 					  " for C3 to be enabled on SMP systems\n"));
 			return;
 		}
-		acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD,
-				  0, ACPI_MTX_DO_NOT_LOCK);
+		acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
 	}
 
 	/*
@@ -1096,7 +1090,7 @@
 		seq_printf(seq, "latency[%03d] usage[%08d] duration[%020llu]\n",
 			   pr->power.states[i].latency,
 			   pr->power.states[i].usage,
-			   pr->power.states[i].time);
+			   (unsigned long long)pr->power.states[i].time);
 	}
 
       end:
@@ -1164,9 +1158,9 @@
 	if (!pr)
 		return -EINVAL;
 
-	if (acpi_fadt.cst_cnt && !nocst) {
+	if (acpi_gbl_FADT.cst_control && !nocst) {
 		status =
-		    acpi_os_write_port(acpi_fadt.smi_cmd, acpi_fadt.cst_cnt, 8);
+		    acpi_os_write_port(acpi_gbl_FADT.smi_command, acpi_gbl_FADT.cst_control, 8);
 		if (ACPI_FAILURE(status)) {
 			ACPI_EXCEPTION((AE_INFO, status,
 					"Notifying BIOS of _CST ability failed"));
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index cbb6f08..058f13c 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -352,31 +352,24 @@
 
 	is_done = -EIO;
 
-	/* Can't write pstate_cnt to smi_cmd if either value is zero */
-	if ((!acpi_fadt.smi_cmd) || (!acpi_fadt.pstate_cnt)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_cnt\n"));
+	/* Can't write pstate_control to smi_command if either value is zero */
+	if ((!acpi_gbl_FADT.smi_command) || (!acpi_gbl_FADT.pstate_control)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_control\n"));
 		module_put(calling_module);
 		return 0;
 	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-			  "Writing pstate_cnt [0x%x] to smi_cmd [0x%x]\n",
-			  acpi_fadt.pstate_cnt, acpi_fadt.smi_cmd));
+			  "Writing pstate_control [0x%x] to smi_command [0x%x]\n",
+			  acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
 
-	/* FADT v1 doesn't support pstate_cnt, many BIOS vendors use
-	 * it anyway, so we need to support it... */
-	if (acpi_fadt_is_v1) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				  "Using v1.0 FADT reserved value for pstate_cnt\n"));
-	}
-
-	status = acpi_os_write_port(acpi_fadt.smi_cmd,
-				    (u32) acpi_fadt.pstate_cnt, 8);
+	status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+				    (u32) acpi_gbl_FADT.pstate_control, 8);
 	if (ACPI_FAILURE(status)) {
 		ACPI_EXCEPTION((AE_INFO, status,
-				"Failed to write pstate_cnt [0x%x] to "
-				"smi_cmd [0x%x]", acpi_fadt.pstate_cnt,
-				acpi_fadt.smi_cmd));
+				"Failed to write pstate_control [0x%x] to "
+				"smi_command [0x%x]", acpi_gbl_FADT.pstate_control,
+				acpi_gbl_FADT.smi_command));
 		module_put(calling_module);
 		return status;
 	}
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index 0ec7dcd..89dff36 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -125,7 +125,7 @@
 		/* Used to clear all duty_value bits */
 		duty_mask = pr->throttling.state_count - 1;
 
-		duty_mask <<= acpi_fadt.duty_offset;
+		duty_mask <<= acpi_gbl_FADT.duty_offset;
 		duty_mask = ~duty_mask;
 	}
 
@@ -208,7 +208,7 @@
 		return 0;
 	}
 
-	pr->throttling.state_count = 1 << acpi_fadt.duty_width;
+	pr->throttling.state_count = 1 << acpi_gbl_FADT.duty_width;
 
 	/*
 	 * Compute state values. Note that throttling displays a linear power/
diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c
index 8fa3213..271e615 100644
--- a/drivers/acpi/resources/rsaddr.c
+++ b/drivers/acpi/resources/rsaddr.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c
index cf87b02..8c6d3fd 100644
--- a/drivers/acpi/resources/rscalc.c
+++ b/drivers/acpi/resources/rscalc.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c
index 008058a..1358c06 100644
--- a/drivers/acpi/resources/rscreate.c
+++ b/drivers/acpi/resources/rscreate.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c
index 9c99a72..de20a5d 100644
--- a/drivers/acpi/resources/rsdump.c
+++ b/drivers/acpi/resources/rsdump.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsinfo.c b/drivers/acpi/resources/rsinfo.c
index 9e7ae2f..7e3c335 100644
--- a/drivers/acpi/resources/rsinfo.c
+++ b/drivers/acpi/resources/rsinfo.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsio.c b/drivers/acpi/resources/rsio.c
index ea56716..b297bc3 100644
--- a/drivers/acpi/resources/rsio.c
+++ b/drivers/acpi/resources/rsio.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c
index 1fa63bc..5657f7b 100644
--- a/drivers/acpi/resources/rsirq.c
+++ b/drivers/acpi/resources/rsirq.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c
index 29423ce..a92755c 100644
--- a/drivers/acpi/resources/rslist.c
+++ b/drivers/acpi/resources/rslist.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsmemory.c b/drivers/acpi/resources/rsmemory.c
index a513193..521eab7 100644
--- a/drivers/acpi/resources/rsmemory.c
+++ b/drivers/acpi/resources/rsmemory.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c
index faf6e10..3b63b56 100644
--- a/drivers/acpi/resources/rsmisc.c
+++ b/drivers/acpi/resources/rsmisc.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c
index a9cbee8..2442a8f 100644
--- a/drivers/acpi/resources/rsutils.c
+++ b/drivers/acpi/resources/rsutils.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c
index 1999e2a..991f890 100644
--- a/drivers/acpi/resources/rsxface.c
+++ b/drivers/acpi/resources/rsxface.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 283d875..64f26db 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -21,101 +21,305 @@
 #define ACPI_BUS_DEVICE_NAME		"System Bus"
 
 static LIST_HEAD(acpi_device_list);
+static LIST_HEAD(acpi_bus_id_list);
 DEFINE_SPINLOCK(acpi_device_lock);
 LIST_HEAD(acpi_wakeup_device_list);
 
-
-static void acpi_device_release(struct kobject *kobj)
+struct acpi_device_bus_id{
+	char bus_id[15];
+	unsigned int instance_no;
+	struct list_head node;
+};
+static int acpi_eject_operation(acpi_handle handle, int lockable)
 {
-	struct acpi_device *dev = container_of(kobj, struct acpi_device, kobj);
-	kfree(dev->pnp.cid_list);
-	kfree(dev);
+	struct acpi_object_list arg_list;
+	union acpi_object arg;
+	acpi_status status = AE_OK;
+
+	/*
+	 * TBD: evaluate _PS3?
+	 */
+
+	if (lockable) {
+		arg_list.count = 1;
+		arg_list.pointer = &arg;
+		arg.type = ACPI_TYPE_INTEGER;
+		arg.integer.value = 0;
+		acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
+	}
+
+	arg_list.count = 1;
+	arg_list.pointer = &arg;
+	arg.type = ACPI_TYPE_INTEGER;
+	arg.integer.value = 1;
+
+	/*
+	 * TBD: _EJD support.
+	 */
+
+	status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
+	if (ACPI_FAILURE(status)) {
+		return (-ENODEV);
+	}
+
+	return (0);
 }
 
-struct acpi_device_attribute {
-	struct attribute attr;
-	 ssize_t(*show) (struct acpi_device *, char *);
-	 ssize_t(*store) (struct acpi_device *, const char *, size_t);
-};
-
-typedef void acpi_device_sysfs_files(struct kobject *,
-				     const struct attribute *);
-
-static void setup_sys_fs_device_files(struct acpi_device *dev,
-				      acpi_device_sysfs_files * func);
-
-#define create_sysfs_device_files(dev)	\
-	setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_create_file)
-#define remove_sysfs_device_files(dev)	\
-	setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_remove_file)
-
-#define to_acpi_device(n) container_of(n, struct acpi_device, kobj)
-#define to_handle_attr(n) container_of(n, struct acpi_device_attribute, attr);
-
-static ssize_t acpi_device_attr_show(struct kobject *kobj,
-				     struct attribute *attr, char *buf)
+static ssize_t
+acpi_eject_store(struct device *d, struct device_attribute *attr,
+		const char *buf, size_t count)
 {
-	struct acpi_device *device = to_acpi_device(kobj);
-	struct acpi_device_attribute *attribute = to_handle_attr(attr);
-	return attribute->show ? attribute->show(device, buf) : -EIO;
-}
-static ssize_t acpi_device_attr_store(struct kobject *kobj,
-				      struct attribute *attr, const char *buf,
-				      size_t len)
-{
-	struct acpi_device *device = to_acpi_device(kobj);
-	struct acpi_device_attribute *attribute = to_handle_attr(attr);
-	return attribute->store ? attribute->store(device, buf, len) : -EIO;
+	int result;
+	int ret = count;
+	int islockable;
+	acpi_status status;
+	acpi_handle handle;
+	acpi_object_type type = 0;
+	struct acpi_device *acpi_device = to_acpi_device(d);
+
+	if ((!count) || (buf[0] != '1')) {
+		return -EINVAL;
+	}
+#ifndef FORCE_EJECT
+	if (acpi_device->driver == NULL) {
+		ret = -ENODEV;
+		goto err;
+	}
+#endif
+	status = acpi_get_type(acpi_device->handle, &type);
+	if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	islockable = acpi_device->flags.lockable;
+	handle = acpi_device->handle;
+
+	result = acpi_bus_trim(acpi_device, 1);
+
+	if (!result)
+		result = acpi_eject_operation(handle, islockable);
+
+	if (result) {
+		ret = -EBUSY;
+	}
+      err:
+	return ret;
 }
 
-static struct sysfs_ops acpi_device_sysfs_ops = {
-	.show = acpi_device_attr_show,
-	.store = acpi_device_attr_store,
-};
+static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
 
-static struct kobj_type ktype_acpi_ns = {
-	.sysfs_ops = &acpi_device_sysfs_ops,
-	.release = acpi_device_release,
-};
+static ssize_t
+acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) {
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
 
-static int namespace_uevent(struct kset *kset, struct kobject *kobj,
-			     char **envp, int num_envp, char *buffer,
-			     int buffer_size)
+	return sprintf(buf, "%s\n", acpi_dev->pnp.hardware_id);
+}
+static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
+
+static ssize_t
+acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) {
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
+	int result;
+
+	result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path);
+	if(result)
+		goto end;
+
+	result = sprintf(buf, "%s\n", (char*)path.pointer);
+	kfree(path.pointer);
+  end:
+	return result;
+}
+static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
+
+static int acpi_device_setup_files(struct acpi_device *dev)
 {
-	struct acpi_device *dev = to_acpi_device(kobj);
-	int i = 0;
-	int len = 0;
+	acpi_status status;
+	acpi_handle temp;
+	int result = 0;
 
-	if (!dev->driver)
-		return 0;
+	/*
+	 * Devices gotten from FADT don't have a "path" attribute
+	 */
+	if(dev->handle) {
+		result = device_create_file(&dev->dev, &dev_attr_path);
+		if(result)
+			goto end;
+	}
 
-	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-			   "PHYSDEVDRIVER=%s", dev->driver->name))
-		return -ENOMEM;
+	if(dev->flags.hardware_id) {
+		result = device_create_file(&dev->dev, &dev_attr_hid);
+		if(result)
+			goto end;
+	}
 
-	envp[i] = NULL;
+        /*
+         * If device has _EJ0, 'eject' file is created that is used to trigger
+         * hot-removal function from userland.
+         */
+	status = acpi_get_handle(dev->handle, "_EJ0", &temp);
+	if (ACPI_SUCCESS(status))
+		result = device_create_file(&dev->dev, &dev_attr_eject);
+  end:
+	return result;
+}
 
+static void acpi_device_remove_files(struct acpi_device *dev)
+{
+	acpi_status status;
+	acpi_handle temp;
+
+	/*
+	 * If device has _EJ0, 'eject' file is created that is used to trigger
+	 * hot-removal function from userland.
+	 */
+	status = acpi_get_handle(dev->handle, "_EJ0", &temp);
+	if (ACPI_SUCCESS(status))
+		device_remove_file(&dev->dev, &dev_attr_eject);
+
+	if(dev->flags.hardware_id)
+		device_remove_file(&dev->dev, &dev_attr_hid);
+	if(dev->handle)
+		device_remove_file(&dev->dev, &dev_attr_path);
+}
+/* --------------------------------------------------------------------------
+			ACPI Bus operations
+   -------------------------------------------------------------------------- */
+static void acpi_device_release(struct device *dev)
+{
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+
+	kfree(acpi_dev->pnp.cid_list);
+	kfree(acpi_dev);
+}
+
+static int acpi_device_suspend(struct device *dev, pm_message_t state)
+{
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	struct acpi_driver *acpi_drv = acpi_dev->driver;
+
+	if (acpi_drv && acpi_drv->ops.suspend)
+		return acpi_drv->ops.suspend(acpi_dev, state);
 	return 0;
 }
 
-static struct kset_uevent_ops namespace_uevent_ops = {
-	.uevent = &namespace_uevent,
+static int acpi_device_resume(struct device *dev)
+{
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	struct acpi_driver *acpi_drv = acpi_dev->driver;
+
+	if (acpi_drv && acpi_drv->ops.resume)
+		return acpi_drv->ops.resume(acpi_dev);
+	return 0;
+}
+
+static int acpi_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	struct acpi_driver *acpi_drv = to_acpi_driver(drv);
+
+	return !acpi_match_ids(acpi_dev, acpi_drv->ids);
+}
+
+static int acpi_device_uevent(struct device *dev, char **envp, int num_envp,
+	char *buffer, int buffer_size)
+{
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	int i = 0, length = 0, ret = 0;
+
+	if (acpi_dev->flags.hardware_id)
+		ret = add_uevent_var(envp, num_envp, &i,
+			buffer, buffer_size, &length,
+			"HWID=%s", acpi_dev->pnp.hardware_id);
+	if (ret)
+		return -ENOMEM;
+	if (acpi_dev->flags.compatible_ids) {
+		int j;
+		struct acpi_compatible_id_list *cid_list;
+
+		cid_list = acpi_dev->pnp.cid_list;
+
+		for (j = 0; j < cid_list->count; j++) {
+			ret = add_uevent_var(envp, num_envp, &i, buffer,
+				buffer_size, &length, "COMPTID=%s",
+				cid_list->id[j].value);
+			if (ret)
+				return -ENOMEM;
+		}
+	}
+
+	envp[i] = NULL;
+	return 0;
+}
+
+static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *);
+static int acpi_start_single_object(struct acpi_device *);
+static int acpi_device_probe(struct device * dev)
+{
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
+	int ret;
+
+	ret = acpi_bus_driver_init(acpi_dev, acpi_drv);
+	if (!ret) {
+		if (acpi_dev->bus_ops.acpi_op_start)
+			acpi_start_single_object(acpi_dev);
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+			"Found driver [%s] for device [%s]\n",
+			acpi_drv->name, acpi_dev->pnp.bus_id));
+		get_device(dev);
+	}
+	return ret;
+}
+
+static int acpi_device_remove(struct device * dev)
+{
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	struct acpi_driver *acpi_drv = acpi_dev->driver;
+
+	if (acpi_drv) {
+		if (acpi_drv->ops.stop)
+			acpi_drv->ops.stop(acpi_dev, acpi_dev->removal_type);
+		if (acpi_drv->ops.remove)
+			acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
+	}
+	acpi_dev->driver = NULL;
+	acpi_driver_data(dev) = NULL;
+
+	put_device(dev);
+	return 0;
+}
+
+static void acpi_device_shutdown(struct device *dev)
+{
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	struct acpi_driver *acpi_drv = acpi_dev->driver;
+
+	if (acpi_drv && acpi_drv->ops.shutdown)
+		acpi_drv->ops.shutdown(acpi_dev);
+
+	return ;
+}
+
+static struct bus_type acpi_bus_type = {
+	.name		= "acpi",
+	.suspend	= acpi_device_suspend,
+	.resume		= acpi_device_resume,
+	.shutdown	= acpi_device_shutdown,
+	.match		= acpi_bus_match,
+	.probe		= acpi_device_probe,
+	.remove		= acpi_device_remove,
+	.uevent		= acpi_device_uevent,
 };
 
-static struct kset acpi_namespace_kset = {
-	.kobj = {
-		 .name = "namespace",
-		 },
-	.subsys = &acpi_subsys,
-	.ktype = &ktype_acpi_ns,
-	.uevent_ops = &namespace_uevent_ops,
-};
-
-static void acpi_device_register(struct acpi_device *device,
+static int acpi_device_register(struct acpi_device *device,
 				 struct acpi_device *parent)
 {
-	int err;
-
+	int result;
+	struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
+	int found = 0;
 	/*
 	 * Linkage
 	 * -------
@@ -126,7 +330,33 @@
 	INIT_LIST_HEAD(&device->g_list);
 	INIT_LIST_HEAD(&device->wakeup_list);
 
+	new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
+	if (!new_bus_id) {
+		printk(KERN_ERR PREFIX "Memory allocation error\n");
+		return -ENOMEM;
+	}
+
 	spin_lock(&acpi_device_lock);
+	/*
+	 * Find suitable bus_id and instance number in acpi_bus_id_list
+	 * If failed, create one and link it into acpi_bus_id_list
+	 */
+	list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) {
+		if(!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id? device->pnp.hardware_id : "device")) {
+			acpi_device_bus_id->instance_no ++;
+			found = 1;
+			kfree(new_bus_id);
+			break;
+		}
+	}
+	if(!found) {
+		acpi_device_bus_id = new_bus_id;
+		strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "device");
+		acpi_device_bus_id->instance_no = 0;
+		list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
+	}
+	sprintf(device->dev.bus_id, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no);
+
 	if (device->parent) {
 		list_add_tail(&device->node, &device->parent->children);
 		list_add_tail(&device->g_list, &device->parent->g_list);
@@ -136,16 +366,33 @@
 		list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list);
 	spin_unlock(&acpi_device_lock);
 
-	strlcpy(device->kobj.name, device->pnp.bus_id, KOBJ_NAME_LEN);
-	if (parent)
-		device->kobj.parent = &parent->kobj;
-	device->kobj.ktype = &ktype_acpi_ns;
-	device->kobj.kset = &acpi_namespace_kset;
-	err = kobject_register(&device->kobj);
-	if (err < 0)
-		printk(KERN_WARNING "%s: kobject_register error: %d\n",
-			__FUNCTION__, err);
-	create_sysfs_device_files(device);
+	if (device->parent)
+		device->dev.parent = &parent->dev;
+	device->dev.bus = &acpi_bus_type;
+	device_initialize(&device->dev);
+	device->dev.release = &acpi_device_release;
+	result = device_add(&device->dev);
+	if(result) {
+		printk("Error adding device %s", device->dev.bus_id);
+		goto end;
+	}
+
+	result = acpi_device_setup_files(device);
+	if(result)
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error creating sysfs interface for device %s\n", device->dev.bus_id));
+
+	device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
+	return 0;
+  end:
+	spin_lock(&acpi_device_lock);
+	if (device->parent) {
+		list_del(&device->node);
+		list_del(&device->g_list);
+	} else
+		list_del(&device->g_list);
+	list_del(&device->wakeup_list);
+	spin_unlock(&acpi_device_lock);
+	return result;
 }
 
 static void acpi_device_unregister(struct acpi_device *device, int type)
@@ -158,14 +405,137 @@
 		list_del(&device->g_list);
 
 	list_del(&device->wakeup_list);
-
 	spin_unlock(&acpi_device_lock);
 
 	acpi_detach_data(device->handle, acpi_bus_data_handler);
-	remove_sysfs_device_files(device);
-	kobject_unregister(&device->kobj);
+
+	acpi_device_remove_files(device);
+	device_unregister(&device->dev);
 }
 
+/* --------------------------------------------------------------------------
+                                 Driver Management
+   -------------------------------------------------------------------------- */
+/**
+ * acpi_bus_driver_init - add a device to a driver
+ * @device: the device to add and initialize
+ * @driver: driver for the device
+ *
+ * Used to initialize a device via its device driver.  Called whenever a 
+ * driver is bound to a device.  Invokes the driver's add() ops.
+ */
+static int
+acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
+{
+	int result = 0;
+
+
+	if (!device || !driver)
+		return -EINVAL;
+
+	if (!driver->ops.add)
+		return -ENOSYS;
+
+	result = driver->ops.add(device);
+	if (result) {
+		device->driver = NULL;
+		acpi_driver_data(device) = NULL;
+		return result;
+	}
+
+	device->driver = driver;
+
+	/*
+	 * TBD - Configuration Management: Assign resources to device based
+	 * upon possible configuration and currently allocated resources.
+	 */
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+			  "Driver successfully bound to device\n"));
+	return 0;
+}
+
+static int acpi_start_single_object(struct acpi_device *device)
+{
+	int result = 0;
+	struct acpi_driver *driver;
+
+
+	if (!(driver = device->driver))
+		return 0;
+
+	if (driver->ops.start) {
+		result = driver->ops.start(device);
+		if (result && driver->ops.remove)
+			driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
+	}
+
+	return result;
+}
+
+/**
+ * acpi_bus_register_driver - register a driver with the ACPI bus
+ * @driver: driver being registered
+ *
+ * Registers a driver with the ACPI bus.  Searches the namespace for all
+ * devices that match the driver's criteria and binds.  Returns zero for
+ * success or a negative error status for failure.
+ */
+int acpi_bus_register_driver(struct acpi_driver *driver)
+{
+	int ret;
+
+	if (acpi_disabled)
+		return -ENODEV;
+	driver->drv.name = driver->name;
+	driver->drv.bus = &acpi_bus_type;
+	driver->drv.owner = driver->owner;
+
+	ret = driver_register(&driver->drv);
+	return ret;
+}
+
+EXPORT_SYMBOL(acpi_bus_register_driver);
+
+/**
+ * acpi_bus_unregister_driver - unregisters a driver with the APIC bus
+ * @driver: driver to unregister
+ *
+ * Unregisters a driver with the ACPI bus.  Searches the namespace for all
+ * devices that match the driver's criteria and unbinds.
+ */
+void acpi_bus_unregister_driver(struct acpi_driver *driver)
+{
+	driver_unregister(&driver->drv);
+}
+
+EXPORT_SYMBOL(acpi_bus_unregister_driver);
+
+/* --------------------------------------------------------------------------
+                                 Device Enumeration
+   -------------------------------------------------------------------------- */
+acpi_status
+acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
+{
+	acpi_status status;
+	acpi_handle tmp;
+	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	union acpi_object *obj;
+
+	status = acpi_get_handle(handle, "_EJD", &tmp);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);
+	if (ACPI_SUCCESS(status)) {
+		obj = buffer.pointer;
+		status = acpi_get_handle(NULL, obj->string.pointer, ejd);
+		kfree(buffer.pointer);
+	}
+	return status;
+}
+EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
+
 void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context)
 {
 
@@ -174,67 +544,6 @@
 	return;
 }
 
-static int acpi_bus_get_power_flags(struct acpi_device *device)
-{
-	acpi_status status = 0;
-	acpi_handle handle = NULL;
-	u32 i = 0;
-
-
-	/*
-	 * Power Management Flags
-	 */
-	status = acpi_get_handle(device->handle, "_PSC", &handle);
-	if (ACPI_SUCCESS(status))
-		device->power.flags.explicit_get = 1;
-	status = acpi_get_handle(device->handle, "_IRC", &handle);
-	if (ACPI_SUCCESS(status))
-		device->power.flags.inrush_current = 1;
-
-	/*
-	 * Enumerate supported power management states
-	 */
-	for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) {
-		struct acpi_device_power_state *ps = &device->power.states[i];
-		char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' };
-
-		/* Evaluate "_PRx" to se if power resources are referenced */
-		acpi_evaluate_reference(device->handle, object_name, NULL,
-					&ps->resources);
-		if (ps->resources.count) {
-			device->power.flags.power_resources = 1;
-			ps->flags.valid = 1;
-		}
-
-		/* Evaluate "_PSx" to see if we can do explicit sets */
-		object_name[2] = 'S';
-		status = acpi_get_handle(device->handle, object_name, &handle);
-		if (ACPI_SUCCESS(status)) {
-			ps->flags.explicit_set = 1;
-			ps->flags.valid = 1;
-		}
-
-		/* State is valid if we have some power control */
-		if (ps->resources.count || ps->flags.explicit_set)
-			ps->flags.valid = 1;
-
-		ps->power = -1;	/* Unknown - driver assigned */
-		ps->latency = -1;	/* Unknown - driver assigned */
-	}
-
-	/* Set defaults for D0 and D3 states (always valid) */
-	device->power.states[ACPI_STATE_D0].flags.valid = 1;
-	device->power.states[ACPI_STATE_D0].power = 100;
-	device->power.states[ACPI_STATE_D3].flags.valid = 1;
-	device->power.states[ACPI_STATE_D3].power = 0;
-
-	/* TBD: System wake support and resource requirements. */
-
-	device->power.state = ACPI_STATE_UNKNOWN;
-
-	return 0;
-}
-
 int acpi_match_ids(struct acpi_device *device, char *ids)
 {
 	if (device->flags.hardware_id)
@@ -254,6 +563,12 @@
 	return -ENOENT;
 }
 
+static int acpi_bus_get_perf_flags(struct acpi_device *device)
+{
+	device->performance.state = ACPI_STATE_UNKNOWN;
+	return 0;
+}
+
 static acpi_status
 acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device,
 					     union acpi_object *package)
@@ -338,360 +653,67 @@
 	return 0;
 }
 
-/* --------------------------------------------------------------------------
-		ACPI sysfs device file support
-   -------------------------------------------------------------------------- */
-static ssize_t acpi_eject_store(struct acpi_device *device,
-				const char *buf, size_t count);
-
-#define ACPI_DEVICE_ATTR(_name,_mode,_show,_store) \
-static struct acpi_device_attribute acpi_device_attr_##_name = \
-		__ATTR(_name, _mode, _show, _store)
-
-ACPI_DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
-
-/**
- * setup_sys_fs_device_files - sets up the device files under device namespace
- * @dev:	acpi_device object
- * @func:	function pointer to create or destroy the device file
- */
-static void
-setup_sys_fs_device_files(struct acpi_device *dev,
-			  acpi_device_sysfs_files * func)
+static int acpi_bus_get_power_flags(struct acpi_device *device)
 {
-	acpi_status status;
-	acpi_handle temp = NULL;
+	acpi_status status = 0;
+	acpi_handle handle = NULL;
+	u32 i = 0;
+
 
 	/*
-	 * If device has _EJ0, 'eject' file is created that is used to trigger
-	 * hot-removal function from userland.
+	 * Power Management Flags
 	 */
-	status = acpi_get_handle(dev->handle, "_EJ0", &temp);
+	status = acpi_get_handle(device->handle, "_PSC", &handle);
 	if (ACPI_SUCCESS(status))
-		(*(func)) (&dev->kobj, &acpi_device_attr_eject.attr);
-}
-
-static int acpi_eject_operation(acpi_handle handle, int lockable)
-{
-	struct acpi_object_list arg_list;
-	union acpi_object arg;
-	acpi_status status = AE_OK;
+		device->power.flags.explicit_get = 1;
+	status = acpi_get_handle(device->handle, "_IRC", &handle);
+	if (ACPI_SUCCESS(status))
+		device->power.flags.inrush_current = 1;
 
 	/*
-	 * TBD: evaluate _PS3?
+	 * Enumerate supported power management states
 	 */
+	for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) {
+		struct acpi_device_power_state *ps = &device->power.states[i];
+		char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' };
 
-	if (lockable) {
-		arg_list.count = 1;
-		arg_list.pointer = &arg;
-		arg.type = ACPI_TYPE_INTEGER;
-		arg.integer.value = 0;
-		acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
-	}
-
-	arg_list.count = 1;
-	arg_list.pointer = &arg;
-	arg.type = ACPI_TYPE_INTEGER;
-	arg.integer.value = 1;
-
-	/*
-	 * TBD: _EJD support.
-	 */
-
-	status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
-	if (ACPI_FAILURE(status)) {
-		return (-ENODEV);
-	}
-
-	return (0);
-}
-
-static ssize_t
-acpi_eject_store(struct acpi_device *device, const char *buf, size_t count)
-{
-	int result;
-	int ret = count;
-	int islockable;
-	acpi_status status;
-	acpi_handle handle;
-	acpi_object_type type = 0;
-
-	if ((!count) || (buf[0] != '1')) {
-		return -EINVAL;
-	}
-#ifndef FORCE_EJECT
-	if (device->driver == NULL) {
-		ret = -ENODEV;
-		goto err;
-	}
-#endif
-	status = acpi_get_type(device->handle, &type);
-	if (ACPI_FAILURE(status) || (!device->flags.ejectable)) {
-		ret = -ENODEV;
-		goto err;
-	}
-
-	islockable = device->flags.lockable;
-	handle = device->handle;
-
-	result = acpi_bus_trim(device, 1);
-
-	if (!result)
-		result = acpi_eject_operation(handle, islockable);
-
-	if (result) {
-		ret = -EBUSY;
-	}
-      err:
-	return ret;
-}
-
-/* --------------------------------------------------------------------------
-                              Performance Management
-   -------------------------------------------------------------------------- */
-
-static int acpi_bus_get_perf_flags(struct acpi_device *device)
-{
-	device->performance.state = ACPI_STATE_UNKNOWN;
-	return 0;
-}
-
-/* --------------------------------------------------------------------------
-                                 Driver Management
-   -------------------------------------------------------------------------- */
-
-static LIST_HEAD(acpi_bus_drivers);
-
-/**
- * acpi_bus_match - match device IDs to driver's supported IDs
- * @device: the device that we are trying to match to a driver
- * @driver: driver whose device id table is being checked
- *
- * Checks the device's hardware (_HID) or compatible (_CID) ids to see if it
- * matches the specified driver's criteria.
- */
-static int
-acpi_bus_match(struct acpi_device *device, struct acpi_driver *driver)
-{
-	if (driver && driver->ops.match)
-		return driver->ops.match(device, driver);
-	return acpi_match_ids(device, driver->ids);
-}
-
-/**
- * acpi_bus_driver_init - add a device to a driver
- * @device: the device to add and initialize
- * @driver: driver for the device
- *
- * Used to initialize a device via its device driver.  Called whenever a 
- * driver is bound to a device.  Invokes the driver's add() and start() ops.
- */
-static int
-acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
-{
-	int result = 0;
-
-
-	if (!device || !driver)
-		return -EINVAL;
-
-	if (!driver->ops.add)
-		return -ENOSYS;
-
-	result = driver->ops.add(device);
-	if (result) {
-		device->driver = NULL;
-		acpi_driver_data(device) = NULL;
-		return result;
-	}
-
-	device->driver = driver;
-
-	/*
-	 * TBD - Configuration Management: Assign resources to device based
-	 * upon possible configuration and currently allocated resources.
-	 */
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-			  "Driver successfully bound to device\n"));
-	return 0;
-}
-
-static int acpi_start_single_object(struct acpi_device *device)
-{
-	int result = 0;
-	struct acpi_driver *driver;
-
-
-	if (!(driver = device->driver))
-		return 0;
-
-	if (driver->ops.start) {
-		result = driver->ops.start(device);
-		if (result && driver->ops.remove)
-			driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
-	}
-
-	return result;
-}
-
-static void acpi_driver_attach(struct acpi_driver *drv)
-{
-	struct list_head *node, *next;
-
-
-	spin_lock(&acpi_device_lock);
-	list_for_each_safe(node, next, &acpi_device_list) {
-		struct acpi_device *dev =
-		    container_of(node, struct acpi_device, g_list);
-
-		if (dev->driver || !dev->status.present)
-			continue;
-		spin_unlock(&acpi_device_lock);
-
-		if (!acpi_bus_match(dev, drv)) {
-			if (!acpi_bus_driver_init(dev, drv)) {
-				acpi_start_single_object(dev);
-				atomic_inc(&drv->references);
-				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-						  "Found driver [%s] for device [%s]\n",
-						  drv->name, dev->pnp.bus_id));
-			}
+		/* Evaluate "_PRx" to se if power resources are referenced */
+		acpi_evaluate_reference(device->handle, object_name, NULL,
+					&ps->resources);
+		if (ps->resources.count) {
+			device->power.flags.power_resources = 1;
+			ps->flags.valid = 1;
 		}
-		spin_lock(&acpi_device_lock);
-	}
-	spin_unlock(&acpi_device_lock);
-}
 
-static void acpi_driver_detach(struct acpi_driver *drv)
-{
-	struct list_head *node, *next;
-
-
-	spin_lock(&acpi_device_lock);
-	list_for_each_safe(node, next, &acpi_device_list) {
-		struct acpi_device *dev =
-		    container_of(node, struct acpi_device, g_list);
-
-		if (dev->driver == drv) {
-			spin_unlock(&acpi_device_lock);
-			if (drv->ops.remove)
-				drv->ops.remove(dev, ACPI_BUS_REMOVAL_NORMAL);
-			spin_lock(&acpi_device_lock);
-			dev->driver = NULL;
-			dev->driver_data = NULL;
-			atomic_dec(&drv->references);
+		/* Evaluate "_PSx" to see if we can do explicit sets */
+		object_name[2] = 'S';
+		status = acpi_get_handle(device->handle, object_name, &handle);
+		if (ACPI_SUCCESS(status)) {
+			ps->flags.explicit_set = 1;
+			ps->flags.valid = 1;
 		}
+
+		/* State is valid if we have some power control */
+		if (ps->resources.count || ps->flags.explicit_set)
+			ps->flags.valid = 1;
+
+		ps->power = -1;	/* Unknown - driver assigned */
+		ps->latency = -1;	/* Unknown - driver assigned */
 	}
-	spin_unlock(&acpi_device_lock);
-}
 
-/**
- * acpi_bus_register_driver - register a driver with the ACPI bus
- * @driver: driver being registered
- *
- * Registers a driver with the ACPI bus.  Searches the namespace for all
- * devices that match the driver's criteria and binds.  Returns zero for
- * success or a negative error status for failure.
- */
-int acpi_bus_register_driver(struct acpi_driver *driver)
-{
+	/* Set defaults for D0 and D3 states (always valid) */
+	device->power.states[ACPI_STATE_D0].flags.valid = 1;
+	device->power.states[ACPI_STATE_D0].power = 100;
+	device->power.states[ACPI_STATE_D3].flags.valid = 1;
+	device->power.states[ACPI_STATE_D3].power = 0;
 
-	if (acpi_disabled)
-		return -ENODEV;
+	/* TBD: System wake support and resource requirements. */
 
-	spin_lock(&acpi_device_lock);
-	list_add_tail(&driver->node, &acpi_bus_drivers);
-	spin_unlock(&acpi_device_lock);
-	acpi_driver_attach(driver);
+	device->power.state = ACPI_STATE_UNKNOWN;
 
 	return 0;
 }
 
-EXPORT_SYMBOL(acpi_bus_register_driver);
-
-/**
- * acpi_bus_unregister_driver - unregisters a driver with the APIC bus
- * @driver: driver to unregister
- *
- * Unregisters a driver with the ACPI bus.  Searches the namespace for all
- * devices that match the driver's criteria and unbinds.
- */
-void acpi_bus_unregister_driver(struct acpi_driver *driver)
-{
-	acpi_driver_detach(driver);
-
-	if (!atomic_read(&driver->references)) {
-		spin_lock(&acpi_device_lock);
-		list_del_init(&driver->node);
-		spin_unlock(&acpi_device_lock);
-	}
-	return;
-}
-
-EXPORT_SYMBOL(acpi_bus_unregister_driver);
-
-/**
- * acpi_bus_find_driver - check if there is a driver installed for the device
- * @device: device that we are trying to find a supporting driver for
- *
- * Parses the list of registered drivers looking for a driver applicable for
- * the specified device.
- */
-static int acpi_bus_find_driver(struct acpi_device *device)
-{
-	int result = 0;
-	struct list_head *node, *next;
-
-
-	spin_lock(&acpi_device_lock);
-	list_for_each_safe(node, next, &acpi_bus_drivers) {
-		struct acpi_driver *driver =
-		    container_of(node, struct acpi_driver, node);
-
-		atomic_inc(&driver->references);
-		spin_unlock(&acpi_device_lock);
-		if (!acpi_bus_match(device, driver)) {
-			result = acpi_bus_driver_init(device, driver);
-			if (!result)
-				goto Done;
-		}
-		atomic_dec(&driver->references);
-		spin_lock(&acpi_device_lock);
-	}
-	spin_unlock(&acpi_device_lock);
-
-      Done:
-	return result;
-}
-
-/* --------------------------------------------------------------------------
-                                 Device Enumeration
-   -------------------------------------------------------------------------- */
-
-acpi_status
-acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
-{
-	acpi_status status;
-	acpi_handle tmp;
-	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
-	union acpi_object *obj;
-
-	status = acpi_get_handle(handle, "_EJD", &tmp);
-	if (ACPI_FAILURE(status))
-		return status;
-
-	status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);
-	if (ACPI_SUCCESS(status)) {
-		obj = buffer.pointer;
-		status = acpi_get_handle(NULL, obj->string.pointer, ejd);
-		kfree(buffer.pointer);
-	}
-	return status;
-}
-EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
-
-
 static int acpi_bus_get_flags(struct acpi_device *device)
 {
 	acpi_status status = AE_OK;
@@ -782,6 +804,75 @@
 	}
 }
 
+static int
+acpi_video_bus_match(struct acpi_device *device)
+{
+	acpi_handle h_dummy1;
+	acpi_handle h_dummy2;
+	acpi_handle h_dummy3;
+
+
+	if (!device)
+		return -EINVAL;
+
+	/* Since there is no HID, CID for ACPI Video drivers, we have
+	 * to check well known required nodes for each feature we support.
+	 */
+
+	/* Does this device able to support video switching ? */
+	if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
+	    ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
+		return 0;
+
+	/* Does this device able to retrieve a video ROM ? */
+	if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
+		return 0;
+
+	/* Does this device able to configure which video head to be POSTed ? */
+	if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
+	    ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
+	    ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
+		return 0;
+
+	return -ENODEV;
+}
+
+/*
+ * acpi_bay_match - see if a device is an ejectable driver bay
+ *
+ * If an acpi object is ejectable and has one of the ACPI ATA methods defined,
+ * then we can safely call it an ejectable drive bay
+ */
+static int acpi_bay_match(struct acpi_device *device){
+	acpi_status status;
+	acpi_handle handle;
+	acpi_handle tmp;
+	acpi_handle phandle;
+
+	handle = device->handle;
+
+	status = acpi_get_handle(handle, "_EJ0", &tmp);
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
+		(ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
+		(ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
+		(ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
+		return 0;
+
+	if (acpi_get_parent(handle, &phandle))
+		return -ENODEV;
+
+        if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) ||
+                (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) ||
+                (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) ||
+                (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp))))
+                return 0;
+
+	return -ENODEV;
+}
+
 static void acpi_device_set_id(struct acpi_device *device,
 			       struct acpi_device *parent, acpi_handle handle,
 			       int type)
@@ -812,6 +903,16 @@
 			device->pnp.bus_address = info->address;
 			device->flags.bus_address = 1;
 		}
+
+		if(!(info->valid & (ACPI_VALID_HID | ACPI_VALID_CID))){
+			status = acpi_video_bus_match(device);
+			if(ACPI_SUCCESS(status))
+				hid = ACPI_VIDEO_HID;
+
+			status = acpi_bay_match(device);
+			if (ACPI_SUCCESS(status))
+				hid = ACPI_BAY_HID;
+		}
 		break;
 	case ACPI_BUS_TYPE_POWER:
 		hid = ACPI_POWER_HID;
@@ -888,86 +989,24 @@
 	return result;
 }
 
-static void acpi_device_get_debug_info(struct acpi_device *device,
-				       acpi_handle handle, int type)
-{
-#ifdef CONFIG_ACPI_DEBUG_OUTPUT
-	char *type_string = NULL;
-	char name[80] = { '?', '\0' };
-	struct acpi_buffer buffer = { sizeof(name), name };
-
-	switch (type) {
-	case ACPI_BUS_TYPE_DEVICE:
-		type_string = "Device";
-		acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-		break;
-	case ACPI_BUS_TYPE_POWER:
-		type_string = "Power Resource";
-		acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-		break;
-	case ACPI_BUS_TYPE_PROCESSOR:
-		type_string = "Processor";
-		acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-		break;
-	case ACPI_BUS_TYPE_SYSTEM:
-		type_string = "System";
-		acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-		break;
-	case ACPI_BUS_TYPE_THERMAL:
-		type_string = "Thermal Zone";
-		acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-		break;
-	case ACPI_BUS_TYPE_POWER_BUTTON:
-		type_string = "Power Button";
-		sprintf(name, "PWRB");
-		break;
-	case ACPI_BUS_TYPE_SLEEP_BUTTON:
-		type_string = "Sleep Button";
-		sprintf(name, "SLPB");
-		break;
-	}
-
-	printk(KERN_DEBUG "Found %s %s [%p]\n", type_string, name, handle);
-#endif				/*CONFIG_ACPI_DEBUG_OUTPUT */
-}
-
 static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
 {
-	int result = 0;
-	struct acpi_driver *driver;
-
-
 	if (!dev)
 		return -EINVAL;
 
-	driver = dev->driver;
-
-	if ((driver) && (driver->ops.remove)) {
-
-		if (driver->ops.stop) {
-			result = driver->ops.stop(dev, ACPI_BUS_REMOVAL_EJECT);
-			if (result)
-				return result;
-		}
-
-		result = dev->driver->ops.remove(dev, ACPI_BUS_REMOVAL_EJECT);
-		if (result) {
-			return result;
-		}
-
-		atomic_dec(&dev->driver->references);
-		dev->driver = NULL;
-		acpi_driver_data(dev) = NULL;
-	}
+	dev->removal_type = ACPI_BUS_REMOVAL_EJECT;
+	device_release_driver(&dev->dev);
 
 	if (!rmdevice)
 		return 0;
 
+	/*
+	 * unbind _ADR-Based Devices when hot removal
+	 */
 	if (dev->flags.bus_address) {
 		if ((dev->parent) && (dev->parent->ops.unbind))
 			dev->parent->ops.unbind(dev);
 	}
-
 	acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT);
 
 	return 0;
@@ -975,7 +1014,8 @@
 
 static int
 acpi_add_single_object(struct acpi_device **child,
-		       struct acpi_device *parent, acpi_handle handle, int type)
+		       struct acpi_device *parent, acpi_handle handle, int type,
+			struct acpi_bus_ops *ops)
 {
 	int result = 0;
 	struct acpi_device *device = NULL;
@@ -992,6 +1032,8 @@
 
 	device->handle = handle;
 	device->parent = parent;
+	device->bus_ops = *ops; /* workround for not call .start */
+
 
 	acpi_device_get_busid(device, handle, type);
 
@@ -1076,33 +1118,16 @@
 	if ((result = acpi_device_set_context(device, type)))
 		goto end;
 
-	acpi_device_get_debug_info(device, handle, type);
-
-	acpi_device_register(device, parent);
+	result = acpi_device_register(device, parent);
 
 	/*
-	 * Bind _ADR-Based Devices
-	 * -----------------------
-	 * If there's a a bus address (_ADR) then we utilize the parent's 
-	 * 'bind' function (if exists) to bind the ACPI- and natively-
-	 * enumerated device representations.
+	 * Bind _ADR-Based Devices when hot add
 	 */
 	if (device->flags.bus_address) {
 		if (device->parent && device->parent->ops.bind)
 			device->parent->ops.bind(device);
 	}
 
-	/*
-	 * Locate & Attach Driver
-	 * ----------------------
-	 * If there's a hardware id (_HID) or compatible ids (_CID) we check
-	 * to see if there's a driver installed for this kind of device.  Note
-	 * that drivers can install before or after a device is enumerated.
-	 *
-	 * TBD: Assumes LDM provides driver hot-plug capability.
-	 */
-	acpi_bus_find_driver(device);
-
       end:
 	if (!result)
 		*child = device;
@@ -1188,14 +1213,14 @@
 
 		if (ops->acpi_op_add)
 			status = acpi_add_single_object(&child, parent,
-							chandle, type);
+				chandle, type, ops);
 		else
 			status = acpi_bus_get_device(chandle, &child);
 
 		if (ACPI_FAILURE(status))
 			continue;
 
-		if (ops->acpi_op_start) {
+		if (ops->acpi_op_start && !(ops->acpi_op_add)) {
 			status = acpi_start_single_object(child);
 			if (ACPI_FAILURE(status))
 				continue;
@@ -1233,13 +1258,13 @@
 	int result;
 	struct acpi_bus_ops ops;
 
+	memset(&ops, 0, sizeof(ops));
+	ops.acpi_op_add = 1;
 
-	result = acpi_add_single_object(child, parent, handle, type);
-	if (!result) {
-		memset(&ops, 0, sizeof(ops));
-		ops.acpi_op_add = 1;
+	result = acpi_add_single_object(child, parent, handle, type, &ops);
+	if (!result)
 		result = acpi_bus_scan(*child, &ops);
-	}
+
 	return result;
 }
 
@@ -1325,127 +1350,35 @@
 {
 	int result = 0;
 	struct acpi_device *device = NULL;
-
+	struct acpi_bus_ops ops;
 
 	if (!root)
 		return -ENODEV;
 
+	memset(&ops, 0, sizeof(ops));
+	ops.acpi_op_add = 1;
+	ops.acpi_op_start = 1;
+
 	/*
 	 * Enumerate all fixed-feature devices.
 	 */
-	if (acpi_fadt.pwr_button == 0) {
+	if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) {
 		result = acpi_add_single_object(&device, acpi_root,
 						NULL,
-						ACPI_BUS_TYPE_POWER_BUTTON);
-		if (!result)
-			result = acpi_start_single_object(device);
+						ACPI_BUS_TYPE_POWER_BUTTON,
+						&ops);
 	}
 
-	if (acpi_fadt.sleep_button == 0) {
+	if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) {
 		result = acpi_add_single_object(&device, acpi_root,
 						NULL,
-						ACPI_BUS_TYPE_SLEEP_BUTTON);
-		if (!result)
-			result = acpi_start_single_object(device);
+						ACPI_BUS_TYPE_SLEEP_BUTTON,
+						&ops);
 	}
 
 	return result;
 }
 
-
-static inline struct acpi_device * to_acpi_dev(struct device * dev)
-{
-	return container_of(dev, struct acpi_device, dev);
-}
-
-
-static int root_suspend(struct acpi_device * acpi_dev, pm_message_t state)
-{
-	struct acpi_device * dev, * next;
-	int result;
-
-	spin_lock(&acpi_device_lock);
-	list_for_each_entry_safe_reverse(dev, next, &acpi_device_list, g_list) {
-		if (dev->driver && dev->driver->ops.suspend) {
-			spin_unlock(&acpi_device_lock);
-			result = dev->driver->ops.suspend(dev, 0);
-			if (result) {
-				printk(KERN_ERR PREFIX "[%s - %s] Suspend failed: %d\n",
-				       acpi_device_name(dev),
-				       acpi_device_bid(dev), result);
-			}
-			spin_lock(&acpi_device_lock);
-		}
-	}
-	spin_unlock(&acpi_device_lock);
-	return 0;
-}
-
-
-static int acpi_device_suspend(struct device * dev, pm_message_t state)
-{
-	struct acpi_device * acpi_dev = to_acpi_dev(dev);
-
-	/*
-	 * For now, we should only register 1 generic device -
-	 * the ACPI root device - and from there, we walk the
-	 * tree of ACPI devices to suspend each one using the
-	 * ACPI driver methods.
-	 */
-	if (acpi_dev->handle == ACPI_ROOT_OBJECT)
-		root_suspend(acpi_dev, state);
-	return 0;
-}
-
-
-
-static int root_resume(struct acpi_device * acpi_dev)
-{
-	struct acpi_device * dev, * next;
-	int result;
-
-	spin_lock(&acpi_device_lock);
-	list_for_each_entry_safe(dev, next, &acpi_device_list, g_list) {
-		if (dev->driver && dev->driver->ops.resume) {
-			spin_unlock(&acpi_device_lock);
-			result = dev->driver->ops.resume(dev, 0);
-			if (result) {
-				printk(KERN_ERR PREFIX "[%s - %s] resume failed: %d\n",
-				       acpi_device_name(dev),
-				       acpi_device_bid(dev), result);
-			}
-			spin_lock(&acpi_device_lock);
-		}
-	}
-	spin_unlock(&acpi_device_lock);
-	return 0;
-}
-
-
-static int acpi_device_resume(struct device * dev)
-{
-	struct acpi_device * acpi_dev = to_acpi_dev(dev);
-
-	/*
-	 * For now, we should only register 1 generic device -
-	 * the ACPI root device - and from there, we walk the
-	 * tree of ACPI devices to resume each one using the
-	 * ACPI driver methods.
-	 */
-	if (acpi_dev->handle == ACPI_ROOT_OBJECT)
-		root_resume(acpi_dev);
-	return 0;
-}
-
-
-static struct bus_type acpi_bus_type = {
-	.name		= "acpi",
-	.suspend	= acpi_device_suspend,
-	.resume		= acpi_device_resume,
-};
-
-
-
 static int __init acpi_scan_init(void)
 {
 	int result;
@@ -1455,9 +1388,9 @@
 	if (acpi_disabled)
 		return 0;
 
-	result = kset_register(&acpi_namespace_kset);
-	if (result < 0)
-		printk(KERN_ERR PREFIX "kset_register error: %d\n", result);
+	memset(&ops, 0, sizeof(ops));
+	ops.acpi_op_add = 1;
+	ops.acpi_op_start = 1;
 
 	result = bus_register(&acpi_bus_type);
 	if (result) {
@@ -1469,32 +1402,16 @@
 	 * Create the root device in the bus's device tree
 	 */
 	result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT,
-					ACPI_BUS_TYPE_SYSTEM);
+					ACPI_BUS_TYPE_SYSTEM, &ops);
 	if (result)
 		goto Done;
 
-	result = acpi_start_single_object(acpi_root);
-	if (result)
-		goto Done;
-
-	acpi_root->dev.bus = &acpi_bus_type;
-	snprintf(acpi_root->dev.bus_id, BUS_ID_SIZE, "%s", acpi_bus_type.name);
-	result = device_register(&acpi_root->dev);
-	if (result) {
-		/* We don't want to quit even if we failed to add suspend/resume */
-		printk(KERN_ERR PREFIX "Could not register device\n");
-	}
-
 	/*
 	 * Enumerate devices in the ACPI namespace.
 	 */
 	result = acpi_bus_scan_fixed(acpi_root);
-	if (!result) {
-		memset(&ops, 0, sizeof(ops));
-		ops.acpi_op_add = 1;
-		ops.acpi_op_start = 1;
+	if (!result)
 		result = acpi_bus_scan(acpi_root, &ops);
-	}
 
 	if (result)
 		acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 3496257..ccc11b3 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -73,7 +73,7 @@
 static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
 {
 	u32 sec, min, hr;
-	u32 day, mo, yr;
+	u32 day, mo, yr, cent = 0;
 	unsigned char rtc_control = 0;
 	unsigned long flags;
 
@@ -87,20 +87,19 @@
 	rtc_control = CMOS_READ(RTC_CONTROL);
 
 	/* If we ever get an FACP with proper values... */
-	if (acpi_gbl_FADT->day_alrm)
+	if (acpi_gbl_FADT.day_alarm)
 		/* ACPI spec: only low 6 its should be cared */
-		day = CMOS_READ(acpi_gbl_FADT->day_alrm) & 0x3F;
+		day = CMOS_READ(acpi_gbl_FADT.day_alarm) & 0x3F;
 	else
 		day = CMOS_READ(RTC_DAY_OF_MONTH);
-	if (acpi_gbl_FADT->mon_alrm)
-		mo = CMOS_READ(acpi_gbl_FADT->mon_alrm);
+	if (acpi_gbl_FADT.month_alarm)
+		mo = CMOS_READ(acpi_gbl_FADT.month_alarm);
 	else
 		mo = CMOS_READ(RTC_MONTH);
-	if (acpi_gbl_FADT->century)
-		yr = CMOS_READ(acpi_gbl_FADT->century) * 100 +
-		    CMOS_READ(RTC_YEAR);
-	else
-		yr = CMOS_READ(RTC_YEAR);
+	if (acpi_gbl_FADT.century)
+		cent = CMOS_READ(acpi_gbl_FADT.century);
+
+	yr = CMOS_READ(RTC_YEAR);
 
 	spin_unlock_irqrestore(&rtc_lock, flags);
 
@@ -111,10 +110,11 @@
 		BCD_TO_BIN(day);
 		BCD_TO_BIN(mo);
 		BCD_TO_BIN(yr);
+		BCD_TO_BIN(cent);
 	}
 
 	/* we're trusting the FADT (see above) */
-	if (!acpi_gbl_FADT->century)
+	if (!acpi_gbl_FADT.century)
 		/* If we're not trusting the FADT, we should at least make it
 		 * right for _this_ century... ehm, what is _this_ century?
 		 *
@@ -134,6 +134,8 @@
 		 *
 		 */
 		yr += 2000;
+	else
+		yr += cent * 100;
 
 	seq_printf(seq, "%4.4u-", yr);
 	(mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo);
@@ -317,12 +319,12 @@
 	 * offsets into the CMOS RAM here -- which for some reason are pointing
 	 * to the RTC area of memory.
 	 */
-	if (acpi_gbl_FADT->day_alrm)
-		CMOS_WRITE(day, acpi_gbl_FADT->day_alrm);
-	if (acpi_gbl_FADT->mon_alrm)
-		CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm);
-	if (acpi_gbl_FADT->century)
-		CMOS_WRITE(yr / 100, acpi_gbl_FADT->century);
+	if (acpi_gbl_FADT.day_alarm)
+		CMOS_WRITE(day, acpi_gbl_FADT.day_alarm);
+	if (acpi_gbl_FADT.month_alarm)
+		CMOS_WRITE(mo, acpi_gbl_FADT.month_alarm);
+	if (acpi_gbl_FADT.century)
+		CMOS_WRITE(yr / 100, acpi_gbl_FADT.century);
 	/* enable the rtc alarm interrupt */
 	rtc_control |= RTC_AIE;
 	CMOS_WRITE(rtc_control, RTC_CONTROL);
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index d86dcb3..7147b0b 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -32,6 +32,11 @@
 
 #define _COMPONENT		ACPI_SYSTEM_COMPONENT
 ACPI_MODULE_NAME("acpi_system")
+#ifdef MODULE_PARAM_PREFIX
+#undef MODULE_PARAM_PREFIX
+#endif
+#define MODULE_PARAM_PREFIX "acpi."
+
 #define ACPI_SYSTEM_CLASS		"system"
 #define ACPI_SYSTEM_DRIVER_NAME		"ACPI System Driver"
 #define ACPI_SYSTEM_DEVICE_NAME		"System"
@@ -39,11 +44,24 @@
 #define ACPI_SYSTEM_FILE_EVENT		"event"
 #define ACPI_SYSTEM_FILE_DSDT		"dsdt"
 #define ACPI_SYSTEM_FILE_FADT		"fadt"
-extern struct fadt_descriptor acpi_fadt;
+
+/*
+ * Make ACPICA version work as module param
+ */
+static int param_get_acpica_version(char *buffer, struct kernel_param *kp) {
+	int result;
+
+	result = sprintf(buffer, "%x", ACPI_CA_VERSION);
+
+	return result;
+}
+
+module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
 
 /* --------------------------------------------------------------------------
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROCFS
 
 static int acpi_system_read_info(struct seq_file *seq, void *offset)
 {
@@ -63,6 +81,7 @@
 	.llseek = seq_lseek,
 	.release = single_release,
 };
+#endif
 
 static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t,
 				     loff_t *);
@@ -76,17 +95,16 @@
 		      char __user * buffer, size_t count, loff_t * ppos)
 {
 	acpi_status status = AE_OK;
-	struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
+	struct acpi_table_header *dsdt = NULL;
 	ssize_t res;
 
 
-	status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt);
+	status = acpi_get_table(ACPI_SIG_DSDT, 1, &dsdt);
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
 	res = simple_read_from_buffer(buffer, count, ppos,
-				      dsdt.pointer, dsdt.length);
-	kfree(dsdt.pointer);
+				      dsdt, dsdt->length);
 
 	return res;
 }
@@ -103,17 +121,16 @@
 		      char __user * buffer, size_t count, loff_t * ppos)
 {
 	acpi_status status = AE_OK;
-	struct acpi_buffer fadt = { ACPI_ALLOCATE_BUFFER, NULL };
+	struct acpi_table_header *fadt = NULL;
 	ssize_t res;
 
 
-	status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &fadt);
+	status = acpi_get_table(ACPI_SIG_FADT, 1, &fadt);
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
 	res = simple_read_from_buffer(buffer, count, ppos,
-				      fadt.pointer, fadt.length);
-	kfree(fadt.pointer);
+				      fadt, fadt->length);
 
 	return res;
 }
@@ -128,6 +145,7 @@
 	if (acpi_disabled)
 		return 0;
 
+#ifdef CONFIG_ACPI_PROCFS
 	/* 'info' [R] */
 	name = ACPI_SYSTEM_FILE_INFO;
 	entry = create_proc_entry(name, S_IRUGO, acpi_root_dir);
@@ -136,6 +154,7 @@
 	else {
 		entry->proc_fops = &acpi_system_info_ops;
 	}
+#endif
 
 	/* 'dsdt' [R] */
 	name = ACPI_SYSTEM_FILE_DSDT;
@@ -159,7 +178,9 @@
       Error:
 	remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir);
 	remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir);
+#ifdef CONFIG_ACPI_PROCFS
 	remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir);
+#endif
 
 	error = -EFAULT;
 	goto Done;
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index ffa30c9..ba4cb20 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -38,154 +38,97 @@
 
 #define ACPI_MAX_TABLES		128
 
-static char *acpi_table_signatures[ACPI_TABLE_COUNT] = {
-	[ACPI_TABLE_UNKNOWN] = "????",
-	[ACPI_APIC] = "APIC",
-	[ACPI_BOOT] = "BOOT",
-	[ACPI_DBGP] = "DBGP",
-	[ACPI_DSDT] = "DSDT",
-	[ACPI_ECDT] = "ECDT",
-	[ACPI_ETDT] = "ETDT",
-	[ACPI_FADT] = "FACP",
-	[ACPI_FACS] = "FACS",
-	[ACPI_OEMX] = "OEM",
-	[ACPI_PSDT] = "PSDT",
-	[ACPI_SBST] = "SBST",
-	[ACPI_SLIT] = "SLIT",
-	[ACPI_SPCR] = "SPCR",
-	[ACPI_SRAT] = "SRAT",
-	[ACPI_SSDT] = "SSDT",
-	[ACPI_SPMI] = "SPMI",
-	[ACPI_HPET] = "HPET",
-	[ACPI_MCFG] = "MCFG",
-};
-
 static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
 static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" };
 
-/* System Description Table (RSDT/XSDT) */
-struct acpi_table_sdt {
-	unsigned long pa;
-	enum acpi_table_id id;
-	unsigned long size;
-} __attribute__ ((packed));
+static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata;
 
-static unsigned long sdt_pa;	/* Physical Address */
-static unsigned long sdt_count;	/* Table count */
-
-static struct acpi_table_sdt sdt_entry[ACPI_MAX_TABLES] __initdata;
-
-void acpi_table_print(struct acpi_table_header *header, unsigned long phys_addr)
-{
-	char *name = NULL;
-
-	if (!header)
-		return;
-
-	/* Some table signatures aren't good table names */
-
-	if (!strncmp((char *)&header->signature,
-		     acpi_table_signatures[ACPI_APIC],
-		     sizeof(header->signature))) {
-		name = "MADT";
-	} else if (!strncmp((char *)&header->signature,
-			    acpi_table_signatures[ACPI_FADT],
-			    sizeof(header->signature))) {
-		name = "FADT";
-	} else
-		name = header->signature;
-
-	printk(KERN_DEBUG PREFIX
-	       "%.4s (v%3.3d %6.6s %8.8s 0x%08x %.4s 0x%08x) @ 0x%p\n", name,
-	       header->revision, header->oem_id, header->oem_table_id,
-	       header->oem_revision, header->asl_compiler_id,
-	       header->asl_compiler_revision, (void *)phys_addr);
-}
-
-void acpi_table_print_madt_entry(acpi_table_entry_header * header)
+void acpi_table_print_madt_entry(struct acpi_subtable_header * header)
 {
 	if (!header)
 		return;
 
 	switch (header->type) {
 
-	case ACPI_MADT_LAPIC:
+	case ACPI_MADT_TYPE_LOCAL_APIC:
 		{
-			struct acpi_table_lapic *p =
-			    (struct acpi_table_lapic *)header;
+			struct acpi_madt_local_apic *p =
+			    (struct acpi_madt_local_apic *)header;
 			printk(KERN_INFO PREFIX
 			       "LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n",
-			       p->acpi_id, p->id,
-			       p->flags.enabled ? "enabled" : "disabled");
+			       p->processor_id, p->id,
+			       (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
 		}
 		break;
 
-	case ACPI_MADT_IOAPIC:
+	case ACPI_MADT_TYPE_IO_APIC:
 		{
-			struct acpi_table_ioapic *p =
-			    (struct acpi_table_ioapic *)header;
+			struct acpi_madt_io_apic *p =
+			    (struct acpi_madt_io_apic *)header;
 			printk(KERN_INFO PREFIX
 			       "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
 			       p->id, p->address, p->global_irq_base);
 		}
 		break;
 
-	case ACPI_MADT_INT_SRC_OVR:
+	case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
 		{
-			struct acpi_table_int_src_ovr *p =
-			    (struct acpi_table_int_src_ovr *)header;
+			struct acpi_madt_interrupt_override *p =
+			    (struct acpi_madt_interrupt_override *)header;
 			printk(KERN_INFO PREFIX
 			       "INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n",
-			       p->bus, p->bus_irq, p->global_irq,
-			       mps_inti_flags_polarity[p->flags.polarity],
-			       mps_inti_flags_trigger[p->flags.trigger]);
-			if (p->flags.reserved)
+			       p->bus, p->source_irq, p->global_irq,
+			       mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+			       mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]);
+			if (p->inti_flags  &
+			    ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK))
 				printk(KERN_INFO PREFIX
 				       "INT_SRC_OVR unexpected reserved flags: 0x%x\n",
-				       p->flags.reserved);
+				       p->inti_flags  &
+					~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK));
 
 		}
 		break;
 
-	case ACPI_MADT_NMI_SRC:
+	case ACPI_MADT_TYPE_NMI_SOURCE:
 		{
-			struct acpi_table_nmi_src *p =
-			    (struct acpi_table_nmi_src *)header;
+			struct acpi_madt_nmi_source *p =
+			    (struct acpi_madt_nmi_source *)header;
 			printk(KERN_INFO PREFIX
 			       "NMI_SRC (%s %s global_irq %d)\n",
-			       mps_inti_flags_polarity[p->flags.polarity],
-			       mps_inti_flags_trigger[p->flags.trigger],
+			       mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+			       mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
 			       p->global_irq);
 		}
 		break;
 
-	case ACPI_MADT_LAPIC_NMI:
+	case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
 		{
-			struct acpi_table_lapic_nmi *p =
-			    (struct acpi_table_lapic_nmi *)header;
+			struct acpi_madt_local_apic_nmi *p =
+			    (struct acpi_madt_local_apic_nmi *)header;
 			printk(KERN_INFO PREFIX
 			       "LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n",
-			       p->acpi_id,
-			       mps_inti_flags_polarity[p->flags.polarity],
-			       mps_inti_flags_trigger[p->flags.trigger],
+			       p->processor_id,
+			       mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK	],
+			       mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
 			       p->lint);
 		}
 		break;
 
-	case ACPI_MADT_LAPIC_ADDR_OVR:
+	case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE:
 		{
-			struct acpi_table_lapic_addr_ovr *p =
-			    (struct acpi_table_lapic_addr_ovr *)header;
+			struct acpi_madt_local_apic_override *p =
+			    (struct acpi_madt_local_apic_override *)header;
 			printk(KERN_INFO PREFIX
 			       "LAPIC_ADDR_OVR (address[%p])\n",
 			       (void *)(unsigned long)p->address);
 		}
 		break;
 
-	case ACPI_MADT_IOSAPIC:
+	case ACPI_MADT_TYPE_IO_SAPIC:
 		{
-			struct acpi_table_iosapic *p =
-			    (struct acpi_table_iosapic *)header;
+			struct acpi_madt_io_sapic *p =
+			    (struct acpi_madt_io_sapic *)header;
 			printk(KERN_INFO PREFIX
 			       "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
 			       p->id, (void *)(unsigned long)p->address,
@@ -193,26 +136,26 @@
 		}
 		break;
 
-	case ACPI_MADT_LSAPIC:
+	case ACPI_MADT_TYPE_LOCAL_SAPIC:
 		{
-			struct acpi_table_lsapic *p =
-			    (struct acpi_table_lsapic *)header;
+			struct acpi_madt_local_sapic *p =
+			    (struct acpi_madt_local_sapic *)header;
 			printk(KERN_INFO PREFIX
 			       "LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n",
-			       p->acpi_id, p->id, p->eid,
-			       p->flags.enabled ? "enabled" : "disabled");
+			       p->processor_id, p->id, p->eid,
+			       (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
 		}
 		break;
 
-	case ACPI_MADT_PLAT_INT_SRC:
+	case ACPI_MADT_TYPE_INTERRUPT_SOURCE:
 		{
-			struct acpi_table_plat_int_src *p =
-			    (struct acpi_table_plat_int_src *)header;
+			struct acpi_madt_interrupt_source *p =
+			    (struct acpi_madt_interrupt_source *)header;
 			printk(KERN_INFO PREFIX
 			       "PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n",
-			       mps_inti_flags_polarity[p->flags.polarity],
-			       mps_inti_flags_trigger[p->flags.trigger],
-			       p->type, p->id, p->eid, p->iosapic_vector,
+			       mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+			       mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
+			       p->type, p->id, p->eid, p->io_sapic_vector,
 			       p->global_irq);
 		}
 		break;
@@ -225,342 +168,76 @@
 	}
 }
 
-static int
-acpi_table_compute_checksum(void *table_pointer, unsigned long length)
-{
-	u8 *p = table_pointer;
-	unsigned long remains = length;
-	unsigned long sum = 0;
-
-	if (!p || !length)
-		return -EINVAL;
-
-	while (remains--)
-		sum += *p++;
-
-	return (sum & 0xFF);
-}
-
-/*
- * acpi_get_table_header_early()
- * for acpi_blacklisted(), acpi_table_get_sdt()
- */
-int __init
-acpi_get_table_header_early(enum acpi_table_id id,
-			    struct acpi_table_header **header)
-{
-	unsigned int i;
-	enum acpi_table_id temp_id;
-
-	/* DSDT is different from the rest */
-	if (id == ACPI_DSDT)
-		temp_id = ACPI_FADT;
-	else
-		temp_id = id;
-
-	/* Locate the table. */
-
-	for (i = 0; i < sdt_count; i++) {
-		if (sdt_entry[i].id != temp_id)
-			continue;
-		*header = (void *)
-		    __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size);
-		if (!*header) {
-			printk(KERN_WARNING PREFIX "Unable to map %s\n",
-			       acpi_table_signatures[temp_id]);
-			return -ENODEV;
-		}
-		break;
-	}
-
-	if (!*header) {
-		printk(KERN_WARNING PREFIX "%s not present\n",
-		       acpi_table_signatures[id]);
-		return -ENODEV;
-	}
-
-	/* Map the DSDT header via the pointer in the FADT */
-	if (id == ACPI_DSDT) {
-		struct fadt_descriptor *fadt =
-		    (struct fadt_descriptor *)*header;
-
-		if (fadt->revision == 3 && fadt->Xdsdt) {
-			*header = (void *)__acpi_map_table(fadt->Xdsdt,
-							   sizeof(struct
-								  acpi_table_header));
-		} else if (fadt->V1_dsdt) {
-			*header = (void *)__acpi_map_table(fadt->V1_dsdt,
-							   sizeof(struct
-								  acpi_table_header));
-		} else
-			*header = NULL;
-
-		if (!*header) {
-			printk(KERN_WARNING PREFIX "Unable to map DSDT\n");
-			return -ENODEV;
-		}
-	}
-
-	return 0;
-}
 
 int __init
-acpi_table_parse_madt_family(enum acpi_table_id id,
+acpi_table_parse_madt_family(char *id,
 			     unsigned long madt_size,
 			     int entry_id,
 			     acpi_madt_entry_handler handler,
 			     unsigned int max_entries)
 {
-	void *madt = NULL;
-	acpi_table_entry_header *entry;
+	struct acpi_table_header *madt = NULL;
+	struct acpi_subtable_header *entry;
 	unsigned int count = 0;
 	unsigned long madt_end;
-	unsigned int i;
 
 	if (!handler)
 		return -EINVAL;
 
 	/* Locate the MADT (if exists). There should only be one. */
-
-	for (i = 0; i < sdt_count; i++) {
-		if (sdt_entry[i].id != id)
-			continue;
-		madt = (void *)
-		    __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size);
-		if (!madt) {
-			printk(KERN_WARNING PREFIX "Unable to map %s\n",
-			       acpi_table_signatures[id]);
-			return -ENODEV;
-		}
-		break;
-	}
+	acpi_get_table(id, 0, &madt);
 
 	if (!madt) {
-		printk(KERN_WARNING PREFIX "%s not present\n",
-		       acpi_table_signatures[id]);
+		printk(KERN_WARNING PREFIX "%4.4s not present\n", id);
 		return -ENODEV;
 	}
 
-	madt_end = (unsigned long)madt + sdt_entry[i].size;
+	madt_end = (unsigned long)madt + madt->length;
 
 	/* Parse all entries looking for a match. */
 
-	entry = (acpi_table_entry_header *)
+	entry = (struct acpi_subtable_header *)
 	    ((unsigned long)madt + madt_size);
 
-	while (((unsigned long)entry) + sizeof(acpi_table_entry_header) <
+	while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) <
 	       madt_end) {
 		if (entry->type == entry_id
 		    && (!max_entries || count++ < max_entries))
 			if (handler(entry, madt_end))
 				return -EINVAL;
 
-		entry = (acpi_table_entry_header *)
+		entry = (struct acpi_subtable_header *)
 		    ((unsigned long)entry + entry->length);
 	}
 	if (max_entries && count > max_entries) {
-		printk(KERN_WARNING PREFIX "[%s:0x%02x] ignored %i entries of "
-		       "%i found\n", acpi_table_signatures[id], entry_id,
-		       count - max_entries, count);
+		printk(KERN_WARNING PREFIX "[%4.4s:0x%02x] ignored %i entries of "
+		       "%i found\n", id, entry_id, count - max_entries, count);
 	}
 
 	return count;
 }
 
 int __init
-acpi_table_parse_madt(enum acpi_madt_entry_id id,
+acpi_table_parse_madt(enum acpi_madt_type id,
 		      acpi_madt_entry_handler handler, unsigned int max_entries)
 {
-	return acpi_table_parse_madt_family(ACPI_APIC,
+	return acpi_table_parse_madt_family(ACPI_SIG_MADT,
 					    sizeof(struct acpi_table_madt), id,
 					    handler, max_entries);
 }
 
-int __init acpi_table_parse(enum acpi_table_id id, acpi_table_handler handler)
+int __init acpi_table_parse(char *id, acpi_table_handler handler)
 {
-	int count = 0;
-	unsigned int i = 0;
-
+	struct acpi_table_header *table = NULL;
 	if (!handler)
 		return -EINVAL;
 
-	for (i = 0; i < sdt_count; i++) {
-		if (sdt_entry[i].id != id)
-			continue;
-		count++;
-		if (count == 1)
-			handler(sdt_entry[i].pa, sdt_entry[i].size);
-
-		else
-			printk(KERN_WARNING PREFIX
-			       "%d duplicate %s table ignored.\n", count,
-			       acpi_table_signatures[id]);
-	}
-
-	return count;
-}
-
-static int __init acpi_table_get_sdt(struct acpi_table_rsdp *rsdp)
-{
-	struct acpi_table_header *header = NULL;
-	unsigned int i, id = 0;
-
-	if (!rsdp)
-		return -EINVAL;
-
-	/* First check XSDT (but only on ACPI 2.0-compatible systems) */
-
-	if ((rsdp->revision >= 2) &&
-	    (((struct acpi20_table_rsdp *)rsdp)->xsdt_address)) {
-
-		struct acpi_table_xsdt *mapped_xsdt = NULL;
-
-		sdt_pa = ((struct acpi20_table_rsdp *)rsdp)->xsdt_address;
-
-		/* map in just the header */
-		header = (struct acpi_table_header *)
-		    __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header));
-
-		if (!header) {
-			printk(KERN_WARNING PREFIX
-			       "Unable to map XSDT header\n");
-			return -ENODEV;
-		}
-
-		/* remap in the entire table before processing */
-		mapped_xsdt = (struct acpi_table_xsdt *)
-		    __acpi_map_table(sdt_pa, header->length);
-		if (!mapped_xsdt) {
-			printk(KERN_WARNING PREFIX "Unable to map XSDT\n");
-			return -ENODEV;
-		}
-		header = &mapped_xsdt->header;
-
-		if (strncmp(header->signature, "XSDT", 4)) {
-			printk(KERN_WARNING PREFIX
-			       "XSDT signature incorrect\n");
-			return -ENODEV;
-		}
-
-		if (acpi_table_compute_checksum(header, header->length)) {
-			printk(KERN_WARNING PREFIX "Invalid XSDT checksum\n");
-			return -ENODEV;
-		}
-
-		sdt_count =
-		    (header->length - sizeof(struct acpi_table_header)) >> 3;
-		if (sdt_count > ACPI_MAX_TABLES) {
-			printk(KERN_WARNING PREFIX
-			       "Truncated %lu XSDT entries\n",
-			       (sdt_count - ACPI_MAX_TABLES));
-			sdt_count = ACPI_MAX_TABLES;
-		}
-
-		for (i = 0; i < sdt_count; i++)
-			sdt_entry[i].pa = (unsigned long)mapped_xsdt->entry[i];
-	}
-
-	/* Then check RSDT */
-
-	else if (rsdp->rsdt_address) {
-
-		struct acpi_table_rsdt *mapped_rsdt = NULL;
-
-		sdt_pa = rsdp->rsdt_address;
-
-		/* map in just the header */
-		header = (struct acpi_table_header *)
-		    __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header));
-		if (!header) {
-			printk(KERN_WARNING PREFIX
-			       "Unable to map RSDT header\n");
-			return -ENODEV;
-		}
-
-		/* remap in the entire table before processing */
-		mapped_rsdt = (struct acpi_table_rsdt *)
-		    __acpi_map_table(sdt_pa, header->length);
-		if (!mapped_rsdt) {
-			printk(KERN_WARNING PREFIX "Unable to map RSDT\n");
-			return -ENODEV;
-		}
-		header = &mapped_rsdt->header;
-
-		if (strncmp(header->signature, "RSDT", 4)) {
-			printk(KERN_WARNING PREFIX
-			       "RSDT signature incorrect\n");
-			return -ENODEV;
-		}
-
-		if (acpi_table_compute_checksum(header, header->length)) {
-			printk(KERN_WARNING PREFIX "Invalid RSDT checksum\n");
-			return -ENODEV;
-		}
-
-		sdt_count =
-		    (header->length - sizeof(struct acpi_table_header)) >> 2;
-		if (sdt_count > ACPI_MAX_TABLES) {
-			printk(KERN_WARNING PREFIX
-			       "Truncated %lu RSDT entries\n",
-			       (sdt_count - ACPI_MAX_TABLES));
-			sdt_count = ACPI_MAX_TABLES;
-		}
-
-		for (i = 0; i < sdt_count; i++)
-			sdt_entry[i].pa = (unsigned long)mapped_rsdt->entry[i];
-	}
-
-	else {
-		printk(KERN_WARNING PREFIX
-		       "No System Description Table (RSDT/XSDT) specified in RSDP\n");
-		return -ENODEV;
-	}
-
-	acpi_table_print(header, sdt_pa);
-
-	for (i = 0; i < sdt_count; i++) {
-
-		/* map in just the header */
-		header = (struct acpi_table_header *)
-		    __acpi_map_table(sdt_entry[i].pa,
-				     sizeof(struct acpi_table_header));
-		if (!header)
-			continue;
-
-		/* remap in the entire table before processing */
-		header = (struct acpi_table_header *)
-		    __acpi_map_table(sdt_entry[i].pa, header->length);
-		if (!header)
-			continue;
-
-		acpi_table_print(header, sdt_entry[i].pa);
-
-		if (acpi_table_compute_checksum(header, header->length)) {
-			printk(KERN_WARNING "  >>> ERROR: Invalid checksum\n");
-			continue;
-		}
-
-		sdt_entry[i].size = header->length;
-
-		for (id = 0; id < ACPI_TABLE_COUNT; id++) {
-			if (!strncmp((char *)&header->signature,
-				     acpi_table_signatures[id],
-				     sizeof(header->signature))) {
-				sdt_entry[i].id = id;
-			}
-		}
-	}
-
-	/* 
-	 * The DSDT is *not* in the RSDT (why not? no idea.) but we want
-	 * to print its info, because this is what people usually blacklist
-	 * against. Unfortunately, we don't know the phys_addr, so just
-	 * print 0. Maybe no one will notice.
-	 */
-	if (!acpi_get_table_header_early(ACPI_DSDT, &header))
-		acpi_table_print(header, 0);
-
-	return 0;
+	acpi_get_table(id, 0, &table);
+	if (table) {
+		handler(table);
+		return 1;
+	} else
+		return 0;
 }
 
 /*
@@ -568,54 +245,13 @@
  *
  * find RSDP, find and checksum SDT/XSDT.
  * checksum all tables, print SDT/XSDT
- * 
+ *
  * result: sdt_entry[] is initialized
  */
 
+
 int __init acpi_table_init(void)
 {
-	struct acpi_table_rsdp *rsdp = NULL;
-	unsigned long rsdp_phys = 0;
-	int result = 0;
-
-	/* Locate and map the Root System Description Table (RSDP) */
-
-	rsdp_phys = acpi_find_rsdp();
-	if (!rsdp_phys) {
-		printk(KERN_ERR PREFIX "Unable to locate RSDP\n");
-		return -ENODEV;
-	}
-
-	rsdp = (struct acpi_table_rsdp *)__acpi_map_table(rsdp_phys,
-		sizeof(struct acpi_table_rsdp));
-	if (!rsdp) {
-		printk(KERN_WARNING PREFIX "Unable to map RSDP\n");
-		return -ENODEV;
-	}
-
-	printk(KERN_DEBUG PREFIX
-	       "RSDP (v%3.3d %6.6s                                ) @ 0x%p\n",
-	       rsdp->revision, rsdp->oem_id, (void *)rsdp_phys);
-
-	if (rsdp->revision < 2)
-		result =
-		    acpi_table_compute_checksum(rsdp,
-						sizeof(struct acpi_table_rsdp));
-	else
-		result =
-		    acpi_table_compute_checksum(rsdp,
-						((struct acpi20_table_rsdp *)
-						 rsdp)->length);
-
-	if (result) {
-		printk(KERN_WARNING "  >>> ERROR: Invalid checksum\n");
-		return -ENODEV;
-	}
-
-	/* Locate and map the System Description table (RSDT/XSDT) */
-
-	if (acpi_table_get_sdt(rsdp))
-		return -ENODEV;
-
+	acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
 	return 0;
 }
diff --git a/drivers/acpi/tables/Makefile b/drivers/acpi/tables/Makefile
index aa4c695..0a7d7af 100644
--- a/drivers/acpi/tables/Makefile
+++ b/drivers/acpi/tables/Makefile
@@ -2,7 +2,6 @@
 # Makefile for all Linux ACPI interpreter subdirectories
 #
 
-obj-y := tbconvrt.o  tbget.o     tbrsdt.o   tbxface.o  \
-	 tbgetall.o  tbinstal.o  tbutils.o  tbxfroot.o
+obj-y := tbxface.o tbinstal.o  tbutils.o tbfind.o tbfadt.o
 
 EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c
deleted file mode 100644
index d697fcb..0000000
--- a/drivers/acpi/tables/tbconvrt.c
+++ /dev/null
@@ -1,622 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbconvrt - ACPI Table conversion utilities
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- *    substantially similar to the "NO WARRANTY" disclaimer below
- *    ("Disclaimer") and any redistribution must be conditioned upon
- *    including a substantially similar Disclaimer requirement for further
- *    binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- *    of any contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT          ACPI_TABLES
-ACPI_MODULE_NAME("tbconvrt")
-
-/* Local prototypes */
-static void
-acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct,
-			     u8 register_bit_width,
-			     acpi_physical_address address);
-
-static void
-acpi_tb_convert_fadt1(struct fadt_descriptor *local_fadt,
-		      struct fadt_descriptor_rev1 *original_fadt);
-
-static void
-acpi_tb_convert_fadt2(struct fadt_descriptor *local_fadt,
-		      struct fadt_descriptor *original_fadt);
-
-u8 acpi_fadt_is_v1;
-ACPI_EXPORT_SYMBOL(acpi_fadt_is_v1)
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_table_count
- *
- * PARAMETERS:  RSDP            - Pointer to the RSDP
- *              RSDT            - Pointer to the RSDT/XSDT
- *
- * RETURN:      The number of tables pointed to by the RSDT or XSDT.
- *
- * DESCRIPTION: Calculate the number of tables.  Automatically handles either
- *              an RSDT or XSDT.
- *
- ******************************************************************************/
-
-u32
-acpi_tb_get_table_count(struct rsdp_descriptor *RSDP,
-			struct acpi_table_header *RSDT)
-{
-	u32 pointer_size;
-
-	ACPI_FUNCTION_ENTRY();
-
-	/* RSDT pointers are 32 bits, XSDT pointers are 64 bits */
-
-	if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
-		pointer_size = sizeof(u32);
-	} else {
-		pointer_size = sizeof(u64);
-	}
-
-	/*
-	 * Determine the number of tables pointed to by the RSDT/XSDT.
-	 * This is defined by the ACPI Specification to be the number of
-	 * pointers contained within the RSDT/XSDT.  The size of the pointers
-	 * is architecture-dependent.
-	 */
-	return ((RSDT->length -
-		 sizeof(struct acpi_table_header)) / pointer_size);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_convert_to_xsdt
- *
- * PARAMETERS:  table_info      - Info about the RSDT
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Convert an RSDT to an XSDT (internal common format)
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_convert_to_xsdt(struct acpi_table_desc *table_info)
-{
-	acpi_size table_size;
-	u32 i;
-	struct xsdt_descriptor *new_table;
-
-	ACPI_FUNCTION_ENTRY();
-
-	/* Compute size of the converted XSDT */
-
-	table_size = ((acpi_size) acpi_gbl_rsdt_table_count * sizeof(u64)) +
-	    sizeof(struct acpi_table_header);
-
-	/* Allocate an XSDT */
-
-	new_table = ACPI_ALLOCATE_ZEROED(table_size);
-	if (!new_table) {
-		return (AE_NO_MEMORY);
-	}
-
-	/* Copy the header and set the length */
-
-	ACPI_MEMCPY(new_table, table_info->pointer,
-		    sizeof(struct acpi_table_header));
-	new_table->length = (u32) table_size;
-
-	/* Copy the table pointers */
-
-	for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
-
-		/* RSDT pointers are 32 bits, XSDT pointers are 64 bits */
-
-		if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
-			ACPI_STORE_ADDRESS(new_table->table_offset_entry[i],
-					   (ACPI_CAST_PTR
-					    (struct rsdt_descriptor,
-					     table_info->pointer))->
-					   table_offset_entry[i]);
-		} else {
-			new_table->table_offset_entry[i] =
-			    (ACPI_CAST_PTR(struct xsdt_descriptor,
-					   table_info->pointer))->
-			    table_offset_entry[i];
-		}
-	}
-
-	/* Delete the original table (either mapped or in a buffer) */
-
-	acpi_tb_delete_single_table(table_info);
-
-	/* Point the table descriptor to the new table */
-
-	table_info->pointer =
-	    ACPI_CAST_PTR(struct acpi_table_header, new_table);
-	table_info->length = table_size;
-	table_info->allocation = ACPI_MEM_ALLOCATED;
-
-	return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_init_generic_address
- *
- * PARAMETERS:  new_gas_struct      - GAS struct to be initialized
- *              register_bit_width  - Width of this register
- *              Address             - Address of the register
- *
- * RETURN:      None
- *
- * DESCRIPTION: Initialize a GAS structure.
- *
- ******************************************************************************/
-
-static void
-acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct,
-			     u8 register_bit_width,
-			     acpi_physical_address address)
-{
-
-	ACPI_STORE_ADDRESS(new_gas_struct->address, address);
-
-	new_gas_struct->address_space_id = ACPI_ADR_SPACE_SYSTEM_IO;
-	new_gas_struct->register_bit_width = register_bit_width;
-	new_gas_struct->register_bit_offset = 0;
-	new_gas_struct->access_width = 0;
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_convert_fadt1
- *
- * PARAMETERS:  local_fadt      - Pointer to new FADT
- *              original_fadt   - Pointer to old FADT
- *
- * RETURN:      None, populates local_fadt
- *
- * DESCRIPTION: Convert an ACPI 1.0 FADT to common internal format
- *
- ******************************************************************************/
-
-static void
-acpi_tb_convert_fadt1(struct fadt_descriptor *local_fadt,
-		      struct fadt_descriptor_rev1 *original_fadt)
-{
-
-	/* ACPI 1.0 FACS */
-	/* The BIOS stored FADT should agree with Revision 1.0 */
-	acpi_fadt_is_v1 = 1;
-
-	/*
-	 * Copy the table header and the common part of the tables.
-	 *
-	 * The 2.0 table is an extension of the 1.0 table, so the entire 1.0
-	 * table can be copied first, then expand some fields to 64 bits.
-	 */
-	ACPI_MEMCPY(local_fadt, original_fadt,
-		    sizeof(struct fadt_descriptor_rev1));
-
-	/* Convert table pointers to 64-bit fields */
-
-	ACPI_STORE_ADDRESS(local_fadt->xfirmware_ctrl,
-			   local_fadt->V1_firmware_ctrl);
-	ACPI_STORE_ADDRESS(local_fadt->Xdsdt, local_fadt->V1_dsdt);
-
-	/*
-	 * System Interrupt Model isn't used in ACPI 2.0
-	 * (local_fadt->Reserved1 = 0;)
-	 */
-
-	/*
-	 * This field is set by the OEM to convey the preferred power management
-	 * profile to OSPM. It doesn't have any 1.0 equivalence.  Since we don't
-	 * know what kind of 32-bit system this is, we will use "unspecified".
-	 */
-	local_fadt->prefer_PM_profile = PM_UNSPECIFIED;
-
-	/*
-	 * Processor Performance State Control. This is the value OSPM writes to
-	 * the SMI_CMD register to assume processor performance state control
-	 * responsibility. There isn't any equivalence in 1.0, but as many 1.x
-	 * ACPI tables contain _PCT and _PSS we also keep this value, unless
-	 * acpi_strict is set.
-	 */
-	if (acpi_strict)
-		local_fadt->pstate_cnt = 0;
-
-	/*
-	 * Support for the _CST object and C States change notification.
-	 * This data item hasn't any 1.0 equivalence so leave it zero.
-	 */
-	local_fadt->cst_cnt = 0;
-
-	/*
-	 * FADT Rev 2 was an interim FADT released between ACPI 1.0 and ACPI 2.0.
-	 * It primarily adds the FADT reset mechanism.
-	 */
-	if ((original_fadt->revision == 2) &&
-	    (original_fadt->length ==
-	     sizeof(struct fadt_descriptor_rev2_minus))) {
-		/*
-		 * Grab the entire generic address struct, plus the 1-byte reset value
-		 * that immediately follows.
-		 */
-		ACPI_MEMCPY(&local_fadt->reset_register,
-			    &(ACPI_CAST_PTR(struct fadt_descriptor_rev2_minus,
-					    original_fadt))->reset_register,
-			    sizeof(struct acpi_generic_address) + 1);
-	} else {
-		/*
-		 * Since there isn't any equivalence in 1.0 and since it is highly
-		 * likely that a 1.0 system has legacy support.
-		 */
-		local_fadt->iapc_boot_arch = BAF_LEGACY_DEVICES;
-	}
-
-	/*
-	 * Convert the V1.0 block addresses to V2.0 GAS structures
-	 */
-	acpi_tb_init_generic_address(&local_fadt->xpm1a_evt_blk,
-				     local_fadt->pm1_evt_len,
-				     (acpi_physical_address) local_fadt->
-				     V1_pm1a_evt_blk);
-	acpi_tb_init_generic_address(&local_fadt->xpm1b_evt_blk,
-				     local_fadt->pm1_evt_len,
-				     (acpi_physical_address) local_fadt->
-				     V1_pm1b_evt_blk);
-	acpi_tb_init_generic_address(&local_fadt->xpm1a_cnt_blk,
-				     local_fadt->pm1_cnt_len,
-				     (acpi_physical_address) local_fadt->
-				     V1_pm1a_cnt_blk);
-	acpi_tb_init_generic_address(&local_fadt->xpm1b_cnt_blk,
-				     local_fadt->pm1_cnt_len,
-				     (acpi_physical_address) local_fadt->
-				     V1_pm1b_cnt_blk);
-	acpi_tb_init_generic_address(&local_fadt->xpm2_cnt_blk,
-				     local_fadt->pm2_cnt_len,
-				     (acpi_physical_address) local_fadt->
-				     V1_pm2_cnt_blk);
-	acpi_tb_init_generic_address(&local_fadt->xpm_tmr_blk,
-				     local_fadt->pm_tm_len,
-				     (acpi_physical_address) local_fadt->
-				     V1_pm_tmr_blk);
-	acpi_tb_init_generic_address(&local_fadt->xgpe0_blk, 0,
-				     (acpi_physical_address) local_fadt->
-				     V1_gpe0_blk);
-	acpi_tb_init_generic_address(&local_fadt->xgpe1_blk, 0,
-				     (acpi_physical_address) local_fadt->
-				     V1_gpe1_blk);
-
-	/* Create separate GAS structs for the PM1 Enable registers */
-
-	acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
-				     (u8) ACPI_DIV_2(acpi_gbl_FADT->
-						     pm1_evt_len),
-				     (acpi_physical_address)
-				     (local_fadt->xpm1a_evt_blk.address +
-				      ACPI_DIV_2(acpi_gbl_FADT->pm1_evt_len)));
-
-	/* PM1B is optional; leave null if not present */
-
-	if (local_fadt->xpm1b_evt_blk.address) {
-		acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
-					     (u8) ACPI_DIV_2(acpi_gbl_FADT->
-							     pm1_evt_len),
-					     (acpi_physical_address)
-					     (local_fadt->xpm1b_evt_blk.
-					      address +
-					      ACPI_DIV_2(acpi_gbl_FADT->
-							 pm1_evt_len)));
-	}
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_convert_fadt2
- *
- * PARAMETERS:  local_fadt      - Pointer to new FADT
- *              original_fadt   - Pointer to old FADT
- *
- * RETURN:      None, populates local_fadt
- *
- * DESCRIPTION: Convert an ACPI 2.0 FADT to common internal format.
- *              Handles optional "X" fields.
- *
- ******************************************************************************/
-
-static void
-acpi_tb_convert_fadt2(struct fadt_descriptor *local_fadt,
-		      struct fadt_descriptor *original_fadt)
-{
-
-	/* We have an ACPI 2.0 FADT but we must copy it to our local buffer */
-
-	ACPI_MEMCPY(local_fadt, original_fadt, sizeof(struct fadt_descriptor));
-
-	/*
-	 * "X" fields are optional extensions to the original V1.0 fields, so
-	 * we must selectively expand V1.0 fields if the corresponding X field
-	 * is zero.
-	 */
-	if (!(local_fadt->xfirmware_ctrl)) {
-		ACPI_STORE_ADDRESS(local_fadt->xfirmware_ctrl,
-				   local_fadt->V1_firmware_ctrl);
-	}
-
-	if (!(local_fadt->Xdsdt)) {
-		ACPI_STORE_ADDRESS(local_fadt->Xdsdt, local_fadt->V1_dsdt);
-	}
-
-	if (!(local_fadt->xpm1a_evt_blk.address)) {
-		acpi_tb_init_generic_address(&local_fadt->xpm1a_evt_blk,
-					     local_fadt->pm1_evt_len,
-					     (acpi_physical_address)
-					     local_fadt->V1_pm1a_evt_blk);
-	}
-
-	if (!(local_fadt->xpm1b_evt_blk.address)) {
-		acpi_tb_init_generic_address(&local_fadt->xpm1b_evt_blk,
-					     local_fadt->pm1_evt_len,
-					     (acpi_physical_address)
-					     local_fadt->V1_pm1b_evt_blk);
-	}
-
-	if (!(local_fadt->xpm1a_cnt_blk.address)) {
-		acpi_tb_init_generic_address(&local_fadt->xpm1a_cnt_blk,
-					     local_fadt->pm1_cnt_len,
-					     (acpi_physical_address)
-					     local_fadt->V1_pm1a_cnt_blk);
-	}
-
-	if (!(local_fadt->xpm1b_cnt_blk.address)) {
-		acpi_tb_init_generic_address(&local_fadt->xpm1b_cnt_blk,
-					     local_fadt->pm1_cnt_len,
-					     (acpi_physical_address)
-					     local_fadt->V1_pm1b_cnt_blk);
-	}
-
-	if (!(local_fadt->xpm2_cnt_blk.address)) {
-		acpi_tb_init_generic_address(&local_fadt->xpm2_cnt_blk,
-					     local_fadt->pm2_cnt_len,
-					     (acpi_physical_address)
-					     local_fadt->V1_pm2_cnt_blk);
-	}
-
-	if (!(local_fadt->xpm_tmr_blk.address)) {
-		acpi_tb_init_generic_address(&local_fadt->xpm_tmr_blk,
-					     local_fadt->pm_tm_len,
-					     (acpi_physical_address)
-					     local_fadt->V1_pm_tmr_blk);
-	}
-
-	if (!(local_fadt->xgpe0_blk.address)) {
-		acpi_tb_init_generic_address(&local_fadt->xgpe0_blk,
-					     0,
-					     (acpi_physical_address)
-					     local_fadt->V1_gpe0_blk);
-	}
-
-	if (!(local_fadt->xgpe1_blk.address)) {
-		acpi_tb_init_generic_address(&local_fadt->xgpe1_blk,
-					     0,
-					     (acpi_physical_address)
-					     local_fadt->V1_gpe1_blk);
-	}
-
-	/* Create separate GAS structs for the PM1 Enable registers */
-
-	acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
-				     (u8) ACPI_DIV_2(acpi_gbl_FADT->
-						     pm1_evt_len),
-				     (acpi_physical_address)
-				     (local_fadt->xpm1a_evt_blk.address +
-				      ACPI_DIV_2(acpi_gbl_FADT->pm1_evt_len)));
-
-	acpi_gbl_xpm1a_enable.address_space_id =
-	    local_fadt->xpm1a_evt_blk.address_space_id;
-
-	/* PM1B is optional; leave null if not present */
-
-	if (local_fadt->xpm1b_evt_blk.address) {
-		acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
-					     (u8) ACPI_DIV_2(acpi_gbl_FADT->
-							     pm1_evt_len),
-					     (acpi_physical_address)
-					     (local_fadt->xpm1b_evt_blk.
-					      address +
-					      ACPI_DIV_2(acpi_gbl_FADT->
-							 pm1_evt_len)));
-
-		acpi_gbl_xpm1b_enable.address_space_id =
-		    local_fadt->xpm1b_evt_blk.address_space_id;
-	}
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_convert_table_fadt
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Converts a BIOS supplied ACPI 1.0 FADT to a local
- *              ACPI 2.0 FADT. If the BIOS supplied a 2.0 FADT then it is simply
- *              copied to the local FADT.  The ACPI CA software uses this
- *              local FADT. Thus a significant amount of special #ifdef
- *              type codeing is saved.
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_convert_table_fadt(void)
-{
-	struct fadt_descriptor *local_fadt;
-	struct acpi_table_desc *table_desc;
-
-	ACPI_FUNCTION_TRACE(tb_convert_table_fadt);
-
-	/*
-	 * acpi_gbl_FADT is valid. Validate the FADT length. The table must be
-	 * at least as long as the version 1.0 FADT
-	 */
-	if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor_rev1)) {
-		ACPI_ERROR((AE_INFO, "FADT is invalid, too short: 0x%X",
-			    acpi_gbl_FADT->length));
-		return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
-	}
-
-	/* Allocate buffer for the ACPI 2.0(+) FADT */
-
-	local_fadt = ACPI_ALLOCATE_ZEROED(sizeof(struct fadt_descriptor));
-	if (!local_fadt) {
-		return_ACPI_STATUS(AE_NO_MEMORY);
-	}
-
-	if (acpi_gbl_FADT->revision >= FADT2_REVISION_ID) {
-		if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor)) {
-
-			/* Length is too short to be a V2.0 table */
-
-			ACPI_WARNING((AE_INFO,
-				      "Inconsistent FADT length (0x%X) and revision (0x%X), using FADT V1.0 portion of table",
-				      acpi_gbl_FADT->length,
-				      acpi_gbl_FADT->revision));
-
-			acpi_tb_convert_fadt1(local_fadt,
-					      (void *)acpi_gbl_FADT);
-		} else {
-			/* Valid V2.0 table */
-
-			acpi_tb_convert_fadt2(local_fadt, acpi_gbl_FADT);
-		}
-	} else {
-		/* Valid V1.0 table */
-
-		acpi_tb_convert_fadt1(local_fadt, (void *)acpi_gbl_FADT);
-	}
-
-	/* Global FADT pointer will point to the new common V2.0 FADT */
-
-	acpi_gbl_FADT = local_fadt;
-	acpi_gbl_FADT->length = sizeof(struct fadt_descriptor);
-
-	/* Free the original table */
-
-	table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_FADT].next;
-	acpi_tb_delete_single_table(table_desc);
-
-	/* Install the new table */
-
-	table_desc->pointer =
-	    ACPI_CAST_PTR(struct acpi_table_header, acpi_gbl_FADT);
-	table_desc->allocation = ACPI_MEM_ALLOCATED;
-	table_desc->length = sizeof(struct fadt_descriptor);
-
-	/* Dump the entire FADT */
-
-	ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
-			  "Hex dump of common internal FADT, size %d (%X)\n",
-			  acpi_gbl_FADT->length, acpi_gbl_FADT->length));
-
-	ACPI_DUMP_BUFFER(ACPI_CAST_PTR(u8, acpi_gbl_FADT),
-			 acpi_gbl_FADT->length);
-
-	return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_build_common_facs
- *
- * PARAMETERS:  table_info      - Info for currently installed FACS
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Convert ACPI 1.0 and ACPI 2.0 FACS to a common internal
- *              table format.
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_build_common_facs(struct acpi_table_desc *table_info)
-{
-
-	ACPI_FUNCTION_TRACE(tb_build_common_facs);
-
-	/* Absolute minimum length is 24, but the ACPI spec says 64 */
-
-	if (acpi_gbl_FACS->length < 24) {
-		ACPI_ERROR((AE_INFO, "Invalid FACS table length: 0x%X",
-			    acpi_gbl_FACS->length));
-		return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
-	}
-
-	if (acpi_gbl_FACS->length < 64) {
-		ACPI_WARNING((AE_INFO,
-			      "FACS is shorter than the ACPI specification allows: 0x%X, using anyway",
-			      acpi_gbl_FACS->length));
-	}
-
-	/* Copy fields to the new FACS */
-
-	acpi_gbl_common_fACS.global_lock = &(acpi_gbl_FACS->global_lock);
-
-	if ((acpi_gbl_RSDP->revision < 2) ||
-	    (acpi_gbl_FACS->length < 32) ||
-	    (!(acpi_gbl_FACS->xfirmware_waking_vector))) {
-
-		/* ACPI 1.0 FACS or short table or optional X_ field is zero */
-
-		acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR(u64,
-									    &
-									    (acpi_gbl_FACS->
-									     firmware_waking_vector));
-		acpi_gbl_common_fACS.vector_width = 32;
-	} else {
-		/* ACPI 2.0 FACS with valid X_ field */
-
-		acpi_gbl_common_fACS.firmware_waking_vector =
-		    &acpi_gbl_FACS->xfirmware_waking_vector;
-		acpi_gbl_common_fACS.vector_width = 64;
-	}
-
-	return_ACPI_STATUS(AE_OK);
-}
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
new file mode 100644
index 0000000..807c711
--- /dev/null
+++ b/drivers/acpi/tables/tbfadt.c
@@ -0,0 +1,434 @@
+/******************************************************************************
+ *
+ * Module Name: tbfadt   - FADT table utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2007, R. Byron Moore
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/actables.h>
+
+#define _COMPONENT          ACPI_TABLES
+ACPI_MODULE_NAME("tbfadt")
+
+/* Local prototypes */
+static void inline
+acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
+			     u8 bit_width, u64 address);
+
+static void acpi_tb_convert_fadt(void);
+
+static void acpi_tb_validate_fadt(void);
+
+/* Table for conversion of FADT to common internal format and FADT validation */
+
+typedef struct acpi_fadt_info {
+	char *name;
+	u8 target;
+	u8 source;
+	u8 length;
+	u8 type;
+
+} acpi_fadt_info;
+
+#define ACPI_FADT_REQUIRED          1
+#define ACPI_FADT_SEPARATE_LENGTH   2
+
+static struct acpi_fadt_info fadt_info_table[] = {
+	{"Pm1aEventBlock", ACPI_FADT_OFFSET(xpm1a_event_block),
+	 ACPI_FADT_OFFSET(pm1a_event_block),
+	 ACPI_FADT_OFFSET(pm1_event_length), ACPI_FADT_REQUIRED},
+
+	{"Pm1bEventBlock", ACPI_FADT_OFFSET(xpm1b_event_block),
+	 ACPI_FADT_OFFSET(pm1b_event_block),
+	 ACPI_FADT_OFFSET(pm1_event_length), 0},
+
+	{"Pm1aControlBlock", ACPI_FADT_OFFSET(xpm1a_control_block),
+	 ACPI_FADT_OFFSET(pm1a_control_block),
+	 ACPI_FADT_OFFSET(pm1_control_length), ACPI_FADT_REQUIRED},
+
+	{"Pm1bControlBlock", ACPI_FADT_OFFSET(xpm1b_control_block),
+	 ACPI_FADT_OFFSET(pm1b_control_block),
+	 ACPI_FADT_OFFSET(pm1_control_length), 0},
+
+	{"Pm2ControlBlock", ACPI_FADT_OFFSET(xpm2_control_block),
+	 ACPI_FADT_OFFSET(pm2_control_block),
+	 ACPI_FADT_OFFSET(pm2_control_length), ACPI_FADT_SEPARATE_LENGTH},
+
+	{"PmTimerBlock", ACPI_FADT_OFFSET(xpm_timer_block),
+	 ACPI_FADT_OFFSET(pm_timer_block),
+	 ACPI_FADT_OFFSET(pm_timer_length), ACPI_FADT_REQUIRED},
+
+	{"Gpe0Block", ACPI_FADT_OFFSET(xgpe0_block),
+	 ACPI_FADT_OFFSET(gpe0_block),
+	 ACPI_FADT_OFFSET(gpe0_block_length), ACPI_FADT_SEPARATE_LENGTH},
+
+	{"Gpe1Block", ACPI_FADT_OFFSET(xgpe1_block),
+	 ACPI_FADT_OFFSET(gpe1_block),
+	 ACPI_FADT_OFFSET(gpe1_block_length), ACPI_FADT_SEPARATE_LENGTH}
+};
+
+#define ACPI_FADT_INFO_ENTRIES        (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info))
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_init_generic_address
+ *
+ * PARAMETERS:  generic_address     - GAS struct to be initialized
+ *              bit_width           - Width of this register
+ *              Address             - Address of the register
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Initialize a Generic Address Structure (GAS)
+ *              See the ACPI specification for a full description and
+ *              definition of this structure.
+ *
+ ******************************************************************************/
+
+static void inline
+acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
+			     u8 bit_width, u64 address)
+{
+
+	/*
+	 * The 64-bit Address field is non-aligned in the byte packed
+	 * GAS struct.
+	 */
+	ACPI_MOVE_64_TO_64(&generic_address->address, &address);
+
+	/* All other fields are byte-wide */
+
+	generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO;
+	generic_address->bit_width = bit_width;
+	generic_address->bit_offset = 0;
+	generic_address->access_width = 0;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_parse_fadt
+ *
+ * PARAMETERS:  table_index         - Index for the FADT
+ *              Flags               - Flags
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Initialize the FADT, DSDT and FACS tables
+ *              (FADT contains the addresses of the DSDT and FACS)
+ *
+ ******************************************************************************/
+
+void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags)
+{
+	u32 length;
+	struct acpi_table_header *table;
+
+	/*
+	 * The FADT has multiple versions with different lengths,
+	 * and it contains pointers to both the DSDT and FACS tables.
+	 *
+	 * Get a local copy of the FADT and convert it to a common format
+	 * Map entire FADT, assumed to be smaller than one page.
+	 */
+	length = acpi_gbl_root_table_list.tables[table_index].length;
+
+	table =
+	    acpi_os_map_memory(acpi_gbl_root_table_list.tables[table_index].
+			       address, length);
+	if (!table) {
+		return;
+	}
+
+	/*
+	 * Validate the FADT checksum before we copy the table. Ignore
+	 * checksum error as we want to try to get the DSDT and FACS.
+	 */
+	(void)acpi_tb_verify_checksum(table, length);
+
+	/* Obtain a local copy of the FADT in common ACPI 2.0+ format */
+
+	acpi_tb_create_local_fadt(table, length);
+
+	/* All done with the real FADT, unmap it */
+
+	acpi_os_unmap_memory(table, length);
+
+	/* Obtain the DSDT and FACS tables via their addresses within the FADT */
+
+	acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt,
+			      flags, ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT);
+
+	acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs,
+			      flags, ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_create_local_fadt
+ *
+ * PARAMETERS:  Table               - Pointer to BIOS FADT
+ *              Length              - Length of the table
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Get a local copy of the FADT and convert it to a common format.
+ *              Performs validation on some important FADT fields.
+ *
+ ******************************************************************************/
+
+void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
+{
+
+	/*
+	 * Check if the FADT is larger than what we know about (ACPI 2.0 version).
+	 * Truncate the table, but make some noise.
+	 */
+	if (length > sizeof(struct acpi_table_fadt)) {
+		ACPI_WARNING((AE_INFO,
+			      "FADT (revision %u) is longer than ACPI 2.0 version, truncating length 0x%X to 0x%zX",
+			      table->revision, (unsigned)length,
+			      sizeof(struct acpi_table_fadt)));
+	}
+
+	/* Copy the entire FADT locally. Zero first for tb_convert_fadt */
+
+	ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt));
+
+	ACPI_MEMCPY(&acpi_gbl_FADT, table,
+		    ACPI_MIN(length, sizeof(struct acpi_table_fadt)));
+
+	/*
+	 * 1) Convert the local copy of the FADT to the common internal format
+	 * 2) Validate some of the important values within the FADT
+	 */
+	acpi_tb_convert_fadt();
+	acpi_tb_validate_fadt();
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_convert_fadt
+ *
+ * PARAMETERS:  None, uses acpi_gbl_FADT
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Converts all versions of the FADT to a common internal format.
+ *              -> Expand all 32-bit addresses to 64-bit.
+ *
+ * NOTE:        acpi_gbl_FADT must be of size (struct acpi_table_fadt),
+ *              and must contain a copy of the actual FADT.
+ *
+ * ACPICA will use the "X" fields of the FADT for all addresses.
+ *
+ * "X" fields are optional extensions to the original V1.0 fields. Even if
+ * they are present in the structure, they can be optionally not used by
+ * setting them to zero. Therefore, we must selectively expand V1.0 fields
+ * if the corresponding X field is zero.
+ *
+ * For ACPI 1.0 FADTs, all address fields are expanded to the corresponding
+ * "X" fields.
+ *
+ * For ACPI 2.0 FADTs, any "X" fields that are NULL are filled in by
+ * expanding the corresponding ACPI 1.0 field.
+ *
+ ******************************************************************************/
+
+static void acpi_tb_convert_fadt(void)
+{
+	u8 pm1_register_length;
+	struct acpi_generic_address *target;
+	acpi_native_uint i;
+
+	/* Update the local FADT table header length */
+
+	acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt);
+
+	/* Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary */
+
+	if (!acpi_gbl_FADT.Xfacs) {
+		acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs;
+	}
+
+	if (!acpi_gbl_FADT.Xdsdt) {
+		acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt;
+	}
+
+	/*
+	 * Expand the 32-bit V1.0 addresses to the 64-bit "X" generic address
+	 * structures as necessary.
+	 */
+	for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
+		target =
+		    ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
+				 fadt_info_table[i].target);
+
+		/* Expand only if the X target is null */
+
+		if (!target->address) {
+			acpi_tb_init_generic_address(target,
+						     *ACPI_ADD_PTR(u8,
+								   &acpi_gbl_FADT,
+								   fadt_info_table
+								   [i].length),
+						     (u64) * ACPI_ADD_PTR(u32,
+									  &acpi_gbl_FADT,
+									  fadt_info_table
+									  [i].
+									  source));
+		}
+	}
+
+	/*
+	 * Calculate separate GAS structs for the PM1 Enable registers.
+	 * These addresses do not appear (directly) in the FADT, so it is
+	 * useful to calculate them once, here.
+	 *
+	 * The PM event blocks are split into two register blocks, first is the
+	 * PM Status Register block, followed immediately by the PM Enable Register
+	 * block. Each is of length (pm1_event_length/2)
+	 */
+	pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length);
+
+	/* The PM1A register block is required */
+
+	acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
+				     pm1_register_length,
+				     (acpi_gbl_FADT.xpm1a_event_block.address +
+				      pm1_register_length));
+	/* Don't forget to copy space_id of the GAS */
+	acpi_gbl_xpm1a_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
+
+	/* The PM1B register block is optional, ignore if not present */
+
+	if (acpi_gbl_FADT.xpm1b_event_block.address) {
+		acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
+					     pm1_register_length,
+					     (acpi_gbl_FADT.xpm1b_event_block.
+					      address + pm1_register_length));
+		/* Don't forget to copy space_id of the GAS */
+		acpi_gbl_xpm1b_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
+
+	}
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_validate_fadt
+ *
+ * PARAMETERS:  Table           - Pointer to the FADT to be validated
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Validate various important fields within the FADT. If a problem
+ *              is found, issue a message, but no status is returned.
+ *              Used by both the table manager and the disassembler.
+ *
+ * Possible additional checks:
+ * (acpi_gbl_FADT.pm1_event_length >= 4)
+ * (acpi_gbl_FADT.pm1_control_length >= 2)
+ * (acpi_gbl_FADT.pm_timer_length >= 4)
+ * Gpe block lengths must be multiple of 2
+ *
+ ******************************************************************************/
+
+static void acpi_tb_validate_fadt(void)
+{
+	u32 *address32;
+	struct acpi_generic_address *address64;
+	u8 length;
+	acpi_native_uint i;
+
+	/* Examine all of the 64-bit extended address fields (X fields) */
+
+	for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
+
+		/* Generate pointers to the 32-bit and 64-bit addresses and get the length */
+
+		address64 =
+		    ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
+				 fadt_info_table[i].target);
+		address32 =
+		    ACPI_ADD_PTR(u32, &acpi_gbl_FADT,
+				 fadt_info_table[i].source);
+		length =
+		    *ACPI_ADD_PTR(u8, &acpi_gbl_FADT,
+				  fadt_info_table[i].length);
+
+		if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) {
+			/*
+			 * Field is required (Pm1a_event, Pm1a_control, pm_timer).
+			 * Both the address and length must be non-zero.
+			 */
+			if (!address64->address || !length) {
+				ACPI_ERROR((AE_INFO,
+					    "Required field \"%s\" has zero address and/or length: %8.8X%8.8X/%X",
+					    fadt_info_table[i].name,
+					    ACPI_FORMAT_UINT64(address64->
+							       address),
+					    length));
+			}
+		} else if (fadt_info_table[i].type & ACPI_FADT_SEPARATE_LENGTH) {
+			/*
+			 * Field is optional (PM2Control, GPE0, GPE1) AND has its own
+			 * length field. If present, both the address and length must be valid.
+			 */
+			if ((address64->address && !length)
+			    || (!address64->address && length)) {
+				ACPI_WARNING((AE_INFO,
+					      "Optional field \"%s\" has zero address or length: %8.8X%8.8X/%X",
+					      fadt_info_table[i].name,
+					      ACPI_FORMAT_UINT64(address64->
+								 address),
+					      length));
+			}
+		}
+
+		/* If both 32- and 64-bit addresses are valid (non-zero), they must match */
+
+		if (address64->address && *address32 &&
+		    (address64->address != (u64) * address32)) {
+			ACPI_ERROR((AE_INFO,
+				    "32/64X address mismatch in \"%s\": [%8.8X] [%8.8X%8.8X], using 64X",
+				    fadt_info_table[i].name, *address32,
+				    ACPI_FORMAT_UINT64(address64->address)));
+		}
+	}
+}
diff --git a/drivers/acpi/tables/tbfind.c b/drivers/acpi/tables/tbfind.c
new file mode 100644
index 0000000..058c064
--- /dev/null
+++ b/drivers/acpi/tables/tbfind.c
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ * Module Name: tbfind   - find table
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2007, R. Byron Moore
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/actables.h>
+
+#define _COMPONENT          ACPI_TABLES
+ACPI_MODULE_NAME("tbfind")
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_find_table
+ *
+ * PARAMETERS:  Signature           - String with ACPI table signature
+ *              oem_id              - String with the table OEM ID
+ *              oem_table_id        - String with the OEM Table ID
+ *              table_index         - Where the table index is returned
+ *
+ * RETURN:      Status and table index
+ *
+ * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the
+ *              Signature, OEM ID and OEM Table ID. Returns an index that can
+ *              be used to get the table header or entire table.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_tb_find_table(char *signature,
+		   char *oem_id,
+		   char *oem_table_id, acpi_native_uint * table_index)
+{
+	acpi_native_uint i;
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(tb_find_table);
+
+	for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+		if (ACPI_MEMCMP(&(acpi_gbl_root_table_list.tables[i].signature),
+				signature, ACPI_NAME_SIZE)) {
+
+			/* Not the requested table */
+
+			continue;
+		}
+
+		/* Table with matching signature has been found */
+
+		if (!acpi_gbl_root_table_list.tables[i].pointer) {
+
+			/* Table is not currently mapped, map it */
+
+			status =
+			    acpi_tb_verify_table(&acpi_gbl_root_table_list.
+						 tables[i]);
+			if (ACPI_FAILURE(status)) {
+				return_ACPI_STATUS(status);
+			}
+
+			if (!acpi_gbl_root_table_list.tables[i].pointer) {
+				continue;
+			}
+		}
+
+		/* Check for table match on all IDs */
+
+		if (!ACPI_MEMCMP
+		    (acpi_gbl_root_table_list.tables[i].pointer->signature,
+		     signature, ACPI_NAME_SIZE) && (!oem_id[0]
+						    ||
+						    !ACPI_MEMCMP
+						    (acpi_gbl_root_table_list.
+						     tables[i].pointer->oem_id,
+						     oem_id, ACPI_OEM_ID_SIZE))
+		    && (!oem_table_id[0]
+			|| !ACPI_MEMCMP(acpi_gbl_root_table_list.tables[i].
+					pointer->oem_table_id, oem_table_id,
+					ACPI_OEM_TABLE_ID_SIZE))) {
+			*table_index = i;
+
+			ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
+					  "Found table [%4.4s]\n", signature));
+			return_ACPI_STATUS(AE_OK);
+		}
+	}
+
+	return_ACPI_STATUS(AE_NOT_FOUND);
+}
diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c
deleted file mode 100644
index 11e2d44..0000000
--- a/drivers/acpi/tables/tbget.c
+++ /dev/null
@@ -1,471 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbget - ACPI Table get* routines
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- *    substantially similar to the "NO WARRANTY" disclaimer below
- *    ("Disclaimer") and any redistribution must be conditioned upon
- *    including a substantially similar Disclaimer requirement for further
- *    binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- *    of any contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT          ACPI_TABLES
-ACPI_MODULE_NAME("tbget")
-
-/* Local prototypes */
-static acpi_status
-acpi_tb_get_this_table(struct acpi_pointer *address,
-		       struct acpi_table_header *header,
-		       struct acpi_table_desc *table_info);
-
-static acpi_status
-acpi_tb_table_override(struct acpi_table_header *header,
-		       struct acpi_table_desc *table_info);
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_table
- *
- * PARAMETERS:  Address             - Address of table to retrieve.  Can be
- *                                    Logical or Physical
- *              table_info          - Where table info is returned
- *
- * RETURN:      None
- *
- * DESCRIPTION: Get entire table of unknown size.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table(struct acpi_pointer *address,
-		  struct acpi_table_desc *table_info)
-{
-	acpi_status status;
-	struct acpi_table_header header;
-
-	ACPI_FUNCTION_TRACE(tb_get_table);
-
-	/* Get the header in order to get signature and table size */
-
-	status = acpi_tb_get_table_header(address, &header);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Get the entire table */
-
-	status = acpi_tb_get_table_body(address, &header, table_info);
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status,
-				"Could not get ACPI table (size %X)",
-				header.length));
-		return_ACPI_STATUS(status);
-	}
-
-	return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_table_header
- *
- * PARAMETERS:  Address             - Address of table to retrieve.  Can be
- *                                    Logical or Physical
- *              return_header       - Where the table header is returned
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Get an ACPI table header.  Works in both physical or virtual
- *              addressing mode.  Works with both physical or logical pointers.
- *              Table is either copied or mapped, depending on the pointer
- *              type and mode of the processor.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table_header(struct acpi_pointer *address,
-			 struct acpi_table_header *return_header)
-{
-	acpi_status status = AE_OK;
-	struct acpi_table_header *header = NULL;
-
-	ACPI_FUNCTION_TRACE(tb_get_table_header);
-
-	/*
-	 * Flags contains the current processor mode (Virtual or Physical
-	 * addressing) The pointer_type is either Logical or Physical
-	 */
-	switch (address->pointer_type) {
-	case ACPI_PHYSMODE_PHYSPTR:
-	case ACPI_LOGMODE_LOGPTR:
-
-		/* Pointer matches processor mode, copy the header */
-
-		ACPI_MEMCPY(return_header, address->pointer.logical,
-			    sizeof(struct acpi_table_header));
-		break;
-
-	case ACPI_LOGMODE_PHYSPTR:
-
-		/* Create a logical address for the physical pointer */
-
-		status = acpi_os_map_memory(address->pointer.physical,
-					    sizeof(struct acpi_table_header),
-					    (void *)&header);
-		if (ACPI_FAILURE(status)) {
-			ACPI_ERROR((AE_INFO,
-				    "Could not map memory at %8.8X%8.8X for table header",
-				    ACPI_FORMAT_UINT64(address->pointer.
-						       physical)));
-			return_ACPI_STATUS(status);
-		}
-
-		/* Copy header and delete mapping */
-
-		ACPI_MEMCPY(return_header, header,
-			    sizeof(struct acpi_table_header));
-		acpi_os_unmap_memory(header, sizeof(struct acpi_table_header));
-		break;
-
-	default:
-
-		ACPI_ERROR((AE_INFO, "Invalid address flags %X",
-			    address->pointer_type));
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-	}
-
-	ACPI_DEBUG_PRINT((ACPI_DB_TABLES, "Table Signature: [%4.4s]\n",
-			  return_header->signature));
-
-	return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_table_body
- *
- * PARAMETERS:  Address             - Address of table to retrieve.  Can be
- *                                    Logical or Physical
- *              Header              - Header of the table to retrieve
- *              table_info          - Where the table info is returned
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Get an entire ACPI table with support to allow the host OS to
- *              replace the table with a newer version (table override.)
- *              Works in both physical or virtual
- *              addressing mode.  Works with both physical or logical pointers.
- *              Table is either copied or mapped, depending on the pointer
- *              type and mode of the processor.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table_body(struct acpi_pointer *address,
-		       struct acpi_table_header *header,
-		       struct acpi_table_desc *table_info)
-{
-	acpi_status status;
-
-	ACPI_FUNCTION_TRACE(tb_get_table_body);
-
-	if (!table_info || !address) {
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-	}
-
-	/* Attempt table override. */
-
-	status = acpi_tb_table_override(header, table_info);
-	if (ACPI_SUCCESS(status)) {
-
-		/* Table was overridden by the host OS */
-
-		return_ACPI_STATUS(status);
-	}
-
-	/* No override, get the original table */
-
-	status = acpi_tb_get_this_table(address, header, table_info);
-	return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_table_override
- *
- * PARAMETERS:  Header              - Pointer to table header
- *              table_info          - Return info if table is overridden
- *
- * RETURN:      None
- *
- * DESCRIPTION: Attempts override of current table with a new one if provided
- *              by the host OS.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_table_override(struct acpi_table_header *header,
-		       struct acpi_table_desc *table_info)
-{
-	struct acpi_table_header *new_table;
-	acpi_status status;
-	struct acpi_pointer address;
-
-	ACPI_FUNCTION_TRACE(tb_table_override);
-
-	/*
-	 * The OSL will examine the header and decide whether to override this
-	 * table.  If it decides to override, a table will be returned in new_table,
-	 * which we will then copy.
-	 */
-	status = acpi_os_table_override(header, &new_table);
-	if (ACPI_FAILURE(status)) {
-
-		/* Some severe error from the OSL, but we basically ignore it */
-
-		ACPI_EXCEPTION((AE_INFO, status,
-				"Could not override ACPI table"));
-		return_ACPI_STATUS(status);
-	}
-
-	if (!new_table) {
-
-		/* No table override */
-
-		return_ACPI_STATUS(AE_NO_ACPI_TABLES);
-	}
-
-	/*
-	 * We have a new table to override the old one.  Get a copy of
-	 * the new one.  We know that the new table has a logical pointer.
-	 */
-	address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING;
-	address.pointer.logical = new_table;
-
-	status = acpi_tb_get_this_table(&address, new_table, table_info);
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "Could not copy ACPI table"));
-		return_ACPI_STATUS(status);
-	}
-
-	/* Copy the table info */
-
-	ACPI_INFO((AE_INFO, "Table [%4.4s] replaced by host OS",
-		   table_info->pointer->signature));
-
-	return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_this_table
- *
- * PARAMETERS:  Address             - Address of table to retrieve.  Can be
- *                                    Logical or Physical
- *              Header              - Header of the table to retrieve
- *              table_info          - Where the table info is returned
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Get an entire ACPI table.  Works in both physical or virtual
- *              addressing mode.  Works with both physical or logical pointers.
- *              Table is either copied or mapped, depending on the pointer
- *              type and mode of the processor.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_get_this_table(struct acpi_pointer *address,
-		       struct acpi_table_header *header,
-		       struct acpi_table_desc *table_info)
-{
-	struct acpi_table_header *full_table = NULL;
-	u8 allocation;
-	acpi_status status = AE_OK;
-
-	ACPI_FUNCTION_TRACE(tb_get_this_table);
-
-	/* Validate minimum length */
-
-	if (header->length < sizeof(struct acpi_table_header)) {
-		ACPI_ERROR((AE_INFO,
-			    "Table length (%X) is smaller than minimum (%zX)",
-			    header->length, sizeof(struct acpi_table_header)));
-
-		return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
-	}
-
-	/*
-	 * Flags contains the current processor mode (Virtual or Physical
-	 * addressing) The pointer_type is either Logical or Physical
-	 */
-	switch (address->pointer_type) {
-	case ACPI_PHYSMODE_PHYSPTR:
-	case ACPI_LOGMODE_LOGPTR:
-
-		/* Pointer matches processor mode, copy the table to a new buffer */
-
-		full_table = ACPI_ALLOCATE(header->length);
-		if (!full_table) {
-			ACPI_ERROR((AE_INFO,
-				    "Could not allocate table memory for [%4.4s] length %X",
-				    header->signature, header->length));
-			return_ACPI_STATUS(AE_NO_MEMORY);
-		}
-
-		/* Copy the entire table (including header) to the local buffer */
-
-		ACPI_MEMCPY(full_table, address->pointer.logical,
-			    header->length);
-
-		/* Save allocation type */
-
-		allocation = ACPI_MEM_ALLOCATED;
-		break;
-
-	case ACPI_LOGMODE_PHYSPTR:
-
-		/*
-		 * Just map the table's physical memory
-		 * into our address space.
-		 */
-		status = acpi_os_map_memory(address->pointer.physical,
-					    (acpi_size) header->length,
-					    ACPI_CAST_PTR(void, &full_table));
-		if (ACPI_FAILURE(status)) {
-			ACPI_ERROR((AE_INFO,
-				    "Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X",
-				    header->signature,
-				    ACPI_FORMAT_UINT64(address->pointer.
-						       physical),
-				    header->length));
-			return (status);
-		}
-
-		/* Save allocation type */
-
-		allocation = ACPI_MEM_MAPPED;
-		break;
-
-	default:
-
-		ACPI_ERROR((AE_INFO, "Invalid address flags %X",
-			    address->pointer_type));
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-	}
-
-	/*
-	 * Validate checksum for _most_ tables,
-	 * even the ones whose signature we don't recognize
-	 */
-	if (table_info->type != ACPI_TABLE_ID_FACS) {
-		status = acpi_tb_verify_table_checksum(full_table);
-
-#if (!ACPI_CHECKSUM_ABORT)
-		if (ACPI_FAILURE(status)) {
-
-			/* Ignore the error if configuration says so */
-
-			status = AE_OK;
-		}
-#endif
-	}
-
-	/* Return values */
-
-	table_info->pointer = full_table;
-	table_info->length = (acpi_size) header->length;
-	table_info->allocation = allocation;
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-			  "Found table [%4.4s] at %8.8X%8.8X, mapped/copied to %p\n",
-			  full_table->signature,
-			  ACPI_FORMAT_UINT64(address->pointer.physical),
-			  full_table));
-
-	return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_table_ptr
- *
- * PARAMETERS:  table_type      - one of the defined table types
- *              Instance        - Which table of this type
- *              return_table    - pointer to location to place the pointer for
- *                                return
- *
- * RETURN:      Status
- *
- * DESCRIPTION: This function is called to get the pointer to an ACPI table.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table_ptr(acpi_table_type table_type,
-		      u32 instance, struct acpi_table_header **return_table)
-{
-	struct acpi_table_desc *table_desc;
-	u32 i;
-
-	ACPI_FUNCTION_TRACE(tb_get_table_ptr);
-
-	if (table_type > ACPI_TABLE_ID_MAX) {
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-	}
-
-	/* Check for instance out of range of the current table count */
-
-	if (instance > acpi_gbl_table_lists[table_type].count) {
-		return_ACPI_STATUS(AE_NOT_EXIST);
-	}
-
-	/*
-	 * Walk the list to get the desired table
-	 * Note: Instance is one-based
-	 */
-	table_desc = acpi_gbl_table_lists[table_type].next;
-	for (i = 1; i < instance; i++) {
-		table_desc = table_desc->next;
-	}
-
-	/* We are now pointing to the requested table's descriptor */
-
-	*return_table = table_desc->pointer;
-	return_ACPI_STATUS(AE_OK);
-}
diff --git a/drivers/acpi/tables/tbgetall.c b/drivers/acpi/tables/tbgetall.c
deleted file mode 100644
index ad98211..0000000
--- a/drivers/acpi/tables/tbgetall.c
+++ /dev/null
@@ -1,311 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbgetall - Get all required ACPI tables
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- *    substantially similar to the "NO WARRANTY" disclaimer below
- *    ("Disclaimer") and any redistribution must be conditioned upon
- *    including a substantially similar Disclaimer requirement for further
- *    binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- *    of any contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT          ACPI_TABLES
-ACPI_MODULE_NAME("tbgetall")
-
-/* Local prototypes */
-static acpi_status
-acpi_tb_get_primary_table(struct acpi_pointer *address,
-			  struct acpi_table_desc *table_info);
-
-static acpi_status
-acpi_tb_get_secondary_table(struct acpi_pointer *address,
-			    acpi_string signature,
-			    struct acpi_table_desc *table_info);
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_primary_table
- *
- * PARAMETERS:  Address             - Physical address of table to retrieve
- *              *table_info         - Where the table info is returned
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Maps the physical address of table into a logical address
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_get_primary_table(struct acpi_pointer *address,
-			  struct acpi_table_desc *table_info)
-{
-	acpi_status status;
-	struct acpi_table_header header;
-
-	ACPI_FUNCTION_TRACE(tb_get_primary_table);
-
-	/* Ignore a NULL address in the RSDT */
-
-	if (!address->pointer.value) {
-		return_ACPI_STATUS(AE_OK);
-	}
-
-	/* Get the header in order to get signature and table size */
-
-	status = acpi_tb_get_table_header(address, &header);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Clear the table_info */
-
-	ACPI_MEMSET(table_info, 0, sizeof(struct acpi_table_desc));
-
-	/*
-	 * Check the table signature and make sure it is recognized.
-	 * Also checks the header checksum
-	 */
-	table_info->pointer = &header;
-	status = acpi_tb_recognize_table(table_info, ACPI_TABLE_PRIMARY);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Get the entire table */
-
-	status = acpi_tb_get_table_body(address, &header, table_info);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Install the table */
-
-	status = acpi_tb_install_table(table_info);
-	return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_secondary_table
- *
- * PARAMETERS:  Address             - Physical address of table to retrieve
- *              *table_info         - Where the table info is returned
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Maps the physical address of table into a logical address
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_get_secondary_table(struct acpi_pointer *address,
-			    acpi_string signature,
-			    struct acpi_table_desc *table_info)
-{
-	acpi_status status;
-	struct acpi_table_header header;
-
-	ACPI_FUNCTION_TRACE_STR(tb_get_secondary_table, signature);
-
-	/* Get the header in order to match the signature */
-
-	status = acpi_tb_get_table_header(address, &header);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Signature must match request */
-
-	if (!ACPI_COMPARE_NAME(header.signature, signature)) {
-		ACPI_ERROR((AE_INFO,
-			    "Incorrect table signature - wanted [%s] found [%4.4s]",
-			    signature, header.signature));
-		return_ACPI_STATUS(AE_BAD_SIGNATURE);
-	}
-
-	/*
-	 * Check the table signature and make sure it is recognized.
-	 * Also checks the header checksum
-	 */
-	table_info->pointer = &header;
-	status = acpi_tb_recognize_table(table_info, ACPI_TABLE_SECONDARY);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Get the entire table */
-
-	status = acpi_tb_get_table_body(address, &header, table_info);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Install the table */
-
-	status = acpi_tb_install_table(table_info);
-	return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_required_tables
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Load and validate tables other than the RSDT.  The RSDT must
- *              already be loaded and validated.
- *
- *              Get the minimum set of ACPI tables, namely:
- *
- *              1) FADT (via RSDT in loop below)
- *              2) FACS (via FADT)
- *              3) DSDT (via FADT)
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_get_required_tables(void)
-{
-	acpi_status status = AE_OK;
-	u32 i;
-	struct acpi_table_desc table_info;
-	struct acpi_pointer address;
-
-	ACPI_FUNCTION_TRACE(tb_get_required_tables);
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%d ACPI tables in RSDT\n",
-			  acpi_gbl_rsdt_table_count));
-
-	address.pointer_type = acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING;
-
-	/*
-	 * Loop through all table pointers found in RSDT.
-	 * This will NOT include the FACS and DSDT - we must get
-	 * them after the loop.
-	 *
-	 * The only tables we are interested in getting here is the FADT and
-	 * any SSDTs.
-	 */
-	for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
-
-		/* Get the table address from the common internal XSDT */
-
-		address.pointer.value = acpi_gbl_XSDT->table_offset_entry[i];
-
-		/*
-		 * Get the tables needed by this subsystem (FADT and any SSDTs).
-		 * NOTE: All other tables are completely ignored at this time.
-		 */
-		status = acpi_tb_get_primary_table(&address, &table_info);
-		if ((status != AE_OK) && (status != AE_TABLE_NOT_SUPPORTED)) {
-			ACPI_WARNING((AE_INFO,
-				      "%s, while getting table at %8.8X%8.8X",
-				      acpi_format_exception(status),
-				      ACPI_FORMAT_UINT64(address.pointer.
-							 value)));
-		}
-	}
-
-	/* We must have a FADT to continue */
-
-	if (!acpi_gbl_FADT) {
-		ACPI_ERROR((AE_INFO, "No FADT present in RSDT/XSDT"));
-		return_ACPI_STATUS(AE_NO_ACPI_TABLES);
-	}
-
-	/*
-	 * Convert the FADT to a common format.  This allows earlier revisions of
-	 * the table to coexist with newer versions, using common access code.
-	 */
-	status = acpi_tb_convert_table_fadt();
-	if (ACPI_FAILURE(status)) {
-		ACPI_ERROR((AE_INFO,
-			    "Could not convert FADT to internal common format"));
-		return_ACPI_STATUS(status);
-	}
-
-	/* Get the FACS (Pointed to by the FADT) */
-
-	address.pointer.value = acpi_gbl_FADT->xfirmware_ctrl;
-
-	status = acpi_tb_get_secondary_table(&address, FACS_SIG, &table_info);
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status,
-				"Could not get/install the FACS"));
-		return_ACPI_STATUS(status);
-	}
-
-	/*
-	 * Create the common FACS pointer table
-	 * (Contains pointers to the original table)
-	 */
-	status = acpi_tb_build_common_facs(&table_info);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Get/install the DSDT (Pointed to by the FADT) */
-
-	address.pointer.value = acpi_gbl_FADT->Xdsdt;
-
-	status = acpi_tb_get_secondary_table(&address, DSDT_SIG, &table_info);
-	if (ACPI_FAILURE(status)) {
-		ACPI_ERROR((AE_INFO, "Could not get/install the DSDT"));
-		return_ACPI_STATUS(status);
-	}
-
-	/* Set Integer Width (32/64) based upon DSDT revision */
-
-	acpi_ut_set_integer_width(acpi_gbl_DSDT->revision);
-
-	/* Dump the entire DSDT */
-
-	ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
-			  "Hex dump of entire DSDT, size %d (0x%X), Integer width = %d\n",
-			  acpi_gbl_DSDT->length, acpi_gbl_DSDT->length,
-			  acpi_gbl_integer_bit_width));
-
-	ACPI_DUMP_BUFFER(ACPI_CAST_PTR(u8, acpi_gbl_DSDT),
-			 acpi_gbl_DSDT->length);
-
-	/* Always delete the RSDP mapping, we are done with it */
-
-	acpi_tb_delete_tables_by_type(ACPI_TABLE_ID_RSDP);
-	return_ACPI_STATUS(status);
-}
diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
index 1668a23..0e7b121 100644
--- a/drivers/acpi/tables/tbinstal.c
+++ b/drivers/acpi/tables/tbinstal.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,510 +42,498 @@
  */
 
 #include <acpi/acpi.h>
+#include <acpi/acnamesp.h>
 #include <acpi/actables.h>
 
 #define _COMPONENT          ACPI_TABLES
 ACPI_MODULE_NAME("tbinstal")
 
-/* Local prototypes */
-static acpi_status
-acpi_tb_match_signature(char *signature,
-			struct acpi_table_desc *table_info, u8 search_type);
-
-/*******************************************************************************
+/******************************************************************************
  *
- * FUNCTION:    acpi_tb_match_signature
+ * FUNCTION:    acpi_tb_verify_table
  *
- * PARAMETERS:  Signature           - Table signature to match
- *              table_info          - Return data
- *              search_type         - Table type to match (primary/secondary)
+ * PARAMETERS:  table_desc          - table
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Compare signature against the list of "ACPI-subsystem-owned"
- *              tables (DSDT/FADT/SSDT, etc.) Returns the table_type_iD on match.
+ * DESCRIPTION: this function is called to verify and map table
  *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_match_signature(char *signature,
-			struct acpi_table_desc *table_info, u8 search_type)
+ *****************************************************************************/
+acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc)
 {
-	acpi_native_uint i;
+	acpi_status status = AE_OK;
 
-	ACPI_FUNCTION_TRACE(tb_match_signature);
+	ACPI_FUNCTION_TRACE(tb_verify_table);
 
-	/* Search for a signature match among the known table types */
+	/* Map the table if necessary */
 
-	for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) {
-		if (!(acpi_gbl_table_data[i].flags & search_type)) {
-			continue;
+	if (!table_desc->pointer) {
+		if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) ==
+		    ACPI_TABLE_ORIGIN_MAPPED) {
+			table_desc->pointer =
+			    acpi_os_map_memory(table_desc->address,
+					       table_desc->length);
 		}
-
-		if (!ACPI_STRNCMP(signature, acpi_gbl_table_data[i].signature,
-				  acpi_gbl_table_data[i].sig_length)) {
-
-			/* Found a signature match, return index if requested */
-
-			if (table_info) {
-				table_info->type = (u8) i;
-			}
-
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-					  "Table [%4.4s] is an ACPI table consumed by the core subsystem\n",
-					  (char *)acpi_gbl_table_data[i].
-					  signature));
-
-			return_ACPI_STATUS(AE_OK);
+		if (!table_desc->pointer) {
+			return_ACPI_STATUS(AE_NO_MEMORY);
 		}
 	}
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-			  "Table [%4.4s] is not an ACPI table consumed by the core subsystem - ignored\n",
-			  (char *)signature));
+	/* FACS is the odd table, has no standard ACPI header and no checksum */
 
-	return_ACPI_STATUS(AE_TABLE_NOT_SUPPORTED);
+	if (!ACPI_COMPARE_NAME(&table_desc->signature, ACPI_SIG_FACS)) {
+
+		/* Always calculate checksum, ignore bad checksum if requested */
+
+		status =
+		    acpi_tb_verify_checksum(table_desc->pointer,
+					    table_desc->length);
+	}
+
+	return_ACPI_STATUS(status);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_install_table
+ * FUNCTION:    acpi_tb_add_table
  *
- * PARAMETERS:  table_info          - Return value from acpi_tb_get_table_body
+ * PARAMETERS:  table_desc          - Table descriptor
+ *              table_index         - Where the table index is returned
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Install the table into the global data structures.
+ * DESCRIPTION: This function is called to add the ACPI table
  *
  ******************************************************************************/
 
-acpi_status acpi_tb_install_table(struct acpi_table_desc *table_info)
+acpi_status
+acpi_tb_add_table(struct acpi_table_desc *table_desc,
+		  acpi_native_uint * table_index)
 {
-	acpi_status status;
+	acpi_native_uint i;
+	acpi_native_uint length;
+	acpi_status status = AE_OK;
 
-	ACPI_FUNCTION_TRACE(tb_install_table);
+	ACPI_FUNCTION_TRACE(tb_add_table);
 
-	/* Lock tables while installing */
+	if (!table_desc->pointer) {
+		status = acpi_tb_verify_table(table_desc);
+		if (ACPI_FAILURE(status) || !table_desc->pointer) {
+			return_ACPI_STATUS(status);
+		}
+	}
 
-	status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status,
-				"Could not acquire table mutex"));
-		return_ACPI_STATUS(status);
+	/* The table must be either an SSDT or a PSDT */
+
+	if ((!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_PSDT))
+	    &&
+	    (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)))
+	{
+		ACPI_ERROR((AE_INFO,
+			    "Table has invalid signature [%4.4s], must be SSDT or PSDT",
+			    table_desc->pointer->signature));
+		return_ACPI_STATUS(AE_BAD_SIGNATURE);
+	}
+
+	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
+	/* Check if table is already registered */
+
+	for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+		if (!acpi_gbl_root_table_list.tables[i].pointer) {
+			status =
+			    acpi_tb_verify_table(&acpi_gbl_root_table_list.
+						 tables[i]);
+			if (ACPI_FAILURE(status)
+			    || !acpi_gbl_root_table_list.tables[i].pointer) {
+				continue;
+			}
+		}
+
+		length = ACPI_MIN(table_desc->length,
+				  acpi_gbl_root_table_list.tables[i].length);
+		if (ACPI_MEMCMP(table_desc->pointer,
+				acpi_gbl_root_table_list.tables[i].pointer,
+				length)) {
+			continue;
+		}
+
+		/* Table is already registered */
+
+		acpi_tb_delete_table(table_desc);
+		*table_index = i;
+		goto release;
 	}
 
 	/*
-	 * Ignore a table that is already installed. For example, some BIOS
-	 * ASL code will repeatedly attempt to load the same SSDT.
+	 * Add the table to the global table list
 	 */
-	status = acpi_tb_is_table_installed(table_info);
+	status = acpi_tb_store_table(table_desc->address, table_desc->pointer,
+				     table_desc->length, table_desc->flags,
+				     table_index);
 	if (ACPI_FAILURE(status)) {
-		goto unlock_and_exit;
+		goto release;
 	}
 
-	/* Install the table into the global data structure */
+	acpi_tb_print_table_header(table_desc->address, table_desc->pointer);
 
-	status = acpi_tb_init_table_descriptor(table_info->type, table_info);
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status,
-				"Could not install table [%4.4s]",
-				table_info->pointer->signature));
-	}
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s located at %p\n",
-			  acpi_gbl_table_data[table_info->type].name,
-			  table_info->pointer));
-
-      unlock_and_exit:
+      release:
 	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
 	return_ACPI_STATUS(status);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_recognize_table
+ * FUNCTION:    acpi_tb_resize_root_table_list
  *
- * PARAMETERS:  table_info          - Return value from acpi_tb_get_table_body
- *              search_type         - Table type to match (primary/secondary)
+ * PARAMETERS:  None
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Check a table signature for a match against known table types
- *
- * NOTE:  All table pointers are validated as follows:
- *          1) Table pointer must point to valid physical memory
- *          2) Signature must be 4 ASCII chars, even if we don't recognize the
- *             name
- *          3) Table must be readable for length specified in the header
- *          4) Table checksum must be valid (with the exception of the FACS
- *             which has no checksum for some odd reason)
+ * DESCRIPTION: Expand the size of global table array
  *
  ******************************************************************************/
 
-acpi_status
-acpi_tb_recognize_table(struct acpi_table_desc *table_info, u8 search_type)
+acpi_status acpi_tb_resize_root_table_list(void)
 {
-	struct acpi_table_header *table_header;
-	acpi_status status;
+	struct acpi_table_desc *tables;
 
-	ACPI_FUNCTION_TRACE(tb_recognize_table);
+	ACPI_FUNCTION_TRACE(tb_resize_root_table_list);
 
-	/* Ensure that we have a valid table pointer */
+	/* allow_resize flag is a parameter to acpi_initialize_tables */
 
-	table_header = (struct acpi_table_header *)table_info->pointer;
-	if (!table_header) {
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
+	if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) {
+		ACPI_ERROR((AE_INFO,
+			    "Resize of Root Table Array is not allowed"));
+		return_ACPI_STATUS(AE_SUPPORT);
 	}
 
-	/*
-	 * We only "recognize" a limited number of ACPI tables -- namely, the
-	 * ones that are used by the subsystem (DSDT, FADT, etc.)
-	 *
-	 * An AE_TABLE_NOT_SUPPORTED means that the table was not recognized.
-	 * This can be any one of many valid ACPI tables, it just isn't one of
-	 * the tables that is consumed by the core subsystem
-	 */
-	status = acpi_tb_match_signature(table_header->signature,
-					 table_info, search_type);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
+	/* Increase the Table Array size */
 
-	status = acpi_tb_validate_table_header(table_header);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Return the table type and length via the info struct */
-
-	table_info->length = (acpi_size) table_header->length;
-	return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_init_table_descriptor
- *
- * PARAMETERS:  table_type          - The type of the table
- *              table_info          - A table info struct
- *
- * RETURN:      None.
- *
- * DESCRIPTION: Install a table into the global data structs.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_init_table_descriptor(acpi_table_type table_type,
-			      struct acpi_table_desc *table_info)
-{
-	struct acpi_table_list *list_head;
-	struct acpi_table_desc *table_desc;
-	acpi_status status;
-
-	ACPI_FUNCTION_TRACE_U32(tb_init_table_descriptor, table_type);
-
-	/* Allocate a descriptor for this table */
-
-	table_desc = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc));
-	if (!table_desc) {
+	tables = ACPI_ALLOCATE_ZEROED((acpi_gbl_root_table_list.size +
+				       ACPI_ROOT_TABLE_SIZE_INCREMENT)
+				      * sizeof(struct acpi_table_desc));
+	if (!tables) {
+		ACPI_ERROR((AE_INFO,
+			    "Could not allocate new root table array"));
 		return_ACPI_STATUS(AE_NO_MEMORY);
 	}
 
-	/* Get a new owner ID for the table */
+	/* Copy and free the previous table array */
 
-	status = acpi_ut_allocate_owner_id(&table_desc->owner_id);
-	if (ACPI_FAILURE(status)) {
-		goto error_exit1;
-	}
+	if (acpi_gbl_root_table_list.tables) {
+		ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables,
+			    acpi_gbl_root_table_list.size *
+			    sizeof(struct acpi_table_desc));
 
-	/* Install the table into the global data structure */
-
-	list_head = &acpi_gbl_table_lists[table_type];
-
-	/*
-	 * Two major types of tables:  1) Only one instance is allowed.  This
-	 * includes most ACPI tables such as the DSDT.  2) Multiple instances of
-	 * the table are allowed.  This includes SSDT and PSDTs.
-	 */
-	if (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags)) {
-		/*
-		 * Only one table allowed, and a table has alread been installed
-		 * at this location, so return an error.
-		 */
-		if (list_head->next) {
-			status = AE_ALREADY_EXISTS;
-			goto error_exit2;
-		}
-
-		table_desc->next = list_head->next;
-		list_head->next = table_desc;
-
-		if (table_desc->next) {
-			table_desc->next->prev = table_desc;
-		}
-
-		list_head->count++;
-	} else {
-		/*
-		 * Link the new table in to the list of tables of this type.
-		 * Insert at the end of the list, order IS IMPORTANT.
-		 *
-		 * table_desc->Prev & Next are already NULL from calloc()
-		 */
-		list_head->count++;
-
-		if (!list_head->next) {
-			list_head->next = table_desc;
-		} else {
-			table_desc->next = list_head->next;
-
-			while (table_desc->next->next) {
-				table_desc->next = table_desc->next->next;
-			}
-
-			table_desc->next->next = table_desc;
-			table_desc->prev = table_desc->next;
-			table_desc->next = NULL;
+		if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+			ACPI_FREE(acpi_gbl_root_table_list.tables);
 		}
 	}
 
-	/* Finish initialization of the table descriptor */
+	acpi_gbl_root_table_list.tables = tables;
+	acpi_gbl_root_table_list.size += ACPI_ROOT_TABLE_SIZE_INCREMENT;
+	acpi_gbl_root_table_list.flags |= (u8) ACPI_ROOT_ORIGIN_ALLOCATED;
 
-	table_desc->loaded_into_namespace = FALSE;
-	table_desc->type = (u8) table_type;
-	table_desc->pointer = table_info->pointer;
-	table_desc->length = table_info->length;
-	table_desc->allocation = table_info->allocation;
-	table_desc->aml_start = (u8 *) (table_desc->pointer + 1),
-	    table_desc->aml_length = (u32)
-	    (table_desc->length - (u32) sizeof(struct acpi_table_header));
-
-	/*
-	 * Set the appropriate global pointer (if there is one) to point to the
-	 * newly installed table
-	 */
-	if (acpi_gbl_table_data[table_type].global_ptr) {
-		*(acpi_gbl_table_data[table_type].global_ptr) =
-		    table_info->pointer;
-	}
-
-	/* Return Data */
-
-	table_info->owner_id = table_desc->owner_id;
-	table_info->installed_desc = table_desc;
 	return_ACPI_STATUS(AE_OK);
-
-	/* Error exit with cleanup */
-
-      error_exit2:
-
-	acpi_ut_release_owner_id(&table_desc->owner_id);
-
-      error_exit1:
-
-	ACPI_FREE(table_desc);
-	return_ACPI_STATUS(status);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_delete_all_tables
+ * FUNCTION:    acpi_tb_store_table
  *
- * PARAMETERS:  None.
+ * PARAMETERS:  Address             - Table address
+ *              Table               - Table header
+ *              Length              - Table length
+ *              Flags               - flags
  *
- * RETURN:      None.
+ * RETURN:      Status and table index.
+ *
+ * DESCRIPTION: Add an ACPI table to the global table list
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_store_table(acpi_physical_address address,
+		    struct acpi_table_header *table,
+		    u32 length, u8 flags, acpi_native_uint * table_index)
+{
+	acpi_status status = AE_OK;
+
+	/* Ensure that there is room for the table in the Root Table List */
+
+	if (acpi_gbl_root_table_list.count >= acpi_gbl_root_table_list.size) {
+		status = acpi_tb_resize_root_table_list();
+		if (ACPI_FAILURE(status)) {
+			return (status);
+		}
+	}
+
+	/* Initialize added table */
+
+	acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+	    address = address;
+	acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+	    pointer = table;
+	acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].length =
+	    length;
+	acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+	    owner_id = 0;
+	acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].flags =
+	    flags;
+
+	ACPI_MOVE_32_TO_32(&
+			   (acpi_gbl_root_table_list.
+			    tables[acpi_gbl_root_table_list.count].signature),
+			   table->signature);
+
+	*table_index = acpi_gbl_root_table_list.count;
+	acpi_gbl_root_table_list.count++;
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_delete_table
+ *
+ * PARAMETERS:  table_index         - Table index
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Delete one internal ACPI table
+ *
+ ******************************************************************************/
+
+void acpi_tb_delete_table(struct acpi_table_desc *table_desc)
+{
+	/* Table must be mapped or allocated */
+	if (!table_desc->pointer) {
+		return;
+	}
+	switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
+	case ACPI_TABLE_ORIGIN_MAPPED:
+		acpi_os_unmap_memory(table_desc->pointer, table_desc->length);
+		break;
+	case ACPI_TABLE_ORIGIN_ALLOCATED:
+		ACPI_FREE(table_desc->pointer);
+		break;
+	default:;
+	}
+
+	table_desc->pointer = NULL;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_terminate
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
  *
  * DESCRIPTION: Delete all internal ACPI tables
  *
  ******************************************************************************/
 
-void acpi_tb_delete_all_tables(void)
+void acpi_tb_terminate(void)
 {
-	acpi_table_type type;
+	acpi_native_uint i;
+
+	ACPI_FUNCTION_TRACE(tb_terminate);
+
+	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
+	/* Delete the individual tables */
+
+	for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+		acpi_tb_delete_table(&acpi_gbl_root_table_list.tables[i]);
+	}
 
 	/*
-	 * Free memory allocated for ACPI tables
-	 * Memory can either be mapped or allocated
+	 * Delete the root table array if allocated locally. Array cannot be
+	 * mapped, so we don't need to check for that flag.
 	 */
-	for (type = 0; type < (ACPI_TABLE_ID_MAX + 1); type++) {
-		acpi_tb_delete_tables_by_type(type);
+	if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+		ACPI_FREE(acpi_gbl_root_table_list.tables);
 	}
+
+	acpi_gbl_root_table_list.tables = NULL;
+	acpi_gbl_root_table_list.flags = 0;
+	acpi_gbl_root_table_list.count = 0;
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n"));
+	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_delete_tables_by_type
+ * FUNCTION:    acpi_tb_delete_namespace_by_owner
  *
- * PARAMETERS:  Type                - The table type to be deleted
+ * PARAMETERS:  table_index         - Table index
  *
- * RETURN:      None.
+ * RETURN:      None
  *
- * DESCRIPTION: Delete an internal ACPI table
- *              Locks the ACPI table mutex
+ * DESCRIPTION: Delete all namespace objects created when this table was loaded.
  *
  ******************************************************************************/
 
-void acpi_tb_delete_tables_by_type(acpi_table_type type)
+void acpi_tb_delete_namespace_by_owner(acpi_native_uint table_index)
 {
-	struct acpi_table_desc *table_desc;
-	u32 count;
-	u32 i;
+	acpi_owner_id owner_id;
 
-	ACPI_FUNCTION_TRACE_U32(tb_delete_tables_by_type, type);
-
-	if (type > ACPI_TABLE_ID_MAX) {
-		return_VOID;
-	}
-
-	if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_TABLES))) {
+	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+	if (table_index < acpi_gbl_root_table_list.count) {
+		owner_id =
+		    acpi_gbl_root_table_list.tables[table_index].owner_id;
+	} else {
+		(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
 		return;
 	}
 
-	/* Clear the appropriate "typed" global table pointer */
-
-	switch (type) {
-	case ACPI_TABLE_ID_RSDP:
-		acpi_gbl_RSDP = NULL;
-		break;
-
-	case ACPI_TABLE_ID_DSDT:
-		acpi_gbl_DSDT = NULL;
-		break;
-
-	case ACPI_TABLE_ID_FADT:
-		acpi_gbl_FADT = NULL;
-		break;
-
-	case ACPI_TABLE_ID_FACS:
-		acpi_gbl_FACS = NULL;
-		break;
-
-	case ACPI_TABLE_ID_XSDT:
-		acpi_gbl_XSDT = NULL;
-		break;
-
-	case ACPI_TABLE_ID_SSDT:
-	case ACPI_TABLE_ID_PSDT:
-	default:
-		break;
-	}
-
-	/*
-	 * Free the table
-	 * 1) Get the head of the list
-	 */
-	table_desc = acpi_gbl_table_lists[type].next;
-	count = acpi_gbl_table_lists[type].count;
-
-	/*
-	 * 2) Walk the entire list, deleting both the allocated tables
-	 *    and the table descriptors
-	 */
-	for (i = 0; i < count; i++) {
-		table_desc = acpi_tb_uninstall_table(table_desc);
-	}
-
 	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
-	return_VOID;
+	acpi_ns_delete_namespace_by_owner(owner_id);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_delete_single_table
+ * FUNCTION:    acpi_tb_allocate_owner_id
  *
- * PARAMETERS:  table_info          - A table info struct
+ * PARAMETERS:  table_index         - Table index
  *
- * RETURN:      None.
+ * RETURN:      Status
  *
- * DESCRIPTION: Low-level free for a single ACPI table.  Handles cases where
- *              the table was allocated a buffer or was mapped.
+ * DESCRIPTION: Allocates owner_id in table_desc
  *
  ******************************************************************************/
 
-void acpi_tb_delete_single_table(struct acpi_table_desc *table_desc)
+acpi_status acpi_tb_allocate_owner_id(acpi_native_uint table_index)
 {
+	acpi_status status = AE_BAD_PARAMETER;
 
-	/* Must have a valid table descriptor and pointer */
+	ACPI_FUNCTION_TRACE(tb_allocate_owner_id);
 
-	if ((!table_desc) || (!table_desc->pointer)) {
-		return;
+	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+	if (table_index < acpi_gbl_root_table_list.count) {
+		status = acpi_ut_allocate_owner_id
+		    (&(acpi_gbl_root_table_list.tables[table_index].owner_id));
 	}
 
-	/* Valid table, determine type of memory allocation */
-
-	switch (table_desc->allocation) {
-	case ACPI_MEM_NOT_ALLOCATED:
-		break;
-
-	case ACPI_MEM_ALLOCATED:
-
-		ACPI_FREE(table_desc->pointer);
-		break;
-
-	case ACPI_MEM_MAPPED:
-
-		acpi_os_unmap_memory(table_desc->pointer, table_desc->length);
-		break;
-
-	default:
-		break;
-	}
+	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+	return_ACPI_STATUS(status);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_uninstall_table
+ * FUNCTION:    acpi_tb_release_owner_id
  *
- * PARAMETERS:  table_info          - A table info struct
+ * PARAMETERS:  table_index         - Table index
  *
- * RETURN:      Pointer to the next table in the list (of same type)
+ * RETURN:      Status
  *
- * DESCRIPTION: Free the memory associated with an internal ACPI table that
- *              is either installed or has never been installed.
- *              Table mutex should be locked.
+ * DESCRIPTION: Releases owner_id in table_desc
  *
  ******************************************************************************/
 
-struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc
-						*table_desc)
+acpi_status acpi_tb_release_owner_id(acpi_native_uint table_index)
 {
-	struct acpi_table_desc *next_desc;
+	acpi_status status = AE_BAD_PARAMETER;
 
-	ACPI_FUNCTION_TRACE_PTR(tb_uninstall_table, table_desc);
+	ACPI_FUNCTION_TRACE(tb_release_owner_id);
 
-	if (!table_desc) {
-		return_PTR(NULL);
+	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+	if (table_index < acpi_gbl_root_table_list.count) {
+		acpi_ut_release_owner_id(&
+					 (acpi_gbl_root_table_list.
+					  tables[table_index].owner_id));
+		status = AE_OK;
 	}
 
-	/* Unlink the descriptor from the doubly linked list */
+	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+	return_ACPI_STATUS(status);
+}
 
-	if (table_desc->prev) {
-		table_desc->prev->next = table_desc->next;
-	} else {
-		/* Is first on list, update list head */
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_get_owner_id
+ *
+ * PARAMETERS:  table_index         - Table index
+ *              owner_id            - Where the table owner_id is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: returns owner_id for the ACPI table
+ *
+ ******************************************************************************/
 
-		acpi_gbl_table_lists[table_desc->type].next = table_desc->next;
+acpi_status
+acpi_tb_get_owner_id(acpi_native_uint table_index, acpi_owner_id * owner_id)
+{
+	acpi_status status = AE_BAD_PARAMETER;
+
+	ACPI_FUNCTION_TRACE(tb_get_owner_id);
+
+	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+	if (table_index < acpi_gbl_root_table_list.count) {
+		*owner_id =
+		    acpi_gbl_root_table_list.tables[table_index].owner_id;
+		status = AE_OK;
 	}
 
-	if (table_desc->next) {
-		table_desc->next->prev = table_desc->prev;
+	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+	return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_is_table_loaded
+ *
+ * PARAMETERS:  table_index         - Table index
+ *
+ * RETURN:      Table Loaded Flag
+ *
+ ******************************************************************************/
+
+u8 acpi_tb_is_table_loaded(acpi_native_uint table_index)
+{
+	u8 is_loaded = FALSE;
+
+	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+	if (table_index < acpi_gbl_root_table_list.count) {
+		is_loaded = (u8)
+		    (acpi_gbl_root_table_list.tables[table_index].
+		     flags & ACPI_TABLE_IS_LOADED);
 	}
 
-	/* Free the memory allocated for the table itself */
+	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+	return (is_loaded);
+}
 
-	acpi_tb_delete_single_table(table_desc);
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_set_table_loaded_flag
+ *
+ * PARAMETERS:  table_index         - Table index
+ *              is_loaded           - TRUE if table is loaded, FALSE otherwise
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE.
+ *
+ ******************************************************************************/
 
-	/* Free the owner ID associated with this table */
+void acpi_tb_set_table_loaded_flag(acpi_native_uint table_index, u8 is_loaded)
+{
 
-	acpi_ut_release_owner_id(&table_desc->owner_id);
+	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+	if (table_index < acpi_gbl_root_table_list.count) {
+		if (is_loaded) {
+			acpi_gbl_root_table_list.tables[table_index].flags |=
+			    ACPI_TABLE_IS_LOADED;
+		} else {
+			acpi_gbl_root_table_list.tables[table_index].flags &=
+			    ~ACPI_TABLE_IS_LOADED;
+		}
+	}
 
-	/* Free the table descriptor */
-
-	next_desc = table_desc->next;
-	ACPI_FREE(table_desc);
-
-	/* Return pointer to the next descriptor */
-
-	return_PTR(next_desc);
+	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
 }
diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c
deleted file mode 100644
index 86a5fca..0000000
--- a/drivers/acpi/tables/tbrsdt.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbrsdt - ACPI RSDT table utilities
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- *    substantially similar to the "NO WARRANTY" disclaimer below
- *    ("Disclaimer") and any redistribution must be conditioned upon
- *    including a substantially similar Disclaimer requirement for further
- *    binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- *    of any contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT          ACPI_TABLES
-ACPI_MODULE_NAME("tbrsdt")
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_verify_rsdp
- *
- * PARAMETERS:  Address         - RSDP (Pointer to RSDT)
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table)
- *
- ******************************************************************************/
-acpi_status acpi_tb_verify_rsdp(struct acpi_pointer *address)
-{
-	struct acpi_table_desc table_info;
-	acpi_status status;
-	struct rsdp_descriptor *rsdp;
-
-	ACPI_FUNCTION_TRACE(tb_verify_rsdp);
-
-	switch (address->pointer_type) {
-	case ACPI_LOGICAL_POINTER:
-
-		rsdp = address->pointer.logical;
-		break;
-
-	case ACPI_PHYSICAL_POINTER:
-		/*
-		 * Obtain access to the RSDP structure
-		 */
-		status = acpi_os_map_memory(address->pointer.physical,
-					    sizeof(struct rsdp_descriptor),
-					    ACPI_CAST_PTR(void, &rsdp));
-		if (ACPI_FAILURE(status)) {
-			return_ACPI_STATUS(status);
-		}
-		break;
-
-	default:
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-	}
-
-	/* Verify RSDP signature and checksum */
-
-	status = acpi_tb_validate_rsdp(rsdp);
-	if (ACPI_FAILURE(status)) {
-		goto cleanup;
-	}
-
-	/* RSDP is ok. Init the table info */
-
-	table_info.pointer = ACPI_CAST_PTR(struct acpi_table_header, rsdp);
-	table_info.length = sizeof(struct rsdp_descriptor);
-
-	if (address->pointer_type == ACPI_PHYSICAL_POINTER) {
-		table_info.allocation = ACPI_MEM_MAPPED;
-	} else {
-		table_info.allocation = ACPI_MEM_NOT_ALLOCATED;
-	}
-
-	/* Save the table pointers and allocation info */
-
-	status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_RSDP, &table_info);
-	if (ACPI_FAILURE(status)) {
-		goto cleanup;
-	}
-
-	/* Save the RSDP in a global for easy access */
-
-	acpi_gbl_RSDP =
-	    ACPI_CAST_PTR(struct rsdp_descriptor, table_info.pointer);
-	return_ACPI_STATUS(status);
-
-	/* Error exit */
-      cleanup:
-
-	if (acpi_gbl_table_flags & ACPI_PHYSICAL_POINTER) {
-		acpi_os_unmap_memory(rsdp, sizeof(struct rsdp_descriptor));
-	}
-	return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_rsdt_address
- *
- * PARAMETERS:  out_address         - Where the address is returned
- *
- * RETURN:      None, Address
- *
- * DESCRIPTION: Extract the address of either the RSDT or XSDT, depending on the
- *              version of the RSDP and whether the XSDT pointer is valid
- *
- ******************************************************************************/
-
-void acpi_tb_get_rsdt_address(struct acpi_pointer *out_address)
-{
-
-	ACPI_FUNCTION_ENTRY();
-
-	out_address->pointer_type =
-	    acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING;
-
-	/* Use XSDT if it is present */
-
-	if ((acpi_gbl_RSDP->revision >= 2) &&
-	    acpi_gbl_RSDP->xsdt_physical_address) {
-		out_address->pointer.value =
-		    acpi_gbl_RSDP->xsdt_physical_address;
-		acpi_gbl_root_table_type = ACPI_TABLE_TYPE_XSDT;
-	} else {
-		/* No XSDT, use the RSDT */
-
-		out_address->pointer.value =
-		    acpi_gbl_RSDP->rsdt_physical_address;
-		acpi_gbl_root_table_type = ACPI_TABLE_TYPE_RSDT;
-	}
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_validate_rsdt
- *
- * PARAMETERS:  table_ptr       - Addressable pointer to the RSDT.
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Validate signature for the RSDT or XSDT
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr)
-{
-	char *signature;
-
-	ACPI_FUNCTION_ENTRY();
-
-	/* Validate minimum length */
-
-	if (table_ptr->length < sizeof(struct acpi_table_header)) {
-		ACPI_ERROR((AE_INFO,
-			    "RSDT/XSDT length (%X) is smaller than minimum (%zX)",
-			    table_ptr->length,
-			    sizeof(struct acpi_table_header)));
-
-		return (AE_INVALID_TABLE_LENGTH);
-	}
-
-	/* Search for appropriate signature, RSDT or XSDT */
-
-	if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
-		signature = RSDT_SIG;
-	} else {
-		signature = XSDT_SIG;
-	}
-
-	if (!ACPI_COMPARE_NAME(table_ptr->signature, signature)) {
-
-		/* Invalid RSDT or XSDT signature */
-
-		ACPI_ERROR((AE_INFO,
-			    "Invalid signature where RSDP indicates RSDT/XSDT should be located. RSDP:"));
-
-		ACPI_DUMP_BUFFER(acpi_gbl_RSDP, 20);
-
-		ACPI_ERROR((AE_INFO,
-			    "RSDT/XSDT signature at %X is invalid",
-			    acpi_gbl_RSDP->rsdt_physical_address));
-
-		if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
-			ACPI_ERROR((AE_INFO, "Looking for RSDT"));
-		} else {
-			ACPI_ERROR((AE_INFO, "Looking for XSDT"));
-		}
-
-		ACPI_DUMP_BUFFER(ACPI_CAST_PTR(char, table_ptr), 48);
-		return (AE_BAD_SIGNATURE);
-	}
-
-	return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_table_rsdt
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table)
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_get_table_rsdt(void)
-{
-	struct acpi_table_desc table_info;
-	acpi_status status;
-	struct acpi_pointer address;
-
-	ACPI_FUNCTION_TRACE(tb_get_table_rsdt);
-
-	/* Get the RSDT/XSDT via the RSDP */
-
-	acpi_tb_get_rsdt_address(&address);
-
-	table_info.type = ACPI_TABLE_ID_XSDT;
-	status = acpi_tb_get_table(&address, &table_info);
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status,
-				"Could not get the RSDT/XSDT"));
-		return_ACPI_STATUS(status);
-	}
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-			  "RSDP located at %p, points to RSDT physical=%8.8X%8.8X\n",
-			  acpi_gbl_RSDP,
-			  ACPI_FORMAT_UINT64(address.pointer.value)));
-
-	/* Check the RSDT or XSDT signature */
-
-	status = acpi_tb_validate_rsdt(table_info.pointer);
-	if (ACPI_FAILURE(status)) {
-		goto error_cleanup;
-	}
-
-	/* Get the number of tables defined in the RSDT or XSDT */
-
-	acpi_gbl_rsdt_table_count = acpi_tb_get_table_count(acpi_gbl_RSDP,
-							    table_info.pointer);
-
-	/* Convert and/or copy to an XSDT structure */
-
-	status = acpi_tb_convert_to_xsdt(&table_info);
-	if (ACPI_FAILURE(status)) {
-		goto error_cleanup;
-	}
-
-	/* Save the table pointers and allocation info */
-
-	status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_XSDT, &table_info);
-	if (ACPI_FAILURE(status)) {
-		goto error_cleanup;
-	}
-
-	acpi_gbl_XSDT =
-	    ACPI_CAST_PTR(struct xsdt_descriptor, table_info.pointer);
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT));
-	return_ACPI_STATUS(status);
-
-      error_cleanup:
-
-	/* Free table allocated by acpi_tb_get_table */
-
-	acpi_tb_delete_single_table(&table_info);
-
-	return_ACPI_STATUS(status);
-}
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
index 209a401..1da64b4 100644
--- a/drivers/acpi/tables/tbutils.c
+++ b/drivers/acpi/tables/tbutils.c
@@ -1,11 +1,11 @@
 /******************************************************************************
  *
- * Module Name: tbutils - Table manipulation utilities
+ * Module Name: tbutils   - table utilities
  *
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,137 +48,119 @@
 ACPI_MODULE_NAME("tbutils")
 
 /* Local prototypes */
-#ifdef ACPI_OBSOLETE_FUNCTIONS
-acpi_status
-acpi_tb_handle_to_object(u16 table_id, struct acpi_table_desc **table_desc);
-#endif
+static acpi_physical_address
+acpi_tb_get_root_table_entry(u8 * table_entry,
+			     acpi_native_uint table_entry_size);
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_is_table_installed
+ * FUNCTION:    acpi_tb_tables_loaded
  *
- * PARAMETERS:  new_table_desc      - Descriptor for new table being installed
+ * PARAMETERS:  None
  *
- * RETURN:      Status - AE_ALREADY_EXISTS if the table is already installed
+ * RETURN:      TRUE if required ACPI tables are loaded
  *
- * DESCRIPTION: Determine if an ACPI table is already installed
- *
- * MUTEX:       Table data structures should be locked
+ * DESCRIPTION: Determine if the minimum required ACPI tables are present
+ *              (FADT, FACS, DSDT)
  *
  ******************************************************************************/
 
-acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc)
+u8 acpi_tb_tables_loaded(void)
 {
-	struct acpi_table_desc *table_desc;
 
-	ACPI_FUNCTION_TRACE(tb_is_table_installed);
-
-	/* Get the list descriptor and first table descriptor */
-
-	table_desc = acpi_gbl_table_lists[new_table_desc->type].next;
-
-	/* Examine all installed tables of this type */
-
-	while (table_desc) {
-		/*
-		 * If the table lengths match, perform a full bytewise compare. This
-		 * means that we will allow tables with duplicate oem_table_id(s), as
-		 * long as the tables are different in some way.
-		 *
-		 * Checking if the table has been loaded into the namespace means that
-		 * we don't check for duplicate tables during the initial installation
-		 * of tables within the RSDT/XSDT.
-		 */
-		if ((table_desc->loaded_into_namespace) &&
-		    (table_desc->pointer->length ==
-		     new_table_desc->pointer->length)
-		    &&
-		    (!ACPI_MEMCMP
-		     (table_desc->pointer, new_table_desc->pointer,
-		      new_table_desc->pointer->length))) {
-
-			/* Match: this table is already installed */
-
-			ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
-					  "Table [%4.4s] already installed: Rev %X OemTableId [%8.8s]\n",
-					  new_table_desc->pointer->signature,
-					  new_table_desc->pointer->revision,
-					  new_table_desc->pointer->
-					  oem_table_id));
-
-			new_table_desc->owner_id = table_desc->owner_id;
-			new_table_desc->installed_desc = table_desc;
-
-			return_ACPI_STATUS(AE_ALREADY_EXISTS);
-		}
-
-		/* Get next table on the list */
-
-		table_desc = table_desc->next;
+	if (acpi_gbl_root_table_list.count >= 3) {
+		return (TRUE);
 	}
 
-	return_ACPI_STATUS(AE_OK);
+	return (FALSE);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_validate_table_header
+ * FUNCTION:    acpi_tb_print_table_header
  *
- * PARAMETERS:  table_header        - Logical pointer to the table
+ * PARAMETERS:  Address             - Table physical address
+ *              Header              - Table header
  *
- * RETURN:      Status
+ * RETURN:      None
  *
- * DESCRIPTION: Check an ACPI table header for validity
- *
- * NOTE:  Table pointers are validated as follows:
- *          1) Table pointer must point to valid physical memory
- *          2) Signature must be 4 ASCII chars, even if we don't recognize the
- *             name
- *          3) Table must be readable for length specified in the header
- *          4) Table checksum must be valid (with the exception of the FACS
- *              which has no checksum because it contains variable fields)
+ * DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP.
  *
  ******************************************************************************/
 
-acpi_status
-acpi_tb_validate_table_header(struct acpi_table_header *table_header)
+void
+acpi_tb_print_table_header(acpi_physical_address address,
+			   struct acpi_table_header *header)
 {
-	acpi_name signature;
 
-	ACPI_FUNCTION_ENTRY();
+	if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) {
 
-	/* Verify that this is a valid address */
+		/* FACS only has signature and length fields of common table header */
 
-	if (!acpi_os_readable(table_header, sizeof(struct acpi_table_header))) {
-		ACPI_ERROR((AE_INFO,
-			    "Cannot read table header at %p", table_header));
+		ACPI_INFO((AE_INFO, "%4.4s %08lX, %04X",
+			   header->signature, (unsigned long)address,
+			   header->length));
+	} else if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_RSDP)) {
 
-		return (AE_BAD_ADDRESS);
+		/* RSDP has no common fields */
+
+		ACPI_INFO((AE_INFO, "RSDP %08lX, %04X (r%d %6.6s)",
+			   (unsigned long)address,
+			   (ACPI_CAST_PTR(struct acpi_table_rsdp, header)->
+			    revision >
+			    0) ? ACPI_CAST_PTR(struct acpi_table_rsdp,
+					       header)->length : 20,
+			   ACPI_CAST_PTR(struct acpi_table_rsdp,
+					 header)->revision,
+			   ACPI_CAST_PTR(struct acpi_table_rsdp,
+					 header)->oem_id));
+	} else {
+		/* Standard ACPI table with full common header */
+
+		ACPI_INFO((AE_INFO,
+			   "%4.4s %08lX, %04X (r%d %6.6s %8.8s %8X %4.4s %8X)",
+			   header->signature, (unsigned long)address,
+			   header->length, header->revision, header->oem_id,
+			   header->oem_table_id, header->oem_revision,
+			   header->asl_compiler_id,
+			   header->asl_compiler_revision));
 	}
+}
 
-	/* Ensure that the signature is 4 ASCII characters */
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_validate_checksum
+ *
+ * PARAMETERS:  Table               - ACPI table to verify
+ *              Length              - Length of entire table
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns
+ *              exception on bad checksum.
+ *
+ ******************************************************************************/
 
-	ACPI_MOVE_32_TO_32(&signature, table_header->signature);
-	if (!acpi_ut_valid_acpi_name(signature)) {
-		ACPI_ERROR((AE_INFO, "Invalid table signature 0x%8.8X",
-			    signature));
+acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length)
+{
+	u8 checksum;
 
-		ACPI_DUMP_BUFFER(table_header,
-				 sizeof(struct acpi_table_header));
-		return (AE_BAD_SIGNATURE);
-	}
+	/* Compute the checksum on the table */
 
-	/* Validate the table length */
+	checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, table), length);
 
-	if (table_header->length < sizeof(struct acpi_table_header)) {
-		ACPI_ERROR((AE_INFO,
-			    "Invalid length 0x%X in table with signature %4.4s",
-			    (u32) table_header->length,
-			    ACPI_CAST_PTR(char, &signature)));
+	/* Checksum ok? (should be zero) */
 
-		ACPI_DUMP_BUFFER(table_header,
-				 sizeof(struct acpi_table_header));
-		return (AE_BAD_HEADER);
+	if (checksum) {
+		ACPI_WARNING((AE_INFO,
+			      "Incorrect checksum in table [%4.4s] -  %2.2X, should be %2.2X",
+			      table->signature, table->checksum,
+			      (u8) (table->checksum - checksum)));
+
+#if (ACPI_CHECKSUM_ABORT)
+
+		return (AE_BAD_CHECKSUM);
+#endif
 	}
 
 	return (AE_OK);
@@ -186,157 +168,320 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_sum_table
+ * FUNCTION:    acpi_tb_checksum
  *
- * PARAMETERS:  Buffer              - Buffer to sum
- *              Length              - Size of the buffer
+ * PARAMETERS:  Buffer          - Pointer to memory region to be checked
+ *              Length          - Length of this memory region
  *
- * RETURN:      8 bit sum of buffer
+ * RETURN:      Checksum (u8)
  *
- * DESCRIPTION: Computes an 8 bit sum of the buffer(length) and returns it.
+ * DESCRIPTION: Calculates circular checksum of memory region.
  *
  ******************************************************************************/
 
-u8 acpi_tb_sum_table(void *buffer, u32 length)
+u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length)
 {
-	acpi_native_uint i;
 	u8 sum = 0;
+	u8 *end = buffer + length;
 
-	if (!buffer || !length) {
-		return (0);
+	while (buffer < end) {
+		sum = (u8) (sum + *(buffer++));
 	}
 
-	for (i = 0; i < length; i++) {
-		sum = (u8) (sum + ((u8 *) buffer)[i]);
-	}
-	return (sum);
+	return sum;
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_generate_checksum
+ * FUNCTION:    acpi_tb_install_table
  *
- * PARAMETERS:  Table               - Pointer to a valid ACPI table (with a
- *                                    standard ACPI header)
+ * PARAMETERS:  Address                 - Physical address of DSDT or FACS
+ *              Flags                   - Flags
+ *              Signature               - Table signature, NULL if no need to
+ *                                        match
+ *              table_index             - Index into root table array
  *
- * RETURN:      8 bit checksum of buffer
+ * RETURN:      None
  *
- * DESCRIPTION: Computes an 8 bit checksum of the table.
+ * DESCRIPTION: Install an ACPI table into the global data structure.
  *
  ******************************************************************************/
 
-u8 acpi_tb_generate_checksum(struct acpi_table_header * table)
+void
+acpi_tb_install_table(acpi_physical_address address,
+		      u8 flags, char *signature, acpi_native_uint table_index)
 {
-	u8 checksum;
+	struct acpi_table_header *table;
 
-	/* Sum the entire table as-is */
-
-	checksum = acpi_tb_sum_table(table, table->length);
-
-	/* Subtract off the existing checksum value in the table */
-
-	checksum = (u8) (checksum - table->checksum);
-
-	/* Compute the final checksum */
-
-	checksum = (u8) (0 - checksum);
-	return (checksum);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_set_checksum
- *
- * PARAMETERS:  Table               - Pointer to a valid ACPI table (with a
- *                                    standard ACPI header)
- *
- * RETURN:      None. Sets the table checksum field
- *
- * DESCRIPTION: Computes an 8 bit checksum of the table and inserts the
- *              checksum into the table header.
- *
- ******************************************************************************/
-
-void acpi_tb_set_checksum(struct acpi_table_header *table)
-{
-
-	table->checksum = acpi_tb_generate_checksum(table);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_verify_table_checksum
- *
- * PARAMETERS:  *table_header           - ACPI table to verify
- *
- * RETURN:      8 bit checksum of table
- *
- * DESCRIPTION: Generates an 8 bit checksum of table and returns and compares
- *              it to the existing checksum value.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_verify_table_checksum(struct acpi_table_header *table_header)
-{
-	u8 checksum;
-
-	ACPI_FUNCTION_TRACE(tb_verify_table_checksum);
-
-	/* Compute the checksum on the table */
-
-	checksum = acpi_tb_generate_checksum(table_header);
-
-	/* Checksum ok? */
-
-	if (checksum == table_header->checksum) {
-		return_ACPI_STATUS(AE_OK);
+	if (!address) {
+		ACPI_ERROR((AE_INFO,
+			    "Null physical address for ACPI table [%s]",
+			    signature));
+		return;
 	}
 
-	ACPI_WARNING((AE_INFO,
-		      "Incorrect checksum in table [%4.4s] - is %2.2X, should be %2.2X",
-		      table_header->signature, table_header->checksum,
-		      checksum));
+	/* Map just the table header */
 
-	return_ACPI_STATUS(AE_BAD_CHECKSUM);
+	table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+	if (!table) {
+		return;
+	}
+
+	/* If a particular signature is expected, signature must match */
+
+	if (signature && !ACPI_COMPARE_NAME(table->signature, signature)) {
+		ACPI_ERROR((AE_INFO,
+			    "Invalid signature 0x%X for ACPI table [%s]",
+			    *ACPI_CAST_PTR(u32, table->signature), signature));
+		goto unmap_and_exit;
+	}
+
+	/* Initialize the table entry */
+
+	acpi_gbl_root_table_list.tables[table_index].address = address;
+	acpi_gbl_root_table_list.tables[table_index].length = table->length;
+	acpi_gbl_root_table_list.tables[table_index].flags = flags;
+
+	ACPI_MOVE_32_TO_32(&
+			   (acpi_gbl_root_table_list.tables[table_index].
+			    signature), table->signature);
+
+	acpi_tb_print_table_header(address, table);
+
+	if (table_index == ACPI_TABLE_INDEX_DSDT) {
+
+		/* Global integer width is based upon revision of the DSDT */
+
+		acpi_ut_set_integer_width(table->revision);
+	}
+
+      unmap_and_exit:
+	acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
 }
 
-#ifdef ACPI_OBSOLETE_FUNCTIONS
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_handle_to_object
+ * FUNCTION:    acpi_tb_get_root_table_entry
  *
- * PARAMETERS:  table_id            - Id for which the function is searching
- *              table_desc          - Pointer to return the matching table
- *                                      descriptor.
+ * PARAMETERS:  table_entry         - Pointer to the RSDT/XSDT table entry
+ *              table_entry_size    - sizeof 32 or 64 (RSDT or XSDT)
  *
- * RETURN:      Search the tables to find one with a matching table_id and
- *              return a pointer to that table descriptor.
+ * RETURN:      Physical address extracted from the root table
+ *
+ * DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on
+ *              both 32-bit and 64-bit platforms
+ *
+ * NOTE:        acpi_physical_address is 32-bit on 32-bit platforms, 64-bit on
+ *              64-bit platforms.
  *
  ******************************************************************************/
 
-acpi_status
-acpi_tb_handle_to_object(u16 table_id,
-			 struct acpi_table_desc **return_table_desc)
+static acpi_physical_address
+acpi_tb_get_root_table_entry(u8 * table_entry,
+			     acpi_native_uint table_entry_size)
 {
-	u32 i;
-	struct acpi_table_desc *table_desc;
+	u64 address64;
 
-	ACPI_FUNCTION_NAME(tb_handle_to_object);
+	/*
+	 * Get the table physical address (32-bit for RSDT, 64-bit for XSDT):
+	 * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT
+	 */
+	if (table_entry_size == sizeof(u32)) {
+		/*
+		 * 32-bit platform, RSDT: Return 32-bit table entry
+		 * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return
+		 */
+		return ((acpi_physical_address)
+			(*ACPI_CAST_PTR(u32, table_entry)));
+	} else {
+		/*
+		 * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return
+		 * 64-bit platform, XSDT: Move (unaligned) 64-bit to local, return 64-bit
+		 */
+		ACPI_MOVE_64_TO_64(&address64, table_entry);
 
-	for (i = 0; i < ACPI_TABLE_MAX; i++) {
-		table_desc = acpi_gbl_table_lists[i].next;
-		while (table_desc) {
-			if (table_desc->table_id == table_id) {
-				*return_table_desc = table_desc;
-				return (AE_OK);
+#if ACPI_MACHINE_WIDTH == 32
+		if (address64 > ACPI_UINT32_MAX) {
+
+			/* Will truncate 64-bit address to 32 bits, issue warning */
+
+			ACPI_WARNING((AE_INFO,
+				      "64-bit Physical Address in XSDT is too large (%8.8X%8.8X), truncating",
+				      ACPI_FORMAT_UINT64(address64)));
+		}
+#endif
+		return ((acpi_physical_address) (address64));
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_parse_root_table
+ *
+ * PARAMETERS:  Rsdp                    - Pointer to the RSDP
+ *              Flags                   - Flags
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: This function is called to parse the Root System Description
+ *              Table (RSDT or XSDT)
+ *
+ * NOTE:        Tables are mapped (not copied) for efficiency. The FACS must
+ *              be mapped and cannot be copied because it contains the actual
+ *              memory location of the ACPI Global Lock.
+ *
+ ******************************************************************************/
+
+acpi_status __init
+acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
+{
+	struct acpi_table_rsdp *rsdp;
+	acpi_native_uint table_entry_size;
+	acpi_native_uint i;
+	u32 table_count;
+	struct acpi_table_header *table;
+	acpi_physical_address address;
+	u32 length;
+	u8 *table_entry;
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(tb_parse_root_table);
+
+	/*
+	 * Map the entire RSDP and extract the address of the RSDT or XSDT
+	 */
+	rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp));
+	if (!rsdp) {
+		return_ACPI_STATUS(AE_NO_MEMORY);
+	}
+
+	acpi_tb_print_table_header(rsdp_address,
+				   ACPI_CAST_PTR(struct acpi_table_header,
+						 rsdp));
+
+	/* Differentiate between RSDT and XSDT root tables */
+
+	if (rsdp->revision > 1 && rsdp->xsdt_physical_address) {
+		/*
+		 * Root table is an XSDT (64-bit physical addresses). We must use the
+		 * XSDT if the revision is > 1 and the XSDT pointer is present, as per
+		 * the ACPI specification.
+		 */
+		address = (acpi_physical_address) rsdp->xsdt_physical_address;
+		table_entry_size = sizeof(u64);
+	} else {
+		/* Root table is an RSDT (32-bit physical addresses) */
+
+		address = (acpi_physical_address) rsdp->rsdt_physical_address;
+		table_entry_size = sizeof(u32);
+	}
+
+	/*
+	 * It is not possible to map more than one entry in some environments,
+	 * so unmap the RSDP here before mapping other tables
+	 */
+	acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
+
+	/* Map the RSDT/XSDT table header to get the full table length */
+
+	table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+	if (!table) {
+		return_ACPI_STATUS(AE_NO_MEMORY);
+	}
+
+	acpi_tb_print_table_header(address, table);
+
+	/* Get the length of the full table, verify length and map entire table */
+
+	length = table->length;
+	acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
+
+	if (length < sizeof(struct acpi_table_header)) {
+		ACPI_ERROR((AE_INFO, "Invalid length 0x%X in RSDT/XSDT",
+			    length));
+		return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
+	}
+
+	table = acpi_os_map_memory(address, length);
+	if (!table) {
+		return_ACPI_STATUS(AE_NO_MEMORY);
+	}
+
+	/* Validate the root table checksum */
+
+	status = acpi_tb_verify_checksum(table, length);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_unmap_memory(table, length);
+		return_ACPI_STATUS(status);
+	}
+
+	/* Calculate the number of tables described in the root table */
+
+	table_count =
+	    (u32) ((table->length -
+		    sizeof(struct acpi_table_header)) / table_entry_size);
+
+	/*
+	 * First two entries in the table array are reserved for the DSDT and FACS,
+	 * which are not actually present in the RSDT/XSDT - they come from the FADT
+	 */
+	table_entry =
+	    ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
+	acpi_gbl_root_table_list.count = 2;
+
+	/*
+	 * Initialize the root table array from the RSDT/XSDT
+	 */
+	for (i = 0; i < table_count; i++) {
+		if (acpi_gbl_root_table_list.count >=
+		    acpi_gbl_root_table_list.size) {
+
+			/* There is no more room in the root table array, attempt resize */
+
+			status = acpi_tb_resize_root_table_list();
+			if (ACPI_FAILURE(status)) {
+				ACPI_WARNING((AE_INFO,
+					      "Truncating %u table entries!",
+					      (unsigned)
+					      (acpi_gbl_root_table_list.size -
+					       acpi_gbl_root_table_list.
+					       count)));
+				break;
 			}
+		}
 
-			table_desc = table_desc->next;
+		/* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */
+
+		acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+		    address =
+		    acpi_tb_get_root_table_entry(table_entry, table_entry_size);
+
+		table_entry += table_entry_size;
+		acpi_gbl_root_table_list.count++;
+	}
+
+	/*
+	 * It is not possible to map more than one entry in some environments,
+	 * so unmap the root table here before mapping other tables
+	 */
+	acpi_os_unmap_memory(table, length);
+
+	/*
+	 * Complete the initialization of the root table array by examining
+	 * the header of each table
+	 */
+	for (i = 2; i < acpi_gbl_root_table_list.count; i++) {
+		acpi_tb_install_table(acpi_gbl_root_table_list.tables[i].
+				      address, flags, NULL, i);
+
+		/* Special case for FADT - get the DSDT and FACS */
+
+		if (ACPI_COMPARE_NAME
+		    (&acpi_gbl_root_table_list.tables[i].signature,
+		     ACPI_SIG_FADT)) {
+			acpi_tb_parse_fadt(i, flags);
 		}
 	}
 
-	ACPI_ERROR((AE_INFO, "TableId=%X does not exist", table_id));
-	return (AE_BAD_PARAMETER);
+	return_ACPI_STATUS(AE_OK);
 }
-#endif
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
index 5ba9303..807978d 100644
--- a/drivers/acpi/tables/tbxface.c
+++ b/drivers/acpi/tables/tbxface.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -49,80 +49,158 @@
 #define _COMPONENT          ACPI_TABLES
 ACPI_MODULE_NAME("tbxface")
 
+/* Local prototypes */
+static acpi_status acpi_tb_load_namespace(void);
+
 /*******************************************************************************
  *
- * FUNCTION:    acpi_load_tables
+ * FUNCTION:    acpi_allocate_root_table
+ *
+ * PARAMETERS:  initial_table_count - Size of initial_table_array, in number of
+ *                                    struct acpi_table_desc structures
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Allocate a root table array. Used by i_aSL compiler and
+ *              acpi_initialize_tables.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_allocate_root_table(u32 initial_table_count)
+{
+
+	acpi_gbl_root_table_list.size = initial_table_count;
+	acpi_gbl_root_table_list.flags = ACPI_ROOT_ALLOW_RESIZE;
+
+	return (acpi_tb_resize_root_table_list());
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_initialize_tables
+ *
+ * PARAMETERS:  initial_table_array - Pointer to an array of pre-allocated
+ *                                    struct acpi_table_desc structures. If NULL, the
+ *                                    array is dynamically allocated.
+ *              initial_table_count - Size of initial_table_array, in number of
+ *                                    struct acpi_table_desc structures
+ *              allow_realloc       - Flag to tell Table Manager if resize of
+ *                                    pre-allocated array is allowed. Ignored
+ *                                    if initial_table_array is NULL.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Initialize the table manager, get the RSDP and RSDT/XSDT.
+ *
+ * NOTE:        Allows static allocation of the initial table array in order
+ *              to avoid the use of dynamic memory in confined environments
+ *              such as the kernel boot sequence where it may not be available.
+ *
+ *              If the host OS memory managers are initialized, use NULL for
+ *              initial_table_array, and the table will be dynamically allocated.
+ *
+ ******************************************************************************/
+
+acpi_status __init
+acpi_initialize_tables(struct acpi_table_desc * initial_table_array,
+		       u32 initial_table_count, u8 allow_resize)
+{
+	acpi_physical_address rsdp_address;
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(acpi_initialize_tables);
+
+	/*
+	 * Set up the Root Table Array
+	 * Allocate the table array if requested
+	 */
+	if (!initial_table_array) {
+		status = acpi_allocate_root_table(initial_table_count);
+		if (ACPI_FAILURE(status)) {
+			return_ACPI_STATUS(status);
+		}
+	} else {
+		/* Root Table Array has been statically allocated by the host */
+
+		ACPI_MEMSET(initial_table_array, 0,
+			    initial_table_count *
+			    sizeof(struct acpi_table_desc));
+
+		acpi_gbl_root_table_list.tables = initial_table_array;
+		acpi_gbl_root_table_list.size = initial_table_count;
+		acpi_gbl_root_table_list.flags = ACPI_ROOT_ORIGIN_UNKNOWN;
+		if (allow_resize) {
+			acpi_gbl_root_table_list.flags |=
+			    ACPI_ROOT_ALLOW_RESIZE;
+		}
+	}
+
+	/* Get the address of the RSDP */
+
+	rsdp_address = acpi_os_get_root_pointer();
+	if (!rsdp_address) {
+		return_ACPI_STATUS(AE_NOT_FOUND);
+	}
+
+	/*
+	 * Get the root table (RSDT or XSDT) and extract all entries to the local
+	 * Root Table Array. This array contains the information of the RSDT/XSDT
+	 * in a common, more useable format.
+	 */
+	status =
+	    acpi_tb_parse_root_table(rsdp_address, ACPI_TABLE_ORIGIN_MAPPED);
+	return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_reallocate_root_table
  *
  * PARAMETERS:  None
  *
  * RETURN:      Status
  *
- * DESCRIPTION: This function is called to load the ACPI tables from the
- *              provided RSDT
+ * DESCRIPTION: Reallocate Root Table List into dynamic memory. Copies the
+ *              root list from the previously provided scratch area. Should
+ *              be called once dynamic memory allocation is available in the
+ *              kernel
  *
  ******************************************************************************/
-acpi_status acpi_load_tables(void)
+acpi_status acpi_reallocate_root_table(void)
 {
-	struct acpi_pointer rsdp_address;
-	acpi_status status;
+	struct acpi_table_desc *tables;
+	acpi_size new_size;
 
-	ACPI_FUNCTION_TRACE(acpi_load_tables);
+	ACPI_FUNCTION_TRACE(acpi_reallocate_root_table);
 
-	/* Get the RSDP */
-
-	status = acpi_os_get_root_pointer(ACPI_LOGICAL_ADDRESSING,
-					  &rsdp_address);
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "Could not get the RSDP"));
-		goto error_exit;
+	/*
+	 * Only reallocate the root table if the host provided a static buffer
+	 * for the table array in the call to acpi_initialize_tables.
+	 */
+	if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+		return_ACPI_STATUS(AE_SUPPORT);
 	}
 
-	/* Map and validate the RSDP */
+	new_size =
+	    (acpi_gbl_root_table_list.count +
+	     ACPI_ROOT_TABLE_SIZE_INCREMENT) * sizeof(struct acpi_table_desc);
 
-	acpi_gbl_table_flags = rsdp_address.pointer_type;
+	/* Create new array and copy the old array */
 
-	status = acpi_tb_verify_rsdp(&rsdp_address);
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "During RSDP validation"));
-		goto error_exit;
+	tables = ACPI_ALLOCATE_ZEROED(new_size);
+	if (!tables) {
+		return_ACPI_STATUS(AE_NO_MEMORY);
 	}
 
-	/* Get the RSDT via the RSDP */
+	ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, new_size);
 
-	status = acpi_tb_get_table_rsdt();
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "Could not load RSDT"));
-		goto error_exit;
-	}
-
-	/* Now get the tables needed by this subsystem (FADT, DSDT, etc.) */
-
-	status = acpi_tb_get_required_tables();
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status,
-				"Could not get all required tables (DSDT/FADT/FACS)"));
-		goto error_exit;
-	}
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n"));
-
-	/* Load the namespace from the tables */
-
-	status = acpi_ns_load_namespace();
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "Could not load namespace"));
-		goto error_exit;
-	}
+	acpi_gbl_root_table_list.size = acpi_gbl_root_table_list.count;
+	acpi_gbl_root_table_list.tables = tables;
+	acpi_gbl_root_table_list.flags =
+	    ACPI_ROOT_ORIGIN_ALLOCATED | ACPI_ROOT_ALLOW_RESIZE;
 
 	return_ACPI_STATUS(AE_OK);
-
-      error_exit:
-	ACPI_EXCEPTION((AE_INFO, status, "Could not load tables"));
-	return_ACPI_STATUS(status);
 }
-
-ACPI_EXPORT_SYMBOL(acpi_load_tables)
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_load_table
@@ -141,342 +219,405 @@
 acpi_status acpi_load_table(struct acpi_table_header *table_ptr)
 {
 	acpi_status status;
-	struct acpi_table_desc table_info;
-	struct acpi_pointer address;
+	acpi_native_uint table_index;
+	struct acpi_table_desc table_desc;
 
-	ACPI_FUNCTION_TRACE(acpi_load_table);
+	if (!table_ptr)
+		return AE_BAD_PARAMETER;
 
-	if (!table_ptr) {
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-	}
+	ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc));
+	table_desc.pointer = table_ptr;
+	table_desc.length = table_ptr->length;
+	table_desc.flags = ACPI_TABLE_ORIGIN_UNKNOWN;
 
-	/* Copy the table to a local buffer */
-
-	address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING;
-	address.pointer.logical = table_ptr;
-
-	status = acpi_tb_get_table_body(&address, table_ptr, &table_info);
+	/*
+	 * Install the new table into the local data structures
+	 */
+	status = acpi_tb_add_table(&table_desc, &table_index);
 	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
+		return status;
 	}
-
-	/* Check signature for a valid table type */
-
-	status = acpi_tb_recognize_table(&table_info, ACPI_TABLE_ALL);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Install the new table into the local data structures */
-
-	status = acpi_tb_install_table(&table_info);
-	if (ACPI_FAILURE(status)) {
-		if (status == AE_ALREADY_EXISTS) {
-
-			/* Table already exists, no error */
-
-			status = AE_OK;
-		}
-
-		/* Free table allocated by acpi_tb_get_table_body */
-
-		acpi_tb_delete_single_table(&table_info);
-		return_ACPI_STATUS(status);
-	}
-
-	/* Convert the table to common format if necessary */
-
-	switch (table_info.type) {
-	case ACPI_TABLE_ID_FADT:
-
-		status = acpi_tb_convert_table_fadt();
-		break;
-
-	case ACPI_TABLE_ID_FACS:
-
-		status = acpi_tb_build_common_facs(&table_info);
-		break;
-
-	default:
-		/* Load table into namespace if it contains executable AML */
-
-		status =
-		    acpi_ns_load_table(table_info.installed_desc,
-				       acpi_gbl_root_node);
-		break;
-	}
-
-	if (ACPI_FAILURE(status)) {
-
-		/* Uninstall table and free the buffer */
-
-		(void)acpi_tb_uninstall_table(table_info.installed_desc);
-	}
-
-	return_ACPI_STATUS(status);
+	status = acpi_ns_load_table(table_index, acpi_gbl_root_node);
+	return status;
 }
 
 ACPI_EXPORT_SYMBOL(acpi_load_table)
 
-/*******************************************************************************
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_get_table_header
+ *
+ * PARAMETERS:  Signature           - ACPI signature of needed table
+ *              Instance            - Which instance (for SSDTs)
+ *              out_table_header    - The pointer to the table header to fill
+ *
+ * RETURN:      Status and pointer to mapped table header
+ *
+ * DESCRIPTION: Finds an ACPI table header.
+ *
+ * NOTE:        Caller is responsible in unmapping the header with
+ *              acpi_os_unmap_memory
+ *
+ *****************************************************************************/
+acpi_status
+acpi_get_table_header(char *signature,
+		      acpi_native_uint instance,
+		      struct acpi_table_header *out_table_header)
+{
+	acpi_native_uint i;
+	acpi_native_uint j;
+	struct acpi_table_header *header;
+
+	/* Parameter validation */
+
+	if (!signature || !out_table_header) {
+		return (AE_BAD_PARAMETER);
+	}
+
+	/*
+	 * Walk the root table list
+	 */
+	for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) {
+		if (!ACPI_COMPARE_NAME
+		    (&(acpi_gbl_root_table_list.tables[i].signature),
+		     signature)) {
+			continue;
+		}
+
+		if (++j < instance) {
+			continue;
+		}
+
+		if (!acpi_gbl_root_table_list.tables[i].pointer) {
+			if ((acpi_gbl_root_table_list.tables[i].
+			     flags & ACPI_TABLE_ORIGIN_MASK) ==
+			    ACPI_TABLE_ORIGIN_MAPPED) {
+				header =
+				    acpi_os_map_memory(acpi_gbl_root_table_list.
+						       tables[i].address,
+						       sizeof(struct
+							      acpi_table_header));
+				if (!header) {
+					return AE_NO_MEMORY;
+				}
+				ACPI_MEMCPY(out_table_header, header,
+					    sizeof(struct acpi_table_header));
+				acpi_os_unmap_memory(header,
+						     sizeof(struct
+							    acpi_table_header));
+			} else {
+				return AE_NOT_FOUND;
+			}
+		} else {
+			ACPI_MEMCPY(out_table_header,
+				    acpi_gbl_root_table_list.tables[i].pointer,
+				    sizeof(struct acpi_table_header));
+		}
+		return (AE_OK);
+	}
+
+	return (AE_NOT_FOUND);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_get_table_header)
+
+
+/******************************************************************************
  *
  * FUNCTION:    acpi_unload_table_id
  *
- * PARAMETERS:  table_type    - Type of table to be unloaded
- *              id            - Owner ID of the table to be removed.
+ * PARAMETERS:  id            - Owner ID of the table to be removed.
  *
  * RETURN:      Status
  *
  * DESCRIPTION: This routine is used to force the unload of a table (by id)
  *
  ******************************************************************************/
-acpi_status acpi_unload_table_id(acpi_table_type table_type, acpi_owner_id id)
+acpi_status acpi_unload_table_id(acpi_owner_id id)
 {
-	struct acpi_table_desc *table_desc;
-	acpi_status status;
+	int i;
+	acpi_status status = AE_NOT_EXIST;
 
 	ACPI_FUNCTION_TRACE(acpi_unload_table);
 
-	/* Parameter validation */
-	if (table_type > ACPI_TABLE_ID_MAX)
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-
 	/* Find table from the requested type list */
-	table_desc = acpi_gbl_table_lists[table_type].next;
-	while (table_desc && table_desc->owner_id != id)
-		table_desc = table_desc->next;
-
-	if (!table_desc)
-		return_ACPI_STATUS(AE_NOT_EXIST);
-
-	/*
-	 * Delete all namespace objects owned by this table. Note that these
-	 * objects can appear anywhere in the namespace by virtue of the AML
-	 * "Scope" operator. Thus, we need to track ownership by an ID, not
-	 * simply a position within the hierarchy
-	 */
-	acpi_ns_delete_namespace_by_owner(table_desc->owner_id);
-
-	status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
-	if (ACPI_FAILURE(status))
-		return_ACPI_STATUS(status);
-
-	(void)acpi_tb_uninstall_table(table_desc);
-
-	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
-
-	return_ACPI_STATUS(AE_OK);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_unload_table_id)
-
-#ifdef ACPI_FUTURE_USAGE
-/*******************************************************************************
- *
- * FUNCTION:    acpi_unload_table
- *
- * PARAMETERS:  table_type    - Type of table to be unloaded
- *
- * RETURN:      Status
- *
- * DESCRIPTION: This routine is used to force the unload of a table
- *
- ******************************************************************************/
-acpi_status acpi_unload_table(acpi_table_type table_type)
-{
-	struct acpi_table_desc *table_desc;
-
-	ACPI_FUNCTION_TRACE(acpi_unload_table);
-
-	/* Parameter validation */
-
-	if (table_type > ACPI_TABLE_ID_MAX) {
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-	}
-
-	/* Find all tables of the requested type */
-
-	table_desc = acpi_gbl_table_lists[table_type].next;
-	if (!table_desc) {
-		return_ACPI_STATUS(AE_NOT_EXIST);
-	}
-
-	while (table_desc) {
+	for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+		if (id != acpi_gbl_root_table_list.tables[i].owner_id) {
+			continue;
+		}
 		/*
-		 * Delete all namespace objects owned by this table. Note that these
-		 * objects can appear anywhere in the namespace by virtue of the AML
-		 * "Scope" operator. Thus, we need to track ownership by an ID, not
-		 * simply a position within the hierarchy
-		 */
-		acpi_ns_delete_namespace_by_owner(table_desc->owner_id);
-		table_desc = table_desc->next;
+		* Delete all namespace objects owned by this table. Note that these
+		* objects can appear anywhere in the namespace by virtue of the AML
+		* "Scope" operator. Thus, we need to track ownership by an ID, not
+		* simply a position within the hierarchy
+		*/
+		acpi_tb_delete_namespace_by_owner(i);
+		acpi_tb_release_owner_id(i);
+		acpi_tb_set_table_loaded_flag(i, FALSE);
 	}
-
-	/* Delete (or unmap) all tables of this type */
-
-	acpi_tb_delete_tables_by_type(table_type);
-	return_ACPI_STATUS(AE_OK);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_unload_table)
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_get_table_header
- *
- * PARAMETERS:  table_type      - one of the defined table types
- *              Instance        - the non zero instance of the table, allows
- *                                support for multiple tables of the same type
- *                                see acpi_gbl_acpi_table_flag
- *              out_table_header - pointer to the struct acpi_table_header if successful
- *
- * DESCRIPTION: This function is called to get an ACPI table header. The caller
- *              supplies an pointer to a data area sufficient to contain an ACPI
- *              struct acpi_table_header structure.
- *
- *              The header contains a length field that can be used to determine
- *              the size of the buffer needed to contain the entire table. This
- *              function is not valid for the RSD PTR table since it does not
- *              have a standard header and is fixed length.
- *
- ******************************************************************************/
-acpi_status
-acpi_get_table_header(acpi_table_type table_type,
-		      u32 instance, struct acpi_table_header *out_table_header)
-{
-	struct acpi_table_header *tbl_ptr;
-	acpi_status status;
-
-	ACPI_FUNCTION_TRACE(acpi_get_table_header);
-
-	if ((instance == 0) ||
-	    (table_type == ACPI_TABLE_ID_RSDP) || (!out_table_header)) {
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-	}
-
-	/* Check the table type and instance */
-
-	if ((table_type > ACPI_TABLE_ID_MAX) ||
-	    (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) &&
-	     instance > 1)) {
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-	}
-
-	/* Get a pointer to the entire table */
-
-	status = acpi_tb_get_table_ptr(table_type, instance, &tbl_ptr);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* The function will return a NULL pointer if the table is not loaded */
-
-	if (tbl_ptr == NULL) {
-		return_ACPI_STATUS(AE_NOT_EXIST);
-	}
-
-	/* Copy the header to the caller's buffer */
-
-	ACPI_MEMCPY(ACPI_CAST_PTR(void, out_table_header),
-		    ACPI_CAST_PTR(void, tbl_ptr),
-		    sizeof(struct acpi_table_header));
-
 	return_ACPI_STATUS(status);
 }
 
-ACPI_EXPORT_SYMBOL(acpi_get_table_header)
-#endif				/*  ACPI_FUTURE_USAGE  */
+ACPI_EXPORT_SYMBOL(acpi_unload_table_id)
 
 /*******************************************************************************
  *
  * FUNCTION:    acpi_get_table
  *
- * PARAMETERS:  table_type      - one of the defined table types
- *              Instance        - the non zero instance of the table, allows
- *                                support for multiple tables of the same type
- *                                see acpi_gbl_acpi_table_flag
- *              ret_buffer      - pointer to a structure containing a buffer to
- *                                receive the table
+ * PARAMETERS:  Signature           - ACPI signature of needed table
+ *              Instance            - Which instance (for SSDTs)
+ *              out_table           - Where the pointer to the table is returned
  *
- * RETURN:      Status
+ * RETURN:      Status and pointer to table
  *
- * DESCRIPTION: This function is called to get an ACPI table. The caller
- *              supplies an out_buffer large enough to contain the entire ACPI
- *              table. The caller should call the acpi_get_table_header function
- *              first to determine the buffer size needed. Upon completion
- *              the out_buffer->Length field will indicate the number of bytes
- *              copied into the out_buffer->buf_ptr buffer. This table will be
- *              a complete table including the header.
+ * DESCRIPTION: Finds and verifies an ACPI table.
  *
- ******************************************************************************/
+ *****************************************************************************/
 acpi_status
-acpi_get_table(acpi_table_type table_type,
-	       u32 instance, struct acpi_buffer *ret_buffer)
+acpi_get_table(char *signature,
+	       acpi_native_uint instance, struct acpi_table_header ** out_table)
 {
-	struct acpi_table_header *tbl_ptr;
+	acpi_native_uint i;
+	acpi_native_uint j;
 	acpi_status status;
-	acpi_size table_length;
-
-	ACPI_FUNCTION_TRACE(acpi_get_table);
 
 	/* Parameter validation */
 
-	if (instance == 0) {
+	if (!signature || !out_table) {
+		return (AE_BAD_PARAMETER);
+	}
+
+	/*
+	 * Walk the root table list
+	 */
+	for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) {
+		if (!ACPI_COMPARE_NAME
+		    (&(acpi_gbl_root_table_list.tables[i].signature),
+		     signature)) {
+			continue;
+		}
+
+		if (++j < instance) {
+			continue;
+		}
+
+		status =
+		    acpi_tb_verify_table(&acpi_gbl_root_table_list.tables[i]);
+		if (ACPI_SUCCESS(status)) {
+			*out_table = acpi_gbl_root_table_list.tables[i].pointer;
+		}
+
+		if (!acpi_gbl_permanent_mmap) {
+			acpi_gbl_root_table_list.tables[i].pointer = 0;
+		}
+
+		return (status);
+	}
+
+	return (AE_NOT_FOUND);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_get_table)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_get_table_by_index
+ *
+ * PARAMETERS:  table_index         - Table index
+ *              Table               - Where the pointer to the table is returned
+ *
+ * RETURN:      Status and pointer to the table
+ *
+ * DESCRIPTION: Obtain a table by an index into the global table list.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_get_table_by_index(acpi_native_uint table_index,
+			struct acpi_table_header ** table)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(acpi_get_table_by_index);
+
+	/* Parameter validation */
+
+	if (!table) {
 		return_ACPI_STATUS(AE_BAD_PARAMETER);
 	}
 
-	status = acpi_ut_validate_buffer(ret_buffer);
+	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
+	/* Validate index */
+
+	if (table_index >= acpi_gbl_root_table_list.count) {
+		(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+		return_ACPI_STATUS(AE_BAD_PARAMETER);
+	}
+
+	if (!acpi_gbl_root_table_list.tables[table_index].pointer) {
+
+		/* Table is not mapped, map it */
+
+		status =
+		    acpi_tb_verify_table(&acpi_gbl_root_table_list.
+					 tables[table_index]);
+		if (ACPI_FAILURE(status)) {
+			(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+			return_ACPI_STATUS(status);
+		}
+	}
+
+	*table = acpi_gbl_root_table_list.tables[table_index].pointer;
+	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+	return_ACPI_STATUS(AE_OK);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_get_table_by_index)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_load_namespace
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Load the namespace from the DSDT and all SSDTs/PSDTs found in
+ *              the RSDT/XSDT.
+ *
+ ******************************************************************************/
+static acpi_status acpi_tb_load_namespace(void)
+{
+	acpi_status status;
+	struct acpi_table_header *table;
+	acpi_native_uint i;
+
+	ACPI_FUNCTION_TRACE(tb_load_namespace);
+
+	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
+	/*
+	 * Load the namespace. The DSDT is required, but any SSDT and PSDT tables
+	 * are optional.
+	 */
+	if (!acpi_gbl_root_table_list.count ||
+	    !ACPI_COMPARE_NAME(&
+			       (acpi_gbl_root_table_list.
+				tables[ACPI_TABLE_INDEX_DSDT].signature),
+			       ACPI_SIG_DSDT)
+	    ||
+	    ACPI_FAILURE(acpi_tb_verify_table
+			 (&acpi_gbl_root_table_list.
+			  tables[ACPI_TABLE_INDEX_DSDT]))) {
+		status = AE_NO_ACPI_TABLES;
+		goto unlock_and_exit;
+	}
+
+	/*
+	 * Find DSDT table
+	 */
+	status =
+	    acpi_os_table_override(acpi_gbl_root_table_list.
+				   tables[ACPI_TABLE_INDEX_DSDT].pointer,
+				   &table);
+	if (ACPI_SUCCESS(status) && table) {
+		/*
+		 * DSDT table has been found
+		 */
+		acpi_tb_delete_table(&acpi_gbl_root_table_list.
+				     tables[ACPI_TABLE_INDEX_DSDT]);
+		acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].pointer =
+		    table;
+		acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].length =
+		    table->length;
+		acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].flags =
+		    ACPI_TABLE_ORIGIN_UNKNOWN;
+
+		ACPI_INFO((AE_INFO, "Table DSDT replaced by host OS"));
+		acpi_tb_print_table_header(0, table);
+	}
+
+	status =
+	    acpi_tb_verify_table(&acpi_gbl_root_table_list.
+				 tables[ACPI_TABLE_INDEX_DSDT]);
 	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
+
+		/* A valid DSDT is required */
+
+		status = AE_NO_ACPI_TABLES;
+		goto unlock_and_exit;
 	}
 
-	/* Check the table type and instance */
+	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
 
-	if ((table_type > ACPI_TABLE_ID_MAX) ||
-	    (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) &&
-	     instance > 1)) {
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-	}
-
-	/* Get a pointer to the entire table */
-
-	status = acpi_tb_get_table_ptr(table_type, instance, &tbl_ptr);
+	/*
+	 * Load and parse tables.
+	 */
+	status = acpi_ns_load_table(ACPI_TABLE_INDEX_DSDT, acpi_gbl_root_node);
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
 
 	/*
-	 * acpi_tb_get_table_ptr will return a NULL pointer if the
-	 * table is not loaded.
+	 * Load any SSDT or PSDT tables. Note: Loop leaves tables locked
 	 */
-	if (tbl_ptr == NULL) {
-		return_ACPI_STATUS(AE_NOT_EXIST);
+	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+	for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+		if ((!ACPI_COMPARE_NAME
+		     (&(acpi_gbl_root_table_list.tables[i].signature),
+		      ACPI_SIG_SSDT)
+		     &&
+		     !ACPI_COMPARE_NAME(&
+					(acpi_gbl_root_table_list.tables[i].
+					 signature), ACPI_SIG_PSDT))
+		    ||
+		    ACPI_FAILURE(acpi_tb_verify_table
+				 (&acpi_gbl_root_table_list.tables[i]))) {
+			continue;
+		}
+
+		/* Ignore errors while loading tables, get as many as possible */
+
+		(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+		(void)acpi_ns_load_table(i, acpi_gbl_root_node);
+		(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
 	}
 
-	/* Get the table length */
+	ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n"));
 
-	if (table_type == ACPI_TABLE_ID_RSDP) {
-
-		/* RSD PTR is the only "table" without a header */
-
-		table_length = sizeof(struct rsdp_descriptor);
-	} else {
-		table_length = (acpi_size) tbl_ptr->length;
-	}
-
-	/* Validate/Allocate/Clear caller buffer */
-
-	status = acpi_ut_initialize_buffer(ret_buffer, table_length);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Copy the table to the buffer */
-
-	ACPI_MEMCPY(ACPI_CAST_PTR(void, ret_buffer->pointer),
-		    ACPI_CAST_PTR(void, tbl_ptr), table_length);
-
-	return_ACPI_STATUS(AE_OK);
+      unlock_and_exit:
+	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+	return_ACPI_STATUS(status);
 }
 
-ACPI_EXPORT_SYMBOL(acpi_get_table)
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_load_tables
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Load the ACPI tables from the RSDT/XSDT
+ *
+ ******************************************************************************/
+
+acpi_status acpi_load_tables(void)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(acpi_load_tables);
+
+	/*
+	 * Load the namespace from the tables
+	 */
+	status = acpi_tb_load_namespace();
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status,
+				"While loading namespace from ACPI tables"));
+	}
+
+	return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_load_tables)
diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c
index da2648b..cf8fa51 100644
--- a/drivers/acpi/tables/tbxfroot.c
+++ b/drivers/acpi/tables/tbxfroot.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,16 +48,15 @@
 ACPI_MODULE_NAME("tbxfroot")
 
 /* Local prototypes */
-static acpi_status
-acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags);
-
 static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length);
 
+static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp);
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_tb_validate_rsdp
  *
- * PARAMETERS:  Rsdp        - Pointer to unvalidated RSDP
+ * PARAMETERS:  Rsdp                - Pointer to unvalidated RSDP
  *
  * RETURN:      Status
  *
@@ -65,14 +64,18 @@
  *
  ******************************************************************************/
 
-acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp)
+static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
 {
 	ACPI_FUNCTION_ENTRY();
 
 	/*
-	 *  The signature and checksum must both be correct
+	 * The signature and checksum must both be correct
+	 *
+	 * Note: Sometimes there exists more than one RSDP in memory; the valid
+	 * RSDP has a valid checksum, all others have an invalid checksum.
 	 */
-	if (ACPI_STRNCMP((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0) {
+	if (ACPI_STRNCMP((char *)rsdp, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1)
+	    != 0) {
 
 		/* Nope, BAD Signature */
 
@@ -81,14 +84,14 @@
 
 	/* Check the standard checksum */
 
-	if (acpi_tb_sum_table(rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
+	if (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
 		return (AE_BAD_CHECKSUM);
 	}
 
 	/* Check extended checksum if table version >= 2 */
 
 	if ((rsdp->revision >= 2) &&
-	    (acpi_tb_sum_table(rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
+	    (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
 		return (AE_BAD_CHECKSUM);
 	}
 
@@ -97,314 +100,123 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_find_table
+ * FUNCTION:    acpi_tb_find_rsdp
  *
- * PARAMETERS:  Signature           - String with ACPI table signature
- *              oem_id              - String with the table OEM ID
- *              oem_table_id        - String with the OEM Table ID
- *              table_ptr           - Where the table pointer is returned
+ * PARAMETERS:  table_address           - Where the table pointer is returned
  *
- * RETURN:      Status
+ * RETURN:      Status, RSDP physical address
  *
- * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the
- *              Signature, OEM ID and OEM Table ID.
+ * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor
+ *              pointer structure.  If it is found, set *RSDP to point to it.
+ *
+ * NOTE1:       The RSDP must be either in the first 1_k of the Extended
+ *              BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.)
+ *              Only a 32-bit physical address is necessary.
+ *
+ * NOTE2:       This function is always available, regardless of the
+ *              initialization state of the rest of ACPI.
  *
  ******************************************************************************/
 
-acpi_status
-acpi_tb_find_table(char *signature,
-		   char *oem_id,
-		   char *oem_table_id, struct acpi_table_header ** table_ptr)
+acpi_status acpi_find_root_pointer(acpi_native_uint * table_address)
 {
-	acpi_status status;
-	struct acpi_table_header *table;
-
-	ACPI_FUNCTION_TRACE(tb_find_table);
-
-	/* Validate string lengths */
-
-	if ((ACPI_STRLEN(signature) > ACPI_NAME_SIZE) ||
-	    (ACPI_STRLEN(oem_id) > sizeof(table->oem_id)) ||
-	    (ACPI_STRLEN(oem_table_id) > sizeof(table->oem_table_id))) {
-		return_ACPI_STATUS(AE_AML_STRING_LIMIT);
-	}
-
-	if (ACPI_COMPARE_NAME(signature, DSDT_SIG)) {
-		/*
-		 * The DSDT pointer is contained in the FADT, not the RSDT.
-		 * This code should suffice, because the only code that would perform
-		 * a "find" on the DSDT is the data_table_region() AML opcode -- in
-		 * which case, the DSDT is guaranteed to be already loaded.
-		 * If this becomes insufficient, the FADT will have to be found first.
-		 */
-		if (!acpi_gbl_DSDT) {
-			return_ACPI_STATUS(AE_NO_ACPI_TABLES);
-		}
-		table = acpi_gbl_DSDT;
-	} else {
-		/* Find the table */
-
-		status = acpi_get_firmware_table(signature, 1,
-						 ACPI_LOGICAL_ADDRESSING,
-						 &table);
-		if (ACPI_FAILURE(status)) {
-			return_ACPI_STATUS(status);
-		}
-	}
-
-	/* Check oem_id and oem_table_id */
-
-	if ((oem_id[0] &&
-	     ACPI_STRNCMP(oem_id, table->oem_id,
-			  sizeof(table->oem_id))) ||
-	    (oem_table_id[0] &&
-	     ACPI_STRNCMP(oem_table_id, table->oem_table_id,
-			  sizeof(table->oem_table_id)))) {
-		return_ACPI_STATUS(AE_AML_NAME_NOT_FOUND);
-	}
-
-	ACPI_DEBUG_PRINT((ACPI_DB_TABLES, "Found table [%4.4s]\n",
-			  table->signature));
-
-	*table_ptr = table;
-	return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_get_firmware_table
- *
- * PARAMETERS:  Signature       - Any ACPI table signature
- *              Instance        - the non zero instance of the table, allows
- *                                support for multiple tables of the same type
- *              Flags           - Physical/Virtual support
- *              table_pointer   - Where a buffer containing the table is
- *                                returned
- *
- * RETURN:      Status
- *
- * DESCRIPTION: This function is called to get an ACPI table. A buffer is
- *              allocated for the table and returned in table_pointer.
- *              This table will be a complete table including the header.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_get_firmware_table(acpi_string signature,
-			u32 instance,
-			u32 flags, struct acpi_table_header **table_pointer)
-{
-	acpi_status status;
-	struct acpi_pointer address;
-	struct acpi_table_header *header = NULL;
-	struct acpi_table_desc *table_info = NULL;
-	struct acpi_table_desc *rsdt_info;
-	u32 table_count;
-	u32 i;
-	u32 j;
-
-	ACPI_FUNCTION_TRACE(acpi_get_firmware_table);
-
-	/*
-	 * Ensure that at least the table manager is initialized.  We don't
-	 * require that the entire ACPI subsystem is up for this interface.
-	 * If we have a buffer, we must have a length too
-	 */
-	if ((instance == 0) || (!signature) || (!table_pointer)) {
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-	}
-
-	/* Ensure that we have a RSDP */
-
-	if (!acpi_gbl_RSDP) {
-
-		/* Get the RSDP */
-
-		status = acpi_os_get_root_pointer(flags, &address);
-		if (ACPI_FAILURE(status)) {
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "RSDP not found\n"));
-			return_ACPI_STATUS(AE_NO_ACPI_TABLES);
-		}
-
-		/* Map and validate the RSDP */
-
-		if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
-			status = acpi_os_map_memory(address.pointer.physical,
-						    sizeof(struct
-							   rsdp_descriptor),
-						    (void *)&acpi_gbl_RSDP);
-			if (ACPI_FAILURE(status)) {
-				return_ACPI_STATUS(status);
-			}
-		} else {
-			acpi_gbl_RSDP = address.pointer.logical;
-		}
-
-		/* The RDSP signature and checksum must both be correct */
-
-		status = acpi_tb_validate_rsdp(acpi_gbl_RSDP);
-		if (ACPI_FAILURE(status)) {
-			return_ACPI_STATUS(status);
-		}
-	}
-
-	/* Get the RSDT address via the RSDP */
-
-	acpi_tb_get_rsdt_address(&address);
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-			  "RSDP located at %p, RSDT physical=%8.8X%8.8X\n",
-			  acpi_gbl_RSDP,
-			  ACPI_FORMAT_UINT64(address.pointer.value)));
-
-	/* Insert processor_mode flags */
-
-	address.pointer_type |= flags;
-
-	/* Get and validate the RSDT */
-
-	rsdt_info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc));
-	if (!rsdt_info) {
-		return_ACPI_STATUS(AE_NO_MEMORY);
-	}
-
-	status = acpi_tb_get_table(&address, rsdt_info);
-	if (ACPI_FAILURE(status)) {
-		goto cleanup;
-	}
-
-	status = acpi_tb_validate_rsdt(rsdt_info->pointer);
-	if (ACPI_FAILURE(status)) {
-		goto cleanup;
-	}
-
-	/* Allocate a scratch table header and table descriptor */
-
-	header = ACPI_ALLOCATE(sizeof(struct acpi_table_header));
-	if (!header) {
-		status = AE_NO_MEMORY;
-		goto cleanup;
-	}
-
-	table_info = ACPI_ALLOCATE(sizeof(struct acpi_table_desc));
-	if (!table_info) {
-		status = AE_NO_MEMORY;
-		goto cleanup;
-	}
-
-	/* Get the number of table pointers within the RSDT */
-
-	table_count =
-	    acpi_tb_get_table_count(acpi_gbl_RSDP, rsdt_info->pointer);
-	address.pointer_type = acpi_gbl_table_flags | flags;
-
-	/*
-	 * Search the RSDT/XSDT for the correct instance of the
-	 * requested table
-	 */
-	for (i = 0, j = 0; i < table_count; i++) {
-		/*
-		 * Get the next table pointer, handle RSDT vs. XSDT
-		 * RSDT pointers are 32 bits, XSDT pointers are 64 bits
-		 */
-		if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
-			address.pointer.value =
-			    (ACPI_CAST_PTR
-			     (struct rsdt_descriptor,
-			      rsdt_info->pointer))->table_offset_entry[i];
-		} else {
-			address.pointer.value =
-			    (ACPI_CAST_PTR
-			     (struct xsdt_descriptor,
-			      rsdt_info->pointer))->table_offset_entry[i];
-		}
-
-		/* Get the table header */
-
-		status = acpi_tb_get_table_header(&address, header);
-		if (ACPI_FAILURE(status)) {
-			goto cleanup;
-		}
-
-		/* Compare table signatures and table instance */
-
-		if (ACPI_COMPARE_NAME(header->signature, signature)) {
-
-			/* An instance of the table was found */
-
-			j++;
-			if (j >= instance) {
-
-				/* Found the correct instance, get the entire table */
-
-				status =
-				    acpi_tb_get_table_body(&address, header,
-							   table_info);
-				if (ACPI_FAILURE(status)) {
-					goto cleanup;
-				}
-
-				*table_pointer = table_info->pointer;
-				goto cleanup;
-			}
-		}
-	}
-
-	/* Did not find the table */
-
-	status = AE_NOT_EXIST;
-
-      cleanup:
-	if (rsdt_info->pointer) {
-		acpi_os_unmap_memory(rsdt_info->pointer,
-				     (acpi_size) rsdt_info->pointer->length);
-	}
-	ACPI_FREE(rsdt_info);
-
-	if (header) {
-		ACPI_FREE(header);
-	}
-	if (table_info) {
-		ACPI_FREE(table_info);
-	}
-	return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_get_firmware_table)
-
-/* TBD: Move to a new file */
-#if ACPI_MACHINE_WIDTH != 16
-/*******************************************************************************
- *
- * FUNCTION:    acpi_find_root_pointer
- *
- * PARAMETERS:  Flags                   - Logical/Physical addressing
- *              rsdp_address            - Where to place the RSDP address
- *
- * RETURN:      Status, Physical address of the RSDP
- *
- * DESCRIPTION: Find the RSDP
- *
- ******************************************************************************/
-acpi_status acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address)
-{
-	struct acpi_table_desc table_info;
-	acpi_status status;
+	u8 *table_ptr;
+	u8 *mem_rover;
+	u32 physical_address;
 
 	ACPI_FUNCTION_TRACE(acpi_find_root_pointer);
 
-	/* Get the RSDP */
+	/* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
 
-	status = acpi_tb_find_rsdp(&table_info, flags);
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status,
-				"RSDP structure not found - Flags=%X", flags));
+	table_ptr = acpi_os_map_memory((acpi_physical_address)
+				       ACPI_EBDA_PTR_LOCATION,
+				       ACPI_EBDA_PTR_LENGTH);
+	if (!table_ptr) {
+		ACPI_ERROR((AE_INFO,
+			    "Could not map memory at %8.8X for length %X",
+			    ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH));
 
-		return_ACPI_STATUS(AE_NO_ACPI_TABLES);
+		return_ACPI_STATUS(AE_NO_MEMORY);
 	}
 
-	rsdp_address->pointer_type = ACPI_PHYSICAL_POINTER;
-	rsdp_address->pointer.physical = table_info.physical_address;
-	return_ACPI_STATUS(AE_OK);
+	ACPI_MOVE_16_TO_32(&physical_address, table_ptr);
+
+	/* Convert segment part to physical address */
+
+	physical_address <<= 4;
+	acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH);
+
+	/* EBDA present? */
+
+	if (physical_address > 0x400) {
+		/*
+		 * 1b) Search EBDA paragraphs (EBDA is required to be a
+		 *     minimum of 1_k length)
+		 */
+		table_ptr = acpi_os_map_memory((acpi_native_uint)
+					       physical_address,
+					       ACPI_EBDA_WINDOW_SIZE);
+		if (!table_ptr) {
+			ACPI_ERROR((AE_INFO,
+				    "Could not map memory at %8.8X for length %X",
+				    physical_address, ACPI_EBDA_WINDOW_SIZE));
+
+			return_ACPI_STATUS(AE_NO_MEMORY);
+		}
+
+		mem_rover =
+		    acpi_tb_scan_memory_for_rsdp(table_ptr,
+						 ACPI_EBDA_WINDOW_SIZE);
+		acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE);
+
+		if (mem_rover) {
+
+			/* Return the physical address */
+
+			physical_address +=
+			    (u32) ACPI_PTR_DIFF(mem_rover, table_ptr);
+
+			*table_address = physical_address;
+			return_ACPI_STATUS(AE_OK);
+		}
+	}
+
+	/*
+	 * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh
+	 */
+	table_ptr = acpi_os_map_memory((acpi_physical_address)
+				       ACPI_HI_RSDP_WINDOW_BASE,
+				       ACPI_HI_RSDP_WINDOW_SIZE);
+
+	if (!table_ptr) {
+		ACPI_ERROR((AE_INFO,
+			    "Could not map memory at %8.8X for length %X",
+			    ACPI_HI_RSDP_WINDOW_BASE,
+			    ACPI_HI_RSDP_WINDOW_SIZE));
+
+		return_ACPI_STATUS(AE_NO_MEMORY);
+	}
+
+	mem_rover =
+	    acpi_tb_scan_memory_for_rsdp(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
+	acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
+
+	if (mem_rover) {
+
+		/* Return the physical address */
+
+		physical_address = (u32)
+		    (ACPI_HI_RSDP_WINDOW_BASE +
+		     ACPI_PTR_DIFF(mem_rover, table_ptr));
+
+		*table_address = physical_address;
+		return_ACPI_STATUS(AE_OK);
+	}
+
+	/* A valid RSDP was not found */
+
+	ACPI_ERROR((AE_INFO, "A valid RSDP was not found"));
+	return_ACPI_STATUS(AE_NOT_FOUND);
 }
 
 ACPI_EXPORT_SYMBOL(acpi_find_root_pointer)
@@ -440,7 +252,7 @@
 
 		status =
 		    acpi_tb_validate_rsdp(ACPI_CAST_PTR
-					  (struct rsdp_descriptor, mem_rover));
+					  (struct acpi_table_rsdp, mem_rover));
 		if (ACPI_SUCCESS(status)) {
 
 			/* Sig and checksum valid, we have found a real RSDP */
@@ -461,189 +273,3 @@
 			  start_address));
 	return_PTR(NULL);
 }
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_find_rsdp
- *
- * PARAMETERS:  table_info              - Where the table info is returned
- *              Flags                   - Current memory mode (logical vs.
- *                                        physical addressing)
- *
- * RETURN:      Status, RSDP physical address
- *
- * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor
- *              pointer structure.  If it is found, set *RSDP to point to it.
- *
- *              NOTE1: The RSDP must be either in the first 1_k of the Extended
- *              BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.)
- *              Only a 32-bit physical address is necessary.
- *
- *              NOTE2: This function is always available, regardless of the
- *              initialization state of the rest of ACPI.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags)
-{
-	u8 *table_ptr;
-	u8 *mem_rover;
-	u32 physical_address;
-	acpi_status status;
-
-	ACPI_FUNCTION_TRACE(tb_find_rsdp);
-
-	/*
-	 * Scan supports either logical addressing or physical addressing
-	 */
-	if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
-
-		/* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
-
-		status = acpi_os_map_memory((acpi_physical_address)
-					    ACPI_EBDA_PTR_LOCATION,
-					    ACPI_EBDA_PTR_LENGTH,
-					    (void *)&table_ptr);
-		if (ACPI_FAILURE(status)) {
-			ACPI_ERROR((AE_INFO,
-				    "Could not map memory at %8.8X for length %X",
-				    ACPI_EBDA_PTR_LOCATION,
-				    ACPI_EBDA_PTR_LENGTH));
-
-			return_ACPI_STATUS(status);
-		}
-
-		ACPI_MOVE_16_TO_32(&physical_address, table_ptr);
-
-		/* Convert segment part to physical address */
-
-		physical_address <<= 4;
-		acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH);
-
-		/* EBDA present? */
-
-		if (physical_address > 0x400) {
-			/*
-			 * 1b) Search EBDA paragraphs (EBDA is required to be a
-			 *     minimum of 1_k length)
-			 */
-			status = acpi_os_map_memory((acpi_physical_address)
-						    physical_address,
-						    ACPI_EBDA_WINDOW_SIZE,
-						    (void *)&table_ptr);
-			if (ACPI_FAILURE(status)) {
-				ACPI_ERROR((AE_INFO,
-					    "Could not map memory at %8.8X for length %X",
-					    physical_address,
-					    ACPI_EBDA_WINDOW_SIZE));
-
-				return_ACPI_STATUS(status);
-			}
-
-			mem_rover = acpi_tb_scan_memory_for_rsdp(table_ptr,
-								 ACPI_EBDA_WINDOW_SIZE);
-			acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE);
-
-			if (mem_rover) {
-
-				/* Return the physical address */
-
-				physical_address +=
-				    (u32) ACPI_PTR_DIFF(mem_rover, table_ptr);
-
-				table_info->physical_address =
-				    (acpi_physical_address) physical_address;
-				return_ACPI_STATUS(AE_OK);
-			}
-		}
-
-		/*
-		 * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh
-		 */
-		status = acpi_os_map_memory((acpi_physical_address)
-					    ACPI_HI_RSDP_WINDOW_BASE,
-					    ACPI_HI_RSDP_WINDOW_SIZE,
-					    (void *)&table_ptr);
-
-		if (ACPI_FAILURE(status)) {
-			ACPI_ERROR((AE_INFO,
-				    "Could not map memory at %8.8X for length %X",
-				    ACPI_HI_RSDP_WINDOW_BASE,
-				    ACPI_HI_RSDP_WINDOW_SIZE));
-
-			return_ACPI_STATUS(status);
-		}
-
-		mem_rover =
-		    acpi_tb_scan_memory_for_rsdp(table_ptr,
-						 ACPI_HI_RSDP_WINDOW_SIZE);
-		acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
-
-		if (mem_rover) {
-
-			/* Return the physical address */
-
-			physical_address = (u32)
-			    (ACPI_HI_RSDP_WINDOW_BASE +
-			     ACPI_PTR_DIFF(mem_rover, table_ptr));
-
-			table_info->physical_address =
-			    (acpi_physical_address) physical_address;
-			return_ACPI_STATUS(AE_OK);
-		}
-	}
-
-	/*
-	 * Physical addressing
-	 */
-	else {
-		/* 1a) Get the location of the EBDA */
-
-		ACPI_MOVE_16_TO_32(&physical_address, ACPI_EBDA_PTR_LOCATION);
-		physical_address <<= 4;	/* Convert segment to physical address */
-
-		/* EBDA present? */
-
-		if (physical_address > 0x400) {
-			/*
-			 * 1b) Search EBDA paragraphs (EBDA is required to be a minimum of
-			 *     1_k length)
-			 */
-			mem_rover =
-			    acpi_tb_scan_memory_for_rsdp(ACPI_PHYSADDR_TO_PTR
-							 (physical_address),
-							 ACPI_EBDA_WINDOW_SIZE);
-			if (mem_rover) {
-
-				/* Return the physical address */
-
-				table_info->physical_address =
-				    ACPI_TO_INTEGER(mem_rover);
-				return_ACPI_STATUS(AE_OK);
-			}
-		}
-
-		/* 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */
-
-		mem_rover =
-		    acpi_tb_scan_memory_for_rsdp(ACPI_PHYSADDR_TO_PTR
-						 (ACPI_HI_RSDP_WINDOW_BASE),
-						 ACPI_HI_RSDP_WINDOW_SIZE);
-		if (mem_rover) {
-
-			/* Found it, return the physical address */
-
-			table_info->physical_address =
-			    ACPI_TO_INTEGER(mem_rover);
-			return_ACPI_STATUS(AE_OK);
-		}
-	}
-
-	/* A valid RSDP was not found */
-
-	ACPI_ERROR((AE_INFO, "No valid RSDP was found"));
-	return_ACPI_STATUS(AE_NOT_FOUND);
-}
-
-#endif
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 40ddb4d..f76d316 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -82,7 +82,7 @@
 
 static int acpi_thermal_add(struct acpi_device *device);
 static int acpi_thermal_remove(struct acpi_device *device, int type);
-static int acpi_thermal_resume(struct acpi_device *device, int state);
+static int acpi_thermal_resume(struct acpi_device *device);
 static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
 static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
 static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
@@ -1353,7 +1353,7 @@
 	return 0;
 }
 
-static int acpi_thermal_resume(struct acpi_device *device, int state)
+static int acpi_thermal_resume(struct acpi_device *device)
 {
 	struct acpi_thermal *tz = NULL;
 	int i;
diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c
index f6cbc0b..55a7648 100644
--- a/drivers/acpi/utilities/utalloc.c
+++ b/drivers/acpi/utilities/utalloc.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,7 @@
  */
 
 #include <acpi/acpi.h>
+#include <acpi/acdebug.h>
 
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utalloc")
@@ -142,6 +143,14 @@
 
 acpi_status acpi_ut_delete_caches(void)
 {
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+	char buffer[7];
+
+	if (acpi_gbl_display_final_mem_stats) {
+		ACPI_STRCPY(buffer, "MEMORY");
+		acpi_db_display_statistics(buffer);
+	}
+#endif
 
 	(void)acpi_os_delete_cache(acpi_gbl_namespace_cache);
 	acpi_gbl_namespace_cache = NULL;
diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c
index 1a1f810..870f6ed 100644
--- a/drivers/acpi/utilities/utcache.c
+++ b/drivers/acpi/utilities/utcache.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -289,6 +289,14 @@
 
 		ACPI_MEM_TRACKING(cache->total_allocated++);
 
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+		if ((cache->total_allocated - cache->total_freed) >
+		    cache->max_occupied) {
+			cache->max_occupied =
+			    cache->total_allocated - cache->total_freed;
+		}
+#endif
+
 		/* Avoid deadlock with ACPI_ALLOCATE_ZEROED */
 
 		status = acpi_ut_release_mutex(ACPI_MTX_CACHES);
diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c
index 5e1a80d..84d529db 100644
--- a/drivers/acpi/utilities/utcopy.c
+++ b/drivers/acpi/utilities/utcopy.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -719,6 +719,15 @@
 		acpi_ut_add_reference(source_desc->reference.object);
 		break;
 
+	case ACPI_TYPE_REGION:
+		/*
+		 * We copied the Region Handler, so we now must add a reference
+		 */
+		if (dest_desc->region.handler) {
+			acpi_ut_add_reference(dest_desc->region.handler);
+		}
+		break;
+
 	default:
 		/* Nothing to do for other simple objects */
 		break;
diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c
index 9e9054e..61ad4f2 100644
--- a/drivers/acpi/utilities/utdebug.c
+++ b/drivers/acpi/utilities/utdebug.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -181,8 +181,7 @@
 		if (ACPI_LV_THREADS & acpi_dbg_level) {
 			acpi_os_printf
 			    ("\n**** Context Switch from TID %lX to TID %lX ****\n\n",
-			     (unsigned long) acpi_gbl_prev_thread_id,
-			     (unsigned long) thread_id);
+			     (unsigned long)acpi_gbl_prev_thread_id, (unsigned long)thread_id);
 		}
 
 		acpi_gbl_prev_thread_id = thread_id;
@@ -195,7 +194,7 @@
 	acpi_os_printf("%8s-%04ld ", module_name, line_number);
 
 	if (ACPI_LV_THREADS & acpi_dbg_level) {
-		acpi_os_printf("[%04lX] ", thread_id);
+		acpi_os_printf("[%04lX] ", (unsigned long)thread_id);
 	}
 
 	acpi_os_printf("[%02ld] %-22.22s: ",
diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c
index 9d3f114..f777ceb 100644
--- a/drivers/acpi/utilities/utdelete.c
+++ b/drivers/acpi/utilities/utdelete.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -158,16 +158,20 @@
 				  "***** Mutex %p, OS Mutex %p\n",
 				  object, object->mutex.os_mutex));
 
-		if (object->mutex.os_mutex != ACPI_GLOBAL_LOCK) {
-			acpi_ex_unlink_mutex(object);
-			acpi_os_delete_mutex(object->mutex.os_mutex);
-		} else {
-			/* Global Lock "mutex" is actually a counting semaphore */
+		if (object->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+
+			/* Global Lock has extra semaphore */
 
 			(void)
 			    acpi_os_delete_semaphore
 			    (acpi_gbl_global_lock_semaphore);
 			acpi_gbl_global_lock_semaphore = NULL;
+
+			acpi_os_delete_mutex(object->mutex.os_mutex);
+			acpi_gbl_global_lock_mutex = NULL;
+		} else {
+			acpi_ex_unlink_mutex(object);
+			acpi_os_delete_mutex(object->mutex.os_mutex);
 		}
 		break;
 
diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c
index d6d7121..13d5879 100644
--- a/drivers/acpi/utilities/uteval.c
+++ b/drivers/acpi/utilities/uteval.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
index 014030a..af33358 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -46,89 +46,9 @@
 #include <acpi/acpi.h>
 #include <acpi/acnamesp.h>
 
+ACPI_EXPORT_SYMBOL(acpi_gbl_FADT)
 #define _COMPONENT          ACPI_UTILITIES
-ACPI_MODULE_NAME("utglobal")
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_format_exception
- *
- * PARAMETERS:  Status       - The acpi_status code to be formatted
- *
- * RETURN:      A string containing the exception text. A valid pointer is
- *              always returned.
- *
- * DESCRIPTION: This function translates an ACPI exception into an ASCII string.
- *
- ******************************************************************************/
-const char *acpi_format_exception(acpi_status status)
-{
-	acpi_status sub_status;
-	const char *exception = NULL;
-
-	ACPI_FUNCTION_ENTRY();
-
-	/*
-	 * Status is composed of two parts, a "type" and an actual code
-	 */
-	sub_status = (status & ~AE_CODE_MASK);
-
-	switch (status & AE_CODE_MASK) {
-	case AE_CODE_ENVIRONMENTAL:
-
-		if (sub_status <= AE_CODE_ENV_MAX) {
-			exception = acpi_gbl_exception_names_env[sub_status];
-		}
-		break;
-
-	case AE_CODE_PROGRAMMER:
-
-		if (sub_status <= AE_CODE_PGM_MAX) {
-			exception =
-			    acpi_gbl_exception_names_pgm[sub_status - 1];
-		}
-		break;
-
-	case AE_CODE_ACPI_TABLES:
-
-		if (sub_status <= AE_CODE_TBL_MAX) {
-			exception =
-			    acpi_gbl_exception_names_tbl[sub_status - 1];
-		}
-		break;
-
-	case AE_CODE_AML:
-
-		if (sub_status <= AE_CODE_AML_MAX) {
-			exception =
-			    acpi_gbl_exception_names_aml[sub_status - 1];
-		}
-		break;
-
-	case AE_CODE_CONTROL:
-
-		if (sub_status <= AE_CODE_CTRL_MAX) {
-			exception =
-			    acpi_gbl_exception_names_ctrl[sub_status - 1];
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	if (!exception) {
-
-		/* Exception code was not recognized */
-
-		ACPI_ERROR((AE_INFO,
-			    "Unknown exception code: 0x%8.8X", status));
-
-		exception = "UNKNOWN_STATUS_CODE";
-	}
-
-	return (ACPI_CAST_PTR(const char, exception));
-}
+    ACPI_MODULE_NAME("utglobal")
 
 /*******************************************************************************
  *
@@ -163,8 +83,6 @@
 
 u8 acpi_gbl_shutdown = TRUE;
 
-const u8 acpi_gbl_decode_to8bit[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
-
 const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = {
 	"\\_S0_",
 	"\\_S1_",
@@ -183,10 +101,45 @@
 
 /*******************************************************************************
  *
- * Namespace globals
+ * FUNCTION:    acpi_format_exception
+ *
+ * PARAMETERS:  Status       - The acpi_status code to be formatted
+ *
+ * RETURN:      A string containing the exception text. A valid pointer is
+ *              always returned.
+ *
+ * DESCRIPTION: This function translates an ACPI exception into an ASCII string
+ *              It is here instead of utxface.c so it is always present.
  *
  ******************************************************************************/
 
+const char *acpi_format_exception(acpi_status status)
+{
+	const char *exception = NULL;
+
+	ACPI_FUNCTION_ENTRY();
+
+	exception = acpi_ut_validate_exception(status);
+	if (!exception) {
+
+		/* Exception code was not recognized */
+
+		ACPI_ERROR((AE_INFO,
+			    "Unknown exception code: 0x%8.8X", status));
+
+		exception = "UNKNOWN_STATUS_CODE";
+	}
+
+	return (ACPI_CAST_PTR(const char, exception));
+}
+
+ACPI_EXPORT_SYMBOL(acpi_format_exception)
+
+/*******************************************************************************
+ *
+ * Namespace globals
+ *
+ ******************************************************************************/
 /*
  * Predefined ACPI Names (Built-in to the Interpreter)
  *
@@ -280,53 +233,6 @@
 	return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]);
 }
 
-/*******************************************************************************
- *
- * Table name globals
- *
- * NOTE: This table includes ONLY the ACPI tables that the subsystem consumes.
- * it is NOT an exhaustive list of all possible ACPI tables.  All ACPI tables
- * that are not used by the subsystem are simply ignored.
- *
- * Do NOT add any table to this list that is not consumed directly by this
- * subsystem (No MADT, ECDT, SBST, etc.)
- *
- ******************************************************************************/
-
-struct acpi_table_list acpi_gbl_table_lists[ACPI_TABLE_ID_MAX + 1];
-
-struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1] = {
-	/***********    Name,   Signature, Global typed pointer     Signature size,      Type                  How many allowed?,    Contains valid AML? */
-
-	/* RSDP 0 */ {RSDP_NAME, RSDP_SIG, NULL, sizeof(RSDP_SIG) - 1,
-		      ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE}
-	,
-	/* DSDT 1 */ {DSDT_SIG, DSDT_SIG, (void *)&acpi_gbl_DSDT,
-		      sizeof(DSDT_SIG) - 1,
-		      ACPI_TABLE_SECONDARY | ACPI_TABLE_SINGLE |
-		      ACPI_TABLE_EXECUTABLE}
-	,
-	/* FADT 2 */ {FADT_SIG, FADT_SIG, (void *)&acpi_gbl_FADT,
-		      sizeof(FADT_SIG) - 1,
-		      ACPI_TABLE_PRIMARY | ACPI_TABLE_SINGLE}
-	,
-	/* FACS 3 */ {FACS_SIG, FACS_SIG, (void *)&acpi_gbl_FACS,
-		      sizeof(FACS_SIG) - 1,
-		      ACPI_TABLE_SECONDARY | ACPI_TABLE_SINGLE}
-	,
-	/* PSDT 4 */ {PSDT_SIG, PSDT_SIG, NULL, sizeof(PSDT_SIG) - 1,
-		      ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE |
-		      ACPI_TABLE_EXECUTABLE}
-	,
-	/* SSDT 5 */ {SSDT_SIG, SSDT_SIG, NULL, sizeof(SSDT_SIG) - 1,
-		      ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE |
-		      ACPI_TABLE_EXECUTABLE}
-	,
-	/* XSDT 6 */ {XSDT_SIG, XSDT_SIG, NULL, sizeof(RSDT_SIG) - 1,
-		      ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE}
-	,
-};
-
 /******************************************************************************
  *
  * Event and Hardware globals
@@ -612,7 +518,7 @@
 	/* Name must be a valid ACPI name */
 
 	if (!acpi_ut_valid_acpi_name(node->name.integer)) {
-		node->name.integer = acpi_ut_repair_name(node->name.integer);
+		node->name.integer = acpi_ut_repair_name(node->name.ascii);
 	}
 
 	/* Return the name */
@@ -751,13 +657,6 @@
 		return;
 	}
 
-	/* ACPI table structure */
-
-	for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) {
-		acpi_gbl_table_lists[i].next = NULL;
-		acpi_gbl_table_lists[i].count = 0;
-	}
-
 	/* Mutex locked flags */
 
 	for (i = 0; i < ACPI_NUM_MUTEX; i++) {
@@ -773,6 +672,7 @@
 
 	/* GPE support */
 
+	acpi_gpe_count = 0;
 	acpi_gbl_gpe_xrupt_list_head = NULL;
 	acpi_gbl_gpe_fadt_blocks[0] = NULL;
 	acpi_gbl_gpe_fadt_blocks[1] = NULL;
@@ -784,25 +684,15 @@
 	acpi_gbl_exception_handler = NULL;
 	acpi_gbl_init_handler = NULL;
 
-	/* Global "typed" ACPI table pointers */
-
-	acpi_gbl_RSDP = NULL;
-	acpi_gbl_XSDT = NULL;
-	acpi_gbl_FACS = NULL;
-	acpi_gbl_FADT = NULL;
-	acpi_gbl_DSDT = NULL;
-
 	/* Global Lock support */
 
 	acpi_gbl_global_lock_semaphore = NULL;
+	acpi_gbl_global_lock_mutex = NULL;
 	acpi_gbl_global_lock_acquired = FALSE;
-	acpi_gbl_global_lock_thread_count = 0;
 	acpi_gbl_global_lock_handle = 0;
 
 	/* Miscellaneous variables */
 
-	acpi_gbl_table_flags = ACPI_PHYSICAL_POINTER;
-	acpi_gbl_rsdp_original_location = 0;
 	acpi_gbl_cm_single_step = FALSE;
 	acpi_gbl_db_terminate_threads = FALSE;
 	acpi_gbl_shutdown = FALSE;
@@ -837,8 +727,13 @@
 	acpi_gbl_lowest_stack_pointer = ACPI_SIZE_MAX;
 #endif
 
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+	acpi_gbl_display_final_mem_stats = FALSE;
+#endif
+
 	return_VOID;
 }
 
 ACPI_EXPORT_SYMBOL(acpi_dbg_level)
 ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
+ACPI_EXPORT_SYMBOL(acpi_gpe_count)
diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c
index ff76055..ad3c0d0 100644
--- a/drivers/acpi/utilities/utinit.c
+++ b/drivers/acpi/utilities/utinit.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,119 +44,14 @@
 #include <acpi/acpi.h>
 #include <acpi/acnamesp.h>
 #include <acpi/acevents.h>
+#include <acpi/actables.h>
 
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utinit")
 
 /* Local prototypes */
-static void
-acpi_ut_fadt_register_error(char *register_name, u32 value, u8 offset);
-
 static void acpi_ut_terminate(void);
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_fadt_register_error
- *
- * PARAMETERS:  register_name           - Pointer to string identifying register
- *              Value                   - Actual register contents value
- *              Offset                  - Byte offset in the FADT
- *
- * RETURN:      AE_BAD_VALUE
- *
- * DESCRIPTION: Display failure message
- *
- ******************************************************************************/
-
-static void
-acpi_ut_fadt_register_error(char *register_name, u32 value, u8 offset)
-{
-
-	ACPI_WARNING((AE_INFO,
-		      "Invalid FADT value %s=%X at offset %X FADT=%p",
-		      register_name, value, offset, acpi_gbl_FADT));
-}
-
-/******************************************************************************
- *
- * FUNCTION:    acpi_ut_validate_fadt
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Validate various ACPI registers in the FADT
- *
- ******************************************************************************/
-
-acpi_status acpi_ut_validate_fadt(void)
-{
-
-	/*
-	 * Verify Fixed ACPI Description Table fields,
-	 * but don't abort on any problems, just display error
-	 */
-	if (acpi_gbl_FADT->pm1_evt_len < 4) {
-		acpi_ut_fadt_register_error("PM1_EVT_LEN",
-					    (u32) acpi_gbl_FADT->pm1_evt_len,
-					    ACPI_FADT_OFFSET(pm1_evt_len));
-	}
-
-	if (!acpi_gbl_FADT->pm1_cnt_len) {
-		acpi_ut_fadt_register_error("PM1_CNT_LEN", 0,
-					    ACPI_FADT_OFFSET(pm1_cnt_len));
-	}
-
-	if (!acpi_gbl_FADT->xpm1a_evt_blk.address) {
-		acpi_ut_fadt_register_error("X_PM1a_EVT_BLK", 0,
-					    ACPI_FADT_OFFSET(xpm1a_evt_blk.
-							     address));
-	}
-
-	if (!acpi_gbl_FADT->xpm1a_cnt_blk.address) {
-		acpi_ut_fadt_register_error("X_PM1a_CNT_BLK", 0,
-					    ACPI_FADT_OFFSET(xpm1a_cnt_blk.
-							     address));
-	}
-
-	if (!acpi_gbl_FADT->xpm_tmr_blk.address) {
-		acpi_ut_fadt_register_error("X_PM_TMR_BLK", 0,
-					    ACPI_FADT_OFFSET(xpm_tmr_blk.
-							     address));
-	}
-
-	if ((acpi_gbl_FADT->xpm2_cnt_blk.address &&
-	     !acpi_gbl_FADT->pm2_cnt_len)) {
-		acpi_ut_fadt_register_error("PM2_CNT_LEN",
-					    (u32) acpi_gbl_FADT->pm2_cnt_len,
-					    ACPI_FADT_OFFSET(pm2_cnt_len));
-	}
-
-	if (acpi_gbl_FADT->pm_tm_len < 4) {
-		acpi_ut_fadt_register_error("PM_TM_LEN",
-					    (u32) acpi_gbl_FADT->pm_tm_len,
-					    ACPI_FADT_OFFSET(pm_tm_len));
-	}
-
-	/* Length of GPE blocks must be a multiple of 2 */
-
-	if (acpi_gbl_FADT->xgpe0_blk.address &&
-	    (acpi_gbl_FADT->gpe0_blk_len & 1)) {
-		acpi_ut_fadt_register_error("(x)GPE0_BLK_LEN",
-					    (u32) acpi_gbl_FADT->gpe0_blk_len,
-					    ACPI_FADT_OFFSET(gpe0_blk_len));
-	}
-
-	if (acpi_gbl_FADT->xgpe1_blk.address &&
-	    (acpi_gbl_FADT->gpe1_blk_len & 1)) {
-		acpi_ut_fadt_register_error("(x)GPE1_BLK_LEN",
-					    (u32) acpi_gbl_FADT->gpe1_blk_len,
-					    ACPI_FADT_OFFSET(gpe1_blk_len));
-	}
-
-	return (AE_OK);
-}
-
 /******************************************************************************
  *
  * FUNCTION:    acpi_ut_terminate
@@ -178,7 +73,6 @@
 
 	ACPI_FUNCTION_TRACE(ut_terminate);
 
-	/* Free global tables, etc. */
 	/* Free global GPE blocks and related info structures */
 
 	gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
@@ -239,6 +133,10 @@
 
 	acpi_ns_terminate();
 
+	/* Delete the ACPI tables */
+
+	acpi_tb_terminate();
+
 	/* Close the globals */
 
 	acpi_ut_terminate();
diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/utilities/utmath.c
index 19d74be..0c56a0d 100644
--- a/drivers/acpi/utilities/utmath.c
+++ b/drivers/acpi/utilities/utmath.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
index 6d8a821..50133ff 100644
--- a/drivers/acpi/utilities/utmisc.c
+++ b/drivers/acpi/utilities/utmisc.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -51,6 +51,78 @@
 
 /*******************************************************************************
  *
+ * FUNCTION:    acpi_ut_validate_exception
+ *
+ * PARAMETERS:  Status       - The acpi_status code to be formatted
+ *
+ * RETURN:      A string containing the exception text. NULL if exception is
+ *              not valid.
+ *
+ * DESCRIPTION: This function validates and translates an ACPI exception into
+ *              an ASCII string.
+ *
+ ******************************************************************************/
+const char *acpi_ut_validate_exception(acpi_status status)
+{
+	acpi_status sub_status;
+	const char *exception = NULL;
+
+	ACPI_FUNCTION_ENTRY();
+
+	/*
+	 * Status is composed of two parts, a "type" and an actual code
+	 */
+	sub_status = (status & ~AE_CODE_MASK);
+
+	switch (status & AE_CODE_MASK) {
+	case AE_CODE_ENVIRONMENTAL:
+
+		if (sub_status <= AE_CODE_ENV_MAX) {
+			exception = acpi_gbl_exception_names_env[sub_status];
+		}
+		break;
+
+	case AE_CODE_PROGRAMMER:
+
+		if (sub_status <= AE_CODE_PGM_MAX) {
+			exception =
+			    acpi_gbl_exception_names_pgm[sub_status - 1];
+		}
+		break;
+
+	case AE_CODE_ACPI_TABLES:
+
+		if (sub_status <= AE_CODE_TBL_MAX) {
+			exception =
+			    acpi_gbl_exception_names_tbl[sub_status - 1];
+		}
+		break;
+
+	case AE_CODE_AML:
+
+		if (sub_status <= AE_CODE_AML_MAX) {
+			exception =
+			    acpi_gbl_exception_names_aml[sub_status - 1];
+		}
+		break;
+
+	case AE_CODE_CONTROL:
+
+		if (sub_status <= AE_CODE_CTRL_MAX) {
+			exception =
+			    acpi_gbl_exception_names_ctrl[sub_status - 1];
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return (ACPI_CAST_PTR(const char, exception));
+}
+
+/*******************************************************************************
+ *
  * FUNCTION:    acpi_ut_is_aml_table
  *
  * PARAMETERS:  Table               - An ACPI table
@@ -62,14 +134,15 @@
  *              data tables that do not contain AML code.
  *
  ******************************************************************************/
+
 u8 acpi_ut_is_aml_table(struct acpi_table_header *table)
 {
 
 	/* These are the only tables that contain executable AML */
 
-	if (ACPI_COMPARE_NAME(table->signature, DSDT_SIG) ||
-	    ACPI_COMPARE_NAME(table->signature, PSDT_SIG) ||
-	    ACPI_COMPARE_NAME(table->signature, SSDT_SIG)) {
+	if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) ||
+	    ACPI_COMPARE_NAME(table->signature, ACPI_SIG_PSDT) ||
+	    ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) {
 		return (TRUE);
 	}
 
@@ -418,7 +491,7 @@
 void acpi_ut_set_integer_width(u8 revision)
 {
 
-	if (revision <= 1) {
+	if (revision < 2) {
 
 		/* 32-bit case */
 
@@ -582,26 +655,25 @@
  *
  ******************************************************************************/
 
-acpi_name acpi_ut_repair_name(acpi_name name)
+acpi_name acpi_ut_repair_name(char *name)
 {
-	char *name_ptr = ACPI_CAST_PTR(char, &name);
-	char new_name[ACPI_NAME_SIZE];
 	acpi_native_uint i;
+	char new_name[ACPI_NAME_SIZE];
 
 	for (i = 0; i < ACPI_NAME_SIZE; i++) {
-		new_name[i] = name_ptr[i];
+		new_name[i] = name[i];
 
 		/*
 		 * Replace a bad character with something printable, yet technically
 		 * still invalid. This prevents any collisions with existing "good"
 		 * names in the namespace.
 		 */
-		if (!acpi_ut_valid_acpi_char(name_ptr[i], i)) {
+		if (!acpi_ut_valid_acpi_char(name[i], i)) {
 			new_name[i] = '*';
 		}
 	}
 
-	return (*ACPI_CAST_PTR(u32, new_name));
+	return (*(u32 *) new_name);
 }
 
 /*******************************************************************************
@@ -996,9 +1068,13 @@
 {
 	va_list args;
 
-	acpi_os_printf("ACPI (%s-%04d): ", module_name, line_number);
+	/*
+	 * Removed module_name, line_number, and acpica version, not needed
+	 * for info output
+	 */
+	acpi_os_printf("ACPI: ");
 
 	va_start(args, format);
 	acpi_os_vprintf(format, args);
-	acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
+	acpi_os_printf("\n");
 }
diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c
index 180e73c..cbad2ef 100644
--- a/drivers/acpi/utilities/utmutex.c
+++ b/drivers/acpi/utilities/utmutex.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c
index ba7d8ac..4696124 100644
--- a/drivers/acpi/utilities/utobject.c
+++ b/drivers/acpi/utilities/utobject.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/utilities/utresrc.c
index 5a2de92..e8fe1ba 100644
--- a/drivers/acpi/utilities/utresrc.c
+++ b/drivers/acpi/utilities/utresrc.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/utilities/utstate.c
index eaa13d0..edcaafa 100644
--- a/drivers/acpi/utilities/utstate.c
+++ b/drivers/acpi/utilities/utstate.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c
index 3538f69..de3276f 100644
--- a/drivers/acpi/utilities/utxface.c
+++ b/drivers/acpi/utilities/utxface.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -67,6 +67,7 @@
 
 	ACPI_FUNCTION_TRACE(acpi_initialize_subsystem);
 
+	acpi_gbl_startup_flags = ACPI_SUBSYSTEM_INITIALIZE;
 	ACPI_DEBUG_EXEC(acpi_ut_init_stack_ptr_trace());
 
 	/* Initialize the OS-Dependent layer */
@@ -127,20 +128,6 @@
 
 	ACPI_FUNCTION_TRACE(acpi_enable_subsystem);
 
-	/*
-	 * We must initialize the hardware before we can enable ACPI.
-	 * The values from the FADT are validated here.
-	 */
-	if (!(flags & ACPI_NO_HARDWARE_INIT)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-				  "[Init] Initializing ACPI hardware\n"));
-
-		status = acpi_hw_initialize();
-		if (ACPI_FAILURE(status)) {
-			return_ACPI_STATUS(status);
-		}
-	}
-
 	/* Enable ACPI mode */
 
 	if (!(flags & ACPI_NO_ACPI_ENABLE)) {
@@ -398,7 +385,6 @@
 {
 	struct acpi_system_info *info_ptr;
 	acpi_status status;
-	u32 i;
 
 	ACPI_FUNCTION_TRACE(acpi_get_system_info);
 
@@ -431,9 +417,7 @@
 
 	/* Timer resolution - 24 or 32 bits  */
 
-	if (!acpi_gbl_FADT) {
-		info_ptr->timer_resolution = 0;
-	} else if (acpi_gbl_FADT->tmr_val_ext == 0) {
+	if (acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) {
 		info_ptr->timer_resolution = 24;
 	} else {
 		info_ptr->timer_resolution = 32;
@@ -449,13 +433,6 @@
 	info_ptr->debug_layer = acpi_dbg_layer;
 	info_ptr->debug_level = acpi_dbg_level;
 
-	/* Current status of the ACPI tables, per table type */
-
-	info_ptr->num_table_types = ACPI_TABLE_ID_MAX + 1;
-	for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) {
-		info_ptr->table_info[i].count = acpi_gbl_table_lists[i].count;
-	}
-
 	return_ACPI_STATUS(AE_OK);
 }
 
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 3d54680..e0b97ad 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -32,6 +32,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 
+#include <linux/backlight.h>
 #include <asm/uaccess.h>
 
 #include <acpi/acpi_bus.h>
@@ -56,6 +57,12 @@
 
 #define ACPI_VIDEO_HEAD_INVALID		(~0u - 1)
 #define ACPI_VIDEO_HEAD_END		(~0u)
+#define MAX_NAME_LEN	20
+
+#define ACPI_VIDEO_DISPLAY_CRT	1
+#define ACPI_VIDEO_DISPLAY_TV	2
+#define ACPI_VIDEO_DISPLAY_DVI	3
+#define ACPI_VIDEO_DISPLAY_LCD	4
 
 #define _COMPONENT		ACPI_VIDEO_COMPONENT
 ACPI_MODULE_NAME("acpi_video")
@@ -66,16 +73,14 @@
 
 static int acpi_video_bus_add(struct acpi_device *device);
 static int acpi_video_bus_remove(struct acpi_device *device, int type);
-static int acpi_video_bus_match(struct acpi_device *device,
-				struct acpi_driver *driver);
 
 static struct acpi_driver acpi_video_bus = {
 	.name = ACPI_VIDEO_DRIVER_NAME,
 	.class = ACPI_VIDEO_CLASS,
+	.ids = ACPI_VIDEO_HID,
 	.ops = {
 		.add = acpi_video_bus_add,
 		.remove = acpi_video_bus_remove,
-		.match = acpi_video_bus_match,
 		},
 };
 
@@ -133,20 +138,21 @@
 	u8 crt:1;
 	u8 lcd:1;
 	u8 tvout:1;
+	u8 dvi:1;
 	u8 bios:1;
 	u8 unknown:1;
-	u8 reserved:3;
+	u8 reserved:2;
 };
 
 struct acpi_video_device_cap {
 	u8 _ADR:1;		/*Return the unique ID */
 	u8 _BCL:1;		/*Query list of brightness control levels supported */
 	u8 _BCM:1;		/*Set the brightness level */
+	u8 _BQC:1;		/* Get current brightness level */
 	u8 _DDC:1;		/*Return the EDID for this device */
 	u8 _DCS:1;		/*Return status of output device */
 	u8 _DGS:1;		/*Query graphics state */
 	u8 _DSS:1;		/*Device state set */
-	u8 _reserved:1;
 };
 
 struct acpi_video_device_brightness {
@@ -163,6 +169,8 @@
 	struct acpi_video_bus *video;
 	struct acpi_device *dev;
 	struct acpi_video_device_brightness *brightness;
+	struct backlight_device *backlight;
+	struct backlight_properties *data;
 };
 
 /* bus */
@@ -257,11 +265,35 @@
 				   struct acpi_video_device *device);
 static int acpi_video_device_enumerate(struct acpi_video_bus *video);
 static int acpi_video_switch_output(struct acpi_video_bus *video, int event);
+static int acpi_video_device_lcd_set_level(struct acpi_video_device *device,
+			int level);
+static int acpi_video_device_lcd_get_level_current(
+			struct acpi_video_device *device,
+			unsigned long *level);
 static int acpi_video_get_next_level(struct acpi_video_device *device,
 				     u32 level_current, u32 event);
 static void acpi_video_switch_brightness(struct acpi_video_device *device,
 					 int event);
 
+/*backlight device sysfs support*/
+static int acpi_video_get_brightness(struct backlight_device *bd)
+{
+	unsigned long cur_level;
+	struct acpi_video_device *vd =
+		(struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+	acpi_video_device_lcd_get_level_current(vd, &cur_level);
+	return (int) cur_level;
+}
+
+static int acpi_video_set_brightness(struct backlight_device *bd)
+{
+	int request_level = bd->props->brightness;
+	struct acpi_video_device *vd =
+		(struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+	acpi_video_device_lcd_set_level(vd, request_level);
+	return 0;
+}
+
 /* --------------------------------------------------------------------------
                                Video Management
    -------------------------------------------------------------------------- */
@@ -499,6 +531,7 @@
 	acpi_integer status;
 	acpi_handle h_dummy1;
 	int i;
+	u32 max_level = 0;
 	union acpi_object *obj = NULL;
 	struct acpi_video_device_brightness *br = NULL;
 
@@ -514,6 +547,8 @@
 	if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) {
 		device->cap._BCM = 1;
 	}
+	if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1)))
+		device->cap._BQC = 1;
 	if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) {
 		device->cap._DDC = 1;
 	}
@@ -550,6 +585,8 @@
 					continue;
 				}
 				br->levels[count] = (u32) o->integer.value;
+				if (br->levels[count] > max_level)
+					max_level = br->levels[count];
 				count++;
 			}
 		      out:
@@ -568,6 +605,37 @@
 
 	kfree(obj);
 
+	if (device->cap._BCL && device->cap._BCM && device->cap._BQC){
+		unsigned long tmp;
+		static int count = 0;
+		char *name;
+		struct backlight_properties *acpi_video_data;
+
+		name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
+		if (!name)
+			return;
+
+		acpi_video_data = kzalloc(
+			sizeof(struct backlight_properties),
+			GFP_KERNEL);
+		if (!acpi_video_data){
+			kfree(name);
+			return;
+		}
+		acpi_video_data->owner = THIS_MODULE;
+		acpi_video_data->get_brightness =
+			acpi_video_get_brightness;
+		acpi_video_data->update_status =
+			acpi_video_set_brightness;
+		sprintf(name, "acpi_video%d", count++);
+		device->data = acpi_video_data;
+		acpi_video_data->max_brightness = max_level;
+		acpi_video_device_lcd_get_level_current(device, &tmp);
+		acpi_video_data->brightness = (int)tmp;
+		device->backlight = backlight_device_register(name,
+			NULL, device, acpi_video_data);
+		kfree(name);
+	}
 	return;
 }
 
@@ -668,6 +736,8 @@
 		seq_printf(seq, "LCD\n");
 	else if (dev->flags.tvout)
 		seq_printf(seq, "TVOUT\n");
+	else if (dev->flags.dvi)
+		seq_printf(seq, "DVI\n");
 	else
 		seq_printf(seq, "UNKNOWN\n");
 
@@ -1242,6 +1312,16 @@
    -------------------------------------------------------------------------- */
 
 /* device interface */
+static struct acpi_video_device_attrib*
+acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id)
+{
+	int count;
+
+	for(count = 0; count < video->attached_count; count++)
+		if((video->attached_array[count].value.int_val & 0xffff) == device_id)
+			return &(video->attached_array[count].value.attrib);
+	return NULL;
+}
 
 static int
 acpi_video_bus_get_one_device(struct acpi_device *device,
@@ -1250,7 +1330,7 @@
 	unsigned long device_id;
 	int status;
 	struct acpi_video_device *data;
-
+	struct acpi_video_device_attrib* attribute;
 
 	if (!device || !video)
 		return -EINVAL;
@@ -1271,20 +1351,30 @@
 		data->video = video;
 		data->dev = device;
 
-		switch (device_id & 0xffff) {
-		case 0x0100:
-			data->flags.crt = 1;
-			break;
-		case 0x0400:
-			data->flags.lcd = 1;
-			break;
-		case 0x0200:
-			data->flags.tvout = 1;
-			break;
-		default:
+		attribute = acpi_video_get_device_attr(video, device_id);
+
+		if((attribute != NULL) && attribute->device_id_scheme) {
+			switch (attribute->display_type) {
+			case ACPI_VIDEO_DISPLAY_CRT:
+				data->flags.crt = 1;
+				break;
+			case ACPI_VIDEO_DISPLAY_TV:
+				data->flags.tvout = 1;
+				break;
+			case ACPI_VIDEO_DISPLAY_DVI:
+				data->flags.dvi = 1;
+				break;
+			case ACPI_VIDEO_DISPLAY_LCD:
+				data->flags.lcd = 1;
+				break;
+			default:
+				data->flags.unknown = 1;
+				break;
+			}
+			if(attribute->bios_can_detect)
+				data->flags.bios = 1;
+		} else
 			data->flags.unknown = 1;
-			break;
-		}
 
 		acpi_video_device_bind(video, data);
 		acpi_video_device_find_cap(data);
@@ -1588,7 +1678,10 @@
 	status = acpi_remove_notify_handler(device->dev->handle,
 					    ACPI_DEVICE_NOTIFY,
 					    acpi_video_device_notify);
-
+	if (device->backlight){
+		backlight_device_unregister(device->backlight);
+		kfree(device->data);
+	}
 	return 0;
 }
 
@@ -1790,39 +1883,6 @@
 	return 0;
 }
 
-static int
-acpi_video_bus_match(struct acpi_device *device, struct acpi_driver *driver)
-{
-	acpi_handle h_dummy1;
-	acpi_handle h_dummy2;
-	acpi_handle h_dummy3;
-
-
-	if (!device || !driver)
-		return -EINVAL;
-
-	/* Since there is no HID, CID for ACPI Video drivers, we have
-	 * to check well known required nodes for each feature we support.
-	 */
-
-	/* Does this device able to support video switching ? */
-	if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
-	    ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
-		return 0;
-
-	/* Does this device able to retrieve a video ROM ? */
-	if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
-		return 0;
-
-	/* Does this device able to configure which video head to be POSTed ? */
-	if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
-	    ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
-	    ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
-		return 0;
-
-	return -ENODEV;
-}
-
 static int __init acpi_video_init(void)
 {
 	int result = 0;
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 48616c6..e2796fb 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1173,7 +1173,7 @@
 		 * dangerous, we need to know more about them.  Print
 		 * more of it.
 		 */
-		const u32 *f = pp->rx_fis + RX_FIS_SDB;
+		const __le32 *f = pp->rx_fis + RX_FIS_SDB;
 
 		ata_port_printk(ap, KERN_INFO, "Spurious SDB FIS during NCQ "
 				"issue=0x%x SAct=0x%x FIS=%08x:%08x%s\n",
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index 46d8a94..5f4e82a 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -116,7 +116,7 @@
 {
 	if (sc_reg > SCR_CONTROL)
 		return 0xffffffffU;
-	return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+	return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
 }
 
 
@@ -125,7 +125,7 @@
 {
 	if (sc_reg > SCR_CONTROL)
 		return;
-	writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+	writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
 }
 
 
@@ -262,7 +262,7 @@
 
 static u8 k2_stat_check_status(struct ata_port *ap)
 {
-       	return readl((void *) ap->ioaddr.status_addr);
+       	return readl((void __iomem *) ap->ioaddr.status_addr);
 }
 
 #ifdef CONFIG_PPC_OF
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 8bf2ca2..96def1d 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -364,7 +364,7 @@
 
 	class_name = kmalloc(size, GFP_KERNEL);
 	if (!class_name)
-		return ERR_PTR(-ENOMEM);
+		return NULL;
 
 	strcpy(class_name, name);
 	strcat(class_name, ":");
@@ -411,8 +411,11 @@
 		return 0;
 
 	class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
-	error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
-				  class_name);
+	if (class_name)
+		error = sysfs_create_link(&class_dev->dev->kobj,
+					  &class_dev->kobj, class_name);
+	else
+		error = -ENOMEM;
 	kfree(class_name);
 	return error;
 }
@@ -425,7 +428,8 @@
 		return;
 
 	class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
-	sysfs_remove_link(&class_dev->dev->kobj, class_name);
+	if (class_name)
+		sysfs_remove_link(&class_dev->dev->kobj, class_name);
 	kfree(class_name);
 }
 #else
@@ -863,9 +867,12 @@
 	if (class_dev->dev) {
 		new_class_name = make_class_name(class_dev->class->name,
 						 &class_dev->kobj);
-		sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
-				  new_class_name);
-		sysfs_remove_link(&class_dev->dev->kobj, old_class_name);
+		if (new_class_name)
+			sysfs_create_link(&class_dev->dev->kobj,
+					  &class_dev->kobj, new_class_name);
+		if (old_class_name)
+			sysfs_remove_link(&class_dev->dev->kobj,
+						old_class_name);
 	}
 #endif
 	class_device_put(class_dev);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 67b79a7..e136142 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -95,6 +95,8 @@
 
 	if (dev->release)
 		dev->release(dev);
+	else if (dev->type && dev->type->release)
+		dev->type->release(dev);
 	else if (dev->class && dev->class->dev_release)
 		dev->class->dev_release(dev);
 	else {
@@ -154,25 +156,47 @@
 			       "MINOR=%u", MINOR(dev->devt));
 	}
 
-#ifdef CONFIG_SYSFS_DEPRECATED
-	/* add bus name (same as SUBSYSTEM, deprecated) */
-	if (dev->bus)
-		add_uevent_var(envp, num_envp, &i,
-			       buffer, buffer_size, &length,
-			       "PHYSDEVBUS=%s", dev->bus->name);
-#endif
-
-	/* add driver name (PHYSDEV* values are deprecated)*/
-	if (dev->driver) {
+	if (dev->driver)
 		add_uevent_var(envp, num_envp, &i,
 			       buffer, buffer_size, &length,
 			       "DRIVER=%s", dev->driver->name);
+
 #ifdef CONFIG_SYSFS_DEPRECATED
+	if (dev->class) {
+		struct device *parent = dev->parent;
+
+		/* find first bus device in parent chain */
+		while (parent && !parent->bus)
+			parent = parent->parent;
+		if (parent && parent->bus) {
+			const char *path;
+
+			path = kobject_get_path(&parent->kobj, GFP_KERNEL);
+			add_uevent_var(envp, num_envp, &i,
+				       buffer, buffer_size, &length,
+				       "PHYSDEVPATH=%s", path);
+			kfree(path);
+
+			add_uevent_var(envp, num_envp, &i,
+				       buffer, buffer_size, &length,
+				       "PHYSDEVBUS=%s", parent->bus->name);
+
+			if (parent->driver)
+				add_uevent_var(envp, num_envp, &i,
+					       buffer, buffer_size, &length,
+					       "PHYSDEVDRIVER=%s", parent->driver->name);
+		}
+	} else if (dev->bus) {
 		add_uevent_var(envp, num_envp, &i,
 			       buffer, buffer_size, &length,
-			       "PHYSDEVDRIVER=%s", dev->driver->name);
-#endif
+			       "PHYSDEVBUS=%s", dev->bus->name);
+
+		if (dev->driver)
+			add_uevent_var(envp, num_envp, &i,
+				       buffer, buffer_size, &length,
+				       "PHYSDEVDRIVER=%s", dev->driver->name);
 	}
+#endif
 
 	/* terminate, set to next free slot, shrink available space */
 	envp[i] = NULL;
@@ -184,19 +208,25 @@
 	if (dev->bus && dev->bus->uevent) {
 		/* have the bus specific function add its stuff */
 		retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size);
-			if (retval) {
-			pr_debug ("%s - uevent() returned %d\n",
+		if (retval)
+			pr_debug ("%s: bus uevent() returned %d\n",
 				  __FUNCTION__, retval);
-		}
 	}
 
 	if (dev->class && dev->class->dev_uevent) {
 		/* have the class specific function add its stuff */
 		retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size);
-			if (retval) {
-				pr_debug("%s - dev_uevent() returned %d\n",
-					 __FUNCTION__, retval);
-		}
+		if (retval)
+			pr_debug("%s: class uevent() returned %d\n",
+				 __FUNCTION__, retval);
+	}
+
+	if (dev->type && dev->type->uevent) {
+		/* have the device type specific fuction add its stuff */
+		retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size);
+		if (retval)
+			pr_debug("%s: dev_type uevent() returned %d\n",
+				 __FUNCTION__, retval);
 	}
 
 	return retval;
@@ -247,37 +277,50 @@
 static int device_add_attrs(struct device *dev)
 {
 	struct class *class = dev->class;
+	struct device_type *type = dev->type;
 	int error = 0;
 	int i;
 
-	if (!class)
-		return 0;
-
-	if (class->dev_attrs) {
+	if (class && class->dev_attrs) {
 		for (i = 0; attr_name(class->dev_attrs[i]); i++) {
 			error = device_create_file(dev, &class->dev_attrs[i]);
 			if (error)
 				break;
 		}
+		if (error)
+			while (--i >= 0)
+				device_remove_file(dev, &class->dev_attrs[i]);
 	}
-	if (error)
-		while (--i >= 0)
-			device_remove_file(dev, &class->dev_attrs[i]);
+
+	if (type && type->attrs) {
+		for (i = 0; attr_name(type->attrs[i]); i++) {
+			error = device_create_file(dev, &type->attrs[i]);
+			if (error)
+				break;
+		}
+		if (error)
+			while (--i >= 0)
+				device_remove_file(dev, &type->attrs[i]);
+	}
+
 	return error;
 }
 
 static void device_remove_attrs(struct device *dev)
 {
 	struct class *class = dev->class;
+	struct device_type *type = dev->type;
 	int i;
 
-	if (!class)
-		return;
-
-	if (class->dev_attrs) {
+	if (class && class->dev_attrs) {
 		for (i = 0; attr_name(class->dev_attrs[i]); i++)
 			device_remove_file(dev, &class->dev_attrs[i]);
 	}
+
+	if (type && type->attrs) {
+		for (i = 0; attr_name(type->attrs[i]); i++)
+			device_remove_file(dev, &type->attrs[i]);
+	}
 }
 
 
@@ -390,22 +433,23 @@
 }
 
 #ifdef CONFIG_SYSFS_DEPRECATED
-static int setup_parent(struct device *dev, struct device *parent)
+static struct kobject * get_device_parent(struct device *dev,
+					  struct device *parent)
 {
 	/* Set the parent to the class, not the parent device */
 	/* this keeps sysfs from having a symlink to make old udevs happy */
 	if (dev->class)
-		dev->kobj.parent = &dev->class->subsys.kset.kobj;
+		return &dev->class->subsys.kset.kobj;
 	else if (parent)
-		dev->kobj.parent = &parent->kobj;
+		return &parent->kobj;
 
-	return 0;
+	return NULL;
 }
 #else
-static int virtual_device_parent(struct device *dev)
+static struct kobject * virtual_device_parent(struct device *dev)
 {
 	if (!dev->class)
-		return -ENODEV;
+		return ERR_PTR(-ENODEV);
 
 	if (!dev->class->virtual_dir) {
 		static struct kobject *virtual_dir = NULL;
@@ -415,25 +459,31 @@
 		dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name);
 	}
 
-	dev->kobj.parent = dev->class->virtual_dir;
-	return 0;
+	return dev->class->virtual_dir;
 }
 
-static int setup_parent(struct device *dev, struct device *parent)
+static struct kobject * get_device_parent(struct device *dev,
+					  struct device *parent)
 {
-	int error;
-
 	/* if this is a class device, and has no parent, create one */
 	if ((dev->class) && (parent == NULL)) {
-		error = virtual_device_parent(dev);
-		if (error)
-			return error;
+		return virtual_device_parent(dev);
 	} else if (parent)
-		dev->kobj.parent = &parent->kobj;
+		return &parent->kobj;
+	return NULL;
+}
 
+#endif
+static int setup_parent(struct device *dev, struct device *parent)
+{
+	struct kobject *kobj;
+	kobj = get_device_parent(dev, parent);
+	if (IS_ERR(kobj))
+		return PTR_ERR(kobj);
+	if (kobj)
+		dev->kobj.parent = kobj;
 	return 0;
 }
-#endif
 
 /**
  *	device_add - add device to device hierarchy.
@@ -520,9 +570,13 @@
 					  &dev->kobj, dev->bus_id);
 #ifdef CONFIG_SYSFS_DEPRECATED
 		if (parent) {
-			sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device");
-			class_name = make_class_name(dev->class->name, &dev->kobj);
-			sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name);
+			sysfs_create_link(&dev->kobj, &dev->parent->kobj,
+							"device");
+			class_name = make_class_name(dev->class->name,
+							&dev->kobj);
+			if (class_name)
+				sysfs_create_link(&dev->parent->kobj,
+						  &dev->kobj, class_name);
 		}
 #endif
 	}
@@ -535,7 +589,8 @@
 		goto PMError;
 	if ((error = bus_add_device(dev)))
 		goto BusError;
-	kobject_uevent(&dev->kobj, KOBJ_ADD);
+	if (!dev->uevent_suppress)
+		kobject_uevent(&dev->kobj, KOBJ_ADD);
 	if ((error = bus_attach_device(dev)))
 		goto AttachError;
 	if (parent)
@@ -665,7 +720,9 @@
 		if (parent) {
 			char *class_name = make_class_name(dev->class->name,
 							   &dev->kobj);
-			sysfs_remove_link(&dev->parent->kobj, class_name);
+			if (class_name)
+				sysfs_remove_link(&dev->parent->kobj,
+						  class_name);
 			kfree(class_name);
 			sysfs_remove_link(&dev->kobj, "device");
 		}
@@ -968,20 +1025,25 @@
 
 	class_name = make_class_name(dev->class->name, &dev->kobj);
 	if (!class_name) {
-		error = PTR_ERR(class_name);
-		class_name = NULL;
+		error = -ENOMEM;
 		goto out;
 	}
 	if (old_parent) {
 		sysfs_remove_link(&dev->kobj, "device");
 		sysfs_remove_link(&old_parent->kobj, class_name);
 	}
-	error = sysfs_create_link(&dev->kobj, &new_parent->kobj, "device");
-	if (error)
-		goto out;
-	error = sysfs_create_link(&new_parent->kobj, &dev->kobj, class_name);
-	if (error)
-		sysfs_remove_link(&dev->kobj, "device");
+	if (new_parent) {
+		error = sysfs_create_link(&dev->kobj, &new_parent->kobj,
+					  "device");
+		if (error)
+			goto out;
+		error = sysfs_create_link(&new_parent->kobj, &dev->kobj,
+					  class_name);
+		if (error)
+			sysfs_remove_link(&dev->kobj, "device");
+	}
+	else
+		error = 0;
 out:
 	kfree(class_name);
 	return error;
@@ -993,29 +1055,28 @@
 /**
  * device_move - moves a device to a new parent
  * @dev: the pointer to the struct device to be moved
- * @new_parent: the new parent of the device
+ * @new_parent: the new parent of the device (can by NULL)
  */
 int device_move(struct device *dev, struct device *new_parent)
 {
 	int error;
 	struct device *old_parent;
+	struct kobject *new_parent_kobj;
 
 	dev = get_device(dev);
 	if (!dev)
 		return -EINVAL;
 
-	if (!device_is_registered(dev)) {
-		error = -EINVAL;
-		goto out;
-	}
 	new_parent = get_device(new_parent);
-	if (!new_parent) {
-		error = -EINVAL;
+	new_parent_kobj = get_device_parent (dev, new_parent);
+	if (IS_ERR(new_parent_kobj)) {
+		error = PTR_ERR(new_parent_kobj);
+		put_device(new_parent);
 		goto out;
 	}
 	pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id,
-		new_parent->bus_id);
-	error = kobject_move(&dev->kobj, &new_parent->kobj);
+		 new_parent ? new_parent->bus_id : "<NULL>");
+	error = kobject_move(&dev->kobj, new_parent_kobj);
 	if (error) {
 		put_device(new_parent);
 		goto out;
@@ -1024,7 +1085,8 @@
 	dev->parent = new_parent;
 	if (old_parent)
 		klist_remove(&dev->knode_parent);
-	klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
+	if (new_parent)
+		klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
 	if (!dev->class)
 		goto out_put;
 	error = device_move_class_links(dev, old_parent, new_parent);
@@ -1032,7 +1094,8 @@
 		/* We ignore errors on cleanup since we're hosed anyway... */
 		device_move_class_links(dev, new_parent, old_parent);
 		if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
-			klist_remove(&dev->knode_parent);
+			if (new_parent)
+				klist_remove(&dev->knode_parent);
 			if (old_parent)
 				klist_add_tail(&dev->knode_parent,
 					       &old_parent->klist_children);
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 510e788..b5bf243 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -86,8 +86,12 @@
  */
 int device_bind_driver(struct device *dev)
 {
-	driver_bound(dev);
-	return driver_sysfs_add(dev);
+	int ret;
+
+	ret = driver_sysfs_add(dev);
+	if (!ret)
+		driver_bound(dev);
+	return ret;
 }
 
 struct stupid_thread_structure {
@@ -136,18 +140,17 @@
 	driver_sysfs_remove(dev);
 	dev->driver = NULL;
 
-	if (ret == -ENODEV || ret == -ENXIO) {
-		/* Driver matched, but didn't support device
-		 * or device not found.
-		 * Not an error; keep going.
-		 */
-		ret = 0;
-	} else {
+	if (ret != -ENODEV && ret != -ENXIO) {
 		/* driver matched but the probe failed */
 		printk(KERN_WARNING
 		       "%s: probe of %s failed with error %d\n",
 		       drv->name, dev->bus_id, ret);
 	}
+	/*
+	 * Ignore errors returned by ->probe so that the next driver can try
+	 * its luck.
+	 */
+	ret = 0;
 done:
 	kfree(data);
 	atomic_dec(&probe_count);
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 64558f4..c0a979a5 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -35,7 +35,7 @@
 	FW_STATUS_READY_NOHOTPLUG,
 };
 
-static int loading_timeout = 10;	/* In seconds */
+static int loading_timeout = 60;	/* In seconds */
 
 /* fw_lock could be moved to 'struct firmware_priv' but since it is just
  * guarding for corner cases a global lock should be OK */
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index f9c903b..30480f6 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -611,8 +611,15 @@
 
 int __init platform_bus_init(void)
 {
-	device_register(&platform_bus);
-	return bus_register(&platform_bus_type);
+	int error;
+
+	error = device_register(&platform_bus);
+	if (error)
+		return error;
+	error =  bus_register(&platform_bus_type);
+	if (error)
+		device_unregister(&platform_bus);
+	return error;
 }
 
 #ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 9e43e39..d08bb4e 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -610,6 +610,13 @@
 	help
 	  IBM Console device driver which makes use of RTAS
 
+config HVC_BEAT
+	bool "Toshiba's Beat Hypervisor Console support"
+	depends on PPC_CELLEB
+	select HVC_DRIVER
+	help
+	  Toshiba's Cell Reference Set Beat Console device driver
+
 config HVCS
 	tristate "IBM Hypervisor Virtual Console Server support"
 	depends on PPC_PSERIES
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index fc11063..ae8567c 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -45,6 +45,7 @@
 obj-$(CONFIG_HVC_CONSOLE)	+= hvc_vio.o hvsi.o
 obj-$(CONFIG_HVC_ISERIES)	+= hvc_iseries.o
 obj-$(CONFIG_HVC_RTAS)		+= hvc_rtas.o
+obj-$(CONFIG_HVC_BEAT)		+= hvc_beat.o
 obj-$(CONFIG_HVC_DRIVER)	+= hvc_console.o
 obj-$(CONFIG_RAW_DRIVER)	+= raw.o
 obj-$(CONFIG_SGI_SNSC)		+= snsc.o snsc_event.o
@@ -59,6 +60,8 @@
 obj-$(CONFIG_PRINTER)		+= lp.o
 obj-$(CONFIG_TIPAR)		+= tipar.o
 
+obj-$(CONFIG_APM_EMULATION)	+= apm-emulation.o
+
 obj-$(CONFIG_DTLK)		+= dtlk.o
 obj-$(CONFIG_R3964)		+= n_r3964.o
 obj-$(CONFIG_APPLICOM)		+= applicom.o
diff --git a/arch/arm/kernel/apm.c b/drivers/char/apm-emulation.c
similarity index 98%
rename from arch/arm/kernel/apm.c
rename to drivers/char/apm-emulation.c
index 2c37b70..179c7a3 100644
--- a/arch/arm/kernel/apm.c
+++ b/drivers/char/apm-emulation.c
@@ -1,5 +1,5 @@
 /*
- * bios-less APM driver for ARM Linux 
+ * bios-less APM driver for ARM Linux
  *  Jamey Hicks <jamey@crl.dec.com>
  *  adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com)
  *
@@ -19,6 +19,7 @@
 #include <linux/capability.h>
 #include <linux/sched.h>
 #include <linux/pm.h>
+#include <linux/apm-emulation.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
@@ -27,7 +28,6 @@
 #include <linux/kthread.h>
 #include <linux/delay.h>
 
-#include <asm/apm.h> /* apm_power_info */
 #include <asm/system.h>
 
 /*
@@ -225,7 +225,7 @@
 	list_for_each_entry(as, &apm_user_list, list) {
 		if (as->suspend_state == SUSPEND_WAIT ||
 		    as->suspend_state == SUSPEND_ACKED) {
-	  		as->suspend_result = err;
+			as->suspend_result = err;
 			as->suspend_state = SUSPEND_DONE;
 		}
 	}
@@ -529,7 +529,7 @@
 		     info.battery_flag, info.battery_life,
 		     info.time, units);
 
- 	return ret;
+	return ret;
 }
 #endif
 
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 6dcdceb..85d99e2 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -532,11 +532,13 @@
 	int free;
 	unsigned long start;
 	unsigned long size;
+	struct drm_mm *mm;
 	void *private;
 } drm_mm_node_t;
 
 typedef struct drm_mm {
-	drm_mm_node_t root_node;
+	struct list_head fl_entry;
+	struct list_head ml_entry;
 } drm_mm_t;
 
 /**
@@ -843,9 +845,6 @@
 extern int drm_mem_info(char *buf, char **start, off_t offset,
 			int request, int *eof, void *data);
 extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area);
-extern void *drm_ioremap(unsigned long offset, unsigned long size,
-			 drm_device_t * dev);
-extern void drm_ioremapfree(void *pt, unsigned long size, drm_device_t * dev);
 
 extern DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type);
 extern int drm_free_agp(DRM_AGP_MEM * handle, int pages);
@@ -1053,33 +1052,18 @@
 extern drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
 				       unsigned long size,
 				       unsigned alignment);
-extern void drm_mm_put_block(drm_mm_t *mm, drm_mm_node_t *cur);
+void drm_mm_put_block(drm_mm_node_t * cur);
 extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size,
 					 unsigned alignment, int best_match);
 extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size);
 extern void drm_mm_takedown(drm_mm_t *mm);
+extern int drm_mm_clean(drm_mm_t *mm);
+extern unsigned long drm_mm_tail_space(drm_mm_t *mm);
+extern int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size);
+extern int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size);
 
-/* Inline replacements for DRM_IOREMAP macros */
-static __inline__ void drm_core_ioremap(struct drm_map *map,
-					struct drm_device *dev)
-{
-	map->handle = drm_ioremap(map->offset, map->size, dev);
-}
-
-#if 0
-static __inline__ void drm_core_ioremap_nocache(struct drm_map *map,
-						struct drm_device *dev)
-{
-	map->handle = drm_ioremap_nocache(map->offset, map->size, dev);
-}
-#endif  /*  0  */
-
-static __inline__ void drm_core_ioremapfree(struct drm_map *map,
-					    struct drm_device *dev)
-{
-	if (map->handle && map->size)
-		drm_ioremapfree(map->handle, map->size, dev);
-}
+extern void drm_core_ioremap(struct drm_map *map, struct drm_device *dev);
+extern void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev);
 
 static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev,
 						   unsigned int token)
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index 9f65f56..a6828cc 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -79,14 +79,14 @@
 
 	if (!use_hashed_handle) {
 		int ret;
-		hash->key = user_token;
+		hash->key = user_token >> PAGE_SHIFT;
 		ret = drm_ht_insert_item(&dev->map_hash, hash);
 		if (ret != -EINVAL)
 			return ret;
 	}
 	return drm_ht_just_insert_please(&dev->map_hash, hash,
 					 user_token, 32 - PAGE_SHIFT - 3,
-					 PAGE_SHIFT, DRM_MAP_HASH_OFFSET);
+					 0, DRM_MAP_HASH_OFFSET >> PAGE_SHIFT);
 }
 
 /**
@@ -178,11 +178,11 @@
 			}
 		}
 		if (map->type == _DRM_REGISTERS)
-			map->handle = drm_ioremap(map->offset, map->size, dev);
+			map->handle = ioremap(map->offset, map->size);
 		break;
 
 	case _DRM_SHM:
-		map->handle = vmalloc_32(map->size);
+		map->handle = vmalloc_user(map->size);
 		DRM_DEBUG("%lu %d %p\n",
 			  map->size, drm_order(map->size), map->handle);
 		if (!map->handle) {
@@ -238,7 +238,7 @@
 	list = drm_alloc(sizeof(*list), DRM_MEM_MAPS);
 	if (!list) {
 		if (map->type == _DRM_REGISTERS)
-			drm_ioremapfree(map->handle, map->size, dev);
+			iounmap(map->handle);
 		drm_free(map, sizeof(*map), DRM_MEM_MAPS);
 		return -EINVAL;
 	}
@@ -255,14 +255,14 @@
 	ret = drm_map_handle(dev, &list->hash, user_token, 0);
 	if (ret) {
 		if (map->type == _DRM_REGISTERS)
-			drm_ioremapfree(map->handle, map->size, dev);
+			iounmap(map->handle);
 		drm_free(map, sizeof(*map), DRM_MEM_MAPS);
 		drm_free(list, sizeof(*list), DRM_MEM_MAPS);
 		mutex_unlock(&dev->struct_mutex);
 		return ret;
 	}
 
-	list->user_token = list->hash.key;
+	list->user_token = list->hash.key << PAGE_SHIFT;
 	mutex_unlock(&dev->struct_mutex);
 
 	*maplist = list;
@@ -347,7 +347,8 @@
 
 		if (r_list->map == map) {
 			list_del(list);
-			drm_ht_remove_key(&dev->map_hash, r_list->user_token);
+			drm_ht_remove_key(&dev->map_hash,
+					  r_list->user_token >> PAGE_SHIFT);
 			drm_free(list, sizeof(*list), DRM_MEM_MAPS);
 			break;
 		}
@@ -362,7 +363,7 @@
 
 	switch (map->type) {
 	case _DRM_REGISTERS:
-		drm_ioremapfree(map->handle, map->size, dev);
+		iounmap(map->handle);
 		/* FALLTHROUGH */
 	case _DRM_FRAME_BUFFER:
 		if (drm_core_has_MTRR(dev) && map->mtrr >= 0) {
diff --git a/drivers/char/drm/drm_memory.c b/drivers/char/drm/drm_memory.c
index 5681cae..92a8670 100644
--- a/drivers/char/drm/drm_memory.c
+++ b/drivers/char/drm/drm_memory.c
@@ -79,28 +79,6 @@
 }
 
 #if __OS_HAS_AGP
-/*
- * Find the drm_map that covers the range [offset, offset+size).
- */
-static drm_map_t *drm_lookup_map(unsigned long offset,
-				 unsigned long size, drm_device_t * dev)
-{
-	struct list_head *list;
-	drm_map_list_t *r_list;
-	drm_map_t *map;
-
-	list_for_each(list, &dev->maplist->head) {
-		r_list = (drm_map_list_t *) list;
-		map = r_list->map;
-		if (!map)
-			continue;
-		if (map->offset <= offset
-		    && (offset + size) <= (map->offset + map->size))
-			return map;
-	}
-	return NULL;
-}
-
 static void *agp_remap(unsigned long offset, unsigned long size,
 		       drm_device_t * dev)
 {
@@ -169,13 +147,6 @@
 }
 
 #else  /*  __OS_HAS_AGP  */
-
-static inline drm_map_t *drm_lookup_map(unsigned long offset,
-					unsigned long size, drm_device_t * dev)
-{
-	return NULL;
-}
-
 static inline void *agp_remap(unsigned long offset, unsigned long size,
 			      drm_device_t * dev)
 {
@@ -184,57 +155,28 @@
 
 #endif				/* agp */
 
-void *drm_ioremap(unsigned long offset, unsigned long size,
-				drm_device_t * dev)
-{
-	if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) {
-		drm_map_t *map = drm_lookup_map(offset, size, dev);
-
-		if (map && map->type == _DRM_AGP)
-			return agp_remap(offset, size, dev);
-	}
-	return ioremap(offset, size);
-}
-EXPORT_SYMBOL(drm_ioremap);
-
-#if 0
-void *drm_ioremap_nocache(unsigned long offset,
-					unsigned long size, drm_device_t * dev)
-{
-	if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) {
-		drm_map_t *map = drm_lookup_map(offset, size, dev);
-
-		if (map && map->type == _DRM_AGP)
-			return agp_remap(offset, size, dev);
-	}
-	return ioremap_nocache(offset, size);
-}
-#endif  /*  0  */
-
-void drm_ioremapfree(void *pt, unsigned long size,
-				   drm_device_t * dev)
-{
-	/*
-	 * This is a bit ugly.  It would be much cleaner if the DRM API would use separate
-	 * routines for handling mappings in the AGP space.  Hopefully this can be done in
-	 * a future revision of the interface...
-	 */
-	if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture
-	    && ((unsigned long)pt >= VMALLOC_START
-		&& (unsigned long)pt < VMALLOC_END)) {
-		unsigned long offset;
-		drm_map_t *map;
-
-		offset = drm_follow_page(pt) | ((unsigned long)pt & ~PAGE_MASK);
-		map = drm_lookup_map(offset, size, dev);
-		if (map && map->type == _DRM_AGP) {
-			vunmap(pt);
-			return;
-		}
-	}
-
-	iounmap(pt);
-}
-EXPORT_SYMBOL(drm_ioremapfree);
-
 #endif				/* debug_memory */
+
+void drm_core_ioremap(struct drm_map *map, struct drm_device *dev)
+{
+	if (drm_core_has_AGP(dev) &&
+	    dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
+		map->handle = agp_remap(map->offset, map->size, dev);
+	else
+		map->handle = ioremap(map->offset, map->size);
+}
+EXPORT_SYMBOL(drm_core_ioremap);
+
+void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev)
+{
+	if (!map->handle || !map->size)
+		return;
+
+	if (drm_core_has_AGP(dev) &&
+	    dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
+		vunmap(map->handle);
+	else
+		iounmap(map->handle);
+}
+EXPORT_SYMBOL(drm_core_ioremapfree);
+
diff --git a/drivers/char/drm/drm_memory.h b/drivers/char/drm/drm_memory.h
index f1b97af..63e425b 100644
--- a/drivers/char/drm/drm_memory.h
+++ b/drivers/char/drm/drm_memory.h
@@ -56,26 +56,6 @@
 # endif
 #endif
 
-static inline unsigned long drm_follow_page(void *vaddr)
-{
-	pgd_t *pgd = pgd_offset_k((unsigned long)vaddr);
-	pud_t *pud = pud_offset(pgd, (unsigned long)vaddr);
-	pmd_t *pmd = pmd_offset(pud, (unsigned long)vaddr);
-	pte_t *ptep = pte_offset_kernel(pmd, (unsigned long)vaddr);
-	return pte_pfn(*ptep) << PAGE_SHIFT;
-}
-
 #else				/* __OS_HAS_AGP */
 
-static inline unsigned long drm_follow_page(void *vaddr)
-{
-	return 0;
-}
-
 #endif
-
-void *drm_ioremap(unsigned long offset, unsigned long size,
-				drm_device_t * dev);
-
-void drm_ioremapfree(void *pt, unsigned long size,
-				   drm_device_t * dev);
diff --git a/drivers/char/drm/drm_memory_debug.h b/drivers/char/drm/drm_memory_debug.h
index 74581af..6463271 100644
--- a/drivers/char/drm/drm_memory_debug.h
+++ b/drivers/char/drm/drm_memory_debug.h
@@ -205,76 +205,6 @@
 	}
 }
 
-void *drm_ioremap (unsigned long offset, unsigned long size,
-		    drm_device_t * dev) {
-	void *pt;
-
-	if (!size) {
-		DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
-			      "Mapping 0 bytes at 0x%08lx\n", offset);
-		return NULL;
-	}
-
-	if (!(pt = drm_ioremap(offset, size, dev))) {
-		spin_lock(&drm_mem_lock);
-		++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
-		spin_unlock(&drm_mem_lock);
-		return NULL;
-	}
-	spin_lock(&drm_mem_lock);
-	++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
-	drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
-	spin_unlock(&drm_mem_lock);
-	return pt;
-}
-
-#if 0
-void *drm_ioremap_nocache (unsigned long offset, unsigned long size,
-			    drm_device_t * dev) {
-	void *pt;
-
-	if (!size) {
-		DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
-			      "Mapping 0 bytes at 0x%08lx\n", offset);
-		return NULL;
-	}
-
-	if (!(pt = drm_ioremap_nocache(offset, size, dev))) {
-		spin_lock(&drm_mem_lock);
-		++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
-		spin_unlock(&drm_mem_lock);
-		return NULL;
-	}
-	spin_lock(&drm_mem_lock);
-	++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
-	drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
-	spin_unlock(&drm_mem_lock);
-	return pt;
-}
-#endif  /*  0  */
-
-void drm_ioremapfree (void *pt, unsigned long size, drm_device_t * dev) {
-	int alloc_count;
-	int free_count;
-
-	if (!pt)
-		DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
-			      "Attempt to free NULL pointer\n");
-	else
-		drm_ioremapfree(pt, size, dev);
-
-	spin_lock(&drm_mem_lock);
-	drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size;
-	free_count = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count;
-	alloc_count = drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
-	spin_unlock(&drm_mem_lock);
-	if (free_count > alloc_count) {
-		DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
-			      "Excess frees: %d frees, %d allocs\n",
-			      free_count, alloc_count);
-	}
-}
-
 #if __OS_HAS_AGP
 
 DRM_AGP_MEM *drm_alloc_agp (drm_device_t *dev, int pages, u32 type) {
diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c
index 617526b..9b46b85 100644
--- a/drivers/char/drm/drm_mm.c
+++ b/drivers/char/drm/drm_mm.c
@@ -42,36 +42,131 @@
  */
 
 #include "drmP.h"
+#include <linux/slab.h>
+
+unsigned long drm_mm_tail_space(drm_mm_t *mm)
+{
+	struct list_head *tail_node;
+	drm_mm_node_t *entry;
+
+	tail_node = mm->ml_entry.prev;
+	entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+	if (!entry->free)
+		return 0;
+
+	return entry->size;
+}
+
+int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size)
+{
+	struct list_head *tail_node;
+	drm_mm_node_t *entry;
+
+	tail_node = mm->ml_entry.prev;
+	entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+	if (!entry->free)
+		return -ENOMEM;
+
+	if (entry->size <= size)
+		return -ENOMEM;
+
+	entry->size -= size;
+	return 0;
+}
+
+
+static int drm_mm_create_tail_node(drm_mm_t *mm,
+			    unsigned long start,
+			    unsigned long size)
+{
+	drm_mm_node_t *child;
+
+	child = (drm_mm_node_t *)
+		drm_alloc(sizeof(*child), DRM_MEM_MM);
+	if (!child)
+		return -ENOMEM;
+
+	child->free = 1;
+	child->size = size;
+	child->start = start;
+	child->mm = mm;
+
+	list_add_tail(&child->ml_entry, &mm->ml_entry);
+	list_add_tail(&child->fl_entry, &mm->fl_entry);
+
+	return 0;
+}
+
+
+int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size)
+{
+	struct list_head *tail_node;
+	drm_mm_node_t *entry;
+
+	tail_node = mm->ml_entry.prev;
+	entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+	if (!entry->free) {
+		return drm_mm_create_tail_node(mm, entry->start + entry->size, size);
+	}
+	entry->size += size;
+	return 0;
+}
+
+static drm_mm_node_t *drm_mm_split_at_start(drm_mm_node_t *parent,
+					    unsigned long size)
+{
+	drm_mm_node_t *child;
+
+	child = (drm_mm_node_t *)
+		drm_alloc(sizeof(*child), DRM_MEM_MM);
+	if (!child)
+		return NULL;
+
+	INIT_LIST_HEAD(&child->fl_entry);
+
+	child->free = 0;
+	child->size = size;
+	child->start = parent->start;
+	child->mm = parent->mm;
+
+	list_add_tail(&child->ml_entry, &parent->ml_entry);
+	INIT_LIST_HEAD(&child->fl_entry);
+
+	parent->size -= size;
+	parent->start += size;
+	return child;
+}
+
+
 
 drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
 				unsigned long size, unsigned alignment)
 {
 
+	drm_mm_node_t *align_splitoff = NULL;
 	drm_mm_node_t *child;
+	unsigned tmp = 0;
 
 	if (alignment)
-		size += alignment - 1;
+		tmp = parent->start % alignment;
+
+	if (tmp) {
+		align_splitoff = drm_mm_split_at_start(parent, alignment - tmp);
+		if (!align_splitoff)
+			return NULL;
+	}
 
 	if (parent->size == size) {
 		list_del_init(&parent->fl_entry);
 		parent->free = 0;
 		return parent;
 	} else {
-		child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
-		if (!child)
-			return NULL;
-
-		INIT_LIST_HEAD(&child->ml_entry);
-		INIT_LIST_HEAD(&child->fl_entry);
-
-		child->free = 0;
-		child->size = size;
-		child->start = parent->start;
-
-		list_add_tail(&child->ml_entry, &parent->ml_entry);
-		parent->size -= size;
-		parent->start += size;
+		child = drm_mm_split_at_start(parent, size);
 	}
+
+	if (align_splitoff)
+		drm_mm_put_block(align_splitoff);
+
 	return child;
 }
 
@@ -80,12 +175,12 @@
  * Otherwise add to the free stack.
  */
 
-void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur)
+void drm_mm_put_block(drm_mm_node_t * cur)
 {
 
-	drm_mm_node_t *list_root = &mm->root_node;
+	drm_mm_t *mm = cur->mm;
 	struct list_head *cur_head = &cur->ml_entry;
-	struct list_head *root_head = &list_root->ml_entry;
+	struct list_head *root_head = &mm->ml_entry;
 	drm_mm_node_t *prev_node = NULL;
 	drm_mm_node_t *next_node;
 
@@ -116,7 +211,7 @@
 	}
 	if (!merged) {
 		cur->free = 1;
-		list_add(&cur->fl_entry, &list_root->fl_entry);
+		list_add(&cur->fl_entry, &mm->fl_entry);
 	} else {
 		list_del(&cur->ml_entry);
 		drm_free(cur, sizeof(*cur), DRM_MEM_MM);
@@ -128,20 +223,30 @@
 				  unsigned alignment, int best_match)
 {
 	struct list_head *list;
-	const struct list_head *free_stack = &mm->root_node.fl_entry;
+	const struct list_head *free_stack = &mm->fl_entry;
 	drm_mm_node_t *entry;
 	drm_mm_node_t *best;
 	unsigned long best_size;
+	unsigned wasted;
 
 	best = NULL;
 	best_size = ~0UL;
 
-	if (alignment)
-		size += alignment - 1;
-
 	list_for_each(list, free_stack) {
 		entry = list_entry(list, drm_mm_node_t, fl_entry);
-		if (entry->size >= size) {
+		wasted = 0;
+
+		if (entry->size < size)
+			continue;
+
+		if (alignment) {
+			register unsigned tmp = entry->start % alignment;
+			if (tmp)
+				wasted += alignment - tmp;
+		}
+
+
+		if (entry->size >= size + wasted) {
 			if (!best_match)
 				return entry;
 			if (size < best_size) {
@@ -154,40 +259,32 @@
 	return best;
 }
 
+int drm_mm_clean(drm_mm_t * mm)
+{
+	struct list_head *head = &mm->ml_entry;
+
+	return (head->next->next == head);
+}
+
 int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
 {
-	drm_mm_node_t *child;
+	INIT_LIST_HEAD(&mm->ml_entry);
+	INIT_LIST_HEAD(&mm->fl_entry);
 
-	INIT_LIST_HEAD(&mm->root_node.ml_entry);
-	INIT_LIST_HEAD(&mm->root_node.fl_entry);
-	child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
-	if (!child)
-		return -ENOMEM;
-
-	INIT_LIST_HEAD(&child->ml_entry);
-	INIT_LIST_HEAD(&child->fl_entry);
-
-	child->start = start;
-	child->size = size;
-	child->free = 1;
-
-	list_add(&child->fl_entry, &mm->root_node.fl_entry);
-	list_add(&child->ml_entry, &mm->root_node.ml_entry);
-
-	return 0;
+	return drm_mm_create_tail_node(mm, start, size);
 }
 
 EXPORT_SYMBOL(drm_mm_init);
 
 void drm_mm_takedown(drm_mm_t * mm)
 {
-	struct list_head *bnode = mm->root_node.fl_entry.next;
+	struct list_head *bnode = mm->fl_entry.next;
 	drm_mm_node_t *entry;
 
 	entry = list_entry(bnode, drm_mm_node_t, fl_entry);
 
-	if (entry->ml_entry.next != &mm->root_node.ml_entry ||
-	    entry->fl_entry.next != &mm->root_node.fl_entry) {
+	if (entry->ml_entry.next != &mm->ml_entry ||
+	    entry->fl_entry.next != &mm->fl_entry) {
 		DRM_ERROR("Memory manager not clean. Delaying takedown\n");
 		return;
 	}
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index 09398d5..ad54b84 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -226,12 +226,14 @@
 	{0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x1106, 0x3118, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \
 	{0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-	{0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \
 	{0, 0, 0}
 
 #define i810_PCI_IDS \
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c
index 62d5fe1..7fd0da7 100644
--- a/drivers/char/drm/drm_proc.c
+++ b/drivers/char/drm/drm_proc.c
@@ -500,7 +500,7 @@
 	for (pt = dev->vmalist; pt; pt = pt->next) {
 		if (!(vma = pt->vma))
 			continue;
-		DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
+		DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000",
 			       pt->pid,
 			       vma->vm_start,
 			       vma->vm_end,
@@ -510,7 +510,7 @@
 			       vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
 			       vma->vm_flags & VM_LOCKED ? 'l' : '-',
 			       vma->vm_flags & VM_IO ? 'i' : '-',
-			       vma->vm_pgoff << PAGE_SHIFT);
+			       vma->vm_pgoff);
 
 #if defined(__i386__)
 		pgprot = pgprot_val(vma->vm_page_prot);
diff --git a/drivers/char/drm/drm_sman.c b/drivers/char/drm/drm_sman.c
index 19c81d2..e15db6d 100644
--- a/drivers/char/drm/drm_sman.c
+++ b/drivers/char/drm/drm_sman.c
@@ -101,10 +101,9 @@
 
 static void drm_sman_mm_free(void *private, void *ref)
 {
-	drm_mm_t *mm = (drm_mm_t *) private;
 	drm_mm_node_t *node = (drm_mm_node_t *) ref;
 
-	drm_mm_put_block(mm, node);
+	drm_mm_put_block(node);
 }
 
 static void drm_sman_mm_destroy(void *private)
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index b9cfc07..54a6328 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -70,7 +70,7 @@
 	if (!dev->agp || !dev->agp->cant_use_aperture)
 		goto vm_nopage_error;
 
-	if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash))
+	if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash))
 		goto vm_nopage_error;
 
 	r_list = drm_hash_entry(hash, drm_map_list_t, hash);
@@ -227,7 +227,7 @@
 							   map->size);
 					DRM_DEBUG("mtrr_del = %d\n", retcode);
 				}
-				drm_ioremapfree(map->handle, map->size, dev);
+				iounmap(map->handle);
 				break;
 			case _DRM_SHM:
 				vfree(map->handle);
@@ -463,8 +463,8 @@
 	lock_kernel();
 	dev = priv->head->dev;
 	dma = dev->dma;
-	DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
-		  vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
+	DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
+		  vma->vm_start, vma->vm_end, vma->vm_pgoff);
 
 	/* Length must match exact page count */
 	if (!dma || (length >> PAGE_SHIFT) != dma->page_count) {
@@ -537,8 +537,8 @@
 	unsigned long offset = 0;
 	drm_hash_item_t *hash;
 
-	DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
-		  vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
+	DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
+		  vma->vm_start, vma->vm_end, vma->vm_pgoff);
 
 	if (!priv->authenticated)
 		return -EACCES;
@@ -547,7 +547,7 @@
 	 * the AGP mapped at physical address 0
 	 * --BenH.
 	 */
-	if (!(vma->vm_pgoff << PAGE_SHIFT)
+	if (!vma->vm_pgoff
 #if __OS_HAS_AGP
 	    && (!dev->agp
 		|| dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE)
@@ -555,7 +555,7 @@
 	    )
 		return drm_mmap_dma(filp, vma);
 
-	if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) {
+	if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) {
 		DRM_ERROR("Could not find map\n");
 		return -EINVAL;
 	}
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index fa2de70..60cb4e4 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -219,8 +219,7 @@
 		    (drm_i810_private_t *) dev->dev_private;
 
 		if (dev_priv->ring.virtual_start) {
-			drm_ioremapfree((void *)dev_priv->ring.virtual_start,
-					dev_priv->ring.Size, dev);
+			drm_core_ioremapfree(&dev_priv->ring.map, dev);
 		}
 		if (dev_priv->hw_status_page) {
 			pci_free_consistent(dev->pdev, PAGE_SIZE,
@@ -236,9 +235,9 @@
 		for (i = 0; i < dma->buf_count; i++) {
 			drm_buf_t *buf = dma->buflist[i];
 			drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+
 			if (buf_priv->kernel_virtual && buf->total)
-				drm_ioremapfree(buf_priv->kernel_virtual,
-						buf->total, dev);
+				drm_core_ioremapfree(&buf_priv->map, dev);
 		}
 	}
 	return 0;
@@ -311,8 +310,15 @@
 
 		*buf_priv->in_use = I810_BUF_FREE;
 
-		buf_priv->kernel_virtual = drm_ioremap(buf->bus_address,
-						       buf->total, dev);
+		buf_priv->map.offset = buf->bus_address;
+		buf_priv->map.size = buf->total;
+		buf_priv->map.type = _DRM_AGP;
+		buf_priv->map.flags = 0;
+		buf_priv->map.mtrr = 0;
+
+		drm_core_ioremap(&buf_priv->map, dev);
+		buf_priv->kernel_virtual = buf_priv->map.handle;
+
 	}
 	return 0;
 }
@@ -363,18 +369,24 @@
 	dev_priv->ring.End = init->ring_end;
 	dev_priv->ring.Size = init->ring_size;
 
-	dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base +
-						   init->ring_start,
-						   init->ring_size, dev);
+	dev_priv->ring.map.offset = dev->agp->base + init->ring_start;
+	dev_priv->ring.map.size = init->ring_size;
+	dev_priv->ring.map.type = _DRM_AGP;
+	dev_priv->ring.map.flags = 0;
+	dev_priv->ring.map.mtrr = 0;
 
-	if (dev_priv->ring.virtual_start == NULL) {
+	drm_core_ioremap(&dev_priv->ring.map, dev);
+
+	if (dev_priv->ring.map.handle == NULL) {
 		dev->dev_private = (void *)dev_priv;
 		i810_dma_cleanup(dev);
 		DRM_ERROR("can not ioremap virtual address for"
 			  " ring buffer\n");
-		return -ENOMEM;
+		return DRM_ERR(ENOMEM);
 	}
 
+	dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+
 	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
 
 	dev_priv->w = init->w;
diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h
index e8cf3ff..e6df49f 100644
--- a/drivers/char/drm/i810_drv.h
+++ b/drivers/char/drm/i810_drv.h
@@ -61,6 +61,7 @@
 	int currently_mapped;
 	void *virtual;
 	void *kernel_virtual;
+	drm_local_map_t map;
 } drm_i810_buf_priv_t;
 
 typedef struct _drm_i810_ring_buffer {
@@ -72,6 +73,7 @@
 	int head;
 	int tail;
 	int space;
+	drm_local_map_t map;
 } drm_i810_ring_buffer_t;
 
 typedef struct drm_i810_private {
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index 4f0e574..9522445 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -223,8 +223,7 @@
 		    (drm_i830_private_t *) dev->dev_private;
 
 		if (dev_priv->ring.virtual_start) {
-			drm_ioremapfree((void *)dev_priv->ring.virtual_start,
-					dev_priv->ring.Size, dev);
+			drm_core_ioremapfree(&dev_priv->ring.map, dev);
 		}
 		if (dev_priv->hw_status_page) {
 			pci_free_consistent(dev->pdev, PAGE_SIZE,
@@ -242,8 +241,7 @@
 			drm_buf_t *buf = dma->buflist[i];
 			drm_i830_buf_priv_t *buf_priv = buf->dev_private;
 			if (buf_priv->kernel_virtual && buf->total)
-				drm_ioremapfree(buf_priv->kernel_virtual,
-						buf->total, dev);
+				drm_core_ioremapfree(&buf_priv->map, dev);
 		}
 	}
 	return 0;
@@ -320,8 +318,14 @@
 
 		*buf_priv->in_use = I830_BUF_FREE;
 
-		buf_priv->kernel_virtual = drm_ioremap(buf->bus_address,
-						       buf->total, dev);
+		buf_priv->map.offset = buf->bus_address;
+		buf_priv->map.size = buf->total;
+		buf_priv->map.type = _DRM_AGP;
+		buf_priv->map.flags = 0;
+		buf_priv->map.mtrr = 0;
+
+		drm_core_ioremap(&buf_priv->map, dev);
+		buf_priv->kernel_virtual = buf_priv->map.handle;
 	}
 	return 0;
 }
@@ -373,18 +377,24 @@
 	dev_priv->ring.End = init->ring_end;
 	dev_priv->ring.Size = init->ring_size;
 
-	dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base +
-						   init->ring_start,
-						   init->ring_size, dev);
+	dev_priv->ring.map.offset = dev->agp->base + init->ring_start;
+	dev_priv->ring.map.size = init->ring_size;
+	dev_priv->ring.map.type = _DRM_AGP;
+	dev_priv->ring.map.flags = 0;
+	dev_priv->ring.map.mtrr = 0;
 
-	if (dev_priv->ring.virtual_start == NULL) {
+	drm_core_ioremap(&dev_priv->ring.map, dev);
+
+	if (dev_priv->ring.map.handle == NULL) {
 		dev->dev_private = (void *)dev_priv;
 		i830_dma_cleanup(dev);
 		DRM_ERROR("can not ioremap virtual address for"
 			  " ring buffer\n");
-		return -ENOMEM;
+		return DRM_ERR(ENOMEM);
 	}
 
+	dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+
 	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
 
 	dev_priv->w = init->w;
diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h
index 85bc5be..e91f94a 100644
--- a/drivers/char/drm/i830_drv.h
+++ b/drivers/char/drm/i830_drv.h
@@ -68,6 +68,7 @@
 	int currently_mapped;
 	void __user *virtual;
 	void *kernel_virtual;
+	drm_local_map_t map;
 } drm_i830_buf_priv_t;
 
 typedef struct _drm_i830_ring_buffer {
@@ -79,6 +80,7 @@
 	int head;
 	int tail;
 	int space;
+	drm_local_map_t map;
 } drm_i830_ring_buffer_t;
 
 typedef struct drm_i830_private {
diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c
index a691ae7..c0539c6 100644
--- a/drivers/char/drm/via_dma.c
+++ b/drivers/char/drm/via_dma.c
@@ -190,6 +190,11 @@
 		return DRM_ERR(EFAULT);
 	}
 
+	if (dev_priv->chipset == VIA_DX9_0) {
+		DRM_ERROR("AGP DMA is not supported on this chip\n");
+		return DRM_ERR(EINVAL);
+	}
+
 	dev_priv->ring.map.offset = dev->agp->base + init->offset;
 	dev_priv->ring.map.size = init->size;
 	dev_priv->ring.map.type = 0;
@@ -480,6 +485,7 @@
 			VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
 			VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
 			VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
+			VIA_READ(VIA_REG_TRANSPACE);
 		}
 	}
 	return paused;
@@ -557,8 +563,9 @@
 
 	VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
 	VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
-
+	DRM_WRITEMEMORYBARRIER();
 	VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
+	VIA_READ(VIA_REG_TRANSPACE);
 }
 
 static void via_pad_cache(drm_via_private_t * dev_priv, int qwords)
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c
index 806f9ce..2054d57 100644
--- a/drivers/char/drm/via_dmablit.c
+++ b/drivers/char/drm/via_dmablit.c
@@ -218,7 +218,9 @@
 	VIA_WRITE(VIA_PCI_DMA_MR0  + engine*0x04, VIA_DMA_MR_CM | VIA_DMA_MR_TDIE);
 	VIA_WRITE(VIA_PCI_DMA_BCR0 + engine*0x10, 0);
 	VIA_WRITE(VIA_PCI_DMA_DPR0 + engine*0x10, vsg->chain_start);
+	DRM_WRITEMEMORYBARRIER();
 	VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DE | VIA_DMA_CSR_TS);
+	VIA_READ(VIA_PCI_DMA_CSR0 + engine*0x04);
 }
 
 /*
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
index d21b5b7..8b8778d 100644
--- a/drivers/char/drm/via_drv.h
+++ b/drivers/char/drm/via_drv.h
@@ -29,10 +29,10 @@
 
 #define DRIVER_NAME		"via"
 #define DRIVER_DESC		"VIA Unichrome / Pro"
-#define DRIVER_DATE		"20060529"
+#define DRIVER_DATE		"20061227"
 
 #define DRIVER_MAJOR		2
-#define DRIVER_MINOR		10
+#define DRIVER_MINOR		11
 #define DRIVER_PATCHLEVEL	0
 
 #include "via_verifier.h"
@@ -79,7 +79,7 @@
 	char pci_buf[VIA_PCI_BUF_SIZE];
 	const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
 	uint32_t num_fire_offsets;
-	int pro_group_a;
+	int chipset;
 	drm_via_irq_t via_irqs[VIA_NUM_IRQS];
 	unsigned num_irqs;
 	maskarray_t *irq_masks;
@@ -96,8 +96,9 @@
 } drm_via_private_t;
 
 enum via_family {
-	VIA_OTHER = 0,
-	VIA_PRO_GROUP_A,
+  VIA_OTHER = 0,     /* Baseline */
+  VIA_PRO_GROUP_A,   /* Another video engine and DMA commands */
+  VIA_DX9_0          /* Same video as pro_group_a, but 3D is unsupported */
 };
 
 /* VIA MMIO register access */
diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c
index c33d068..1ac5941 100644
--- a/drivers/char/drm/via_irq.c
+++ b/drivers/char/drm/via_irq.c
@@ -258,12 +258,16 @@
 		dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE;
 		dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING;
 
-		dev_priv->irq_masks = (dev_priv->pro_group_a) ?
-		    via_pro_group_a_irqs : via_unichrome_irqs;
-		dev_priv->num_irqs = (dev_priv->pro_group_a) ?
-		    via_num_pro_group_a : via_num_unichrome;
-		dev_priv->irq_map = (dev_priv->pro_group_a) ?
-			via_irqmap_pro_group_a : via_irqmap_unichrome;
+		if (dev_priv->chipset == VIA_PRO_GROUP_A ||
+		    dev_priv->chipset == VIA_DX9_0) {
+			dev_priv->irq_masks = via_pro_group_a_irqs;
+			dev_priv->num_irqs = via_num_pro_group_a;
+			dev_priv->irq_map = via_irqmap_pro_group_a;
+		} else {
+			dev_priv->irq_masks = via_unichrome_irqs;
+			dev_priv->num_irqs = via_num_unichrome;
+			dev_priv->irq_map = via_irqmap_unichrome;
+		}
 
 		for (i = 0; i < dev_priv->num_irqs; ++i) {
 			atomic_set(&cur_irq->irq_received, 0);
diff --git a/drivers/char/drm/via_map.c b/drivers/char/drm/via_map.c
index 782011e..4e3fc07 100644
--- a/drivers/char/drm/via_map.c
+++ b/drivers/char/drm/via_map.c
@@ -106,8 +106,7 @@
 
 	dev->dev_private = (void *)dev_priv;
 
-	if (chipset == VIA_PRO_GROUP_A)
-		dev_priv->pro_group_a = 1;
+	dev_priv->chipset = chipset;
 
 	ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
 	if (ret) {
diff --git a/drivers/char/drm/via_verifier.c b/drivers/char/drm/via_verifier.c
index 70c897c..2e7e080 100644
--- a/drivers/char/drm/via_verifier.c
+++ b/drivers/char/drm/via_verifier.c
@@ -306,6 +306,7 @@
 			unsigned long lo = ~0, hi = 0, tmp;
 			uint32_t *addr, *pitch, *height, tex;
 			unsigned i;
+			int npot;
 
 			if (end > 9)
 				end = 9;
@@ -316,12 +317,15 @@
 			    &(cur_seq->t_addr[tex = cur_seq->texture][start]);
 			pitch = &(cur_seq->pitch[tex][start]);
 			height = &(cur_seq->height[tex][start]);
-
+			npot = cur_seq->tex_npot[tex];
 			for (i = start; i <= end; ++i) {
 				tmp = *addr++;
 				if (tmp < lo)
 					lo = tmp;
-				tmp += (*height++ << *pitch++);
+				if (i == 0 && npot)
+					tmp += (*height++ * *pitch++);
+				else
+					tmp += (*height++ << *pitch++);
 				if (tmp > hi)
 					hi = tmp;
 			}
@@ -443,13 +447,21 @@
 		return 0;
 	case check_texture_addr3:
 		cur_seq->unfinished = tex_address;
-		tmp = ((cmd >> 24) - 0x2B);
-		cur_seq->pitch[cur_seq->texture][tmp] =
-		    (cmd & 0x00F00000) >> 20;
-		if (!tmp && (cmd & 0x000FFFFF)) {
-			DRM_ERROR
-			    ("Unimplemented texture level 0 pitch mode.\n");
-			return 2;
+		tmp = ((cmd >> 24) - HC_SubA_HTXnL0Pit);
+		if (tmp == 0 &&
+		    (cmd & HC_HTXnEnPit_MASK)) {
+			cur_seq->pitch[cur_seq->texture][tmp] =
+				(cmd & HC_HTXnLnPit_MASK);
+			cur_seq->tex_npot[cur_seq->texture] = 1;
+		} else {
+			cur_seq->pitch[cur_seq->texture][tmp] =
+				(cmd & HC_HTXnLnPitE_MASK) >> HC_HTXnLnPitE_SHIFT;
+			cur_seq->tex_npot[cur_seq->texture] = 0;
+			if (cmd & 0x000FFFFF) {
+				DRM_ERROR
+					("Unimplemented texture level 0 pitch mode.\n");
+				return 2;
+			}
 		}
 		return 0;
 	case check_texture_addr4:
@@ -961,7 +973,13 @@
 	uint32_t cmd;
 	const uint32_t *buf_end = buf + (size >> 2);
 	verifier_state_t state = state_command;
-	int pro_group_a = dev_priv->pro_group_a;
+	int cme_video;
+	int supported_3d;
+
+	cme_video = (dev_priv->chipset == VIA_PRO_GROUP_A ||
+		     dev_priv->chipset == VIA_DX9_0);
+
+	supported_3d = dev_priv->chipset != VIA_DX9_0;
 
 	hc_state->dev = dev;
 	hc_state->unfinished = no_sequence;
@@ -986,17 +1004,21 @@
 			state = via_check_vheader6(&buf, buf_end);
 			break;
 		case state_command:
-			if (HALCYON_HEADER2 == (cmd = *buf))
+			if ((HALCYON_HEADER2 == (cmd = *buf)) &&
+			    supported_3d)
 				state = state_header2;
 			else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
 				state = state_header1;
-			else if (pro_group_a
+			else if (cme_video
 				 && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
 				state = state_vheader5;
-			else if (pro_group_a
+			else if (cme_video
 				 && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
 				state = state_vheader6;
-			else {
+			else if ((cmd == HALCYON_HEADER2) && !supported_3d) {
+				DRM_ERROR("Accelerated 3D is not supported on this chipset yet.\n");
+				state = state_error;
+			} else {
 				DRM_ERROR
 				    ("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
 				     cmd);
diff --git a/drivers/char/drm/via_verifier.h b/drivers/char/drm/via_verifier.h
index 256590f..b77f59d 100644
--- a/drivers/char/drm/via_verifier.h
+++ b/drivers/char/drm/via_verifier.h
@@ -43,6 +43,7 @@
 	uint32_t tex_level_lo[2];
 	uint32_t tex_level_hi[2];
 	uint32_t tex_palette_size[2];
+	uint32_t tex_npot[2];
 	drm_via_sequence_t unfinished;
 	int agp_texture;
 	int multitex;
diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c
new file mode 100644
index 0000000..6f019f1
--- /dev/null
+++ b/drivers/char/hvc_beat.c
@@ -0,0 +1,134 @@
+/*
+ * Beat hypervisor console driver
+ *
+ * (C) Copyright 2006 TOSHIBA CORPORATION
+ *
+ * This code is based on drivers/char/hvc_rtas.c:
+ * (C) Copyright IBM Corporation 2001-2005
+ * (C) Copyright Red Hat, Inc. 2005
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/console.h>
+#include <asm/prom.h>
+#include <asm/hvconsole.h>
+#include <asm/firmware.h>
+
+#include "hvc_console.h"
+
+extern int64_t beat_get_term_char(uint64_t, uint64_t *, uint64_t *, uint64_t *);
+extern int64_t beat_put_term_char(uint64_t, uint64_t, uint64_t, uint64_t);
+
+struct hvc_struct *hvc_beat_dev = NULL;
+
+/* bug: only one queue is available regardless of vtermno */
+static int hvc_beat_get_chars(uint32_t vtermno, char *buf, int cnt)
+{
+	static unsigned char q[sizeof(unsigned long) * 2]
+		__attribute__((aligned(sizeof(unsigned long))));
+	static int qlen = 0;
+	unsigned long got;
+
+again:
+	if (qlen) {
+		if (qlen > cnt) {
+			memcpy(buf, q, cnt);
+			qlen -= cnt;
+			memmove(q + cnt, q, qlen);
+			return cnt;
+		} else {	/* qlen <= cnt */
+			int	r;
+
+			memcpy(buf, q, qlen);
+			r = qlen;
+			qlen = 0;
+			return r;
+		}
+	}
+	if (beat_get_term_char(vtermno, &got,
+		((unsigned long *)q), ((unsigned long *)q) + 1) == 0) {
+		qlen = got;
+		goto again;
+	}
+	return 0;
+}
+
+static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt)
+{
+	unsigned long kb[2];
+	int rest, nlen;
+
+	for (rest = cnt; rest > 0; rest -= nlen) {
+		nlen = (rest > 16) ? 16 : rest;
+		memcpy(kb, buf, nlen);
+		beat_put_term_char(vtermno, rest, kb[0], kb[1]);
+		rest -= nlen;
+	}
+	return cnt;
+}
+
+static struct hv_ops hvc_beat_get_put_ops = {
+	.get_chars = hvc_beat_get_chars,
+	.put_chars = hvc_beat_put_chars,
+};
+
+static int hvc_beat_useit = 1;
+
+static int hvc_beat_config(char *p)
+{
+	hvc_beat_useit = simple_strtoul(p, NULL, 0);
+	return 0;
+}
+
+static int hvc_beat_console_init(void)
+{
+	if (hvc_beat_useit && machine_is_compatible("Beat")) {
+		hvc_instantiate(0, 0, &hvc_beat_get_put_ops);
+	}
+	return 0;
+}
+
+/* temp */
+static int hvc_beat_init(void)
+{
+	struct hvc_struct *hp;
+
+	if (!firmware_has_feature(FW_FEATURE_BEAT))
+		return -ENODEV;
+
+	hp = hvc_alloc(0, NO_IRQ, &hvc_beat_get_put_ops, 16);
+	if (IS_ERR(hp))
+		return PTR_ERR(hp);
+	hvc_beat_dev = hp;
+	return 0;
+}
+
+static void __exit hvc_beat_exit(void)
+{
+	if (hvc_beat_dev)
+		hvc_remove(hvc_beat_dev);
+}
+
+module_init(hvc_beat_init);
+module_exit(hvc_beat_exit);
+
+__setup("hvc_beat=", hvc_beat_config);
+
+console_initcall(hvc_beat_console_init);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index f1afd26..a7b33d2 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -1802,7 +1802,7 @@
   	    return -ENODEV;
 	}
 
-	if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+	if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
 		addr_space = IPMI_MEM_ADDR_SPACE;
 	else
 		addr_space = IPMI_IO_ADDR_SPACE;
@@ -1848,19 +1848,19 @@
 		info->irq_setup = NULL;
 	}
 
-	if (spmi->addr.register_bit_width) {
+	if (spmi->addr.bit_width) {
 		/* A (hopefully) properly formed register bit width. */
-		info->io.regspacing = spmi->addr.register_bit_width / 8;
+		info->io.regspacing = spmi->addr.bit_width / 8;
 	} else {
 		info->io.regspacing = DEFAULT_REGSPACING;
 	}
 	info->io.regsize = info->io.regspacing;
-	info->io.regshift = spmi->addr.register_bit_offset;
+	info->io.regshift = spmi->addr.bit_offset;
 
-	if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+	if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
 		info->io_setup = mem_setup;
 		info->io.addr_type = IPMI_IO_ADDR_SPACE;
-	} else if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
+	} else if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
 		info->io_setup = port_setup;
 		info->io.addr_type = IPMI_MEM_ADDR_SPACE;
 	} else {
@@ -1888,10 +1888,8 @@
 		return;
 
 	for (i = 0; ; i++) {
-		status = acpi_get_firmware_table("SPMI", i+1,
-						 ACPI_LOGICAL_ADDRESSING,
-						 (struct acpi_table_header **)
-						 &spmi);
+		status = acpi_get_table(ACPI_SIG_SPMI, i+1,
+					(struct acpi_table_header **)&spmi);
 		if (status != AE_OK)
 			return;
 
diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c
index a611972..7fca5f4 100644
--- a/drivers/char/tpm/tpm_bios.c
+++ b/drivers/char/tpm/tpm_bios.c
@@ -372,10 +372,8 @@
 	}
 
 	/* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
-	status = acpi_get_firmware_table(ACPI_TCPA_SIG, 1,
-					 ACPI_LOGICAL_ADDRESSING,
-					 (struct acpi_table_header **)
-					 &buff);
+	status = acpi_get_table(ACPI_SIG_TCPA, 1,
+				(struct acpi_table_header **)&buff);
 
 	if (ACPI_FAILURE(status)) {
 		printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
@@ -409,7 +407,7 @@
 
 	log->bios_event_log_end = log->bios_event_log + len;
 
-	acpi_os_map_memory(start, len, (void *) &virt);
+	virt = acpi_os_map_memory(start, len);
 
 	memcpy(log->bios_event_log, virt, len);
 
diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c
index 4889022..0e23f29 100644
--- a/drivers/char/watchdog/booke_wdt.c
+++ b/drivers/char/watchdog/booke_wdt.c
@@ -35,7 +35,7 @@
 #ifdef	CONFIG_FSL_BOOKE
 #define WDT_PERIOD_DEFAULT 63	/* Ex. wdt_period=28 bus=333Mhz , reset=~40sec */
 #else
-#define WDT_PERIOD_DEFAULT 4	/* Refer to the PPC40x and PPC4xx manuals */
+#define WDT_PERIOD_DEFAULT 3	/* Refer to the PPC40x and PPC4xx manuals */
 #endif				/* for timing information */
 
 u32 booke_wdt_enabled = 0;
@@ -48,12 +48,22 @@
 #endif
 
 /*
+ * booke_wdt_ping:
+ */
+static __inline__ void booke_wdt_ping(void)
+{
+	mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
+}
+
+/*
  * booke_wdt_enable:
  */
 static __inline__ void booke_wdt_enable(void)
 {
 	u32 val;
 
+	/* clear status before enabling watchdog */
+	booke_wdt_ping();
 	val = mfspr(SPRN_TCR);
 	val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period));
 
@@ -61,14 +71,6 @@
 }
 
 /*
- * booke_wdt_ping:
- */
-static __inline__ void booke_wdt_ping(void)
-{
-	mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
-}
-
-/*
  * booke_wdt_write:
  */
 static ssize_t booke_wdt_write (struct file *file, const char __user *buf,
diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c
index 276577d..4d730fd 100644
--- a/drivers/char/watchdog/machzwd.c
+++ b/drivers/char/watchdog/machzwd.c
@@ -325,7 +325,7 @@
 			return put_user(0, p);
 
 		case WDIOC_KEEPALIVE:
-			zf_ping(0);
+			zf_ping(NULL);
 			break;
 
 		default:
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 879250d..ff8c4be 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -51,6 +51,8 @@
 	  If unsure say M. The compiled module will be
 	  called padlock-sha.ko
 
+source "arch/s390/crypto/Kconfig"
+
 config CRYPTO_DEV_GEODE
 	tristate "Support for the Geode LX AES engine"
 	depends on CRYPTO && X86_32 && PCI
diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c
index 43a6839..31ea405 100644
--- a/drivers/crypto/geode-aes.c
+++ b/drivers/crypto/geode-aes.c
@@ -457,7 +457,7 @@
 static int __init
 geode_aes_init(void)
 {
-	return pci_module_init(&geode_aes_driver);
+	return pci_register_driver(&geode_aes_driver);
 }
 
 static void __exit
diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c
index c2ad72f..2b4b76e 100644
--- a/drivers/firmware/pcdp.c
+++ b/drivers/firmware/pcdp.c
@@ -26,7 +26,7 @@
 	static char options[64], *p = options;
 	char parity;
 
-	mmio = (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
+	mmio = (uart->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
 	p += sprintf(p, "console=uart,%s,0x%lx",
 		mmio ? "mmio" : "io", uart->addr.address);
 	if (uart->baud) {
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index ec796ad..850788f 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -22,5 +22,19 @@
 
 	  If unsure, say Y
 
+config HID_DEBUG
+	bool "HID debugging support"
+	depends on HID
+	---help---
+	This option lets the HID layer output diagnostics about its internal
+	state, resolve HID usages, dump HID fields, etc. Individual HID drivers
+	use this debugging facility to output information about individual HID
+	devices, etc.
+
+	This feature is useful for those who are either debugging the HID parser
+	or any HID hardware device.
+
+	If unsure, say N
+
 endmenu
 
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 6432392..52e97d8 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -1,15 +1,8 @@
 #
 # Makefile for the HID driver
 #
-
-# Multipart objects.
-hid-objs	:= hid-core.o hid-input.o
-
-# Optional parts of multipart objects.
+hid-objs			:= hid-core.o hid-input.o
 
 obj-$(CONFIG_HID)		+= hid.o
-
-ifeq ($(CONFIG_INPUT_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+hid-$(CONFIG_HID_DEBUG)		+= hid-debug.o
 
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 49f18f5..8c7d48e 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -28,11 +28,9 @@
 #include <linux/input.h>
 #include <linux/wait.h>
 
-#undef DEBUG
-#undef DEBUG_DATA
-
 #include <linux/hid.h>
 #include <linux/hiddev.h>
+#include <linux/hid-debug.h>
 
 /*
  * Version Information
@@ -951,7 +949,7 @@
 		return -1;
 	}
 
-#ifdef DEBUG_DATA
+#ifdef CONFIG_HID_DEBUG
 	printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
 #endif
 
@@ -961,7 +959,7 @@
 		size--;
 	}
 
-#ifdef DEBUG_DATA
+#ifdef CONFIG_HID_DEBUG
 	{
 		int i;
 		printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, size);
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
new file mode 100644
index 0000000..89241be
--- /dev/null
+++ b/drivers/hid/hid-debug.c
@@ -0,0 +1,764 @@
+/*
+ * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $
+ *
+ *  (c) 1999 Andreas Gal		<gal@cs.uni-magdeburg.de>
+ *  (c) 2000-2001 Vojtech Pavlik	<vojtech@ucw.cz>
+ *  (c) 2007 Jiri Kosina
+ *
+ *  Some debug stuff for the HID parser.
+ */
+
+/*
+ * 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
+ *
+ * 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
+ */
+
+#include <linux/hid.h>
+
+struct hid_usage_entry {
+	unsigned  page;
+	unsigned  usage;
+	char     *description;
+};
+
+static const struct hid_usage_entry hid_usage_table[] = {
+  {  0,      0, "Undefined" },
+  {  1,      0, "GenericDesktop" },
+    {0, 0x01, "Pointer"},
+    {0, 0x02, "Mouse"},
+    {0, 0x04, "Joystick"},
+    {0, 0x05, "GamePad"},
+    {0, 0x06, "Keyboard"},
+    {0, 0x07, "Keypad"},
+    {0, 0x08, "MultiAxis"},
+      {0, 0x30, "X"},
+      {0, 0x31, "Y"},
+      {0, 0x32, "Z"},
+      {0, 0x33, "Rx"},
+      {0, 0x34, "Ry"},
+      {0, 0x35, "Rz"},
+      {0, 0x36, "Slider"},
+      {0, 0x37, "Dial"},
+      {0, 0x38, "Wheel"},
+      {0, 0x39, "HatSwitch"},
+    {0, 0x3a, "CountedBuffer"},
+      {0, 0x3b, "ByteCount"},
+      {0, 0x3c, "MotionWakeup"},
+      {0, 0x3d, "Start"},
+      {0, 0x3e, "Select"},
+      {0, 0x40, "Vx"},
+      {0, 0x41, "Vy"},
+      {0, 0x42, "Vz"},
+      {0, 0x43, "Vbrx"},
+      {0, 0x44, "Vbry"},
+      {0, 0x45, "Vbrz"},
+      {0, 0x46, "Vno"},
+    {0, 0x80, "SystemControl"},
+      {0, 0x81, "SystemPowerDown"},
+      {0, 0x82, "SystemSleep"},
+      {0, 0x83, "SystemWakeUp"},
+      {0, 0x84, "SystemContextMenu"},
+      {0, 0x85, "SystemMainMenu"},
+      {0, 0x86, "SystemAppMenu"},
+      {0, 0x87, "SystemMenuHelp"},
+      {0, 0x88, "SystemMenuExit"},
+      {0, 0x89, "SystemMenuSelect"},
+      {0, 0x8a, "SystemMenuRight"},
+      {0, 0x8b, "SystemMenuLeft"},
+      {0, 0x8c, "SystemMenuUp"},
+      {0, 0x8d, "SystemMenuDown"},
+      {0, 0x90, "D-PadUp"},
+      {0, 0x91, "D-PadDown"},
+      {0, 0x92, "D-PadRight"},
+      {0, 0x93, "D-PadLeft"},
+  {  2, 0, "Simulation" },
+      {0, 0xb0, "Aileron"},
+      {0, 0xb1, "AileronTrim"},
+      {0, 0xb2, "Anti-Torque"},
+      {0, 0xb3, "Autopilot"},
+      {0, 0xb4, "Chaff"},
+      {0, 0xb5, "Collective"},
+      {0, 0xb6, "DiveBrake"},
+      {0, 0xb7, "ElectronicCountermeasures"},
+      {0, 0xb8, "Elevator"},
+      {0, 0xb9, "ElevatorTrim"},
+      {0, 0xba, "Rudder"},
+      {0, 0xbb, "Throttle"},
+      {0, 0xbc, "FlightCommunications"},
+      {0, 0xbd, "FlareRelease"},
+      {0, 0xbe, "LandingGear"},
+      {0, 0xbf, "ToeBrake"},
+  {  7, 0, "Keyboard" },
+  {  8, 0, "LED" },
+      {0, 0x01, "NumLock"},
+      {0, 0x02, "CapsLock"},
+      {0, 0x03, "ScrollLock"},
+      {0, 0x04, "Compose"},
+      {0, 0x05, "Kana"},
+      {0, 0x4b, "GenericIndicator"},
+  {  9, 0, "Button" },
+  { 10, 0, "Ordinal" },
+  { 12, 0, "Consumer" },
+      {0, 0x238, "HorizontalWheel"},
+  { 13, 0, "Digitizers" },
+    {0, 0x01, "Digitizer"},
+    {0, 0x02, "Pen"},
+    {0, 0x03, "LightPen"},
+    {0, 0x04, "TouchScreen"},
+    {0, 0x05, "TouchPad"},
+    {0, 0x20, "Stylus"},
+    {0, 0x21, "Puck"},
+    {0, 0x22, "Finger"},
+    {0, 0x30, "TipPressure"},
+    {0, 0x31, "BarrelPressure"},
+    {0, 0x32, "InRange"},
+    {0, 0x33, "Touch"},
+    {0, 0x34, "UnTouch"},
+    {0, 0x35, "Tap"},
+    {0, 0x39, "TabletFunctionKey"},
+    {0, 0x3a, "ProgramChangeKey"},
+    {0, 0x3c, "Invert"},
+    {0, 0x42, "TipSwitch"},
+    {0, 0x43, "SecondaryTipSwitch"},
+    {0, 0x44, "BarrelSwitch"},
+    {0, 0x45, "Eraser"},
+    {0, 0x46, "TabletPick"},
+  { 15, 0, "PhysicalInterfaceDevice" },
+    {0, 0x00, "Undefined"},
+    {0, 0x01, "Physical_Interface_Device"},
+      {0, 0x20, "Normal"},
+    {0, 0x21, "Set_Effect_Report"},
+      {0, 0x22, "Effect_Block_Index"},
+      {0, 0x23, "Parameter_Block_Offset"},
+      {0, 0x24, "ROM_Flag"},
+      {0, 0x25, "Effect_Type"},
+        {0, 0x26, "ET_Constant_Force"},
+        {0, 0x27, "ET_Ramp"},
+        {0, 0x28, "ET_Custom_Force_Data"},
+        {0, 0x30, "ET_Square"},
+        {0, 0x31, "ET_Sine"},
+        {0, 0x32, "ET_Triangle"},
+        {0, 0x33, "ET_Sawtooth_Up"},
+        {0, 0x34, "ET_Sawtooth_Down"},
+        {0, 0x40, "ET_Spring"},
+        {0, 0x41, "ET_Damper"},
+        {0, 0x42, "ET_Inertia"},
+        {0, 0x43, "ET_Friction"},
+      {0, 0x50, "Duration"},
+      {0, 0x51, "Sample_Period"},
+      {0, 0x52, "Gain"},
+      {0, 0x53, "Trigger_Button"},
+      {0, 0x54, "Trigger_Repeat_Interval"},
+      {0, 0x55, "Axes_Enable"},
+        {0, 0x56, "Direction_Enable"},
+      {0, 0x57, "Direction"},
+      {0, 0x58, "Type_Specific_Block_Offset"},
+        {0, 0x59, "Block_Type"},
+        {0, 0x5A, "Set_Envelope_Report"},
+          {0, 0x5B, "Attack_Level"},
+          {0, 0x5C, "Attack_Time"},
+          {0, 0x5D, "Fade_Level"},
+          {0, 0x5E, "Fade_Time"},
+        {0, 0x5F, "Set_Condition_Report"},
+        {0, 0x60, "CP_Offset"},
+        {0, 0x61, "Positive_Coefficient"},
+        {0, 0x62, "Negative_Coefficient"},
+        {0, 0x63, "Positive_Saturation"},
+        {0, 0x64, "Negative_Saturation"},
+        {0, 0x65, "Dead_Band"},
+      {0, 0x66, "Download_Force_Sample"},
+      {0, 0x67, "Isoch_Custom_Force_Enable"},
+      {0, 0x68, "Custom_Force_Data_Report"},
+        {0, 0x69, "Custom_Force_Data"},
+        {0, 0x6A, "Custom_Force_Vendor_Defined_Data"},
+      {0, 0x6B, "Set_Custom_Force_Report"},
+        {0, 0x6C, "Custom_Force_Data_Offset"},
+        {0, 0x6D, "Sample_Count"},
+      {0, 0x6E, "Set_Periodic_Report"},
+        {0, 0x6F, "Offset"},
+        {0, 0x70, "Magnitude"},
+        {0, 0x71, "Phase"},
+        {0, 0x72, "Period"},
+      {0, 0x73, "Set_Constant_Force_Report"},
+        {0, 0x74, "Set_Ramp_Force_Report"},
+        {0, 0x75, "Ramp_Start"},
+        {0, 0x76, "Ramp_End"},
+      {0, 0x77, "Effect_Operation_Report"},
+        {0, 0x78, "Effect_Operation"},
+          {0, 0x79, "Op_Effect_Start"},
+          {0, 0x7A, "Op_Effect_Start_Solo"},
+          {0, 0x7B, "Op_Effect_Stop"},
+          {0, 0x7C, "Loop_Count"},
+      {0, 0x7D, "Device_Gain_Report"},
+        {0, 0x7E, "Device_Gain"},
+    {0, 0x7F, "PID_Pool_Report"},
+      {0, 0x80, "RAM_Pool_Size"},
+      {0, 0x81, "ROM_Pool_Size"},
+      {0, 0x82, "ROM_Effect_Block_Count"},
+      {0, 0x83, "Simultaneous_Effects_Max"},
+      {0, 0x84, "Pool_Alignment"},
+    {0, 0x85, "PID_Pool_Move_Report"},
+      {0, 0x86, "Move_Source"},
+      {0, 0x87, "Move_Destination"},
+      {0, 0x88, "Move_Length"},
+    {0, 0x89, "PID_Block_Load_Report"},
+      {0, 0x8B, "Block_Load_Status"},
+      {0, 0x8C, "Block_Load_Success"},
+      {0, 0x8D, "Block_Load_Full"},
+      {0, 0x8E, "Block_Load_Error"},
+      {0, 0x8F, "Block_Handle"},
+      {0, 0x90, "PID_Block_Free_Report"},
+      {0, 0x91, "Type_Specific_Block_Handle"},
+    {0, 0x92, "PID_State_Report"},
+      {0, 0x94, "Effect_Playing"},
+      {0, 0x95, "PID_Device_Control_Report"},
+        {0, 0x96, "PID_Device_Control"},
+        {0, 0x97, "DC_Enable_Actuators"},
+        {0, 0x98, "DC_Disable_Actuators"},
+        {0, 0x99, "DC_Stop_All_Effects"},
+        {0, 0x9A, "DC_Device_Reset"},
+        {0, 0x9B, "DC_Device_Pause"},
+        {0, 0x9C, "DC_Device_Continue"},
+      {0, 0x9F, "Device_Paused"},
+      {0, 0xA0, "Actuators_Enabled"},
+      {0, 0xA4, "Safety_Switch"},
+      {0, 0xA5, "Actuator_Override_Switch"},
+      {0, 0xA6, "Actuator_Power"},
+    {0, 0xA7, "Start_Delay"},
+    {0, 0xA8, "Parameter_Block_Size"},
+    {0, 0xA9, "Device_Managed_Pool"},
+    {0, 0xAA, "Shared_Parameter_Blocks"},
+    {0, 0xAB, "Create_New_Effect_Report"},
+    {0, 0xAC, "RAM_Pool_Available"},
+  { 0x84, 0, "Power Device" },
+    { 0x84, 0x02, "PresentStatus" },
+    { 0x84, 0x03, "ChangeStatus" },
+    { 0x84, 0x04, "UPS" },
+    { 0x84, 0x05, "PowerSupply" },
+    { 0x84, 0x10, "BatterySystem" },
+    { 0x84, 0x11, "BatterySystemID" },
+    { 0x84, 0x12, "Battery" },
+    { 0x84, 0x13, "BatteryID" },
+    { 0x84, 0x14, "Charger" },
+    { 0x84, 0x15, "ChargerID" },
+    { 0x84, 0x16, "PowerConverter" },
+    { 0x84, 0x17, "PowerConverterID" },
+    { 0x84, 0x18, "OutletSystem" },
+    { 0x84, 0x19, "OutletSystemID" },
+    { 0x84, 0x1a, "Input" },
+    { 0x84, 0x1b, "InputID" },
+    { 0x84, 0x1c, "Output" },
+    { 0x84, 0x1d, "OutputID" },
+    { 0x84, 0x1e, "Flow" },
+    { 0x84, 0x1f, "FlowID" },
+    { 0x84, 0x20, "Outlet" },
+    { 0x84, 0x21, "OutletID" },
+    { 0x84, 0x22, "Gang" },
+    { 0x84, 0x24, "PowerSummary" },
+    { 0x84, 0x25, "PowerSummaryID" },
+    { 0x84, 0x30, "Voltage" },
+    { 0x84, 0x31, "Current" },
+    { 0x84, 0x32, "Frequency" },
+    { 0x84, 0x33, "ApparentPower" },
+    { 0x84, 0x35, "PercentLoad" },
+    { 0x84, 0x40, "ConfigVoltage" },
+    { 0x84, 0x41, "ConfigCurrent" },
+    { 0x84, 0x43, "ConfigApparentPower" },
+    { 0x84, 0x53, "LowVoltageTransfer" },
+    { 0x84, 0x54, "HighVoltageTransfer" },
+    { 0x84, 0x56, "DelayBeforeStartup" },
+    { 0x84, 0x57, "DelayBeforeShutdown" },
+    { 0x84, 0x58, "Test" },
+    { 0x84, 0x5a, "AudibleAlarmControl" },
+    { 0x84, 0x60, "Present" },
+    { 0x84, 0x61, "Good" },
+    { 0x84, 0x62, "InternalFailure" },
+    { 0x84, 0x65, "Overload" },
+    { 0x84, 0x66, "OverCharged" },
+    { 0x84, 0x67, "OverTemperature" },
+    { 0x84, 0x68, "ShutdownRequested" },
+    { 0x84, 0x69, "ShutdownImminent" },
+    { 0x84, 0x6b, "SwitchOn/Off" },
+    { 0x84, 0x6c, "Switchable" },
+    { 0x84, 0x6d, "Used" },
+    { 0x84, 0x6e, "Boost" },
+    { 0x84, 0x73, "CommunicationLost" },
+    { 0x84, 0xfd, "iManufacturer" },
+    { 0x84, 0xfe, "iProduct" },
+    { 0x84, 0xff, "iSerialNumber" },
+  { 0x85, 0, "Battery System" },
+    { 0x85, 0x01, "SMBBatteryMode" },
+    { 0x85, 0x02, "SMBBatteryStatus" },
+    { 0x85, 0x03, "SMBAlarmWarning" },
+    { 0x85, 0x04, "SMBChargerMode" },
+    { 0x85, 0x05, "SMBChargerStatus" },
+    { 0x85, 0x06, "SMBChargerSpecInfo" },
+    { 0x85, 0x07, "SMBSelectorState" },
+    { 0x85, 0x08, "SMBSelectorPresets" },
+    { 0x85, 0x09, "SMBSelectorInfo" },
+    { 0x85, 0x29, "RemainingCapacityLimit" },
+    { 0x85, 0x2c, "CapacityMode" },
+    { 0x85, 0x42, "BelowRemainingCapacityLimit" },
+    { 0x85, 0x44, "Charging" },
+    { 0x85, 0x45, "Discharging" },
+    { 0x85, 0x4b, "NeedReplacement" },
+    { 0x85, 0x66, "RemainingCapacity" },
+    { 0x85, 0x68, "RunTimeToEmpty" },
+    { 0x85, 0x6a, "AverageTimeToFull" },
+    { 0x85, 0x83, "DesignCapacity" },
+    { 0x85, 0x85, "ManufacturerDate" },
+    { 0x85, 0x89, "iDeviceChemistry" },
+    { 0x85, 0x8b, "Rechargable" },
+    { 0x85, 0x8f, "iOEMInformation" },
+    { 0x85, 0x8d, "CapacityGranularity1" },
+    { 0x85, 0xd0, "ACPresent" },
+  /* pages 0xff00 to 0xffff are vendor-specific */
+  { 0xffff, 0, "Vendor-specific-FF" },
+  { 0, 0, NULL }
+};
+
+static void resolv_usage_page(unsigned page) {
+	const struct hid_usage_entry *p;
+
+	for (p = hid_usage_table; p->description; p++)
+		if (p->page == page) {
+			printk("%s", p->description);
+			return;
+		}
+	printk("%04x", page);
+}
+
+void hid_resolv_usage(unsigned usage) {
+	const struct hid_usage_entry *p;
+
+	resolv_usage_page(usage >> 16);
+	printk(".");
+	for (p = hid_usage_table; p->description; p++)
+		if (p->page == (usage >> 16)) {
+			for(++p; p->description && p->usage != 0; p++)
+				if (p->usage == (usage & 0xffff)) {
+					printk("%s", p->description);
+					return;
+				}
+			break;
+		}
+	printk("%04x", usage & 0xffff);
+}
+EXPORT_SYMBOL_GPL(hid_resolv_usage);
+
+__inline__ static void tab(int n) {
+	while (n--) printk(" ");
+}
+
+void hid_dump_field(struct hid_field *field, int n) {
+	int j;
+
+	if (field->physical) {
+		tab(n);
+		printk("Physical(");
+		hid_resolv_usage(field->physical); printk(")\n");
+	}
+	if (field->logical) {
+		tab(n);
+		printk("Logical(");
+		hid_resolv_usage(field->logical); printk(")\n");
+	}
+	tab(n); printk("Usage(%d)\n", field->maxusage);
+	for (j = 0; j < field->maxusage; j++) {
+		tab(n+2); hid_resolv_usage(field->usage[j].hid); printk("\n");
+	}
+	if (field->logical_minimum != field->logical_maximum) {
+		tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum);
+		tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum);
+	}
+	if (field->physical_minimum != field->physical_maximum) {
+		tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum);
+		tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum);
+	}
+	if (field->unit_exponent) {
+		tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent);
+	}
+	if (field->unit) {
+		char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
+		char *units[5][8] = {
+			{ "None", "None", "None", "None", "None", "None", "None", "None" },
+			{ "None", "Centimeter", "Gram", "Seconds", "Kelvin",     "Ampere", "Candela", "None" },
+			{ "None", "Radians",    "Gram", "Seconds", "Kelvin",     "Ampere", "Candela", "None" },
+			{ "None", "Inch",       "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" },
+			{ "None", "Degrees",    "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }
+		};
+
+		int i;
+		int sys;
+                __u32 data = field->unit;
+
+		/* First nibble tells us which system we're in. */
+		sys = data & 0xf;
+		data >>= 4;
+
+		if(sys > 4) {
+			tab(n); printk("Unit(Invalid)\n");
+		}
+		else {
+			int earlier_unit = 0;
+
+			tab(n); printk("Unit(%s : ", systems[sys]);
+
+			for (i=1 ; i<sizeof(__u32)*2 ; i++) {
+				char nibble = data & 0xf;
+				data >>= 4;
+				if (nibble != 0) {
+					if(earlier_unit++ > 0)
+						printk("*");
+					printk("%s", units[sys][i]);
+					if(nibble != 1) {
+						/* This is a _signed_ nibble(!) */
+
+						int val = nibble & 0x7;
+						if(nibble & 0x08)
+							val = -((0x7 & ~val) +1);
+						printk("^%d", val);
+					}
+				}
+			}
+			printk(")\n");
+		}
+	}
+	tab(n); printk("Report Size(%u)\n", field->report_size);
+	tab(n); printk("Report Count(%u)\n", field->report_count);
+	tab(n); printk("Report Offset(%u)\n", field->report_offset);
+
+	tab(n); printk("Flags( ");
+	j = field->flags;
+	printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : "");
+	printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array ");
+	printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute ");
+	printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : "");
+	printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : "");
+	printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : "");
+	printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : "");
+	printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : "");
+	printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : "");
+	printk(")\n");
+}
+EXPORT_SYMBOL_GPL(hid_dump_field);
+
+void hid_dump_device(struct hid_device *device) {
+	struct hid_report_enum *report_enum;
+	struct hid_report *report;
+	struct list_head *list;
+	unsigned i,k;
+	static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
+
+	for (i = 0; i < HID_REPORT_TYPES; i++) {
+		report_enum = device->report_enum + i;
+		list = report_enum->report_list.next;
+		while (list != &report_enum->report_list) {
+			report = (struct hid_report *) list;
+			tab(2);
+			printk("%s", table[i]);
+			if (report->id)
+				printk("(%d)", report->id);
+			printk("[%s]", table[report->type]);
+			printk("\n");
+			for (k = 0; k < report->maxfield; k++) {
+				tab(4);
+				printk("Field(%d)\n", k);
+				hid_dump_field(report->field[k], 6);
+			}
+			list = list->next;
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(hid_dump_device);
+
+void hid_dump_input(struct hid_usage *usage, __s32 value) {
+	printk("hid-debug: input ");
+	hid_resolv_usage(usage->hid);
+	printk(" = %d\n", value);
+}
+EXPORT_SYMBOL_GPL(hid_dump_input);
+
+static char *events[EV_MAX + 1] = {
+	[EV_SYN] = "Sync",			[EV_KEY] = "Key",
+	[EV_REL] = "Relative",			[EV_ABS] = "Absolute",
+	[EV_MSC] = "Misc",			[EV_LED] = "LED",
+	[EV_SND] = "Sound",			[EV_REP] = "Repeat",
+	[EV_FF] = "ForceFeedback",		[EV_PWR] = "Power",
+	[EV_FF_STATUS] = "ForceFeedbackStatus",
+};
+
+static char *syncs[2] = {
+	[SYN_REPORT] = "Report",		[SYN_CONFIG] = "Config",
+};
+static char *keys[KEY_MAX + 1] = {
+	[KEY_RESERVED] = "Reserved",		[KEY_ESC] = "Esc",
+	[KEY_1] = "1",				[KEY_2] = "2",
+	[KEY_3] = "3",				[KEY_4] = "4",
+	[KEY_5] = "5",				[KEY_6] = "6",
+	[KEY_7] = "7",				[KEY_8] = "8",
+	[KEY_9] = "9",				[KEY_0] = "0",
+	[KEY_MINUS] = "Minus",			[KEY_EQUAL] = "Equal",
+	[KEY_BACKSPACE] = "Backspace",		[KEY_TAB] = "Tab",
+	[KEY_Q] = "Q",				[KEY_W] = "W",
+	[KEY_E] = "E",				[KEY_R] = "R",
+	[KEY_T] = "T",				[KEY_Y] = "Y",
+	[KEY_U] = "U",				[KEY_I] = "I",
+	[KEY_O] = "O",				[KEY_P] = "P",
+	[KEY_LEFTBRACE] = "LeftBrace",		[KEY_RIGHTBRACE] = "RightBrace",
+	[KEY_ENTER] = "Enter",			[KEY_LEFTCTRL] = "LeftControl",
+	[KEY_A] = "A",				[KEY_S] = "S",
+	[KEY_D] = "D",				[KEY_F] = "F",
+	[KEY_G] = "G",				[KEY_H] = "H",
+	[KEY_J] = "J",				[KEY_K] = "K",
+	[KEY_L] = "L",				[KEY_SEMICOLON] = "Semicolon",
+	[KEY_APOSTROPHE] = "Apostrophe",	[KEY_GRAVE] = "Grave",
+	[KEY_LEFTSHIFT] = "LeftShift",		[KEY_BACKSLASH] = "BackSlash",
+	[KEY_Z] = "Z",				[KEY_X] = "X",
+	[KEY_C] = "C",				[KEY_V] = "V",
+	[KEY_B] = "B",				[KEY_N] = "N",
+	[KEY_M] = "M",				[KEY_COMMA] = "Comma",
+	[KEY_DOT] = "Dot",			[KEY_SLASH] = "Slash",
+	[KEY_RIGHTSHIFT] = "RightShift",	[KEY_KPASTERISK] = "KPAsterisk",
+	[KEY_LEFTALT] = "LeftAlt",		[KEY_SPACE] = "Space",
+	[KEY_CAPSLOCK] = "CapsLock",		[KEY_F1] = "F1",
+	[KEY_F2] = "F2",			[KEY_F3] = "F3",
+	[KEY_F4] = "F4",			[KEY_F5] = "F5",
+	[KEY_F6] = "F6",			[KEY_F7] = "F7",
+	[KEY_F8] = "F8",			[KEY_F9] = "F9",
+	[KEY_F10] = "F10",			[KEY_NUMLOCK] = "NumLock",
+	[KEY_SCROLLLOCK] = "ScrollLock",	[KEY_KP7] = "KP7",
+	[KEY_KP8] = "KP8",			[KEY_KP9] = "KP9",
+	[KEY_KPMINUS] = "KPMinus",		[KEY_KP4] = "KP4",
+	[KEY_KP5] = "KP5",			[KEY_KP6] = "KP6",
+	[KEY_KPPLUS] = "KPPlus",		[KEY_KP1] = "KP1",
+	[KEY_KP2] = "KP2",			[KEY_KP3] = "KP3",
+	[KEY_KP0] = "KP0",			[KEY_KPDOT] = "KPDot",
+	[KEY_ZENKAKUHANKAKU] = "Zenkaku/Hankaku", [KEY_102ND] = "102nd",
+	[KEY_F11] = "F11",			[KEY_F12] = "F12",
+	[KEY_RO] = "RO",			[KEY_KATAKANA] = "Katakana",
+	[KEY_HIRAGANA] = "HIRAGANA",		[KEY_HENKAN] = "Henkan",
+	[KEY_KATAKANAHIRAGANA] = "Katakana/Hiragana", [KEY_MUHENKAN] = "Muhenkan",
+	[KEY_KPJPCOMMA] = "KPJpComma",		[KEY_KPENTER] = "KPEnter",
+	[KEY_RIGHTCTRL] = "RightCtrl",		[KEY_KPSLASH] = "KPSlash",
+	[KEY_SYSRQ] = "SysRq",			[KEY_RIGHTALT] = "RightAlt",
+	[KEY_LINEFEED] = "LineFeed",		[KEY_HOME] = "Home",
+	[KEY_UP] = "Up",			[KEY_PAGEUP] = "PageUp",
+	[KEY_LEFT] = "Left",			[KEY_RIGHT] = "Right",
+	[KEY_END] = "End",			[KEY_DOWN] = "Down",
+	[KEY_PAGEDOWN] = "PageDown",		[KEY_INSERT] = "Insert",
+	[KEY_DELETE] = "Delete",		[KEY_MACRO] = "Macro",
+	[KEY_MUTE] = "Mute",			[KEY_VOLUMEDOWN] = "VolumeDown",
+	[KEY_VOLUMEUP] = "VolumeUp",		[KEY_POWER] = "Power",
+	[KEY_KPEQUAL] = "KPEqual",		[KEY_KPPLUSMINUS] = "KPPlusMinus",
+	[KEY_PAUSE] = "Pause",			[KEY_KPCOMMA] = "KPComma",
+	[KEY_HANGUEL] = "Hangeul",		[KEY_HANJA] = "Hanja",
+	[KEY_YEN] = "Yen",			[KEY_LEFTMETA] = "LeftMeta",
+	[KEY_RIGHTMETA] = "RightMeta",		[KEY_COMPOSE] = "Compose",
+	[KEY_STOP] = "Stop",			[KEY_AGAIN] = "Again",
+	[KEY_PROPS] = "Props",			[KEY_UNDO] = "Undo",
+	[KEY_FRONT] = "Front",			[KEY_COPY] = "Copy",
+	[KEY_OPEN] = "Open",			[KEY_PASTE] = "Paste",
+	[KEY_FIND] = "Find",			[KEY_CUT] = "Cut",
+	[KEY_HELP] = "Help",			[KEY_MENU] = "Menu",
+	[KEY_CALC] = "Calc",			[KEY_SETUP] = "Setup",
+	[KEY_SLEEP] = "Sleep",			[KEY_WAKEUP] = "WakeUp",
+	[KEY_FILE] = "File",			[KEY_SENDFILE] = "SendFile",
+	[KEY_DELETEFILE] = "DeleteFile",	[KEY_XFER] = "X-fer",
+	[KEY_PROG1] = "Prog1",			[KEY_PROG2] = "Prog2",
+	[KEY_WWW] = "WWW",			[KEY_MSDOS] = "MSDOS",
+	[KEY_COFFEE] = "Coffee",		[KEY_DIRECTION] = "Direction",
+	[KEY_CYCLEWINDOWS] = "CycleWindows",	[KEY_MAIL] = "Mail",
+	[KEY_BOOKMARKS] = "Bookmarks",		[KEY_COMPUTER] = "Computer",
+	[KEY_BACK] = "Back",			[KEY_FORWARD] = "Forward",
+	[KEY_CLOSECD] = "CloseCD",		[KEY_EJECTCD] = "EjectCD",
+	[KEY_EJECTCLOSECD] = "EjectCloseCD",	[KEY_NEXTSONG] = "NextSong",
+	[KEY_PLAYPAUSE] = "PlayPause",		[KEY_PREVIOUSSONG] = "PreviousSong",
+	[KEY_STOPCD] = "StopCD",		[KEY_RECORD] = "Record",
+	[KEY_REWIND] = "Rewind",		[KEY_PHONE] = "Phone",
+	[KEY_ISO] = "ISOKey",			[KEY_CONFIG] = "Config",
+	[KEY_HOMEPAGE] = "HomePage",		[KEY_REFRESH] = "Refresh",
+	[KEY_EXIT] = "Exit",			[KEY_MOVE] = "Move",
+	[KEY_EDIT] = "Edit",			[KEY_SCROLLUP] = "ScrollUp",
+	[KEY_SCROLLDOWN] = "ScrollDown",	[KEY_KPLEFTPAREN] = "KPLeftParenthesis",
+	[KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_NEW] = "New",
+	[KEY_REDO] = "Redo",			[KEY_F13] = "F13",
+	[KEY_F14] = "F14",			[KEY_F15] = "F15",
+	[KEY_F16] = "F16",			[KEY_F17] = "F17",
+	[KEY_F18] = "F18",			[KEY_F19] = "F19",
+	[KEY_F20] = "F20",			[KEY_F21] = "F21",
+	[KEY_F22] = "F22",			[KEY_F23] = "F23",
+	[KEY_F24] = "F24",			[KEY_PLAYCD] = "PlayCD",
+	[KEY_PAUSECD] = "PauseCD",		[KEY_PROG3] = "Prog3",
+	[KEY_PROG4] = "Prog4",			[KEY_SUSPEND] = "Suspend",
+	[KEY_CLOSE] = "Close",			[KEY_PLAY] = "Play",
+	[KEY_FASTFORWARD] = "FastForward",	[KEY_BASSBOOST] = "BassBoost",
+	[KEY_PRINT] = "Print",			[KEY_HP] = "HP",
+	[KEY_CAMERA] = "Camera",		[KEY_SOUND] = "Sound",
+	[KEY_QUESTION] = "Question",		[KEY_EMAIL] = "Email",
+	[KEY_CHAT] = "Chat",			[KEY_SEARCH] = "Search",
+	[KEY_CONNECT] = "Connect",		[KEY_FINANCE] = "Finance",
+	[KEY_SPORT] = "Sport",			[KEY_SHOP] = "Shop",
+	[KEY_ALTERASE] = "AlternateErase",	[KEY_CANCEL] = "Cancel",
+	[KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp",
+	[KEY_MEDIA] = "Media",			[KEY_UNKNOWN] = "Unknown",
+	[BTN_0] = "Btn0",			[BTN_1] = "Btn1",
+	[BTN_2] = "Btn2",			[BTN_3] = "Btn3",
+	[BTN_4] = "Btn4",			[BTN_5] = "Btn5",
+	[BTN_6] = "Btn6",			[BTN_7] = "Btn7",
+	[BTN_8] = "Btn8",			[BTN_9] = "Btn9",
+	[BTN_LEFT] = "LeftBtn",			[BTN_RIGHT] = "RightBtn",
+	[BTN_MIDDLE] = "MiddleBtn",		[BTN_SIDE] = "SideBtn",
+	[BTN_EXTRA] = "ExtraBtn",		[BTN_FORWARD] = "ForwardBtn",
+	[BTN_BACK] = "BackBtn",			[BTN_TASK] = "TaskBtn",
+	[BTN_TRIGGER] = "Trigger",		[BTN_THUMB] = "ThumbBtn",
+	[BTN_THUMB2] = "ThumbBtn2",		[BTN_TOP] = "TopBtn",
+	[BTN_TOP2] = "TopBtn2",			[BTN_PINKIE] = "PinkieBtn",
+	[BTN_BASE] = "BaseBtn",			[BTN_BASE2] = "BaseBtn2",
+	[BTN_BASE3] = "BaseBtn3",		[BTN_BASE4] = "BaseBtn4",
+	[BTN_BASE5] = "BaseBtn5",		[BTN_BASE6] = "BaseBtn6",
+	[BTN_DEAD] = "BtnDead",			[BTN_A] = "BtnA",
+	[BTN_B] = "BtnB",			[BTN_C] = "BtnC",
+	[BTN_X] = "BtnX",			[BTN_Y] = "BtnY",
+	[BTN_Z] = "BtnZ",			[BTN_TL] = "BtnTL",
+	[BTN_TR] = "BtnTR",			[BTN_TL2] = "BtnTL2",
+	[BTN_TR2] = "BtnTR2",			[BTN_SELECT] = "BtnSelect",
+	[BTN_START] = "BtnStart",		[BTN_MODE] = "BtnMode",
+	[BTN_THUMBL] = "BtnThumbL",		[BTN_THUMBR] = "BtnThumbR",
+	[BTN_TOOL_PEN] = "ToolPen",		[BTN_TOOL_RUBBER] = "ToolRubber",
+	[BTN_TOOL_BRUSH] = "ToolBrush",		[BTN_TOOL_PENCIL] = "ToolPencil",
+	[BTN_TOOL_AIRBRUSH] = "ToolAirbrush",	[BTN_TOOL_FINGER] = "ToolFinger",
+	[BTN_TOOL_MOUSE] = "ToolMouse",		[BTN_TOOL_LENS] = "ToolLens",
+	[BTN_TOUCH] = "Touch",			[BTN_STYLUS] = "Stylus",
+	[BTN_STYLUS2] = "Stylus2",		[BTN_TOOL_DOUBLETAP] = "ToolDoubleTap",
+	[BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn",
+	[BTN_GEAR_UP] = "Gear up",		[KEY_OK] = "Ok",
+	[KEY_SELECT] = "Select",		[KEY_GOTO] = "Goto",
+	[KEY_CLEAR] = "Clear",			[KEY_POWER2] = "Power2",
+	[KEY_OPTION] = "Option",		[KEY_INFO] = "Info",
+	[KEY_TIME] = "Time",			[KEY_VENDOR] = "Vendor",
+	[KEY_ARCHIVE] = "Archive",		[KEY_PROGRAM] = "Program",
+	[KEY_CHANNEL] = "Channel",		[KEY_FAVORITES] = "Favorites",
+	[KEY_EPG] = "EPG",			[KEY_PVR] = "PVR",
+	[KEY_MHP] = "MHP",			[KEY_LANGUAGE] = "Language",
+	[KEY_TITLE] = "Title",			[KEY_SUBTITLE] = "Subtitle",
+	[KEY_ANGLE] = "Angle",			[KEY_ZOOM] = "Zoom",
+	[KEY_MODE] = "Mode",			[KEY_KEYBOARD] = "Keyboard",
+	[KEY_SCREEN] = "Screen",		[KEY_PC] = "PC",
+	[KEY_TV] = "TV",			[KEY_TV2] = "TV2",
+	[KEY_VCR] = "VCR",			[KEY_VCR2] = "VCR2",
+	[KEY_SAT] = "Sat",			[KEY_SAT2] = "Sat2",
+	[KEY_CD] = "CD",			[KEY_TAPE] = "Tape",
+	[KEY_RADIO] = "Radio",			[KEY_TUNER] = "Tuner",
+	[KEY_PLAYER] = "Player",		[KEY_TEXT] = "Text",
+	[KEY_DVD] = "DVD",			[KEY_AUX] = "Aux",
+	[KEY_MP3] = "MP3",			[KEY_AUDIO] = "Audio",
+	[KEY_VIDEO] = "Video",			[KEY_DIRECTORY] = "Directory",
+	[KEY_LIST] = "List",			[KEY_MEMO] = "Memo",
+	[KEY_CALENDAR] = "Calendar",		[KEY_RED] = "Red",
+	[KEY_GREEN] = "Green",			[KEY_YELLOW] = "Yellow",
+	[KEY_BLUE] = "Blue",			[KEY_CHANNELUP] = "ChannelUp",
+	[KEY_CHANNELDOWN] = "ChannelDown",	[KEY_FIRST] = "First",
+	[KEY_LAST] = "Last",			[KEY_AB] = "AB",
+	[KEY_NEXT] = "Next",			[KEY_RESTART] = "Restart",
+	[KEY_SLOW] = "Slow",			[KEY_SHUFFLE] = "Shuffle",
+	[KEY_BREAK] = "Break",			[KEY_PREVIOUS] = "Previous",
+	[KEY_DIGITS] = "Digits",		[KEY_TEEN] = "TEEN",
+	[KEY_TWEN] = "TWEN",			[KEY_DEL_EOL] = "DeleteEOL",
+	[KEY_DEL_EOS] = "DeleteEOS",		[KEY_INS_LINE] = "InsertLine",
+	[KEY_DEL_LINE] = "DeleteLine",
+	[KEY_SEND] = "Send",			[KEY_REPLY] = "Reply",
+	[KEY_FORWARDMAIL] = "ForwardMail",	[KEY_SAVE] = "Save",
+	[KEY_DOCUMENTS] = "Documents",
+	[KEY_FN] = "Fn",			[KEY_FN_ESC] = "Fn+ESC",
+	[KEY_FN_1] = "Fn+1",			[KEY_FN_2] = "Fn+2",
+	[KEY_FN_B] = "Fn+B",			[KEY_FN_D] = "Fn+D",
+	[KEY_FN_E] = "Fn+E",			[KEY_FN_F] = "Fn+F",
+	[KEY_FN_S] = "Fn+S",
+	[KEY_FN_F1] = "Fn+F1",			[KEY_FN_F2] = "Fn+F2",
+	[KEY_FN_F3] = "Fn+F3",			[KEY_FN_F4] = "Fn+F4",
+	[KEY_FN_F5] = "Fn+F5",			[KEY_FN_F6] = "Fn+F6",
+	[KEY_FN_F7] = "Fn+F7",			[KEY_FN_F8] = "Fn+F8",
+	[KEY_FN_F9] = "Fn+F9",			[KEY_FN_F10] = "Fn+F10",
+	[KEY_FN_F11] = "Fn+F11",		[KEY_FN_F12] = "Fn+F12",
+	[KEY_KBDILLUMTOGGLE] = "KbdIlluminationToggle",
+	[KEY_KBDILLUMDOWN] = "KbdIlluminationDown",
+	[KEY_KBDILLUMUP] = "KbdIlluminationUp",
+	[KEY_SWITCHVIDEOMODE] = "SwitchVideoMode",
+};
+
+static char *relatives[REL_MAX + 1] = {
+	[REL_X] = "X",			[REL_Y] = "Y",
+	[REL_Z] = "Z",			[REL_RX] = "Rx",
+	[REL_RY] = "Ry",		[REL_RZ] = "Rz",
+	[REL_HWHEEL] = "HWheel",	[REL_DIAL] = "Dial",
+	[REL_WHEEL] = "Wheel",		[REL_MISC] = "Misc",
+};
+
+static char *absolutes[ABS_MAX + 1] = {
+	[ABS_X] = "X",			[ABS_Y] = "Y",
+	[ABS_Z] = "Z",			[ABS_RX] = "Rx",
+	[ABS_RY] = "Ry",		[ABS_RZ] = "Rz",
+	[ABS_THROTTLE] = "Throttle",	[ABS_RUDDER] = "Rudder",
+	[ABS_WHEEL] = "Wheel",		[ABS_GAS] = "Gas",
+	[ABS_BRAKE] = "Brake",		[ABS_HAT0X] = "Hat0X",
+	[ABS_HAT0Y] = "Hat0Y",		[ABS_HAT1X] = "Hat1X",
+	[ABS_HAT1Y] = "Hat1Y",		[ABS_HAT2X] = "Hat2X",
+	[ABS_HAT2Y] = "Hat2Y",		[ABS_HAT3X] = "Hat3X",
+	[ABS_HAT3Y] = "Hat 3Y",		[ABS_PRESSURE] = "Pressure",
+	[ABS_DISTANCE] = "Distance",	[ABS_TILT_X] = "XTilt",
+	[ABS_TILT_Y] = "YTilt",		[ABS_TOOL_WIDTH] = "Tool Width",
+	[ABS_VOLUME] = "Volume",	[ABS_MISC] = "Misc",
+};
+
+static char *misc[MSC_MAX + 1] = {
+	[MSC_SERIAL] = "Serial",	[MSC_PULSELED] = "Pulseled",
+	[MSC_GESTURE] = "Gesture",	[MSC_RAW] = "RawData"
+};
+
+static char *leds[LED_MAX + 1] = {
+	[LED_NUML] = "NumLock",		[LED_CAPSL] = "CapsLock",
+	[LED_SCROLLL] = "ScrollLock",	[LED_COMPOSE] = "Compose",
+	[LED_KANA] = "Kana",		[LED_SLEEP] = "Sleep",
+	[LED_SUSPEND] = "Suspend",	[LED_MUTE] = "Mute",
+	[LED_MISC] = "Misc",
+};
+
+static char *repeats[REP_MAX + 1] = {
+	[REP_DELAY] = "Delay",		[REP_PERIOD] = "Period"
+};
+
+static char *sounds[SND_MAX + 1] = {
+	[SND_CLICK] = "Click",		[SND_BELL] = "Bell",
+	[SND_TONE] = "Tone"
+};
+
+static char **names[EV_MAX + 1] = {
+	[EV_SYN] = syncs,			[EV_KEY] = keys,
+	[EV_REL] = relatives,			[EV_ABS] = absolutes,
+	[EV_MSC] = misc,			[EV_LED] = leds,
+	[EV_SND] = sounds,			[EV_REP] = repeats,
+};
+
+void hid_resolv_event(__u8 type, __u16 code) {
+
+	printk("%s.%s", events[type] ? events[type] : "?",
+		names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
+}
+EXPORT_SYMBOL_GPL(hid_resolv_event);
+
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index c7a6833..25d180a 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -31,9 +31,8 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 
-#undef DEBUG
-
 #include <linux/hid.h>
+#include <linux/hid-debug.h>
 
 static int hid_pb_fnmode = 1;
 module_param_named(pb_fnmode, hid_pb_fnmode, int, 0644);
@@ -252,9 +251,9 @@
 
 	field->hidinput = hidinput;
 
-#ifdef DEBUG
+#ifdef CONFIG_HID_DEBUG
 	printk(KERN_DEBUG "Mapping: ");
-	resolv_usage(usage->hid);
+	hid_resolv_usage(usage->hid);
 	printk(" ---> ");
 #endif
 
@@ -682,14 +681,14 @@
 			field->dpad = usage->code;
 	}
 
-#ifdef DEBUG
-	resolv_event(usage->type, usage->code);
+	hid_resolv_event(usage->type, usage->code);
+#ifdef CONFIG_HID_DEBUG
 	printk("\n");
 #endif
 	return;
 
 ignore:
-#ifdef DEBUG
+#ifdef CONFIG_HID_DEBUG
 	printk("IGNORED\n");
 #endif
 	return;
@@ -804,6 +803,18 @@
 }
 EXPORT_SYMBOL_GPL(hidinput_find_field);
 
+static int hidinput_open(struct input_dev *dev)
+{
+	struct hid_device *hid = dev->private;
+	return hid->hid_open(hid);
+}
+
+static void hidinput_close(struct input_dev *dev)
+{
+	struct hid_device *hid = dev->private;
+	hid->hid_close(hid);
+}
+
 /*
  * Register the input device; print a message.
  * Configure the input layer interface
@@ -816,6 +827,7 @@
 	struct hid_input *hidinput = NULL;
 	struct input_dev *input_dev;
 	int i, j, k;
+	int max_report_type = HID_OUTPUT_REPORT;
 
 	INIT_LIST_HEAD(&hid->inputs);
 
@@ -828,7 +840,10 @@
 	if (i == hid->maxcollection)
 		return -1;
 
-	for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++)
+	if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
+		max_report_type = HID_INPUT_REPORT;
+
+	for (k = HID_INPUT_REPORT; k <= max_report_type; k++)
 		list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
 
 			if (!report->maxfield)
@@ -846,8 +861,8 @@
 
 				input_dev->private = hid;
 				input_dev->event = hid->hidinput_input_event;
-				input_dev->open = hid->hidinput_open;
-				input_dev->close = hid->hidinput_close;
+				input_dev->open = hidinput_open;
+				input_dev->close = hidinput_close;
 
 				input_dev->name = hid->name;
 				input_dev->phys = hid->phys;
diff --git a/drivers/hwmon/ams/ams-input.c b/drivers/hwmon/ams/ams-input.c
index f126aa4..1821016 100644
--- a/drivers/hwmon/ams/ams-input.c
+++ b/drivers/hwmon/ams/ams-input.c
@@ -153,7 +153,7 @@
 }
 
 /* Call with ams_info.lock held! */
-void ams_input_exit()
+void ams_input_exit(void)
 {
 	ams_input_disable();
 	device_remove_file(&ams_info.of_dev->dev, &dev_attr_joystick);
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
index ccdf3e9..9fafadb 100644
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/i2c/chips/isp1301_omap.c
@@ -27,7 +27,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb.h>
 #include <linux/usb/otg.h>
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 3f82805..ec03341 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -167,6 +167,13 @@
 	  Support for Compact Flash cards, outboard IDE disks, tape drives,
 	  and CD-ROM drives connected through a PCMCIA card.
 
+config BLK_DEV_DELKIN
+	tristate "Cardbus IDE support (Delkin/ASKA/Workbit)"
+	depends on CARDBUS && PCI
+	help
+	  Support for Delkin, ASKA, and Workbit Cardbus CompactFlash
+	  Adapters.  This may also work for similar SD and XD adapters.
+
 config BLK_DEV_IDECD
 	tristate "Include IDE/ATAPI CDROM support"
 	---help---
@@ -264,6 +271,13 @@
 	  If both this SCSI emulation and native ATAPI support are compiled
 	  into the kernel, the native support will be used.
 
+config BLK_DEV_IDEACPI
+	bool "IDE ACPI support"
+	depends on ACPI
+	---help---
+	  Implement ACPI support for generic IDE devices. On modern
+	  machines ACPI support is required to properly handle ACPI S3 states.
+
 config IDE_TASK_IOCTL
 	bool "IDE Taskfile Access"
 	help
@@ -606,6 +620,11 @@
 	  the kernel to change PIO, DMA and UDMA speeds and to configure
 	  the chip to optimum performance.
 
+config BLK_DEV_IT8213
+	tristate "IT8213 IDE support"
+	help
+	 This driver adds support for the ITE 8213 IDE controller.
+
 config BLK_DEV_IT821X
 	tristate "IT821X IDE support"
 	help
@@ -742,6 +761,11 @@
 	  This allows the kernel to change PIO, DMA and UDMA speeds and to
 	  configure the chip to optimum performance.
 
+config BLK_DEV_TC86C001
+	tristate "Toshiba TC86C001 support"
+	help
+	This driver adds support for Toshiba TC86C001 GOKU-S chip.
+
 endif
 
 config BLK_DEV_IDE_PMAC
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index 569fae7..d9f029e 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -22,6 +22,7 @@
 ide-core-$(CONFIG_BLK_DEV_IDEDMA)	+= ide-dma.o
 ide-core-$(CONFIG_PROC_FS)		+= ide-proc.o
 ide-core-$(CONFIG_BLK_DEV_IDEPNP)	+= ide-pnp.o
+ide-core-$(CONFIG_BLK_DEV_IDEACPI)	+= ide-acpi.o
 
 # built-in only drivers from arm/
 ide-core-$(CONFIG_IDE_ARM)		+= arm/ide_arm.o
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
new file mode 100644
index 0000000..17aea65
--- /dev/null
+++ b/drivers/ide/ide-acpi.c
@@ -0,0 +1,697 @@
+/*
+ * ide-acpi.c
+ * Provides ACPI support for IDE drives.
+ *
+ * Copyright (C) 2005 Intel Corp.
+ * Copyright (C) 2005 Randy Dunlap
+ * Copyright (C) 2006 SUSE Linux Products GmbH
+ * Copyright (C) 2006 Hannes Reinecke
+ */
+
+#include <linux/ata.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <acpi/acpi.h>
+#include <linux/ide.h>
+#include <linux/pci.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acnames.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+#include <acpi/acexcep.h>
+#include <acpi/acmacros.h>
+#include <acpi/actypes.h>
+
+#define REGS_PER_GTF		7
+struct taskfile_array {
+	u8	tfa[REGS_PER_GTF];	/* regs. 0x1f1 - 0x1f7 */
+};
+
+struct GTM_buffer {
+	u32	PIO_speed0;
+	u32	DMA_speed0;
+	u32	PIO_speed1;
+	u32	DMA_speed1;
+	u32	GTM_flags;
+};
+
+struct ide_acpi_drive_link {
+	ide_drive_t	*drive;
+	acpi_handle	 obj_handle;
+	u8		 idbuff[512];
+};
+
+struct ide_acpi_hwif_link {
+	ide_hwif_t			*hwif;
+	acpi_handle			 obj_handle;
+	struct GTM_buffer		 gtm;
+	struct ide_acpi_drive_link	 master;
+	struct ide_acpi_drive_link	 slave;
+};
+
+#undef DEBUGGING
+/* note: adds function name and KERN_DEBUG */
+#ifdef DEBUGGING
+#define DEBPRINT(fmt, args...)	\
+		printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args)
+#else
+#define DEBPRINT(fmt, args...)	do {} while (0)
+#endif	/* DEBUGGING */
+
+extern int ide_noacpi;
+extern int ide_noacpitfs;
+extern int ide_noacpionboot;
+
+/**
+ * ide_get_dev_handle - finds acpi_handle and PCI device.function
+ * @dev: device to locate
+ * @handle: returned acpi_handle for @dev
+ * @pcidevfn: return PCI device.func for @dev
+ *
+ * Returns the ACPI object handle to the corresponding PCI device.
+ *
+ * Returns 0 on success, <0 on error.
+ */
+static int ide_get_dev_handle(struct device *dev, acpi_handle *handle,
+			       acpi_integer *pcidevfn)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	unsigned int bus, devnum, func;
+	acpi_integer addr;
+	acpi_handle dev_handle;
+	struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER,
+					.pointer = NULL};
+	acpi_status status;
+	struct acpi_device_info	*dinfo = NULL;
+	int ret = -ENODEV;
+
+	bus = pdev->bus->number;
+	devnum = PCI_SLOT(pdev->devfn);
+	func = PCI_FUNC(pdev->devfn);
+	/* ACPI _ADR encoding for PCI bus: */
+	addr = (acpi_integer)(devnum << 16 | func);
+
+	DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func);
+
+	dev_handle = DEVICE_ACPI_HANDLE(dev);
+	if (!dev_handle) {
+		DEBPRINT("no acpi handle for device\n");
+		goto err;
+	}
+
+	status = acpi_get_object_info(dev_handle, &buffer);
+	if (ACPI_FAILURE(status)) {
+		DEBPRINT("get_object_info for device failed\n");
+		goto err;
+	}
+	dinfo = buffer.pointer;
+	if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&
+	    dinfo->address == addr) {
+		*pcidevfn = addr;
+		*handle = dev_handle;
+	} else {
+		DEBPRINT("get_object_info for device has wrong "
+			" address: %llu, should be %u\n",
+			dinfo ? (unsigned long long)dinfo->address : -1ULL,
+			(unsigned int)addr);
+		goto err;
+	}
+
+	DEBPRINT("for dev=0x%x.%x, addr=0x%llx, *handle=0x%p\n",
+		 devnum, func, (unsigned long long)addr, *handle);
+	ret = 0;
+err:
+	kfree(dinfo);
+	return ret;
+}
+
+/**
+ * ide_acpi_hwif_get_handle - Get ACPI object handle for a given hwif
+ * @hwif: device to locate
+ *
+ * Retrieves the object handle for a given hwif.
+ *
+ * Returns handle on success, 0 on error.
+ */
+static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
+{
+	struct device		*dev = hwif->gendev.parent;
+	acpi_handle		dev_handle;
+	acpi_integer		pcidevfn;
+	acpi_handle		chan_handle;
+	int			err;
+
+	DEBPRINT("ENTER: device %s\n", hwif->name);
+
+	if (!dev) {
+		DEBPRINT("no PCI device for %s\n", hwif->name);
+		return NULL;
+	}
+
+	err = ide_get_dev_handle(dev, &dev_handle, &pcidevfn);
+	if (err < 0) {
+		DEBPRINT("ide_get_dev_handle failed (%d)\n", err);
+		return NULL;
+	}
+
+	/* get child objects of dev_handle == channel objects,
+	 * + _their_ children == drive objects */
+	/* channel is hwif->channel */
+	chan_handle = acpi_get_child(dev_handle, hwif->channel);
+	DEBPRINT("chan adr=%d: handle=0x%p\n",
+		 hwif->channel, chan_handle);
+
+	return chan_handle;
+}
+
+/**
+ * ide_acpi_drive_get_handle - Get ACPI object handle for a given drive
+ * @drive: device to locate
+ *
+ * Retrieves the object handle of a given drive. According to the ACPI
+ * spec the drive is a child of the hwif.
+ *
+ * Returns handle on success, 0 on error.
+ */
+static acpi_handle ide_acpi_drive_get_handle(ide_drive_t *drive)
+{
+	ide_hwif_t	*hwif = HWIF(drive);
+	int		 port;
+	acpi_handle	 drive_handle;
+
+	if (!hwif->acpidata)
+		return NULL;
+
+	if (!hwif->acpidata->obj_handle)
+		return NULL;
+
+	port = hwif->channel ? drive->dn - 2: drive->dn;
+
+	DEBPRINT("ENTER: %s at channel#: %d port#: %d\n",
+		 drive->name, hwif->channel, port);
+
+
+	/* TBD: could also check ACPI object VALID bits */
+	drive_handle = acpi_get_child(hwif->acpidata->obj_handle, port);
+	DEBPRINT("drive %s handle 0x%p\n", drive->name, drive_handle);
+
+	return drive_handle;
+}
+
+/**
+ * do_drive_get_GTF - get the drive bootup default taskfile settings
+ * @drive: the drive for which the taskfile settings should be retrieved
+ * @gtf_length: number of bytes of _GTF data returned at @gtf_address
+ * @gtf_address: buffer containing _GTF taskfile arrays
+ *
+ * The _GTF method has no input parameters.
+ * It returns a variable number of register set values (registers
+ * hex 1F1..1F7, taskfiles).
+ * The <variable number> is not known in advance, so have ACPI-CA
+ * allocate the buffer as needed and return it, then free it later.
+ *
+ * The returned @gtf_length and @gtf_address are only valid if the
+ * function return value is 0.
+ */
+static int do_drive_get_GTF(ide_drive_t *drive,
+		     unsigned int *gtf_length, unsigned long *gtf_address,
+		     unsigned long *obj_loc)
+{
+	acpi_status			status;
+	struct acpi_buffer		output;
+	union acpi_object 		*out_obj;
+	ide_hwif_t			*hwif = HWIF(drive);
+	struct device			*dev = hwif->gendev.parent;
+	int				err = -ENODEV;
+	int				port;
+
+	*gtf_length = 0;
+	*gtf_address = 0UL;
+	*obj_loc = 0UL;
+
+	if (ide_noacpi)
+		return 0;
+
+	if (!dev) {
+		DEBPRINT("no PCI device for %s\n", hwif->name);
+		goto out;
+	}
+
+	if (!hwif->acpidata) {
+		DEBPRINT("no ACPI data for %s\n", hwif->name);
+		goto out;
+	}
+
+	port = hwif->channel ? drive->dn - 2: drive->dn;
+
+	if (!drive->acpidata) {
+		if (port == 0) {
+			drive->acpidata = &hwif->acpidata->master;
+			hwif->acpidata->master.drive = drive;
+		} else {
+			drive->acpidata = &hwif->acpidata->slave;
+			hwif->acpidata->slave.drive = drive;
+		}
+	}
+
+	DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n",
+		 hwif->name, dev->bus_id, port, hwif->channel);
+
+	if (!drive->present) {
+		DEBPRINT("%s drive %d:%d not present\n",
+			 hwif->name, hwif->channel, port);
+		goto out;
+	}
+
+	/* Get this drive's _ADR info. if not already known. */
+	if (!drive->acpidata->obj_handle) {
+		drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
+		if (!drive->acpidata->obj_handle) {
+			DEBPRINT("No ACPI object found for %s\n",
+				 drive->name);
+			goto out;
+		}
+	}
+
+	/* Setting up output buffer */
+	output.length = ACPI_ALLOCATE_BUFFER;
+	output.pointer = NULL;	/* ACPI-CA sets this; save/free it later */
+
+	/* _GTF has no input parameters */
+	err = -EIO;
+	status = acpi_evaluate_object(drive->acpidata->obj_handle, "_GTF",
+				      NULL, &output);
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_DEBUG
+		       "%s: Run _GTF error: status = 0x%x\n",
+		       __FUNCTION__, status);
+		goto out;
+	}
+
+	if (!output.length || !output.pointer) {
+		DEBPRINT("Run _GTF: "
+		       "length or ptr is NULL (0x%llx, 0x%p)\n",
+		       (unsigned long long)output.length,
+		       output.pointer);
+		goto out;
+	}
+
+	out_obj = output.pointer;
+	if (out_obj->type != ACPI_TYPE_BUFFER) {
+		DEBPRINT("Run _GTF: error: "
+		       "expected object type of ACPI_TYPE_BUFFER, "
+		       "got 0x%x\n", out_obj->type);
+		err = -ENOENT;
+		kfree(output.pointer);
+		goto out;
+	}
+
+	if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
+	    out_obj->buffer.length % REGS_PER_GTF) {
+		printk(KERN_ERR
+		       "%s: unexpected GTF length (%d) or addr (0x%p)\n",
+		       __FUNCTION__, out_obj->buffer.length,
+		       out_obj->buffer.pointer);
+		err = -ENOENT;
+		kfree(output.pointer);
+		goto out;
+	}
+
+	*gtf_length = out_obj->buffer.length;
+	*gtf_address = (unsigned long)out_obj->buffer.pointer;
+	*obj_loc = (unsigned long)out_obj;
+	DEBPRINT("returning gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n",
+		 *gtf_length, *gtf_address, *obj_loc);
+	err = 0;
+out:
+	return err;
+}
+
+/**
+ * taskfile_load_raw - send taskfile registers to drive
+ * @drive: drive to which output is sent
+ * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
+ *
+ * Outputs IDE taskfile to the drive.
+ */
+static int taskfile_load_raw(ide_drive_t *drive,
+			      const struct taskfile_array *gtf)
+{
+	ide_task_t args;
+	int err = 0;
+
+	DEBPRINT("(0x1f1-1f7): hex: "
+	       "%02x %02x %02x %02x %02x %02x %02x\n",
+	       gtf->tfa[0], gtf->tfa[1], gtf->tfa[2],
+	       gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
+
+	memset(&args, 0, sizeof(ide_task_t));
+	args.command_type = IDE_DRIVE_TASK_NO_DATA;
+	args.data_phase   = TASKFILE_IN;
+	args.handler      = &task_no_data_intr;
+
+	/* convert gtf to IDE Taskfile */
+	args.tfRegister[1] = gtf->tfa[0];	/* 0x1f1 */
+	args.tfRegister[2] = gtf->tfa[1];	/* 0x1f2 */
+	args.tfRegister[3] = gtf->tfa[2];	/* 0x1f3 */
+	args.tfRegister[4] = gtf->tfa[3];	/* 0x1f4 */
+	args.tfRegister[5] = gtf->tfa[4];	/* 0x1f5 */
+	args.tfRegister[6] = gtf->tfa[5];	/* 0x1f6 */
+	args.tfRegister[7] = gtf->tfa[6];	/* 0x1f7 */
+
+	if (ide_noacpitfs) {
+		DEBPRINT("_GTF execution disabled\n");
+		return err;
+	}
+
+	err = ide_raw_taskfile(drive, &args, NULL);
+	if (err)
+		printk(KERN_ERR "%s: ide_raw_taskfile failed: %u\n",
+		       __FUNCTION__, err);
+
+	return err;
+}
+
+/**
+ * do_drive_set_taskfiles - write the drive taskfile settings from _GTF
+ * @drive: the drive to which the taskfile command should be sent
+ * @gtf_length: total number of bytes of _GTF taskfiles
+ * @gtf_address: location of _GTF taskfile arrays
+ *
+ * Write {gtf_address, length gtf_length} in groups of
+ * REGS_PER_GTF bytes.
+ */
+static int do_drive_set_taskfiles(ide_drive_t *drive,
+				  unsigned int gtf_length,
+				  unsigned long gtf_address)
+{
+	int			rc = -ENODEV, err;
+	int			gtf_count = gtf_length / REGS_PER_GTF;
+	int			ix;
+	struct taskfile_array	*gtf;
+
+	if (ide_noacpi)
+		return 0;
+
+	DEBPRINT("ENTER: %s, hard_port#: %d\n", drive->name, drive->dn);
+
+	if (!drive->present)
+		goto out;
+	if (!gtf_count)		/* shouldn't be here */
+		goto out;
+
+	DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n",
+		 gtf_length, gtf_length, gtf_count, gtf_address);
+
+	if (gtf_length % REGS_PER_GTF) {
+		printk(KERN_ERR "%s: unexpected GTF length (%d)\n",
+		       __FUNCTION__, gtf_length);
+		goto out;
+	}
+
+	rc = 0;
+	for (ix = 0; ix < gtf_count; ix++) {
+		gtf = (struct taskfile_array *)
+			(gtf_address + ix * REGS_PER_GTF);
+
+		/* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */
+		err = taskfile_load_raw(drive, gtf);
+		if (err)
+			rc = err;
+	}
+
+out:
+	return rc;
+}
+
+/**
+ * ide_acpi_exec_tfs - get then write drive taskfile settings
+ * @drive: the drive for which the taskfile settings should be
+ *         written.
+ *
+ * According to the ACPI spec this should be called after _STM
+ * has been evaluated for the interface. Some ACPI vendors interpret
+ * that as a hard requirement and modify the taskfile according
+ * to the Identify Drive information passed down with _STM.
+ * So one should really make sure to call this only after _STM has
+ * been executed.
+ */
+int ide_acpi_exec_tfs(ide_drive_t *drive)
+{
+	int		ret;
+	unsigned int	gtf_length;
+	unsigned long	gtf_address;
+	unsigned long	obj_loc;
+
+	if (ide_noacpi)
+		return 0;
+
+	DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn);
+
+	ret = do_drive_get_GTF(drive, &gtf_length, &gtf_address, &obj_loc);
+	if (ret < 0) {
+		DEBPRINT("get_GTF error (%d)\n", ret);
+		return ret;
+	}
+
+	DEBPRINT("call set_taskfiles, drive=%s\n", drive->name);
+
+	ret = do_drive_set_taskfiles(drive, gtf_length, gtf_address);
+	kfree((void *)obj_loc);
+	if (ret < 0) {
+		DEBPRINT("set_taskfiles error (%d)\n", ret);
+	}
+
+	DEBPRINT("ret=%d\n", ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ide_acpi_exec_tfs);
+
+/**
+ * ide_acpi_get_timing - get the channel (controller) timings
+ * @hwif: target IDE interface (channel)
+ *
+ * This function executes the _GTM ACPI method for the target channel.
+ *
+ */
+void ide_acpi_get_timing(ide_hwif_t *hwif)
+{
+	acpi_status		status;
+	struct acpi_buffer	output;
+	union acpi_object 	*out_obj;
+
+	if (ide_noacpi)
+		return;
+
+	DEBPRINT("ENTER:\n");
+
+	if (!hwif->acpidata) {
+		DEBPRINT("no ACPI data for %s\n", hwif->name);
+		return;
+	}
+
+	/* Setting up output buffer for _GTM */
+	output.length = ACPI_ALLOCATE_BUFFER;
+	output.pointer = NULL;	/* ACPI-CA sets this; save/free it later */
+
+	/* _GTM has no input parameters */
+	status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_GTM",
+				      NULL, &output);
+
+	DEBPRINT("_GTM status: %d, outptr: 0x%p, outlen: 0x%llx\n",
+		 status, output.pointer,
+		 (unsigned long long)output.length);
+
+	if (ACPI_FAILURE(status)) {
+		DEBPRINT("Run _GTM error: status = 0x%x\n", status);
+		return;
+	}
+
+	if (!output.length || !output.pointer) {
+		DEBPRINT("Run _GTM: length or ptr is NULL (0x%llx, 0x%p)\n",
+		       (unsigned long long)output.length,
+		       output.pointer);
+		kfree(output.pointer);
+		return;
+	}
+
+	out_obj = output.pointer;
+	if (out_obj->type != ACPI_TYPE_BUFFER) {
+		kfree(output.pointer);
+		DEBPRINT("Run _GTM: error: "
+		       "expected object type of ACPI_TYPE_BUFFER, "
+		       "got 0x%x\n", out_obj->type);
+		return;
+	}
+
+	if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
+	    out_obj->buffer.length != sizeof(struct GTM_buffer)) {
+		kfree(output.pointer);
+		printk(KERN_ERR
+			"%s: unexpected _GTM length (0x%x)[should be 0x%zx] or "
+			"addr (0x%p)\n",
+			__FUNCTION__, out_obj->buffer.length,
+			sizeof(struct GTM_buffer), out_obj->buffer.pointer);
+		return;
+	}
+
+	memcpy(&hwif->acpidata->gtm, out_obj->buffer.pointer,
+	       sizeof(struct GTM_buffer));
+
+	DEBPRINT("_GTM info: ptr: 0x%p, len: 0x%x, exp.len: 0x%Zx\n",
+		 out_obj->buffer.pointer, out_obj->buffer.length,
+		 sizeof(struct GTM_buffer));
+
+	DEBPRINT("_GTM fields: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
+		 hwif->acpidata->gtm.PIO_speed0,
+		 hwif->acpidata->gtm.DMA_speed0,
+		 hwif->acpidata->gtm.PIO_speed1,
+		 hwif->acpidata->gtm.DMA_speed1,
+		 hwif->acpidata->gtm.GTM_flags);
+
+	kfree(output.pointer);
+}
+EXPORT_SYMBOL_GPL(ide_acpi_get_timing);
+
+/**
+ * ide_acpi_push_timing - set the channel (controller) timings
+ * @hwif: target IDE interface (channel)
+ *
+ * This function executes the _STM ACPI method for the target channel.
+ *
+ * _STM requires Identify Drive data, which has to passed as an argument.
+ * Unfortunately hd_driveid is a mangled version which we can't readily
+ * use; hence we'll get the information afresh.
+ */
+void ide_acpi_push_timing(ide_hwif_t *hwif)
+{
+	acpi_status		status;
+	struct acpi_object_list	input;
+	union acpi_object 	in_params[3];
+	struct ide_acpi_drive_link	*master = &hwif->acpidata->master;
+	struct ide_acpi_drive_link	*slave = &hwif->acpidata->slave;
+
+	if (ide_noacpi)
+		return;
+
+	DEBPRINT("ENTER:\n");
+
+	if (!hwif->acpidata) {
+		DEBPRINT("no ACPI data for %s\n", hwif->name);
+		return;
+	}
+
+	/* Give the GTM buffer + drive Identify data to the channel via the
+	 * _STM method: */
+	/* setup input parameters buffer for _STM */
+	input.count = 3;
+	input.pointer = in_params;
+	in_params[0].type = ACPI_TYPE_BUFFER;
+	in_params[0].buffer.length = sizeof(struct GTM_buffer);
+	in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm;
+	in_params[1].type = ACPI_TYPE_BUFFER;
+	in_params[1].buffer.length = sizeof(struct hd_driveid);
+	in_params[1].buffer.pointer = (u8 *)&master->idbuff;
+	in_params[2].type = ACPI_TYPE_BUFFER;
+	in_params[2].buffer.length = sizeof(struct hd_driveid);
+	in_params[2].buffer.pointer = (u8 *)&slave->idbuff;
+	/* Output buffer: _STM has no output */
+
+	status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_STM",
+				      &input, NULL);
+
+	if (ACPI_FAILURE(status)) {
+		DEBPRINT("Run _STM error: status = 0x%x\n", status);
+	}
+	DEBPRINT("_STM status: %d\n", status);
+}
+EXPORT_SYMBOL_GPL(ide_acpi_push_timing);
+
+/**
+ * ide_acpi_init - initialize the ACPI link for an IDE interface
+ * @hwif: target IDE interface (channel)
+ *
+ * The ACPI spec is not quite clear when the drive identify buffer
+ * should be obtained. Calling IDENTIFY DEVICE during shutdown
+ * is not the best of ideas as the drive might already being put to
+ * sleep. And obviously we can't call it during resume.
+ * So we get the information during startup; but this means that
+ * any changes during run-time will be lost after resume.
+ */
+void ide_acpi_init(ide_hwif_t *hwif)
+{
+	int unit;
+	int			err;
+	struct ide_acpi_drive_link	*master;
+	struct ide_acpi_drive_link	*slave;
+
+	hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL);
+	if (!hwif->acpidata)
+		return;
+
+	hwif->acpidata->obj_handle = ide_acpi_hwif_get_handle(hwif);
+	if (!hwif->acpidata->obj_handle) {
+		DEBPRINT("no ACPI object for %s found\n", hwif->name);
+		kfree(hwif->acpidata);
+		hwif->acpidata = NULL;
+		return;
+	}
+
+	/*
+	 * The ACPI spec mandates that we send information
+	 * for both drives, regardless whether they are connected
+	 * or not.
+	 */
+	hwif->acpidata->master.drive = &hwif->drives[0];
+	hwif->drives[0].acpidata = &hwif->acpidata->master;
+	master = &hwif->acpidata->master;
+
+	hwif->acpidata->slave.drive = &hwif->drives[1];
+	hwif->drives[1].acpidata = &hwif->acpidata->slave;
+	slave = &hwif->acpidata->slave;
+
+
+	/*
+	 * Send IDENTIFY for each drive
+	 */
+	if (master->drive->present) {
+		err = taskfile_lib_get_identify(master->drive, master->idbuff);
+		if (err) {
+			DEBPRINT("identify device %s failed (%d)\n",
+				 master->drive->name, err);
+		}
+	}
+
+	if (slave->drive->present) {
+		err = taskfile_lib_get_identify(slave->drive, slave->idbuff);
+		if (err) {
+			DEBPRINT("identify device %s failed (%d)\n",
+				 slave->drive->name, err);
+		}
+	}
+
+	if (ide_noacpionboot) {
+		DEBPRINT("ACPI methods disabled on boot\n");
+		return;
+	}
+
+	/*
+	 * ACPI requires us to call _STM on startup
+	 */
+	ide_acpi_get_timing(hwif);
+	ide_acpi_push_timing(hwif);
+
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+
+		if (drive->present) {
+			/* Execute ACPI startup code */
+			ide_acpi_exec_tfs(drive);
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(ide_acpi_init);
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 5a5c565..176bbc8 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -1384,6 +1384,9 @@
 
 done:
 	init_gendisk(hwif);
+
+	ide_acpi_init(hwif);
+
 	hwif->present = 1;	/* success */
 	return 1;
 
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 6c9bd51..c750f6c 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -187,6 +187,12 @@
 
 EXPORT_SYMBOL(noautodma);
 
+#ifdef CONFIG_BLK_DEV_IDEACPI
+int ide_noacpi = 0;
+int ide_noacpitfs = 1;
+int ide_noacpionboot = 1;
+#endif
+
 /*
  * This is declared extern in ide.h, for access by other IDE modules:
  */
@@ -1214,10 +1220,15 @@
 static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
 {
 	ide_drive_t *drive = dev->driver_data;
+	ide_hwif_t *hwif = HWIF(drive);
 	struct request rq;
 	struct request_pm_state rqpm;
 	ide_task_t args;
 
+	/* Call ACPI _GTM only once */
+	if (!(drive->dn % 2))
+		ide_acpi_get_timing(hwif);
+
 	memset(&rq, 0, sizeof(rq));
 	memset(&rqpm, 0, sizeof(rqpm));
 	memset(&args, 0, sizeof(args));
@@ -1235,10 +1246,17 @@
 static int generic_ide_resume(struct device *dev)
 {
 	ide_drive_t *drive = dev->driver_data;
+	ide_hwif_t *hwif = HWIF(drive);
 	struct request rq;
 	struct request_pm_state rqpm;
 	ide_task_t args;
 
+	/* Call ACPI _STM only once */
+	if (!(drive->dn % 2))
+		ide_acpi_push_timing(hwif);
+
+	ide_acpi_exec_tfs(drive);
+
 	memset(&rq, 0, sizeof(rq));
 	memset(&rqpm, 0, sizeof(rqpm));
 	memset(&args, 0, sizeof(args));
@@ -1543,6 +1561,24 @@
 	}
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 
+#ifdef CONFIG_BLK_DEV_IDEACPI
+	if (!strcmp(s, "ide=noacpi")) {
+		//printk(" : Disable IDE ACPI support.\n");
+		ide_noacpi = 1;
+		return 1;
+	}
+	if (!strcmp(s, "ide=acpigtf")) {
+		//printk(" : Enable IDE ACPI _GTF support.\n");
+		ide_noacpitfs = 0;
+		return 1;
+	}
+	if (!strcmp(s, "ide=acpionboot")) {
+		//printk(" : Call IDE ACPI methods on boot.\n");
+		ide_noacpionboot = 0;
+		return 1;
+	}
+#endif /* CONFIG_BLK_DEV_IDEACPI */
+
 	/*
 	 * Look for drive options:  "hdx="
 	 */
diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
index fef0896..6591ff4 100644
--- a/drivers/ide/pci/Makefile
+++ b/drivers/ide/pci/Makefile
@@ -9,9 +9,10 @@
 obj-$(CONFIG_BLK_DEV_CS5535)		+= cs5535.o
 obj-$(CONFIG_BLK_DEV_SC1200)		+= sc1200.o
 obj-$(CONFIG_BLK_DEV_CY82C693)		+= cy82c693.o
+obj-$(CONFIG_BLK_DEV_DELKIN)		+= delkin_cb.o
 obj-$(CONFIG_BLK_DEV_HPT34X)		+= hpt34x.o
 obj-$(CONFIG_BLK_DEV_HPT366)		+= hpt366.o
-#obj-$(CONFIG_BLK_DEV_HPT37X)		+= hpt37x.o
+obj-$(CONFIG_BLK_DEV_IT8213)		+= it8213.o
 obj-$(CONFIG_BLK_DEV_IT821X)		+= it821x.o
 obj-$(CONFIG_BLK_DEV_JMICRON)		+= jmicron.o
 obj-$(CONFIG_BLK_DEV_NS87415)		+= ns87415.o
@@ -26,6 +27,7 @@
 obj-$(CONFIG_BLK_DEV_SIS5513)		+= sis5513.o
 obj-$(CONFIG_BLK_DEV_SL82C105)		+= sl82c105.o
 obj-$(CONFIG_BLK_DEV_SLC90E66)		+= slc90e66.o
+obj-$(CONFIG_BLK_DEV_TC86C001)		+= tc86c001.o
 obj-$(CONFIG_BLK_DEV_TRIFLEX)		+= triflex.o
 obj-$(CONFIG_BLK_DEV_TRM290)		+= trm290.o
 obj-$(CONFIG_BLK_DEV_VIA82CXXX)		+= via82cxxx.o
diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c
new file mode 100644
index 0000000..e2672fc
--- /dev/null
+++ b/drivers/ide/pci/delkin_cb.c
@@ -0,0 +1,140 @@
+/*
+ *  linux/drivers/ide/pci/delkin_cb.c
+ *
+ *  Created 20 Oct 2004 by Mark Lord
+ *
+ *  Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter
+ *
+ *  Modeled after the 16-bit PCMCIA driver: ide-cs.c
+ *
+ *  This is slightly peculiar, in that it is a PCI driver,
+ *  but is NOT an IDE PCI driver -- the IDE layer does not directly
+ *  support hot insertion/removal of PCI interfaces, so this driver
+ *  is unable to use the IDE PCI interfaces.  Instead, it uses the
+ *  same interfaces as the ide-cs (PCMCIA) driver uses.
+ *  On the plus side, the driver is also smaller/simpler this way.
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+#include <linux/autoconf.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+/*
+ * No chip documentation has yet been found,
+ * so these configuration values were pulled from
+ * a running Win98 system using "debug".
+ * This gives around 3MByte/second read performance,
+ * which is about 2/3 of what the chip is capable of.
+ *
+ * There is also a 4KByte mmio region on the card,
+ * but its purpose has yet to be reverse-engineered.
+ */
+static const u8 setup[] = {
+	0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00,
+	0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13,
+};
+
+static int __devinit
+delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
+{
+	unsigned long base;
+	hw_regs_t hw;
+	ide_hwif_t *hwif = NULL;
+	ide_drive_t *drive;
+	int i, rc;
+
+	rc = pci_enable_device(dev);
+	if (rc) {
+		printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc);
+		return rc;
+	}
+	rc = pci_request_regions(dev, "delkin_cb");
+	if (rc) {
+		printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc);
+		pci_disable_device(dev);
+		return rc;
+	}
+	base = pci_resource_start(dev, 0);
+	outb(0x02, base + 0x1e);	/* set nIEN to block interrupts */
+	inb(base + 0x17);		/* read status to clear interrupts */
+	for (i = 0; i < sizeof(setup); ++i) {
+		if (setup[i])
+			outb(setup[i], base + i);
+	}
+	pci_release_regions(dev);	/* IDE layer handles regions itself */
+
+	memset(&hw, 0, sizeof(hw));
+	ide_std_init_ports(&hw, base + 0x10, base + 0x1e);
+	hw.irq = dev->irq;
+	hw.chipset = ide_pci;		/* this enables IRQ sharing */
+
+	rc = ide_register_hw_with_fixup(&hw, &hwif, ide_undecoded_slave);
+	if (rc < 0) {
+		printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc);
+		pci_disable_device(dev);
+		return -ENODEV;
+	}
+	pci_set_drvdata(dev, hwif);
+	hwif->pci_dev = dev;
+	drive = &hwif->drives[0];
+	if (drive->present) {
+		drive->io_32bit = 1;
+		drive->unmask   = 1;
+	}
+	return 0;
+}
+
+static void
+delkin_cb_remove (struct pci_dev *dev)
+{
+	ide_hwif_t *hwif = pci_get_drvdata(dev);
+
+	if (hwif)
+		ide_unregister(hwif->index);
+	pci_disable_device(dev);
+}
+
+static struct pci_device_id delkin_cb_pci_tbl[] __devinitdata = {
+	{ 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl);
+
+static struct pci_driver driver = {
+	.name		= "Delkin-ASKA-Workbit Cardbus IDE",
+	.id_table	= delkin_cb_pci_tbl,
+	.probe		= delkin_cb_probe,
+	.remove		= delkin_cb_remove,
+};
+
+static int
+delkin_cb_init (void)
+{
+	return pci_module_init(&driver);
+}
+
+static void
+delkin_cb_exit (void)
+{
+	pci_unregister_driver(&driver);
+}
+
+module_init(delkin_cb_init);
+module_exit(delkin_cb_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index b486442..05be8fa 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/hpt366.c		Version 0.36	April 25, 2003
+ * linux/drivers/ide/pci/hpt366.c		Version 1.01	Dec 23, 2006
  *
  * Copyright (C) 1999-2003		Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
@@ -60,13 +60,10 @@
  *   channel caused the cached register value to get out of sync with the
  *   actual one, the channels weren't serialized, the turnaround shouldn't
  *   be done on 66 MHz PCI bus
- * - avoid calibrating PLL twice as the second time results in a wrong PCI
- *   frequency and thus in the wrong timings for the secondary channel
- * - disable UltraATA/133 for HPT372 by default (50 MHz DPLL clock do not
- *   allow for this speed anyway)
- * - add support for HPT302N and HPT371N clocking (the same as for HPT372N)
- * - HPT371/N are single channel chips, so avoid touching the primary channel
- *   which exists only virtually (there's no pins for it)
+ * - disable UltraATA/100 for HPT370 by default as the 33 MHz clock being used
+ *   does not allow for this speed anyway
+ * - avoid touching disabled channels (e.g. HPT371/N are single channel chips,
+ *   their primary channel is kind of virtual, it isn't tied to any pins)
  * - fix/remove bad/unused timing tables and use one set of tables for the whole
  *   HPT37x chip family; save space by introducing the separate transfer mode
  *   table in which the mode lookup is done
@@ -76,11 +73,47 @@
  *   and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead
  * - pass to init_chipset() handlers a copy of the IDE PCI device structure as
  *   they tamper with its fields
- *		<source@mvista.com>
- *
+ * - pass  to the init_setup handlers a copy of the ide_pci_device_t structure
+ *   since they may tamper with its fields
+ * - prefix the driver startup messages with the real chip name
+ * - claim the extra 240 bytes of I/O space for all chips
+ * - optimize the rate masking/filtering and the drive list lookup code
+ * - use pci_get_slot() to get to the function 1 of HPT36x/374
+ * - cache offset of the channel's misc. control registers (MCRs) being used
+ *   throughout the driver
+ * - only touch the relevant MCR when detecting the cable type on HPT374's
+ *   function 1
+ * - rename all the register related variables consistently
+ * - move all the interrupt twiddling code from the speedproc handlers into
+ *   init_hwif_hpt366(), also grouping all the DMA related code together there
+ * - merge two HPT37x speedproc handlers, fix the PIO timing register mask and
+ *   separate the UltraDMA and MWDMA masks there to avoid changing PIO timings
+ *   when setting an UltraDMA mode
+ * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select
+ *   the best possible one
+ * - clean up DMA timeout handling for HPT370
+ * - switch to using the enumeration type to differ between the numerous chip
+ *   variants, matching PCI device/revision ID with the chip type early, at the
+ *   init_setup stage
+ * - extend the hpt_info structure to hold the DPLL and PCI clock frequencies,
+ *   stop duplicating it for each channel by storing the pointer in the pci_dev
+ *   structure: first, at the init_setup stage, point it to a static "template"
+ *   with only the chip type and its specific base DPLL frequency, the highest
+ *   supported DMA mode, and the chip settings table pointer filled, then, at
+ *   the init_chipset stage, allocate per-chip instance  and fill it with the
+ *   rest of the necessary information
+ * - get rid of the constant thresholds in the HPT37x PCI clock detection code,
+ *   switch  to calculating  PCI clock frequency based on the chip's base DPLL
+ *   frequency
+ * - switch to using the  DPLL clock and enable UltraATA/133 mode by default on
+ *   anything  newer than HPT370/A
+ * - fold PCI clock detection and DPLL setup code into init_chipset_hpt366(),
+ *   also fixing the interchanged 25/40 MHz PCI clock cases for HPT36x chips;
+ *   unify HPT36x/37x timing setup code and the speedproc handlers by joining
+ *   the register setting lists into the table indexed by the clock selected
+ *	Sergei Shtylyov, <sshtylyov@ru.mvista.com> or <source@mvista.com>
  */
 
-
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -332,93 +365,159 @@
 };
 
 #define HPT366_DEBUG_DRIVE_INFO		0
-#define HPT374_ALLOW_ATA133_6		0
-#define HPT371_ALLOW_ATA133_6		0
-#define HPT302_ALLOW_ATA133_6		0
-#define HPT372_ALLOW_ATA133_6		0
-#define HPT370_ALLOW_ATA100_5		1
+#define HPT374_ALLOW_ATA133_6		1
+#define HPT371_ALLOW_ATA133_6		1
+#define HPT302_ALLOW_ATA133_6		1
+#define HPT372_ALLOW_ATA133_6		1
+#define HPT370_ALLOW_ATA100_5		0
 #define HPT366_ALLOW_ATA66_4		1
 #define HPT366_ALLOW_ATA66_3		1
 #define HPT366_MAX_DEVS			8
 
-#define F_LOW_PCI_33	0x23
-#define F_LOW_PCI_40	0x29
-#define F_LOW_PCI_50	0x2d
-#define F_LOW_PCI_66	0x42
-
-/*
- *	Hold all the highpoint quirks and revision information in one
- *	place.
- */
-
-struct hpt_info
-{
-	u8 max_mode;		/* Speeds allowed */
-	int revision;		/* Chipset revision */
-	int flags;		/* Chipset properties */
-#define PLL_MODE	1
-#define IS_3xxN 	2
-#define PCI_66MHZ	4
-				/* Speed table */
-	u32 *speed;
+/* Supported ATA clock frequencies */
+enum ata_clock {
+	ATA_CLOCK_25MHZ,
+	ATA_CLOCK_33MHZ,
+	ATA_CLOCK_40MHZ,
+	ATA_CLOCK_50MHZ,
+	ATA_CLOCK_66MHZ,
+	NUM_ATA_CLOCKS
 };
 
 /*
- *	This wants fixing so that we do everything not by classrev
- *	(which breaks on the newest chips) but by creating an
- *	enumeration of chip variants and using that
+ *	Hold all the HighPoint chip information in one place.
  */
 
-static __devinit u32 hpt_revision (struct pci_dev *dev)
-{
-	u32 class_rev;
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
+struct hpt_info {
+	u8 chip_type;		/* Chip type */
+	u8 max_mode;		/* Speeds allowed */
+	u8 dpll_clk;		/* DPLL clock in MHz */
+	u8 pci_clk;		/* PCI  clock in MHz */
+	u32 **settings; 	/* Chipset settings table */
+};
 
-	switch(dev->device) {
-		/* Remap new 372N onto 372 */
-		case PCI_DEVICE_ID_TTI_HPT372N:
-			class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
-		case PCI_DEVICE_ID_TTI_HPT374:
-			class_rev = PCI_DEVICE_ID_TTI_HPT374; break;
-		case PCI_DEVICE_ID_TTI_HPT371:
-			class_rev = PCI_DEVICE_ID_TTI_HPT371; break;
-		case PCI_DEVICE_ID_TTI_HPT302:
-			class_rev = PCI_DEVICE_ID_TTI_HPT302; break;
-		case PCI_DEVICE_ID_TTI_HPT372:
-			class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
-		default:
-			break;
-	}
-	return class_rev;
+/* Supported HighPoint chips */
+enum {
+	HPT36x,
+	HPT370,
+	HPT370A,
+	HPT374,
+	HPT372,
+	HPT372A,
+	HPT302,
+	HPT371,
+	HPT372N,
+	HPT302N,
+	HPT371N
+};
+
+static u32 *hpt36x_settings[NUM_ATA_CLOCKS] = {
+	twenty_five_base_hpt36x,
+	thirty_three_base_hpt36x,
+	forty_base_hpt36x,
+	NULL,
+	NULL
+};
+
+static u32 *hpt37x_settings[NUM_ATA_CLOCKS] = {
+	NULL,
+	thirty_three_base_hpt37x,
+	NULL,
+	fifty_base_hpt37x,
+	sixty_six_base_hpt37x
+};
+
+static struct hpt_info hpt36x __devinitdata = {
+	.chip_type	= HPT36x,
+	.max_mode	= (HPT366_ALLOW_ATA66_4 || HPT366_ALLOW_ATA66_3) ? 2 : 1,
+	.dpll_clk	= 0,	/* no DPLL */
+	.settings	= hpt36x_settings
+};
+
+static struct hpt_info hpt370 __devinitdata = {
+	.chip_type	= HPT370,
+	.max_mode	= HPT370_ALLOW_ATA100_5 ? 3 : 2,
+	.dpll_clk	= 48,
+	.settings	= hpt37x_settings
+};
+
+static struct hpt_info hpt370a __devinitdata = {
+	.chip_type	= HPT370A,
+	.max_mode	= HPT370_ALLOW_ATA100_5 ? 3 : 2,
+	.dpll_clk	= 48,
+	.settings	= hpt37x_settings
+};
+
+static struct hpt_info hpt374 __devinitdata = {
+	.chip_type	= HPT374,
+	.max_mode	= HPT374_ALLOW_ATA133_6 ? 4 : 3,
+	.dpll_clk	= 48,
+	.settings	= hpt37x_settings
+};
+
+static struct hpt_info hpt372 __devinitdata = {
+	.chip_type	= HPT372,
+	.max_mode	= HPT372_ALLOW_ATA133_6 ? 4 : 3,
+	.dpll_clk	= 55,
+	.settings	= hpt37x_settings
+};
+
+static struct hpt_info hpt372a __devinitdata = {
+	.chip_type	= HPT372A,
+	.max_mode	= HPT372_ALLOW_ATA133_6 ? 4 : 3,
+	.dpll_clk	= 66,
+	.settings	= hpt37x_settings
+};
+
+static struct hpt_info hpt302 __devinitdata = {
+	.chip_type	= HPT302,
+	.max_mode	= HPT302_ALLOW_ATA133_6 ? 4 : 3,
+	.dpll_clk	= 66,
+	.settings	= hpt37x_settings
+};
+
+static struct hpt_info hpt371 __devinitdata = {
+	.chip_type	= HPT371,
+	.max_mode	= HPT371_ALLOW_ATA133_6 ? 4 : 3,
+	.dpll_clk	= 66,
+	.settings	= hpt37x_settings
+};
+
+static struct hpt_info hpt372n __devinitdata = {
+	.chip_type	= HPT372N,
+	.max_mode	= HPT372_ALLOW_ATA133_6 ? 4 : 3,
+	.dpll_clk	= 77,
+	.settings	= hpt37x_settings
+};
+
+static struct hpt_info hpt302n __devinitdata = {
+	.chip_type	= HPT302N,
+	.max_mode	= HPT302_ALLOW_ATA133_6 ? 4 : 3,
+	.dpll_clk	= 77,
+};
+
+static struct hpt_info hpt371n __devinitdata = {
+	.chip_type	= HPT371N,
+	.max_mode	= HPT371_ALLOW_ATA133_6 ? 4 : 3,
+	.dpll_clk	= 77,
+	.settings	= hpt37x_settings
+};
+
+static int check_in_drive_list(ide_drive_t *drive, const char **list)
+{
+	struct hd_driveid *id = drive->id;
+
+	while (*list)
+		if (!strcmp(*list++,id->model))
+			return 1;
+	return 0;
 }
 
-static int check_in_drive_lists(ide_drive_t *drive, const char **list);
-
-static u8 hpt3xx_ratemask (ide_drive_t *drive)
+static u8 hpt3xx_ratemask(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif	= drive->hwif;
-	struct hpt_info *info	= ide_get_hwifdata(hwif);
-	u8 mode			= 0;
+	struct hpt_info *info	= pci_get_drvdata(HWIF(drive)->pci_dev);
+	u8 mode			= info->max_mode;
 
-	/* FIXME: TODO - move this to set info->mode once at boot */
-
-	if (info->revision >= 8) {		/* HPT374 */
-		mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3;
-	} else if (info->revision >= 7) {	/* HPT371 */
-		mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3;
-	} else if (info->revision >= 6) {	/* HPT302 */
-		mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3;
-	} else if (info->revision >= 5) {	/* HPT372 */
-		mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3;
-	} else if (info->revision >= 4) {	/* HPT370A */
-		mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
-	} else if (info->revision >= 3) {	/* HPT370 */
-		mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
-		mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode;
-	} else {				/* HPT366 and HPT368 */
-		mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2;
-	}
 	if (!eighty_ninty_three(drive) && mode)
 		mode = min(mode, (u8)1);
 	return mode;
@@ -429,75 +528,61 @@
  *	either PIO or UDMA modes 0,4,5
  */
  
-static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
+static u8 hpt3xx_ratefilter(ide_drive_t *drive, u8 speed)
 {
-	ide_hwif_t *hwif	= drive->hwif;
-	struct hpt_info *info	= ide_get_hwifdata(hwif);
+	struct hpt_info *info	= pci_get_drvdata(HWIF(drive)->pci_dev);
+	u8 chip_type		= info->chip_type;
 	u8 mode			= hpt3xx_ratemask(drive);
 
 	if (drive->media != ide_disk)
 		return min(speed, (u8)XFER_PIO_4);
 
-	switch(mode) {
+	switch (mode) {
 		case 0x04:
-			speed = min(speed, (u8)XFER_UDMA_6);
+			speed = min_t(u8, speed, XFER_UDMA_6);
 			break;
 		case 0x03:
-			speed = min(speed, (u8)XFER_UDMA_5);
-			if (info->revision >= 5)
+			speed = min_t(u8, speed, XFER_UDMA_5);
+			if (chip_type >= HPT374)
 				break;
-			if (check_in_drive_lists(drive, bad_ata100_5))
-				speed = min(speed, (u8)XFER_UDMA_4);
-			break;
+			if (!check_in_drive_list(drive, bad_ata100_5))
+				goto check_bad_ata33;
+			/* fall thru */
 		case 0x02:
-			speed = min(speed, (u8)XFER_UDMA_4);
-	/*
-	 * CHECK ME, Does this need to be set to 5 ??
-	 */
-			if (info->revision >= 3)
-				break;
-			if ((check_in_drive_lists(drive, bad_ata66_4)) ||
-			    (!(HPT366_ALLOW_ATA66_4)))
-				speed = min(speed, (u8)XFER_UDMA_3);
-			if ((check_in_drive_lists(drive, bad_ata66_3)) ||
-			    (!(HPT366_ALLOW_ATA66_3)))
-				speed = min(speed, (u8)XFER_UDMA_2);
-			break;
+			speed = min_t(u8, speed, XFER_UDMA_4);
+
+			/*
+			 * CHECK ME, Does this need to be changed to HPT374 ??
+			 */
+			if (chip_type >= HPT370)
+				goto check_bad_ata33;
+			if (HPT366_ALLOW_ATA66_4 &&
+			    !check_in_drive_list(drive, bad_ata66_4))
+				goto check_bad_ata33;
+
+			speed = min_t(u8, speed, XFER_UDMA_3);
+			if (HPT366_ALLOW_ATA66_3 &&
+			    !check_in_drive_list(drive, bad_ata66_3))
+				goto check_bad_ata33;
+			/* fall thru */
 		case 0x01:
-			speed = min(speed, (u8)XFER_UDMA_2);
-	/*
-	 * CHECK ME, Does this need to be set to 5 ??
-	 */
-			if (info->revision >= 3)
+			speed = min_t(u8, speed, XFER_UDMA_2);
+
+		check_bad_ata33:
+			if (chip_type >= HPT370A)
 				break;
-			if (check_in_drive_lists(drive, bad_ata33))
-				speed = min(speed, (u8)XFER_MW_DMA_2);
-			break;
+			if (!check_in_drive_list(drive, bad_ata33))
+				break;
+			/* fall thru */
 		case 0x00:
 		default:
-			speed = min(speed, (u8)XFER_MW_DMA_2);
+			speed = min_t(u8, speed, XFER_MW_DMA_2);
 			break;
 	}
 	return speed;
 }
 
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (quirk_drives == list) {
-		while (*list)
-			if (strstr(id->model, *list++))
-				return 1;
-	} else {
-		while (*list)
-			if (!strcmp(*list++,id->model))
-				return 1;
-	}
-	return 0;
-}
-
-static u32 pci_bus_clock_list(u8 speed, u32 *chipset_table)
+static u32 get_speed_setting(u8 speed, struct hpt_info *info)
 {
 	int i;
 
@@ -510,228 +595,161 @@
 	for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++)
 		if (xfer_speeds[i] == speed)
 			break;
-	return chipset_table[i];
+	/*
+	 * NOTE: info->settings only points to the pointer
+	 * to the list of the actual register values
+	 */
+	return (*info->settings)[i];
 }
 
 static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 {
-	ide_hwif_t *hwif	= drive->hwif;
-	struct pci_dev *dev	= hwif->pci_dev;
-	struct hpt_info	*info	= ide_get_hwifdata(hwif);
-	u8 speed		= hpt3xx_ratefilter(drive, xferspeed);
-	u8 regtime		= (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
-	u8 regfast		= (hwif->channel) ? 0x55 : 0x51;
-	u8 drive_fast		= 0;
-	u32 reg1 = 0, reg2	= 0;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev  *dev	= hwif->pci_dev;
+	struct hpt_info	*info	= pci_get_drvdata(dev);
+	u8  speed		= hpt3xx_ratefilter(drive, xferspeed);
+	u8  itr_addr		= drive->dn ? 0x44 : 0x40;
+	u32 itr_mask		= speed < XFER_MW_DMA_0 ? 0x30070000 :
+				 (speed < XFER_UDMA_0   ? 0xc0070000 : 0xc03800ff);
+	u32 new_itr		= get_speed_setting(speed, info);
+	u32 old_itr		= 0;
 
 	/*
-	 * Disable the "fast interrupt" prediction.
+	 * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well)
+	 * to avoid problems handling I/O errors later
 	 */
-	pci_read_config_byte(dev, regfast, &drive_fast);
-	if (drive_fast & 0x80)
-		pci_write_config_byte(dev, regfast, drive_fast & ~0x80);
+	pci_read_config_dword(dev, itr_addr, &old_itr);
+	new_itr  = (new_itr & ~itr_mask) | (old_itr & itr_mask);
+	new_itr &= ~0xc0000000;
 
-	reg2 = pci_bus_clock_list(speed, info->speed);
-
-	/*
-	 * Disable on-chip PIO FIFO/buffer
-	 *  (to avoid problems handling I/O errors later)
-	 */
-	pci_read_config_dword(dev, regtime, &reg1);
-	if (speed >= XFER_MW_DMA_0) {
-		reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
-	} else {
-		reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
-	}	
-	reg2 &= ~0x80000000;
-
-	pci_write_config_dword(dev, regtime, reg2);
+	pci_write_config_dword(dev, itr_addr, new_itr);
 
 	return ide_config_drive_speed(drive, speed);
 }
 
-static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 {
-	ide_hwif_t *hwif	= drive->hwif;
-	struct pci_dev *dev = hwif->pci_dev;
-	struct hpt_info	*info	= ide_get_hwifdata(hwif);
-	u8 speed	= hpt3xx_ratefilter(drive, xferspeed);
-	u8 regfast	= (drive->hwif->channel) ? 0x55 : 0x51;
-	u8 drive_pci	= 0x40 + (drive->dn * 4);
-	u8 new_fast	= 0, drive_fast = 0;
-	u32 list_conf	= 0, drive_conf = 0;
-	u32 conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev  *dev	= hwif->pci_dev;
+	struct hpt_info	*info	= pci_get_drvdata(dev);
+	u8  speed		= hpt3xx_ratefilter(drive, xferspeed);
+	u8  itr_addr		= 0x40 + (drive->dn * 4);
+	u32 itr_mask		= speed < XFER_MW_DMA_0 ? 0x303c0000 :
+				 (speed < XFER_UDMA_0   ? 0xc03c0000 : 0xc1c001ff);
+	u32 new_itr		= get_speed_setting(speed, info);
+	u32 old_itr		= 0;
 
-	/*
-	 * Disable the "fast interrupt" prediction.
-	 * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
-	 */
-	pci_read_config_byte(dev, regfast, &drive_fast);
-	new_fast = drive_fast;
-	if (new_fast & 0x02)
-		new_fast &= ~0x02;
-
-#ifdef HPT_DELAY_INTERRUPT
-	if (new_fast & 0x01)
-		new_fast &= ~0x01;
-#else
-	if ((new_fast & 0x01) == 0)
-		new_fast |= 0x01;
-#endif
-	if (new_fast != drive_fast)
-		pci_write_config_byte(dev, regfast, new_fast);
-
-	list_conf = pci_bus_clock_list(speed, info->speed);
-
-	pci_read_config_dword(dev, drive_pci, &drive_conf);
-	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+	pci_read_config_dword(dev, itr_addr, &old_itr);
+	new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
 	
 	if (speed < XFER_MW_DMA_0)
-		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
-	pci_write_config_dword(dev, drive_pci, list_conf);
+		new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+	pci_write_config_dword(dev, itr_addr, new_itr);
 
 	return ide_config_drive_speed(drive, speed);
 }
 
-static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed)
 {
-	ide_hwif_t *hwif	= drive->hwif;
-	struct pci_dev *dev	= hwif->pci_dev;
-	struct hpt_info	*info	= ide_get_hwifdata(hwif);
-	u8 speed	= hpt3xx_ratefilter(drive, xferspeed);
-	u8 regfast	= (drive->hwif->channel) ? 0x55 : 0x51;
-	u8 drive_fast	= 0, drive_pci = 0x40 + (drive->dn * 4);
-	u32 list_conf	= 0, drive_conf = 0;
-	u32 conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hpt_info	*info	= pci_get_drvdata(hwif->pci_dev);
 
-	/*
-	 * Disable the "fast interrupt" prediction.
-	 * don't holdoff on interrupts. (== 0x01 despite what the docs say)
-	 */
-	pci_read_config_byte(dev, regfast, &drive_fast);
-	drive_fast &= ~0x07;
-	pci_write_config_byte(dev, regfast, drive_fast);
-
-	list_conf = pci_bus_clock_list(speed, info->speed);
-	pci_read_config_dword(dev, drive_pci, &drive_conf);
-	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
-	if (speed < XFER_MW_DMA_0)
-		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
-	pci_write_config_dword(dev, drive_pci, list_conf);
-
-	return ide_config_drive_speed(drive, speed);
-}
-
-static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed)
-{
-	ide_hwif_t *hwif	= drive->hwif;
-	struct hpt_info	*info	= ide_get_hwifdata(hwif);
-
-	if (info->revision >= 8)
-		return hpt372_tune_chipset(drive, speed); /* not a typo */
-	else if (info->revision >= 5)
-		return hpt372_tune_chipset(drive, speed);
-	else if (info->revision >= 3)
-		return hpt370_tune_chipset(drive, speed);
+	if (info->chip_type >= HPT370)
+		return hpt37x_tune_chipset(drive, speed);
 	else	/* hpt368: hpt_minimum_revision(dev, 2) */
 		return hpt36x_tune_chipset(drive, speed);
 }
 
-static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio)
+static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio)
 {
-	pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
-	(void) hpt3xx_tune_chipset(drive, (XFER_PIO_0 + pio));
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	(void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio);
 }
 
 /*
  * This allows the configuration of ide_pci chipset registers
  * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.  Initially for designed for
+ * after the drive is reported by the OS.  Initially designed for
  * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
  *
- * check_in_drive_lists(drive, bad_ata66_4)
- * check_in_drive_lists(drive, bad_ata66_3)
- * check_in_drive_lists(drive, bad_ata33)
- *
  */
-static int config_chipset_for_dma (ide_drive_t *drive)
+static int config_chipset_for_dma(ide_drive_t *drive)
 {
 	u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
-	ide_hwif_t *hwif = drive->hwif;
-	struct hpt_info	*info	= ide_get_hwifdata(hwif);
 
 	if (!speed)
 		return 0;
 
-	/* If we don't have any timings we can't do a lot */
-	if (info->speed == NULL)
-		return 0;
-
 	(void) hpt3xx_tune_chipset(drive, speed);
 	return ide_dma_enable(drive);
 }
 
-static int hpt3xx_quirkproc (ide_drive_t *drive)
+static int hpt3xx_quirkproc(ide_drive_t *drive)
 {
-	return ((int) check_in_drive_lists(drive, quirk_drives));
+	struct hd_driveid *id	= drive->id;
+	const  char **list	= quirk_drives;
+
+	while (*list)
+		if (strstr(id->model, *list++))
+			return 1;
+	return 0;
 }
 
-static void hpt3xx_intrproc (ide_drive_t *drive)
+static void hpt3xx_intrproc(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = drive->hwif;
+	ide_hwif_t *hwif = HWIF(drive);
 
 	if (drive->quirk_list)
 		return;
 	/* drives in the quirk_list may not like intr setups/cleanups */
-	hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+	hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
 }
 
-static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
+static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
 {
-	ide_hwif_t *hwif = drive->hwif;
-	struct hpt_info *info = ide_get_hwifdata(hwif);
-	struct pci_dev *dev = hwif->pci_dev;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev	*dev	= hwif->pci_dev;
+	struct hpt_info *info	= pci_get_drvdata(dev);
 
 	if (drive->quirk_list) {
-		if (info->revision >= 3) {
-			u8 reg5a = 0;
-			pci_read_config_byte(dev, 0x5a, &reg5a);
-			if (((reg5a & 0x10) >> 4) != mask)
-				pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
-		} else {
-			if (mask) {
-				disable_irq(hwif->irq);
-			} else {
-				enable_irq(hwif->irq);
+		if (info->chip_type >= HPT370) {
+			u8 scr1 = 0;
+
+			pci_read_config_byte(dev, 0x5a, &scr1);
+			if (((scr1 & 0x10) >> 4) != mask) {
+				if (mask)
+					scr1 |=  0x10;
+				else
+					scr1 &= ~0x10;
+				pci_write_config_byte(dev, 0x5a, scr1);
 			}
+		} else {
+			if (mask)
+				disable_irq(hwif->irq);
+			else
+				enable_irq (hwif->irq);
 		}
-	} else {
-		if (IDE_CONTROL_REG)
-			hwif->OUTB(mask ? (drive->ctl | 2) :
-						 (drive->ctl & ~2),
-						 IDE_CONTROL_REG);
-	}
+	} else
+		hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2),
+			   IDE_CONTROL_REG);
 }
 
-static int hpt366_config_drive_xfer_rate (ide_drive_t *drive)
+static int hpt366_config_drive_xfer_rate(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif	= drive->hwif;
+	ide_hwif_t *hwif	= HWIF(drive);
 	struct hd_driveid *id	= drive->id;
 
 	drive->init_speed = 0;
 
 	if ((id->capability & 1) && drive->autodma) {
-
-		if (ide_use_dma(drive)) {
-			if (config_chipset_for_dma(drive))
-				return hwif->ide_dma_on(drive);
-		}
+		if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+			return hwif->ide_dma_on(drive);
 
 		goto fast_ata_pio;
 
 	} else if ((id->capability & 8) || (id->field_valid & 2)) {
 fast_ata_pio:
-		hpt3xx_tune_drive(drive, 5);
+		hpt3xx_tune_drive(drive, 255);
 		return hwif->ide_dma_off_quietly(drive);
 	}
 	/* IORDY not supported */
@@ -739,31 +757,48 @@
 }
 
 /*
- * This is specific to the HPT366 UDMA bios chipset
+ * This is specific to the HPT366 UDMA chipset
  * by HighPoint|Triones Technologies, Inc.
  */
-static int hpt366_ide_dma_lostirq (ide_drive_t *drive)
+static int hpt366_ide_dma_lostirq(ide_drive_t *drive)
 {
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	u8 reg50h = 0, reg52h = 0, reg5ah = 0;
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	u8 mcr1 = 0, mcr3 = 0, scr1 = 0;
 
-	pci_read_config_byte(dev, 0x50, &reg50h);
-	pci_read_config_byte(dev, 0x52, &reg52h);
-	pci_read_config_byte(dev, 0x5a, &reg5ah);
-	printk("%s: (%s)  reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
-		drive->name, __FUNCTION__, reg50h, reg52h, reg5ah);
-	if (reg5ah & 0x10)
-		pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
+	pci_read_config_byte(dev, 0x50, &mcr1);
+	pci_read_config_byte(dev, 0x52, &mcr3);
+	pci_read_config_byte(dev, 0x5a, &scr1);
+	printk("%s: (%s)  mcr1=0x%02x, mcr3=0x%02x, scr1=0x%02x\n",
+		drive->name, __FUNCTION__, mcr1, mcr3, scr1);
+	if (scr1 & 0x10)
+		pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
 	return __ide_dma_lostirq(drive);
 }
 
-static void hpt370_clear_engine (ide_drive_t *drive)
+static void hpt370_clear_engine(ide_drive_t *drive)
 {
-	u8 regstate = HWIF(drive)->channel ? 0x54 : 0x50;
-	pci_write_config_byte(HWIF(drive)->pci_dev, regstate, 0x37);
+	ide_hwif_t *hwif = HWIF(drive);
+
+	pci_write_config_byte(hwif->pci_dev, hwif->select_data, 0x37);
 	udelay(10);
 }
 
+static void hpt370_irq_timeout(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u16 bfifo		= 0;
+	u8  dma_cmd;
+
+	pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
+	printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff);
+
+	/* get DMA command mode */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop DMA */
+	hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
+	hpt370_clear_engine(drive);
+}
+
 static void hpt370_ide_dma_start(ide_drive_t *drive)
 {
 #ifdef HPT_RESET_STATE_ENGINE
@@ -772,64 +807,35 @@
 	ide_dma_start(drive);
 }
 
-static int hpt370_ide_dma_end (ide_drive_t *drive)
+static int hpt370_ide_dma_end(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
-	u8 dma_stat		= hwif->INB(hwif->dma_status);
+	u8  dma_stat		= hwif->INB(hwif->dma_status);
 
 	if (dma_stat & 0x01) {
 		/* wait a little */
 		udelay(20);
 		dma_stat = hwif->INB(hwif->dma_status);
+		if (dma_stat & 0x01)
+			hpt370_irq_timeout(drive);
 	}
-	if ((dma_stat & 0x01) != 0) 
-		/* fallthrough */
-		(void) HWIF(drive)->ide_dma_timeout(drive);
-
 	return __ide_dma_end(drive);
 }
 
-static void hpt370_lostirq_timeout (ide_drive_t *drive)
+static int hpt370_ide_dma_timeout(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 bfifo = 0, reginfo	= hwif->channel ? 0x56 : 0x52;
-	u8 dma_stat = 0, dma_cmd = 0;
-
-	pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo);
-	printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo);
-	hpt370_clear_engine(drive);
-	/* get dma command mode */
-	dma_cmd = hwif->INB(hwif->dma_command);
-	/* stop dma */
-	hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
-	dma_stat = hwif->INB(hwif->dma_status);
-	/* clear errors */
-	hwif->OUTB(dma_stat | 0x6, hwif->dma_status);
-}
-
-static int hpt370_ide_dma_timeout (ide_drive_t *drive)
-{
-	hpt370_lostirq_timeout(drive);
-	hpt370_clear_engine(drive);
+	hpt370_irq_timeout(drive);
 	return __ide_dma_timeout(drive);
 }
 
-static int hpt370_ide_dma_lostirq (ide_drive_t *drive)
-{
-	hpt370_lostirq_timeout(drive);
-	hpt370_clear_engine(drive);
-	return __ide_dma_lostirq(drive);
-}
-
 /* returns 1 if DMA IRQ issued, 0 otherwise */
 static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	u16 bfifo		= 0;
-	u8 reginfo		= hwif->channel ? 0x56 : 0x52;
-	u8 dma_stat;
+	u8  dma_stat;
 
-	pci_read_config_word(hwif->pci_dev, reginfo, &bfifo);
+	pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
 	if (bfifo & 0x1FF) {
 //		printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
 		return 0;
@@ -837,7 +843,7 @@
 
 	dma_stat = hwif->INB(hwif->dma_status);
 	/* return 1 if INTR asserted */
-	if ((dma_stat & 4) == 4)
+	if (dma_stat & 4)
 		return 1;
 
 	if (!drive->waiting_for_dma)
@@ -846,17 +852,17 @@
 	return 0;
 }
 
-static int hpt374_ide_dma_end (ide_drive_t *drive)
+static int hpt374_ide_dma_end(ide_drive_t *drive)
 {
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
 	ide_hwif_t *hwif	= HWIF(drive);
-	u8 msc_stat = 0, mscreg	= hwif->channel ? 0x54 : 0x50;
-	u8 bwsr_stat = 0, bwsr_mask = hwif->channel ? 0x02 : 0x01;
+	struct pci_dev	*dev	= hwif->pci_dev;
+	u8 mcr	= 0, mcr_addr	= hwif->select_data;
+	u8 bwsr = 0, mask	= hwif->channel ? 0x02 : 0x01;
 
-	pci_read_config_byte(dev, 0x6a, &bwsr_stat);
-	pci_read_config_byte(dev, mscreg, &msc_stat);
-	if ((bwsr_stat & bwsr_mask) == bwsr_mask)
-		pci_write_config_byte(dev, mscreg, msc_stat|0x30);
+	pci_read_config_byte(dev, 0x6a, &bwsr);
+	pci_read_config_byte(dev, mcr_addr, &mcr);
+	if (bwsr & mask)
+		pci_write_config_byte(dev, mcr_addr, mcr | 0x30);
 	return __ide_dma_end(drive);
 }
 
@@ -866,40 +872,37 @@
  *	@mode: clocking mode (0x21 for write, 0x23 otherwise)
  *
  *	Switch the DPLL clock on the HPT3xxN devices. This is a	right mess.
- *	NOTE: avoid touching the disabled primary channel on HPT371N -- it
- *	doesn't physically exist anyway...
  */
 
 static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
 {
-	u8 mcr1, scr2 = hwif->INB(hwif->dma_master + 0x7b);
+	u8 scr2 = hwif->INB(hwif->dma_master + 0x7b);
 
 	if ((scr2 & 0x7f) == mode)
 		return;
 
-	/* MISC. control register 1 has the channel enable bit... */
-	mcr1 = hwif->INB(hwif->dma_master + 0x70);
-
 	/* Tristate the bus */
-	if (mcr1 & 0x04)
-		hwif->OUTB(0x80, hwif->dma_master + 0x73);
+	hwif->OUTB(0x80, hwif->dma_master + 0x73);
 	hwif->OUTB(0x80, hwif->dma_master + 0x77);
 
 	/* Switch clock and reset channels */
 	hwif->OUTB(mode, hwif->dma_master + 0x7b);
 	hwif->OUTB(0xc0, hwif->dma_master + 0x79);
 
-	/* Reset state machines */
-	if (mcr1 & 0x04)
-		hwif->OUTB(0x37, hwif->dma_master + 0x70);
-	hwif->OUTB(0x37, hwif->dma_master + 0x74);
+	/*
+	 * Reset the state machines.
+	 * NOTE: avoid accidentally enabling the disabled channels.
+	 */
+	hwif->OUTB(hwif->INB(hwif->dma_master + 0x70) | 0x32,
+		   hwif->dma_master + 0x70);
+	hwif->OUTB(hwif->INB(hwif->dma_master + 0x74) | 0x32,
+		   hwif->dma_master + 0x74);
 
 	/* Complete reset */
 	hwif->OUTB(0x00, hwif->dma_master + 0x79);
 
 	/* Reconnect channels to bus */
-	if (mcr1 & 0x04)
-		hwif->OUTB(0x00, hwif->dma_master + 0x73);
+	hwif->OUTB(0x00, hwif->dma_master + 0x73);
 	hwif->OUTB(0x00, hwif->dma_master + 0x77);
 }
 
@@ -914,14 +917,12 @@
 
 static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 wantclock		= rq_data_dir(rq) ? 0x23 : 0x21;
-
-	hpt3xxn_set_clock(hwif, wantclock);
+	hpt3xxn_set_clock(HWIF(drive), rq_data_dir(rq) ? 0x23 : 0x21);
 }
 
 /* 
  * Set/get power state for a drive.
+ * NOTE: affects both drives on each channel.
  *
  * When we turn the power back on, we need to re-initialize things.
  */
@@ -929,26 +930,18 @@
 
 static int hpt3xx_busproc(ide_drive_t *drive, int state)
 {
-	ide_hwif_t *hwif	= drive->hwif;
+	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
-	u8  tristate, resetmask, bus_reg = 0;
-	u16 tri_reg = 0;
+	u8  mcr_addr		= hwif->select_data + 2;
+	u8  resetmask		= hwif->channel ? 0x80 : 0x40;
+	u8  bsr2		= 0;
+	u16 mcr			= 0;
 
 	hwif->bus_state = state;
 
-	if (hwif->channel) { 
-		/* secondary channel */
-		tristate  = 0x56;
-		resetmask = 0x80;
-	} else { 
-		/* primary channel */
-		tristate  = 0x52;
-		resetmask = 0x40;
-	}
-
 	/* Grab the status. */
-	pci_read_config_word(dev, tristate, &tri_reg);
-	pci_read_config_byte(dev, 0x59, &bus_reg);
+	pci_read_config_word(dev, mcr_addr, &mcr);
+	pci_read_config_byte(dev, 0x59, &bsr2);
 
 	/*
 	 * Set the state. We don't set it if we don't need to do so.
@@ -956,22 +949,22 @@
 	 */
 	switch (state) {
 	case BUSSTATE_ON:
-		if (!(bus_reg & resetmask))
+		if (!(bsr2 & resetmask))
 			return 0;
 		hwif->drives[0].failures = hwif->drives[1].failures = 0;
 
-		pci_write_config_byte(dev, 0x59, bus_reg & ~resetmask);
-		pci_write_config_word(dev, tristate, tri_reg & ~TRISTATE_BIT);
+		pci_write_config_byte(dev, 0x59, bsr2 & ~resetmask);
+		pci_write_config_word(dev, mcr_addr, mcr & ~TRISTATE_BIT);
 		return 0;
 	case BUSSTATE_OFF:
-		if ((bus_reg & resetmask) && !(tri_reg & TRISTATE_BIT))
+		if ((bsr2 & resetmask) && !(mcr & TRISTATE_BIT))
 			return 0;
-		tri_reg &= ~TRISTATE_BIT;
+		mcr &= ~TRISTATE_BIT;
 		break;
 	case BUSSTATE_TRISTATE:
-		if ((bus_reg & resetmask) &&  (tri_reg & TRISTATE_BIT))
+		if ((bsr2 & resetmask) &&  (mcr & TRISTATE_BIT))
 			return 0;
-		tri_reg |= TRISTATE_BIT;
+		mcr |= TRISTATE_BIT;
 		break;
 	default:
 		return -EINVAL;
@@ -980,223 +973,63 @@
 	hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
 	hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
 
-	pci_write_config_word(dev, tristate, tri_reg);
-	pci_write_config_byte(dev, 0x59, bus_reg | resetmask);
+	pci_write_config_word(dev, mcr_addr, mcr);
+	pci_write_config_byte(dev, 0x59, bsr2 | resetmask);
 	return 0;
 }
 
-static void __devinit hpt366_clocking(ide_hwif_t *hwif)
+/**
+ *	hpt37x_calibrate_dpll	-	calibrate the DPLL
+ *	@dev: PCI device
+ *
+ *	Perform a calibration cycle on the DPLL.
+ *	Returns 1 if this succeeds
+ */
+static int __devinit hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high)
 {
-	u32 reg1	= 0;
-	struct hpt_info *info = ide_get_hwifdata(hwif);
+	u32 dpll = (f_high << 16) | f_low | 0x100;
+	u8  scr2;
+	int i;
 
-	pci_read_config_dword(hwif->pci_dev, 0x40, &reg1);
+	pci_write_config_dword(dev, 0x5c, dpll);
 
-	/* detect bus speed by looking at control reg timing: */
-	switch((reg1 >> 8) & 7) {
-		case 5:
-			info->speed = forty_base_hpt36x;
-			break;
-		case 9:
-			info->speed = twenty_five_base_hpt36x;
-			break;
-		case 7:
-		default:
-			info->speed = thirty_three_base_hpt36x;
+	/* Wait for oscillator ready */
+	for(i = 0; i < 0x5000; ++i) {
+		udelay(50);
+		pci_read_config_byte(dev, 0x5b, &scr2);
+		if (scr2 & 0x80)
 			break;
 	}
-}
-
-static void __devinit hpt37x_clocking(ide_hwif_t *hwif)
-{
-	struct hpt_info *info = ide_get_hwifdata(hwif);
-	struct pci_dev *dev = hwif->pci_dev;
-	int adjust, i;
-	u16 freq = 0;
-	u32 pll, temp = 0;
-	u8 reg5bh = 0, mcr1 = 0;
-	
-	/*
-	 * default to pci clock. make sure MA15/16 are set to output
-	 * to prevent drives having problems with 40-pin cables. Needed
-	 * for some drives such as IBM-DTLA which will not enter ready
-	 * state on reset when PDIAG is a input.
-	 *
-	 * ToDo: should we set 0x21 when using PLL mode ?
-	 */
-	pci_write_config_byte(dev, 0x5b, 0x23);
-
-	/*
-	 * We'll have to read f_CNT value in order to determine
-	 * the PCI clock frequency according to the following ratio:
-	 *
-	 * f_CNT = Fpci * 192 / Fdpll
-	 *
-	 * First try reading the register in which the HighPoint BIOS
-	 * saves f_CNT value before  reprogramming the DPLL from its
-	 * default setting (which differs for the various chips).
-	 * NOTE: This register is only accessible via I/O space.
-	 *
-	 * In case the signature check fails, we'll have to resort to
-	 * reading the f_CNT register itself in hopes that nobody has
-	 * touched the DPLL yet...
-	 */
-	temp = inl(pci_resource_start(dev, 4) + 0x90);
-	if ((temp & 0xFFFFF000) != 0xABCDE000) {
-		printk(KERN_WARNING "HPT37X: no clock data saved by BIOS\n");
-
-		/* Calculate the average value of f_CNT */
-		for (temp = i = 0; i < 128; i++) {
-			pci_read_config_word(dev, 0x78, &freq);
-			temp += freq & 0x1ff;
-			mdelay(1);
-		}
-		freq = temp / 128;
-	} else
-		freq = temp & 0x1ff;
-
-	/*
-	 * HPT3xxN chips use different PCI clock information.
-	 * Currently we always set up the PLL for them.
-	 */
-
-	if (info->flags & IS_3xxN) {
-		if(freq < 0x55)
-			pll = F_LOW_PCI_33;
-		else if(freq < 0x70)
-			pll = F_LOW_PCI_40;
-		else if(freq < 0x7F)
-			pll = F_LOW_PCI_50;
-		else
-			pll = F_LOW_PCI_66;
-
-		printk(KERN_INFO "HPT3xxN detected, FREQ: %d, PLL: %d\n", freq, pll);
+	/* See if it stays ready (we'll just bail out if it's not yet) */
+	for(i = 0; i < 0x1000; ++i) {
+		pci_read_config_byte(dev, 0x5b, &scr2);
+		/* DPLL destabilized? */
+		if(!(scr2 & 0x80))
+			return 0;
 	}
-	else
-	{
-		if(freq < 0x9C)
-			pll = F_LOW_PCI_33;
-		else if(freq < 0xb0)
-			pll = F_LOW_PCI_40;
-		else if(freq <0xc8)
-			pll = F_LOW_PCI_50;
-		else
-			pll = F_LOW_PCI_66;
-	
-		if (pll == F_LOW_PCI_33) {
-			info->speed = thirty_three_base_hpt37x;
-			printk(KERN_DEBUG "HPT37X: using 33MHz PCI clock\n");
-		} else if (pll == F_LOW_PCI_40) {
-			/* Unsupported */
-		} else if (pll == F_LOW_PCI_50) {
-			info->speed = fifty_base_hpt37x;
-			printk(KERN_DEBUG "HPT37X: using 50MHz PCI clock\n");
-		} else {
-			info->speed = sixty_six_base_hpt37x;
-			printk(KERN_DEBUG "HPT37X: using 66MHz PCI clock\n");
-		}
-	}
-
-	if (pll == F_LOW_PCI_66)
-		info->flags |= PCI_66MHZ;
-
-	/*
-	 * only try the pll if we don't have a table for the clock
-	 * speed that we're running at. NOTE: the internal PLL will
-	 * result in slow reads when using a 33MHz PCI clock. we also
-	 * don't like to use the PLL because it will cause glitches
-	 * on PRST/SRST when the HPT state engine gets reset.
-	 *
-	 * ToDo: Use 66MHz PLL when ATA133 devices are present on a
-	 * 372 device so we can get ATA133 support
-	 */
-	if (info->speed)
-		goto init_hpt37X_done;
-
-	info->flags |= PLL_MODE;
-	
-	/*
-	 * Adjust the PLL based upon the PCI clock, enable it, and
-	 * wait for stabilization...
-	 */
-	adjust = 0;
-	freq = (pll < F_LOW_PCI_50) ? 2 : 4;
-	while (adjust++ < 6) {
-		pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
-				       pll | 0x100);
-
-		/* wait for clock stabilization */
-		for (i = 0; i < 0x50000; i++) {
-			pci_read_config_byte(dev, 0x5b, &reg5bh);
-			if (reg5bh & 0x80) {
-				/* spin looking for the clock to destabilize */
-				for (i = 0; i < 0x1000; ++i) {
-					pci_read_config_byte(dev, 0x5b, 
-							     &reg5bh);
-					if ((reg5bh & 0x80) == 0)
-						goto pll_recal;
-				}
-				pci_read_config_dword(dev, 0x5c, &pll);
-				pci_write_config_dword(dev, 0x5c, 
-						       pll & ~0x100);
-				pci_write_config_byte(dev, 0x5b, 0x21);
-
-				info->speed = fifty_base_hpt37x;
-				printk("HPT37X: using 50MHz internal PLL\n");
-				goto init_hpt37X_done;
-			}
-		}
-pll_recal:
-		if (adjust & 1)
-			pll -= (adjust >> 1);
-		else
-			pll += (adjust >> 1);
-	} 
-
-init_hpt37X_done:
-	if (!info->speed)
-		printk(KERN_ERR "HPT37x%s: unknown bus timing [%d %d].\n",
-		       (info->flags & IS_3xxN) ? "N" : "", pll, freq);
-	/*
-	 * Reset the state engines.
-	 * NOTE: avoid accidentally enabling the primary channel on HPT371N.
-	 */
-	pci_read_config_byte(dev, 0x50, &mcr1);
-	if (mcr1 & 0x04)
-		pci_write_config_byte(dev, 0x50, 0x37);
-	pci_write_config_byte(dev, 0x54, 0x37);
-	udelay(100);
-}
-
-static int __devinit init_hpt37x(struct pci_dev *dev)
-{
-	u8 reg5ah;
-
-	pci_read_config_byte(dev, 0x5a, &reg5ah);
-	/* interrupt force enable */
-	pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
-	return 0;
-}
-
-static int __devinit init_hpt366(struct pci_dev *dev)
-{
-	u32 reg1	= 0;
-	u8 drive_fast	= 0;
-
-	/*
-	 * Disable the "fast interrupt" prediction.
-	 */
-	pci_read_config_byte(dev, 0x51, &drive_fast);
-	if (drive_fast & 0x80)
-		pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
-	pci_read_config_dword(dev, 0x40, &reg1);
-									
-	return 0;
+	/* Turn off tuning, we have the DPLL set */
+	pci_read_config_dword (dev, 0x5c, &dpll);
+	pci_write_config_dword(dev, 0x5c, (dpll & ~0x100));
+	return 1;
 }
 
 static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
 {
-	int ret = 0;
+	struct hpt_info *info	= kmalloc(sizeof(struct hpt_info), GFP_KERNEL);
+	unsigned long io_base	= pci_resource_start(dev, 4);
+	u8 pci_clk,  dpll_clk	= 0;	/* PCI and DPLL clock in MHz */
+	enum ata_clock	clock;
+
+	if (info == NULL) {
+		printk(KERN_ERR "%s: out of memory!\n", name);
+		return -ENOMEM;
+	}
+
+	/*
+	 * Copy everything from a static "template" structure
+	 * to just allocated per-chip hpt_info structure.
+	 */
+	*info = *(struct hpt_info *)pci_get_drvdata(dev);
 
 	/*
 	 * FIXME: Not portable. Also, why do we enable the ROM in the first place?
@@ -1211,37 +1044,249 @@
 	pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
 	pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
 
-	if (hpt_revision(dev) >= 3)
-		ret = init_hpt37x(dev);
-	else
-		ret = init_hpt366(dev);
+	/*
+	 * First, try to estimate the PCI clock frequency...
+	 */
+	if (info->chip_type >= HPT370) {
+		u8  scr1  = 0;
+		u16 f_cnt = 0;
+		u32 temp  = 0;
 
-	if (ret)
-		return ret;
+		/* Interrupt force enable. */
+		pci_read_config_byte(dev, 0x5a, &scr1);
+		if (scr1 & 0x10)
+			pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
+
+		/*
+		 * HighPoint does this for HPT372A.
+		 * NOTE: This register is only writeable via I/O space.
+		 */
+		if (info->chip_type == HPT372A)
+			outb(0x0e, io_base + 0x9c);
+
+		/*
+		 * Default to PCI clock. Make sure MA15/16 are set to output
+		 * to prevent drives having problems with 40-pin cables.
+		 */
+		pci_write_config_byte(dev, 0x5b, 0x23);
+
+		/*
+		 * We'll have to read f_CNT value in order to determine
+		 * the PCI clock frequency according to the following ratio:
+		 *
+		 * f_CNT = Fpci * 192 / Fdpll
+		 *
+		 * First try reading the register in which the HighPoint BIOS
+		 * saves f_CNT value before  reprogramming the DPLL from its
+		 * default setting (which differs for the various chips).
+		 * NOTE: This register is only accessible via I/O space.
+		 *
+		 * In case the signature check fails, we'll have to resort to
+		 * reading the f_CNT register itself in hopes that nobody has
+		 * touched the DPLL yet...
+		 */
+		temp = inl(io_base + 0x90);
+		if ((temp & 0xFFFFF000) != 0xABCDE000) {
+			int i;
+
+			printk(KERN_WARNING "%s: no clock data saved by BIOS\n",
+			       name);
+
+			/* Calculate the average value of f_CNT. */
+			for (temp = i = 0; i < 128; i++) {
+				pci_read_config_word(dev, 0x78, &f_cnt);
+				temp += f_cnt & 0x1ff;
+				mdelay(1);
+			}
+			f_cnt = temp / 128;
+		} else
+			f_cnt = temp & 0x1ff;
+
+		dpll_clk = info->dpll_clk;
+		pci_clk  = (f_cnt * dpll_clk) / 192;
+
+		/* Clamp PCI clock to bands. */
+		if (pci_clk < 40)
+			pci_clk = 33;
+		else if(pci_clk < 45)
+			pci_clk = 40;
+		else if(pci_clk < 55)
+			pci_clk = 50;
+		else
+			pci_clk = 66;
+
+		printk(KERN_INFO "%s: DPLL base: %d MHz, f_CNT: %d, "
+		       "assuming %d MHz PCI\n", name, dpll_clk, f_cnt, pci_clk);
+	} else {
+		u32 itr1 = 0;
+
+		pci_read_config_dword(dev, 0x40, &itr1);
+
+		/* Detect PCI clock by looking at cmd_high_time. */
+		switch((itr1 >> 8) & 0x07) {
+			case 0x09:
+				pci_clk = 40;
+				break;
+			case 0x05:
+				pci_clk = 25;
+				break;
+			case 0x07:
+			default:
+				pci_clk = 33;
+				break;
+		}
+	}
+
+	/* Let's assume we'll use PCI clock for the ATA clock... */
+	switch (pci_clk) {
+		case 25:
+			clock = ATA_CLOCK_25MHZ;
+			break;
+		case 33:
+		default:
+			clock = ATA_CLOCK_33MHZ;
+			break;
+		case 40:
+			clock = ATA_CLOCK_40MHZ;
+			break;
+		case 50:
+			clock = ATA_CLOCK_50MHZ;
+			break;
+		case 66:
+			clock = ATA_CLOCK_66MHZ;
+			break;
+	}
+
+	/*
+	 * Only try the DPLL if we don't have a table for the PCI clock that
+	 * we are running at for HPT370/A, always use it  for anything newer...
+	 *
+	 * NOTE: Using the internal DPLL results in slow reads on 33 MHz PCI.
+	 * We also  don't like using  the DPLL because this causes glitches
+	 * on PRST-/SRST- when the state engine gets reset...
+	 */
+	if (info->chip_type >= HPT374 || info->settings[clock] == NULL) {
+		u16 f_low, delta = pci_clk < 50 ? 2 : 4;
+		int adjust;
+
+		 /*
+		  * Select 66 MHz DPLL clock only if UltraATA/133 mode is
+		  * supported/enabled, use 50 MHz DPLL clock otherwise...
+		  */
+		if (info->max_mode == 0x04) {
+			dpll_clk = 66;
+			clock = ATA_CLOCK_66MHZ;
+		} else if (dpll_clk) {	/* HPT36x chips don't have DPLL */
+			dpll_clk = 50;
+			clock = ATA_CLOCK_50MHZ;
+		}
+
+		if (info->settings[clock] == NULL) {
+			printk(KERN_ERR "%s: unknown bus timing!\n", name);
+			kfree(info);
+			return -EIO;
+		}
+
+		/* Select the DPLL clock. */
+		pci_write_config_byte(dev, 0x5b, 0x21);
+
+		/*
+		 * Adjust the DPLL based upon PCI clock, enable it,
+		 * and wait for stabilization...
+		 */
+		f_low = (pci_clk * 48) / dpll_clk;
+
+		for (adjust = 0; adjust < 8; adjust++) {
+			if(hpt37x_calibrate_dpll(dev, f_low, f_low + delta))
+				break;
+
+			/*
+			 * See if it'll settle at a fractionally different clock
+			 */
+			if (adjust & 1)
+				f_low -= adjust >> 1;
+			else
+				f_low += adjust >> 1;
+		}
+		if (adjust == 8) {
+			printk(KERN_ERR "%s: DPLL did not stabilize!\n", name);
+			kfree(info);
+			return -EIO;
+		}
+
+		printk("%s: using %d MHz DPLL clock\n", name, dpll_clk);
+	} else {
+		/* Mark the fact that we're not using the DPLL. */
+		dpll_clk = 0;
+
+		printk("%s: using %d MHz PCI clock\n", name, pci_clk);
+	}
+
+	/*
+	 * Advance the table pointer to a slot which points to the list
+	 * of the register values settings matching the clock being used.
+	 */
+	info->settings += clock;
+
+	/* Store the clock frequencies. */
+	info->dpll_clk	= dpll_clk;
+	info->pci_clk	= pci_clk;
+
+	/* Point to this chip's own instance of the hpt_info structure. */
+	pci_set_drvdata(dev, info);
+
+	if (info->chip_type >= HPT370) {
+		u8  mcr1, mcr4;
+
+		/*
+		 * Reset the state engines.
+		 * NOTE: Avoid accidentally enabling the disabled channels.
+		 */
+		pci_read_config_byte (dev, 0x50, &mcr1);
+		pci_read_config_byte (dev, 0x54, &mcr4);
+		pci_write_config_byte(dev, 0x50, (mcr1 | 0x32));
+		pci_write_config_byte(dev, 0x54, (mcr4 | 0x32));
+		udelay(100);
+	}
+
+	/*
+	 * On  HPT371N, if ATA clock is 66 MHz we must set bit 2 in
+	 * the MISC. register to stretch the UltraDMA Tss timing.
+	 * NOTE: This register is only writeable via I/O space.
+	 */
+	if (info->chip_type == HPT371N && clock == ATA_CLOCK_66MHZ)
+
+		outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c);
 
 	return dev->irq;
 }
 
 static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
 {
-	struct pci_dev *dev		= hwif->pci_dev;
-	struct hpt_info *info		= ide_get_hwifdata(hwif);
-	u8 ata66 = 0, regmask		= (hwif->channel) ? 0x01 : 0x02;
+	struct pci_dev	*dev		= hwif->pci_dev;
+	struct hpt_info *info		= pci_get_drvdata(dev);
 	int serialize			= HPT_SERIALIZE_IO;
-	
+	u8  scr1 = 0, ata66		= (hwif->channel) ? 0x01 : 0x02;
+	u8  chip_type			= info->chip_type;
+	u8  new_mcr, old_mcr 		= 0;
+
+	/* Cache the channel's MISC. control registers' offset */
+	hwif->select_data		= hwif->channel ? 0x54 : 0x50;
+
 	hwif->tuneproc			= &hpt3xx_tune_drive;
 	hwif->speedproc			= &hpt3xx_tune_chipset;
 	hwif->quirkproc			= &hpt3xx_quirkproc;
 	hwif->intrproc			= &hpt3xx_intrproc;
 	hwif->maskproc			= &hpt3xx_maskproc;
-	
+	hwif->busproc			= &hpt3xx_busproc;
+
 	/*
 	 * HPT3xxN chips have some complications:
 	 *
 	 * - on 33 MHz PCI we must clock switch
 	 * - on 66 MHz PCI we must NOT use the PCI clock
 	 */
-	if ((info->flags & (IS_3xxN | PCI_66MHZ)) == IS_3xxN) {
+	if (chip_type >= HPT372N && info->dpll_clk && info->pci_clk < 66) {
 		/*
 		 * Clock is shared between the channels,
 		 * so we'll have to serialize them... :-(
@@ -1250,200 +1295,171 @@
 		hwif->rw_disk = &hpt3xxn_rw_disk;
 	}
 
-	/*
-	 * The HPT37x uses the CBLID pins as outputs for MA15/MA16
-	 * address lines to access an external eeprom.  To read valid
-	 * cable detect state the pins must be enabled as inputs.
-	 */
-	if (info->revision >= 8 && (PCI_FUNC(dev->devfn) & 1)) {
-		/*
-		 * HPT374 PCI function 1
-		 * - set bit 15 of reg 0x52 to enable TCBLID as input
-		 * - set bit 15 of reg 0x56 to enable FCBLID as input
-		 */
-		u16 mcr3, mcr6;
-		pci_read_config_word(dev, 0x52, &mcr3);
-		pci_read_config_word(dev, 0x56, &mcr6);
-		pci_write_config_word(dev, 0x52, mcr3 | 0x8000);
-		pci_write_config_word(dev, 0x56, mcr6 | 0x8000);
-		/* now read cable id register */
-		pci_read_config_byte(dev, 0x5a, &ata66);
-		pci_write_config_word(dev, 0x52, mcr3);
-		pci_write_config_word(dev, 0x56, mcr6);
-	} else if (info->revision >= 3) {
-		/*
-		 * HPT370/372 and 374 pcifn 0
-		 * - clear bit 0 of 0x5b to enable P/SCBLID as inputs
-		 */
-		u8 scr2;
-		pci_read_config_byte(dev, 0x5b, &scr2);
-		pci_write_config_byte(dev, 0x5b, scr2 & ~1);
-		/* now read cable id register */
-		pci_read_config_byte(dev, 0x5a, &ata66);
-		pci_write_config_byte(dev, 0x5b, scr2);
-	} else {
-		pci_read_config_byte(dev, 0x5a, &ata66);
-	}
-
-#ifdef DEBUG
-	printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
-		ata66, (ata66 & regmask) ? "33" : "66",
-		PCI_FUNC(hwif->pci_dev->devfn));
-#endif /* DEBUG */
-
-	/* Serialize access to this device */
+	/* Serialize access to this device if needed */
 	if (serialize && hwif->mate)
 		hwif->serialized = hwif->mate->serialized = 1;
 
 	/*
-	 * Set up ioctl for power status.
-	 * NOTE:  power affects both drives on each channel.
+	 * Disable the "fast interrupt" prediction.  Don't hold off
+	 * on interrupts. (== 0x01 despite what the docs say)
 	 */
-	hwif->busproc = &hpt3xx_busproc;
+	pci_read_config_byte(dev, hwif->select_data + 1, &old_mcr);
+
+	if (info->chip_type >= HPT374)
+		new_mcr = old_mcr & ~0x07;
+	else if (info->chip_type >= HPT370) {
+		new_mcr = old_mcr;
+		new_mcr &= ~0x02;
+
+#ifdef HPT_DELAY_INTERRUPT
+		new_mcr &= ~0x01;
+#else
+		new_mcr |=  0x01;
+#endif
+	} else					/* HPT366 and HPT368  */
+		new_mcr = old_mcr & ~0x80;
+
+	if (new_mcr != old_mcr)
+		pci_write_config_byte(dev, hwif->select_data + 1, new_mcr);
 
 	if (!hwif->dma_base) {
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
+		hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
 		return;
 	}
 
 	hwif->ultra_mask = 0x7f;
 	hwif->mwdma_mask = 0x07;
 
-	if (!(hwif->udma_four))
-		hwif->udma_four = ((ata66 & regmask) ? 0 : 1);
-	hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
+	/*
+	 * The HPT37x uses the CBLID pins as outputs for MA15/MA16
+	 * address lines to access an external EEPROM.  To read valid
+	 * cable detect state the pins must be enabled as inputs.
+	 */
+	if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
+		/*
+		 * HPT374 PCI function 1
+		 * - set bit 15 of reg 0x52 to enable TCBLID as input
+		 * - set bit 15 of reg 0x56 to enable FCBLID as input
+		 */
+		u8  mcr_addr = hwif->select_data + 2;
+		u16 mcr;
 
-	if (info->revision >= 8) {
-		hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
-		hwif->ide_dma_end = &hpt374_ide_dma_end;
-	} else if (info->revision >= 5) {
-		hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
-		hwif->ide_dma_end = &hpt374_ide_dma_end;
-	} else if (info->revision >= 3) {
-		hwif->dma_start = &hpt370_ide_dma_start;
-		hwif->ide_dma_end = &hpt370_ide_dma_end;
-		hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
-		hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq;
-	} else if (info->revision >= 2)
-		hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
-	else
-		hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
+		pci_read_config_word (dev, mcr_addr, &mcr);
+		pci_write_config_word(dev, mcr_addr, (mcr | 0x8000));
+		/* now read cable id register */
+		pci_read_config_byte (dev, 0x5a, &scr1);
+		pci_write_config_word(dev, mcr_addr, mcr);
+	} else if (chip_type >= HPT370) {
+		/*
+		 * HPT370/372 and 374 pcifn 0
+		 * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs
+		 */
+		u8 scr2 = 0;
+
+		pci_read_config_byte (dev, 0x5b, &scr2);
+		pci_write_config_byte(dev, 0x5b, (scr2 & ~1));
+		/* now read cable id register */
+		pci_read_config_byte (dev, 0x5a, &scr1);
+		pci_write_config_byte(dev, 0x5b,  scr2);
+	} else
+		pci_read_config_byte (dev, 0x5a, &scr1);
+
+	if (!hwif->udma_four)
+		hwif->udma_four = (scr1 & ata66) ? 0 : 1;
+
+	hwif->ide_dma_check		= &hpt366_config_drive_xfer_rate;
+
+	if (chip_type >= HPT374) {
+		hwif->ide_dma_test_irq	= &hpt374_ide_dma_test_irq;
+		hwif->ide_dma_end	= &hpt374_ide_dma_end;
+	} else if (chip_type >= HPT370) {
+		hwif->dma_start 	= &hpt370_ide_dma_start;
+		hwif->ide_dma_end	= &hpt370_ide_dma_end;
+		hwif->ide_dma_timeout	= &hpt370_ide_dma_timeout;
+	} else
+		hwif->ide_dma_lostirq	= &hpt366_ide_dma_lostirq;
 
 	if (!noautodma)
 		hwif->autodma = 1;
-	hwif->drives[0].autodma = hwif->autodma;
-	hwif->drives[1].autodma = hwif->autodma;
+	hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
 }
 
 static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
 {
-	struct hpt_info	*info	= ide_get_hwifdata(hwif);
-	u8 masterdma	= 0, slavedma = 0;
-	u8 dma_new	= 0, dma_old = 0;
-	u8 primary	= hwif->channel ? 0x4b : 0x43;
-	u8 secondary	= hwif->channel ? 0x4f : 0x47;
+	struct pci_dev	*dev		= hwif->pci_dev;
+	u8 masterdma	= 0, slavedma	= 0;
+	u8 dma_new	= 0, dma_old	= 0;
 	unsigned long flags;
 
 	if (!dmabase)
 		return;
 		
-	if(info->speed == NULL) {
-		printk(KERN_WARNING "hpt366: no known IDE timings, disabling DMA.\n");
-		return;
-	}
-
-	dma_old = hwif->INB(dmabase+2);
+	dma_old = hwif->INB(dmabase + 2);
 
 	local_irq_save(flags);
 
 	dma_new = dma_old;
-	pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
-	pci_read_config_byte(hwif->pci_dev, secondary, &slavedma);
+	pci_read_config_byte(dev, hwif->channel ? 0x4b : 0x43, &masterdma);
+	pci_read_config_byte(dev, hwif->channel ? 0x4f : 0x47,  &slavedma);
 
 	if (masterdma & 0x30)	dma_new |= 0x20;
-	if (slavedma & 0x30)	dma_new |= 0x40;
+	if ( slavedma & 0x30)	dma_new |= 0x40;
 	if (dma_new != dma_old)
-		hwif->OUTB(dma_new, dmabase+2);
+		hwif->OUTB(dma_new, dmabase + 2);
 
 	local_irq_restore(flags);
 
 	ide_setup_dma(hwif, dmabase, 8);
 }
 
-/*
- *	We "borrow" this hook in order to set the data structures
- *	up early enough before dma or init_hwif calls are made.
- */
-
-static void __devinit init_iops_hpt366(ide_hwif_t *hwif)
-{
-	struct hpt_info *info	= kzalloc(sizeof(struct hpt_info), GFP_KERNEL);
-	struct pci_dev  *dev	= hwif->pci_dev;
-	u16 did			= dev->device;
-	u8  rid			= 0;
-
-	if(info == NULL) {
-		printk(KERN_WARNING "hpt366: out of memory.\n");
-		return;
-	}
-	ide_set_hwifdata(hwif, info);
-
-	/* Avoid doing the same thing twice. */
-	if (hwif->channel && hwif->mate) {
-		memcpy(info, ide_get_hwifdata(hwif->mate), sizeof(struct hpt_info));
-		return;
-	}
-
-	pci_read_config_byte(dev, PCI_CLASS_REVISION, &rid);
-
-	if (( did == PCI_DEVICE_ID_TTI_HPT366  && rid == 6) ||
-	    ((did == PCI_DEVICE_ID_TTI_HPT372  ||
-	      did == PCI_DEVICE_ID_TTI_HPT302  ||
-	      did == PCI_DEVICE_ID_TTI_HPT371) && rid > 1) ||
-	      did == PCI_DEVICE_ID_TTI_HPT372N)
-		info->flags |= IS_3xxN;
-
-	info->revision = hpt_revision(dev);
-
-	if (info->revision >= 3)
-		hpt37x_clocking(hwif);
-	else
-		hpt366_clocking(hwif);
-}
-
 static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d)
 {
-	struct pci_dev *findev = NULL;
+	struct pci_dev *dev2;
 
 	if (PCI_FUNC(dev->devfn) & 1)
 		return -ENODEV;
 
-	while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
-		if ((findev->vendor == dev->vendor) &&
-		    (findev->device == dev->device) &&
-		    ((findev->devfn - dev->devfn) == 1) &&
-		    (PCI_FUNC(findev->devfn) & 1)) {
-			if (findev->irq != dev->irq) {
-				/* FIXME: we need a core pci_set_interrupt() */
-				findev->irq = dev->irq;
-				printk(KERN_WARNING "%s: pci-config space interrupt "
-					"fixed.\n", d->name);
-			}
-			return ide_setup_pci_devices(dev, findev, d);
+	pci_set_drvdata(dev, &hpt374);
+
+	if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
+		int ret;
+
+		pci_set_drvdata(dev2, &hpt374);
+
+		if (dev2->irq != dev->irq) {
+			/* FIXME: we need a core pci_set_interrupt() */
+			dev2->irq = dev->irq;
+			printk(KERN_WARNING "%s: PCI config space interrupt "
+			       "fixed.\n", d->name);
 		}
+		ret = ide_setup_pci_devices(dev, dev2, d);
+		if (ret < 0)
+			pci_dev_put(dev2);
+		return ret;
 	}
 	return ide_setup_pci_device(dev, d);
 }
 
-static int __devinit init_setup_hpt37x(struct pci_dev *dev, ide_pci_device_t *d)
+static int __devinit init_setup_hpt372n(struct pci_dev *dev, ide_pci_device_t *d)
 {
+	pci_set_drvdata(dev, &hpt372n);
+
 	return ide_setup_pci_device(dev, d);
 }
 
 static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d)
 {
-	u8 mcr1 = 0;
+	struct hpt_info *info;
+	u8 rev = 0, mcr1 = 0;
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+	if (rev > 1) {
+		d->name = "HPT371N";
+
+		info = &hpt371n;
+	} else
+		info = &hpt371;
 
 	/*
 	 * HPT371 chips physically have only one channel, the secondary one,
@@ -1453,59 +1469,94 @@
 	 */
 	pci_read_config_byte(dev, 0x50, &mcr1);
 	if (mcr1 & 0x04)
-		pci_write_config_byte(dev, 0x50, (mcr1 & ~0x04));
+		pci_write_config_byte(dev, 0x50, mcr1 & ~0x04);
+
+	pci_set_drvdata(dev, info);
+
+	return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_hpt372a(struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct hpt_info *info;
+	u8 rev = 0;
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+	if (rev > 1) {
+		d->name = "HPT372N";
+
+		info = &hpt372n;
+	} else
+		info = &hpt372a;
+	pci_set_drvdata(dev, info);
+
+	return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_hpt302(struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct hpt_info *info;
+	u8 rev = 0;
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+	if (rev > 1) {
+		d->name = "HPT302N";
+
+		info = &hpt302n;
+	} else
+		info = &hpt302;
+	pci_set_drvdata(dev, info);
 
 	return ide_setup_pci_device(dev, d);
 }
 
 static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
 {
-	struct pci_dev *findev = NULL;
-	u8 pin1 = 0, pin2 = 0;
-	unsigned int class_rev;
-	char *chipset_names[] = {"HPT366", "HPT366",  "HPT368",
-				 "HPT370", "HPT370A", "HPT372",
-				 "HPT372N" };
+	struct pci_dev *dev2;
+	u8 rev = 0;
+	static char   *chipset_names[] = { "HPT366", "HPT366",  "HPT368",
+					   "HPT370", "HPT370A", "HPT372",
+					   "HPT372N" };
+	static struct hpt_info *info[] = { &hpt36x,  &hpt36x,  &hpt36x,
+					   &hpt370,  &hpt370a, &hpt372,
+					   &hpt372n  };
 
 	if (PCI_FUNC(dev->devfn) & 1)
 		return -ENODEV;
 
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
+	pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
 
-	if(dev->device == PCI_DEVICE_ID_TTI_HPT372N)
-		class_rev = 6;
+	if (rev > 6)
+		rev = 6;
 		
-	if(class_rev <= 6)
-		d->name = chipset_names[class_rev];
+	d->name = chipset_names[rev];
 
-	switch(class_rev) {
-		case 6:
-		case 5:
-		case 4:
-		case 3:
-			goto init_single;
-		default:
-			break;
-	}
+	pci_set_drvdata(dev, info[rev]);
+
+	if (rev > 2)
+		goto init_single;
 
 	d->channels = 1;
 
-	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
-	while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
-		if ((findev->vendor == dev->vendor) &&
-		    (findev->device == dev->device) &&
-		    ((findev->devfn - dev->devfn) == 1) &&
-		    (PCI_FUNC(findev->devfn) & 1)) {
-			pci_read_config_byte(findev, PCI_INTERRUPT_PIN, &pin2);
-			if ((pin1 != pin2) && (dev->irq == findev->irq)) {
-				d->bootable = ON_BOARD;
-				printk("%s: onboard version of chipset, "
-					"pin1=%d pin2=%d\n", d->name,
-					pin1, pin2);
-			}
-			return ide_setup_pci_devices(dev, findev, d);
+	if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
+	  	u8  pin1 = 0, pin2 = 0;
+		int ret;
+
+		pci_set_drvdata(dev2, info[rev]);
+
+		pci_read_config_byte(dev,  PCI_INTERRUPT_PIN, &pin1);
+		pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
+		if (pin1 != pin2 && dev->irq == dev2->irq) {
+			d->bootable = ON_BOARD;
+			printk("%s: onboard version of chipset, pin1=%d pin2=%d\n",
+			       d->name, pin1, pin2);
 		}
+		ret = ide_setup_pci_devices(dev, dev2, d);
+		if (ret < 0)
+			pci_dev_put(dev2);
+		return ret;
 	}
 init_single:
 	return ide_setup_pci_device(dev, d);
@@ -1516,64 +1567,68 @@
 		.name		= "HPT366",
 		.init_setup	= init_setup_hpt366,
 		.init_chipset	= init_chipset_hpt366,
-		.init_iops	= init_iops_hpt366,
-		.init_hwif	= init_hwif_hpt366,
-		.init_dma	= init_dma_hpt366,
-		.channels	= 2,
-		.autodma	= AUTODMA,
-		.bootable	= OFF_BOARD,
-		.extra		= 240
-	},{	/* 1 */
-		.name		= "HPT372A",
-		.init_setup	= init_setup_hpt37x,
-		.init_chipset	= init_chipset_hpt366,
-		.init_iops	= init_iops_hpt366,
-		.init_hwif	= init_hwif_hpt366,
-		.init_dma	= init_dma_hpt366,
-		.channels	= 2,
-		.autodma	= AUTODMA,
-		.bootable	= OFF_BOARD,
-	},{	/* 2 */
-		.name		= "HPT302",
-		.init_setup	= init_setup_hpt37x,
-		.init_chipset	= init_chipset_hpt366,
-		.init_iops	= init_iops_hpt366,
-		.init_hwif	= init_hwif_hpt366,
-		.init_dma	= init_dma_hpt366,
-		.channels	= 2,
-		.autodma	= AUTODMA,
-		.bootable	= OFF_BOARD,
-	},{	/* 3 */
-		.name		= "HPT371",
-		.init_setup	= init_setup_hpt371,
-		.init_chipset	= init_chipset_hpt366,
-		.init_iops	= init_iops_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.channels	= 2,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
 		.bootable	= OFF_BOARD,
+		.extra		= 240
+	},{	/* 1 */
+		.name		= "HPT372A",
+		.init_setup	= init_setup_hpt372a,
+		.init_chipset	= init_chipset_hpt366,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
+		.bootable	= OFF_BOARD,
+		.extra		= 240
+	},{	/* 2 */
+		.name		= "HPT302",
+		.init_setup	= init_setup_hpt302,
+		.init_chipset	= init_chipset_hpt366,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
+		.bootable	= OFF_BOARD,
+		.extra		= 240
+	},{	/* 3 */
+		.name		= "HPT371",
+		.init_setup	= init_setup_hpt371,
+		.init_chipset	= init_chipset_hpt366,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
+		.bootable	= OFF_BOARD,
+		.extra		= 240
 	},{	/* 4 */
 		.name		= "HPT374",
 		.init_setup	= init_setup_hpt374,
 		.init_chipset	= init_chipset_hpt366,
-		.init_iops	= init_iops_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.channels	= 2,	/* 4 */
 		.autodma	= AUTODMA,
+		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
 		.bootable	= OFF_BOARD,
+		.extra		= 240
 	},{	/* 5 */
 		.name		= "HPT372N",
-		.init_setup	= init_setup_hpt37x,
+		.init_setup	= init_setup_hpt372n,
 		.init_chipset	= init_chipset_hpt366,
-		.init_iops	= init_iops_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.channels	= 2,	/* 4 */
 		.autodma	= AUTODMA,
+		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
 		.bootable	= OFF_BOARD,
+		.extra		= 240
 	}
 };
 
diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
new file mode 100644
index 0000000..63248b6
--- /dev/null
+++ b/drivers/ide/pci/it8213.c
@@ -0,0 +1,362 @@
+/*
+ * ITE 8213 IDE driver
+ *
+ * Copyright (C) 2006 Jack Lee
+ * Copyright (C) 2006 Alan Cox
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+/*
+ *	it8213_ratemask	-	Compute available modes
+ *	@drive: IDE drive
+ *
+ *	Compute the available speeds for the devices on the interface. This
+ *	is all modes to ATA133 clipped by drive cable setup.
+ */
+
+static u8 it8213_ratemask (ide_drive_t *drive)
+{
+	u8 mode	= 4;
+	if (!eighty_ninty_three(drive))
+		mode = min_t(u8, mode, 1);
+	return mode;
+}
+
+/**
+ *	it8213_dma_2_pio		-	return the PIO mode matching DMA
+ *	@xfer_rate: transfer speed
+ *
+ *	Returns the nearest equivalent PIO timing for the PIO or DMA
+ *	mode requested by the controller.
+ */
+
+static u8 it8213_dma_2_pio (u8 xfer_rate) {
+	switch(xfer_rate) {
+		case XFER_UDMA_6:
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
+
+/*
+ *	it8213_tuneproc	-	tune a drive
+ *	@drive: drive to tune
+ *	@pio: desired PIO mode
+ *
+ *	Set the interface PIO mode.
+ */
+
+static void it8213_tuneproc (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	int is_slave		= drive->dn & 1;
+	int master_port		= 0x40;
+	int slave_port		= 0x44;
+	unsigned long flags;
+	u16 master_data;
+	u8 slave_data;
+	static DEFINE_SPINLOCK(tune_lock);
+	int control = 0;
+
+	static const u8 timings[][2]= {
+					{ 0, 0 },
+					{ 0, 0 },
+					{ 1, 0 },
+					{ 2, 1 },
+					{ 2, 3 }, };
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+
+	spin_lock_irqsave(&tune_lock, flags);
+	pci_read_config_word(dev, master_port, &master_data);
+
+	if (pio > 1)
+		control |= 1;	/* Programmable timing on */
+	if (drive->media != ide_disk)
+		control |= 4;	/* ATAPI */
+	if (pio > 2)
+		control |= 2;	/* IORDY */
+	if (is_slave) {
+		master_data |=  0x4000;
+		master_data &= ~0x0070;
+		if (pio > 1)
+			master_data = master_data | (control << 4);
+		pci_read_config_byte(dev, slave_port, &slave_data);
+		slave_data = slave_data & 0xf0;
+		slave_data = slave_data | (timings[pio][0] << 2) | timings[pio][1];
+	} else {
+		master_data &= ~0x3307;
+		if (pio > 1)
+			master_data = master_data | control;
+		master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+	}
+	pci_write_config_word(dev, master_port, master_data);
+	if (is_slave)
+		pci_write_config_byte(dev, slave_port, slave_data);
+	spin_unlock_irqrestore(&tune_lock, flags);
+}
+
+/**
+ *	it8213_tune_chipset	-	set controller timings
+ *	@drive: Drive to set up
+ *	@xferspeed: speed we want to achieve
+ *
+ *	Tune the ITE chipset for the desired mode. If we can't achieve
+ *	the desired mode then tune for a lower one, but ultimately
+ *	make the thing work.
+ */
+
+static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 maslave		= 0x40;
+	u8 speed		= ide_rate_filter(it8213_ratemask(drive), xferspeed);
+	int a_speed		= 3 << (drive->dn * 4);
+	int u_flag		= 1 << drive->dn;
+	int v_flag		= 0x01 << drive->dn;
+	int w_flag		= 0x10 << drive->dn;
+	int u_speed		= 0;
+	u16			reg4042, reg4a;
+	u8			reg48, reg54, reg55;
+
+	pci_read_config_word(dev, maslave, &reg4042);
+	pci_read_config_byte(dev, 0x48, &reg48);
+	pci_read_config_word(dev, 0x4a, &reg4a);
+	pci_read_config_byte(dev, 0x54, &reg54);
+	pci_read_config_byte(dev, 0x55, &reg55);
+
+	switch(speed) {
+		case XFER_UDMA_6:
+		case XFER_UDMA_4:
+		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
+		case XFER_UDMA_5:
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+			break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_SW_DMA_2:
+			break;
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+			break;
+		default:
+			return -1;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		if (!(reg48 & u_flag))
+			pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+		if (speed >= XFER_UDMA_5) {
+			pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
+		} else {
+			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+		}
+
+		if ((reg4a & a_speed) != u_speed)
+			pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
+		if (speed > XFER_UDMA_2) {
+			if (!(reg54 & v_flag))
+				pci_write_config_byte(dev, 0x54, reg54 | v_flag);
+		} else
+			pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+	} else {
+		if (reg48 & u_flag)
+			pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+		if (reg4a & a_speed)
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+		if (reg54 & v_flag)
+			pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+		if (reg55 & w_flag)
+			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+	}
+	it8213_tuneproc(drive, it8213_dma_2_pio(speed));
+	return ide_config_drive_speed(drive, speed);
+}
+
+/*
+ *	config_chipset_for_dma	-	configure for DMA
+ *	@drive: drive to configure
+ *
+ *	Called by the IDE layer when it wants the timings set up.
+ */
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, it8213_ratemask(drive));
+
+	if (!speed)
+		return 0;
+
+	it8213_tune_chipset(drive, speed);
+
+	return ide_dma_enable(drive);
+}
+
+/**
+ *	it8213_configure_drive_for_dma	-	set up for DMA transfers
+ *	@drive: drive we are going to set up
+ *
+ *	Set up the drive for DMA, tune the controller and drive as
+ *	required. If the drive isn't suitable for DMA or we hit
+ *	other problems then we will drop down to PIO and set up
+ *	PIO appropriately
+ */
+
+static int it8213_config_drive_for_dma (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = drive->hwif;
+
+	if (ide_use_dma(drive)) {
+		if (config_chipset_for_dma(drive))
+			return hwif->ide_dma_on(drive);
+	}
+
+	hwif->speedproc(drive, XFER_PIO_0
+			+ ide_get_best_pio_mode(drive, 255, 4, NULL));
+
+ 	return hwif->ide_dma_off_quietly(drive);
+}
+
+/**
+ *	init_hwif_it8213	-	set up hwif structs
+ *	@hwif: interface to set up
+ *
+ *	We do the basic set up of the interface structure. The IT8212
+ *	requires several custom handlers so we override the default
+ *	ide DMA handlers appropriately
+ */
+
+static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
+{
+	u8 reg42h = 0, ata66 = 0;
+
+	hwif->speedproc = &it8213_tune_chipset;
+	hwif->tuneproc	= &it8213_tuneproc;
+
+	hwif->autodma = 0;
+
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x06;
+	hwif->swdma_mask = 0x04;
+
+	pci_read_config_byte(hwif->pci_dev, 0x42, &reg42h);
+	ata66 = (reg42h & 0x02) ? 0 : 1;
+
+	hwif->ide_dma_check = &it8213_config_drive_for_dma;
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66;
+
+	/*
+	 *	The BIOS often doesn't set up DMA on this controller
+	 *	so we always do it.
+	 */
+	if (!noautodma)
+		hwif->autodma = 1;
+
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+
+#define DECLARE_ITE_DEV(name_str)			\
+	{						\
+		.name		= name_str,		\
+		.init_hwif	= init_hwif_it8213,	\
+		.channels	= 1,			\
+		.autodma	= AUTODMA,		\
+		.enablebits	= {{0x41,0x80,0x80}}, \
+		.bootable	= ON_BOARD,		\
+	}
+
+static ide_pci_device_t it8213_chipsets[] __devinitdata = {
+	/* 0 */ DECLARE_ITE_DEV("IT8213"),
+};
+
+
+/**
+ *	it8213_init_one	-	pci layer discovery entry
+ *	@dev: PCI device
+ *	@id: ident table entry
+ *
+ *	Called by the PCI code when it finds an ITE8213 controller. As
+ *	this device follows the standard interfaces we can use the
+ *	standard helper functions to do almost all the work for us.
+ */
+
+static int __devinit it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_setup_pci_device(dev, &it8213_chipsets[id->driver_data]);
+	return 0;
+}
+
+
+static struct pci_device_id it8213_pci_tbl[] = {
+	{ PCI_VENDOR_ID_ITE, 0x8213, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, it8213_pci_tbl);
+
+static struct pci_driver driver = {
+	.name		= "ITE8213_IDE",
+	.id_table	= it8213_pci_tbl,
+	.probe		= it8213_init_one,
+};
+
+static int __init it8213_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+module_init(it8213_ide_init);
+
+MODULE_AUTHOR("Jack Lee, Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for the ITE 8213");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index 77a9aaa..236a031 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -92,26 +92,6 @@
 	return	mode;
 }
 
-static int check_in_drive_lists(ide_drive_t *drive, const char **list)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (pdc_quirk_drives == list) {
-		while (*list) {
-			if (strstr(id->model, *list++)) {
-				return 2;
-			}
-		}
-	} else {
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
 /**
  * get_indexed_reg - Get indexed register
  * @hwif: for the port address
@@ -249,13 +229,6 @@
 	return err;
 }
 
-/*   0    1    2    3    4    5    6   7   8
- * 960, 480, 390, 300, 240, 180, 120, 90, 60
- *           180, 150, 120,  90,  60
- * DMA_Speed
- * 180, 120,  90,  90,  90,  60,  30
- *  11,   5,   4,   3,   2,   1,   0
- */
 static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio)
 {
 	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
@@ -313,12 +286,10 @@
 
 	drive->init_speed = 0;
 
-	if (id && (id->capability & 1) && drive->autodma) {
+	if ((id->capability & 1) && drive->autodma) {
 
-		if (ide_use_dma(drive)) {
-			if (config_chipset_for_dma(drive))
-				return hwif->ide_dma_on(drive);
-		}
+		if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+			return hwif->ide_dma_on(drive);
 
 		goto fast_ata_pio;
 
@@ -333,21 +304,12 @@
 
 static int pdcnew_quirkproc(ide_drive_t *drive)
 {
-	return check_in_drive_lists(drive, pdc_quirk_drives);
-}
+	const char **list, *model = drive->id->model;
 
-static int pdcnew_ide_dma_lostirq(ide_drive_t *drive)
-{
-	if (HWIF(drive)->resetproc != NULL)
-		HWIF(drive)->resetproc(drive);
-	return __ide_dma_lostirq(drive);
-}
-
-static int pdcnew_ide_dma_timeout(ide_drive_t *drive)
-{
-	if (HWIF(drive)->resetproc != NULL)
-		HWIF(drive)->resetproc(drive);
-	return __ide_dma_timeout(drive);
+	for (list = pdc_quirk_drives; *list != NULL; list++)
+		if (strstr(model, *list) != NULL)
+			return 2;
+	return 0;
 }
 
 static void pdcnew_reset(ide_drive_t *drive)
@@ -599,8 +561,6 @@
 	hwif->err_stops_fifo = 1;
 
 	hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
-	hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq;
-	hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout;
 
 	if (!hwif->udma_four)
 		hwif->udma_four = pdcnew_cable_detect(hwif) ? 0 : 1;
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index 143239c..730e8d1 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -123,26 +123,6 @@
 	return mode;
 }
 
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (pdc_quirk_drives == list) {
-		while (*list) {
-			if (strstr(id->model, *list++)) {
-				return 2;
-			}
-		}
-	} else {
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
 static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
@@ -377,7 +357,12 @@
 
 static int pdc202xx_quirkproc (ide_drive_t *drive)
 {
-	return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+	const char **list, *model = drive->id->model;
+
+	for (list = pdc_quirk_drives; *list != NULL; list++)
+		if (strstr(model, *list) != NULL)
+			return 2;
+	return 0;
 }
 
 static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index edb37f3..52cfc2a 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/pci/piix.c	Version 0.45	May 12, 2006
+ *  linux/drivers/ide/pci/piix.c	Version 0.46	December 3, 2006
  *
  *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
  *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
@@ -163,7 +163,7 @@
 	 *	if the drive cannot see an 80pin cable.
 	 */
 	if (!eighty_ninty_three(drive))
-		mode = min(mode, (u8)1);
+		mode = min_t(u8, mode, 1);
 	return mode;
 }
 
@@ -216,7 +216,7 @@
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
-	int is_slave		= (&hwif->drives[1] == drive);
+	int is_slave		= drive->dn & 1;
 	int master_port		= hwif->channel ? 0x42 : 0x40;
 	int slave_port		= 0x44;
 	unsigned long flags;
@@ -225,7 +225,7 @@
 	static DEFINE_SPINLOCK(tune_lock);
 	int control = 0;
 
-				 /* ISP  RTC */
+				     /* ISP  RTC */
 	static const u8 timings[][2]= {
 					{ 0, 0 },
 					{ 0, 0 },
@@ -233,7 +233,7 @@
 					{ 2, 1 },
 					{ 2, 3 }, };
 
-	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
 
 	/*
 	 * Master vs slave is synchronized above us but the slave register is
@@ -243,25 +243,24 @@
 	spin_lock_irqsave(&tune_lock, flags);
 	pci_read_config_word(dev, master_port, &master_data);
 
-	if (pio >= 2)
+	if (pio > 1)
 		control |= 1;	/* Programmable timing on */
 	if (drive->media == ide_disk)
 		control |= 4;	/* Prefetch, post write */
-	if (pio >= 3)
+	if (pio > 2)
 		control |= 2;	/* IORDY */
 	if (is_slave) {
-		master_data = master_data | 0x4000;
+		master_data |=  0x4000;
+		master_data &= ~0x0070;
 		if (pio > 1) {
 			/* enable PPE, IE and TIME */
 			master_data = master_data | (control << 4);
-		} else {
-			master_data &= ~0x0070;
 		}
 		pci_read_config_byte(dev, slave_port, &slave_data);
 		slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
 		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
 	} else {
-		master_data = master_data & 0xccf8;
+		master_data &= ~0x3307;
 		if (pio > 1) {
 			/* enable PPE, IE and TIME */
 			master_data = master_data | control;
@@ -539,13 +538,19 @@
 	/*  0 */ DECLARE_PIIX_DEV("PIIXa"),
 	/*  1 */ DECLARE_PIIX_DEV("PIIXb"),
 
-	{	/* 2 */
+	/*  2 */
+	{	/*
+		 * MPIIX actually has only a single IDE channel mapped to
+		 * the primary or secondary ports depending on the value
+		 * of the bit 14 of the IDETIM register at offset 0x6c
+		 */
 		.name		= "MPIIX",
 		.init_hwif	= init_hwif_piix,
 		.channels	= 2,
 		.autodma	= NODMA,
-		.enablebits	= {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},
+		.enablebits	= {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}},
 		.bootable	= ON_BOARD,
+		.flags		= IDEPCI_FLAG_ISA_PORTS
 	},
 
 	/*  3 */ DECLARE_PIIX_DEV("PIIX3"),
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
index 90e79c0..2663ddb 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/pci/slc90e66.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/pci/slc90e66.c	Version 0.12	May 12, 2006
+ *  linux/drivers/ide/pci/slc90e66.c	Version 0.13	December 30, 2006
  *
  *  Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
  *  Copyright (C) 2006 MontaVista Software, Inc. <source@mvista.com>
@@ -26,7 +26,7 @@
 	u8 mode	= 2;
 
 	if (!eighty_ninty_three(drive))
-		mode = min(mode, (u8)1);
+		mode = min_t(u8, mode, 1);
 	return mode;
 }
 
@@ -65,36 +65,47 @@
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
-	int is_slave		= (&hwif->drives[1] == drive);
+	int is_slave		= drive->dn & 1;
 	int master_port		= hwif->channel ? 0x42 : 0x40;
 	int slave_port		= 0x44;
 	unsigned long flags;
 	u16 master_data;
 	u8 slave_data;
-				 /* ISP  RTC */
+ 	int control = 0;
+				     /* ISP  RTC */
 	static const u8 timings[][2]= {
-				    { 0, 0 },
-				    { 0, 0 },
-				    { 1, 0 },
-				    { 2, 1 },
-				    { 2, 3 }, };
+					{ 0, 0 },
+					{ 0, 0 },
+					{ 1, 0 },
+					{ 2, 1 },
+					{ 2, 3 }, };
 
-	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
 	spin_lock_irqsave(&ide_lock, flags);
 	pci_read_config_word(dev, master_port, &master_data);
+
+	if (pio > 1)
+		control |= 1;	/* Programmable timing on */
+	if (drive->media == ide_disk)
+		control |= 4;	/* Prefetch, post write */
+	if (pio > 2)
+		control |= 2;	/* IORDY */
 	if (is_slave) {
-		master_data = master_data | 0x4000;
-		if (pio > 1)
+		master_data |=  0x4000;
+		master_data &= ~0x0070;
+		if (pio > 1) {
 			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0070;
+			master_data = master_data | (control << 4);
+		}
 		pci_read_config_byte(dev, slave_port, &slave_data);
 		slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
 		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
 	} else {
-		master_data = master_data & 0xccf8;
-		if (pio > 1)
+		master_data &= ~0x3307;
+		if (pio > 1) {
 			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0007;
+			master_data = master_data | control;
+		}
 		master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
 	}
 	pci_write_config_word(dev, master_port, master_data);
@@ -173,7 +184,7 @@
 
 	drive->init_speed = 0;
 
-	if (id && (id->capability & 1) && drive->autodma) {
+	if ((id->capability & 1) && drive->autodma) {
 
 		if (ide_use_dma(drive) && slc90e66_config_drive_for_dma(drive))
 			return hwif->ide_dma_on(drive);
@@ -201,7 +212,7 @@
 		hwif->irq = hwif->channel ? 15 : 14;
 
 	hwif->speedproc = &slc90e66_tune_chipset;
-	hwif->tuneproc = &slc90e66_tune_drive;
+	hwif->tuneproc	= &slc90e66_tune_drive;
 
 	pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
 
@@ -213,14 +224,16 @@
 
 	hwif->atapi_dma = 1;
 	hwif->ultra_mask = 0x1f;
-	hwif->mwdma_mask = 0x07;
-	hwif->swdma_mask = 0x07;
+	hwif->mwdma_mask = 0x06;
+	hwif->swdma_mask = 0x04;
 
-	if (!(hwif->udma_four))
+	if (!hwif->udma_four) {
 		/* bit[0(1)]: 0:80, 1:40 */
 		hwif->udma_four = (reg47 & mask) ? 0 : 1;
+	}
 
 	hwif->ide_dma_check = &slc90e66_config_drive_xfer_rate;
+
 	if (!noautodma)
 		hwif->autodma = 1;
 	hwif->drives[0].autodma = hwif->autodma;
diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c
new file mode 100644
index 0000000..2ad72bb
--- /dev/null
+++ b/drivers/ide/pci/tc86c001.c
@@ -0,0 +1,309 @@
+/*
+ * drivers/ide/pci/tc86c001.c	Version 1.00	Dec 12, 2006
+ *
+ * Copyright (C) 2002 Toshiba Corporation
+ * Copyright (C) 2005-2006 MontaVista Software, Inc. <source@mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static inline u8 tc86c001_ratemask(ide_drive_t *drive)
+{
+	return eighty_ninty_three(drive) ? 2 : 1;
+}
+
+static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned long scr_port	= hwif->config_data + (drive->dn ? 0x02 : 0x00);
+	u16 mode, scr		= hwif->INW(scr_port);
+
+	speed = ide_rate_filter(tc86c001_ratemask(drive), speed);
+
+	switch (speed) {
+		case XFER_UDMA_4:	mode = 0x00c0; break;
+		case XFER_UDMA_3:	mode = 0x00b0; break;
+		case XFER_UDMA_2:	mode = 0x00a0; break;
+		case XFER_UDMA_1:	mode = 0x0090; break;
+		case XFER_UDMA_0:	mode = 0x0080; break;
+		case XFER_MW_DMA_2:	mode = 0x0070; break;
+		case XFER_MW_DMA_1:	mode = 0x0060; break;
+		case XFER_MW_DMA_0:	mode = 0x0050; break;
+		case XFER_PIO_4:	mode = 0x0400; break;
+		case XFER_PIO_3:	mode = 0x0300; break;
+		case XFER_PIO_2:	mode = 0x0200; break;
+		case XFER_PIO_1:	mode = 0x0100; break;
+		case XFER_PIO_0:
+		default:		mode = 0x0000; break;
+	}
+
+	scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f;
+	scr |= mode;
+	hwif->OUTW(scr, scr_port);
+
+	return ide_config_drive_speed(drive, speed);
+}
+
+static void tc86c001_tune_drive(ide_drive_t *drive, u8 pio)
+{
+	pio =  ide_get_best_pio_mode(drive, pio, 4, NULL);
+	(void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio);
+}
+
+/*
+ * HACKITY HACK
+ *
+ * This is a workaround for the limitation 5 of the TC86C001 IDE controller:
+ * if a DMA transfer terminates prematurely, the controller leaves the device's
+ * interrupt request (INTRQ) pending and does not generate a PCI interrupt (or
+ * set the interrupt bit in the DMA status register), thus no PCI interrupt
+ * will occur until a DMA transfer has been successfully completed.
+ *
+ * We work around this by initiating dummy, zero-length DMA transfer on
+ * a DMA timeout expiration. I found no better way to do this with the current
+ * IDE core than to temporarily replace a higher level driver's timer expiry
+ * handler with our own backing up to that handler in case our recovery fails.
+ */
+static int tc86c001_timer_expiry(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	ide_expiry_t *expiry	= ide_get_hwifdata(hwif);
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
+
+	/* Restore a higher level driver's expiry handler first. */
+	hwgroup->expiry	= expiry;
+
+	if ((dma_stat & 5) == 1) {	/* DMA active and no interrupt */
+		unsigned long sc_base	= hwif->config_data;
+		unsigned long twcr_port	= sc_base + (drive->dn ? 0x06 : 0x04);
+		u8 dma_cmd		= hwif->INB(hwif->dma_command);
+
+		printk(KERN_WARNING "%s: DMA interrupt possibly stuck, "
+		       "attempting recovery...\n", drive->name);
+
+		/* Stop DMA */
+		hwif->OUTB(dma_cmd & ~0x01, hwif->dma_command);
+
+		/* Setup the dummy DMA transfer */
+		hwif->OUTW(0, sc_base + 0x0a);	/* Sector Count */
+		hwif->OUTW(0, twcr_port);	/* Transfer Word Count 1 or 2 */
+
+		/* Start the dummy DMA transfer */
+		hwif->OUTB(0x00, hwif->dma_command); /* clear R_OR_WCTR for write */
+		hwif->OUTB(0x01, hwif->dma_command); /* set START_STOPBM */
+
+		/*
+		 * If an interrupt was pending, it should come thru shortly.
+		 * If not, a higher level driver's expiry handler should
+		 * eventually cause some kind of recovery from the DMA stall.
+		 */
+		return WAIT_MIN_SLEEP;
+	}
+
+	/* Chain to the restored expiry handler if DMA wasn't active. */
+	if (likely(expiry != NULL))
+		return expiry(drive);
+
+	/* If there was no handler, "emulate" that for ide_timer_expiry()... */
+	return -1;
+}
+
+static void tc86c001_dma_start(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	unsigned long sc_base	= hwif->config_data;
+	unsigned long twcr_port	= sc_base + (drive->dn ? 0x06 : 0x04);
+	unsigned long nsectors	= hwgroup->rq->nr_sectors;
+
+	/*
+	 * We have to manually load the sector count and size into
+	 * the appropriate system control registers for DMA to work
+	 * with LBA48 and ATAPI devices...
+	 */
+	hwif->OUTW(nsectors, sc_base + 0x0a);	/* Sector Count */
+	hwif->OUTW(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */
+
+	/* Install our timeout expiry hook, saving the current handler... */
+	ide_set_hwifdata(hwif, hwgroup->expiry);
+	hwgroup->expiry = &tc86c001_timer_expiry;
+
+	ide_dma_start(drive);
+}
+
+static int tc86c001_busproc(ide_drive_t *drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned long sc_base	= hwif->config_data;
+	u16 scr1;
+
+	/* System Control 1 Register bit 11 (ATA Hard Reset) read */
+	scr1 = hwif->INW(sc_base + 0x00);
+
+	switch (state) {
+		case BUSSTATE_ON:
+			if (!(scr1 & 0x0800))
+				return 0;
+			scr1 &= ~0x0800;
+
+			hwif->drives[0].failures = hwif->drives[1].failures = 0;
+			break;
+		case BUSSTATE_OFF:
+			if (scr1 & 0x0800)
+				return 0;
+			scr1 |= 0x0800;
+
+			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	/* System Control 1 Register bit 11 (ATA Hard Reset) write */
+	hwif->OUTW(scr1, sc_base + 0x00);
+	return 0;
+}
+
+static int config_chipset_for_dma(ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, tc86c001_ratemask(drive));
+
+	if (!speed)
+		return 0;
+
+	(void) tc86c001_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int tc86c001_config_drive_xfer_rate(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	if ((id->capability & 1) && drive->autodma) {
+
+		if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+			return hwif->ide_dma_on(drive);
+
+		goto fast_ata_pio;
+
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+		tc86c001_tune_drive(drive, 255);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	/* IORDY not supported */
+	return 0;
+}
+
+static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
+{
+	unsigned long sc_base	= pci_resource_start(hwif->pci_dev, 5);
+	u16 scr1		= hwif->INW(sc_base + 0x00);;
+
+	/* System Control 1 Register bit 15 (Soft Reset) set */
+	hwif->OUTW(scr1 |  0x8000, sc_base + 0x00);
+
+	/* System Control 1 Register bit 14 (FIFO Reset) set */
+	hwif->OUTW(scr1 |  0x4000, sc_base + 0x00);
+
+	/* System Control 1 Register: reset clear */
+	hwif->OUTW(scr1 & ~0xc000, sc_base + 0x00);
+
+	/* Store the system control register base for convenience... */
+	hwif->config_data = sc_base;
+
+	hwif->tuneproc	= &tc86c001_tune_drive;
+	hwif->speedproc = &tc86c001_tune_chipset;
+	hwif->busproc	= &tc86c001_busproc;
+
+	hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+
+	if (!hwif->dma_base)
+		return;
+
+	/*
+	 * Sector Count Control Register bits 0 and 1 set:
+	 * software sets Sector Count Register for master and slave device
+	 */
+	hwif->OUTW(0x0003, sc_base + 0x0c);
+
+	/* Sector Count Register limit */
+	hwif->rqsize	 = 0xffff;
+
+	hwif->atapi_dma  = 1;
+	hwif->ultra_mask = 0x1f;
+	hwif->mwdma_mask = 0x07;
+
+	hwif->ide_dma_check	= &tc86c001_config_drive_xfer_rate;
+	hwif->dma_start 	= &tc86c001_dma_start;
+
+	if (!hwif->udma_four) {
+		/*
+		 * System Control  1 Register bit 13 (PDIAGN):
+		 * 0=80-pin cable, 1=40-pin cable
+		 */
+		scr1 = hwif->INW(sc_base + 0x00);
+		hwif->udma_four = (scr1 & 0x2000) ? 0 : 1;
+	}
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+}
+
+static unsigned int __devinit init_chipset_tc86c001(struct pci_dev *dev,
+							const char *name)
+{
+	int err = pci_request_region(dev, 5, name);
+
+	if (err)
+		printk(KERN_ERR "%s: system control regs already in use", name);
+	return err;
+}
+
+static ide_pci_device_t tc86c001_chipset __devinitdata = {
+	.name		= "TC86C001",
+	.init_chipset	= init_chipset_tc86c001,
+	.init_hwif	= init_hwif_tc86c001,
+	.channels	= 1,
+	.autodma	= AUTODMA,
+	.bootable	= OFF_BOARD
+};
+
+static int __devinit tc86c001_init_one(struct pci_dev *dev,
+				       const struct pci_device_id *id)
+{
+	return ide_setup_pci_device(dev, &tc86c001_chipset);
+}
+
+static struct pci_device_id tc86c001_pci_tbl[] = {
+	{ PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, tc86c001_pci_tbl);
+
+static struct pci_driver driver = {
+	.name		= "TC86C001",
+	.id_table	= tc86c001_pci_tbl,
+	.probe		= tc86c001_init_one
+};
+
+static int __init tc86c001_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+module_init(tc86c001_ide_init);
+
+MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
+MODULE_DESCRIPTION("PCI driver module for TC86C001 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index 695e239..a52c80f 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -783,10 +783,11 @@
  *	Returns are the same as for pci_register_driver
  */
 
-int __ide_pci_register_driver(struct pci_driver *driver, struct module *module)
+int __ide_pci_register_driver(struct pci_driver *driver, struct module *module,
+			      const char *mod_name)
 {
 	if(!pre_init)
-		return __pci_register_driver(driver, module);
+		return __pci_register_driver(driver, module, mod_name);
 	driver->driver.owner = module;
 	list_add_tail(&driver->node, &ide_pci_drivers);
 	return 0;
@@ -862,6 +863,6 @@
 	{
 		list_del(l);
 		d = list_entry(l, struct pci_driver, node);
-		__pci_register_driver(d, d->driver.owner);
+		__pci_register_driver(d, d->driver.owner, d->driver.mod_name);
 	}
 }
diff --git a/drivers/ieee1394/.gitignore b/drivers/ieee1394/.gitignore
deleted file mode 100644
index 33da10a..0000000
--- a/drivers/ieee1394/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-oui.c
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
index e7d5657..b8a4734 100644
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -35,20 +35,6 @@
 	  Say Y if you really want or need the debugging output, everyone
 	  else says N.
 
-config IEEE1394_OUI_DB
-	bool "OUI Database built-in (deprecated)"
-	depends on IEEE1394
-	help
-	  If you say Y here, then an OUI list (vendor unique ID's) will be
-	  compiled into the ieee1394 module. This doesn't really do much
-	  except being able to display the vendor of a hardware node. The
-	  downside is that it adds about 300k to the size of the module,
-	  or kernel (depending on whether you compile ieee1394 as a
-	  module, or static in the kernel).
-
-	  This option is not needed for userspace programs like gscanbus
-	  to show this information.
-
 config IEEE1394_EXTRA_CONFIG_ROMS
 	bool "Build in extra config rom entries for certain functionality"
 	depends on IEEE1394
@@ -66,13 +52,6 @@
 	  with MacOSX and WinXP IP-over-1394), enable this option and the
 	  eth1394 option below.
 
-config IEEE1394_EXPORT_FULL_API
-	bool "Export all symbols of ieee1394's API (deprecated)"
-	depends on IEEE1394
-	default n
-	help
-	  This option will be removed soon.  Don't worry, say N.
-
 comment "Device Drivers"
 	depends on IEEE1394
 
diff --git a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile
index d9650d3..489c133 100644
--- a/drivers/ieee1394/Makefile
+++ b/drivers/ieee1394/Makefile
@@ -5,9 +5,6 @@
 ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
 		 highlevel.o csr.o nodemgr.o dma.o iso.o \
 		 csr1212.o config_roms.o
-ifdef CONFIG_IEEE1394_OUI_DB
-ieee1394-objs += oui.o
-endif
 
 obj-$(CONFIG_IEEE1394) += ieee1394.o
 obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o
@@ -18,10 +15,3 @@
 obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o
 obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o
 
-quiet_cmd_oui2c = OUI2C   $@
-      cmd_oui2c = $(CONFIG_SHELL) $(srctree)/$(src)/oui2c.sh < $< > $@
-
-targets := oui.c
-$(obj)/oui.o: $(obj)/oui.c
-$(obj)/oui.c: $(src)/oui.db $(src)/oui2c.sh FORCE
-	$(call if_changed,oui2c)
diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c
index 586f71e..c28f639 100644
--- a/drivers/ieee1394/csr1212.c
+++ b/drivers/ieee1394/csr1212.c
@@ -47,14 +47,14 @@
 #define __D (1 << CSR1212_KV_TYPE_DIRECTORY)
 #define __L (1 << CSR1212_KV_TYPE_LEAF)
 static const u_int8_t csr1212_key_id_type_map[0x30] = {
-	0,			/* Reserved */
+	__C,			/* used by Apple iSight */
 	__D | __L,		/* Descriptor */
 	__I | __D | __L,	/* Bus_Dependent_Info */
 	__I | __D | __L,	/* Vendor */
 	__I,			/* Hardware_Version */
 	0, 0,			/* Reserved */
-	__D | __L,		/* Module */
-	0, 0, 0, 0,		/* Reserved */
+	__D | __L | __I,	/* Module */
+	__I, 0, 0, 0,		/* used by Apple iSight, Reserved */
 	__I,			/* Node_Capabilities */
 	__L,			/* EUI_64 */
 	0, 0, 0,		/* Reserved */
@@ -1234,6 +1234,12 @@
 					 csr->private);
 		if (ret != CSR1212_SUCCESS)
 			return ret;
+
+		/* check ROM header's info_length */
+		if (i == 0 &&
+		    CSR1212_BE32_TO_CPU(csr->cache_head->data[0]) >> 24 !=
+		    bytes_to_quads(csr->bus_info_len) - 1)
+			return CSR1212_EINVAL;
 	}
 
 	bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data;
@@ -1250,9 +1256,6 @@
 			return ret;
 	}
 
-	if (bytes_to_quads(csr->bus_info_len - sizeof(csr1212_quad_t)) != bi->length)
-		return CSR1212_EINVAL;
-
 #if 0
 	/* Apparently there are too many differnt wrong implementations of the
 	 * CRC algorithm that verifying them is moot. */
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
index 1084da4..55d6ae6 100644
--- a/drivers/ieee1394/dv1394.c
+++ b/drivers/ieee1394/dv1394.c
@@ -2255,49 +2255,37 @@
 	return 0;
 }
 
-static void dv1394_un_init(struct video_card *video)
+static void dv1394_remove_host(struct hpsb_host *host)
 {
-	/* obviously nobody has the driver open at this point */
-	do_dv1394_shutdown(video, 1);
-	kfree(video);
-}
-
-
-static void dv1394_remove_host (struct hpsb_host *host)
-{
-	struct video_card *video;
+	struct video_card *video, *tmp_video;
 	unsigned long flags;
-	int id = host->id;
+	int found_ohci_card = 0;
 
-	/* We only work with the OHCI-1394 driver */
-	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
-		return;
-
-	/* find the corresponding video_cards */
 	do {
-		struct video_card *tmp_vid;
-
 		video = NULL;
-
 		spin_lock_irqsave(&dv1394_cards_lock, flags);
-		list_for_each_entry(tmp_vid, &dv1394_cards, list) {
-			if ((tmp_vid->id >> 2) == id) {
-				list_del(&tmp_vid->list);
-				video = tmp_vid;
+		list_for_each_entry(tmp_video, &dv1394_cards, list) {
+			if ((tmp_video->id >> 2) == host->id) {
+				list_del(&tmp_video->list);
+				video = tmp_video;
+				found_ohci_card = 1;
 				break;
 			}
 		}
 		spin_unlock_irqrestore(&dv1394_cards_lock, flags);
 
-		if (video)
-			dv1394_un_init(video);
-	} while (video != NULL);
+		if (video) {
+			do_dv1394_shutdown(video, 1);
+			kfree(video);
+		}
+	} while (video);
 
-	class_device_destroy(hpsb_protocol_class,
-		MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)));
+	if (found_ohci_card)
+		class_device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
+			   IEEE1394_MINOR_BLOCK_DV1394 * 16 + (host->id << 2)));
 }
 
-static void dv1394_add_host (struct hpsb_host *host)
+static void dv1394_add_host(struct hpsb_host *host)
 {
 	struct ti_ohci *ohci;
 	int id = host->id;
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
index ee82a53..32a1309 100644
--- a/drivers/ieee1394/hosts.c
+++ b/drivers/ieee1394/hosts.c
@@ -190,14 +190,19 @@
 {
 	if (hpsb_default_host_entry(host))
 		return -ENOMEM;
-
 	hpsb_add_extra_config_roms(host);
-
 	highlevel_add_host(host);
-
 	return 0;
 }
 
+void hpsb_resume_host(struct hpsb_host *host)
+{
+	if (host->driver->set_hw_config_rom)
+		host->driver->set_hw_config_rom(host,
+						host->csr.rom->bus_info_data);
+	host->driver->devctl(host, RESET_BUS, SHORT_RESET);
+}
+
 void hpsb_remove_host(struct hpsb_host *host)
 {
 	host->is_shutdown = 1;
@@ -206,9 +211,7 @@
 	flush_scheduled_work();
 
 	host->driver = &dummy_driver;
-
 	highlevel_remove_host(host);
-
 	hpsb_remove_extra_config_roms(host);
 
 	class_device_unregister(&host->class_dev);
diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
index d553e38..4bf4fb7 100644
--- a/drivers/ieee1394/hosts.h
+++ b/drivers/ieee1394/hosts.h
@@ -61,9 +61,9 @@
 	struct device device;
 	struct class_device class_dev;
 
-	int update_config_rom;
 	struct delayed_work delayed_reset;
-	unsigned int config_roms;
+	unsigned config_roms:31;
+	unsigned update_config_rom:1;
 
 	struct list_head addr_space;
 	u64 low_addr_space;	/* upper bound of physical DMA area */
@@ -200,7 +200,8 @@
 struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
 				  struct device *dev);
 int hpsb_add_host(struct hpsb_host *host);
-void hpsb_remove_host(struct hpsb_host *h);
+void hpsb_resume_host(struct hpsb_host *host);
+void hpsb_remove_host(struct hpsb_host *host);
 
 /* Updates the configuration rom image of a host.  rom_version must be the
  * current version, otherwise it will fail with return value -1. If this
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index 9a48ca2..1521e57 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -1178,6 +1178,7 @@
 /** hosts.c **/
 EXPORT_SYMBOL(hpsb_alloc_host);
 EXPORT_SYMBOL(hpsb_add_host);
+EXPORT_SYMBOL(hpsb_resume_host);
 EXPORT_SYMBOL(hpsb_remove_host);
 EXPORT_SYMBOL(hpsb_update_config_rom_image);
 
@@ -1195,10 +1196,6 @@
 EXPORT_SYMBOL(hpsb_packet_sent);
 EXPORT_SYMBOL(hpsb_packet_received);
 EXPORT_SYMBOL_GPL(hpsb_disable_irm);
-#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
-EXPORT_SYMBOL(hpsb_send_phy_config);
-EXPORT_SYMBOL(hpsb_send_packet_and_wait);
-#endif
 
 /** ieee1394_transactions.c **/
 EXPORT_SYMBOL(hpsb_get_tlabel);
@@ -1229,20 +1226,12 @@
 EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
 EXPORT_SYMBOL(hpsb_set_hostinfo);
 EXPORT_SYMBOL(highlevel_host_reset);
-#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
-EXPORT_SYMBOL(highlevel_add_host);
-EXPORT_SYMBOL(highlevel_remove_host);
-#endif
 
 /** nodemgr.c **/
 EXPORT_SYMBOL(hpsb_node_fill_packet);
 EXPORT_SYMBOL(hpsb_node_write);
 EXPORT_SYMBOL(__hpsb_register_protocol);
 EXPORT_SYMBOL(hpsb_unregister_protocol);
-#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
-EXPORT_SYMBOL(ieee1394_bus_type);
-EXPORT_SYMBOL(nodemgr_for_each_host);
-#endif
 
 /** csr.c **/
 EXPORT_SYMBOL(hpsb_update_config_rom);
@@ -1287,13 +1276,3 @@
 EXPORT_SYMBOL(csr1212_parse_keyval);
 EXPORT_SYMBOL(_csr1212_read_keyval);
 EXPORT_SYMBOL(_csr1212_destroy_keyval);
-#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
-EXPORT_SYMBOL(csr1212_create_csr);
-EXPORT_SYMBOL(csr1212_init_local_csr);
-EXPORT_SYMBOL(csr1212_new_immediate);
-EXPORT_SYMBOL(csr1212_associate_keyval);
-EXPORT_SYMBOL(csr1212_new_string_descriptor_leaf);
-EXPORT_SYMBOL(csr1212_destroy_csr);
-EXPORT_SYMBOL(csr1212_generate_csr_image);
-EXPORT_SYMBOL(csr1212_parse_csr);
-#endif
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 61307ca..ba9faef 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -41,22 +41,6 @@
 };
 
 
-static char *nodemgr_find_oui_name(int oui)
-{
-#ifdef CONFIG_IEEE1394_OUI_DB
-	extern struct oui_list_struct {
-		int oui;
-		char *name;
-	} oui_list[];
-	int i;
-
-	for (i = 0; oui_list[i].name; i++)
-		if (oui_list[i].oui == oui)
-			return oui_list[i].name;
-#endif
-	return NULL;
-}
-
 /*
  * Correct the speed map entry.  This is necessary
  *  - for nodes with link speed < phy speed,
@@ -274,7 +258,6 @@
 struct device nodemgr_dev_template_host = {
 	.bus		= &ieee1394_bus_type,
 	.release	= nodemgr_release_host,
-	.driver		= &nodemgr_mid_layer_driver,
 };
 
 
@@ -473,11 +456,9 @@
 
 fw_attr(ne, struct node_entry, vendor_id, unsigned int, "0x%06x\n")
 fw_attr_td(ne, struct node_entry, vendor_name_kv)
-fw_attr(ne, struct node_entry, vendor_oui, const char *, "%s\n")
 
 fw_attr(ne, struct node_entry, guid, unsigned long long, "0x%016Lx\n")
 fw_attr(ne, struct node_entry, guid_vendor_id, unsigned int, "0x%06x\n")
-fw_attr(ne, struct node_entry, guid_vendor_oui, const char *, "%s\n")
 fw_attr(ne, struct node_entry, in_limbo, int, "%d\n");
 
 static struct device_attribute *const fw_ne_attrs[] = {
@@ -503,7 +484,6 @@
 fw_attr(ud, struct unit_directory, specifier_id, unsigned int, "0x%06x\n")
 fw_attr(ud, struct unit_directory, version, unsigned int, "0x%06x\n")
 fw_attr_td(ud, struct unit_directory, vendor_name_kv)
-fw_attr(ud, struct unit_directory, vendor_oui, const char *, "%s\n")
 fw_attr_td(ud, struct unit_directory, model_name_kv)
 
 static struct device_attribute *const fw_ud_attrs[] = {
@@ -865,7 +845,6 @@
 
 	ne->guid = guid;
 	ne->guid_vendor_id = (guid >> 40) & 0xffffff;
-	ne->guid_vendor_oui = nodemgr_find_oui_name(ne->guid_vendor_id);
 	ne->csr = csr;
 
 	memcpy(&ne->device, &nodemgr_dev_template_ne,
@@ -885,9 +864,6 @@
 		goto fail_classdevreg;
 	get_device(&ne->device);
 
-	if (ne->guid_vendor_oui &&
-	    device_create_file(&ne->device, &dev_attr_ne_guid_vendor_oui))
-		goto fail_addoiu;
 	nodemgr_create_ne_dev_files(ne);
 
 	nodemgr_update_bus_options(ne);
@@ -898,8 +874,6 @@
 
 	return ne;
 
-fail_addoiu:
-	put_device(&ne->device);
 fail_classdevreg:
 	device_unregister(&ne->device);
 fail_devreg:
@@ -975,15 +949,10 @@
 		goto fail_classdevreg;
 	get_device(&ud->device);
 
-	if (ud->vendor_oui &&
-	    device_create_file(&ud->device, &dev_attr_ud_vendor_oui))
-		goto fail_addoui;
 	nodemgr_create_ud_dev_files(ud);
 
 	return;
 
-fail_addoui:
-	put_device(&ud->device);
 fail_classdevreg:
 	device_unregister(&ud->device);
 fail_devreg:
@@ -1020,9 +989,6 @@
 			if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
 				ud->vendor_id = kv->value.immediate;
 				ud->flags |= UNIT_DIRECTORY_VENDOR_ID;
-
-				if (ud->vendor_id)
-					ud->vendor_oui = nodemgr_find_oui_name(ud->vendor_id);
 			}
 			break;
 
@@ -1153,9 +1119,6 @@
 		switch (kv->key.id) {
 		case CSR1212_KV_ID_VENDOR:
 			ne->vendor_id = kv->value.immediate;
-
-			if (ne->vendor_id)
-				ne->vendor_oui = nodemgr_find_oui_name(ne->vendor_id);
 			break;
 
 		case CSR1212_KV_ID_NODE_CAPABILITIES:
@@ -1183,9 +1146,6 @@
 		last_key_id = kv->key.id;
 	}
 
-	if (ne->vendor_oui &&
-	    device_create_file(&ne->device, &dev_attr_ne_vendor_oui))
-		goto fail;
 	if (ne->vendor_name_kv &&
 	    device_create_file(&ne->device, &dev_attr_ne_vendor_name_kv))
 		goto fail;
@@ -1889,22 +1849,31 @@
 
 	error = class_register(&nodemgr_ne_class);
 	if (error)
-		return error;
-
+		goto fail_ne;
 	error = class_register(&nodemgr_ud_class);
-	if (error) {
-		class_unregister(&nodemgr_ne_class);
-		return error;
-	}
+	if (error)
+		goto fail_ud;
 	error = driver_register(&nodemgr_mid_layer_driver);
+	if (error)
+		goto fail_ml;
+	/* This driver is not used if nodemgr is off (disable_nodemgr=1). */
+	nodemgr_dev_template_host.driver = &nodemgr_mid_layer_driver;
+
 	hpsb_register_highlevel(&nodemgr_highlevel);
 	return 0;
+
+fail_ml:
+	class_unregister(&nodemgr_ud_class);
+fail_ud:
+	class_unregister(&nodemgr_ne_class);
+fail_ne:
+	return error;
 }
 
 void cleanup_ieee1394_nodemgr(void)
 {
 	hpsb_unregister_highlevel(&nodemgr_highlevel);
-
+	driver_unregister(&nodemgr_mid_layer_driver);
 	class_unregister(&nodemgr_ud_class);
 	class_unregister(&nodemgr_ne_class);
 }
diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h
index e25cbad..4147303 100644
--- a/drivers/ieee1394/nodemgr.h
+++ b/drivers/ieee1394/nodemgr.h
@@ -70,7 +70,6 @@
 
 	quadlet_t vendor_id;
 	struct csr1212_keyval *vendor_name_kv;
-	const char *vendor_oui;
 
 	quadlet_t model_id;
 	struct csr1212_keyval *model_name_kv;
@@ -93,7 +92,6 @@
 struct node_entry {
 	u64 guid;			/* GUID of this node */
 	u32 guid_vendor_id;		/* Top 24bits of guid */
-	const char *guid_vendor_oui;	/* OUI name of guid vendor id */
 
 	struct hpsb_host *host;		/* Host this node is attached to */
 	nodeid_t nodeid;		/* NodeID */
@@ -104,7 +102,6 @@
 	/* The following is read from the config rom */
 	u32 vendor_id;
 	struct csr1212_keyval *vendor_name_kv;
-	const char *vendor_oui;
 
 	u32 capabilities;
 
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 628130a..5729e41 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -3281,14 +3281,11 @@
 		PRINT(KERN_WARNING, "PCI resource length of 0x%llx too small!",
 		      (unsigned long long)pci_resource_len(dev, 0));
 
-	/* Seems PCMCIA handles this internally. Not sure why. Seems
-	 * pretty bogus to force a driver to special case this.  */
-#ifndef PCMCIA
-	if (!request_mem_region (ohci_base, OHCI1394_REGISTER_SIZE, OHCI1394_DRIVER_NAME))
+	if (!request_mem_region(ohci_base, OHCI1394_REGISTER_SIZE,
+				OHCI1394_DRIVER_NAME))
 		FAIL(-ENOMEM, "MMIO resource (0x%llx - 0x%llx) unavailable",
 			(unsigned long long)ohci_base,
 			(unsigned long long)ohci_base + OHCI1394_REGISTER_SIZE);
-#endif
 	ohci->init_state = OHCI_INIT_HAVE_MEM_REGION;
 
 	ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE);
@@ -3509,10 +3506,8 @@
 		iounmap(ohci->registers);
 
 	case OHCI_INIT_HAVE_MEM_REGION:
-#ifndef PCMCIA
 		release_mem_region(pci_resource_start(ohci->dev, 0),
 				   OHCI1394_REGISTER_SIZE);
-#endif
 
 #ifdef CONFIG_PPC_PMAC
 	/* On UniNorth, power down the cable and turn off the chip clock
@@ -3541,9 +3536,6 @@
 	int err;
 	struct ti_ohci *ohci = pci_get_drvdata(pdev);
 
-	printk(KERN_INFO "%s does not fully support suspend and resume yet\n",
-	       OHCI1394_DRIVER_NAME);
-
 	if (!ohci) {
 		printk(KERN_ERR "%s: tried to suspend nonexisting host\n",
 		       OHCI1394_DRIVER_NAME);
@@ -3630,15 +3622,14 @@
 	mdelay(50);
 	ohci_initialize(ohci);
 
+	hpsb_resume_host(ohci->host);
 	return 0;
 }
 #endif /* CONFIG_PM */
 
-#define PCI_CLASS_FIREWIRE_OHCI     ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
-
 static struct pci_device_id ohci1394_pci_tbl[] = {
 	{
-		.class = 	PCI_CLASS_FIREWIRE_OHCI,
+		.class = 	PCI_CLASS_SERIAL_FIREWIRE_OHCI,
 		.class_mask = 	PCI_ANY_ID,
 		.vendor =	PCI_ANY_ID,
 		.device =	PCI_ANY_ID,
diff --git a/drivers/ieee1394/oui.db b/drivers/ieee1394/oui.db
deleted file mode 100644
index 592c8a6..0000000
--- a/drivers/ieee1394/oui.db
+++ /dev/null
@@ -1,7048 +0,0 @@
-000000 XEROX CORPORATION
-000001 XEROX CORPORATION
-000002 XEROX CORPORATION
-000003 XEROX CORPORATION
-000004 XEROX CORPORATION
-000005 XEROX CORPORATION
-000006 XEROX CORPORATION
-000007 XEROX CORPORATION
-000008 XEROX CORPORATION
-000009 XEROX CORPORATION
-00000A OMRON TATEISI ELECTRONICS CO.
-00000B MATRIX CORPORATION
-00000C CISCO SYSTEMS, INC.
-00000D FIBRONICS LTD.
-00000E FUJITSU LIMITED
-00000F NEXT, INC.
-000010 SYTEK INC.
-000011 NORMEREL SYSTEMES
-000012 INFORMATION TECHNOLOGY LIMITED
-000013 CAMEX
-000014 NETRONIX
-000015 DATAPOINT CORPORATION
-000016 DU PONT PIXEL SYSTEMS     .
-000017 TEKELEC
-000018 WEBSTER COMPUTER CORPORATION
-000019 APPLIED DYNAMICS INTERNATIONAL
-00001A ADVANCED MICRO DEVICES
-00001B NOVELL INC.
-00001C BELL TECHNOLOGIES
-00001D CABLETRON SYSTEMS, INC.
-00001E TELSIST INDUSTRIA ELECTRONICA
-00001F Telco Systems, Inc.
-000020 DATAINDUSTRIER DIAB AB
-000021 SUREMAN COMP. & COMMUN. CORP.
-000022 VISUAL TECHNOLOGY INC.
-000023 ABB INDUSTRIAL SYSTEMS AB
-000024 CONNECT AS
-000025 RAMTEK CORP.
-000026 SHA-KEN CO., LTD.
-000027 JAPAN RADIO COMPANY
-000028 PRODIGY SYSTEMS CORPORATION
-000029 IMC NETWORKS CORP.
-00002A TRW - SEDD/INP
-00002B CRISP AUTOMATION, INC
-00002C AUTOTOTE LIMITED
-00002D CHROMATICS INC
-00002E SOCIETE EVIRA
-00002F TIMEPLEX INC.
-000030 VG LABORATORY SYSTEMS LTD
-000031 QPSX COMMUNICATIONS PTY LTD
-000032 Marconi plc
-000033 EGAN MACHINERY COMPANY
-000034 NETWORK RESOURCES CORPORATION
-000035 SPECTRAGRAPHICS CORPORATION
-000036 ATARI CORPORATION
-000037 OXFORD METRICS LIMITED
-000038 CSS LABS
-000039 TOSHIBA CORPORATION
-00003A CHYRON CORPORATION
-00003B i Controls, Inc.
-00003C AUSPEX SYSTEMS INC.
-00003D UNISYS
-00003E SIMPACT
-00003F SYNTREX, INC.
-000040 APPLICON, INC.
-000041 ICE CORPORATION
-000042 METIER MANAGEMENT SYSTEMS LTD.
-000043 MICRO TECHNOLOGY
-000044 CASTELLE CORPORATION
-000045 FORD AEROSPACE & COMM. CORP.
-000046 OLIVETTI NORTH AMERICA
-000047 NICOLET INSTRUMENTS CORP.
-000048 SEIKO EPSON CORPORATION
-000049 APRICOT COMPUTERS, LTD
-00004A ADC CODENOLL TECHNOLOGY CORP.
-00004B ICL DATA OY
-00004C NEC CORPORATION
-00004D DCI CORPORATION
-00004E AMPEX CORPORATION
-00004F LOGICRAFT, INC.
-000050 RADISYS CORPORATION
-000051 HOB ELECTRONIC GMBH & CO. KG
-000052 Intrusion.com, Inc.
-000053 COMPUCORP
-000054 MODICON, INC.
-000055 COMMISSARIAT A L`ENERGIE ATOM.
-000056 DR. B. STRUCK
-000057 SCITEX CORPORATION LTD.
-000058 RACORE COMPUTER PRODUCTS INC.
-000059 HELLIGE GMBH
-00005A SysKonnect GmbH
-00005B ELTEC ELEKTRONIK AG
-00005C TELEMATICS INTERNATIONAL INC.
-00005D CS TELECOM
-00005E USC INFORMATION SCIENCES INST
-00005F SUMITOMO ELECTRIC IND., LTD.
-000060 KONTRON ELEKTRONIK GMBH
-000061 GATEWAY COMMUNICATIONS
-000062 BULL HN INFORMATION SYSTEMS
-000063 DR.ING.SEUFERT GMBH
-000064 YOKOGAWA DIGITAL COMPUTER CORP
-000065 NETWORK ASSOCIATES, INC.
-000066 TALARIS SYSTEMS, INC.
-000067 SOFT * RITE, INC.
-000068 ROSEMOUNT CONTROLS
-000069 CONCORD COMMUNICATIONS INC
-00006A COMPUTER CONSOLES INC.
-00006B SILICON GRAPHICS INC./MIPS
-00006D CRAY COMMUNICATIONS, LTD.
-00006E ARTISOFT, INC.
-00006F Madge Ltd.
-000070 HCL LIMITED
-000071 ADRA SYSTEMS INC.
-000072 MINIWARE TECHNOLOGY
-000073 SIECOR CORPORATION
-000074 RICOH COMPANY LTD.
-000075 Nortel Networks
-000076 ABEKAS VIDEO SYSTEM
-000077 INTERPHASE CORPORATION
-000078 LABTAM LIMITED
-000079 NETWORTH INCORPORATED
-00007A DANA COMPUTER INC.
-00007B RESEARCH MACHINES
-00007C AMPERE INCORPORATED
-00007D SUN MICROSYSTEMS, INC.
-00007E CLUSTRIX CORPORATION
-00007F LINOTYPE-HELL AG
-000080 CRAY COMMUNICATIONS A/S
-000081 BAY NETWORKS
-000082 LECTRA SYSTEMES SA
-000083 TADPOLE TECHNOLOGY PLC
-000084 SUPERNET
-000085 CANON INC.
-000086 MEGAHERTZ CORPORATION
-000087 HITACHI, LTD.
-000088 COMPUTER NETWORK TECH. CORP.
-000089 CAYMAN SYSTEMS INC.
-00008A DATAHOUSE INFORMATION SYSTEMS
-00008B INFOTRON
-00008C Alloy Computer Products (Australia) Pty Ltd
-00008D VERDIX CORPORATION
-00008E SOLBOURNE COMPUTER, INC.
-00008F RAYTHEON COMPANY
-000090 MICROCOM
-000091 ANRITSU CORPORATION
-000092 COGENT DATA TECHNOLOGIES
-000093 PROTEON INC.
-000094 ASANTE TECHNOLOGIES
-000095 SONY TEKTRONIX CORP.
-000096 MARCONI ELECTRONICS LTD.
-000097 EPOCH SYSTEMS
-000098 CROSSCOMM CORPORATION
-000099 MTX, INC.
-00009A RC COMPUTER A/S
-00009B INFORMATION INTERNATIONAL, INC
-00009C ROLM MIL-SPEC COMPUTERS
-00009D LOCUS COMPUTING CORPORATION
-00009E MARLI S.A.
-00009F AMERISTAR TECHNOLOGIES INC.
-0000A0 TOKYO SANYO ELECTRIC CO. LTD.
-0000A1 MARQUETTE ELECTRIC CO.
-0000A2 BAY NETWORKS
-0000A3 NETWORK APPLICATION TECHNOLOGY
-0000A4 ACORN COMPUTERS LIMITED
-0000A5 COMPATIBLE SYSTEMS CORP.
-0000A6 NETWORK GENERAL CORPORATION
-0000A7 NETWORK COMPUTING DEVICES INC.
-0000A8 STRATUS COMPUTER INC.
-0000A9 NETWORK SYSTEMS CORP.
-0000AA XEROX CORPORATION
-0000AB LOGIC MODELING CORPORATION
-0000AC CONWARE COMPUTER CONSULTING
-0000AD BRUKER INSTRUMENTS INC.
-0000AE DASSAULT ELECTRONIQUE
-0000AF NUCLEAR DATA INSTRUMENTATION
-0000B0 RND-RAD NETWORK DEVICES
-0000B1 ALPHA MICROSYSTEMS INC.
-0000B2 TELEVIDEO SYSTEMS, INC.
-0000B3 CIMLINC INCORPORATED
-0000B4 EDIMAX COMPUTER COMPANY
-0000B5 DATABILITY SOFTWARE SYS. INC.
-0000B6 MICRO-MATIC RESEARCH
-0000B7 DOVE COMPUTER CORPORATION
-0000B8 SEIKOSHA CO., LTD.
-0000B9 MCDONNELL DOUGLAS COMPUTER SYS
-0000BA SIIG, INC.
-0000BB TRI-DATA
-0000BC ALLEN-BRADLEY CO. INC.
-0000BD MITSUBISHI CABLE COMPANY
-0000BE THE NTI GROUP
-0000BF SYMMETRIC COMPUTER SYSTEMS
-0000C0 WESTERN DIGITAL CORPORATION
-0000C1 Madge Ltd.
-0000C2 INFORMATION PRESENTATION TECH.
-0000C3 HARRIS CORP COMPUTER SYS DIV
-0000C4 WATERS DIV. OF MILLIPORE
-0000C5 FARALLON COMPUTING/NETOPIA
-0000C6 EON SYSTEMS
-0000C7 ARIX CORPORATION
-0000C8 ALTOS COMPUTER SYSTEMS
-0000C9 EMULEX CORPORATION
-0000CA APPLITEK
-0000CB COMPU-SHACK ELECTRONIC GMBH
-0000CC DENSAN CO., LTD.
-0000CD Allied Telesyn Research Ltd.
-0000CE MEGADATA CORP.
-0000CF HAYES MICROCOMPUTER PRODUCTS
-0000D0 DEVELCON ELECTRONICS LTD.
-0000D1 ADAPTEC INCORPORATED
-0000D2 SBE, INC.
-0000D3 WANG LABORATORIES INC.
-0000D4 PURE DATA LTD.
-0000D5 MICROGNOSIS INTERNATIONAL
-0000D6 PUNCH LINE HOLDING
-0000D7 DARTMOUTH COLLEGE
-0000D8 NOVELL, INC.
-0000D9 NIPPON TELEGRAPH & TELEPHONE
-0000DA ATEX
-0000DB BRITISH TELECOMMUNICATIONS PLC
-0000DC HAYES MICROCOMPUTER PRODUCTS
-0000DD TCL INCORPORATED
-0000DE CETIA
-0000DF BELL & HOWELL PUB SYS DIV
-0000E0 QUADRAM CORP.
-0000E1 GRID SYSTEMS
-0000E2 ACER TECHNOLOGIES CORP.
-0000E3 INTEGRATED MICRO PRODUCTS LTD
-0000E4 IN2 GROUPE INTERTECHNIQUE
-0000E5 SIGMEX LTD.
-0000E6 APTOR PRODUITS DE COMM INDUST
-0000E7 STAR GATE TECHNOLOGIES
-0000E8 ACCTON TECHNOLOGY CORP.
-0000E9 ISICAD, INC.
-0000EA UPNOD AB
-0000EB MATSUSHITA COMM. IND. CO. LTD.
-0000EC MICROPROCESS
-0000ED APRIL
-0000EE NETWORK DESIGNERS, LTD.
-0000EF KTI
-0000F0 SAMSUNG ELECTRONICS CO., LTD.
-0000F1 MAGNA COMPUTER CORPORATION
-0000F2 SPIDER COMMUNICATIONS
-0000F3 GANDALF DATA LIMITED
-0000F4 ALLIED TELESYN INTERNATIONAL
-0000F5 DIAMOND SALES LIMITED
-0000F6 APPLIED MICROSYSTEMS CORP.
-0000F7 YOUTH KEEP ENTERPRISE CO LTD
-0000F8 DIGITAL EQUIPMENT CORPORATION
-0000F9 QUOTRON SYSTEMS INC.
-0000FA MICROSAGE COMPUTER SYSTEMS INC
-0000FB RECHNER ZUR KOMMUNIKATION
-0000FC MEIKO
-0000FD HIGH LEVEL HARDWARE
-0000FE ANNAPOLIS MICRO SYSTEMS
-0000FF CAMTEC ELECTRONICS LTD.
-000100 EQUIP'TRANS
-000102 3COM CORPORATION
-000103 3COM CORPORATION
-000104 DVICO Co., Ltd.
-000105 BECKHOFF GmbH
-000106 Tews Datentechnik GmbH
-000107 Leiser GmbH
-000108 AVLAB Technology, Inc.
-000109 Nagano Japan Radio Co., Ltd.
-00010A CIS TECHNOLOGY INC.
-00010B Space CyberLink, Inc.
-00010C System Talks Inc.
-00010D CORECO, INC.
-00010E Bri-Link Technologies Co., Ltd
-00010F Nishan Systems, Inc.
-000110 Gotham Networks
-000111 iDigm Inc.
-000112 Shark Multimedia Inc.
-000113 OLYMPUS CORPORATION
-000114 KANDA TSUSHIN KOGYO CO., LTD.
-000115 EXTRATECH CORPORATION
-000116 Netspect Technologies, Inc.
-000117 CANAL +
-000118 EZ Digital Co., Ltd.
-000119 Action Controls Pty. Ltd.
-00011A EEH DataLink GmbH
-00011B Unizone Technologies, Inc.
-00011C Universal Talkware Corporation
-00011D Centillium Communications
-00011E Precidia Technologies, Inc.
-00011F RC Networks, Inc.
-000120 OSCILLOQUARTZ S.A.
-000121 RapidStream Inc.
-000122 Trend Communications, Ltd.
-000123 DIGITAL ELECTRONICS CORP.
-000124 Acer Incorporated
-000125 YAESU MUSEN CO., LTD.
-000126 PAC Labs
-000127 The OPEN Group Limited
-000128 EnjoyWeb, Inc.
-000129 DFI Inc.
-00012A Telematica Sistems Inteligente
-00012B TELENET Co., Ltd.
-00012C Aravox Technologies, Inc.
-00012D Komodo Technology
-00012E PC Partner Ltd.
-00012F Twinhead International Corp
-000130 Extreme Networks
-000131 Detection Systems, Inc.
-000132 Dranetz - BMI
-000133 KYOWA Electronic Instruments C
-000134 SIG Positec Systems AG
-000135 KDC Corp.
-000136 CyberTAN Technology, Inc.
-000137 IT Farm Corporation
-000138 XAVi Technologies Corp.
-000139 Point Multimedia Systems
-00013A SHELCAD COMMUNICATIONS, LTD.
-00013B BNA SYSTEMS
-00013C TIW SYSTEMS
-00013D RiscStation Ltd.
-00013E Ascom Tateco AB
-00013F Neighbor World Co., Ltd.
-000140 Sendtek Corporation
-000141 CABLE PRINT
-000142 Cisco Systems, Inc.
-000143 Cisco Systems, Inc.
-000144 Cereva Networks, Inc.
-000145 WINSYSTEMS, INC.
-000146 Tesco Controls, Inc.
-000147 Zhone Technologies
-000148 X-traWeb Inc.
-000149 T.D.T. Transfer Data Test GmbH
-00014A SONY COMPUTER SCIENCE LABS., I
-00014B Ennovate Networks, Inc.
-00014C Berkeley Process Control
-00014D Shin Kin Enterprises Co., Ltd
-00014E WIN Enterprises, Inc.
-00014F LUMINOUS Networks, Inc.
-000150 GILAT COMMUNICATIONS, LTD.
-000151 Ensemble Communications
-000152 CHROMATEK INC.
-000153 ARCHTEK TELECOM CORPORATION
-000154 G3M Corporation
-000155 Promise Technology, Inc.
-000156 FIREWIREDIRECT.COM, INC.
-000157 SYSWAVE CO., LTD
-000158 Electro Industries/Gauge Tech
-000159 S1 Corporation
-00015A Digital Video Broadcasting
-00015B ITALTEL S.p.A/RF-UP-I
-00015C CADANT INC.
-00015D Sun Microsystems, Inc
-00015E BEST TECHNOLOGY CO., LTD.
-00015F DIGITAL DESIGN GmbH
-000160 ELMEX Co., LTD.
-000161 Meta Machine Technology
-000162 Cygnet Technologies, Inc.
-000163 Cisco Systems, Inc.
-000164 Cisco Systems, Inc.
-000165 AirSwitch Corporation
-000166 TC GROUP A/S
-000167 HIOKI E.E. CORPORATION
-000168 VITANA CORPORATION
-000169 Celestix Networks Pte Ltd.
-00016A ALITEC
-00016B LightChip, Inc.
-00016C FOXCONN
-00016D CarrierComm Inc.
-00016E Conklin Corporation
-00016F HAITAI ELECTRONICS CO., LTD.
-000170 ESE Embedded System Engineer'g
-000171 Allied Data Technologies
-000172 TechnoLand Co., LTD.
-000173 JNI Corporation
-000174 CyberOptics Corporation
-000175 Radiant Communications Corp.
-000176 Orient Silver Enterprises
-000177 EDSL
-000178 MARGI Systems, Inc.
-000179 WIRELESS TECHNOLOGY, INC.
-00017A Chengdu Maipu Electric Industrial Co., Ltd.
-00017B Heidelberger Druckmaschinen AG
-00017C AG-E GmbH
-00017D ThermoQuest
-00017E ADTEK System Science Co., Ltd.
-00017F Experience Music Project
-000180 AOpen, Inc.
-000181 Nortel Networks
-000182 DICA TECHNOLOGIES AG
-000183 ANITE TELECOMS
-000184 SIEB & MEYER AG
-000185 Aloka Co., Ltd.
-000186 DISCH GmbH
-000187 i2SE GmbH
-000188 LXCO Technologies ag
-000189 Refraction Technology, Inc.
-00018A ROI COMPUTER AG
-00018B NetLinks Co., Ltd.
-00018C Mega Vision
-00018D AudeSi Technologies
-00018E Logitec Corporation
-00018F Kenetec, Inc.
-000190 SMK-M
-000191 SYRED Data Systems
-000192 Texas Digital Systems
-000193 Hanbyul Telecom Co., Ltd.
-000194 Capital Equipment Corporation
-000195 Sena Technologies, Inc.
-000196 Cisco Systems, Inc.
-000197 Cisco Systems, Inc.
-000198 Darim Vision
-000199 HeiSei Electronics
-00019A LEUNIG GmbH
-00019B Kyoto Microcomputer Co., Ltd.
-00019C JDS Uniphase Inc.
-00019D E-Control Systems, Inc.
-00019E ESS Technology, Inc.
-00019F Phonex Broadband
-0001A0 Infinilink Corporation
-0001A1 Mag-Tek, Inc.
-0001A2 Logical Co., Ltd.
-0001A3 GENESYS LOGIC, INC.
-0001A4 Microlink Corporation
-0001A5 Nextcomm, Inc.
-0001A6 Scientific-Atlanta Arcodan A/S
-0001A7 UNEX TECHNOLOGY CORPORATION
-0001A8 Welltech Computer Co., Ltd.
-0001A9 BMW AG
-0001AA Airspan Communications, Ltd.
-0001AB Main Street Networks
-0001AC Sitara Networks, Inc.
-0001AD Coach Master International  d.b.a. CMI Worldwide, Inc.
-0001AE Trex Enterprises
-0001AF Motorola Computer Group
-0001B0 Fulltek Technology Co., Ltd.
-0001B1 General Bandwidth
-0001B2 Digital Processing Systems, Inc.
-0001B3 Precision Electronic Manufacturing
-0001B4 Wayport, Inc.
-0001B5 Turin Networks, Inc.
-0001B6 SAEJIN T&M Co., Ltd.
-0001B7 Centos, Inc.
-0001B8 Netsensity, Inc.
-0001B9 SKF Condition Monitoring
-0001BA IC-Net, Inc.
-0001BB Frequentis
-0001BC Brains Corporation
-0001BD Peterson Electro-Musical Products, Inc.
-0001BE Gigalink Co., Ltd.
-0001BF Teleforce Co., Ltd.
-0001C0 CompuLab, Ltd.
-0001C1 Vitesse Semiconductor Corporation
-0001C2 ARK Research Corp.
-0001C3 Acromag, Inc.
-0001C4 NeoWave, Inc.
-0001C5 Simpler Networks
-0001C6 Quarry Technologies
-0001C7 Cisco Systems, Inc.
-0001C8 THOMAS CONRAD CORP.
-0001C8 CONRAD CORP.
-0001C9 Cisco Systems, Inc.
-0001CA Geocast Network Systems, Inc.
-0001CB NetGame, Ltd.
-0001CC Japan Total Design Communication Co., Ltd.
-0001CD ARtem
-0001CE Custom Micro Products, Ltd.
-0001CF Alpha Data Parallel Systems, Ltd.
-0001D0 VitalPoint, Inc.
-0001D1 CoNet Communications, Inc.
-0001D2 MacPower Peripherals, Ltd.
-0001D3 PAXCOMM, Inc.
-0001D4 Leisure Time, Inc.
-0001D5 HAEDONG INFO & COMM CO., LTD
-0001D6 MAN Roland Druckmaschinen AG
-0001D7 F5 Networks, Inc.
-0001D8 Teltronics, Inc.
-0001D9 Sigma, Inc.
-0001DA WINCOMM Corporation
-0001DB Freecom Technologies GmbH
-0001DC Activetelco
-0001DD Avail Networks
-0001DE Trango Systems, Inc.
-0001DF ISDN Communications, Ltd.
-0001E0 Fast Systems, Inc.
-0001E1 Kinpo Electronics, Inc.
-0001E2 Ando Electric Corporation
-0001E3 Siemens AG
-0001E4 Sitera, Inc.
-0001E5 Supernet, Inc.
-0001E6 Hewlett-Packard Company
-0001E7 Hewlett-Packard Company
-0001E8 Force10 Networks, Inc.
-0001E9 Litton Marine Systems B.V.
-0001EA Cirilium Corp.
-0001EB C-COM Corporation
-0001EC Ericsson Group
-0001ED SETA Corp.
-0001EE Comtrol Europe, Ltd.
-0001EF Camtel Technology Corp.
-0001F0 Tridium, Inc.
-0001F1 Innovative Concepts, Inc.
-0001F2 Mark of the Unicorn, Inc.
-0001F3 QPS, Inc.
-0001F4 Enterasys Networks
-0001F5 ERIM S.A.
-0001F6 Association of Musical Electronics Industry
-0001F7 Image Display Systems, Inc.
-0001F8 Adherent Systems, Ltd.
-0001F9 TeraGlobal Communications Corp.
-0001FA HOROSCAS
-0001FB DoTop Technology, Inc.
-0001FC Keyence Corporation
-0001FD Digital Voice Systems, Inc.
-0001FE DIGITAL EQUIPMENT CORPORATION
-0001FF Data Direct Networks, Inc.
-000200 Net & Sys Co., Ltd.
-000201 IFM Electronic gmbh
-000202 Amino Communications, Ltd.
-000203 Woonsang Telecom, Inc.
-000204 Bodmann Industries Elektronik GmbH
-000205 Hitachi Denshi, Ltd.
-000206 Telital R&D Denmark A/S
-000207 VisionGlobal Network Corp.
-000208 Unify Networks, Inc.
-000209 Shenzhen SED Information Technology Co., Ltd.
-00020A Gefran Spa
-00020B Native Networks, Inc.
-00020C Metro-Optix
-00020D Micronpc.com
-00020E Laurel Networks, Inc.
-00020F AATR
-000210 Fenecom
-000211 Nature Worldwide Technology Corp.
-000212 SierraCom
-000213 S.D.E.L.
-000214 DTVRO
-000215 Cotas Computer Technology A/B
-000216 Cisco Systems, Inc.
-000217 Cisco Systems, Inc.
-000218 Advanced Scientific Corp
-000219 Paralon Technologies
-00021A Zuma Networks
-00021B Kollmorgen-Servotronix
-00021C Network Elements, Inc.
-00021D Data General Communication Ltd.
-00021E SIMTEL S.R.L.
-00021F Aculab PLC
-000220 Canon Aptex, Inc.
-000221 DSP Application, Ltd.
-000222 Chromisys, Inc.
-000223 ClickTV
-000224 Lantern Communications, Inc.
-000225 Certus Technology, Inc.
-000226 XESystems, Inc.
-000227 ESD GmbH
-000228 Necsom, Ltd.
-000229 Adtec Corporation
-00022A Asound Electronic
-00022B Tamura Electric Works, Ltd.
-00022C ABB Bomem, Inc.
-00022D Agere Systems
-00022E TEAC Corp. R& D
-00022F P-Cube, Ltd.
-000230 Intersoft Electronics
-000231 Ingersoll-Rand
-000232 Avision, Inc.
-000233 Mantra Communications, Inc.
-000234 Imperial Technology, Inc.
-000235 Paragon Networks International
-000236 INIT GmbH
-000237 Cosmo Research Corp.
-000238 Serome Technology, Inc.
-000239 Visicom
-00023A ZSK Stickmaschinen GmbH
-00023B Redback Networks
-00023C Creative Technology, Ltd.
-00023D NuSpeed, Inc.
-00023E Selta Telematica S.p.a
-00023F Compal Electronics, Inc.
-000240 Seedek Co., Ltd.
-000241 Amer.com
-000242 Videoframe Systems
-000243 Raysis Co., Ltd.
-000244 SURECOM Technology Co.
-000245 Lampus Co, Ltd.
-000246 All-Win Tech Co., Ltd.
-000247 Great Dragon Information Technology (Group) Co., Ltd.
-000248 Pilz GmbH & Co.
-000249 Aviv Infocom Co, Ltd.
-00024A Cisco Systems, Inc.
-00024B Cisco Systems, Inc.
-00024C SiByte, Inc.
-00024D Mannesman Dematic Colby Pty. Ltd.
-00024E Datacard Group
-00024F IPM Datacom S.R.L.
-000250 Geyser Networks, Inc.
-000251 Soma Networks
-000252 Carrier Corporation
-000253 Televideo, Inc.
-000254 WorldGate
-000255 IBM Corporation
-000256 Alpha Processor, Inc.
-000257 Microcom Corp.
-000258 Flying Packets Communications
-000259 Tsann Kuen China (Shanghai)Enterprise Co., Ltd. IT Group
-00025A Catena Networks
-00025B Cambridge Silicon Radio
-00025C SCI Systems (Kunshan) Co., Ltd.
-00025D Calix Networks
-00025E High Technology Ltd
-00025F Nortel Networks
-000260 Accordion Networks, Inc.
-000261 i3 Micro Technology AB
-000262 Soyo Group Soyo Com Tech Co., Ltd
-000263 UPS Manufacturing SRL
-000264 AudioRamp.com
-000265 Virditech Co. Ltd.
-000266 Thermalogic Corporation
-000267 NODE RUNNER, INC.
-000268 Harris Government Communications
-000269 Nadatel Co., Ltd
-00026A Cocess Telecom Co., Ltd.
-00026B BCM Computers Co., Ltd.
-00026C Philips CFT
-00026D Adept Telecom
-00026E NeGeN Access, Inc.
-00026F Senao International Co., Ltd.
-000270 Crewave Co., Ltd.
-000271 Vpacket Communications
-000272 CC&C Technologies, Inc.
-000273 Coriolis Networks
-000274 Tommy Technologies Corp.
-000275 SMART Technologies, Inc.
-000276 Primax Electronics Ltd.
-000277 Cash Systemes Industrie
-000278 Samsung Electro-Mechanics Co., Ltd.
-000279 Control Applications, Ltd.
-00027A IOI Technology Corporation
-00027B Amplify Net, Inc.
-00027C Trilithic, Inc.
-00027D Cisco Systems, Inc.
-00027E Cisco Systems, Inc.
-00027F ask-technologies.com
-000280 Mu Net, Inc.
-000281 Madge Ltd.
-000282 ViaClix, Inc.
-000283 Spectrum Controls, Inc.
-000284 Alstom T&D P&C
-000285 Riverstone Networks
-000286 Occam Networks
-000287 Adapcom
-000288 GLOBAL VILLAGE COMMUNICATION
-000289 DNE Technologies
-00028A Ambit Microsystems Corporation
-00028B VDSL Systems OY
-00028C Micrel-Synergy Semiconductor
-00028D Movita Technologies, Inc.
-00028E Rapid 5 Networks, Inc.
-00028F Globetek, Inc.
-000290 Woorigisool, Inc.
-000291 Open Network Co., Ltd.
-000292 Logic Innovations, Inc.
-000293 Solid Data Systems
-000294 Tokyo Sokushin Co., Ltd.
-000295 IP.Access Limited
-000296 Lectron Co,. Ltd.
-000297 C-COR.net
-000298 Broadframe Corporation
-000299 Apex, Inc.
-00029A Storage Apps
-00029B Kreatel Communications AB
-00029C 3COM
-00029D Merix Corp.
-00029E Information Equipment Co., Ltd.
-00029F L-3 Communication Aviation Recorders
-0002A0 Flatstack Ltd.
-0002A1 World Wide Packets
-0002A2 Hilscher GmbH
-0002A3 ABB Power Automation
-0002A4 AddPac Technology Co., Ltd.
-0002A5 Compaq Computer Corporation
-0002A6 Effinet Systems Co., Ltd.
-0002A7 Vivace Networks
-0002A8 Air Link Technology
-0002A9 RACOM, s.r.o.
-0002AA PLcom Co., Ltd.
-0002AB CTC Union Technologies Co., Ltd.
-0002AC 3PAR data
-0002AD Pentax Corpotation
-0002AE Scannex Electronics Ltd.
-0002AF TeleCruz Technology, Inc.
-0002B0 Hokubu Communication & Industrial Co., Ltd.
-0002B1 Anritsu, Ltd.
-0002B2 Cablevision
-0002B3 Intel Corporation
-0002B4 DAPHNE
-0002B5 Avnet, Inc.
-0002B6 Acrosser Technology Co., Ltd.
-0002B7 Watanabe Electric Industry Co., Ltd.
-0002B8 WHI KONSULT AB
-0002B9 Cisco Systems, Inc.
-0002BA Cisco Systems, Inc.
-0002BB Continuous Computing
-0002BC LVL 7 Systems, Inc.
-0002BD Bionet Co., Ltd.
-0002BE Totsu Engineering, Inc.
-0002BF dotRocket, Inc.
-0002C0 Bencent Tzeng Industry Co., Ltd.
-0002C1 Innovative Electronic Designs, Inc.
-0002C2 Net Vision Telecom
-0002C3 Arelnet Ltd.
-0002C4 Vector International BUBA
-0002C5 Evertz Microsystems Ltd.
-0002C6 Data Track Technology PLC
-0002C7 ALPS ELECTRIC Co., Ltd.
-0002C8 Technocom Communications Technology (pte) Ltd
-0002C9 Mellanox Technologies
-0002CA EndPoints, Inc.
-0002CB TriState Ltd.
-0002CC M.C.C.I
-0002CD TeleDream, Inc.
-0002CE FoxJet, Inc.
-0002CF ZyGate Communications, Inc.
-0002D0 Comdial Corporation
-0002D1 Vivotek, Inc.
-0002D2 Workstation AG
-0002D3 NetBotz, Inc.
-0002D4 PDA Peripherals, Inc.
-0002D5 ACR
-0002D6 NICE Systems
-0002D7 EMPEG Ltd
-0002D8 BRECIS Communications Corporation
-0002D9 Reliable Controls
-0002DA ExiO Communications, Inc.
-0002DB NETSEC
-0002DC Fujitsu General Limited
-0002DD Bromax Communications, Ltd.
-0002DE Astrodesign, Inc.
-0002DF Net Com Systems, Inc.
-0002E0 ETAS GmbH
-0002E1 Integrated Network Corporation
-0002E2 NDC Infared Engineering
-0002E3 LITE-ON Communications, Inc.
-0002E4 JC HYUN Systems, Inc.
-0002E5 Timeware Ltd.
-0002E6 Gould Instrument Systems, Inc.
-0002E7 CAB GmbH & Co KG
-0002E8 E.D.&A.
-0002E9 CS Systemes De Securite - C3S
-0002EA Videonics, Inc.
-0002EB Pico Communications
-0002EC Maschoff Design Engineering
-0002ED DXO Telecom Co., Ltd.
-0002EE Nokia Danmark A/S
-0002EF CCC Network Systems Group Ltd.
-0002F0 AME Optimedia Technology Co., Ltd.
-0002F1 Pinetron Co., Ltd.
-0002F2 eDevice, Inc.
-0002F3 Media Serve Co., Ltd.
-0002F4 PCTEL, Inc.
-0002F5 VIVE Synergies, Inc.
-0002F6 Equipe Communications
-0002F7 ARM
-0002F8 SEAKR Engineering, Inc.
-0002F9 Mimos Semiconductor SDN BHD
-0002FA DX Antenna Co., Ltd.
-0002FB Baumuller Aulugen-Systemtechnik GmbH
-0002FC Cisco Systems, Inc.
-0002FD Cisco Systems, Inc.
-0002FE Viditec, Inc.
-0002FF Handan BroadInfoCom
-000300 NetContinuum, Inc.
-000301 Avantas Networks Corporation
-000302 Oasys Telecom, Inc.
-000303 JAMA Electronics Co., Ltd.
-000304 Pacific Broadband Communications
-000305 Smart Network Devices GmbH
-000306 Fusion In Tech Co., Ltd.
-000307 Secure Works, Inc.
-000308 AM Communications, Inc.
-000309 Texcel Technology PLC
-00030A Argus Technologies
-00030B Hunter Technology, Inc.
-00030C Telesoft Technologies Ltd.
-00030D Uniwill Computer Corp.
-00030E Core Communications Co., Ltd.
-00030F Digital China (Shanghai) Networks Ltd.
-000310 Link Evolution Corp.
-000311 Micro Technology Co., Ltd.
-000312 TR-Systemtechnik GmbH
-000313 Access Media SPA
-000314 Teleware Network Systems
-000315 Cidco Incorporated
-000316 Nobell Communications, Inc.
-000317 Merlin Systems, Inc.
-000318 Cyras Systems, Inc.
-000319 Infineon AG
-00031A Beijing Broad Telecom Ltd., China
-00031B Cellvision Systems, Inc.
-00031C Svenska Hardvarufabriken AB
-00031D Taiwan Commate Computer, Inc.
-00031E Optranet, Inc.
-00031F Condev Ltd.
-000320 Xpeed, Inc.
-000321 Reco Research Co., Ltd.
-000322 IDIS Co., Ltd.
-000323 Cornet Technology, Inc.
-000324 SANYO Multimedia Tottori Co., Ltd.
-000325 Arima Computer Corp.
-000326 Iwasaki Information Systems Co., Ltd.
-000327 ACT'L
-000328 Mace Group, Inc.
-000329 F3, Inc.
-00032A UniData Communication Systems, Inc.
-00032B GAI Datenfunksysteme GmbH
-00032C ABB Industrie AG
-00032D IBASE Technology, Inc.
-00032E Scope Information Management, Ltd.
-00032F Global Sun Technology, Inc.
-000330 Imagenics, Co., Ltd.
-000331 Cisco Systems, Inc.
-000332 Cisco Systems, Inc.
-000333 Digitel Co., Ltd.
-000334 Newport Electronics
-000335 Mirae Technology
-000336 Zetes Technologies
-000337 Vaone, Inc.
-000338 Oak Technology
-000339 Eurologic Systems, Ltd.
-00033A Silicon Wave, Inc.
-00033B TAMI Tech Co., Ltd.
-00033C Daiden Co., Ltd.
-00033D ILSHin Lab
-00033E Tateyama System Laboratory Co., Ltd.
-00033F BigBand Networks, Ltd.
-000340 Floware Wireless Systems, Ltd.
-000341 Axon Digital Design
-000342 Nortel Networks
-000343 Martin Professional A/S
-000344 Tietech.Co., Ltd.
-000345 Routrek Networks Corporation
-000346 Hitachi Kokusai Electric, Inc.
-000347 Intel Corporation
-000348 Norscan Instruments, Ltd.
-000349 Vidicode Datacommunicatie B.V.
-00034A RIAS Corporation
-00034B Nortel Networks
-00034C Shanghai DigiVision Technology Co., Ltd.
-00034D Chiaro Networks, Ltd.
-00034E Pos Data Company, Ltd.
-00034F Sur-Gard Security
-000350 BTICINO SPA
-000351 Diebold, Inc.
-000352 Colubris Networks
-000353 Mitac, Inc.
-000354 Fiber Logic Communications
-000355 TeraBeam Internet Systems
-000356 Wincor Nixdorf GmbH & Co KG
-000357 Intervoice-Brite, Inc.
-000358 iCable System Co., Ltd.
-000359 DigitalSis
-00035A Photron Limited
-00035B BridgeWave Communications
-00035C Saint Song Corp.
-00035D Bosung Hi-Net Co., Ltd.
-00035E Metropolitan Area Networks, Inc.
-00035F Prueftechnik Condition Monitoring GmbH & Co. KG
-000360 PAC Interactive Technology, Inc.
-000361 Widcomm, Inc.
-000362 Vodtel Communications, Inc.
-000363 Miraesys Co., Ltd.
-000364 Scenix Semiconductor, Inc.
-000365 Kira Information & Communications, Ltd.
-000366 ASM Pacific Technology
-000367 Jasmine Networks, Inc.
-000368 Embedone Co., Ltd.
-000369 Nippon Antenna Co., Ltd.
-00036A Mainnet, Ltd.
-00036B Cisco Systems, Inc.
-00036C Cisco Systems, Inc.
-00036D Runtop, Inc.
-00036E Nicon Systems (Pty) Limited
-00036F Telsey SPA
-000370 NXTV, Inc.
-000371 Acomz Networks Corp.
-000372 ULAN
-000373 Aselsan A.S
-000374 Hunter Watertech
-000375 NetMedia, Inc.
-000376 Graphtec Technology, Inc.
-000377 Gigabit Wireless
-000378 HUMAX Co., Ltd.
-000379 Proscend Communications, Inc.
-00037A Taiyo Yuden Co., Ltd.
-00037B IDEC IZUMI Corporation
-00037C Coax Media
-00037D Stellcom
-00037E PORTech Communications, Inc.
-00037F Atheros Communications, Inc.
-000380 SSH Communications Security Corp.
-000381 Ingenico International
-000382 A-One Co., Ltd.
-000383 Metera Networks, Inc.
-000384 AETA
-000385 Actelis Networks, Inc.
-000386 Ho Net, Inc.
-000387 Blaze Network Products
-000388 Fastfame Technology Co., Ltd.
-000389 Plantronics
-00038A America Online, Inc.
-00038B PLUS-ONE I&T, Inc.
-00038C Total Impact
-00038D PCS Revenue Control Systems, Inc.
-00038E Atoga Systems, Inc.
-00038F Weinschel Corporation
-000390 Digital Video Communications, Inc.
-000392 Hyundai Teletek Co., Ltd.
-000393 Apple Computer, Inc.
-000394 Connect One
-000395 California Amplifier
-000396 EZ Cast Co., Ltd.
-000397 Watchfront Electronics
-000398 WISI
-000399 Dongju Informations & Communications Co., Ltd.
-00039A nSine, Ltd.
-00039B NetChip Technology, Inc.
-00039C OptiMight Communications, Inc.
-00039D BENQ CORPORATION
-00039E Tera System Co., Ltd.
-00039F Cisco Systems, Inc.
-0003A0 Cisco Systems, Inc.
-0003A1 HIPER Information & Communication, Inc.
-0003A2 Catapult Communications
-0003A3 MAVIX, Ltd.
-0003A4 Data Storage and Information Management
-0003A5 Medea Corporation
-0003A7 Unixtar Technology, Inc.
-0003A8 IDOT Computers, Inc.
-0003A9 AXCENT Media AG
-0003AA Watlow
-0003AB Bridge Information Systems
-0003AC Fronius Schweissmaschinen
-0003AD Emerson Energy Systems AB
-0003AE Allied Advanced Manufacturing Pte, Ltd.
-0003AF Paragea Communications
-0003B0 Xsense Technology Corp.
-0003B1 Abbott Laboratories HPD
-0003B2 Radware
-0003B3 IA Link Systems Co., Ltd.
-0003B4 Macrotek International Corp.
-0003B5 Entra Technology Co.
-0003B6 QSI Corporation
-0003B7 ZACCESS Systems
-0003B8 NetKit Solutions, LLC
-0003B9 Hualong Telecom Co., Ltd.
-0003BA Sun Microsystems
-0003BB Signal Communications Limited
-0003BC COT GmbH
-0003BD OmniCluster Technologies, Inc.
-0003BE Netility
-0003BF Centerpoint Broadband Technologies, Inc.
-0003C0 RFTNC Co., Ltd.
-0003C1 Packet Dynamics Ltd
-0003C2 Solphone K.K.
-0003C3 Micronik Multimedia
-0003C4 Tomra Systems ASA
-0003C5 Mobotix AG
-0003C6 ICUE Systems, Inc.
-0003C7 hopf Elektronik GmbH
-0003C8 CML Emergency Services
-0003C9 TECOM Co., Ltd.
-0003CA MTS Systems Corp.
-0003CB Nippon Systems Development Co., Ltd.
-0003CC Momentum Computer, Inc.
-0003CD Clovertech, Inc.
-0003CE ETEN Technologies, Inc.
-0003CF Muxcom, Inc.
-0003D0 KOANKEISO Co., Ltd.
-0003D1 Takaya Corporation
-0003D2 Crossbeam Systems, Inc.
-0003D3 Internet Energy Systems, Inc.
-0003D4 Alloptic, Inc.
-0003D5 Advanced Communications Co., Ltd.
-0003D6 RADVision, Ltd.
-0003D7 NextNet Wireless, Inc.
-0003D8 iMPath Networks, Inc.
-0003D9 Secheron SA
-0003DA Takamisawa Cybernetics Co., Ltd.
-0003DB Apogee Electronics Corp.
-0003DC Lexar Media, Inc.
-0003DD Comark Corp.
-0003DE OTC Wireless
-0003DF Desana Systems
-0003E0 RadioFrame Networks, Inc.
-0003E1 Winmate Communication, Inc.
-0003E2 Comspace Corporation
-0003E3 Cisco Systems, Inc.
-0003E4 Cisco Systems, Inc.
-0003E5 Hermstedt SG
-0003E6 Entone Technologies, Inc.
-0003E7 Logostek Co. Ltd.
-0003E8 Wavelength Digital Limited
-0003E9 Akara Canada, Inc.
-0003EA Mega System Technologies, Inc.
-0003EB Atrica
-0003EC ICG Research, Inc.
-0003ED Shinkawa Electric Co., Ltd.
-0003EE MKNet Corporation
-0003EF Oneline AG
-0003F0 Redfern Broadband Networks
-0003F1 Cicada Semiconductor, Inc.
-0003F2 Seneca Networks
-0003F3 Dazzle Multimedia, Inc.
-0003F4 NetBurner
-0003F5 Chip2Chip
-0003F6 Allegro Networks, Inc.
-0003F7 Plast-Control GmbH
-0003F8 SanCastle Technologies, Inc.
-0003F9 Pleiades Communications, Inc.
-0003FA TiMetra Networks
-0003FB Toko Seiki Company, Ltd.
-0003FC Intertex Data AB
-0003FD Cisco Systems, Inc.
-0003FE Cisco Systems, Inc.
-0003FF Connectix
-000400 LEXMARK INTERNATIONAL, INC.
-000401 Osaki Electric Co., Ltd.
-000402 Nexsan Technologies, Ltd.
-000403 Nexsi Corporation
-000404 Makino Milling Machine Co., Ltd.
-000405 ACN Technologies
-000406 Fa. Metabox AG
-000407 Topcon Positioning Systems, Inc.
-000408 Sanko Electronics Co., Ltd.
-000409 Cratos Networks
-00040A Sage Systems
-00040B 3com Europe Ltd.
-00040C KANNO Work's Ltd.
-00040D Avaya, Inc.
-00040E AVM GmbH
-00040F Asus Network Technologies, Inc.
-000410 Spinnaker Networks, Inc.
-000411 Inkra Networks, Inc.
-000412 WaveSmith Networks, Inc.
-000413 SNOM Technology AG
-000414 Umezawa Musen Denki Co., Ltd.
-000415 Rasteme Systems Co., Ltd.
-000416 Parks S/A Comunicacoes Digitais
-000417 ELAU AG
-000418 Teltronic S.A.U.
-000419 Fibercycle Networks, Inc.
-00041A ines GmbH
-00041B Digital Interfaces Ltd.
-00041C ipDialog, Inc.
-00041D Corega of America
-00041E Shikoku Instrumentation Co., Ltd.
-00041F Sony Computer Entertainment, Inc.
-000420 Slim Devices, Inc.
-000421 Ocular Networks
-000422 Gordon Kapes, Inc.
-000423 Intel Corporation
-000424 TMC s.r.l.
-000425 Atmel Corporation
-000426 Autosys
-000427 Cisco Systems, Inc.
-000428 Cisco Systems, Inc.
-000429 Pixord Corporation
-00042A Wireless Networks, Inc.
-00042B IT Access Co., Ltd.
-00042C Minet, Inc.
-00042D Sarian Systems, Ltd.
-00042E Netous Technologies, Ltd.
-00042F International Communications Products, Inc.
-000430 Netgem
-000431 GlobalStreams, Inc.
-000432 Voyetra Turtle Beach, Inc.
-000433 Cyberboard A/S
-000434 Accelent Systems, Inc.
-000435 Comptek International, Inc.
-000436 ELANsat Technologies, Inc.
-000437 Powin Information Technology, Inc.
-000438 Nortel Networks
-000439 Rosco Entertainment Technology, Inc.
-00043A Intelligent Telecommunications, Inc.
-00043B Lava Computer Mfg., Inc.
-00043C SONOS Co., Ltd.
-00043D INDEL AG
-00043E Telencomm
-00043F Electronic Systems Technology, Inc.
-000440 cyberPIXIE, Inc.
-000441 Half Dome Systems, Inc.
-000442 NACT
-000443 Agilent Technologies, Inc.
-000444 Western Multiplex Corporation
-000445 LMS Skalar Instruments GmbH
-000446 CYZENTECH Co., Ltd.
-000447 Acrowave Systems Co., Ltd.
-000448 Polaroid Professional Imaging
-000449 Mapletree Networks
-00044A iPolicy Networks, Inc.
-00044B NVIDIA
-00044C JENOPTIK
-00044D Cisco Systems, Inc.
-00044E Cisco Systems, Inc.
-00044F Leukhardt Systemelektronik GmbH
-000450 DMD Computers SRL
-000451 Medrad, Inc.
-000452 RocketLogix, Inc.
-000453 YottaYotta, Inc.
-000454 Quadriga UK
-000455 ANTARA.net
-000456 PipingHot Networks
-000457 Universal Access Technology, Inc.
-000458 Fusion X Co., Ltd.
-000459 Veristar Corporation
-00045A The Linksys Group, Inc.
-00045B Techsan Electronics Co., Ltd.
-00045C Mobiwave Pte Ltd
-00045D BEKA Elektronik
-00045E PolyTrax Information Technology AG
-00045F Evalue Technology, Inc.
-000460 Knilink Technology, Inc.
-000461 EPOX Computer Co., Ltd.
-000462 DAKOS Data & Communication Co., Ltd.
-000463 Bosch Security Systems
-000464 Fantasma Networks, Inc.
-000465 i.s.t isdn-support technik GmbH
-000466 ARMITEL Co.
-000467 Wuhan Research Institute of MII
-000468 Vivity, Inc.
-000469 Innocom, Inc.
-00046A Navini Networks
-00046B Palm Wireless, Inc.
-00046C Cyber Technology Co., Ltd.
-00046D Cisco Systems, Inc.
-00046E Cisco Systems, Inc.
-00046F Digitel S/A Industria Eletronica
-000470 ipUnplugged AB
-000471 IPrad
-000472 Telelynx, Inc.
-000473 Photonex Corporation
-000474 LEGRAND
-000475 3 Com Corporation
-000476 3 Com Corporation
-000477 Scalant Systems, Inc.
-000478 G. Star Technology Corporation
-000479 Radius Co., Ltd.
-00047A AXXESSIT ASA
-00047B Schlumberger
-00047C Skidata AG
-00047D Pelco
-00047E NKF Electronics
-00047F Chr. Mayr GmbH & Co. KG
-000480 Foundry Networks, Inc.
-000481 Econolite Control Products, Inc.
-000482 Medialogic Corp.
-000483 Deltron Technology, Inc.
-000484 Amann GmbH
-000485 PicoLight
-000486 ITTC, University of Kansas
-000487 Cogency Semiconductor, Inc.
-000488 Eurotherm Action Incorporated.
-000489 YAFO Networks, Inc.
-00048A Temia Vertriebs GmbH
-00048B Poscon Corporation
-00048C Nayna Networks, Inc.
-00048D Tone Commander Systems, Inc.
-00048E Ohm Tech Labs, Inc.
-00048F TD Systems Corp.
-000490 Optical Access
-000491 Technovision, Inc.
-000492 Hive Internet, Ltd.
-000493 Tsinghua Unisplendour Co., Ltd.
-000494 Breezecom, Ltd.
-000495 Tejas Networks
-000496 Extreme Networks
-000497 MacroSystem Digital Video AG
-000499 Chino Corporation
-00049A Cisco Systems, Inc.
-00049B Cisco Systems, Inc.
-00049C Surgient Networks, Inc.
-00049D Ipanema Technologies
-00049E Wirelink Co., Ltd.
-00049F Metrowerks
-0004A0 Verity Instruments, Inc.
-0004A1 Pathway Connectivity
-0004A2 L.S.I. Japan Co., Ltd.
-0004A3 Microchip Technology, Inc.
-0004A4 NetEnabled, Inc.
-0004A5 Barco Projection Systems NV
-0004A6 SAF Tehnika Ltd.
-0004A7 FabiaTech Corporation
-0004A8 Broadmax Technologies, Inc.
-0004A9 SandStream Technologies, Inc.
-0004AA Jetstream Communications
-0004AB Comverse Network Systems, Inc.
-0004AC IBM CORP.
-0004AD Malibu Networks
-0004AE Liquid Metronics
-0004AF Digital Fountain, Inc.
-0004B0 ELESIGN Co., Ltd.
-0004B1 Signal Technology, Inc.
-0004B2 ESSEGI SRL
-0004B3 Videotek, Inc.
-0004B4 CIAC
-0004B5 Equitrac Corporation
-0004B6 Stratex Networks, Inc.
-0004B7 AMB i.t. Holding
-0004B8 Kumahira Co., Ltd.
-0004B9 S.I. Soubou, Inc.
-0004BA KDD Media Will Corporation
-0004BB Bardac Corporation
-0004BC Giantec, Inc.
-0004BD Motorola BCS
-0004BE OptXCon, Inc.
-0004BF VersaLogic Corp.
-0004C0 Cisco Systems, Inc.
-0004C1 Cisco Systems, Inc.
-0004C2 Magnipix, Inc.
-0004C3 CASTOR Informatique
-0004C4 Allen & Heath Limited
-0004C5 ASE Technologies, USA
-0004C6 Yamaha Motor Co., Ltd.
-0004C7 NetMount
-0004C8 LIBA Maschinenfabrik GmbH
-0004C9 Micro Electron Co., Ltd.
-0004CA FreeMs Corp.
-0004CB Tdsoft Communication, Ltd.
-0004CC Peek Traffic B.V.
-0004CD Informedia Research Group
-0004CE Patria Ailon
-0004CF Seagate Technology
-0004D0 Softlink s.r.o.
-0004D1 Drew Technologies, Inc.
-0004D2 Adcon Telemetry AG
-0004D3 Toyokeiki Co., Ltd.
-0004D4 Proview Electronics Co., Ltd.
-0004D5 Hitachi Communication Systems, Inc.
-0004D6 Takagi Industrial Co., Ltd.
-0004D7 Omitec Instrumentation Ltd.
-0004D8 IPWireless, Inc.
-0004D9 Titan Electronics, Inc.
-0004DA Relax Technology, Inc.
-0004DB Tellus Group Corp.
-0004DC Nortel Networks
-0004DD Cisco Systems, Inc.
-0004DE Cisco Systems, Inc.
-0004DF Teracom Telematica Ltda.
-0004E0 Procket Networks
-0004E1 Infinior Microsystems
-0004E2 SMC Networks, Inc.
-0004E3 Accton Technology Corp.
-0004E4 Daeryung Ind., Inc.
-0004E5 Glonet Systems, Inc.
-0004E6 Banyan Network Private Limited
-0004E7 Lightpointe Communications, Inc
-0004E8 IER, Inc.
-0004E9 Infiniswitch Corporation
-0004EA Hewlett-Packard Company
-0004EB Paxonet Communications, Inc.
-0004EC Memobox SA
-0004ED Billion Electric Co., Ltd.
-0004EE Lincoln Electric Company
-0004EF Polestar Corp.
-0004F0 International Computers, Ltd
-0004F1 WhereNet
-0004F2 Circa Communications, Ltd.
-0004F3 FS FORTH-SYSTEME GmbH
-0004F4 Infinite Electronics Inc.
-0004F5 SnowShore Networks, Inc.
-0004F6 Amphus
-0004F7 Omega Band, Inc.
-0004F8 QUALICABLE TV Industria E Com., Ltda
-0004F9 Xtera Communications, Inc.
-0004FA MIST Inc.
-0004FB Commtech, Inc.
-0004FC Stratus Computer (DE), Inc.
-0004FD Japan Control Engineering Co., Ltd.
-0004FE Pelago Networks
-0004FF Acronet Co., Ltd.
-000500 Cisco Systems, Inc.
-000501 Cisco Systems, Inc.
-000502 APPLE COMPUTER
-000503 ICONAG
-000504 Naray Information & Communication Enterprise
-000505 Systems Integration Solutions, Inc.
-000506 Reddo Networks AB
-000507 Fine Appliance Corp.
-000508 Inetcam, Inc.
-000509 AVOC Nishimura Ltd.
-00050A ICS Spa
-00050B SICOM Systems, Inc.
-00050C Network Photonics, Inc.
-00050D Midstream Technologies, Inc.
-00050E 3ware, Inc.
-00050F Tanaka S/S Ltd.
-000510 Infinite Shanghai Communication Terminals Ltd.
-000511 Complementary Technologies Ltd
-000512 MeshNetworks, Inc.
-000513 VTLinx Multimedia Systems, Inc.
-000514 KDT Systems Co., Ltd.
-000515 Nuark Co., Ltd.
-000516 SMART Modular Technologies
-000517 Shellcomm, Inc.
-000518 Jupiters Technology
-000519 Siemens Building Technologies AG,
-00051A 3Com Europe Ltd.
-00051B Magic Control Technology Corporation
-00051C Xnet Technology Corp.
-00051D Airocon, Inc.
-00051E Brocade Communications Systems, Inc.
-00051F Taijin Media Co., Ltd.
-000520 Smartronix, Inc.
-000521 Control Microsystems
-000522 LEA*D Corporation, Inc.
-000523 AVL List GmbH
-000524 BTL System (HK) Limited
-000525 Puretek Industrial Co., Ltd.
-000526 IPAS GmbH
-000527 SJ Tek Co. Ltd
-000528 New Focus, Inc.
-000529 Shanghai Broadan Communication Technology Co., Ltd
-00052A Ikegami Tsushinki Co., Ltd.
-00052B HORIBA, Ltd.
-00052C Supreme Magic Corporation
-00052D Zoltrix International Limited
-00052E Cinta Networks
-00052F Leviton Voice and Data
-000530 Andiamo Systems, Inc.
-000531 Cisco Systems, Inc.
-000532 Cisco Systems, Inc.
-000533 Sanera Systems, Inc.
-000534 Northstar Engineering Ltd.
-000535 Chip PC Ltd.
-000536 Danam Communications, Inc.
-000537 Nets Technology Co., Ltd.
-000538 Merilus, Inc.
-000539 A Brand New World in Sweden AB
-00053A Willowglen Services Pte Ltd
-00053B Harbour Networks Ltd., Co. Beijing
-00053C Xircom
-00053D Agere Systems
-00053E KID Systeme GmbH
-00053F VisionTek, Inc.
-000540 FAST Corporation
-000541 Advanced Systems Co., Ltd.
-000542 Otari, Inc.
-000543 IQ Wireless GmbH
-000544 Valley Technologies, Inc.
-000545 Internet Photonics
-000546 K-Solutions Inc.
-000547 Starent Networks
-000548 Disco Corporation
-000549 Salira Optical Network Systems
-00054A Ario Data Networks, Inc.
-00054B Micro Innovation AG
-00054C RF Innovations Pty Ltd
-00054D Brans Technologies, Inc.
-00054E Philips Components
-000550 Digi-Tech Communications Limited
-000551 F & S Elektronik Systeme GmbH
-000552 Xycotec Computer GmbH
-000553 DVC Company, Inc.
-000554 Rangestar Wireless
-000555 Japan Cash Machine Co., Ltd.
-000556 360 Systems
-000557 Agile TV Corporation
-000558 Synchronous, Inc.
-000559 Intracom S.A.
-00055A Power Dsine Ltd.
-00055B Charles Industries, Ltd.
-00055C Kowa Company, Ltd.
-00055D D-Link Systems, Inc.
-00055E Cisco Systems, Inc.
-00055F Cisco Systems, Inc.
-000560 LEADER COMM.CO., LTD
-000561 nac Image Technology, Inc.
-000562 Digital View Limited
-000563 J-Works, Inc.
-000564 Tsinghua Bitway Co., Ltd.
-000565 Tailyn Communication Company Ltd.
-000566 Secui.com Corporation
-000567 Etymonic Design, Inc.
-000568 Piltofish Networks AB
-000569 VMWARE, Inc.
-00056A Heuft Systemtechnik GmbH
-00056B C.P. Technology Co., Ltd.
-00056C Hung Chang Co., Ltd.
-00056D Pacific Corporation
-00056E National Enhance Technology, Inc.
-00056F Innomedia Technologies Pvt. Ltd.
-000570 Baydel Ltd.
-000571 Seiwa Electronics Co.
-000572 Deonet Co., Ltd.
-000573 Cisco Systems, Inc.
-000574 Cisco Systems, Inc.
-000575 CDS-Electronics BV
-000576 NSM Technology Ltd.
-000577 SM Information & Communication
-000579 Universal Control Solution Corp.
-00057A Hatteras Networks
-00057B Chung Nam Electronic Co., Ltd.
-00057C RCO Security AB
-00057D Sun Communications, Inc.
-00057E Eckelmann Steuerungstechnik GmbH
-00057F Acqis Technology
-000580 Fibrolan Ltd.
-000581 Snell & Wilcox Ltd.
-000582 ClearCube Technology
-000583 ImageCom Limited
-000584 AbsoluteValue Systems, Inc.
-000585 Juniper Networks, Inc.
-000586 Lucent Technologies
-000587 Locus, Incorporated
-000588 Sensoria Corp.
-000589 National Datacomputer
-00058A Netcom Co., Ltd.
-00058B IPmental, Inc.
-00058C Opentech Inc.
-00058D Lynx Photonic Networks, Inc.
-00058E Flextronics International GmbH & Co. Nfg. KG
-00058F CLCsoft co.
-000590 Swissvoice Ltd.
-000591 Active Silicon Ltd.
-000592 Pultek Corp.
-000593 Grammar Engine Inc.
-000594 IXXAT Automation GmbH
-000595 Alesis Corporation
-000596 Genotech Co., Ltd.
-000597 Eagle Traffic Control Systems
-000598 CRONOS S.r.l.
-000599 DRS Test and Energy Management or DRS-TEM
-00059A Cisco Systems, Inc.
-00059B Cisco Systems, Inc.
-00059C Kleinknecht GmbH, Ing. Buero
-00059D Daniel Computing Systems, Inc.
-00059E Zinwell Corporation
-00059F Yotta Networks, Inc.
-0005A0 MOBILINE Kft.
-0005A1 Zenocom
-0005A2 CELOX Networks
-0005A3 QEI, Inc.
-0005A4 Lucid Voice Ltd.
-0005A5 KOTT
-0005A6 Extron Electronics
-0005A7 Hyperchip, Inc.
-0005A8 WYLE ELECTRONICS
-0005A9 Princeton Networks, Inc.
-0005AA Moore Industries International Inc.
-0005AB Cyber Fone, Inc.
-0005AC Northern Digital, Inc.
-0005AD Topspin Communications, Inc.
-0005AE Mediaport USA
-0005AF InnoScan Computing A/S
-0005B0 Korea Computer Technology Co., Ltd.
-0005B1 ASB Technology BV
-0005B2 Medison Co., Ltd.
-0005B3 Asahi-Engineering Co., Ltd.
-0005B4 Aceex Corporation
-0005B5 Broadcom Technologies
-0005B6 INSYS Microelectronics GmbH
-0005B7 Arbor Technology Corp.
-0005B8 Electronic Design Associates, Inc.
-0005B9 Airvana, Inc.
-0005BA Area Netwoeks, Inc.
-0005BB Myspace AB
-0005BC Resorsys Ltd.
-0005BD ROAX BV
-0005BE Kongsberg Seatex AS
-0005BF JustEzy Technology, Inc.
-0005C0 Digital Network Alacarte Co., Ltd.
-0005C1 A-Kyung Motion, Inc.
-0005C2 Soronti, Inc.
-0005C3 Pacific Instruments, Inc.
-0005C4 Telect, Inc.
-0005C5 Flaga HF
-0005C6 Triz Communications
-0005C7 I/F-COM A/S
-0005C8 VERYTECH
-0005C9 LG Innotek
-0005CA Hitron Technology, Inc.
-0005CB ROIS Technologies, Inc.
-0005CC Sumtel Communications, Inc.
-0005CD Denon, Ltd.
-0005CE Prolink Microsystems Corporation
-0005CF Thunder River Technologies, Inc.
-0005D0 Solinet Systems
-0005D1 Metavector Technologies
-0005D2 DAP Technologies
-0005D3 eProduction Solutions, Inc.
-0005D4 FutureSmart Networks, Inc.
-0005D5 Speedcom Wireless
-0005D6 Titan Wireless
-0005D7 Vista Imaging, Inc.
-0005D8 Arescom, Inc.
-0005D9 Techno Valley, Inc.
-0005DA Apex Automationstechnik
-0005DB Nentec GmbH
-0005DC Cisco Systems, Inc.
-0005DD Cisco Systems, Inc.
-0005DE Gi Fone Korea, Inc.
-0005DF Electronic Innovation, Inc.
-0005E0 Empirix Corp.
-0005E1 Trellis Photonics, Ltd.
-0005E2 Creativ Network Technologies
-0005E3 LightSand Communications, Inc.
-0005E4 Red Lion Controls L.P.
-0005E5 Renishaw PLC
-0005E6 Egenera, Inc.
-0005E7 Netrake Corp.
-0005E8 TurboWave, Inc.
-0005E9 Unicess Network, Inc.
-0005EA Rednix
-0005EB Blue Ridge Networks, Inc.
-0005EC Mosaic Systems Inc.
-0005ED Technikum Joanneum GmbH
-0005EE BEWATOR Group
-0005EF ADOIR Digital Technology
-0005F0 SATEC
-0005F1 Vrcom, Inc.
-0005F2 Power R, Inc.
-0005F3 Weboyn
-0005F4 System Base Co., Ltd.
-0005F5 OYO Geospace Corp.
-0005F6 Young Chang Co. Ltd.
-0005F7 Analog Devices, Inc.
-0005F8 Real Time Access, Inc.
-0005F9 TOA Corporation
-0005FA IPOptical, Inc.
-0005FB ShareGate, Inc.
-0005FC Schenck Pegasus Corp.
-0005FD PacketLight Networks Ltd.
-0005FE Traficon N.V.
-0005FF SNS Solutions, Inc.
-000600 Tokyo Electronic Industry Co., Ltd.
-000601 Otanikeiki Co., Ltd.
-000602 Cirkitech Electronics Co.
-000603 Baker Hughes Inc.
-000604 @Track Communications, Inc.
-000605 Inncom International, Inc.
-000606 RapidWAN, Inc.
-000607 Omni Directional Control Technology Inc.
-000608 At-Sky SAS
-000609 Crossport Systems
-00060A Blue2space
-00060B Paceline Systems Corporation
-00060C Melco Industries, Inc.
-00060D Wave7 Optics
-00060E IGYS Systems, Inc.
-00060F Narad Networks Inc
-000610 Abeona Networks Inc
-000611 Zeus Wireless, Inc.
-000612 Accusys, Inc.
-000613 Kawasaki Microelectronics Incorporated
-000614 Prism Holdings
-000615 Kimoto Electric Co., Ltd.
-000616 Tel Net Co., Ltd.
-000617 Redswitch Inc.
-000618 DigiPower Manufacturing Inc.
-000619 Connection Technology Systems
-00061A Zetari Inc.
-00061B Portable Systems, IBM Japan Co, Ltd
-00061C Hoshino Metal Industries, Ltd.
-00061D MIP Telecom, Inc.
-00061E Maxan Systems
-00061F Vision Components GmbH
-000620 Serial System Ltd.
-000621 Hinox, Co., Ltd.
-000622 Chung Fu Chen Yeh Enterprise Corp.
-000623 MGE UPS Systems France
-000624 Gentner Communications Corp.
-000625 The Linksys Group, Inc.
-000626 MWE GmbH
-000627 Uniwide Technologies, Inc.
-000628 Cisco Systems, Inc.
-000629 IBM CORPORATION
-00062A Cisco Systems, Inc.
-00062B INTRASERVER TECHNOLOGY
-00062C Network Robots, Inc.
-00062D TouchStar Technologies, L.L.C.
-00062E Aristos Logic Corp.
-00062F Pivotech Systems Inc.
-000630 Adtranz Sweden
-000631 Optical Solutions, Inc.
-000632 Mesco Engineering GmbH
-000633 Heimann Biometric Systems GmbH
-000634 GTE Airfone Inc.
-000635 PacketAir Networks, Inc.
-000636 Jedai Broadband Networks
-000637 Toptrend-Meta Information (ShenZhen) Inc.
-000638 Sungjin C&C Co., Ltd.
-000639 Newtec
-00063A Dura Micro, Inc.
-00063B Arcturus Networks, Inc.
-00063C NMI Electronics Ltd
-00063D Microwave Data Systems Inc.
-00063E Opthos Inc.
-00063F Everex Communications Inc.
-000640 White Rock Networks
-000641 ITCN
-000642 Genetel Systems Inc.
-000643 SONO Computer Co., Ltd.
-000644 NEIX Inc.
-000645 Meisei Electric Co. Ltd.
-000646 ShenZhen XunBao Network Technology Co Ltd
-000647 Etrali S.A.
-000648 Seedsware, Inc.
-000649 Quante
-00064A Honeywell Co., Ltd. (KOREA)
-00064B Alexon Co., Ltd.
-00064C Invicta Networks, Inc.
-00064D Sencore
-00064E Broad Net Technology Inc.
-00064F PRO-NETS Technology Corporation
-000650 Tiburon Networks, Inc.
-000651 Aspen Networks Inc.
-000652 Cisco Systems, Inc.
-000653 Cisco Systems, Inc.
-000654 Maxxio Technologies
-000655 Yipee, Inc.
-000656 Tactel AB
-000657 Market Central, Inc.
-000658 Helmut Fischer GmbH & Co. KG
-000659 EAL (Apeldoorn) B.V.
-00065A Strix Systems
-00065B Dell Computer Corp.
-00065C Malachite Technologies, Inc.
-00065D Heidelberg Web Systems
-00065E Photuris, Inc.
-00065F ECI Telecom - NGTS Ltd.
-000660 NADEX Co., Ltd.
-000661 NIA Home Technologies Corp.
-000662 MBM Technology Ltd.
-000663 Human Technology Co., Ltd.
-000664 Fostex Corporation
-000665 Sunny Giken, Inc.
-000666 Roving Networks
-000667 Tripp Lite
-000668 Vicon Industries Inc.
-000669 Datasound Laboratories Ltd
-00066A InfiniCon Systems, Inc.
-00066B Sysmex Corporation
-00066C Robinson Corporation
-00066D Compuprint S.P.A.
-00066E Delta Electronics, Inc.
-00066F Korea Data Systems
-000670 Upponetti Oy
-000671 Softing AG
-000672 Netezza
-000673 Optelecom, Inc.
-000674 Spectrum Control, Inc.
-000675 Banderacom, Inc.
-000676 Novra Technologies Inc.
-000677 SICK AG
-000678 Marantz Japan, Inc.
-000679 Konami Corporation
-00067A JMP Systems
-00067B Toplink C&C Corporation
-00067C CISCO SYSTEMS, INC.
-00067D Takasago Ltd.
-00067E WinCom Systems, Inc.
-00067F Rearden Steel Technologies
-000680 Card Access, Inc.
-000681 Goepel Electronic GmbH
-000682 Convedia
-000683 Bravara Communications, Inc.
-000684 Biacore AB
-000685 NetNearU Corporation
-000686 ZARDCOM Co., Ltd.
-000687 Omnitron Systems Technology, Inc.
-000688 Telways Communication Co., Ltd.
-000689 yLez Technologies Pte Ltd
-00068A NeuronNet Co. Ltd. R&D Center
-00068B AirRunner Technologies, Inc.
-00068C 3Com Corporation
-00068D SANgate Systems
-00068E HID Corporation
-00068F Telemonitor, Inc.
-000690 Euracom Communication GmbH
-000691 PT Inovacao
-000692 Intruvert Networks, Inc.
-000693 Flexus Computer Technology, Inc.
-000694 Mobillian Corporation
-000695 Ensure Technologies, Inc.
-000696 Advent Networks
-000697 R & D Center
-000698 egnite Software GmbH
-000699 Vida Design Co.
-00069A e & Tel
-00069B AVT Audio Video Technologies GmbH
-00069C Transmode Systems AB
-00069D Petards Mobile Intelligence
-00069E UNIQA, Inc.
-00069F Kuokoa Networks
-0006A0 Mx Imaging
-0006A1 Celsian Technologies, Inc.
-0006A2 Microtune, Inc.
-0006A3 Bitran Corporation
-0006A4 INNOWELL Corp.
-0006A5 PINON Corp.
-0006A6 Artistic Licence (UK) Ltd
-0006A7 Primarion
-0006A8 KC Technology, Inc.
-0006A9 Universal Instruments Corp.
-0006AA Miltope Corporation
-0006AB W-Link Systems, Inc.
-0006AC Intersoft Co.
-0006AD KB Electronics Ltd.
-0006AE Himachal Futuristic Communications Ltd
-0006B0 Comtech EF Data Corp.
-0006B1 Sonicwall
-0006B2 Linxtek Co.
-0006B3 Diagraph Corporation
-0006B4 Vorne Industries, Inc.
-0006B5 Luminent, Inc.
-0006B6 Nir-Or Israel Ltd.
-0006B7 TELEM GmbH
-0006B8 Bandspeed Pty Ltd
-0006B9 A5TEK Corp.
-0006BA Westwave Communications
-0006BB ATI Technologies Inc.
-0006BC Macrolink, Inc.
-0006BD BNTECHNOLOGY Co., Ltd.
-0006BE Baumer Optronic GmbH
-0006BF Accella Technologies Co., Ltd.
-0006C0 United Internetworks, Inc.
-0006C1 CISCO SYSTEMS, INC.
-0006C2 Smartmatic Corporation
-0006C3 Schindler Elevators Ltd.
-0006C4 Piolink Inc.
-0006C5 INNOVI Technologies Limited
-0006C6 lesswire AG
-0006C7 RFNET Technologies Pte Ltd (S)
-0006C8 Sumitomo Metal Micro Devices, Inc.
-0006C9 Technical Marketing Research, Inc.
-0006CA American Computer & Digital Components, Inc. (ACDC)
-0006CB Jotron Electronics A/S
-0006CC JMI Electronics Co., Ltd.
-0006CD CreoScitex Corporation Ltd.
-0006CE DATENO
-0006CF Thales Avionics In-Flight Systems, LLC
-0006D0 Elgar Electronics Corp.
-0006D1 Tahoe Networks, Inc.
-0006D2 Tundra Semiconductor Corp.
-0006D3 Alpha Telecom, Inc. U.S.A.
-0006D4 Interactive Objects, Inc.
-0006D5 Diamond Systems Corp.
-0006D6 Cisco Systems, Inc.
-0006D7 Cisco Systems, Inc.
-0006D8 Maple Optical Systems
-0006D9 IPM-Net S.p.A.
-0006DA ITRAN Communications Ltd.
-0006DB ICHIPS Co., Ltd.
-0006DC Syabas Technology (Amquest)
-0006DD AT & T Laboratories - Cambridge Ltd
-0006DE Flash Technology
-0006DF AIDONIC Corporation
-0006E0 MAT Co., Ltd.
-0006E1 Techno Trade s.a
-0006E2 Ceemax Technology Co., Ltd.
-0006E3 Quantitative Imaging Corporation
-0006E4 Citel Technologies Ltd.
-0006E5 Fujian Newland Computer Ltd. Co.
-0006E6 DongYang Telecom Co., Ltd.
-0006E7 Bit Blitz Communications Inc.
-0006E8 Optical Network Testing, Inc.
-0006E9 Intime Corp.
-0006EA ELZET80 Mikrocomputer GmbH&Co. KG
-0006EB Global Data
-0006EC M/A COM Private Radio System Inc.
-0006ED Inara Networks
-0006EE Shenyang Neu-era Information & Technology Stock Co., Ltd
-0006EF Maxxan Systems, Inc.
-0006F0 Digeo, Inc.
-0006F1 Optillion
-0006F2 Platys Communications
-0006F3 AcceLight Networks
-0006F4 Prime Electronics & Satellitics Inc.
-0006F9 Mitsui Zosen Systems Research Inc.
-0006FA IP SQUARE Co, Ltd.
-0006FB Hitachi Printing Solutions, Ltd.
-0006FC Fnet Co., Ltd.
-0006FD Comjet Information Systems Corp.
-0006FE Celion Networks, Inc.
-0006FF Sheba Systems Co., Ltd.
-000700 Zettamedia Korea
-000701 RACAL-DATACOM
-000702 Varian Medical Systems
-000703 CSEE Transport
-000705 Endress & Hauser GmbH & Co
-000706 Sanritz Corporation
-000707 Interalia Inc.
-000708 Bitrage Inc.
-000709 Westerstrand Urfabrik AB
-00070A Unicom Automation Co., Ltd.
-00070B Octal, SA
-00070C SVA-Intrusion.com Co. Ltd.
-00070D Cisco Systems Inc.
-00070E Cisco Systems Inc.
-00070F Fujant, Inc.
-000710 Adax, Inc.
-000711 Acterna
-000712 JAL Information Technology
-000713 IP One, Inc.
-000714 Brightcom
-000715 General Research of Electronics, Inc.
-000716 J & S Marine Ltd.
-000717 Wieland Electric GmbH
-000718 iCanTek Co., Ltd.
-000719 Mobiis Co., Ltd.
-00071A Finedigital Inc.
-00071B Position Technology Inc.
-00071C AT&T Fixed Wireless Services
-00071D Satelsa Sistemas Y Aplicaciones De Telecomunicaciones, S.A.
-00071E Tri-M Engineering / Nupak Dev. Corp.
-00071F European Systems Integration
-000720 Trutzschler GmbH & Co. KG
-000721 Formac Elektronik GmbH
-000722 Nielsen Media Research
-000723 ELCON Systemtechnik GmbH
-000724 Telemax Co., Ltd.
-000725 Bematech International Corp.
-000727 Zi Corporation (HK) Ltd.
-000728 Neo Telecom
-000729 Kistler Instrumente AG
-00072A Innovance Networks
-00072B Jung Myung Telecom Co., Ltd.
-00072C Fabricom
-00072D CNSystems
-00072E North Node AB
-00072F Instransa, Inc.
-000730 Hutchison OPTEL Telecom Technology Co., Ltd.
-000731 Spiricon, Inc.
-000732 AAEON Technology Inc.
-000733 DANCONTROL Engineering
-000734 ONStor, Inc.
-000735 Flarion Technologies, Inc.
-000736 Data Video Technologies Co., Ltd.
-000737 Soriya Co. Ltd.
-000738 Young Technology Co., Ltd.
-000739 Motion Media Technology Ltd.
-00073A Inventel Systemes
-00073B Tenovis GmbH & Co KG
-00073C Telecom Design
-00073D Nanjing Postel Telecommunications Co., Ltd.
-00073E China Great-Wall Computer Shenzhen Co., Ltd.
-00073F Woojyun Systec Co., Ltd.
-000740 Melco Inc.
-000741 Sierra Automated Systems
-000742 Current Technologies
-000743 Chelsio Communications
-000744 Unico, Inc.
-000745 Radlan Computer Communications Ltd.
-000746 Interlink BT, LLC
-000747 Mecalc
-000748 The Imaging Source Europe
-000749 CENiX Inc.
-00074A Carl Valentin GmbH
-00074B Daihen Corporation
-00074C Beicom Inc.
-00074D Zebra Technologies Corp.
-00074E Naughty boy co., Ltd.
-00074F Cisco Systems, Inc.
-000750 Cisco Systems, Inc.
-000751 m.u.t. - GmbH
-000752 Rhythm Watch Co., Ltd.
-000753 Beijing Qxcomm Technology Co., Ltd.
-000754 Xyterra Computing, Inc.
-000755 Lafon SA
-000756 Juyoung Telecom
-000757 Topcall International AG
-000758 Dragonwave
-000759 Boris Manufacturing Corp.
-00075A Air Products and Chemicals, Inc.
-00075B Gibson Guitars
-00075C ENCAD, Inc.
-00075D Celleritas Inc.
-00075E Pulsar Technologies, Inc.
-00075F VCS Video Communication Systems AG
-000760 TOMIS Information & Telecom Corp.
-000761 Logitech SA
-000762 Group Sense Limited
-000763 Sunniwell Cyber Tech. Co., Ltd.
-000764 YoungWoo Telecom Co. Ltd.
-000765 Jade Quantum Technologies, Inc.
-000766 Chou Chin Industrial Co., Ltd.
-000767 Yuxing Electronics Company Limited
-000768 Danfoss A/S
-000769 Italiana Macchi SpA
-00076A NEXTEYE Co., Ltd.
-00076B Stralfors AB
-00076C Daehanet, Inc.
-00076D Flexlight Networks
-00076E Sinetica Corporation Ltd.
-00076F Synoptics Limited
-000770 Locusnetworks Corporation
-000771 Embedded System Corporation
-000772 Alcatel Shanghai Bell Co., Ltd.
-000773 Ascom Powerline Communications Ltd.
-000774 GuangZhou Thinker Technology Co. Ltd.
-000775 Valence Semiconductor, Inc.
-000776 Federal APD
-000777 Motah Ltd.
-000778 GERSTEL GmbH & Co. KG
-000779 Sungil Telecom Co., Ltd.
-00077A Infoware System Co., Ltd.
-00077B Millimetrix Broadband Networks
-00077C OnTime Networks
-00077E Elrest GmbH
-00077F J Communications Co., Ltd.
-000780 Bluegiga Technologies OY
-000781 Itron Inc.
-000782 Nauticus Networks, Inc.
-000783 SynCom Network, Inc.
-000784 Cisco Systems Inc.
-000785 Cisco Systems Inc.
-000786 Wireless Networks Inc.
-000787 Idea System Co., Ltd.
-000788 Clipcomm, Inc.
-000789 Eastel Systems Corporation
-00078A Mentor Data System Inc.
-00078B Wegener Communications, Inc.
-00078C Elektronikspecialisten i Borlange AB
-00078D NetEngines Ltd.
-00078E Garz & Friche GmbH
-00078F Emkay Innovative Products
-000790 Tri-M Technologies (s) Limited
-000791 International Data Communications, Inc.
-000792 Suetron Electronic GmbH
-000794 Simple Devices, Inc.
-000795 Elitegroup Computer System Co. (ECS)
-000796 LSI Systems, Inc.
-000797 Netpower Co., Ltd.
-000798 Selea SRL
-000799 Tipping Point Technologies, Inc.
-00079A SmartSight Networks Inc.
-00079B Aurora Networks
-00079C Golden Electronics Technology Co., Ltd.
-00079D Musashi Co., Ltd.
-00079E Ilinx Co., Ltd.
-00079F Action Digital Inc.
-0007A0 e-Watch Inc.
-0007A1 VIASYS Healthcare GmbH
-0007A2 Opteon Corporation
-0007A3 Ositis Software, Inc.
-0007A4 GN Netcom Ltd.
-0007A5 Y.D.K Co. Ltd.
-0007A6 Home Automation, Inc.
-0007A7 A-Z Inc.
-0007A8 Haier Group Technologies Ltd.
-0007A9 Novasonics
-0007AA Quantum Data Inc.
-0007AC Eolring
-0007AD Pentacon GmbH Foto-und Feinwerktechnik
-0007AE Layer N Networks
-0007AF N-Tron Corp.
-0007B0 Office Details, Inc.
-0007B1 Equator Technologies
-0007B2 Transaccess S.A.
-0007B3 Cisco Systems Inc.
-0007B4 Cisco Systems Inc.
-0007B5 Any One Wireless Ltd.
-0007B6 Telecom Technology Ltd.
-0007B7 Samurai Ind. Prods Eletronicos Ltda
-0007B8 American Predator Corp.
-0007B9 Ginganet Corporation
-0007BA Xebeo Communications, Inc.
-0007BB Candera Inc.
-0007BC Identix Inc.
-0007BD Radionet Ltd.
-0007BE DataLogic SpA
-0007BF Armillaire Technologies, Inc.
-0007C0 NetZerver Inc.
-0007C1 Overture Networks, Inc.
-0007C2 Netsys Telecom
-0007C3 Cirpack
-0007C4 JEAN Co. Ltd.
-0007C5 Gcom, Inc.
-0007C6 VDS Vosskuhler GmbH
-0007C7 Synectics Systems Limited
-0007C8 Brain21, Inc.
-0007C9 Technol Seven Co., Ltd.
-0007CA Creatix Polymedia Ges Fur Kommunikaitonssysteme
-0007CB Freebox SA
-0007CC Kaba Benzing GmbH
-0007CD NMTEL Co., Ltd.
-0007CE Cabletime Limited
-0007CF Anoto AB
-0007D0 Automat Engenharia de Automaoa Ltda.
-0007D1 Spectrum Signal Processing Inc.
-0007D2 Logopak Systeme
-0007D3 Stork Digital Imaging B.V.
-0007D4 Zhejiang Yutong Network Communication Co Ltd.
-0007D5 3e Technologies Int;., Inc.
-0007D6 Commil Ltd.
-0007D7 Caporis Networks AG
-0007D8 Hitron Systems Inc.
-0007D9 Splicecom
-0007DA Neuro Telecom Co., Ltd.
-0007DB Kirana Networks, Inc.
-0007DC Atek Co, Ltd.
-0007DD Cradle Technologies
-0007DE eCopilt AB
-0007DF Vbrick Systems Inc.
-0007E0 Palm Inc.
-0007E1 WIS Communications Co. Ltd.
-0007E2 Bitworks, Inc.
-0007E3 Navcom Technology, Inc.
-0007E4 SoftRadio Co., Ltd.
-0007E5 Coup Corporation
-0007E6 edgeflow Canada Inc.
-0007E7 FreeWave Technologies
-0007E8 St. Bernard Software
-0007E9 Intel Corporation
-0007EA Massana, Inc.
-0007EB Cisco Systems Inc.
-0007EC Cisco Systems Inc.
-0007ED Altera Corporation
-0007EE telco Informationssysteme GmbH
-0007EF Lockheed Martin Tactical Systems
-0007F0 LogiSync Corporation
-0007F1 TeraBurst Networks Inc.
-0007F2 IOA Corporation
-0007F3 Think Engine Networks
-0007F4 Eletex Co., Ltd.
-0007F5 Bridgeco Co AG
-0007F6 Qqest Software Systems
-0007F7 Galtronics
-0007F8 ITDevices, Inc.
-0007F9 Phonetics, Inc.
-0007FA ITT Co., Ltd.
-0007FB Giga Stream UMTS Technologies GmbH
-0007FC Adept Systems Inc.
-0007FD LANergy Ltd.
-0007FE Rigaku Corporation
-0007FF Gluon Networks
-000800 MULTITECH SYSTEMS, INC.
-000801 HighSpeed Surfing Inc.
-000802 Compaq Computer Corporation
-000803 Cos Tron
-000804 ICA Inc.
-000805 Techno-Holon Corporation
-000806 Raonet Systems, Inc.
-000807 Access Devices Limited
-000808 PPT Vision, Inc.
-000809 Systemonic AG
-00080A Espera-Werke GmbH
-00080B Birka BPA Informationssystem AB
-00080C VDA elettronica SrL
-00080D Toshiba
-00080E Motorola, BCS
-00080F Proximion Fiber Optics AB
-000810 Key Technology, Inc.
-000811 VOIX Corporation
-000812 GM-2 Corporation
-000813 Diskbank, Inc.
-000814 TIL Technologies
-000815 CATS Co., Ltd.
-000816 Bluetags A/S
-000817 EmergeCore Networks LLC
-000818 Pixelworks, Inc.
-000819 Banksys
-00081A Sanrad Intelligence Storage Communications (2000) Ltd.
-00081B Windigo Systems
-00081C @pos.com
-00081D Ipsil, Incorporated
-00081E Repeatit AB
-00081F Pou Yuen Tech Corp. Ltd.
-000820 Cisco Systems Inc.
-000821 Cisco Systems Inc.
-000822 InPro Comm
-000823 Texa Corp.
-000824 Promatek Industries Ltd.
-000825 Acme Packet
-000826 Colorado Med Tech
-000827 Pirelli Cables & Systems
-000828 Koei Engineering Ltd.
-000829 Aval Nagasaki Corporation
-00082A Powerwallz Network Security
-00082B Wooksung Electronics, Inc.
-00082C Homag AG
-00082D Indus Teqsite Private Limited
-00082E Multitone Electronics PLC
-00084E DivergeNet, Inc.
-00084F Qualstar Corporation
-000850 Arizona Instrument Corp.
-000851 Canadian Bank Note Company, Ltd.
-000852 Davolink Co. Inc.
-000853 Schleicher GmbH & Co. Relaiswerke KG
-000854 Netronix, Inc.
-000855 NASA-Goddard Space Flight Center
-000856 Gamatronic Electronic Industries Ltd.
-000857 Polaris Networks, Inc.
-000858 Novatechnology Inc.
-000859 ShenZhen Unitone Electronics Co., Ltd.
-00085A IntiGate Inc.
-00085B Hanbit Electronics Co., Ltd.
-00085C Shanghai Dare Technologies Co. Ltd.
-00085D Aastra
-00085E PCO AG
-00085F Picanol N.V.
-000860 LodgeNet Entertainment Corp.
-000861 SoftEnergy Co., Ltd.
-000862 NEC Eluminant Technologies, Inc.
-000863 Entrisphere Inc.
-000864 Fasy S.p.A.
-000865 JASCOM CO., LTD
-000866 DSX Access Systems, Inc.
-000867 Uptime Devices
-000868 PurOptix
-000869 Command-e Technology Co.,Ltd.
-00086A Industrie Technik IPS GmbH
-00086B MIPSYS
-00086C Plasmon LMS
-00086D Missouri FreeNet
-00086E Hyglo AB
-00086F Resources Computer Network Ltd.
-000870 Rasvia Systems, Inc.
-000871 NORTHDATA Co., Ltd.
-000872 Sorenson Technologies, Inc.
-000873 DAP Design B.V.
-000874 Dell Computer Corp.
-000875 Acorp Electronics Corp.
-000876 SDSystem
-000877 Liebert HIROSS S.p.A.
-000878 Benchmark Storage Innovations
-000879 CEM Corporation
-00087A Wipotec GmbH
-00087B RTX Telecom A/S
-00087C Cisco Systems, Inc.
-00087D Cisco Systems Inc.
-00087E Bon Electro-Telecom Inc.
-00087F SPAUN electronic GmbH & Co. KG
-000880 BroadTel Canada Communications inc.
-000881 DIGITAL HANDS CO.,LTD.
-000882 SIGMA CORPORATION
-000883 Hewlett-Packard Company
-000884 Index Braille AB
-000885 EMS Dr. Thomas Wuensche
-000886 Hansung Teliann, Inc.
-000887 Maschinenfabrik Reinhausen GmbH
-000888 OULLIM Information Technology Inc,.
-000889 Echostar Technologies Corp
-00088A Minds@Work
-00088B Tropic Networks Inc.
-00088C Quanta Network Systems Inc.
-00088D Sigma-Links Inc.
-00088E Nihon Computer Co., Ltd.
-00088F ADVANCED DIGITAL TECHNOLOGY
-000890 AVILINKS SA
-000891 Lyan Inc.
-000892 EM Solutions
-000894 InnoVISION Multimedia Ltd.
-000895 DIRC Technologie GmbH & Co.KG
-000896 Printronix, Inc.
-000897 Quake Technologies
-000898 Gigabit Optics Corporation
-000899 Netbind, Inc.
-00089A Alcatel Microelectronics
-00089B ICP Electronics Inc.
-00089C Elecs Industry Co., Ltd.
-00089D UHD-Elektronik
-00089E Beijing Enter-Net co.LTD
-00089F EFM Networks
-0008A0 Stotz Feinmesstechnik GmbH
-0008A1 CNet Technology Inc.
-0008A2 ADI Engineering, Inc.
-0008A3 Cisco Systems
-0008A4 Cisco Systems
-0008A5 Peninsula Systems Inc.
-0008A6 Multiware & Image Co., Ltd.
-0008A7 iLogic Inc.
-0008A8 Systec Co., Ltd.
-0008A9 SangSang Technology, Inc.
-0008AA KARAM
-0008AB EnerLinx.com, Inc.
-0008AD Toyo-Linx Co., Ltd.
-0008AE Packetfront
-0008AF Novatec Corporation
-0008B0 BKtel communications GmbH
-0008B1 ProQuent Systems
-0008B2 SHENZHEN COMPASS TECHNOLOGY DEVELOPMENT CO.,LTD
-0008B3 Fastwel
-0008B4 SYSPOL
-0008B5 TAI GUEN ENTERPRISE CO., LTD
-0008B6 RouteFree, Inc.
-0008B7 HIT Incorporated
-0008B8 E.F. Johnson
-0008B9 KAON MEDIA Co., Ltd.
-0008BA Erskine Systems Ltd
-0008BB NetExcell
-0008BC Ilevo AB
-0008BD TEPG-US
-0008BE XENPAK MSA Group
-0008BF Aptus Elektronik AB
-0008C0 ASA SYSTEMS
-0008C1 Avistar Communications Corporation
-0008C2 Cisco Systems
-0008C3 Contex A/S
-0008C4 Hikari Co.,Ltd.
-0008C5 Liontech Co., Ltd.
-0008C6 Philips Consumer Communications
-0008C7 COMPAQ COMPUTER CORPORATION
-0008C8 Soneticom, Inc.
-0008C9 TechniSat Digital GmbH
-0008CA TwinHan Technology Co.,Ltd
-0008CB Zeta Broadband Inc.
-0008CC Remotec, Inc.
-0008CD With-Net Inc
-0008CF Nippon Koei Power Systems Co., Ltd.
-0008D0 Musashi Engineering Co., LTD.
-0008D1 KAREL INC.
-0008D2 ZOOM Networks Inc.
-0008D3 Hercules Technologies S.A.
-0008D4 IneoQuest Technologies, Inc
-0008D5 Vanguard Managed Solutions
-0008D6 HASSNET Inc.
-0008D7 HOW CORPORATION
-0008D8 Dowkey Microwave
-0008D9 Mitadenshi Co.,LTD
-0008DA SofaWare Technologies Ltd.
-0008DB Corrigent Systems
-0008DC Wiznet
-0008DD Telena Communications, Inc.
-0008DE 3UP Systems
-0008DF Alistel Inc.
-0008E0 ATO Technology Ltd.
-0008E1 Barix AG
-0008E2 Cisco Systems
-0008E3 Cisco Systems
-0008E4 Envenergy Inc
-0008E5 IDK Corporation
-0008E6 Littlefeet
-0008E7 SHI ControlSystems,Ltd.
-0008E8 Excel Master Ltd.
-0008E9 NextGig
-0008EA Motion Control Engineering, Inc
-0008EB ROMWin Co.,Ltd.
-0008EC Zonu, Inc.
-0008ED ST&T Instrument Corp.
-0008EE Logic Product Development
-0008EF DIBAL,S.A.
-0008F0 Next Generation Systems, Inc.
-0008F1 Voltaire
-0008F2 C&S Technology
-0008F3 WANY
-0008F4 Bluetake Technology Co., Ltd.
-0008F5 YESTECHNOLOGY Co.,Ltd.
-0008F6 SUMITOMO ELECTRIC HIGHTECHS.co.,ltd.
-0008F7 Hitachi Ltd, Semiconductor &amp; Integrated Circuits Gr
-0008F8 Guardall Ltd
-0008F9 Padcom, Inc.
-0008FA Karl E.Brinkmann GmbH
-0008FB SonoSite, Inc.
-0008FC Gigaphoton Inc.
-0008FD BlueKorea Co., Ltd.
-0008FE UNIK C&C Co.,Ltd.
-0008FF Trilogy Broadcast (Holdings) Ltd
-000900 TMT
-000901 Shenzhen Shixuntong Information & Technoligy Co
-000902 Redline Communications Inc.
-000903 Panasas, Inc
-000904 MONDIAL electronic
-000905 iTEC Technologies Ltd.
-000906 Esteem Networks
-000907 Chrysalis Development
-000908 VTech Technology Corp.
-000909 Telenor Connect A/S
-00090A SnedFar Technology Co., Ltd.
-00090B MTL  Instruments PLC
-00090C Mayekawa Mfg. Co. Ltd.
-00090D LEADER ELECTRONICS CORP.
-00090E Helix Technology Inc.
-00090F Fortinet Inc.
-000910 Simple Access Inc.
-000911 Cisco Systems
-000912 Cisco Systems
-000914 COMPUTROLS INC.
-000915 CAS Corp.
-000916 Listman Home Technologies, Inc.
-000917 WEM Technology Inc
-000918 SAMSUNG TECHWIN CO.,LTD
-000919 MDS Gateways
-00091A Macat Optics & Electronics Co., Ltd.
-00091B Digital Generation Inc.
-00091C CacheVision, Inc
-00091D Proteam Computer Corporation
-00091E Firstech Technology Corp.
-00091F A&amp;D Co., Ltd.
-000920 EpoX COMPUTER CO.,LTD.
-000921 Planmeca Oy
-000922 Touchless Sensor Technology AG
-000923 Heaman System Co., Ltd
-000924 Telebau GmbH
-000925 VSN Systemen BV
-000926 YODA COMMUNICATIONS, INC.
-000927 TOYOKEIKI CO.,LTD.
-000928 Telecore Inc
-000929 Sanyo Industries (UK) Limited
-00092A MYTECS Co.,Ltd.
-00092B iQstor Networks, Inc.
-00092C Hitpoint Inc.
-00092D High Tech Computer, Corp.
-00092E B&Tech System Inc.
-00092F Akom Technology Corporation
-000930 AeroConcierge Inc.
-000931 Future Internet, Inc.
-000932 Omnilux
-000933 OPTOVALLEY Co. Ltd.
-000934 Dream-Multimedia-Tv GmbH
-000935 Sandvine Incorporated
-000936 Ipetronik GmbH & Co.KG
-000937 Inventec Appliance Corp
-000938 Allot Communications
-000939 ShibaSoku Co.,Ltd.
-00093A Molex Fiber Optics
-00093B HYUNDAI NETWORKS INC.
-00093C Jacques Technologies P/L
-00093D Newisys,Inc.
-00093E C&I Technologies
-00093F Double-Win Enterpirse CO., LTD
-000940 AGFEO GmbH & Co. KG
-000941 Allied Telesis K.K.
-000942 CRESCO, LTD.
-000943 Cisco Systems
-000944 Cisco Systems
-000945 Palmmicro Communications Inc
-000946 Cluster Labs GmbH
-000947 Aztek, Inc.
-000948 Vista Control Systems, Corp.
-000949 Glyph Technologies Inc.
-00094A Homenet Communications
-00094B FillFactory NV
-00094C Communication Weaver Co.,Ltd.
-00094D Braintree Communications Pty Ltd
-00094E BARTECH SYSTEMS INTERNATIONAL, INC
-00094F elmegt GmbH & Co. KG
-000950 Independent Storage Corporation
-000951 Apogee Instruments, Inc
-000952 Auerswald GmbH & Co. KG
-000953 Linkage System Integration Co.Ltd.
-000954 AMiT spol. s. r. o.
-000955 Young Generation International Corp.
-000956 Network Systems Group, Ltd. (NSG)
-000957 Supercaller, Inc.
-000958 INTELNET S.A.
-000959 Sitecsoft
-00095A RACEWOOD TECHNOLOGY
-00095B Netgear, Inc.
-00095C Philips Medical Systems - Cardiac and Monitoring Systems (CM
-00095D Dialogue Technology Corp.
-00095E Masstech Group Inc.
-00095F Telebyte, Inc.
-000960 YOZAN Inc.
-000961 Switchgear and Instrumentation Ltd
-000962 Filetrac AS
-000963 Dominion Lasercom Inc.
-000964 Hi-Techniques
-000966 Thales Navigation
-000967 Tachyon, Inc
-000968 TECHNOVENTURE, INC.
-000969 Meret Optical Communications
-00096A Cloverleaf Communications Inc.
-00096B IBM Corporation
-00096C Imedia Semiconductor Corp.
-00096D Powernet Technologies Corp.
-00096E GIANT ELECTRONICS LTD.
-00096F Beijing Zhongqing Elegant Tech. Corp.,Limited
-000970 Vibration Research Corporation
-000971 Time Management, Inc.
-000972 Securebase,Inc
-000973 Lenten Technology Co., Ltd.
-000974 Innopia Technologies, Inc.
-000975 fSONA Communications Corporation
-000976 Datasoft ISDN Systems GmbH
-000977 Brunner Elektronik AG
-000978 AIJI System Co., Ltd.
-000979 Advanced Television Systems Committee, Inc.
-00097A Louis Design Labs.
-00097B Cisco Systems
-00097C Cisco Systems
-00097D SecWell Networks Oy
-00097E IMI TECHNOLOGY CO., LTD
-00097F Vsecure 2000 LTD.
-000980 Power Zenith Inc.
-000981 Newport Networks
-000982 Loewe Opta GmbH
-000983 Gvision Incorporated
-000984 MyCasa Network Inc.
-000985 Auto Telecom Company
-000986 Metalink LTD.
-000987 NISHI NIPPON ELECTRIC WIRE & CABLE CO.,LTD.
-000988 Nudian Electron Co., Ltd.
-000989 VividLogic Inc.
-00098A EqualLogic Inc
-00098B Entropic Communications, Inc.
-00098C Possio AB
-00098D DCT Ltd (Digital Communication Technologies Ltd)
-00098E ipcas GmbH
-00098F Cetacean Networks
-000990 ACKSYS Communications & systems
-000991 GE Fanuc Automation Manufacturing, Inc.
-000992 InterEpoch Technology,INC.
-000993 Visteon Corporation
-000994 Cronyx Engineering
-000995 Castle Technology Ltd
-000996 RDI
-000997 Nortel Networks
-000998 Capinfo Company Limited
-000999 CP GEORGES RENAULT
-00099A ELMO COMPANY, LIMITED
-00099B Western Telematic Inc.
-00099C Naval Research Laboratory
-00099D Haliplex Communications
-00099E Testech, Inc.
-00099F VIDEX INC.
-0009A0 Microtechno Corporation
-0009A1 Telewise Communications, Inc.
-0009A2 Interface Co., Ltd.
-0009A3 Leadfly Techologies Corp. Ltd.
-0009A4 HARTEC Corporation
-0009A5 HANSUNG ELETRONIC INDUSTRIES DEVELOPMENT CO., LTD
-0009A6 Ignis Optics, Inc.
-0009A7 Bang & Olufsen A/S
-0009A8 Eastmode Pte Ltd
-0009A9 Ikanos Communications
-0009AA Data Comm for Business, Inc.
-0009AB Netcontrol Oy
-0009AC LANVOICE
-0009AD HYUNDAI SYSCOMM, INC.
-0009AE OKANO ELECTRIC CO.,LTD
-0009AF e-generis
-0009B0 Onkyo Corporation
-0009B1 Kanematsu Electronics, Ltd.
-0009B2 L&F Inc.
-0009B3 MCM Systems Ltd
-0009B4 KISAN TELECOM CO., LTD.
-0009B5 3J Tech. Co., Ltd.
-0009B6 Cisco Systems
-0009B7 Cisco Systems
-0009B8 Entise Systems
-0009B9 Action Imaging Solutions
-0009BA MAKU Informationstechik GmbH
-0009BB MathStar, Inc.
-0009BC Digital Safety Technologies Inc.
-0009BD Epygi Technologies, Ltd.
-0009BE Mamiya-OP Co.,Ltd.
-0009BF Nintendo Co.,Ltd.
-0009C0 6WIND
-0009C1 PROCES-DATA A/S
-0009C3 NETAS
-0009C4 Medicore Co., Ltd
-0009C5 KINGENE Technology Corporation
-0009C6 Visionics Corporation
-0009C7 Movistec
-0009C8 SINAGAWA TSUSHIN KEISOU SERVICE
-0009C9 BlueWINC Co., Ltd.
-0009CA iMaxNetworks(Shenzhen)Limited.
-0009CB HBrain
-0009CC Moog GmbH
-0009CD HUDSON SOFT CO.,LTD.
-0009CE SpaceBridge Semiconductor Corp.
-0009CF iAd GmbH
-0009D0 Versatel Networks
-0009D1 SERANOA NETWORKS INC
-0009D2 Mai Logic Inc.
-0009D3 Western DataCom Co., Inc.
-0009D4 Transtech Networks
-0009D5 Signal Communication, Inc.
-0009D6 KNC One GmbH
-0009D7 DC Security Products
-0009D9 Neoscale Systems, Inc
-0009DA Control Module Inc.
-0009DB eSpace
-0009DC Galaxis Technology AG
-0009DD Mavin Technology Inc.
-0009DE Samjin Information & Communications Co., Ltd.
-0009DF Vestel Komunikasyon Sanayi ve Ticaret A.S.
-0009E0 XEMICS S.A.
-0009E1 Gemtek Technology Co., Ltd.
-0009E2 Sinbon Electronics Co., Ltd.
-0009E3 Angel Iglesias S.A.
-0009E4 K Tech Infosystem Inc.
-0009E5 Hottinger Baldwin Messtechnik GmbH
-0009E6 Cyber Switching Inc.
-0009E7 ADC Techonology
-0009E8 Cisco Systems
-0009E9 Cisco Systems
-0009EA YEM Inc.
-0009EB HuMANDATA LTD.
-0009EC Daktronics, Inc.
-0009ED CipherOptics
-0009EE MEIKYO ELECTRIC CO.,LTD
-0009EF Vocera Communications
-0009F0 Shimizu Technology Inc.
-0009F1 Yamaki Electric Corporation
-0009F2 Cohu, Inc., Electronics Division
-0009F3 WELL Communication Corp.
-0009F4 Alcon Laboratories, Inc.
-0009F5 Emerson Network Power Co.,Ltd
-0009F6 Shenzhen Eastern Digital Tech Ltd.
-0009F7 SED, a division of Calian
-0009F8 UNIMO TECHNOLOGY CO., LTD.
-0009F9 ART JAPAN CO., LTD.
-0009FB Philips Medizinsysteme Boeblingen GmbH
-0009FC IPFLEX Inc.
-0009FD Ubinetics Limited
-0009FE Daisy Technologies, Inc.
-0009FF X.net 2000 GmbH
-000A00 Mediatek Corp.
-000A01 SOHOware, Inc.
-000A02 ANNSO CO., LTD.
-000A03 ENDESA SERVICIOS, S.L.
-000A04 3Com Europe Ltd
-000A05 Widax Corp.
-000A06 Teledex LLC
-000A07 WebWayOne Ltd
-000A08 ALPINE ELECTRONICS, INC.
-000A09 TaraCom Integrated Products, Inc.
-000A0A SUNIX Co., Ltd.
-000A0B Sealevel Systems, Inc.
-000A0C Scientific Research Corporation
-000A0D MergeOptics GmbH
-000A0E Invivo Research Inc.
-000A0F Ilryung Telesys, Inc
-000A10 FAST media integrations AG
-000A11 ExPet Technologies, Inc
-000A12 Azylex Technology, Inc
-000A13 Silent Witness
-000A14 TECO a.s.
-000A15 Silicon Data, Inc
-000A16 Lassen Research
-000A17 NESTAR COMMUNICATIONS, INC
-000A18 Vichel Inc.
-000A19 Valere Power, Inc.
-000A1A Imerge Ltd
-000A1B Stream Labs
-000A1C Bridge Information Co., Ltd.
-000A1D Optical Communications Products Inc.
-000A1E Red-M (Communications) Limited
-000A1F ART WARE Telecommunication Co., Ltd.
-000A20 SVA Networks, Inc.
-000A21 Integra Telecom Co. Ltd
-000A22 Amperion Inc
-000A23 Parama Networks Inc
-000A24 Octave Communications
-000A25 CERAGON NETWORKS
-000A26 CEIA S.p.A.
-000A27 Apple Computer, Inc.
-000A28 Motorola
-000A29 Pan Dacom Networking AG
-000A2A QSI Systems Inc.
-000A2B Etherstuff
-000A2C Active Tchnology Corporation
-000A2E MAPLE NETWORKS CO., LTD
-000A2F Artnix Inc.
-000A30 Johnson Controls-ASG
-000A31 HCV Wireless
-000A32 Xsido Corporation
-000A33 Sierra Logic, Inc.
-000A34 Identicard Systems Incorporated
-000A35 Xilinx
-000A36 Synelec Telecom Multimedia
-000A37 Procera Networks, Inc.
-000A38 Netlock Technologies, Inc.
-000A39 LoPA Information Technology
-000A3A J-THREE INTERNATIONAL Holding Co., Ltd.
-000A3B GCT Semiconductor, Inc
-000A3C Enerpoint Ltd.
-000A3D Elo Sistemas Eletronicos S.A.
-000A3E EADS Telecom
-000A3F Data East Corporation
-000A40 Crown Audio
-000A41 Cisco Systems
-000A42 Cisco Systems
-000A43 Chunghwa Telecom Co., Ltd.
-000A44 Avery Dennison Deutschland GmbH
-000A45 Audio-Technica Corp.
-000A46 ARO Controls SAS
-000A47 Allied Vision Technologies
-000A48 Albatron Technology
-000A49 Acopia Networks
-000A4A Targa Systems Ltd.
-000A4B DataPower Technology, Inc.
-000A4C Molecular Devices Corporation
-000A4D Noritz Corporation
-000A4E UNITEK Electronics INC.
-000A4F Brain Boxes Limited
-000A50 REMOTEK CORPORATION
-000A51 GyroSignal Technology Co., Ltd.
-000A52 Venitek Co. Ltd.
-000A53 Intronics, Incorporated
-000A54 Laguna Hills, Inc.
-000A55 MARKEM Corporation
-000A56 HITACHI Maxell Ltd.
-000A57 Hewlett-Packard Company - Standards
-000A58 Ingenieur-Buero Freyer & Siegel
-000A59 HW server
-000A5A GreenNET Technologies Co.,Ltd.
-000A5B Power-One as
-000A5C Carel s.p.a.
-000A5D PUC Founder (MSC) Berhad
-000A5E 3COM Corporation
-000A5F almedio inc.
-000A60 Autostar Technology Pte Ltd
-000A61 Cellinx Systems Inc.
-000A62 Crinis Networks, Inc.
-000A63 DHD GmbH
-000A64 Eracom Technologies
-000A65 GentechMedia.co.,ltd.
-000A66 MITSUBISHI ELECTRIC SYSTEM & SERVICE CO.,LTD.
-000A67 OngCorp
-000A68 SolarFlare Communications, Inc.
-000A69 SUNNY bell Technology Co., Ltd.
-000A6A SVM Microwaves s.r.o.
-000A6B Tadiran Telecom Business Systems LTD
-000A6C Walchem Corporation
-000A6D EKS Elektronikservice GmbH
-000A6E Broadcast Technology Limited
-000A6F ZyTera Technologies Inc.
-000A70 MPLS Forum
-000A71 Avrio Technologies, Inc
-000A72 SimpleTech, Inc.
-000A73 Scientific Atlanta
-000A74 Manticom Networks Inc.
-000A75 Cat Electronics
-000A76 Beida Jade Bird Huaguang Technology Co.,Ltd
-000A77 Bluewire Technologies LLC
-000A78 OLITEC
-000A79 corega K.K.
-000A7A Kyoritsu Electric Co., Ltd.
-000A7B Cornelius Consult
-000A7C Tecton Ltd
-000A7D Valo, Inc.
-000A7E The Advantage Group
-000A7F Teradon Industries, Inc
-000A80 Telkonet Inc.
-000A81 TEIMA Audiotex S.L.
-000A82 TATSUTA SYSTEM ELECTRONICS CO.,LTD.
-000A83 SALTO SYSTEMS S.L.
-000A84 Rainsun Enterprise Co., Ltd.
-000A85 PLAT'C2,Inc
-000A86 Lenze
-000A87 Integrated Micromachines Inc.
-000A88 InCypher S.A.
-000A89 Creval Systems, Inc.
-000A8A Cisco Systems
-000A8B Cisco Systems
-000A8C Guardware Systems Ltd.
-000A8D EUROTHERM LIMITED
-000A8E Invacom Ltd
-000A8F Aska International Inc.
-000A90 Bayside Interactive, Inc.
-000A91 HemoCue AB
-000A92 Presonus Corporation
-000A93 W2 Networks, Inc.
-000A94 ShangHai cellink CO., LTD
-000A95 Apple Computer, Inc.
-000A96 MEWTEL TECHNOLOGY INC.
-000A97 SONICblue, Inc.
-000A98 M+F Gwinner GmbH & Co
-000A99 Dataradio Inc.
-000A9A Aiptek International Inc
-000A9B Towa Meccs Corporation
-000A9C Server Technology, Inc.
-000A9D King Young Technology Co. Ltd.
-000A9E BroadWeb Corportation
-000A9F Pannaway Technologies, Inc.
-000AA0 Cedar Point Communications
-000AA1 V V S Limited
-000AA2 SYSTEK INC.
-000AA3 SHIMAFUJI ELECTRIC CO.,LTD.
-000AA4 SHANGHAI SURVEILLANCE TECHNOLOGY CO,LTD
-000AA5 MAXLINK INDUSTRIES LIMITED
-000AA6 Hochiki Corporation
-000AA7 FEI Company
-000AA8 ePipe Pty. Ltd.
-000AA9 Brooks Automation GmbH
-000AAA AltiGen Communications Inc.
-000AAB TOYOTA MACS, INC.
-000AAC TerraTec Electronic GmbH
-000AAD Stargames Corporation
-000AAE Rosemount Process Analytical
-000AAF Pipal Systems
-000AB0 LOYTEC electronics GmbH
-000AB1 GENETEC Corporation
-000AB2 Fresnel Wireless Systems
-000AB3 Fa. GIRA
-000AB4 ETIC Telecommunications
-000AB5 Digital Electronic Network
-000AB6 COMPUNETIX, INC
-000AB7 Cisco Systems
-000AB8 Cisco Systems
-000AB9 Astera Technologies Corp.
-000ABA Arcon Technology Limited
-000ABB Taiwan Secom Co,. Ltd
-000ABC Seabridge Ltd.
-000ABD Rupprecht & Patashnick Co.
-000ABE OPNET Technologies CO., LTD.
-000ABF HIROTA SS
-000AC0 Fuyoh Video Industry CO., LTD.
-000AC1 Futuretel
-000AC2 FiberHome Telecommunication Technologies CO.,LTD
-000AC3 eM Technics Co., Ltd.
-000AC4 Daewoo Teletech Co., Ltd
-000AC5 Color Kinetics
-000AC7 Unication Group
-000AC8 ZPSYS CO.,LTD. (Planning&Management)
-000AC9 Zambeel Inc
-000ACA YOKOYAMA SHOKAI CO.,Ltd.
-000ACB XPAK MSA Group
-000ACC Winnow Networks, Inc.
-000ACD Sunrich Technology Limited
-000ACE RADIANTECH, INC.
-000ACF PROVIDEO Multimedia Co. Ltd.
-000AD0 Niigata Develoment Center,  F.I.T. Co., Ltd.
-000AD1 MWS
-000AD2 JEPICO Corporation
-000AD3 INITECH Co., Ltd
-000AD4 CoreBell Systems Inc.
-000AD5 Brainchild Electronic Co., Ltd.
-000AD6 BeamReach Networks
-000AD8 IPCserv Technology Corp.
-000AD9 Sony Ericsson Mobile Communications AB
-000ADB SkyPilot Network, Inc
-000ADC RuggedCom Inc.
-000ADD InSciTek Microsystems, Inc.
-000ADE Happy Communication Co., Ltd.
-000ADF Gennum Corporation
-000AE0 Fujitsu Softek
-000AE1 EG Technology
-000AE2 Binatone Electronics International, Ltd
-000AE3 YANG MEI TECHNOLOGY CO., LTD
-000AE4 Wistron Corp.
-000AE5 ScottCare Corporation
-000AE6 Elitegroup Computer System Co. (ECS)
-000AE7 ELIOP S.A.
-000AE8 Cathay Roxus Information Technology Co. LTD
-000AE9 AirVast Technology Inc.
-000AEA ADAM ELEKTRONIK LTD.STI.
-000AEB Shenzhen Tp-link Technology Co; Ltd.
-000AEC Koatsu Gas Kogyo Co., Ltd.
-000AED HARTING Vending G.m.b.H. & CO KG
-000AEE GCD Hard- & Software GmbH
-000AEF OTRUM ASA
-000AF0 SHIN-OH ELECTRONICS CO., LTD. R&D
-000AF1 Clarity Design, Inc.
-000AF2 NeoAxiom Corp.
-000AF3 Cisco Systems
-000AF4 Cisco Systems
-000AF5 Airgo Networks, Inc.
-000AF6 Computer Process Controls
-000AF7 Broadcom Corp.
-000AF8 American Telecare Inc.
-000AFA Traverse Technologies Australia
-000AFB Ambri Limited
-000AFC Core Tec Communications, LLC
-000AFD Viking Electronic Services
-000AFE NovaPal Ltd
-000AFF Kilchherr Elektronik AG
-000B00 FUJIAN START COMPUTER EQUIPMENT CO.,LTD
-000B01 DAIICHI ELECTRONICS CO., LTD.
-000B02 Dallmeier electronic
-000B03 Taekwang Industrial Co., Ltd
-000B04 Volktek Corporation
-000B05 Pacific Broadband Networks
-000B06 Motorola BCS
-000B07 Voxpath Networks
-000B08 Pillar Data Systems
-000B09 Ifoundry Systems Singapore
-000B0A dBm Optics
-000B0B Corrent Corporation
-000B0C Agile Systems Inc.
-000B0D Air2U, Inc.
-000B0E Trapeze Networks
-000B0F Nyquist Industrial Control BV
-000B10 11wave Technonlogy Co.,Ltd
-000B11 HIMEJI ABC TRADING CO.,LTD.
-000B13 ZETRON INC
-000B14 ViewSonic Corporation
-000B15 Platypus Technology
-000B16 Communication Machinery Corporation
-000B17 MKS Instruments
-000B19 Vernier Networks, Inc.
-000B1A Teltone Corporation
-000B1B Systronix, Inc.
-000B1D LayerZero Power Systems, Inc.
-000B1E KAPPA opto-electronics GmbH
-000B1F I CON Computer Co.
-000B20 Hirata corporation
-000B21 G-Star Communications Inc.
-000B22 Environmental Systems and Services
-000B23 Efficient Networks, Inc.
-000B24 AirLogic
-000B25 Aeluros
-000B26 Wetek Corporation
-000B27 Scion Corporation
-000B28 Quatech Inc.
-000B29 LG Industrial Systems Co.,Ltd.
-000B2A HOWTEL Co., Ltd.
-000B2B HOSTNET CORPORATION
-000B2C Eiki Industrial Co. Ltd.
-000B2D Danfoss Inc.
-000B2E Cal-Comp Electronics (Thailand) Public Company Limited Taipe
-000B2F bplan GmbH
-000B30 Beijing Gongye Science & Technology Co.,Ltd
-000B31 Yantai ZhiYang Scientific and technology industry CO., LTD
-000B32 VORMETRIC, INC.
-000B33 Vivato
-000B34 ShangHai Broadband Technologies CO.LTD
-000B35 Quad Bit System co., Ltd.
-000B36 Productivity Systems, Inc.
-000B37 MANUFACTURE DES MONTRES ROLEX SA
-000B38 Knuerr AG
-000B39 Keisoku Giken Co.,Ltd.
-000B3A Fortel DTV, Inc.
-000B3B devolo AG
-000B3C Cygnal Integrated Products, Inc.
-000B3D CONTAL OK Ltd.
-000B3E BittWare, Inc
-000B3F Anthology Solutions Inc.
-000B40 OpNext Inc.
-000B41 Ing. Buero Dr. Beutlhauser
-000B42 commax Co., Ltd.
-000B43 Microscan Systems, Inc.
-000B44 Concord IDea Corp.
-000B45 Cisco
-000B46 Cisco
-000B47 Advanced Energy
-000B48 sofrel
-000B49 RF-Link System Inc.
-000B4A Visimetrics (UK) Ltd
-000B4B VISIOWAVE SA
-000B4C Clarion (M) Sdn Bhd
-000B4D Emuzed
-000B4E VertexRSI Antenna Products Division
-000B4F Verifone, INC.
-000B50 Oxygnet
-000B51 Micetek International Inc.
-000B52 JOYMAX ELECTRONICS CORP.
-000B53 INITIUM Co., Ltd.
-000B54 BiTMICRO Networks, Inc.
-000B55 ADInstruments
-000B56 Cybernetics
-000B57 Silicon Laboratories
-000B58 Astronautics C.A  LTD
-000B59 ScriptPro, LLC
-000B5A HyperEdge
-000B5B Rincon Research Corporation
-000B5C Newtech Co.,Ltd
-000B5D FUJITSU LIMITED
-000B5E ATMAVA Ltd
-000B5F Cisco Systems
-000B60 Cisco Systems
-000B61 Friedrich Lütze GmbH &Co.
-000B62 Ingenieurbüro Ingo Mohnen
-000B64 Kieback & Peter GmbH & Co KG
-000B65 Sy.A.C. srl
-000B66 Teralink Communications
-000B67 Topview Technology Corporation
-000B68 Addvalue Communications Pte Ltd
-000B69 Franke Finland Oy
-000B6A Asiarock Incorporation
-000B6B Wistron Neweb Corp.
-000B6C Sychip Inc.
-000B6D SOLECTRON JAPAN NAKANIIDA
-000B6E Neff Instrument Corp.
-000B6F Media Streaming Networks Inc
-000B70 Load Technology, Inc.
-000B71 Litchfield Communications Inc.
-000B72 Lawo AG
-000B73 Kodeos Communications
-000B74 Kingwave Technology Co., Ltd.
-000B75 Iosoft Ltd.
-000B76 ET&T Co. Ltd.
-000B77 Cogent Systems, Inc.
-000B78 TAIFATECH INC.
-000B79 X-COM, Inc.
-000B7B Test-Um Inc.
-000B7C Telex Communications
-000B7D SOLOMON EXTREME INTERNATIONAL LTD.
-000B7E SAGINOMIYA Seisakusho Inc.
-000B7F OmniWerks
-000B81 Kaparel Corporation
-000B82 Grandstream Networks, Inc.
-000B83 DATAWATT B.V.
-000B84 BODET
-000B85 Airespace, Inc.
-000B86 Aruba Networks
-000B87 American Reliance Inc.
-000B88 Vidisco ltd.
-000B89 Top Global Technology, Ltd.
-000B8A MITEQ Inc.
-000B8B KERAJET, S.A.
-000B8C flextronics israel
-000B8D Avvio Networks
-000B8E Ascent Corporation
-000B8F AKITA ELECTRONICS SYSTEMS CO.,LTD.
-000B90 Covaro Networks, Inc.
-000B91 Aglaia Gesellschaft für Bildverarbeitung und Kommunikation m
-000B92 Ascom Danmark A/S
-000B93 Barmag Electronic
-000B94 Digital Monitoring Products, Inc.
-000B95 eBet Gaming Systems Pty Ltd
-000B96 Innotrac Diagnostics Oy
-000B97 Matsushita Electric Industrial Co.,Ltd.
-000B98 NiceTechVision
-000B99 SensAble Technologies, Inc.
-000B9A Shanghai Ulink Telecom Equipment Co. Ltd.
-000B9B Sirius System Co, Ltd.
-000B9C TriBeam Technologies, Inc.
-000B9D TwinMOS Technologies Inc.
-000B9E Yasing Technology Corp.
-000B9F Neue ELSA GmbH
-000BA0 T&L Information Inc.
-000BA1 SYSCOM Ltd.
-000BA2 Sumitomo Electric Networks, Inc
-000BA3 Siemens AG, I&S
-000BA4 Shiron Satellite Communications Ltd. (1996)
-000BA5 Quasar Cipta Mandiri, PT
-000BA6 Miyakawa Electric Works Ltd.
-000BA7 Maranti Networks
-000BA8 HANBACK ELECTRONICS CO., LTD.
-000BAA Aiphone co.,Ltd
-000BAB Advantech Technology (CHINA) Co., Ltd.
-000BAC 3Com Europe Ltd.
-000BAD PC-PoS Inc.
-000BAE Vitals System Inc.
-000BB0 Sysnet Telematica srl
-000BB1 Super Star Technology Co., Ltd.
-000BB2 SMALLBIG TECHNOLOGY
-000BB3 RiT technologies Ltd.
-000BB4 RDC Semiconductor Inc.,
-000BB5 nStor Technologies, Inc.
-000BB6 Mototech Inc.
-000BB7 Micro Systems Co.,Ltd.
-000BB8 Kihoku Electronic Co.
-000BB9 Imsys AB
-000BBA Harmonic Broadband Access Networks
-000BBB Etin Systems Co., Ltd
-000BBC En Garde Systems, Inc.
-000BBD Connexionz Limited
-000BBE Cisco Systems
-000BBF Cisco Systems
-000BC0 China IWNComm Co., Ltd.
-000BC1 Bay Microsystems, Inc.
-000BC2 Corinex Communication Corp.
-000BC3 Multiplex, Inc.
-000BC4 BIOTRONIK GmbH & Co
-000BC5 SMC Networks, Inc.
-000BC6 ISAC, Inc.
-000BC7 ICET S.p.A.
-000BC8 AirFlow Networks
-000BC9 Electroline Equipment
-000BCA DATAVAN International Corporation
-000BCB Fagor Automation , S. Coop
-000BCC JUSAN, S.A.
-000BCD Compaq (HP)
-000BCE Free2move AB
-000BCF AGFA NDT INC.
-000BD0 XiMeta Technology Americas Inc.
-000BD1 Aeronix, Inc.
-000BD2 Remopro Technology Inc.
-000BD3 cd3o
-000BD4 Beijing Wise Technology & Science Development Co.Ltd
-000BD5 Nvergence, Inc.
-000BD6 Paxton Access Ltd
-000BD7 MBB Gelma GmbH
-000BD8 Industrial Scientific Corp.
-000BD9 General Hydrogen
-000BDA EyeCross Co.,Inc.
-000BDB Dell ESG PCBA Test
-000BDC AKCP
-000BDD TOHOKU RICOH Co., LTD.
-000BDF Shenzhen RouterD Networks Limited
-000BE0 SercoNet Ltd.
-000BE2 Lumenera Corporation
-000BE3 Key Stream Co., Ltd.
-000BE4 Hosiden Corporation
-000BE5 HIMS Korea Co., Ltd.
-000BE6 Datel Electronics
-000BE7 COMFLUX TECHNOLOGY INC.
-000BE8 AOIP
-000BEA Zultys Technologies
-000BEB Systegra AG
-000BEC NIPPON ELECTRIC INSTRUMENT, INC.
-000BED ELM Inc.
-000BEE inc.jet, Incorporated
-000BEF Code Corporation
-000BF0 MoTEX Products Co., Ltd.
-000BF1 LAP Laser Applikations
-000BF2 Chih-Kan Technology Co., Ltd.
-000BF3 BAE SYSTEMS
-000BF5 Shanghai Sibo Telecom Technology Co.,Ltd
-000BF6 Nitgen Co., Ltd
-000BF7 NIDEK CO.,LTD
-000BF8 Infinera
-000BF9 Gemstone communications, Inc.
-000BFB D-NET International Corporation
-000BFC Cisco Systems
-000BFD Cisco Systems
-000BFE CASTEL Broadband Limited
-000BFF Berkeley Camera Engineering
-000C00 BEB Industrie-Elektronik AG
-000C01 Abatron AG
-000C02 ABB Oy
-000C03 HDMI Licensing, LLC
-000C04 Tecnova
-000C05 RPA Reserch Co., Ltd.
-000C06 Nixvue Systems  Pte Ltd
-000C07 Iftest AG
-000C08 HUMEX Technologies Corp.
-000C09 Hitachi IE Systems Co., Ltd
-000C0A Guangdong Province Electronic Technology Research Institute
-000C0B Broadbus Technologies
-000C0C APPRO TECHNOLOGY INC.
-000C0D Communications & Power Industries / Satcom Division
-000C0E XtremeSpectrum, Inc.
-000C0F Techno-One Co., Ltd
-000C10 PNI Corporation
-000C11 NIPPON DEMPA CO.,LTD.
-000C12 Micro-Optronic-Messtechnik GmbH
-000C13 MediaQ
-000C14 Diagnostic Instruments, Inc.
-000C15 CyberPower Systems, Inc.
-000C16 Concorde Microsystems Inc.
-000C17 AJA Video Systems Inc
-000C18 Zenisu Keisoku Inc.
-000C19 Telio Communications GmbH
-000C1A Quest Technical Solutions Inc.
-000C1B ORACOM Co, Ltd.
-000C1C MicroWeb Co., Ltd.
-000C1D Mettler & Fuchs AG
-000C1E Global Cache
-000C1F Glimmerglass Networks
-000C20 Fi WIn, Inc.
-000C21 Faculty of Science and Technology, Keio University
-000C22 Double D Electronics Ltd
-000C23 Beijing Lanchuan Tech. Co., Ltd.
-000C25 Allied Telesyn Networks
-000C26 Weintek Labs. Inc.
-000C27 Sammy Corporation
-000C28 RIFATRON
-000C29 VMware, Inc.
-000C2A OCTTEL Communication Co., Ltd.
-000C2B ELIAS Technology, Inc.
-000C2C Enwiser Inc.
-000C2D FullWave Technology Co., Ltd.
-000C2E Openet information technology(shenzhen) Co., Ltd.
-000C2F SeorimTechnology Co.,Ltd.
-000C30 Cisco
-000C31 Cisco
-000C32 Avionic Design Development GmbH
-000C33 Compucase Enterprise Co. Ltd.
-000C34 Vixen Co., Ltd.
-000C35 KaVo Dental GmbH & Co. KG
-000C36 SHARP TAKAYA ELECTRONICS INDUSTRY CO.,LTD.
-000C37 Geomation, Inc.
-000C38 TelcoBridges Inc.
-000C39 Sentinel Wireless Inc.
-000C3A Oxance
-000C3B Orion Electric Co., Ltd.
-000C3C MediaChorus, Inc.
-000C3D Glsystech Co., Ltd.
-000C3E Crest Audio
-000C3F Cogent Defence & Security Networks,
-000C40 Altech Controls
-000C41 The Linksys Group, Inc.
-000C42 Routerboard.com
-000C43 Ralink Technology, Corp.
-000C44 Automated Interfaces, Inc.
-000C45 Animation Technologies Inc.
-000C46 Allied Telesyn Inc.
-000C47 SK Teletech(R&D Planning Team)
-000C48 QoStek Corporation
-000C49 Dangaard Telecom RTC Division A/S
-000C4A Cygnus Microsystems Private Limited
-000C4B Cheops Elektronik
-000C4C Arcor AG&Co.
-000C4D ACRA CONTROL
-000C4E Winbest Technology CO,LT
-000C4F UDTech Japan Corporation
-000C50 Seagate Technology
-000C51 Scientific Technologies Inc.
-000C52 Roll Systems Inc.
-000C54 Pedestal Networks, Inc
-000C55 Microlink Communications Inc.
-000C56 Megatel Computer (1986) Corp.
-000C57 MACKIE Engineering Services Belgium BVBA
-000C58 M&S Systems
-000C59 Indyme Electronics, Inc.
-000C5A IBSmm Industrieelektronik Multimedia
-000C5B HANWANG TECHNOLOGY CO.,LTD
-000C5C GTN Systems B.V.
-000C5D CHIC TECHNOLOGY (CHINA) CORP.
-000C5F Avtec, Inc.
-000C60 ACM Systems
-000C61 AC Tech corporation DBA Advanced Digital
-000C62 ABB Automation Technology Products AB, Control
-000C63 Zenith Electronics Corporation
-000C64 X2 MSA Group
-000C65 Sunin Telecom
-000C66 Pronto Networks Inc
-000C67 OYO ELECTRIC CO.,LTD
-000C68 Oasis Semiconductor, Inc.
-000C69 National Radio Astronomy Observatory
-000C6A MBARI
-000C6B Kurz Industrie-Elektronik GmbH
-000C6C Elgato Systems LLC
-000C6D BOC Edwards
-000C6E ASUSTEK COMPUTER INC.
-000C6F Amtek system co.,LTD.
-000C70 ACC GmbH
-000C71 Wybron, Inc
-000C72 Tempearl Industrial Co., Ltd.
-000C73 TELSON ELECTRONICS CO., LTD
-000C74 RIVERTEC CORPORATION
-000C75 Oriental integrated electronics. LTD
-000C76 MICRO-STAR INTERNATIONAL CO., LTD.
-000C77 Life Racing Ltd
-000C78 In-Tech Electronics Limited
-000C79 Extel Communications P/L
-000C7A DaTARIUS Technologies GmbH
-000C7B ALPHA PROJECT Co.,Ltd.
-000C7C Internet Information Image Inc.
-000C7D TEIKOKU ELECTRIC MFG. CO., LTD
-000C7E Tellium Incorporated
-000C7F synertronixx GmbH
-000C80 Opelcomm Inc.
-000C81 Nulec Industries Pty Ltd
-000C82 NETWORK TECHNOLOGIES INC
-000C83 Logical Solutions
-000C84 Eazix, Inc.
-000C85 Cisco Systems
-000C86 Cisco Systems
-000C87 ATI
-000C88 Apache Micro Peripherals, Inc.
-000C89 AC Electric Vehicles, Ltd.
-000C8A Bose Corporation
-000C8B Connect Tech Inc
-000C8C KODICOM CO.,LTD.
-000C8D MATRIX VISION GmbH
-000C8E Mentor Engineering Inc
-000C8F Nergal s.r.l.
-000C90 Octasic Inc.
-000C91 Riverhead Networks Inc.
-000C92 WolfVision Gmbh
-000C93 Xeline Co., Ltd.
-000C94 United Electronic Industries, Inc.
-000C95 PrimeNet
-000C96 OQO, Inc.
-000C97 NV ADB TTV Technologies SA
-000C98 LETEK Communications Inc.
-000C99 HITEL LINK Co.,Ltd
-000C9A Hitech Electronics Corp.
-000C9B EE Solutions, Inc
-000C9C Chongho information & communications
-000C9D AirWalk Communications, Inc.
-000C9E MemoryLink Corp.
-000C9F NKE Corporation
-000CA0 StorCase Technology, Inc.
-000CA1 SIGMACOM Co., LTD.
-000CA2 Scopus Network Technologies Ltd
-000CA3 Rancho Technology, Inc.
-000CA4 Prompttec Product Management GmbH
-000CA6 Mintera Corporation
-000CA7 Metro (Suzhou) Technologies Co., Ltd.
-000CA8 Garuda Networks Corporation
-000CA9 Ebtron Inc.
-000CAA Cubic Transportation Systems Inc
-000CAB COMMEND International
-000CAC Citizen Watch Co., Ltd.
-000CAD BTU International
-000CAE Ailocom Oy
-000CAF TRI TERM CO.,LTD.
-000CB0 Star Semiconductor Corporation
-000CB1 Salland Engineering (Europe) BV
-000CB2 safei Co., Ltd.
-000CB3 ROUND Co.,Ltd.
-000CB4 Propagate Networks, Inc
-000CB5 Premier Technolgies, Inc
-000CB6 NANJING SEU MOBILE & INTERNET TECHNOLOGY CO.,LTD
-000CB7 Nanjing Huazhuo Electronics Co., Ltd.
-000CB8 MEDION AG
-000CB9 LEA
-000CBA Jamex
-000CBB ISKRAEMECO
-000CBC Iscutum
-000CBD Interface Masters, Inc
-000CBF Holy Stone Ent. Co., Ltd.
-000CC0 Genera Oy
-000CC1 Cooper Industries Inc.
-000CC3 BeWAN systems
-000CC4 Tiptel AG
-000CC5 Nextlink Co., Ltd.
-000CC6 Ka-Ro electronics GmbH
-000CC7 Intelligent Computer Solutions Inc.
-000CC8 Integrated Digital Systems, Inc.
-000CC9 ILWOO DATA & TECHNOLOGY CO.,LTD
-000CCA Hitachi Global Storage Technologies
-000CCB Design Combus Ltd
-000CCC Bluesoft Ltd.
-000CCD IEC - TC57
-000CCE Cisco Systems
-000CCF Cisco Systems
-000CD0 Symetrix
-000CD1 SFOM Technology Corp.
-000CD2 Schaffner EMV AG
-000CD3 Prettl Elektronik Radeberg GmbH
-000CD4 Positron Public Safety Systems inc.
-000CD5 Passave Inc.
-000CD6 PARTNER TECH
-000CD7 Nallatech Ltd
-000CD8 M. K. Juchheim GmbH & Co
-000CD9 Itcare Co., Ltd
-000CDA FreeHand Systems, Inc.
-000CDB Foundry Networks
-000CDC BECS Technology, Inc
-000CDD AOS Technologies AG
-000CDE ABB STOTZ-KONTAKT GmbH
-000CDF PULNiX America, Inc
-000CE0 Trek Diagnostics Inc.
-000CE1 The Open Group
-000CE2 Rolls-Royce
-000CE3 Option International N.V.
-000CE4 NeuroCom International, Inc.
-000CE5 Motorola BCS
-000CE6 Meru Networks Inc
-000CE7 MediaTek Inc.
-000CE8 GuangZhou AnJuBao Co., Ltd
-000CE9 BLOOMBERG L.P.
-000CEA aphona Kommunikationssysteme
-000CEB CNMP Networks, Inc.
-000CEC Spectracom Corp.
-000CED Real Digital Media
-000CEE Q-Networks
-000CEF Open Networks Engineering Ltd
-000CF0 M & N GmbH
-000CF1 Intel Corporation
-000CF2 GAMESA EÓLICA
-000CF3 CALL IMAGE SA
-000CF4 AKATSUKI ELECTRIC MFG.CO.,LTD.
-000CF5 InfoExpress
-000CF6 Sitecom Europe BV
-000CF7 Nortel Networks
-000CF8 Nortel Networks
-000CF9 ITT Flygt AB
-000CFA Digital Systems Corp
-000CFB Korea Network Systems
-000CFC S2io Technologies Corp
-000CFE Grand Electronic Co., Ltd
-000CFF MRO-TEK LIMITED
-000D00 Seaway Networks Inc.
-000D01 P&E Microcomputer Systems, Inc.
-000D02 NEC Access Technica,Ltd
-000D03 Matrics, Inc.
-000D04 Foxboro Eckardt Development GmbH
-000D05 cybernet manufacturing inc.
-000D06 Compulogic Limited
-000D07 Calrec Audio Ltd
-000D08 AboveCable, Inc.
-000D09 Yuehua(Zhuhai) Electronic CO. LTD
-000D0A Projectiondesign as
-000D0B Melco Inc.
-000D0C MDI Security Systems
-000D0D ITSupported, LLC
-000D0E Inqnet Systems, Inc.
-000D0F Finlux Ltd
-000D10 Embedtronics Oy
-000D11 DENTSPLY - Gendex
-000D12 AXELL Corporation
-000D13 Wilhelm Rutenbeck GmbH&Co.
-000D14 Vtech Innovation LP dba Advanced American Telephones
-000D15 Voipac s.r.o.
-000D16 UHS Systems Pty Ltd
-000D17 Turbo Networks Co.Ltd
-000D18 Sunitec Enterprise Co., Ltd.
-000D19 ROBE Show lighting
-000D1A Mustek System Inc.
-000D1B Kyoto Electronics Manufacturing Co., Ltd.
-000D1C I2E TELECOM
-000D1D HIGH-TEK HARNESS ENT. CO., LTD.
-000D1E Control Techniques
-000D1F AV Digital
-000D20 ASAHIKASEI TECHNOSYSTEM CO.,LTD.
-000D21 WISCORE Inc.
-000D22 Unitronics
-000D23 Smart Solution, Inc
-000D24 SENTEC E&E CO., LTD.
-000D25 SANDEN CORPORATION
-000D26 Primagraphics Limited
-000D27 MICROPLEX Printware AG
-000D28 Cisco
-000D29 Cisco
-000D2A Scanmatic AS
-000D2B Racal Instruments
-000D2C Patapsco Designs Ltd
-000D2D NCT Deutschland GmbH
-000D2E Matsushita Avionics Systems Corporation
-000D2F AIN Comm.Tech.Co., LTD
-000D30 IceFyre Semiconductor
-000D31 Compellent Technologies, Inc.
-000D32 DispenseSource, Inc.
-000D33 Prediwave Corp.
-000D34 Shell International Exploration and Production, Inc.
-000D35 PAC International Ltd
-000D36 Wu Han Routon Electronic Co., Ltd
-000D37 WIPLUG
-000D38 NISSIN INC.
-000D39 Network Electronics
-000D3A Microsoft Corp.
-000D3B Microelectronics Technology Inc.
-000D3C i.Tech Dynamic Ltd
-000D3E APLUX Communications Ltd.
-000D3F VXI Technology
-000D40 Verint Loronix Video Solutions
-000D41 Siemens AG ICM MP UC RD IT KLF1
-000D42 Newbest Development Limited
-000D43 DRS Tactical Systems Inc.
-000D45 Tottori SANYO Electric Co., Ltd.
-000D46 Eurotherm Drives, Ltd.
-000D47 Collex
-000D48 AEWIN Technologies Co., Ltd.
-000D49 Triton Systems of Delaware, Inc.
-000D4A Steag ETA-Optik
-000D4B Roku, LLC
-000D4C Outline Electronics Ltd.
-000D4D Ninelanes
-000D4E NDR Co.,LTD.
-000D4F Kenwood Corporation
-000D50 Galazar Networks
-000D51 DIVR Systems, Inc.
-000D52 Comart system
-000D53 Beijing 5w Communication Corp.
-000D54 3Com Europe Ltd
-000D55 SANYCOM Technology Co.,Ltd
-000D56 Dell PCBA Test
-000D57 Fujitsu I-Network Systems Limited.
-000D59 Amity Systems, Inc.
-000D5A Tiesse SpA
-000D5B Smart Empire Investments Limited
-000D5C Robert Bosch GmbH, VT-ATMO
-000D5D Raritan Computer, Inc
-000D5E NEC CustomTechnica, Ltd.
-000D5F Minds Inc
-000D60 IBM Corporation
-000D61 Giga-Byte Technology Co., Ltd.
-000D62 Funkwerk Dabendorf GmbH
-000D63 DENT Instruments, Inc.
-000D64 COMAG Handels AG
-000D65 Cisco Systems
-000D66 Cisco Systems
-000D67 BelAir Networks Inc.
-000D68 Vinci Systems, Inc.
-000D69 TMT&D Corporation
-000D6A Redwood Technologies LTD
-000D6B Mita-Teknik A/S
-000D6C M-Audio
-000D6D K-Tech Devices Corp.
-000D6E K-Patents Oy
-000D6F Ember Corporation
-000D70 Datamax Corporation
-000D71 boca systems
-000D72 2Wire, Inc
-000D73 Technical Support, Inc.
-000D74 Sand Network Systems, Inc.
-000D75 Kobian Pte Ltd - Taiwan Branch
-000D76 Hokuto Denshi Co,. Ltd.
-000D77 FalconStor Software
-000D78 Engineering & Security
-000D79 Dynamic Solutions Co,.Ltd.
-000D7A DiGATTO Asia Pacific Pte Ltd
-000D7B Consensys Computers Inc.
-000D7C Codian Ltd
-000D7D Afco Systems
-000D7E Axiowave Networks, Inc.
-000D7F MIDAS  COMMUNICATION TECHNOLOGIES PTE LTD ( Foreign Branch)
-000D80 Online Development Inc
-000D81 Pepperl+Fuchs GmbH
-000D82 PHS srl
-000D83 Sanmina-SCI Hungary  Ltd.
-000D84 Seodu Inchip, Inc.
-000D85 Tapwave, Inc.
-000D86 Huber + Suhner AG
-000D87 Elitegroup Computer System Co. (ECS)
-000D88 D-Link Corporation
-000D89 Bils Technology Inc
-000D8A Winners Electronics Co., Ltd.
-000D8B T&D Corporation
-000D8C Shanghai Wedone Digital Ltd. CO.
-000D8D ProLinx Communication Gateways, Inc.
-000D8E Koden Electronics Co., Ltd.
-000D8F King Tsushin Kogyo Co., LTD.
-000D90 Factum Electronics AB
-000D91 Eclipse (HQ Espana) S.L.
-000D92 Arima Communication Corporation
-000D93 Apple Computer
-000D94 AFAR Communications,Inc
-000D96 Vtera Technology Inc.
-000D97 Tropos Networks, Inc.
-000D98 S.W.A.C. Schmitt-Walter Automation Consult GmbH
-000D99 Orbital Sciences Corp.; Launch Systems Group
-000D9A INFOTEC LTD
-000D9C Elan GmbH & Co KG
-000D9D Hewlett Packard
-000D9E TOKUDEN OHIZUMI SEISAKUSYO Co.,Ltd.
-000D9F RF Micro Devices
-000DA0 NEDAP N.V.
-000DA1 MIRAE ITS Co.,LTD.
-000DA2 Infrant Technologies, Inc.
-000DA3 Emerging Technologies Limited
-000DA4 DOSCH & AMAND SYSTEMS AG
-000DA5 Fabric7 Systems, Inc
-000DA6 Universal Switching Corporation
-000DA8 Teletronics Technology Corporation
-000DA9 T.E.A.M. S.L.
-000DAA S.A.Tehnology co.,Ltd.
-000DAB Parker Hannifin GmbH Electromechanical Division Europe
-000DAC Japan CBM Corporation
-000DAD Dataprobe Inc
-000DAE SAMSUNG HEAVY INDUSTRIES CO., LTD.
-000DAF Plexus Corp (UK) Ltd
-000DB0 Olym-tech Co.,Ltd.
-000DB1 Japan Network Service Co., Ltd.
-000DB2 Ammasso, Inc.
-000DB3 SDO Communication Corperation
-000DB4 NETASQ
-000DB5 GLOBALSAT TECHNOLOGY CORPORATION
-000DB6 Teknovus, Inc.
-000DB7 SANKO ELECTRIC CO,.LTD
-000DB8 SCHILLER AG
-000DB9 PC Engines GmbH
-000DBA Océ Document Technologies GmbH
-000DBB Nippon Dentsu Co.,Ltd.
-000DBC Cisco Systems
-000DBD Cisco Systems
-000DBE Bel Fuse Europe Ltd.,UK
-000DBF TekTone Sound & Signal Mfg., Inc.
-000DC0 Spagat AS
-000DC1 SafeWeb Inc
-000DC3 First Communication, Inc.
-000DC4 Emcore Corporation
-000DC5 EchoStar International Corporation
-000DC6 DigiRose Technology Co., Ltd.
-000DC7 COSMIC ENGINEERING INC.
-000DC8 AirMagnet, Inc
-000DC9 THALES Elektronik Systeme GmbH
-000DCA Tait Electronics
-000DCB Petcomkorea Co., Ltd.
-000DCC NEOSMART Corp.
-000DCD GROUPE TXCOM
-000DCE Dynavac Technology Pte Ltd
-000DCF Cidra Corp.
-000DD0 TetraTec Instruments GmbH
-000DD1 Stryker Corporation
-000DD2 Simrad Optronics ASA
-000DD3 SAMWOO Telecommunication Co.,Ltd.
-000DD4 Revivio Inc.
-000DD5 O'RITE TECHNOLOGY CO.,LTD
-000DD7 Bright
-000DD8 BBN
-000DD9 Anton Paar GmbH
-000DDA ALLIED TELESIS K.K.
-000DDB AIRWAVE TECHNOLOGIES INC.
-000DDC VAC
-000DDD PROFÝLO TELRA ELEKTRONÝK SANAYÝ VE TÝCARET A.Þ.
-000DDE Joyteck Co., Ltd.
-000DDF Japan Image & Network Inc.
-000DE0 ICPDAS Co.,LTD
-000DE1 Control Products, Inc.
-000DE2 CMZ Sistemi Elettronici
-000DE3 AT Sweden AB
-000DE4 DIGINICS, Inc.
-000DE5 Samsung Thales
-000DE6 YOUNGBO ENGINEERING CO.,LTD
-000DE7 Snap-on OEM Group
-000DE8 Nasaco Electronics Pte. Ltd
-000DE9 Napatech Aps
-000DEA Kingtel Telecommunication Corp.
-000DEB CompXs Limited
-000DEC Cisco Systems
-000DED Cisco Systems
-000DEF Soc. Coop. Bilanciai
-000DF0 QCOM TECHNOLOGY INC.
-000DF1 IONIX INC.
-000DF3 Asmax Solutions
-000DF4 Watertek Co.
-000DF5 Teletronics International Inc.
-000DF6 Technology Thesaurus Corp.
-000DF7 Space Dynamics Lab
-000DF8 ORGA Kartensysteme GmbH
-000DF9 NDS Limited
-000DFA Micro Control Systems Ltd.
-000DFB Komax AG
-000DFC ITFOR Inc. resarch and development
-000DFD Huges Hi-Tech Inc.,
-000DFE Hauppauge Computer Works, Inc.
-000DFF CHENMING MOLD INDUSTRY CORP.
-000E01 ASIP Technologies Inc.
-000E02 Advantech AMT Inc.
-000E03 Aarohi Communications, Inc.
-000E05 WIRELESS MATRIX CORP.
-000E06 Team Simoco Ltd
-000E07 Sony Ericsson Mobile Communications AB
-000E08 Sipura Technology, Inc.
-000E09 Shenzhen Coship Software Co.,LTD.
-000E0B Netac Technology Co., Ltd.
-000E0C Intel Corporation
-000E0D HESCH Schröder GmbH
-000E0E ESA elettronica S.P.A.
-000E0F ERMME
-000E11 BDT Büro- und Datentechnik GmbH & Co. KG
-000E12 Adaptive Micro Systems Inc.
-000E13 Accu-Sort Systems inc.
-000E14 Visionary Solutions, Inc.
-000E15 Tadlys LTD
-000E16 SouthWing
-000E18 MyA Technology
-000E19 LogicaCMG Pty Ltd
-000E1B IAV GmbH
-000E1C Hach Company
-000E1F TCL Networks Equipment Co., Ltd.
-000E20 PalmSource, Inc.
-000E21 MTU Friedrichshafen GmbH
-000E23 Incipient, Inc.
-000E25 Hannae Technology Co., Ltd
-000E26 Gincom Technology Corp.
-000E27 Crere Networks, Inc.
-000E28 Dynamic Ratings P/L
-000E29 Shester Communications Inc
-000E2B Safari Technologies
-000E2C Netcodec co.
-000E2D Hyundai Digital Technology Co.,Ltd.
-000E2E Edimax Technology Co., Ltd.
-000E2F Disetronic Medical Systems AG
-000E30 AERAS Networks, Inc.
-000E31 Olympus BioSystems GmbH
-000E32 Kontron Medical
-000E33 Shuko Electronics Co.,Ltd
-000E34 NexxGenCity
-000E35 Intel Corp
-000E36 HEINESYS, Inc.
-000E37 Harms & Wende GmbH & Co.KG
-000E38 Cisco Systems
-000E39 Cisco Systems
-000E3A Cirrus Logic
-000E3B Hawking Technologies, Inc.
-000E3C TransAct Technoloiges Inc.
-000E3D Televic N.V.
-000E3E Sun Optronics Inc
-000E3F Soronti, Inc.
-000E40 Nortel Networks
-000E41 NIHON MECHATRONICS CO.,LTD.
-000E42 Motic Incoporation Ltd.
-000E43 G-Tek Electronics Sdn. Bhd.
-000E44 Digital 5, Inc.
-000E45 Beijing Newtry Electronic Technology Ltd
-000E46 Niigata Seimitsu Co.,Ltd.
-000E47 NCI System Co.,Ltd.
-000E48 Lipman TransAction Solutions
-000E49 Forsway Scandinavia AB
-000E4A Changchun Huayu WEBPAD Co.,LTD
-000E4B atrium c and i
-000E4C Bermai Inc.
-000E4D Numesa Inc.
-000E4E Waveplus Technology Co., Ltd.
-000E4F Trajet GmbH
-000E50 Thomson Multi Media
-000E51 tecna elettronica srl
-000E52 Optium Corporation
-000E53 AV TECH CORPORATION
-000E54 AlphaCell Wireless Ltd.
-000E55 AUVITRAN
-000E56 4G Systems GmbH
-000E57 Iworld Networking, Inc.
-000E58 Rincon Networks
-000E5A TELEFIELD inc.
-000E5B ParkerVision - Direct2Data
-000E5C Motorola BCS
-000E5D Com-X Networks
-000E5E Beijing Raisecom Science & Technology Development Co.,Ltd
-000E5F activ-net GmbH & Co. KG
-000E60 360SUN Digital Broadband Corporation
-000E61 MICROTROL LIMITED
-000E62 Nortel Networks
-000E63 Lemke Diagnostics GmbH
-000E64 Elphel, Inc
-000E65 TransCore
-000E66 Hitachi Advanced Digital, Inc.
-000E67 Eltis Microelectronics Ltd.
-000E68 E-TOP Network Technology Inc.
-000E69 China Electric Power Research Institute
-000E6A 3COM EUROPE LTD
-000E6B Janitza electronics GmbH
-000E6C Device Drivers Limited
-000E6D Murata Manufacturing Co., Ltd.
-000E6E MICRELEC  ELECTRONICS S.A
-000E6F IRIS Corporation Berhad
-000E70 in2 Networks
-000E71 Gemstar Technology Development Ltd.
-000E72 CTS electronics
-000E73 Tpack A/S
-000E74 Solar Telecom. Tech
-000E75 New York Air Brake Corp.
-000E76 GEMSOC INNOVISION INC.
-000E77 Decru, Inc.
-000E78 Amtelco
-000E79 Ample Communications Inc.
-000E7B Toshiba
-000E7D Electronics Line 3000 Ltd.
-000E7E Comprog Oy
-000E7F Hewlett Packard
-000E81 Instant802 Networks Inc.
-000E82 Commtech Wireless
-000E83 Cisco Systems
-000E84 Cisco Systems
-000E85 Catalyst Enterprises, Inc.
-000E86 Alcatel North America
-000E87 adp Gauselmann GmbH
-000E88 VIDEOTRON CORP.
-000E89 CLEMATIC
-000E8A Avara Technologies Pty. Ltd.
-000E8B Astarte Technology Co, Ltd.
-000E8C Siemens AG A&D ET
-000E8D Systems in Progress Holding GmbH
-000E8E SparkLAN Communications, Inc.
-000E8F Sercomm Corp.
-000E90 PONICO CORP.
-000E92 Millinet Co., Ltd.
-000E93 Milénio 3 Sistemas Electrónicos, Lda.
-000E94 Maas International BV
-000E95 Fujiya Denki Seisakusho Co.,Ltd.
-000E96 Cubic Defense Applications, Inc.
-000E97 Ultracker Technology CO., Inc
-000E98 Vitec CC, INC.
-000E99 Spectrum Digital, Inc
-000E9A BOE TECHNOLOGY GROUP CO.,LTD
-000E9C Pemstar
-000E9D Video Networks Ltd
-000E9E Topfield Co., Ltd
-000E9F TEMIC SDS GmbH
-000EA0 NetKlass Technology Inc.
-000EA1 Formosa Teletek Corporation
-000EA2 CyberGuard Corporation
-000EA3 CNCR-IT CO.,LTD,HangZhou P.R.CHINA
-000EA4 Certance Inc.
-000EA5 BLIP Systems
-000EA6 ASUSTEK COMPUTER INC.
-000EA7 Endace Inc Ltd.
-000EA8 United Technologists Europe Limited
-000EA9 Shanghai Xun Shi Communications Equipment Ltd. Co.
-000EAC MINTRON ENTERPRISE CO., LTD.
-000EAD Metanoia Technologies, Inc.
-000EAE GAWELL TECHNOLOGIES CORP.
-000EAF CASTEL
-000EB0 Solutions Radio BV
-000EB1 Newcotech,Ltd
-000EB2 Micro-Research Finland Oy
-000EB3 LeftHand Networks
-000EB4 GUANGZHOU GAOKE COMMUNICATIONS TECHNOLOGY CO.LTD.
-000EB5 Ecastle Electronics Co., Ltd.
-000EB6 Riverbed Technology, Inc.
-000EB7 Knovative, Inc.
-000EB8 Iiga co.,Ltd
-000EB9 HASHIMOTO Electronics Industry Co.,Ltd.
-000EBA HANMI SEMICONDUCTOR CO., LTD.
-000EBB Everbee Networks
-000EBC Cullmann GmbH
-000EBD Burdick, a Quinton Compny
-000EBE B&B Electronics Manufacturing Co.
-000EC0 Nortel Networks
-000EC1 MYNAH Technologies
-000EC2 Lowrance Electronics, Inc.
-000EC3 Logic Controls, Inc.
-000EC4 Iskra Transmission d.d.
-000EC6 ASIX ELECTRONICS CORP.
-000EC7 Appeal Telecom Co.,Ltd.
-000EC8 Zoran Corporation
-000EC9 YOKO Technology Corp.
-000ECB VineSys Technology
-000ECC Tableau
-000ECD SKOV A/S
-000ECE S.I.T.T.I. S.p.A.
-000ECF PROFIBUS Nutzerorganisation e.V.
-000ED0 Privaris, Inc.
-000ED1 Osaka Micro Computer.
-000ED2 Filtronic plc
-000ED3 Epicenter, Inc.
-000ED4 CRESITT INDUSTRIE
-000ED5 COPAN Systems Inc.
-000ED6 Cisco Systems
-000ED7 Cisco Systems
-000ED8 Aktino, Inc.
-000ED9 Aksys, Ltd.
-000EDA C-TECH UNITED CORP.
-000EDB XiNCOM Corp.
-000EDC Tellion INC.
-000EDD SHURE INCORPORATED
-000EDE REMEC, Inc.
-000EDF PLX Technology
-000EE0 Mcharge
-000EE1 ExtremeSpeed Inc.
-000EE2 Custom Engineering S.p.A.
-000EE3 Chiyu Technology Co.,Ltd
-000EE5 bitWallet, Inc.
-000EE6 Adimos Systems LTD
-000EE7 AAC ELECTRONICS CORP.
-000EE8 zioncom
-000EE9 WayTech Development, Inc.
-000EEA Shadong Luneng Jicheng Electronics,Co.,Ltd
-000EEB Sandmartin(zhong shan)Electronics Co.,Ltd
-000EEC Orban
-000EED Nokia Danmark A/S
-000EEE Muco Industrie BV
-000EF0 Festo AG & Co. KG
-000EF1 EZQUEST INC.
-000EF3 Smarthome
-000EF4 Shenzhen Kasda Digital Technology Co.,Ltd
-000EF5 iPAC Technology Co., Ltd.
-000EF6 E-TEN Information Systems Co., Ltd.
-000EF7 Vulcan Portals Inc
-000EF8 SBC ASI
-000EF9 REA Elektronik GmbH
-000EFA Optoway Technology Incorporation
-000EFB Macey Enterprises
-000EFC JTAG Technologies B.V.
-000EFD FUJI PHOTO OPTICAL CO., LTD.
-000EFE EndRun Technologies LLC
-000EFF Megasolution,Inc.
-000F00 Legra Systems, Inc.
-000F01 DIGITALKS INC
-000F02 Digicube Technology Co., Ltd
-000F03 COM&C CO., LTD
-000F04 cim-usa inc
-000F05 3B SYSTEM INC.
-000F06 Nortel Networks
-000F07 Mangrove Systems, Inc.
-000F08 Indagon Oy
-000F0B Kentima Technologies AB
-000F0C SYNCHRONIC ENGINEERING
-000F0D Hunt Electronic Co., Ltd.
-000F0E WaveSplitter Technologies, Inc.
-000F0F Real ID Technology Co., Ltd.
-000F10 RDM Corporation
-000F11 Prodrive B.V.
-000F12 Panasonic AVC Networks Germany GmbH
-000F13 Nisca corporation
-000F14 Mindray Co., Ltd.
-000F15 Kjaerulff1 A/S
-000F16 JAY HOW TECHNOLOGY CO.,
-000F17 Insta Elektro GmbH
-000F18 Industrial Control Systems
-000F19 Guidant Corporation
-000F1A Gaming Support B.V.
-000F1B Ego Systems Inc.
-000F1C DigitAll World Co., Ltd
-000F1D Cosmo Techs Co., Ltd.
-000F1E Chengdu KT Electric Co.of High & New Technology
-000F1F WW PCBA Test
-000F20 WW Ops
-000F21 Scientific Atlanta, Inc
-000F22 Helius, Inc.
-000F23 Cisco Systems
-000F24 Cisco Systems
-000F25 AimValley B.V.
-000F26 WorldAccxx  LLC
-000F27 TEAL Electronics, Inc.
-000F28 Itronix Corporation
-000F29 Augmentix Corporation
-000F2A Cableware Electronics
-000F2B GREENBELL SYSTEMS
-000F2C Uplogix, Inc.
-001000 CABLE TELEVISION LABORATORIES, INC.
-001001 MCK COMMUNICATIONS
-001002 ACTIA
-001003 IMATRON, INC.
-001004 THE BRANTLEY COILE COMPANY,INC
-001005 UEC COMMERCIAL
-001006 Thales Contact Solutions Ltd.
-001007 CISCO SYSTEMS, INC.
-001008 VIENNA SYSTEMS CORPORATION
-001009 HORO QUARTZ
-00100A WILLIAMS COMMUNICATIONS GROUP
-00100B CISCO SYSTEMS, INC.
-00100C ITO CO., LTD.
-00100D CISCO SYSTEMS, INC.
-00100E MICRO LINEAR COPORATION
-00100F INDUSTRIAL CPU SYSTEMS
-001010 INITIO CORPORATION
-001011 CISCO SYSTEMS, INC.
-001012 PROCESSOR SYSTEMS (I) PVT LTD
-001013 INDUSTRIAL COMPUTER SOURCE
-001014 CISCO SYSTEMS, INC.
-001015 OOmon Inc.
-001016 T.SQWARE
-001017 MICOS GmbH
-001018 BROADCOM CORPORATION
-001019 SIRONA DENTAL SYSTEMS GmbH & Co. KG
-00101A PictureTel Corp.
-00101B CORNET TECHNOLOGY, INC.
-00101C OHM TECHNOLOGIES INTL, LLC
-00101D WINBOND ELECTRONICS CORP.
-00101E MATSUSHITA ELECTRONIC INSTRUMENTS CORP.
-00101F CISCO SYSTEMS, INC.
-001020 WELCH ALLYN, DATA COLLECTION
-001021 ENCANTO NETWORKS, INC.
-001022 SatCom Media Corporation
-001023 FLOWWISE NETWORKS, INC.
-001024 NAGOYA ELECTRIC WORKS CO., LTD
-001025 GRAYHILL INC.
-001026 ACCELERATED NETWORKS, INC.
-001027 L-3 COMMUNICATIONS EAST
-001028 COMPUTER TECHNICA, INC.
-001029 CISCO SYSTEMS, INC.
-00102A ZF MICROSYSTEMS, INC.
-00102B UMAX DATA SYSTEMS, INC.
-00102C Lasat Networks A/S
-00102D HITACHI SOFTWARE ENGINEERING
-00102E NETWORK SYSTEMS & TECHNOLOGIES PVT. LTD.
-00102F CISCO SYSTEMS, INC.
-001030 Wi-LAN, Inc.
-001031 OBJECTIVE COMMUNICATIONS, INC.
-001032 ALTA TECHNOLOGY
-001033 ACCESSLAN COMMUNICATIONS, INC.
-001034 GNP Computers
-001035 ELITEGROUP COMPUTER SYSTEMS CO., LTD
-001036 INTER-TEL INTEGRATED SYSTEMS
-001037 CYQ've Technology Co., Ltd.
-001038 MICRO RESEARCH INSTITUTE, INC.
-001039 Vectron Systems AG
-00103A DIAMOND NETWORK TECH
-00103B HIPPI NETWORKING FORUM
-00103C IC ENSEMBLE, INC.
-00103D PHASECOM, LTD.
-00103E NETSCHOOLS CORPORATION
-00103F TOLLGRADE COMMUNICATIONS, INC.
-001040 INTERMEC CORPORATION
-001041 BRISTOL BABCOCK, INC.
-001042 AlacriTech
-001043 A2 CORPORATION
-001044 InnoLabs Corporation
-001045 Nortel Networks
-001046 ALCORN MCBRIDE INC.
-001047 ECHO ELETRIC CO. LTD.
-001048 HTRC AUTOMATION, INC.
-001049 SHORELINE TELEWORKS, INC.
-00104A THE PARVUC CORPORATION
-00104B 3COM CORPORATION
-00104C COMPUTER ACCESS TECHNOLOGY
-00104D SURTEC INDUSTRIES, INC.
-00104E CEOLOGIC
-00104F STORAGE TECHNOLOGY CORPORATION
-001050 RION CO., LTD.
-001051 CMICRO CORPORATION
-001052 METTLER-TOLEDO (ALBSTADT) GMBH
-001053 COMPUTER TECHNOLOGY CORP.
-001054 CISCO SYSTEMS, INC.
-001055 FUJITSU MICROELECTRONICS, INC.
-001056 SODICK CO., LTD.
-001057 Rebel.com, Inc.
-001058 ArrowPoint Communications
-001059 DIABLO RESEARCH CO. LLC
-00105A 3COM CORPORATION
-00105B NET INSIGHT AB
-00105C QUANTUM DESIGNS (H.K.) LTD.
-00105D Draeger Medical
-00105E HEKIMIAN LABORATORIES, INC.
-00105F IN-SNEC
-001060 BILLIONTON SYSTEMS, INC.
-001061 HOSTLINK CORP.
-001062 NX SERVER, ILNC.
-001063 STARGUIDE DIGITAL NETWORKS
-001064 DIGITAL EQUIPMENT CORP.
-001065 RADYNE CORPORATION
-001066 ADVANCED CONTROL SYSTEMS, INC.
-001067 REDBACK NETWORKS, INC.
-001068 COMOS TELECOM
-001069 HELIOSS COMMUNICATIONS, INC.
-00106A DIGITAL MICROWAVE CORPORATION
-00106B SONUS NETWORKS, INC.
-00106C INFRATEC PLUS GmbH
-00106D INTEGRITY COMMUNICATIONS, INC.
-00106E TADIRAN COM. LTD.
-00106F TRENTON TECHNOLOGY INC.
-001070 CARADON TREND LTD.
-001071 ADVANET INC.
-001072 GVN TECHNOLOGIES, INC.
-001073 TECHNOBOX, INC.
-001074 ATEN INTERNATIONAL CO., LTD.
-001075 Maxtor Corporation
-001076 EUREM GmbH
-001077 SAF DRIVE SYSTEMS, LTD.
-001078 NUERA COMMUNICATIONS, INC.
-001079 CISCO SYSTEMS, INC.
-00107A AmbiCom, Inc.
-00107B CISCO SYSTEMS, INC.
-00107C P-COM, INC.
-00107D AURORA COMMUNICATIONS, LTD.
-00107E BACHMANN ELECTRONIC GmbH
-00107F CRESTRON ELECTRONICS, INC.
-001080 METAWAVE COMMUNICATIONS
-001081 DPS, INC.
-001082 JNA TELECOMMUNICATIONS LIMITED
-001083 HEWLETT-PACKARD COMPANY
-001084 K-BOT COMMUNICATIONS
-001085 POLARIS COMMUNICATIONS, INC.
-001086 ATTO TECHNOLOGY, INC.
-001087 Xstreamis PLC
-001088 AMERICAN NETWORKS INC.
-001089 WebSonic
-00108A TeraLogic, Inc.
-00108B LASERANIMATION SOLLINGER GmbH
-00108C FUJITSU TELECOMMUNICATIONS EUROPE, LTD.
-00108D JOHNSON CONTROLS, INC.
-00108E HUGH SYMONS CONCEPT Technologies Ltd.
-00108F RAPTOR SYSTEMS
-001090 CIMETRICS, INC.
-001091 NO WIRES NEEDED BV
-001092 NETCORE INC.
-001093 CMS COMPUTERS, LTD.
-001094 Performance Analysis Broadband, Spirent plc
-001095 Thomson Multimedia, Inc.
-001096 TRACEWELL SYSTEMS, INC.
-001097 WinNet Metropolitan Communications Systems, Inc.
-001098 STARNET TECHNOLOGIES, INC.
-001099 InnoMedia, Inc.
-00109A NETLINE
-00109B VIXEL CORPORATION
-00109C M-SYSTEM CO., LTD.
-00109D CLARINET SYSTEMS, INC.
-00109E AWARE, INC.
-00109F PAVO, INC.
-0010A0 INNOVEX TECHNOLOGIES, INC.
-0010A1 KENDIN SEMICONDUCTOR, INC.
-0010A2 TNS
-0010A3 OMNITRONIX, INC.
-0010A4 XIRCOM
-0010A5 OXFORD INSTRUMENTS
-0010A6 CISCO SYSTEMS, INC.
-0010A7 UNEX TECHNOLOGY CORPORATION
-0010A8 RELIANCE COMPUTER CORP.
-0010A9 ADHOC TECHNOLOGIES
-0010AA MEDIA4, INC.
-0010AB KOITO INDUSTRIES, LTD.
-0010AC IMCI TECHNOLOGIES
-0010AD SOFTRONICS USB, INC.
-0010AE SHINKO ELECTRIC INDUSTRIES CO.
-0010AF TAC SYSTEMS, INC.
-0010B0 MERIDIAN TECHNOLOGY CORP.
-0010B1 FOR-A CO., LTD.
-0010B2 COACTIVE AESTHETICS
-0010B3 NOKIA MULTIMEDIA TERMINALS
-0010B4 ATMOSPHERE NETWORKS
-0010B5 ACCTON TECHNOLOGY CORPORATION
-0010B6 ENTRATA COMMUNICATIONS CORP.
-0010B7 COYOTE TECHNOLOGIES, LLC
-0010B8 ISHIGAKI COMPUTER SYSTEM CO.
-0010B9 MAXTOR CORP.
-0010BA MARTINHO-DAVIS SYSTEMS, INC.
-0010BB DATA & INFORMATION TECHNOLOGY
-0010BC Aastra Telecom
-0010BD THE TELECOMMUNICATION TECHNOLOGY COMMITTEE
-0010BE TELEXIS CORP.
-0010BF InterAir Wireless
-0010C0 ARMA, INC.
-0010C1 OI ELECTRIC CO., LTD.
-0010C2 WILLNET, INC.
-0010C3 CSI-CONTROL SYSTEMS
-0010C4 MEDIA LINKS CO., LTD.
-0010C5 PROTOCOL TECHNOLOGIES, INC.
-0010C6 USI
-0010C7 DATA TRANSMISSION NETWORK
-0010C8 COMMUNICATIONS ELECTRONICS SECURITY GROUP
-0010C9 MITSUBISHI ELECTRONICS LOGISTIC SUPPORT CO.
-0010CA INTEGRAL ACCESS
-0010CB FACIT K.K.
-0010CC CLP COMPUTER LOGISTIK PLANUNG GmbH
-0010CD INTERFACE CONCEPT
-0010CE VOLAMP, LTD.
-0010CF FIBERLANE COMMUNICATIONS
-0010D0 WITCOM, LTD.
-0010D1 Top Layer Networks, Inc.
-0010D2 NITTO TSUSHINKI CO., LTD
-0010D3 GRIPS ELECTRONIC GMBH
-0010D4 STORAGE COMPUTER CORPORATION
-0010D5 IMASDE CANARIAS, S.A.
-0010D6 ITT - A/CD
-0010D7 ARGOSY RESEARCH INC.
-0010D8 CALISTA
-0010D9 IBM JAPAN, FUJISAWA MT+D
-0010DA MOTION ENGINEERING, INC.
-0010DB NetScreen Technologies, Inc.
-0010DC MICRO-STAR INTERNATIONAL CO., LTD.
-0010DD ENABLE SEMICONDUCTOR, INC.
-0010DE INTERNATIONAL DATACASTING CORPORATION
-0010DF RISE COMPUTER INC.
-0010E0 COBALT MICROSERVER, INC.
-0010E1 S.I. TECH, INC.
-0010E2 ArrayComm, Inc.
-0010E3 COMPAQ COMPUTER CORPORATION
-0010E4 NSI CORPORATION
-0010E5 SOLECTRON TEXAS
-0010E6 APPLIED INTELLIGENT SYSTEMS, INC.
-0010E7 BreezeCom
-0010E8 TELOCITY, INCORPORATED
-0010E9 RAIDTEC LTD.
-0010EA ADEPT TECHNOLOGY
-0010EB SELSIUS SYSTEMS, INC.
-0010EC RPCG, LLC
-0010ED SUNDANCE TECHNOLOGY, INC.
-0010EE CTI PRODUCTS, INC.
-0010EF DBTEL INCORPORATED
-0010F1 I-O CORPORATION
-0010F2 ANTEC
-0010F3 Nexcom International Co., Ltd.
-0010F4 VERTICAL NETWORKS, INC.
-0010F5 AMHERST SYSTEMS, INC.
-0010F6 CISCO SYSTEMS, INC.
-0010F7 IRIICHI TECHNOLOGIES Inc.
-0010F8 KENWOOD TMI CORPORATION
-0010F9 UNIQUE SYSTEMS, INC.
-0010FA ZAYANTE, INC.
-0010FB ZIDA TECHNOLOGIES LIMITED
-0010FC BROADBAND NETWORKS, INC.
-0010FD COCOM A/S
-0010FE DIGITAL EQUIPMENT CORPORATION
-0010FF CISCO SYSTEMS, INC.
-001C7C PERQ SYSTEMS CORPORATION
-002000 LEXMARK INTERNATIONAL, INC.
-002001 DSP SOLUTIONS, INC.
-002002 SERITECH ENTERPRISE CO., LTD.
-002003 PIXEL POWER LTD.
-002004 YAMATAKE-HONEYWELL CO., LTD.
-002005 SIMPLE TECHNOLOGY
-002006 GARRETT COMMUNICATIONS, INC.
-002007 SFA, INC.
-002008 CABLE & COMPUTER TECHNOLOGY
-002009 PACKARD BELL ELEC., INC.
-00200A SOURCE-COMM CORP.
-00200B OCTAGON SYSTEMS CORP.
-00200C ADASTRA SYSTEMS CORP.
-00200D CARL ZEISS
-00200E SATELLITE TECHNOLOGY MGMT, INC
-00200F TANBAC CO., LTD.
-002010 JEOL SYSTEM TECHNOLOGY CO. LTD
-002011 CANOPUS CO., LTD.
-002012 CAMTRONICS MEDICAL SYSTEMS
-002013 DIVERSIFIED TECHNOLOGY, INC.
-002014 GLOBAL VIEW CO., LTD.
-002015 ACTIS COMPUTER SA
-002016 SHOWA ELECTRIC WIRE & CABLE CO
-002017 ORBOTECH
-002018 CIS TECHNOLOGY INC.
-002019 OHLER GmbH
-00201A N-BASE SWITCH COMMUNICATIONS
-00201B NORTHERN TELECOM/NETWORK
-00201C EXCEL, INC.
-00201D KATANA PRODUCTS
-00201E NETQUEST CORPORATION
-00201F BEST POWER TECHNOLOGY, INC.
-002020 MEGATRON COMPUTER INDUSTRIES PTY, LTD.
-002021 ALGORITHMS SOFTWARE PVT. LTD.
-002022 TEKNIQUE, INC.
-002023 T.C. TECHNOLOGIES PTY. LTD
-002024 PACIFIC COMMUNICATION SCIENCES
-002025 CONTROL TECHNOLOGY, INC.
-002026 AMKLY SYSTEMS, INC.
-002027 MING FORTUNE INDUSTRY CO., LTD
-002028 WEST EGG SYSTEMS, INC.
-002029 TELEPROCESSING PRODUCTS, INC.
-00202A N.V. DZINE
-00202B ADVANCED TELECOMMUNICATIONS MODULES, LTD.
-00202C WELLTRONIX CO., LTD.
-00202D TAIYO CORPORATION
-00202E DAYSTAR DIGITAL
-00202F ZETA COMMUNICATIONS, LTD.
-002030 ANALOG & DIGITAL SYSTEMS
-002031 ERTEC GmbH
-002032 ALCATEL TAISEL
-002033 SYNAPSE TECHNOLOGIES, INC.
-002034 ROTEC INDUSTRIEAUTOMATION GMBH
-002035 IBM CORPORATION
-002036 BMC SOFTWARE
-002037 SEAGATE TECHNOLOGY
-002038 VME MICROSYSTEMS INTERNATIONAL CORPORATION
-002039 SCINETS
-00203A DIGITAL BI0METRICS INC.
-00203B WISDM LTD.
-00203C EUROTIME AB
-00203D NOVAR ELECTRONICS CORPORATION
-00203E LogiCan Technologies, Inc.
-00203F JUKI CORPORATION
-002040 Motorola Broadband Communications Sector
-002041 DATA NET
-002042 DATAMETRICS CORP.
-002043 NEURON COMPANY LIMITED
-002044 GENITECH PTY LTD
-002045 ION Networks, Inc.
-002046 CIPRICO, INC.
-002047 STEINBRECHER CORP.
-002048 Marconi Communications
-002049 COMTRON, INC.
-00204A PRONET GMBH
-00204B AUTOCOMPUTER CO., LTD.
-00204C MITRON COMPUTER PTE LTD.
-00204D INOVIS GMBH
-00204E NETWORK SECURITY SYSTEMS, INC.
-00204F DEUTSCHE AEROSPACE AG
-002050 KOREA COMPUTER INC.
-002051 Verilink Corporation
-002052 RAGULA SYSTEMS
-002053 HUNTSVILLE MICROSYSTEMS, INC.
-002054 EASTERN RESEARCH, INC.
-002055 ALTECH CO., LTD.
-002056 NEOPRODUCTS
-002057 TITZE DATENTECHNIK GmbH
-002058 ALLIED SIGNAL INC.
-002059 MIRO COMPUTER PRODUCTS AG
-00205A COMPUTER IDENTICS
-00205B SKYLINE TECHNOLOGY
-00205C InterNet Systems of Florida, Inc.
-00205D NANOMATIC OY
-00205E CASTLE ROCK, INC.
-00205F GAMMADATA COMPUTER GMBH
-002060 ALCATEL ITALIA S.p.A.
-002061 DYNATECH COMMUNICATIONS, INC.
-002062 SCORPION LOGIC, LTD.
-002063 WIPRO INFOTECH LTD.
-002064 PROTEC MICROSYSTEMS, INC.
-002065 SUPERNET NETWORKING INC.
-002066 GENERAL MAGIC, INC.
-002068 ISDYNE
-002069 ISDN SYSTEMS CORPORATION
-00206A OSAKA COMPUTER CORP.
-00206B KONICA MINOLTA HOLDINGS, INC.
-00206C EVERGREEN TECHNOLOGY CORP.
-00206D DATA RACE, INC.
-00206E XACT, INC.
-00206F FLOWPOINT CORPORATION
-002070 HYNET, LTD.
-002071 IBR GMBH
-002072 WORKLINK INNOVATIONS
-002073 FUSION SYSTEMS CORPORATION
-002074 SUNGWOON SYSTEMS
-002075 MOTOROLA COMMUNICATION ISRAEL
-002076 REUDO CORPORATION
-002077 KARDIOS SYSTEMS CORP.
-002078 RUNTOP, INC.
-002079 MIKRON GMBH
-00207A WiSE Communications, Inc.
-00207B Intel Corporation
-00207C AUTEC GmbH
-00207D ADVANCED COMPUTER APPLICATIONS
-00207E FINECOM Co., Ltd.
-00207F KYOEI SANGYO CO., LTD.
-002080 SYNERGY (UK) LTD.
-002081 TITAN ELECTRONICS
-002082 ONEAC CORPORATION
-002083 PRESTICOM INCORPORATED
-002084 OCE PRINTING SYSTEMS, GMBH
-002085 EXIDE ELECTRONICS
-002086 MICROTECH ELECTRONICS LIMITED
-002087 MEMOTEC COMMUNICATIONS CORP.
-002088 GLOBAL VILLAGE COMMUNICATION
-002089 T3PLUS NETWORKING, INC.
-00208A SONIX COMMUNICATIONS, LTD.
-00208B LAPIS TECHNOLOGIES, INC.
-00208C GALAXY NETWORKS, INC.
-00208D CMD TECHNOLOGY
-00208E CHEVIN SOFTWARE ENG. LTD.
-00208F ECI TELECOM LTD.
-002090 ADVANCED COMPRESSION TECHNOLOGY, INC.
-002091 J125, NATIONAL SECURITY AGENCY
-002092 CHESS ENGINEERING B.V.
-002093 LANDINGS TECHNOLOGY CORP.
-002094 CUBIX CORPORATION
-002095 RIVA ELECTRONICS
-002096 Invensys
-002097 APPLIED SIGNAL TECHNOLOGY
-002098 HECTRONIC AB
-002099 BON ELECTRIC CO., LTD.
-00209A THE 3DO COMPANY
-00209B ERSAT ELECTRONIC GMBH
-00209C PRIMARY ACCESS CORP.
-00209D LIPPERT AUTOMATIONSTECHNIK
-00209E BROWN'S OPERATING SYSTEM SERVICES, LTD.
-00209F MERCURY COMPUTER SYSTEMS, INC.
-0020A0 OA LABORATORY CO., LTD.
-0020A1 DOVATRON
-0020A2 GALCOM NETWORKING LTD.
-0020A3 DIVICOM INC.
-0020A4 MULTIPOINT NETWORKS
-0020A5 API ENGINEERING
-0020A6 PROXIM, INC.
-0020A7 PAIRGAIN TECHNOLOGIES, INC.
-0020A8 SAST TECHNOLOGY CORP.
-0020A9 WHITE HORSE INDUSTRIAL
-0020AA DIGIMEDIA VISION LTD.
-0020AB MICRO INDUSTRIES CORP.
-0020AC INTERFLEX DATENSYSTEME GMBH
-0020AD LINQ SYSTEMS
-0020AE ORNET DATA COMMUNICATION TECH.
-0020AF 3COM CORPORATION
-0020B0 GATEWAY DEVICES, INC.
-0020B1 COMTECH RESEARCH INC.
-0020B2 GKD Gesellschaft Fur Kommunikation Und Datentechnik
-0020B3 SCLTEC COMMUNICATIONS SYSTEMS
-0020B4 TERMA ELEKTRONIK AS
-0020B5 YASKAWA ELECTRIC CORPORATION
-0020B6 AGILE NETWORKS, INC.
-0020B7 NAMAQUA COMPUTERWARE
-0020B8 PRIME OPTION, INC.
-0020B9 METRICOM, INC.
-0020BA CENTER FOR HIGH PERFORMANCE
-0020BB ZAX CORPORATION
-0020BC JTEC PTY LTD.
-0020BD NIOBRARA R & D CORPORATION
-0020BE LAN ACCESS CORP.
-0020BF AEHR TEST SYSTEMS
-0020C0 PULSE ELECTRONICS, INC.
-0020C1 TAIKO ELECTRIC WORKS, LTD.
-0020C2 TEXAS MEMORY SYSTEMS, INC.
-0020C3 COUNTER SOLUTIONS LTD.
-0020C4 INET,INC.
-0020C5 EAGLE TECHNOLOGY
-0020C6 NECTEC
-0020C7 AKAI Professional M.I. Corp.
-0020C8 LARSCOM INCORPORATED
-0020C9 VICTRON BV
-0020CA DIGITAL OCEAN
-0020CB PRETEC ELECTRONICS CORP.
-0020CC DIGITAL SERVICES, LTD.
-0020CD HYBRID NETWORKS, INC.
-0020CE LOGICAL DESIGN GROUP, INC.
-0020CF TEST & MEASUREMENT SYSTEMS INC
-0020D0 VERSALYNX CORPORATION
-0020D1 MICROCOMPUTER SYSTEMS (M) SDN.
-0020D2 RAD DATA COMMUNICATIONS, LTD.
-0020D3 OST (OUEST STANDARD TELEMATIQU
-0020D4 CABLETRON - ZEITTNET INC.
-0020D5 VIPA GMBH
-0020D6 BREEZECOM
-0020D7 JAPAN MINICOMPUTER SYSTEMS CO., Ltd.
-0020D8 Nortel Networks
-0020D9 PANASONIC TECHNOLOGIES, INC./MIECO-US
-0020DA XYLAN CORPORATION
-0020DB XNET TECHNOLOGY, INC.
-0020DC DENSITRON TAIWAN LTD.
-0020DD Cybertec Pty Ltd
-0020DE JAPAN DIGITAL LABORAT'Y CO.LTD
-0020DF KYOSAN ELECTRIC MFG. CO., LTD.
-0020E0 PREMAX ELECTRONICS, INC.
-0020E1 ALAMAR ELECTRONICS
-0020E2 INFORMATION RESOURCE ENGINEERING
-0020E3 MCD KENCOM CORPORATION
-0020E4 HSING TECH ENTERPRISE CO., LTD
-0020E5 APEX DATA, INC.
-0020E6 LIDKOPING MACHINE TOOLS AB
-0020E7 B&W NUCLEAR SERVICE COMPANY
-0020E8 DATATREK CORPORATION
-0020E9 DANTEL
-0020EA EFFICIENT NETWORKS, INC.
-0020EB CINCINNATI MICROWAVE, INC.
-0020EC TECHWARE SYSTEMS CORP.
-0020ED GIGA-BYTE TECHNOLOGY CO., LTD.
-0020EE GTECH CORPORATION
-0020EF USC CORPORATION
-0020F0 UNIVERSAL MICROELECTRONICS CO.
-0020F1 ALTOS INDIA LIMITED
-0020F2 SUN MICROSYSTEMS, INC.
-0020F3 RAYNET CORPORATION
-0020F4 SPECTRIX CORPORATION
-0020F5 PANDATEL AG
-0020F6 NET TEK  AND KARLNET, INC.
-0020F7 CYBERDATA
-0020F8 CARRERA COMPUTERS, INC.
-0020F9 PARALINK NETWORKS, INC.
-0020FA GDE SYSTEMS, INC.
-0020FB OCTEL COMMUNICATIONS CORP.
-0020FC MATROX
-0020FD ITV TECHNOLOGIES, INC.
-0020FE TOPWARE INC. / GRAND COMPUTER
-0020FF SYMMETRICAL TECHNOLOGIES
-003000 ALLWELL TECHNOLOGY CORP.
-003001 SMP
-003002 Expand Networks
-003003 Phasys Ltd.
-003004 LEADTEK RESEARCH INC.
-003005 Fujitsu Siemens Computers
-003006 SUPERPOWER COMPUTER
-003007 OPTI, INC.
-003008 AVIO DIGITAL, INC.
-003009 Tachion Networks, Inc.
-00300A AZTECH SYSTEMS LTD.
-00300B mPHASE Technologies, Inc.
-00300C CONGRUENCY, LTD.
-00300D MMC Technology, Inc.
-00300E Klotz Digital AG
-00300F IMT - Information Management T
-003010 VISIONETICS INTERNATIONAL
-003011 HMS FIELDBUS SYSTEMS AB
-003012 DIGITAL ENGINEERING LTD.
-003013 NEC Corporation
-003014 DIVIO, INC.
-003015 CP CLARE CORP.
-003016 ISHIDA CO., LTD.
-003017 TERASTACK LTD.
-003018 Jetway Information Co., Ltd.
-003019 CISCO SYSTEMS, INC.
-00301A SMARTBRIDGES PTE. LTD.
-00301B SHUTTLE, INC.
-00301C ALTVATER AIRDATA SYSTEMS
-00301D SKYSTREAM, INC.
-00301E 3COM Europe Ltd.
-00301F OPTICAL NETWORKS, INC.
-003020 TSI, Inc..
-003021 HSING TECH. ENTERPRISE CO.,LTD
-003022 Fong Kai Industrial Co., Ltd.
-003023 COGENT COMPUTER SYSTEMS, INC.
-003024 CISCO SYSTEMS, INC.
-003025 CHECKOUT COMPUTER SYSTEMS, LTD
-003026 HEITEL
-003027 KERBANGO, INC.
-003028 FASE Saldatura srl
-003029 OPICOM
-00302A SOUTHERN INFORMATION
-00302B INALP NETWORKS, INC.
-00302C SYLANTRO SYSTEMS CORPORATION
-00302D QUANTUM BRIDGE COMMUNICATIONS
-00302E Hoft & Wessel AG
-00302F Smiths Industries
-003030 HARMONIX CORPORATION
-003031 LIGHTWAVE COMMUNICATIONS, INC.
-003032 MagicRam, Inc.
-003033 ORIENT TELECOM CO., LTD.
-003036 RMP ELEKTRONIKSYSTEME GMBH
-003037 Packard Bell Nec Services
-003038 XCP, INC.
-003039 SOFTBOOK PRESS
-00303A MAATEL
-00303B PowerCom Technology
-00303C ONNTO CORP.
-00303D IVA CORPORATION
-00303E Radcom Ltd.
-00303F TurboComm Tech Inc.
-003040 CISCO SYSTEMS, INC.
-003041 SAEJIN T & M CO., LTD.
-003042 DeTeWe-Deutsche Telephonwerke
-003043 IDREAM TECHNOLOGIES, PTE. LTD.
-003044 Portsmith LLC
-003045 Village Networks, Inc. (VNI)
-003046 Controlled Electronic Manageme
-003047 NISSEI ELECTRIC CO., LTD.
-003048 Supermicro Computer, Inc.
-003049 BRYANT TECHNOLOGY, LTD.
-00304A FRAUNHOFER INSTITUTE IMS
-00304B ORBACOM SYSTEMS, INC.
-00304C APPIAN COMMUNICATIONS, INC.
-00304D ESI
-00304E BUSTEC PRODUCTION LTD.
-00304F PLANET Technology Corporation
-003050 Versa Technology
-003051 ORBIT AVIONIC & COMMUNICATION
-003052 ELASTIC NETWORKS
-003053 Basler AG
-003054 CASTLENET TECHNOLOGY, INC.
-003055 Hitachi Semiconductor America,
-003056 Beck IPC GmbH
-003057 E-Tel Corporation
-003058 API MOTION
-003059 DIGITAL-LOGIC AG
-00305A TELGEN CORPORATION
-00305B MODULE DEPARTMENT
-00305C SMAR Laboratories Corp.
-00305D DIGITRA SYSTEMS, INC.
-00305E Abelko Innovation
-00305F IMACON APS
-003060 STARMATIX, INC.
-003061 MobyTEL
-003062 PATH 1 NETWORK TECHNOL'S INC.
-003063 SANTERA SYSTEMS, INC.
-003064 ADLINK TECHNOLOGY, INC.
-003065 APPLE COMPUTER, INC.
-003066 DIGITAL WIRELESS CORPORATION
-003067 BIOSTAR MICROTECH INT'L CORP.
-003068 CYBERNETICS TECH. CO., LTD.
-003069 IMPACCT TECHNOLOGY CORP.
-00306A PENTA MEDIA CO., LTD.
-00306B CMOS SYSTEMS, INC.
-00306C Hitex Holding GmbH
-00306D LUCENT TECHNOLOGIES
-00306E HEWLETT PACKARD
-00306F SEYEON TECH. CO., LTD.
-003070 1Net Corporation
-003071 Cisco Systems, Inc.
-003072 INTELLIBYTE INC.
-003073 International Microsystems, In
-003074 EQUIINET LTD.
-003075 ADTECH
-003076 Akamba Corporation
-003077 ONPREM NETWORKS
-003078 Cisco Systems, Inc.
-003079 CQOS, INC.
-00307A Advanced Technology & Systems
-00307B Cisco Systems, Inc.
-00307C ADID SA
-00307D GRE AMERICA, INC.
-00307E Redflex Communication Systems
-00307F IRLAN LTD.
-003080 CISCO SYSTEMS, INC.
-003081 ALTOS C&C
-003082 TAIHAN ELECTRIC WIRE CO., LTD.
-003083 Ivron Systems
-003084 ALLIED TELESYN INTERNAIONAL
-003085 CISCO SYSTEMS, INC.
-003086 Transistor Devices, Inc.
-003087 VEGA GRIESHABER KG
-003088 Siara Systems, Inc.
-003089 Spectrapoint Wireless, LLC
-00308A NICOTRA SISTEMI S.P.A
-00308B Brix Networks
-00308C ADVANCED DIGITAL INFORMATION
-00308D PINNACLE SYSTEMS, INC.
-00308E CROSS MATCH TECHNOLOGIES, INC.
-00308F MICRILOR, Inc.
-003090 CYRA TECHNOLOGIES, INC.
-003091 TAIWAN FIRST LINE ELEC. CORP.
-003092 ModuNORM GmbH
-003093 SONNET TECHNOLOGIES, INC.
-003094 Cisco Systems, Inc.
-003095 Procomp Informatics, Ltd.
-003096 CISCO SYSTEMS, INC.
-003097 EXOMATIC AB
-003098 Global Converging Technologies
-003099 BOENIG UND KALLENBACH OHG
-00309A ASTRO TERRA CORP.
-00309B Smartware
-00309C Timing Applications, Inc.
-00309D Nimble Microsystems, Inc.
-00309E WORKBIT CORPORATION.
-00309F AMBER NETWORKS
-0030A0 TYCO SUBMARINE SYSTEMS, LTD.
-0030A1 WEBGATE Inc.
-0030A2 Lightner Engineering
-0030A3 CISCO SYSTEMS, INC.
-0030A4 Woodwind Communications System
-0030A5 ACTIVE POWER
-0030A6 VIANET TECHNOLOGIES, LTD.
-0030A7 SCHWEITZER ENGINEERING
-0030A8 OL'E COMMUNICATIONS, INC.
-0030A9 Netiverse, Inc.
-0030AA AXUS MICROSYSTEMS, INC.
-0030AB DELTA NETWORKS, INC.
-0030AC Systeme Lauer GmbH & Co., Ltd.
-0030AD SHANGHAI COMMUNICATION
-0030AE Times N System, Inc.
-0030AF Honeywell GmbH
-0030B0 Convergenet Technologies
-0030B1 GOC GESELLSCHAFT FUR OPTISCHE
-0030B2 WESCAM - HEALDSBURG
-0030B3 San Valley Systems, Inc.
-0030B4 INTERSIL CORP.
-0030B5 Tadiran Microwave Networks
-0030B6 CISCO SYSTEMS, INC.
-0030B7 Teletrol Systems, Inc.
-0030B8 RiverDelta Networks
-0030B9 ECTEL
-0030BA AC&T SYSTEM CO., LTD.
-0030BB CacheFlow, Inc.
-0030BC Optronic AG
-0030BD BELKIN COMPONENTS
-0030BE City-Net Technology, Inc.
-0030BF MULTIDATA GMBH
-0030C0 Lara Technology, Inc.
-0030C1 HEWLETT-PACKARD
-0030C2 COMONE
-0030C3 FLUECKIGER ELEKTRONIK AG
-0030C4 Niigata Canotec Co., Inc.
-0030C5 CADENCE DESIGN SYSTEMS
-0030C6 CONTROL SOLUTIONS, INC.
-0030C7 MACROMATE CORP.
-0030C8 GAD LINE, LTD.
-0030C9 LuxN, N
-0030CA Discovery Com
-0030CB OMNI FLOW COMPUTERS, INC.
-0030CC Tenor Networks, Inc.
-0030CD CONEXANT SYSTEMS, INC.
-0030CE Zaffire
-0030CF TWO TECHNOLOGIES, INC.
-0030D1 INOVA CORPORATION
-0030D2 WIN TECHNOLOGIES, CO., LTD.
-0030D3 Agilent Technologies
-0030D4 COMTIER
-0030D5 DResearch GmbH
-0030D6 MSC VERTRIEBS GMBH
-0030D7 Innovative Systems, L.L.C.
-0030D8 SITEK
-0030D9 DATACORE SOFTWARE CORP.
-0030DA COMTREND CO.
-0030DB Mindready Solutions, Inc.
-0030DC RIGHTECH CORPORATION
-0030DD INDIGITA CORPORATION
-0030DE WAGO Kontakttechnik GmbH
-0030DF KB/TEL TELECOMUNICACIONES
-0030E0 OXFORD SEMICONDUCTOR LTD.
-0030E1 ACROTRON SYSTEMS, INC.
-0030E2 GARNET SYSTEMS CO., LTD.
-0030E3 SEDONA NETWORKS CORP.
-0030E4 CHIYODA SYSTEM RIKEN
-0030E5 Amper Datos S.A.
-0030E6 SIEMENS MEDICAL SYSTEMS
-0030E7 CNF MOBILE SOLUTIONS, INC.
-0030E8 ENSIM CORP.
-0030E9 GMA COMMUNICATION MANUFACT'G
-0030EA TeraForce Technology Corporation
-0030EB TURBONET COMMUNICATIONS, INC.
-0030EC BORGARDT
-0030ED Expert Magnetics Corp.
-0030EE DSG Technology, Inc.
-0030EF NEON TECHNOLOGY, INC.
-0030F0 Uniform Industrial Corp.
-0030F1 Accton Technology Corp.
-0030F2 CISCO SYSTEMS, INC.
-0030F3 At Work Computers
-0030F4 STARDOT TECHNOLOGIES
-0030F5 Wild Lab. Ltd.
-0030F6 SECURELOGIX CORPORATION
-0030F7 RAMIX INC.
-0030F8 Dynapro Systems, Inc.
-0030F9 Sollae Systems Co., Ltd.
-0030FA TELICA, INC.
-0030FB AZS Technology AG
-0030FC Terawave Communications, Inc.
-0030FD INTEGRATED SYSTEMS DESIGN
-0030FE DSA GmbH
-0030FF DATAFAB SYSTEMS, INC.
-004000 PCI COMPONENTES DA AMZONIA LTD
-004001 ZYXEL COMMUNICATIONS, INC.
-004002 PERLE SYSTEMS LIMITED
-004003 WESTINGHOUSE PROCESS CONTROL
-004004 ICM CO. LTD.
-004005 ANI COMMUNICATIONS INC.
-004006 SAMPO TECHNOLOGY CORPORATION
-004007 TELMAT INFORMATIQUE
-004008 A PLUS INFO CORPORATION
-004009 TACHIBANA TECTRON CO., LTD.
-00400A PIVOTAL TECHNOLOGIES, INC.
-00400B CISCO SYSTEMS, INC.
-00400C GENERAL MICRO SYSTEMS, INC.
-00400D LANNET DATA COMMUNICATIONS,LTD
-00400E MEMOTEC COMMUNICATIONS, INC.
-00400F DATACOM TECHNOLOGIES
-004010 SONIC SYSTEMS, INC.
-004011 ANDOVER CONTROLS CORPORATION
-004012 WINDATA, INC.
-004013 NTT DATA COMM. SYSTEMS CORP.
-004014 COMSOFT GMBH
-004015 ASCOM INFRASYS AG
-004016 HADAX ELECTRONICS, INC.
-004017 XCD INC.
-004018 ADOBE SYSTEMS, INC.
-004019 AEON SYSTEMS, INC.
-00401A FUJI ELECTRIC CO., LTD.
-00401B PRINTER SYSTEMS CORP.
-00401C AST RESEARCH, INC.
-00401D INVISIBLE SOFTWARE, INC.
-00401E ICC
-00401F COLORGRAPH LTD
-004020 PINACL COMMUNICATION
-004021 RASTER GRAPHICS
-004022 KLEVER COMPUTERS, INC.
-004023 LOGIC CORPORATION
-004024 COMPAC INC.
-004025 MOLECULAR DYNAMICS
-004026 MELCO, INC.
-004027 SMC MASSACHUSETTS, INC.
-004028 NETCOMM LIMITED
-004029 COMPEX
-00402A CANOGA-PERKINS
-00402B TRIGEM COMPUTER, INC.
-00402C ISIS DISTRIBUTED SYSTEMS, INC.
-00402D HARRIS ADACOM CORPORATION
-00402E PRECISION SOFTWARE, INC.
-00402F XLNT DESIGNS INC.
-004030 GK COMPUTER
-004031 KOKUSAI ELECTRIC CO., LTD
-004032 DIGITAL COMMUNICATIONS
-004033 ADDTRON TECHNOLOGY CO., LTD.
-004034 BUSTEK CORPORATION
-004035 OPCOM
-004036 TRIBE COMPUTER WORKS, INC.
-004037 SEA-ILAN, INC.
-004038 TALENT ELECTRIC INCORPORATED
-004039 OPTEC DAIICHI DENKO CO., LTD.
-00403A IMPACT TECHNOLOGIES
-00403B SYNERJET INTERNATIONAL CORP.
-00403C FORKS, INC.
-00403D TERADATA
-00403E RASTER OPS CORPORATION
-00403F SSANGYONG COMPUTER SYSTEMS
-004040 RING ACCESS, INC.
-004041 FUJIKURA LTD.
-004042 N.A.T. GMBH
-004043 NOKIA TELECOMMUNICATIONS
-004044 QNIX COMPUTER CO., LTD.
-004045 TWINHEAD CORPORATION
-004046 UDC RESEARCH LIMITED
-004047 WIND RIVER SYSTEMS
-004048 SMD INFORMATICA S.A.
-004049 TEGIMENTA AG
-00404A WEST AUSTRALIAN DEPARTMENT
-00404B MAPLE COMPUTER SYSTEMS
-00404C HYPERTEC PTY LTD.
-00404D TELECOMMUNICATIONS TECHNIQUES
-00404E FLUENT, INC.
-00404F SPACE & NAVAL WARFARE SYSTEMS
-004050 IRONICS, INCORPORATED
-004051 GRACILIS, INC.
-004052 STAR TECHNOLOGIES, INC.
-004053 AMPRO COMPUTERS
-004054 CONNECTION MACHINES SERVICES
-004055 METRONIX GMBH
-004056 MCM JAPAN LTD.
-004057 LOCKHEED - SANDERS
-004058 KRONOS, INC.
-004059 YOSHIDA KOGYO K. K.
-00405A GOLDSTAR INFORMATION & COMM.
-00405B FUNASSET LIMITED
-00405C FUTURE SYSTEMS, INC.
-00405D STAR-TEK, INC.
-00405E NORTH HILLS ISRAEL
-00405F AFE COMPUTERS LTD.
-004060 COMENDEC LTD
-004061 DATATECH ENTERPRISES CO., LTD.
-004062 E-SYSTEMS, INC./GARLAND DIV.
-004063 VIA TECHNOLOGIES, INC.
-004064 KLA INSTRUMENTS CORPORATION
-004065 GTE SPACENET
-004066 HITACHI CABLE, LTD.
-004067 OMNIBYTE CORPORATION
-004068 EXTENDED SYSTEMS
-004069 LEMCOM SYSTEMS, INC.
-00406A KENTEK INFORMATION SYSTEMS,INC
-00406B SYSGEN
-00406C COPERNIQUE
-00406D LANCO, INC.
-00406E COROLLARY, INC.
-00406F SYNC RESEARCH INC.
-004070 INTERWARE CO., LTD.
-004071 ATM COMPUTER GMBH
-004072 Applied Innovation Inc.
-004073 BASS ASSOCIATES
-004074 CABLE AND WIRELESS
-004075 M-TRADE (UK) LTD
-004076 Sun Conversion Technologies
-004077 MAXTON TECHNOLOGY CORPORATION
-004078 WEARNES AUTOMATION PTE LTD
-004079 JUKO MANUFACTURE COMPANY, LTD.
-00407A SOCIETE D'EXPLOITATION DU CNIT
-00407B SCIENTIFIC ATLANTA
-00407C QUME CORPORATION
-00407D EXTENSION TECHNOLOGY CORP.
-00407E EVERGREEN SYSTEMS, INC.
-00407F FLIR Systems
-004080 ATHENIX CORPORATION
-004081 MANNESMANN SCANGRAPHIC GMBH
-004082 LABORATORY EQUIPMENT CORP.
-004083 TDA INDUSTRIA DE PRODUTOS
-004084 HONEYWELL INC.
-004085 SAAB INSTRUMENTS AB
-004086 MICHELS & KLEBERHOFF COMPUTER
-004087 UBITREX CORPORATION
-004088 MOBIUS TECHNOLOGIES, INC.
-004089 MEIDENSHA CORPORATION
-00408A TPS TELEPROCESSING SYS. GMBH
-00408B RAYLAN CORPORATION
-00408C AXIS COMMUNICATIONS AB
-00408D THE GOODYEAR TIRE & RUBBER CO.
-00408E DIGILOG, INC.
-00408F WM-DATA MINFO AB
-004090 ANSEL COMMUNICATIONS
-004091 PROCOMP INDUSTRIA ELETRONICA
-004092 ASP COMPUTER PRODUCTS, INC.
-004093 PAXDATA NETWORKS LTD.
-004094 SHOGRAPHICS, INC.
-004095 R.P.T. INTERGROUPS INT'L LTD.
-004096 Aironet Wireless Communication
-004097 DATEX DIVISION OF
-004098 DRESSLER GMBH & CO.
-004099 NEWGEN SYSTEMS CORP.
-00409A NETWORK EXPRESS, INC.
-00409B HAL COMPUTER SYSTEMS INC.
-00409C TRANSWARE
-00409D DIGIBOARD, INC.
-00409E CONCURRENT TECHNOLOGIES  LTD.
-00409F LANCAST/CASAT TECHNOLOGY, INC.
-0040A0 GOLDSTAR CO., LTD.
-0040A1 ERGO COMPUTING
-0040A2 KINGSTAR TECHNOLOGY INC.
-0040A3 MICROUNITY SYSTEMS ENGINEERING
-0040A4 ROSE ELECTRONICS
-0040A5 CLINICOMP INTL.
-0040A6 Cray, Inc.
-0040A7 ITAUTEC PHILCO S.A.
-0040A8 IMF INTERNATIONAL LTD.
-0040A9 DATACOM INC.
-0040AA VALMET AUTOMATION INC.
-0040AB ROLAND DG CORPORATION
-0040AC SUPER WORKSTATION, INC.
-0040AD SMA REGELSYSTEME GMBH
-0040AE DELTA CONTROLS, INC.
-0040AF DIGITAL PRODUCTS, INC.
-0040B0 BYTEX CORPORATION, ENGINEERING
-0040B1 CODONICS INC.
-0040B2 SYSTEMFORSCHUNG
-0040B3 PAR MICROSYSTEMS CORPORATION
-0040B4 NEXTCOM K.K.
-0040B5 VIDEO TECHNOLOGY COMPUTERS LTD
-0040B6 COMPUTERM  CORPORATION
-0040B7 STEALTH COMPUTER SYSTEMS
-0040B8 IDEA ASSOCIATES
-0040B9 MACQ ELECTRONIQUE SA
-0040BA ALLIANT COMPUTER SYSTEMS CORP.
-0040BB GOLDSTAR CABLE CO., LTD.
-0040BC ALGORITHMICS LTD.
-0040BD STARLIGHT NETWORKS, INC.
-0040BE BOEING DEFENSE & SPACE
-0040BF CHANNEL SYSTEMS INTERN'L INC.
-0040C0 VISTA CONTROLS CORPORATION
-0040C1 BIZERBA-WERKE WILHEIM KRAUT
-0040C2 APPLIED COMPUTING DEVICES
-0040C3 FISCHER AND PORTER CO.
-0040C4 KINKEI SYSTEM CORPORATION
-0040C5 MICOM COMMUNICATIONS INC.
-0040C6 FIBERNET RESEARCH, INC.
-0040C7 RUBY TECH CORPORATION
-0040C8 MILAN TECHNOLOGY CORPORATION
-0040C9 NCUBE
-0040CA FIRST INTERNAT'L COMPUTER, INC
-0040CB LANWAN TECHNOLOGIES
-0040CC SILCOM MANUF'G TECHNOLOGY INC.
-0040CD TERA MICROSYSTEMS, INC.
-0040CE NET-SOURCE, INC.
-0040CF STRAWBERRY TREE, INC.
-0040D0 MITAC INTERNATIONAL CORP.
-0040D1 FUKUDA DENSHI CO., LTD.
-0040D2 PAGINE CORPORATION
-0040D3 KIMPSION INTERNATIONAL CORP.
-0040D4 GAGE TALKER CORP.
-0040D5 SARTORIUS AG
-0040D6 LOCAMATION B.V.
-0040D7 STUDIO GEN INC.
-0040D8 OCEAN OFFICE AUTOMATION LTD.
-0040D9 AMERICAN MEGATRENDS INC.
-0040DA TELSPEC LTD
-0040DB ADVANCED TECHNICAL SOLUTIONS
-0040DC TRITEC ELECTRONIC GMBH
-0040DD HONG TECHNOLOGIES
-0040DE ELETTRONICA SAN GIORGIO
-0040DF DIGALOG SYSTEMS, INC.
-0040E0 ATOMWIDE LTD.
-0040E1 MARNER INTERNATIONAL, INC.
-0040E2 MESA RIDGE TECHNOLOGIES, INC.
-0040E3 QUIN SYSTEMS LTD
-0040E4 E-M TECHNOLOGY, INC.
-0040E5 SYBUS CORPORATION
-0040E6 C.A.E.N.
-0040E7 ARNOS INSTRUMENTS & COMPUTER
-0040E8 CHARLES RIVER DATA SYSTEMS,INC
-0040E9 ACCORD SYSTEMS, INC.
-0040EA PLAIN TREE SYSTEMS INC
-0040EB MARTIN MARIETTA CORPORATION
-0040EC MIKASA SYSTEM ENGINEERING
-0040ED NETWORK CONTROLS INT'NATL INC.
-0040EE OPTIMEM
-0040EF HYPERCOM, INC.
-0040F0 MICRO SYSTEMS, INC.
-0040F1 CHUO ELECTRONICS CO., LTD.
-0040F2 JANICH & KLASS COMPUTERTECHNIK
-0040F3 NETCOR
-0040F4 CAMEO COMMUNICATIONS, INC.
-0040F5 OEM ENGINES
-0040F6 KATRON COMPUTERS INC.
-0040F7 POLAROID MEDICAL IMAGING SYS.
-0040F8 SYSTEMHAUS DISCOM
-0040F9 COMBINET
-0040FA MICROBOARDS, INC.
-0040FB CASCADE COMMUNICATIONS CORP.
-0040FC IBR COMPUTER TECHNIK GMBH
-0040FD LXE
-0040FE SYMPLEX COMMUNICATIONS
-0040FF TELEBIT CORPORATION
-004252 RLX Technologies
-005000 NEXO COMMUNICATIONS, INC.
-005001 YAMASHITA SYSTEMS CORP.
-005002 OMNISEC AG
-005003 GRETAG MACBETH AG
-005004 3COM CORPORATION
-005006 TAC AB
-005007 SIEMENS TELECOMMUNICATION SYSTEMS LIMITED
-005008 TIVA MICROCOMPUTER CORP. (TMC)
-005009 PHILIPS BROADBAND NETWORKS
-00500A IRIS TECHNOLOGIES, INC.
-00500B CISCO SYSTEMS, INC.
-00500C e-Tek Labs, Inc.
-00500D SATORI ELECTORIC CO., LTD.
-00500E CHROMATIS NETWORKS, INC.
-00500F CISCO SYSTEMS, INC.
-005010 NovaNET Learning, Inc.
-005012 CBL - GMBH
-005013 Chaparral Network Storage
-005014 CISCO SYSTEMS, INC.
-005015 BRIGHT STAR ENGINEERING
-005016 SST/WOODHEAD INDUSTRIES
-005017 RSR S.R.L.
-005018 ADVANCED MULTIMEDIA INTERNET TECHNOLOGY INC.
-005019 SPRING TIDE NETWORKS, INC.
-00501A UISIQN
-00501B ABL CANADA, INC.
-00501C JATOM SYSTEMS, INC.
-00501E Miranda Technologies, Inc.
-00501F MRG SYSTEMS, LTD.
-005020 MEDIASTAR CO., LTD.
-005021 EIS INTERNATIONAL, INC.
-005022 ZONET TECHNOLOGY, INC.
-005023 PG DESIGN ELECTRONICS, INC.
-005024 NAVIC SYSTEMS, INC.
-005026 COSYSTEMS, INC.
-005027 GENICOM CORPORATION
-005028 AVAL COMMUNICATIONS
-005029 1394 PRINTER WORKING GROUP
-00502A CISCO SYSTEMS, INC.
-00502B GENRAD LTD.
-00502C SOYO COMPUTER, INC.
-00502D ACCEL, INC.
-00502E CAMBEX CORPORATION
-00502F TollBridge Technologies, Inc.
-005030 FUTURE PLUS SYSTEMS
-005031 AEROFLEX LABORATORIES, INC.
-005032 PICAZO COMMUNICATIONS, INC.
-005033 MAYAN NETWORKS
-005036 NETCAM, LTD.
-005037 KOGA ELECTRONICS CO.
-005038 DAIN TELECOM CO., LTD.
-005039 MARINER NETWORKS
-00503A DATONG ELECTRONICS LTD.
-00503B MEDIAFIRE CORPORATION
-00503C TSINGHUA NOVEL ELECTRONICS
-00503E CISCO SYSTEMS, INC.
-00503F ANCHOR GAMES
-005040 EMWARE, INC.
-005041 CTX OPTO ELECTRONIC CORP.
-005042 SCI MANUFACTURING SINGAPORE PTE, LTD.
-005043 MARVELL SEMICONDUCTOR, INC.
-005044 ASACA CORPORATION
-005045 RIOWORKS SOLUTIONS, INC.
-005046 MENICX INTERNATIONAL CO., LTD.
-005048 INFOLIBRIA
-005049 ELLACOYA NETWORKS, INC.
-00504A ELTECO A.S.
-00504B BARCONET N.V.
-00504C GALIL MOTION CONTROL, INC.
-00504D TOKYO ELECTRON DEVICE LTD.
-00504E SIERRA MONITOR CORP.
-00504F OLENCOM ELECTRONICS
-005050 CISCO SYSTEMS, INC.
-005051 IWATSU ELECTRIC CO., LTD.
-005052 TIARA NETWORKS, INC.
-005053 CISCO SYSTEMS, INC.
-005054 CISCO SYSTEMS, INC.
-005055 DOMS A/S
-005056 VMWare, Inc.
-005057 BROADBAND ACCESS SYSTEMS
-005058 VEGASTREAM LIMITED
-005059 SUITE TECHNOLOGY SYSTEMS NETWORK
-00505A NETWORK ALCHEMY, INC.
-00505B KAWASAKI LSI U.S.A., INC.
-00505C TUNDO CORPORATION
-00505E DIGITEK MICROLOGIC S.A.
-00505F BRAND INNOVATORS
-005060 TANDBERG TELECOM AS
-005062 KOUWELL ELECTRONICS CORP.  **
-005063 OY COMSEL SYSTEM AB
-005064 CAE ELECTRONICS
-005065 DENSEI-LAMBAD Co., Ltd.
-005066 AtecoM GmbH advanced telecomunication modules
-005067 AEROCOMM, INC.
-005068 ELECTRONIC INDUSTRIES ASSOCIATION
-005069 PixStream Incorporated
-00506A EDEVA, INC.
-00506B SPX-ATEG
-00506C G & L BEIJER ELECTRONICS AB
-00506D VIDEOJET SYSTEMS
-00506E CORDER ENGINEERING CORPORATION
-00506F G-CONNECT
-005070 CHAINTECH COMPUTER CO., LTD.
-005071 AIWA CO., LTD.
-005072 CORVIS CORPORATION
-005073 CISCO SYSTEMS, INC.
-005074 ADVANCED HI-TECH CORP.
-005075 KESTREL SOLUTIONS
-005076 IBM
-005077 PROLIFIC TECHNOLOGY, INC.
-005078 MEGATON HOUSE, LTD.
-00507A XPEED, INC.
-00507B MERLOT COMMUNICATIONS
-00507C VIDEOCON AG
-00507D IFP
-00507E NEWER TECHNOLOGY
-00507F DrayTek Corp.
-005080 CISCO SYSTEMS, INC.
-005081 MURATA MACHINERY, LTD.
-005082 FORESSON CORPORATION
-005083 GILBARCO, INC.
-005084 ATL PRODUCTS
-005086 TELKOM SA, LTD.
-005087 TERASAKI ELECTRIC CO., LTD.
-005088 AMANO CORPORATION
-005089 SAFETY MANAGEMENT SYSTEMS
-00508B COMPAQ COMPUTER CORPORATION
-00508C RSI SYSTEMS
-00508D ABIT COMPUTER CORPORATION
-00508E OPTIMATION, INC.
-00508F ASITA TECHNOLOGIES INT'L LTD.
-005090 DCTRI
-005091 NETACCESS, INC.
-005092 RIGAKU INDUSTRIAL CORPORATION
-005093 BOEING
-005094 PACE MICRO TECHNOLOGY PLC
-005095 PERACOM NETWORKS
-005096 SALIX TECHNOLOGIES, INC.
-005097 MMC-EMBEDDED COMPUTERTECHNIK GmbH
-005098 GLOBALOOP, LTD.
-005099 3COM EUROPE, LTD.
-00509A TAG ELECTRONIC SYSTEMS
-00509B SWITCHCORE AB
-00509C BETA RESEARCH
-00509D THE INDUSTREE B.V.
-00509E Les Technologies SoftAcoustik Inc.
-00509F HORIZON COMPUTER
-0050A0 DELTA COMPUTER SYSTEMS, INC.
-0050A1 CARLO GAVAZZI, INC.
-0050A2 CISCO SYSTEMS, INC.
-0050A3 TransMedia Communications, Inc.
-0050A4 IO TECH, INC.
-0050A5 CAPITOL BUSINESS SYSTEMS, LTD.
-0050A6 OPTRONICS
-0050A7 CISCO SYSTEMS, INC.
-0050A8 OpenCon Systems, Inc.
-0050A9 MOLDAT WIRELESS TECHNOLGIES
-0050AA KONICA MINOLTA HOLDINGS, INC.
-0050AB NALTEC, INC.
-0050AC MAPLE COMPUTER CORPORATION
-0050AD CommUnique Wireless Corp.
-0050AE IWAKI ELECTRONICS CO., LTD.
-0050AF INTERGON, INC.
-0050B0 TECHNOLOGY ATLANTA CORPORATION
-0050B1 GIDDINGS & LEWIS
-0050B2 BRODEL AUTOMATION
-0050B3 VOICEBOARD CORPORATION
-0050B4 SATCHWELL CONTROL SYSTEMS, LTD
-0050B5 FICHET-BAUCHE
-0050B6 GOOD WAY IND. CO., LTD.
-0050B7 BOSER TECHNOLOGY CO., LTD.
-0050B8 INOVA COMPUTERS GMBH & CO. KG
-0050B9 XITRON TECHNOLOGIES, INC.
-0050BA D-LINK
-0050BB CMS TECHNOLOGIES
-0050BC HAMMER STORAGE SOLUTIONS
-0050BD CISCO SYSTEMS, INC.
-0050BE FAST MULTIMEDIA AG
-0050BF MOTOTECH INC.
-0050C0 GATAN, INC.
-0050C1 GEMFLEX NETWORKS, LTD.
-0050C2 IEEE REGISTRATION AUTHORITY
-0050C4 IMD
-0050C5 ADS TECHNOLOGIES, INC.
-0050C6 LOOP TELECOMMUNICATION INTERNATIONAL, INC.
-0050C8 ADDONICS COMMUNICATIONS, INC.
-0050C9 MASPRO DENKOH CORP.
-0050CA NET TO NET TECHNOLOGIES
-0050CB JETTER
-0050CC XYRATEX
-0050CD DIGIANSWER A/S
-0050CE LG INTERNATIONAL CORP.
-0050CF VANLINK COMMUNICATION TECHNOLOGY RESEARCH INSTITUTE
-0050D0 MINERVA SYSTEMS
-0050D1 CISCO SYSTEMS, INC.
-0050D2 BAE Systems Canada, Inc.
-0050D3 DIGITAL AUDIO PROCESSING PTY. LTD.
-0050D4 JOOHONG INFORMATION &
-0050D5 AD SYSTEMS CORP.
-0050D6 ATLAS COPCO TOOLS AB
-0050D7 TELSTRAT
-0050D8 UNICORN COMPUTER CORP.
-0050D9 ENGETRON-ENGENHARIA ELETRONICA IND. e COM. LTDA
-0050DA 3COM CORPORATION
-0050DB CONTEMPORARY CONTROL
-0050DC TAS TELEFONBAU A. SCHWABE GMBH & CO. KG
-0050DD SERRA SOLDADURA, S.A.
-0050DE SIGNUM SYSTEMS CORP.
-0050DF AirFiber, Inc.
-0050E1 NS TECH ELECTRONICS SDN BHD
-0050E2 CISCO SYSTEMS, INC.
-0050E3 Terayon Communications Systems
-0050E4 APPLE COMPUTER, INC.
-0050E6 HAKUSAN CORPORATION
-0050E7 PARADISE INNOVATIONS (ASIA)
-0050E8 NOMADIX INC.
-0050EA XEL COMMUNICATIONS, INC.
-0050EB ALPHA-TOP CORPORATION
-0050EC OLICOM A/S
-0050ED ANDA NETWORKS
-0050EE TEK DIGITEL CORPORATION
-0050EF SPE Systemhaus GmbH
-0050F0 CISCO SYSTEMS, INC.
-0050F1 LIBIT SIGNAL PROCESSING, LTD.
-0050F2 MICROSOFT CORP.
-0050F3 GLOBAL NET INFORMATION CO., Ltd.
-0050F4 SIGMATEK GMBH & CO. KG
-0050F6 PAN-INTERNATIONAL INDUSTRIAL CORP.
-0050F7 VENTURE MANUFACTURING (SINGAPORE) LTD.
-0050F8 ENTREGA TECHNOLOGIES, INC.
-0050FA OXTEL, LTD.
-0050FB VSK ELECTRONICS
-0050FC EDIMAX TECHNOLOGY CO., LTD.
-0050FD VISIONCOMM CO., LTD.
-0050FE PCTVnet ASA
-0050FF HAKKO ELECTRONICS CO., LTD.
-006000 XYCOM INC.
-006001 InnoSys, Inc.
-006002 SCREEN SUBTITLING SYSTEMS, LTD
-006003 TERAOKA WEIGH SYSTEM PTE, LTD.
-006004 COMPUTADORES MODULARES SA
-006005 FEEDBACK DATA LTD.
-006006 SOTEC CO., LTD
-006007 ACRES GAMING, INC.
-006008 3COM CORPORATION
-006009 CISCO SYSTEMS, INC.
-00600A SORD COMPUTER CORPORATION
-00600B LOGWARE GmbH
-00600C APPLIED DATA SYSTEMS, INC.
-00600D Digital Logic GmbH
-00600E WAVENET INTERNATIONAL, INC.
-00600F WESTELL, INC.
-006010 NETWORK MACHINES, INC.
-006011 CRYSTAL SEMICONDUCTOR CORP.
-006012 POWER COMPUTING CORPORATION
-006013 NETSTAL MASCHINEN AG
-006014 EDEC CO., LTD.
-006015 NET2NET CORPORATION
-006016 CLARIION
-006017 TOKIMEC INC.
-006018 STELLAR ONE CORPORATION
-006019 Roche Diagnostics
-00601A KEITHLEY INSTRUMENTS
-00601B MESA ELECTRONICS
-00601C TELXON CORPORATION
-00601D LUCENT TECHNOLOGIES
-00601E SOFTLAB, INC.
-00601F STALLION TECHNOLOGIES
-006020 PIVOTAL NETWORKING, INC.
-006021 DSC CORPORATION
-006022 VICOM SYSTEMS, INC.
-006023 PERICOM SEMICONDUCTOR CORP.
-006024 GRADIENT TECHNOLOGIES, INC.
-006025 ACTIVE IMAGING PLC
-006026 VIKING COMPONENTS, INC.
-006027 Superior Modular Products
-006028 MACROVISION CORPORATION
-006029 CARY PERIPHERALS INC.
-00602A SYMICRON COMPUTER COMMUNICATIONS, LTD.
-00602B PEAK AUDIO
-00602C LINX Data Terminals, Inc.
-00602D ALERTON TECHNOLOGIES, INC.
-00602E CYCLADES CORPORATION
-00602F CISCO SYSTEMS, INC.
-006030 VILLAGE TRONIC ENTWICKLUNG
-006031 HRK SYSTEMS
-006032 I-CUBE, INC.
-006033 ACUITY IMAGING, INC.
-006034 ROBERT BOSCH GmbH
-006035 DALLAS SEMICONDUCTOR, INC.
-006036 AUSTRIAN RESEARCH CENTER SEIBERSDORF
-006037 PHILIPS SEMICONDUCTORS
-006038 Nortel Networks
-006039 SanCom Technology, Inc.
-00603A QUICK CONTROLS LTD.
-00603B AMTEC spa
-00603C HAGIWARA SYS-COM CO., LTD.
-00603D 3CX
-00603E CISCO SYSTEMS, INC.
-00603F PATAPSCO DESIGNS
-006040 NETRO CORP.
-006041 Yokogawa Electric Corporation
-006042 TKS (USA), INC.
-006043 ComSoft Systems, Inc.
-006044 LITTON/POLY-SCIENTIFIC
-006045 PATHLIGHT TECHNOLOGIES
-006046 VMETRO, INC.
-006047 CISCO SYSTEMS, INC.
-006048 EMC CORPORATION
-006049 VINA TECHNOLOGIES
-00604A SAIC IDEAS GROUP
-00604B BIODATA GmbH
-00604C SAT
-00604D MMC NETWORKS, INC.
-00604E CYCLE COMPUTER CORPORATION, INC.
-00604F SUZUKI MFG. CO., LTD.
-006050 INTERNIX INC.
-006051 QUALITY SEMICONDUCTOR
-006052 PERIPHERALS ENTERPRISE CO., Ltd.
-006053 TOYODA MACHINE WORKS, LTD.
-006054 CONTROLWARE GMBH
-006055 CORNELL UNIVERSITY
-006056 NETWORK TOOLS, INC.
-006057 MURATA MANUFACTURING CO., LTD.
-006058 COPPER MOUNTAIN COMMUNICATIONS, INC.
-006059 TECHNICAL COMMUNICATIONS CORP.
-00605A CELCORE, INC.
-00605B IntraServer Technology, Inc.
-00605C CISCO SYSTEMS, INC.
-00605D SCANIVALVE CORP.
-00605E LIBERTY TECHNOLOGY NETWORKING
-00605F NIPPON UNISOFT CORPORATION
-006060 DAWNING TECHNOLOGIES, INC.
-006061 WHISTLE COMMUNICATIONS CORP.
-006062 TELESYNC, INC.
-006063 PSION DACOM PLC.
-006064 NETCOMM LIMITED
-006065 BERNECKER & RAINER INDUSTRIE-ELEKTRONIC GmbH
-006066 LACROIX TECHNOLGIE
-006067 ACER NETXUS INC.
-006068 EICON TECHNOLOGY CORPORATION
-006069 BROCADE COMMUNICATIONS SYSTEMS, Inc.
-00606A MITSUBISHI WIRELESS COMMUNICATIONS. INC.
-00606B Synclayer Inc.
-00606C ARESCOM
-00606D DIGITAL EQUIPMENT CORP.
-00606E DAVICOM SEMICONDUCTOR, INC.
-00606F CLARION CORPORATION OF AMERICA
-006070 CISCO SYSTEMS, INC.
-006071 MIDAS LAB, INC.
-006072 VXL INSTRUMENTS, LIMITED
-006073 REDCREEK COMMUNICATIONS, INC.
-006074 QSC AUDIO PRODUCTS
-006075 PENTEK, INC.
-006076 SCHLUMBERGER TECHNOLOGIES RETAIL PETROLEUM SYSTEMS
-006077 PRISA NETWORKS
-006078 POWER MEASUREMENT LTD.
-006079 Mainstream Data, Inc.
-00607A DVS GmbH
-00607B FORE SYSTEMS, INC.
-00607C WaveAccess, Ltd.
-00607D SENTIENT NETWORKS INC.
-00607E GIGALABS, INC.
-00607F AURORA TECHNOLOGIES, INC.
-006080 MICROTRONIX DATACOM LTD.
-006081 TV/COM INTERNATIONAL
-006082 NOVALINK TECHNOLOGIES, INC.
-006083 CISCO SYSTEMS, INC.
-006084 DIGITAL VIDEO
-006085 Storage Concepts
-006086 LOGIC REPLACEMENT TECH. LTD.
-006087 KANSAI ELECTRIC CO., LTD.
-006088 WHITE MOUNTAIN DSP, INC.
-006089 XATA
-00608A CITADEL COMPUTER
-00608B ConferTech International
-00608C 3COM CORPORATION
-00608D UNIPULSE CORP.
-00608E HE ELECTRONICS, TECHNOLOGIE & SYSTEMTECHNIK GmbH
-00608F TEKRAM TECHNOLOGY CO., LTD.
-006090 ABLE COMMUNICATIONS, INC.
-006091 FIRST PACIFIC NETWORKS, INC.
-006092 MICRO/SYS, INC.
-006093 VARIAN
-006094 IBM CORP.
-006095 ACCU-TIME SYSTEMS, INC.
-006096 T.S. MICROTECH INC.
-006097 3COM CORPORATION
-006098 HT COMMUNICATIONS
-006099 LAN MEDIA CORPORATION
-00609A NJK TECHNO CO.
-00609B ASTRO-MED, INC.
-00609C Perkin-Elmer Incorporated
-00609D PMI FOOD EQUIPMENT GROUP
-00609E ASC X3 - INFORMATION TECHNOLOGY STANDARDS SECRETARIATS
-00609F PHAST CORPORATION
-0060A0 SWITCHED NETWORK TECHNOLOGIES, INC.
-0060A1 VPNet, Inc.
-0060A2 NIHON UNISYS LIMITED CO.
-0060A3 CONTINUUM TECHNOLOGY CORP.
-0060A4 GRINAKER SYSTEM TECHNOLOGIES
-0060A5 PERFORMANCE TELECOM CORP.
-0060A6 PARTICLE MEASURING SYSTEMS
-0060A7 MICROSENS GmbH & CO. KG
-0060A8 TIDOMAT AB
-0060A9 GESYTEC MbH
-0060AA INTELLIGENT DEVICES INC. (IDI)
-0060AB LARSCOM INCORPORATED
-0060AC RESILIENCE CORPORATION
-0060AD MegaChips Corporation
-0060AE TRIO INFORMATION SYSTEMS AB
-0060AF PACIFIC MICRO DATA, INC.
-0060B0 HEWLETT-PACKARD CO.
-0060B1 INPUT/OUTPUT, INC.
-0060B2 PROCESS CONTROL CORP.
-0060B3 Z-COM, INC.
-0060B4 GLENAYRE R&D INC.
-0060B5 KEBA GmbH
-0060B6 LAND COMPUTER CO., LTD.
-0060B7 CHANNELMATIC, INC.
-0060B8 CORELIS INC.
-0060B9 NITSUKO CORPORATION
-0060BA SAHARA NETWORKS, INC.
-0060BB CABLETRON - NETLINK, INC.
-0060BC KeunYoung Electronics & Communication Co., Ltd.
-0060BD HUBBELL-PULSECOM
-0060BE WEBTRONICS
-0060BF MACRAIGOR SYSTEMS, INC.
-0060C0 NERA AS
-0060C1 WaveSpan Corporation
-0060C2 MPL AG
-0060C3 NETVISION CORPORATION
-0060C4 SOLITON SYSTEMS K.K.
-0060C5 ANCOT CORP.
-0060C6 DCS AG
-0060C7 AMATI COMMUNICATIONS CORP.
-0060C8 KUKA WELDING SYSTEMS & ROBOTS
-0060C9 ControlNet, Inc.
-0060CA HARMONIC SYSTEMS INCORPORATED
-0060CB HITACHI ZOSEN CORPORATION
-0060CC EMTRAK, INCORPORATED
-0060CD VideoServer, Inc.
-0060CE ACCLAIM COMMUNICATIONS
-0060CF ALTEON NETWORKS, INC.
-0060D0 SNMP RESEARCH INCORPORATED
-0060D1 CASCADE COMMUNICATIONS
-0060D2 LUCENT TECHNOLOGIES TAIWAN TELECOMMUNICATIONS CO., LTD.
-0060D3 AT&T
-0060D4 ELDAT COMMUNICATION LTD.
-0060D5 MIYACHI TECHNOS CORP.
-0060D6 NovAtel Wireless Technologies Ltd.
-0060D7 ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE (EPFL)
-0060D8 ELMIC SYSTEMS, INC.
-0060D9 TRANSYS NETWORKS INC.
-0060DA JBM ELECTRONICS CO.
-0060DB NTP ELEKTRONIK A/S
-0060DC TOYO COMMUNICATION EQUIPMENT Co., Ltd.
-0060DD MYRICOM, INC.
-0060DE KAYSER-THREDE GmbH
-0060DF CNT Corporation
-0060E0 AXIOM TECHNOLOGY CO., LTD.
-0060E1 ORCKIT COMMUNICATIONS LTD.
-0060E2 QUEST ENGINEERING & DEVELOPMENT
-0060E3 ARBIN INSTRUMENTS
-0060E4 COMPUSERVE, INC.
-0060E5 FUJI AUTOMATION CO., LTD.
-0060E6 SHOMITI SYSTEMS INCORPORATED
-0060E7 RANDATA
-0060E8 HITACHI COMPUTER PRODUCTS (AMERICA), INC.
-0060E9 ATOP TECHNOLOGIES, INC.
-0060EA StreamLogic
-0060EB FOURTHTRACK SYSTEMS
-0060EC HERMARY OPTO ELECTRONICS INC.
-0060ED RICARDO TEST AUTOMATION LTD.
-0060EE APOLLO
-0060EF FLYTECH TECHNOLOGY CO., LTD.
-0060F0 JOHNSON & JOHNSON MEDICAL, INC
-0060F1 EXP COMPUTER, INC.
-0060F2 LASERGRAPHICS, INC.
-0060F3 Performance Analysis Broadband, Spirent plc
-0060F4 ADVANCED COMPUTER SOLUTIONS, Inc.
-0060F5 ICON WEST, INC.
-0060F6 NEXTEST COMMUNICATIONS PRODUCTS, INC.
-0060F7 DATAFUSION SYSTEMS
-0060F8 Loran International Technologies Inc.
-0060F9 DIAMOND LANE COMMUNICATIONS
-0060FA EDUCATIONAL TECHNOLOGY RESOURCES, INC.
-0060FB PACKETEER, INC.
-0060FC CONSERVATION THROUGH INNOVATION LTD.
-0060FD NetICs, Inc.
-0060FE LYNX SYSTEM DEVELOPERS, INC.
-0060FF QuVis, Inc.
-0070B0 M/A-COM INC. COMPANIES
-0070B3 DATA RECALL LTD.
-008000 MULTITECH SYSTEMS, INC.
-008001 PERIPHONICS CORPORATION
-008002 SATELCOM (UK) LTD
-008003 HYTEC ELECTRONICS LTD.
-008004 ANTLOW COMMUNICATIONS, LTD.
-008005 CACTUS COMPUTER INC.
-008006 COMPUADD CORPORATION
-008007 DLOG NC-SYSTEME
-008008 DYNATECH COMPUTER SYSTEMS
-008009 JUPITER SYSTEMS, INC.
-00800A JAPAN COMPUTER CORP.
-00800B CSK CORPORATION
-00800C VIDECOM LIMITED
-00800D VOSSWINKEL F.U.
-00800E ATLANTIX CORPORATION
-00800F STANDARD MICROSYSTEMS
-008010 COMMODORE INTERNATIONAL
-008011 DIGITAL SYSTEMS INT'L. INC.
-008012 INTEGRATED MEASUREMENT SYSTEMS
-008013 THOMAS-CONRAD CORPORATION
-008014 ESPRIT SYSTEMS
-008015 SEIKO SYSTEMS, INC.
-008016 WANDEL AND GOLTERMANN
-008017 PFU LIMITED
-008018 KOBE STEEL, LTD.
-008019 DAYNA COMMUNICATIONS, INC.
-00801A BELL ATLANTIC
-00801B KODIAK TECHNOLOGY
-00801C NEWPORT SYSTEMS SOLUTIONS
-00801D INTEGRATED INFERENCE MACHINES
-00801E XINETRON, INC.
-00801F KRUPP ATLAS ELECTRONIK GMBH
-008020 NETWORK PRODUCTS
-008021 Alcatel Canada Inc.
-008022 SCAN-OPTICS
-008023 INTEGRATED BUSINESS NETWORKS
-008024 KALPANA, INC.
-008025 STOLLMANN GMBH
-008026 NETWORK PRODUCTS CORPORATION
-008027 ADAPTIVE SYSTEMS, INC.
-008028 TRADPOST (HK) LTD
-008029 EAGLE TECHNOLOGY, INC.
-00802A TEST SYSTEMS & SIMULATIONS INC
-00802B INTEGRATED MARKETING CO
-00802C THE SAGE GROUP PLC
-00802D XYLOGICS INC
-00802E CASTLE ROCK COMPUTING
-00802F NATIONAL INSTRUMENTS CORP.
-008030 NEXUS ELECTRONICS
-008031 BASYS, CORP.
-008032 ACCESS CO., LTD.
-008033 FORMATION, INC.
-008034 SMT GOUPIL
-008035 TECHNOLOGY WORKS, INC.
-008036 REFLEX MANUFACTURING SYSTEMS
-008037 Ericsson Group
-008038 DATA RESEARCH & APPLICATIONS
-008039 ALCATEL STC AUSTRALIA
-00803A VARITYPER, INC.
-00803B APT COMMUNICATIONS, INC.
-00803C TVS ELECTRONICS LTD
-00803D SURIGIKEN CO.,  LTD.
-00803E SYNERNETICS
-00803F TATUNG COMPANY
-008040 JOHN FLUKE MANUFACTURING CO.
-008041 VEB KOMBINAT ROBOTRON
-008042 FORCE COMPUTERS
-008043 NETWORLD, INC.
-008044 SYSTECH COMPUTER CORP.
-008045 MATSUSHITA ELECTRIC IND. CO
-008046 UNIVERSITY OF TORONTO
-008047 IN-NET CORP.
-008048 COMPEX INCORPORATED
-008049 NISSIN ELECTRIC CO., LTD.
-00804A PRO-LOG
-00804B EAGLE TECHNOLOGIES PTY.LTD.
-00804C CONTEC CO., LTD.
-00804D CYCLONE MICROSYSTEMS, INC.
-00804E APEX COMPUTER COMPANY
-00804F DAIKIN INDUSTRIES, LTD.
-008050 ZIATECH CORPORATION
-008051 FIBERMUX
-008052 TECHNICALLY ELITE CONCEPTS
-008053 INTELLICOM, INC.
-008054 FRONTIER TECHNOLOGIES CORP.
-008055 FERMILAB
-008056 SPHINX ELEKTRONIK GMBH
-008057 ADSOFT, LTD.
-008058 PRINTER SYSTEMS CORPORATION
-008059 STANLEY ELECTRIC CO., LTD
-00805A TULIP COMPUTERS INTERNAT'L B.V
-00805B CONDOR SYSTEMS, INC.
-00805C AGILIS CORPORATION
-00805D CANSTAR
-00805E LSI LOGIC CORPORATION
-00805F COMPAQ COMPUTER CORPORATION
-008060 NETWORK INTERFACE CORPORATION
-008061 LITTON SYSTEMS, INC.
-008062 INTERFACE  CO.
-008063 RICHARD HIRSCHMANN GMBH & CO.
-008064 WYSE TECHNOLOGY
-008065 CYBERGRAPHIC SYSTEMS PTY LTD.
-008066 ARCOM CONTROL SYSTEMS, LTD.
-008067 SQUARE D COMPANY
-008068 YAMATECH SCIENTIFIC LTD.
-008069 COMPUTONE SYSTEMS
-00806A ERI (EMPAC RESEARCH INC.)
-00806B SCHMID TELECOMMUNICATION
-00806C CEGELEC PROJECTS LTD
-00806D CENTURY SYSTEMS CORP.
-00806E NIPPON STEEL CORPORATION
-00806F ONELAN LTD.
-008070 COMPUTADORAS MICRON
-008071 SAI TECHNOLOGY
-008072 MICROPLEX SYSTEMS LTD.
-008073 DWB ASSOCIATES
-008074 FISHER CONTROLS
-008075 PARSYTEC GMBH
-008076 MCNC
-008077 BROTHER INDUSTRIES, LTD.
-008078 PRACTICAL PERIPHERALS, INC.
-008079 MICROBUS DESIGNS LTD.
-00807A AITECH SYSTEMS LTD.
-00807B ARTEL COMMUNICATIONS CORP.
-00807C FIBERCOM, INC.
-00807D EQUINOX SYSTEMS INC.
-00807E SOUTHERN PACIFIC LTD.
-00807F DY-4 INCORPORATED
-008080 DATAMEDIA CORPORATION
-008081 KENDALL SQUARE RESEARCH CORP.
-008082 PEP MODULAR COMPUTERS GMBH
-008083 AMDAHL
-008084 THE CLOUD INC.
-008085 H-THREE SYSTEMS CORPORATION
-008086 COMPUTER GENERATION INC.
-008087 OKI ELECTRIC INDUSTRY CO., LTD
-008088 VICTOR COMPANY OF JAPAN, LTD.
-008089 TECNETICS (PTY) LTD.
-00808A SUMMIT MICROSYSTEMS CORP.
-00808B DACOLL LIMITED
-00808C NetScout Systems, Inc.
-00808D WESTCOAST TECHNOLOGY B.V.
-00808E RADSTONE TECHNOLOGY
-00808F C. ITOH ELECTRONICS, INC.
-008090 MICROTEK INTERNATIONAL, INC.
-008091 TOKYO ELECTRIC CO.,LTD
-008092 JAPAN COMPUTER INDUSTRY, INC.
-008093 XYRON CORPORATION
-008094 ALFA LAVAL AUTOMATION AB
-008095 BASIC MERTON HANDELSGES.M.B.H.
-008096 HUMAN DESIGNED SYSTEMS, INC.
-008097 CENTRALP AUTOMATISMES
-008098 TDK CORPORATION
-008099 KLOCKNER MOELLER IPC
-00809A NOVUS NETWORKS LTD
-00809B JUSTSYSTEM CORPORATION
-00809C LUXCOM, INC.
-00809D Commscraft Ltd.
-00809E DATUS GMBH
-00809F ALCATEL BUSINESS SYSTEMS
-0080A0 EDISA HEWLETT PACKARD S/A
-0080A1 MICROTEST, INC.
-0080A2 CREATIVE ELECTRONIC SYSTEMS
-0080A3 LANTRONIX
-0080A4 LIBERTY ELECTRONICS
-0080A5 SPEED INTERNATIONAL
-0080A6 REPUBLIC TECHNOLOGY, INC.
-0080A7 MEASUREX CORP.
-0080A8 VITACOM CORPORATION
-0080A9 CLEARPOINT RESEARCH
-0080AA MAXPEED
-0080AB DUKANE NETWORK INTEGRATION
-0080AC IMLOGIX, DIVISION OF GENESYS
-0080AD CNET TECHNOLOGY, INC.
-0080AE HUGHES NETWORK SYSTEMS
-0080AF ALLUMER CO., LTD.
-0080B0 ADVANCED INFORMATION
-0080B1 SOFTCOM A/S
-0080B2 NETWORK EQUIPMENT TECHNOLOGIES
-0080B3 AVAL DATA CORPORATION
-0080B4 SOPHIA SYSTEMS
-0080B5 UNITED NETWORKS INC.
-0080B6 THEMIS COMPUTER
-0080B7 STELLAR COMPUTER
-0080B8 BUG, INCORPORATED
-0080B9 ARCHE TECHNOLIGIES INC.
-0080BA SPECIALIX (ASIA) PTE, LTD
-0080BB HUGHES LAN SYSTEMS
-0080BC HITACHI ENGINEERING CO., LTD
-0080BD THE FURUKAWA ELECTRIC CO., LTD
-0080BE ARIES RESEARCH
-0080BF TAKAOKA ELECTRIC MFG. CO. LTD.
-0080C0 PENRIL DATACOMM
-0080C1 LANEX CORPORATION
-0080C2 IEEE 802.1 COMMITTEE
-0080C3 BICC INFORMATION SYSTEMS & SVC
-0080C4 DOCUMENT TECHNOLOGIES, INC.
-0080C5 NOVELLCO DE MEXICO
-0080C6 NATIONAL DATACOMM CORPORATION
-0080C7 XIRCOM
-0080C8 D-LINK SYSTEMS, INC.
-0080C9 ALBERTA MICROELECTRONIC CENTRE
-0080CA NETCOM RESEARCH INCORPORATED
-0080CB FALCO DATA PRODUCTS
-0080CC MICROWAVE BYPASS SYSTEMS
-0080CD MICRONICS COMPUTER, INC.
-0080CE BROADCAST TELEVISION SYSTEMS
-0080CF EMBEDDED PERFORMANCE INC.
-0080D0 COMPUTER PERIPHERALS, INC.
-0080D1 KIMTRON CORPORATION
-0080D2 SHINNIHONDENKO CO., LTD.
-0080D3 SHIVA CORP.
-0080D4 CHASE RESEARCH LTD.
-0080D5 CADRE TECHNOLOGIES
-0080D6 NUVOTECH, INC.
-0080D7 Fantum Engineering
-0080D8 NETWORK PERIPHERALS INC.
-0080D9 EMK ELEKTRONIK
-0080DA BRUEL & KJAER
-0080DB GRAPHON CORPORATION
-0080DC PICKER INTERNATIONAL
-0080DD GMX INC/GIMIX
-0080DE GIPSI S.A.
-0080DF ADC CODENOLL TECHNOLOGY CORP.
-0080E0 XTP SYSTEMS, INC.
-0080E1 STMICROELECTRONICS
-0080E2 T.D.I. CO., LTD.
-0080E3 CORAL NETWORK CORPORATION
-0080E4 NORTHWEST DIGITAL SYSTEMS, INC
-0080E5 MYLEX CORPORATION
-0080E6 PEER NETWORKS, INC.
-0080E7 LYNWOOD SCIENTIFIC DEV. LTD.
-0080E8 CUMULUS CORPORATIION
-0080E9 Madge Ltd.
-0080EA ADVA Optical Networking Ltd.
-0080EB COMPCONTROL B.V.
-0080EC SUPERCOMPUTING SOLUTIONS, INC.
-0080ED IQ TECHNOLOGIES, INC.
-0080EE THOMSON CSF
-0080EF RATIONAL
-0080F0 Panasonic Communications Co., Ltd.
-0080F1 OPUS SYSTEMS
-0080F2 RAYCOM SYSTEMS INC
-0080F3 SUN ELECTRONICS CORP.
-0080F4 TELEMECANIQUE ELECTRIQUE
-0080F5 QUANTEL LTD
-0080F6 SYNERGY MICROSYSTEMS
-0080F7 ZENITH ELECTRONICS
-0080F8 MIZAR, INC.
-0080F9 HEURIKON CORPORATION
-0080FA RWT GMBH
-0080FB BVM LIMITED
-0080FC AVATAR CORPORATION
-0080FD EXSCEED CORPRATION
-0080FE AZURE TECHNOLOGIES, INC.
-0080FF SOC. DE TELEINFORMATIQUE RTC
-009000 DIAMOND MULTIMEDIA
-009001 NISHIMU ELECTRONICS INDUSTRIES CO., LTD.
-009002 ALLGON AB
-009003 APLIO
-009004 3COM EUROPE LTD.
-009005 PROTECH SYSTEMS CO., LTD.
-009006 HAMAMATSU PHOTONICS K.K.
-009007 DOMEX TECHNOLOGY CORP.
-009008 HanA Systems Inc.
-009009 i Controls, Inc.
-00900A PROTON ELECTRONIC INDUSTRIAL CO., LTD.
-00900B LANNER ELECTRONICS, INC.
-00900C CISCO SYSTEMS, INC.
-00900D OVERLAND DATA INC.
-00900E HANDLINK TECHNOLOGIES, INC.
-00900F KAWASAKI HEAVY INDUSTRIES, LTD
-009010 SIMULATION LABORATORIES, INC.
-009011 WAVTrace, Inc.
-009012 GLOBESPAN SEMICONDUCTOR, INC.
-009013 SAMSAN CORP.
-009014 ROTORK INSTRUMENTS, LTD.
-009015 CENTIGRAM COMMUNICATIONS CORP.
-009016 ZAC
-009017 ZYPCOM, INC.
-009018 ITO ELECTRIC INDUSTRY CO, LTD.
-009019 HERMES ELECTRONICS CO., LTD.
-00901A UNISPHERE SOLUTIONS
-00901B DIGITAL CONTROLS
-00901C mps Software Gmbh
-00901D PEC (NZ) LTD.
-00901E SELESTA INGEGNE RIA S.P.A.
-00901F ADTEC PRODUCTIONS, INC.
-009020 PHILIPS ANALYTICAL X-RAY B.V.
-009021 CISCO SYSTEMS, INC.
-009022 IVEX
-009023 ZILOG INC.
-009024 PIPELINKS, INC.
-009025 VISION SYSTEMS LTD. PTY
-009026 ADVANCED SWITCHING COMMUNICATIONS, INC.
-009027 INTEL CORPORATION
-009028 NIPPON SIGNAL CO., LTD.
-009029 CRYPTO AG
-00902A COMMUNICATION DEVICES, INC.
-00902B CISCO SYSTEMS, INC.
-00902C DATA & CONTROL EQUIPMENT LTD.
-00902D DATA ELECTRONICS (AUST.) PTY, LTD.
-00902E NAMCO LIMITED
-00902F NETCORE SYSTEMS, INC.
-009030 HONEYWELL-DATING
-009031 MYSTICOM, LTD.
-009032 PELCOMBE GROUP LTD.
-009033 INNOVAPHONE GmbH
-009034 IMAGIC, INC.
-009035 ALPHA TELECOM, INC.
-009036 ens, inc.
-009037 ACUCOMM, INC.
-009038 FOUNTAIN TECHNOLOGIES, INC.
-009039 SHASTA NETWORKS
-00903A NIHON MEDIA TOOL INC.
-00903B TriEMS Research Lab, Inc.
-00903C ATLANTIC NETWORK SYSTEMS
-00903D BIOPAC SYSTEMS, INC.
-00903E N.V. PHILIPS INDUSTRIAL ACTIVITIES
-00903F AZTEC RADIOMEDIA
-009040 Siemens Network Convergence LLC
-009041 APPLIED DIGITAL ACCESS
-009042 ECCS, Inc.
-009043 NICHIBEI DENSHI CO., LTD.
-009044 ASSURED DIGITAL, INC.
-009045 Marconi Communications
-009046 DEXDYNE, LTD.
-009047 GIGA FAST E. LTD.
-009048 ZEAL CORPORATION
-009049 ENTRIDIA CORPORATION
-00904A CONCUR SYSTEM TECHNOLOGIES
-00904B GemTek Technology Co., Ltd.
-00904C EPIGRAM, INC.
-00904D SPEC S.A.
-00904E DELEM BV
-00904F ABB POWER T&D COMPANY, INC.
-009050 TELESTE OY
-009051 ULTIMATE TECHNOLOGY CORP.
-009052 SELCOM ELETTRONICA S.R.L.
-009053 DAEWOO ELECTRONICS CO., LTD.
-009054 INNOVATIVE SEMICONDUCTORS, INC
-009055 PARKER HANNIFIN CORPORATION COMPUMOTOR DIVISION
-009056 TELESTREAM, INC.
-009057 AANetcom, Inc.
-009058 Ultra Electronics Ltd., Command and Control Systems
-009059 TELECOM DEVICE K.K.
-00905A DEARBORN GROUP, INC.
-00905B RAYMOND AND LAE ENGINEERING
-00905C EDMI
-00905D NETCOM SICHERHEITSTECHNIK GmbH
-00905E RAULAND-BORG CORPORATION
-00905F CISCO SYSTEMS, INC.
-009060 SYSTEM CREATE CORP.
-009061 PACIFIC RESEARCH & ENGINEERING CORPORATION
-009062 ICP VORTEX COMPUTERSYSTEME GmbH
-009063 COHERENT COMMUNICATIONS SYSTEMS CORPORATION
-009064 THOMSON BROADCAST SYSTEMS
-009065 FINISAR CORPORATION
-009066 Troika Networks, Inc.
-009067 WalkAbout Computers, Inc.
-009068 DVT CORP.
-009069 JUNIPER NETWORKS, INC.
-00906A TURNSTONE SYSTEMS, INC.
-00906B APPLIED RESOURCES, INC.
-00906C GWT GLOBAL WEIGHING TECHNOLOGIES GmbH
-00906D CISCO SYSTEMS, INC.
-00906E PRAXON, INC.
-00906F CISCO SYSTEMS, INC.
-009070 NEO NETWORKS, INC.
-009071 Applied Innovation Inc.
-009072 SIMRAD AS
-009073 GAIO TECHNOLOGY
-009074 ARGON NETWORKS, INC.
-009075 NEC DO BRASIL S.A.
-009076 FMT AIRCRAFT GATE SUPPORT SYSTEMS AB
-009077 ADVANCED FIBRE COMMUNICATIONS
-009078 MER TELEMANAGEMENT SOLUTIONS, LTD.
-009079 ClearOne, Inc.
-00907A SPECTRALINK CORP.
-00907B E-TECH, INC.
-00907C DIGITALCAST, INC.
-00907D Lake Communications
-00907E VETRONIX CORP.
-00907F WatchGuard Technologies, Inc.
-009080 NOT LIMITED, INC.
-009081 ALOHA NETWORKS, INC.
-009082 FORCE INSTITUTE
-009083 TURBO COMMUNICATION, INC.
-009084 ATECH SYSTEM
-009085 GOLDEN ENTERPRISES, INC.
-009086 CISCO SYSTEMS, INC.
-009087 ITIS
-009088 BAXALL SECURITY LTD.
-009089 SOFTCOM MICROSYSTEMS, INC.
-00908A BAYLY COMMUNICATIONS, INC.
-00908B CELL COMPUTING, INC.
-00908C ETREND ELECTRONICS, INC.
-00908D VICKERS ELECTRONICS SYSTEMS
-00908E Nortel Networks Broadband Access
-00908F AUDIO CODES LTD.
-009090 I-BUS
-009091 DigitalScape, Inc.
-009092 CISCO SYSTEMS, INC.
-009093 NANAO CORPORATION
-009094 OSPREY TECHNOLOGIES, INC.
-009095 UNIVERSAL AVIONICS
-009096 ASKEY COMPUTER CORP.
-009097 SYCAMORE NETWORKS
-009098 SBC DESIGNS, INC.
-009099 ALLIED TELESIS, K.K.
-00909A ONE WORLD SYSTEMS, INC.
-00909B MARKPOINT AB
-00909C Terayon Communications Systems
-00909D GSE SYSTEMS, INC.
-00909E Critical IO, LLC
-00909F DIGI-DATA CORPORATION
-0090A0 8X8 INC.
-0090A1 FLYING PIG SYSTEMS, LTD.
-0090A2 CYBERTAN TECHNOLOGY, INC.
-0090A3 Corecess Inc.
-0090A4 ALTIGA NETWORKS
-0090A5 SPECTRA LOGIC
-0090A6 CISCO SYSTEMS, INC.
-0090A7 CLIENTEC CORPORATION
-0090A8 NineTiles Networks, Ltd.
-0090A9 WESTERN DIGITAL
-0090AA INDIGO ACTIVE VISION SYSTEMS LIMITED
-0090AB CISCO SYSTEMS, INC.
-0090AC OPTIVISION, INC.
-0090AD ASPECT ELECTRONICS, INC.
-0090AE ITALTEL S.p.A.
-0090AF J. MORITA MFG. CORP.
-0090B0 VADEM
-0090B1 CISCO SYSTEMS, INC.
-0090B2 AVICI SYSTEMS INC.
-0090B3 AGRANAT SYSTEMS
-0090B4 WILLOWBROOK TECHNOLOGIES
-0090B5 NIKON CORPORATION
-0090B6 FIBEX SYSTEMS
-0090B7 DIGITAL LIGHTWAVE, INC.
-0090B8 ROHDE & SCHWARZ GMBH & CO. KG
-0090B9 BERAN INSTRUMENTS LTD.
-0090BA VALID NETWORKS, INC.
-0090BB TAINET COMMUNICATION SYSTEM Corp.
-0090BC TELEMANN CO., LTD.
-0090BD OMNIA COMMUNICATIONS, INC.
-0090BE IBC/INTEGRATED BUSINESS COMPUTERS
-0090BF CISCO SYSTEMS, INC.
-0090C0 K.J. LAW ENGINEERS, INC.
-0090C1 Peco II, Inc.
-0090C2 JK microsystems, Inc.
-0090C3 TOPIC SEMICONDUCTOR CORP.
-0090C4 JAVELIN SYSTEMS, INC.
-0090C5 INTERNET MAGIC, INC.
-0090C6 OPTIM SYSTEMS, INC.
-0090C7 ICOM INC.
-0090C8 WAVERIDER COMMUNICATIONS (CANADA) INC.
-0090C9 DPAC Technologies
-0090CA ACCORD VIDEO TELECOMMUNICATIONS, LTD.
-0090CB Wireless OnLine, Inc.
-0090CC PLANET COMMUNICATIONS, INC.
-0090CD ENT-EMPRESA NACIONAL DE TELECOMMUNICACOES, S.A.
-0090CE TETRA GmbH
-0090CF NORTEL
-0090D0 Thomson Belgium
-0090D1 LEICHU ENTERPRISE CO., LTD.
-0090D2 ARTEL VIDEO SYSTEMS
-0090D3 GIESECKE & DEVRIENT GmbH
-0090D4 BindView Development Corp.
-0090D5 EUPHONIX, INC.
-0090D6 CRYSTAL GROUP
-0090D7 NetBoost Corp.
-0090D8 WHITECROSS SYSTEMS
-0090D9 CISCO SYSTEMS, INC.
-0090DA DYNARC, INC.
-0090DB NEXT LEVEL COMMUNICATIONS
-0090DC TECO INFORMATION SYSTEMS
-0090DD THE MIHARU COMMUNICATIONS CO., LTD.
-0090DE CARDKEY SYSTEMS, INC.
-0090DF MITSUBISHI CHEMICAL AMERICA, INC.
-0090E0 SYSTRAN CORP.
-0090E1 TELENA S.P.A.
-0090E2 DISTRIBUTED PROCESSING TECHNOLOGY
-0090E3 AVEX ELECTRONICS INC.
-0090E4 NEC AMERICA, INC.
-0090E5 TEKNEMA, INC.
-0090E6 ACER LABORATORIES, INC.
-0090E7 HORSCH ELEKTRONIK AG
-0090E8 MOXA TECHNOLOGIES CORP., LTD.
-0090E9 JANZ COMPUTER AG
-0090EA ALPHA TECHNOLOGIES, INC.
-0090EB SENTRY TELECOM SYSTEMS
-0090EC PYRESCOM
-0090ED CENTRAL SYSTEM RESEARCH CO., LTD.
-0090EE PERSONAL COMMUNICATIONS TECHNOLOGIES
-0090EF INTEGRIX, INC.
-0090F0 HARMONIC LIGHTWAVES, LTD.
-0090F1 DOT HILL SYSTEMS CORPORATION
-0090F2 CISCO SYSTEMS, INC.
-0090F3 ASPECT COMMUNICATIONS
-0090F4 LIGHTNING INSTRUMENTATION
-0090F5 CLEVO CO.
-0090F6 ESCALATE NETWORKS, INC.
-0090F7 NBASE COMMUNICATIONS LTD.
-0090F8 MEDIATRIX TELECOM
-0090F9 LEITCH
-0090FA GigaNet, Inc.
-0090FB PORTWELL, INC.
-0090FC NETWORK COMPUTING DEVICES
-0090FD CopperCom, Inc.
-0090FE ELECOM CO., LTD.  (LANEED DIV.)
-0090FF TELLUS TECHNOLOGY INC.
-0091D6 Crystal Group, Inc.
-009D8E CARDIAC RECORDERS, INC.
-00A000 CENTILLION NETWORKS, INC.
-00A001 WATKINS-JOHNSON COMPANY
-00A002 LEEDS & NORTHRUP AUSTRALIA PTY LTD
-00A003 STAEFA CONTROL SYSTEM
-00A004 NETPOWER, INC.
-00A005 DANIEL INSTRUMENTS, LTD.
-00A006 IMAGE DATA PROCESSING SYSTEM GROUP
-00A007 APEXX TECHNOLOGY, INC.
-00A008 NETCORP
-00A009 WHITETREE NETWORK
-00A00A R.D.C. COMMUNICATION
-00A00B COMPUTEX CO., LTD.
-00A00C KINGMAX TECHNOLOGY, INC.
-00A00D THE PANDA PROJECT
-00A00E VISUAL NETWORKS, INC.
-00A00F Broadband Technologies
-00A010 SYSLOGIC DATENTECHNIK AG
-00A011 MUTOH INDUSTRIES LTD.
-00A012 B.A.T.M. ADVANCED TECHNOLOGIES
-00A013 TELTREND LTD.
-00A014 CSIR
-00A015 WYLE
-00A016 MICROPOLIS CORP.
-00A017 J B M CORPORATION
-00A018 CREATIVE CONTROLLERS, INC.
-00A019 NEBULA CONSULTANTS, INC.
-00A01A BINAR ELEKTRONIK AB
-00A01B PREMISYS COMMUNICATIONS, INC.
-00A01C NASCENT NETWORKS CORPORATION
-00A01D SIXNET
-00A01E EST CORPORATION
-00A01F TRICORD SYSTEMS, INC.
-00A020 CITICORP/TTI
-00A021 GENERAL DYNAMICS-
-00A022 CENTRE FOR DEVELOPMENT OF ADVANCED COMPUTING
-00A023 APPLIED CREATIVE TECHNOLOGY, INC.
-00A024 3COM CORPORATION
-00A025 REDCOM LABS INC.
-00A026 TELDAT, S.A.
-00A027 FIREPOWER SYSTEMS, INC.
-00A028 CONNER PERIPHERALS
-00A029 COULTER CORPORATION
-00A02A TRANCELL SYSTEMS
-00A02B TRANSITIONS RESEARCH CORP.
-00A02C interWAVE Communications
-00A02D 1394 Trade Association
-00A02E BRAND COMMUNICATIONS, LTD.
-00A02F PIRELLI CAVI
-00A030 CAPTOR NV/SA
-00A031 HAZELTINE CORPORATION, MS 1-17
-00A032 GES SINGAPORE PTE. LTD.
-00A033 imc MeBsysteme GmbH
-00A034 AXEL
-00A035 CYLINK CORPORATION
-00A036 APPLIED NETWORK TECHNOLOGY
-00A037 DATASCOPE CORPORATION
-00A038 EMAIL ELECTRONICS
-00A039 ROSS TECHNOLOGY, INC.
-00A03A KUBOTEK CORPORATION
-00A03B TOSHIN ELECTRIC CO., LTD.
-00A03C EG&G NUCLEAR INSTRUMENTS
-00A03D OPTO-22
-00A03E ATM FORUM
-00A03F COMPUTER SOCIETY MICROPROCESSOR & MICROPROCESSOR STANDARDS C
-00A040 APPLE COMPUTER
-00A041 LEYBOLD-INFICON
-00A042 SPUR PRODUCTS CORP.
-00A043 AMERICAN TECHNOLOGY LABS, INC.
-00A044 NTT IT CO., LTD.
-00A045 PHOENIX CONTACT GMBH & CO.
-00A046 SCITEX CORP. LTD.
-00A047 INTEGRATED FITNESS CORP.
-00A048 QUESTECH, LTD.
-00A049 DIGITECH INDUSTRIES, INC.
-00A04A NISSHIN ELECTRIC CO., LTD.
-00A04B TFL LAN INC.
-00A04C INNOVATIVE SYSTEMS & TECHNOLOGIES, INC.
-00A04D EDA INSTRUMENTS, INC.
-00A04E VOELKER TECHNOLOGIES, INC.
-00A04F AMERITEC CORP.
-00A050 CYPRESS SEMICONDUCTOR
-00A051 ANGIA COMMUNICATIONS. INC.
-00A052 STANILITE ELECTRONICS PTY. LTD
-00A053 COMPACT DEVICES, INC.
-00A055 Data Device Corporation
-00A056 MICROPROSS
-00A057 LANCOM Systems GmbH
-00A058 GLORY, LTD.
-00A059 HAMILTON HALLMARK
-00A05A KOFAX IMAGE PRODUCTS
-00A05B MARQUIP, INC.
-00A05C INVENTORY CONVERSION, INC./
-00A05D CS COMPUTER SYSTEME GmbH
-00A05E MYRIAD LOGIC INC.
-00A05F BTG ENGINEERING BV
-00A060 ACER PERIPHERALS, INC.
-00A061 PURITAN BENNETT
-00A062 AES PRODATA
-00A063 JRL SYSTEMS, INC.
-00A064 KVB/ANALECT
-00A065 NEXLAND, INC.
-00A066 ISA CO., LTD.
-00A067 NETWORK SERVICES GROUP
-00A068 BHP LIMITED
-00A069 Symmetricom, Inc.
-00A06A Verilink Corporation
-00A06B DMS DORSCH MIKROSYSTEM GMBH
-00A06C SHINDENGEN ELECTRIC MFG. CO., LTD.
-00A06D MANNESMANN TALLY CORPORATION
-00A06E AUSTRON, INC.
-00A06F THE APPCON GROUP, INC.
-00A070 COASTCOM
-00A071 VIDEO LOTTERY TECHNOLOGIES,INC
-00A072 OVATION SYSTEMS LTD.
-00A073 COM21, INC.
-00A074 PERCEPTION TECHNOLOGY
-00A075 MICRON TECHNOLOGY, INC.
-00A076 CARDWARE LAB, INC.
-00A077 FUJITSU NEXION, INC.
-00A078 Marconi Communications
-00A079 ALPS ELECTRIC (USA), INC.
-00A07A ADVANCED PERIPHERALS TECHNOLOGIES, INC.
-00A07B DAWN COMPUTER INCORPORATION
-00A07C TONYANG NYLON CO., LTD.
-00A07D SEEQ TECHNOLOGY, INC.
-00A07E AVID TECHNOLOGY, INC.
-00A07F GSM-SYNTEL, LTD.
-00A080 ANTARES MICROSYSTEMS
-00A081 ALCATEL DATA NETWORKS
-00A082 NKT ELEKTRONIK A/S
-00A083 ASIMMPHONY TURKEY
-00A084 DATAPLEX PTY. LTD.
-00A086 AMBER WAVE SYSTEMS, INC.
-00A087 Zarlink Semiconductor Ltd.
-00A088 ESSENTIAL COMMUNICATIONS
-00A089 XPOINT TECHNOLOGIES, INC.
-00A08A BROOKTROUT TECHNOLOGY, INC.
-00A08B ASTON ELECTRONIC DESIGNS LTD.
-00A08C MultiMedia LANs, Inc.
-00A08D JACOMO CORPORATION
-00A08E Nokia Internet Communications
-00A08F DESKNET SYSTEMS, INC.
-00A090 TimeStep Corporation
-00A091 APPLICOM INTERNATIONAL
-00A092 H. BOLLMANN MANUFACTURERS, LTD
-00A093 B/E AEROSPACE, Inc.
-00A094 COMSAT CORPORATION
-00A095 ACACIA NETWORKS, INC.
-00A096 MITUMI ELECTRIC CO., LTD.
-00A097 JC INFORMATION SYSTEMS
-00A098 NETWORK APPLIANCE CORP.
-00A099 K-NET LTD.
-00A09A NIHON KOHDEN AMERICA
-00A09B QPSX COMMUNICATIONS, LTD.
-00A09C Xyplex, Inc.
-00A09D JOHNATHON FREEMAN TECHNOLOGIES
-00A09E ICTV
-00A09F COMMVISION CORP.
-00A0A0 COMPACT DATA, LTD.
-00A0A1 EPIC DATA INC.
-00A0A2 DIGICOM S.P.A.
-00A0A3 RELIABLE POWER METERS
-00A0A4 MICROS SYSTEMS, INC.
-00A0A5 TEKNOR MICROSYSTEME, INC.
-00A0A6 M.I. SYSTEMS, K.K.
-00A0A7 VORAX CORPORATION
-00A0A8 RENEX CORPORATION
-00A0A9 GN NETTEST (CANADA) NAVTEL DIVISION
-00A0AA SPACELABS MEDICAL
-00A0AB NETCS INFORMATIONSTECHNIK GMBH
-00A0AC GILAT SATELLITE NETWORKS, LTD.
-00A0AD MARCONI SPA
-00A0AE NUCOM SYSTEMS, INC.
-00A0AF WMS INDUSTRIES
-00A0B0 I-O DATA DEVICE, INC.
-00A0B1 FIRST VIRTUAL CORPORATION
-00A0B2 SHIMA SEIKI
-00A0B3 ZYKRONIX
-00A0B4 TEXAS MICROSYSTEMS, INC.
-00A0B5 3H TECHNOLOGY
-00A0B6 SANRITZ AUTOMATION CO., LTD.
-00A0B7 CORDANT, INC.
-00A0B8 SYMBIOS LOGIC INC.
-00A0B9 EAGLE TECHNOLOGY, INC.
-00A0BA PATTON ELECTRONICS CO.
-00A0BB HILAN GMBH
-00A0BC VIASAT, INCORPORATED
-00A0BD I-TECH CORP.
-00A0BE INTEGRATED CIRCUIT SYSTEMS, INC. COMMUNICATIONS GROUP
-00A0BF WIRELESS DATA GROUP MOTOROLA
-00A0C0 DIGITAL LINK CORP.
-00A0C1 ORTIVUS MEDICAL AB
-00A0C2 R.A. SYSTEMS CO., LTD.
-00A0C3 UNICOMPUTER GMBH
-00A0C4 CRISTIE ELECTRONICS LTD.
-00A0C5 ZYXEL COMMUNICATION
-00A0C6 QUALCOMM INCORPORATED
-00A0C7 TADIRAN TELECOMMUNICATIONS
-00A0C8 ADTRAN INC.
-00A0C9 INTEL CORPORATION - HF1-06
-00A0CA FUJITSU DENSO LTD.
-00A0CB ARK TELECOMMUNICATIONS, INC.
-00A0CC LITE-ON COMMUNICATIONS, INC.
-00A0CD DR. JOHANNES HEIDENHAIN GmbH
-00A0CE ASTROCOM CORPORATION
-00A0CF SOTAS, INC.
-00A0D0 TEN X TECHNOLOGY, INC.
-00A0D1 INVENTEC CORPORATION
-00A0D2 ALLIED TELESIS INTERNATIONAL CORPORATION
-00A0D3 INSTEM COMPUTER SYSTEMS, LTD.
-00A0D4 RADIOLAN,  INC.
-00A0D5 SIERRA WIRELESS INC.
-00A0D6 SBE, INC.
-00A0D7 KASTEN CHASE APPLIED RESEARCH
-00A0D8 SPECTRA - TEK
-00A0D9 CONVEX COMPUTER CORPORATION
-00A0DA INTEGRATED SYSTEMS Technology, Inc.
-00A0DB FISHER & PAYKEL PRODUCTION
-00A0DC O.N. ELECTRONIC CO., LTD.
-00A0DD AZONIX CORPORATION
-00A0DE YAMAHA CORPORATION
-00A0DF STS TECHNOLOGIES, INC.
-00A0E0 TENNYSON TECHNOLOGIES PTY LTD
-00A0E1 WESTPORT RESEARCH ASSOCIATES, INC.
-00A0E2 KEISOKU GIKEN CORP.
-00A0E3 XKL SYSTEMS CORP.
-00A0E4 OPTIQUEST
-00A0E5 NHC COMMUNICATIONS
-00A0E6 DIALOGIC CORPORATION
-00A0E7 CENTRAL DATA CORPORATION
-00A0E8 REUTERS HOLDINGS PLC
-00A0E9 ELECTRONIC RETAILING SYSTEMS INTERNATIONAL
-00A0EA ETHERCOM CORP.
-00A0EB Encore Networks
-00A0EC TRANSMITTON LTD.
-00A0ED PRI AUTOMATION
-00A0EE NASHOBA NETWORKS
-00A0EF LUCIDATA LTD.
-00A0F0 TORONTO MICROELECTRONICS INC.
-00A0F1 MTI
-00A0F2 INFOTEK COMMUNICATIONS, INC.
-00A0F3 STAUBLI
-00A0F4 GE
-00A0F5 RADGUARD LTD.
-00A0F6 AutoGas Systems Inc.
-00A0F7 V.I COMPUTER CORP.
-00A0F8 SYMBOL TECHNOLOGIES, INC.
-00A0F9 BINTEC COMMUNICATIONS GMBH
-00A0FA Marconi Communication GmbH
-00A0FB TORAY ENGINEERING CO., LTD.
-00A0FC IMAGE SCIENCES, INC.
-00A0FD SCITEX DIGITAL PRINTING, INC.
-00A0FE BOSTON TECHNOLOGY, INC.
-00A0FF TELLABS OPERATIONS, INC.
-00AA00 INTEL CORPORATION
-00AA01 INTEL CORPORATION
-00AA02 INTEL CORPORATION
-00AA3C OLIVETTI TELECOM SPA (OLTECO)
-00B009 Grass Valley Group
-00B017 InfoGear Technology Corp.
-00B019 Casi-Rusco
-00B01C Westport Technologies
-00B01E Rantic Labs, Inc.
-00B02A ORSYS GmbH
-00B02D ViaGate Technologies, Inc.
-00B03B HiQ Networks
-00B048 Marconi Communications Inc.
-00B04A Cisco Systems, Inc.
-00B052 Intellon Corporation
-00B064 Cisco Systems, Inc.
-00B069 Honewell Oy
-00B06D Jones Futurex Inc.
-00B080 Mannesmann Ipulsys B.V.
-00B086 LocSoft Limited
-00B08E Cisco Systems, Inc.
-00B091 Transmeta Corp.
-00B094 Alaris, Inc.
-00B09A Morrow Technologies Corp.
-00B09D Point Grey Research Inc.
-00B0AC SIAE-Microelettronica S.p.A.
-00B0AE Symmetricom
-00B0B3 Xstreamis PLC
-00B0C2 Cisco Systems, Inc.
-00B0C7 Tellabs Operations, Inc.
-00B0CE TECHNOLOGY RESCUE
-00B0D0 Dell Computer Corp.
-00B0DB Nextcell, Inc.
-00B0DF Reliable Data Technology, Inc.
-00B0E7 British Federal Ltd.
-00B0EC EACEM
-00B0EE Ajile Systems, Inc.
-00B0F0 CALY NETWORKS
-00B0F5 NetWorth Technologies, Inc.
-00BB01 OCTOTHORPE CORP.
-00BBF0 UNGERMANN-BASS INC.
-00C000 LANOPTICS, LTD.
-00C001 DIATEK PATIENT MANAGMENT
-00C002 SERCOMM CORPORATION
-00C003 GLOBALNET COMMUNICATIONS
-00C004 JAPAN BUSINESS COMPUTER CO.LTD
-00C005 LIVINGSTON ENTERPRISES, INC.
-00C006 NIPPON AVIONICS CO., LTD.
-00C007 PINNACLE DATA SYSTEMS, INC.
-00C008 SECO SRL
-00C009 KT TECHNOLOGY (S) PTE LTD
-00C00A MICRO CRAFT
-00C00B NORCONTROL A.S.
-00C00C RELIA TECHNOLGIES
-00C00D ADVANCED LOGIC RESEARCH, INC.
-00C00E PSITECH, INC.
-00C00F QUANTUM SOFTWARE SYSTEMS LTD.
-00C010 HIRAKAWA HEWTECH CORP.
-00C011 INTERACTIVE COMPUTING DEVICES
-00C012 NETSPAN CORPORATION
-00C013 NETRIX
-00C014 TELEMATICS CALABASAS INT'L,INC
-00C015 NEW MEDIA CORPORATION
-00C016 ELECTRONIC THEATRE CONTROLS
-00C017 FORTE NETWORKS
-00C018 LANART CORPORATION
-00C019 LEAP TECHNOLOGY, INC.
-00C01A COROMETRICS MEDICAL SYSTEMS
-00C01B SOCKET COMMUNICATIONS, INC.
-00C01C INTERLINK COMMUNICATIONS LTD.
-00C01D GRAND JUNCTION NETWORKS, INC.
-00C01E LA FRANCAISE DES JEUX
-00C01F S.E.R.C.E.L.
-00C020 ARCO ELECTRONIC, CONTROL LTD.
-00C021 NETEXPRESS
-00C022 LASERMASTER TECHNOLOGIES, INC.
-00C023 TUTANKHAMON ELECTRONICS
-00C024 EDEN SISTEMAS DE COMPUTACAO SA
-00C025 DATAPRODUCTS CORPORATION
-00C026 LANS TECHNOLOGY CO., LTD.
-00C027 CIPHER SYSTEMS, INC.
-00C028 JASCO CORPORATION
-00C029 Nexans Deutschland AG - ANS
-00C02A OHKURA ELECTRIC CO., LTD.
-00C02B GERLOFF GESELLSCHAFT FUR
-00C02C CENTRUM COMMUNICATIONS, INC.
-00C02D FUJI PHOTO FILM CO., LTD.
-00C02E NETWIZ
-00C02F OKUMA CORPORATION
-00C030 INTEGRATED ENGINEERING B. V.
-00C031 DESIGN RESEARCH SYSTEMS, INC.
-00C032 I-CUBED LIMITED
-00C033 TELEBIT COMMUNICATIONS APS
-00C034 TRANSACTION NETWORK
-00C035 QUINTAR COMPANY
-00C036 RAYTECH ELECTRONIC CORP.
-00C037 DYNATEM
-00C038 RASTER IMAGE PROCESSING SYSTEM
-00C039 TDK SEMICONDUCTOR CORPORATION
-00C03A MEN-MIKRO ELEKTRONIK GMBH
-00C03B MULTIACCESS COMPUTING CORP.
-00C03C TOWER TECH S.R.L.
-00C03D WIESEMANN & THEIS GMBH
-00C03E FA. GEBR. HELLER GMBH
-00C03F STORES AUTOMATED SYSTEMS, INC.
-00C040 ECCI
-00C041 DIGITAL TRANSMISSION SYSTEMS
-00C042 DATALUX CORP.
-00C043 STRATACOM
-00C044 EMCOM CORPORATION
-00C045 ISOLATION SYSTEMS, LTD.
-00C046 KEMITRON LTD.
-00C047 UNIMICRO SYSTEMS, INC.
-00C048 BAY TECHNICAL ASSOCIATES
-00C049 U.S. ROBOTICS, INC.
-00C04A GROUP 2000 AG
-00C04B CREATIVE MICROSYSTEMS
-00C04C DEPARTMENT OF FOREIGN AFFAIRS
-00C04D MITEC, INC.
-00C04E COMTROL CORPORATION
-00C04F DELL COMPUTER CORPORATION
-00C050 TOYO DENKI SEIZO K.K.
-00C051 ADVANCED INTEGRATION RESEARCH
-00C052 BURR-BROWN
-00C053 DAVOX CORPORATION
-00C054 NETWORK PERIPHERALS, LTD.
-00C055 MODULAR COMPUTING TECHNOLOGIES
-00C056 SOMELEC
-00C057 MYCO ELECTRONICS
-00C058 DATAEXPERT CORP.
-00C059 NIPPON DENSO CO., LTD.
-00C05A SEMAPHORE COMMUNICATIONS CORP.
-00C05B NETWORKS NORTHWEST, INC.
-00C05C ELONEX PLC
-00C05D L&N TECHNOLOGIES
-00C05E VARI-LITE, INC.
-00C05F FINE-PAL COMPANY LIMITED
-00C060 ID SCANDINAVIA AS
-00C061 SOLECTEK CORPORATION
-00C062 IMPULSE TECHNOLOGY
-00C063 MORNING STAR TECHNOLOGIES, INC
-00C064 GENERAL DATACOMM IND. INC.
-00C065 SCOPE COMMUNICATIONS, INC.
-00C066 DOCUPOINT, INC.
-00C067 UNITED BARCODE INDUSTRIES
-00C068 PHILIP DRAKE ELECTRONICS LTD.
-00C069 Axxcelera Broadband Wireless
-00C06A ZAHNER-ELEKTRIK GMBH & CO. KG
-00C06B OSI PLUS CORPORATION
-00C06C SVEC COMPUTER CORP.
-00C06D BOCA RESEARCH, INC.
-00C06E HAFT TECHNOLOGY, INC.
-00C06F KOMATSU LTD.
-00C070 SECTRA SECURE-TRANSMISSION AB
-00C071 AREANEX COMMUNICATIONS, INC.
-00C072 KNX LTD.
-00C073 XEDIA CORPORATION
-00C074 TOYODA AUTOMATIC LOOM
-00C075 XANTE CORPORATION
-00C076 I-DATA INTERNATIONAL A-S
-00C077 DAEWOO TELECOM LTD.
-00C078 COMPUTER SYSTEMS ENGINEERING
-00C079 FONSYS CO.,LTD.
-00C07A PRIVA B.V.
-00C07B ASCEND COMMUNICATIONS, INC.
-00C07C HIGHTECH INFORMATION
-00C07D RISC DEVELOPMENTS LTD.
-00C07E KUBOTA CORPORATION ELECTRONIC
-00C07F NUPON COMPUTING CORP.
-00C080 NETSTAR, INC.
-00C081 METRODATA LTD.
-00C082 MOORE PRODUCTS CO.
-00C083 TRACE MOUNTAIN PRODUCTS, INC.
-00C084 DATA LINK CORP. LTD.
-00C085 ELECTRONICS FOR IMAGING, INC.
-00C086 THE LYNK CORPORATION
-00C087 UUNET TECHNOLOGIES, INC.
-00C088 EKF ELEKTRONIK GMBH
-00C089 TELINDUS DISTRIBUTION
-00C08A LAUTERBACH DATENTECHNIK GMBH
-00C08B RISQ MODULAR SYSTEMS, INC.
-00C08C PERFORMANCE TECHNOLOGIES, INC.
-00C08D TRONIX PRODUCT DEVELOPMENT
-00C08E NETWORK INFORMATION TECHNOLOGY
-00C08F MATSUSHITA ELECTRIC WORKS, LTD
-00C090 PRAIM S.R.L.
-00C091 JABIL CIRCUIT, INC.
-00C092 MENNEN MEDICAL INC.
-00C093 ALTA RESEARCH CORP.
-00C094 VMX INC.
-00C095 ZNYX
-00C096 TAMURA CORPORATION
-00C097 ARCHIPEL SA
-00C098 CHUNTEX ELECTRONIC CO., LTD.
-00C099 YOSHIKI INDUSTRIAL CO.,LTD.
-00C09A PHOTONICS CORPORATION
-00C09B RELIANCE COMM/TEC, R-TEC
-00C09C TOA ELECTRONIC LTD.
-00C09D DISTRIBUTED SYSTEMS INT'L, INC
-00C09E CACHE COMPUTERS, INC.
-00C09F QUANTA COMPUTER, INC.
-00C0A0 ADVANCE MICRO RESEARCH, INC.
-00C0A1 TOKYO DENSHI SEKEI CO.
-00C0A2 INTERMEDIUM A/S
-00C0A3 DUAL ENTERPRISES CORPORATION
-00C0A4 UNIGRAF OY
-00C0A5 DICKENS DATA SYSTEMS
-00C0A6 EXICOM AUSTRALIA PTY. LTD
-00C0A7 SEEL LTD.
-00C0A8 GVC CORPORATION
-00C0A9 BARRON MCCANN LTD.
-00C0AA SILICON VALLEY COMPUTER
-00C0AB Telco Systems, Inc.
-00C0AC GAMBIT COMPUTER COMMUNICATIONS
-00C0AD MARBEN COMMUNICATION SYSTEMS
-00C0AE TOWERCOM CO. INC. DBA PC HOUSE
-00C0AF TEKLOGIX INC.
-00C0B0 GCC TECHNOLOGIES,INC.
-00C0B1 GENIUS NET CO.
-00C0B2 NORAND CORPORATION
-00C0B3 COMSTAT DATACOMM CORPORATION
-00C0B4 MYSON TECHNOLOGY, INC.
-00C0B5 CORPORATE NETWORK SYSTEMS,INC.
-00C0B6 Snap Appliance, Inc.
-00C0B7 AMERICAN POWER CONVERSION CORP
-00C0B8 FRASER'S HILL LTD.
-00C0B9 FUNK SOFTWARE, INC.
-00C0BA NETVANTAGE
-00C0BB FORVAL CREATIVE, INC.
-00C0BC TELECOM AUSTRALIA/CSSC
-00C0BD INEX TECHNOLOGIES, INC.
-00C0BE ALCATEL - SEL
-00C0BF TECHNOLOGY CONCEPTS, LTD.
-00C0C0 SHORE MICROSYSTEMS, INC.
-00C0C1 QUAD/GRAPHICS, INC.
-00C0C2 INFINITE NETWORKS LTD.
-00C0C3 ACUSON COMPUTED SONOGRAPHY
-00C0C4 COMPUTER OPERATIONAL
-00C0C5 SID INFORMATICA
-00C0C6 PERSONAL MEDIA CORP.
-00C0C7 SPARKTRUM MICROSYSTEMS, INC.
-00C0C8 MICRO BYTE PTY. LTD.
-00C0C9 ELSAG BAILEY PROCESS
-00C0CA ALFA, INC.
-00C0CB CONTROL TECHNOLOGY CORPORATION
-00C0CC TELESCIENCES CO SYSTEMS, INC.
-00C0CD COMELTA, S.A.
-00C0CE CEI SYSTEMS & ENGINEERING PTE
-00C0CF IMATRAN VOIMA OY
-00C0D0 RATOC SYSTEM INC.
-00C0D1 COMTREE TECHNOLOGY CORPORATION
-00C0D2 SYNTELLECT, INC.
-00C0D3 OLYMPUS IMAGE SYSTEMS, INC.
-00C0D4 AXON NETWORKS, INC.
-00C0D5 QUANCOM ELECTRONIC GMBH
-00C0D6 J1 SYSTEMS, INC.
-00C0D7 TAIWAN TRADING CENTER DBA
-00C0D8 UNIVERSAL DATA SYSTEMS
-00C0D9 QUINTE NETWORK CONFIDENTIALITY
-00C0DA NICE SYSTEMS LTD.
-00C0DB IPC CORPORATION (PTE) LTD.
-00C0DC EOS TECHNOLOGIES, INC.
-00C0DD QLogic Corporation
-00C0DE ZCOMM, INC.
-00C0DF KYE Systems Corp.
-00C0E0 DSC COMMUNICATION CORP.
-00C0E1 SONIC SOLUTIONS
-00C0E2 CALCOMP, INC.
-00C0E3 OSITECH COMMUNICATIONS, INC.
-00C0E4 SIEMENS BUILDING
-00C0E5 GESPAC, S.A.
-00C0E6 Verilink Corporation
-00C0E7 FIBERDATA AB
-00C0E8 PLEXCOM, INC.
-00C0E9 OAK SOLUTIONS, LTD.
-00C0EA ARRAY TECHNOLOGY LTD.
-00C0EB SEH COMPUTERTECHNIK GMBH
-00C0EC DAUPHIN TECHNOLOGY
-00C0ED US ARMY ELECTRONIC
-00C0EE KYOCERA CORPORATION
-00C0EF ABIT CORPORATION
-00C0F0 KINGSTON TECHNOLOGY CORP.
-00C0F1 SHINKO ELECTRIC CO., LTD.
-00C0F2 TRANSITION NETWORKS
-00C0F3 NETWORK COMMUNICATIONS CORP.
-00C0F4 INTERLINK SYSTEM CO., LTD.
-00C0F5 METACOMP, INC.
-00C0F6 CELAN TECHNOLOGY INC.
-00C0F7 ENGAGE COMMUNICATION, INC.
-00C0F8 ABOUT COMPUTING INC.
-00C0F9 HARRIS AND JEFFRIES, INC.
-00C0FA CANARY COMMUNICATIONS, INC.
-00C0FB ADVANCED TECHNOLOGY LABS
-00C0FC ELASTIC REALITY, INC.
-00C0FD PROSUM
-00C0FE APTEC COMPUTER SYSTEMS, INC.
-00C0FF DOT HILL SYSTEMS CORPORATION
-00CBBD Cambridge Broadband Ltd.
-00CF1C COMMUNICATION MACHINERY CORP.
-00D000 FERRAN SCIENTIFIC, INC.
-00D001 VST TECHNOLOGIES, INC.
-00D002 DITECH CORPORATION
-00D003 COMDA ENTERPRISES CORP.
-00D004 PENTACOM LTD.
-00D005 ZHS ZEITMANAGEMENTSYSTEME
-00D006 CISCO SYSTEMS, INC.
-00D007 MIC ASSOCIATES, INC.
-00D008 MACTELL CORPORATION
-00D009 HSING TECH. ENTERPRISE CO. LTD
-00D00A LANACCESS TELECOM S.A.
-00D00B RHK TECHNOLOGY, INC.
-00D00C SNIJDER MICRO SYSTEMS
-00D00D MICROMERITICS INSTRUMENT
-00D00E PLURIS, INC.
-00D00F SPEECH DESIGN GMBH
-00D010 CONVERGENT NETWORKS, INC.
-00D011 PRISM VIDEO, INC.
-00D012 GATEWORKS CORP.
-00D013 PRIMEX AEROSPACE COMPANY
-00D014 ROOT, INC.
-00D015 UNIVEX MICROTECHNOLOGY CORP.
-00D016 SCM MICROSYSTEMS, INC.
-00D017 SYNTECH INFORMATION CO., LTD.
-00D018 QWES. COM, INC.
-00D019 DAINIPPON SCREEN CORPORATE
-00D01A URMET SUD S.P.A.
-00D01B MIMAKI ENGINEERING CO., LTD.
-00D01C SBS TECHNOLOGIES,
-00D01D FURUNO ELECTRIC CO., LTD.
-00D01E PINGTEL CORP.
-00D01F CTAM PTY. LTD.
-00D020 AIM SYSTEM, INC.
-00D021 REGENT ELECTRONICS CORP.
-00D022 INCREDIBLE TECHNOLOGIES, INC.
-00D023 INFORTREND TECHNOLOGY, INC.
-00D024 Cognex Corporation
-00D025 XROSSTECH, INC.
-00D026 HIRSCHMANN AUSTRIA GMBH
-00D027 APPLIED AUTOMATION, INC.
-00D028 OMNEON VIDEO NETWORKS
-00D029 WAKEFERN FOOD CORPORATION
-00D02A Voxent Systems Ltd.
-00D02B JETCELL, INC.
-00D02C CAMPBELL SCIENTIFIC, INC.
-00D02D ADEMCO
-00D02E COMMUNICATION AUTOMATION CORP.
-00D02F VLSI TECHNOLOGY INC.
-00D030 SAFETRAN SYSTEMS CORP.
-00D031 INDUSTRIAL LOGIC CORPORATION
-00D032 YANO ELECTRIC CO., LTD.
-00D033 DALIAN DAXIAN NETWORK
-00D034 ORMEC SYSTEMS CORP.
-00D035 BEHAVIOR TECH. COMPUTER CORP.
-00D036 TECHNOLOGY ATLANTA CORP.
-00D037 PHILIPS-DVS-LO BDR
-00D038 FIVEMERE, LTD.
-00D039 UTILICOM, INC.
-00D03A ZONEWORX, INC.
-00D03B VISION PRODUCTS PTY. LTD.
-00D03C Vieo, Inc.
-00D03D GALILEO TECHNOLOGY, LTD.
-00D03E ROCKETCHIPS, INC.
-00D03F AMERICAN COMMUNICATION
-00D040 SYSMATE CO., LTD.
-00D041 AMIGO TECHNOLOGY CO., LTD.
-00D042 MAHLO GMBH & CO. UG
-00D043 ZONAL RETAIL DATA SYSTEMS
-00D044 ALIDIAN NETWORKS, INC.
-00D045 KVASER AB
-00D046 DOLBY LABORATORIES, INC.
-00D047 XN TECHNOLOGIES
-00D048 ECTON, INC.
-00D049 IMPRESSTEK CO., LTD.
-00D04A PRESENCE TECHNOLOGY GMBH
-00D04B LA CIE GROUP S.A.
-00D04C EUROTEL TELECOM LTD.
-00D04D DIV OF RESEARCH & STATISTICS
-00D04E LOGIBAG
-00D04F BITRONICS, INC.
-00D050 ISKRATEL
-00D051 O2 MICRO, INC.
-00D052 ASCEND COMMUNICATIONS, INC.
-00D053 CONNECTED SYSTEMS
-00D054 SAS INSTITUTE INC.
-00D055 KATHREIN-WERKE KG
-00D056 SOMAT CORPORATION
-00D057 ULTRAK, INC.
-00D058 CISCO SYSTEMS, INC.
-00D059 AMBIT MICROSYSTEMS CORP.
-00D05A SYMBIONICS, LTD.
-00D05B ACROLOOP MOTION CONTROL
-00D05C TECHNOTREND SYSTEMTECHNIK GMBH
-00D05D INTELLIWORXX, INC.
-00D05E STRATABEAM TECHNOLOGY, INC.
-00D05F VALCOM, INC.
-00D060 PANASONIC EUROPEAN
-00D061 TREMON ENTERPRISES CO., LTD.
-00D062 DIGIGRAM
-00D063 CISCO SYSTEMS, INC.
-00D064 MULTITEL
-00D065 TOKO ELECTRIC
-00D066 WINTRISS ENGINEERING CORP.
-00D067 CAMPIO COMMUNICATIONS
-00D068 IWILL CORPORATION
-00D069 TECHNOLOGIC SYSTEMS
-00D06A LINKUP SYSTEMS CORPORATION
-00D06B SR TELECOM INC.
-00D06C SHAREWAVE, INC.
-00D06D ACRISON, INC.
-00D06E TRENDVIEW RECORDERS LTD.
-00D06F KMC CONTROLS
-00D070 LONG WELL ELECTRONICS CORP.
-00D071 ECHELON CORP.
-00D072 BROADLOGIC
-00D073 ACN ADVANCED COMMUNICATIONS
-00D074 TAQUA SYSTEMS, INC.
-00D075 ALARIS MEDICAL SYSTEMS, INC.
-00D076 MERRILL LYNCH & CO., INC.
-00D077 LUCENT TECHNOLOGIES
-00D078 ELTEX OF SWEDEN AB
-00D079 CISCO SYSTEMS, INC.
-00D07A AMAQUEST COMPUTER CORP.
-00D07B COMCAM INTERNATIONAL LTD.
-00D07C KOYO ELECTRONICS INC. CO.,LTD.
-00D07D COSINE COMMUNICATIONS
-00D07E KEYCORP LTD.
-00D07F STRATEGY & TECHNOLOGY, LIMITED
-00D080 EXABYTE CORPORATION
-00D081 REAL TIME DEVICES USA, INC.
-00D082 IOWAVE INC.
-00D083 INVERTEX, INC.
-00D084 NEXCOMM SYSTEMS, INC.
-00D085 OTIS ELEVATOR COMPANY
-00D086 FOVEON, INC.
-00D087 MICROFIRST INC.
-00D088 Terayon Communications Systems
-00D089 DYNACOLOR, INC.
-00D08A PHOTRON USA
-00D08B ADVA Limited
-00D08C GENOA TECHNOLOGY, INC.
-00D08D PHOENIX GROUP, INC.
-00D08E NVISION INC.
-00D08F ARDENT TECHNOLOGIES, INC.
-00D090 CISCO SYSTEMS, INC.
-00D091 SMARTSAN SYSTEMS, INC.
-00D092 GLENAYRE WESTERN MULTIPLEX
-00D093 TQ - COMPONENTS GMBH
-00D094 TIMELINE VISTA, INC.
-00D095 XYLAN CORPORATION
-00D096 3COM EUROPE LTD.
-00D097 CISCO SYSTEMS, INC.
-00D098 Photon Dynamics Canada Inc.
-00D099 ELCARD OY
-00D09A FILANET CORPORATION
-00D09B SPECTEL LTD.
-00D09C KAPADIA COMMUNICATIONS
-00D09D VERIS INDUSTRIES
-00D09E 2WIRE, INC.
-00D09F NOVTEK TEST SYSTEMS
-00D0A0 MIPS DENMARK
-00D0A1 OSKAR VIERLING GMBH + CO. KG
-00D0A2 INTEGRATED DEVICE
-00D0A3 VOCAL DATA, INC.
-00D0A4 ALANTRO COMMUNICATIONS
-00D0A5 AMERICAN ARIUM
-00D0A6 LANBIRD TECHNOLOGY CO., LTD.
-00D0A7 TOKYO SOKKI KENKYUJO CO., LTD.
-00D0A8 NETWORK ENGINES, INC.
-00D0A9 SHINANO KENSHI CO., LTD.
-00D0AA CHASE COMMUNICATIONS
-00D0AB DELTAKABEL TELECOM CV
-00D0AC GRAYSON WIRELESS
-00D0AD TL INDUSTRIES
-00D0AE ORESIS COMMUNICATIONS, INC.
-00D0AF CUTLER-HAMMER, INC.
-00D0B0 BITSWITCH LTD.
-00D0B1 OMEGA ELECTRONICS SA
-00D0B2 XIOTECH CORPORATION
-00D0B3 DRS FLIGHT SAFETY AND
-00D0B4 KATSUJIMA CO., LTD.
-00D0B5 IPricot formerly DotCom
-00D0B6 CRESCENT NETWORKS, INC.
-00D0B7 INTEL CORPORATION
-00D0B8 IOMEGA CORP.
-00D0B9 MICROTEK INTERNATIONAL, INC.
-00D0BA CISCO SYSTEMS, INC.
-00D0BB CISCO SYSTEMS, INC.
-00D0BC CISCO SYSTEMS, INC.
-00D0BD SICAN GMBH
-00D0BE EMUTEC INC.
-00D0BF PIVOTAL TECHNOLOGIES
-00D0C0 CISCO SYSTEMS, INC.
-00D0C1 HARMONIC DATA SYSTEMS, LTD.
-00D0C2 BALTHAZAR TECHNOLOGY AB
-00D0C3 VIVID TECHNOLOGY PTE, LTD.
-00D0C4 TERATECH CORPORATION
-00D0C5 COMPUTATIONAL SYSTEMS, INC.
-00D0C6 THOMAS & BETTS CORP.
-00D0C7 PATHWAY, INC.
-00D0C8 I/O CONSULTING A/S
-00D0C9 ADVANTECH CO., LTD.
-00D0CA INTRINSYC SOFTWARE INC.
-00D0CB DASAN CO., LTD.
-00D0CC TECHNOLOGIES LYRE INC.
-00D0CD ATAN TECHNOLOGY INC.
-00D0CE ASYST ELECTRONIC
-00D0CF MORETON BAY
-00D0D0 ZHONGXING TELECOM LTD.
-00D0D1 SIROCCO SYSTEMS, INC.
-00D0D2 EPILOG CORPORATION
-00D0D3 CISCO SYSTEMS, INC.
-00D0D4 V-BITS, INC.
-00D0D5 GRUNDIG AG
-00D0D6 AETHRA TELECOMUNICAZIONI
-00D0D7 B2C2, INC.
-00D0D8 3Com Corporation
-00D0D9 DEDICATED MICROCOMPUTERS
-00D0DA TAICOM DATA SYSTEMS CO., LTD.
-00D0DB MCQUAY INTERNATIONAL
-00D0DC MODULAR MINING SYSTEMS, INC.
-00D0DD SUNRISE TELECOM, INC.
-00D0DE PHILIPS MULTIMEDIA NETWORK
-00D0DF KUZUMI ELECTRONICS, INC.
-00D0E0 DOOIN ELECTRONICS CO.
-00D0E1 AVIONITEK ISRAEL INC.
-00D0E2 MRT MICRO, INC.
-00D0E3 ELE-CHEM ENGINEERING CO., LTD.
-00D0E4 CISCO SYSTEMS, INC.
-00D0E5 SOLIDUM SYSTEMS CORP.
-00D0E6 IBOND INC.
-00D0E7 VCON TELECOMMUNICATION LTD.
-00D0E8 MAC SYSTEM CO., LTD.
-00D0E9 ADVANTAGE CENTURY
-00D0EA NEXTONE COMMUNICATIONS, INC.
-00D0EB LIGHTERA NETWORKS, INC.
-00D0EC NAKAYO TELECOMMUNICATIONS, INC
-00D0ED XIOX
-00D0EE DICTAPHONE CORPORATION
-00D0EF IGT
-00D0F0 CONVISION TECHNOLOGY GMBH
-00D0F1 SEGA ENTERPRISES, LTD.
-00D0F2 MONTEREY NETWORKS
-00D0F3 SOLARI DI UDINE SPA
-00D0F4 CARINTHIAN TECH INSTITUTE
-00D0F5 ORANGE MICRO, INC.
-00D0F6 Alcatel Canada
-00D0F7 NEXT NETS CORPORATION
-00D0F8 FUJIAN STAR TERMINAL
-00D0F9 ACUTE COMMUNICATIONS CORP.
-00D0FA RACAL GUARDATA
-00D0FB TEK MICROSYSTEMS, INCORPORATED
-00D0FC GRANITE MICROSYSTEMS
-00D0FD OPTIMA TELE.COM, INC.
-00D0FE ASTRAL POINT
-00D0FF CISCO SYSTEMS, INC.
-00DD00 UNGERMANN-BASS INC.
-00DD01 UNGERMANN-BASS INC.
-00DD02 UNGERMANN-BASS INC.
-00DD03 UNGERMANN-BASS INC.
-00DD04 UNGERMANN-BASS INC.
-00DD05 UNGERMANN-BASS INC.
-00DD06 UNGERMANN-BASS INC.
-00DD07 UNGERMANN-BASS INC.
-00DD08 UNGERMANN-BASS INC.
-00DD09 UNGERMANN-BASS INC.
-00DD0A UNGERMANN-BASS INC.
-00DD0B UNGERMANN-BASS INC.
-00DD0C UNGERMANN-BASS INC.
-00DD0D UNGERMANN-BASS INC.
-00DD0E UNGERMANN-BASS INC.
-00DD0F UNGERMANN-BASS INC.
-00E000 FUJITSU, LTD
-00E001 STRAND LIGHTING LIMITED
-00E002 CROSSROADS SYSTEMS, INC.
-00E003 NOKIA WIRELESS BUSINESS COMMUN
-00E004 PMC-SIERRA, INC.
-00E005 TECHNICAL CORP.
-00E006 SILICON INTEGRATED SYS. CORP.
-00E007 NETWORK ALCHEMY LTD.
-00E008 AMAZING CONTROLS! INC.
-00E009 MARATHON TECHNOLOGIES CORP.
-00E00A DIBA, INC.
-00E00B ROOFTOP COMMUNICATIONS CORP.
-00E00C MOTOROLA
-00E00D RADIANT SYSTEMS
-00E00E AVALON IMAGING SYSTEMS, INC.
-00E00F SHANGHAI BAUD DATA
-00E010 HESS SB-AUTOMATENBAU GmbH
-00E011 UNIDEN SAN DIEGO R&D CENTER, INC.
-00E012 PLUTO TECHNOLOGIES INTERNATIONAL INC.
-00E013 EASTERN ELECTRONIC CO., LTD.
-00E014 CISCO SYSTEMS, INC.
-00E015 HEIWA CORPORATION
-00E016 RAPID CITY COMMUNICATIONS
-00E017 EXXACT GmbH
-00E018 ASUSTEK COMPUTER INC.
-00E019 ING. GIORDANO ELETTRONICA
-00E01A COMTEC SYSTEMS. CO., LTD.
-00E01B SPHERE COMMUNICATIONS, INC.
-00E01C MOBILITY ELECTRONICSY
-00E01D WebTV NETWORKS, INC.
-00E01E CISCO SYSTEMS, INC.
-00E01F AVIDIA Systems, Inc.
-00E020 TECNOMEN OY
-00E021 FREEGATE CORP.
-00E022 MediaLight, Inc.
-00E023 TELRAD
-00E024 GADZOOX NETWORKS
-00E025 dit CO., LTD.
-00E026 EASTMAN KODAK CO.
-00E027 DUX, INC.
-00E028 APTIX CORPORATION
-00E029 STANDARD MICROSYSTEMS CORP.
-00E02A TANDBERG TELEVISION AS
-00E02B EXTREME NETWORKS
-00E02C AST COMPUTER
-00E02D InnoMediaLogic, Inc.
-00E02E SPC ELECTRONICS CORPORATION
-00E02F MCNS HOLDINGS, L.P.
-00E030 MELITA INTERNATIONAL CORP.
-00E031 HAGIWARA ELECTRIC CO., LTD.
-00E032 MISYS FINANCIAL SYSTEMS, LTD.
-00E033 E.E.P.D. GmbH
-00E034 CISCO SYSTEMS, INC.
-00E035 LOUGHBOROUGH SOUND IMAGES, PLC
-00E036 PIONEER CORPORATION
-00E037 CENTURY CORPORATION
-00E038 PROXIMA CORPORATION
-00E039 PARADYNE CORP.
-00E03A CABLETRON SYSTEMS, INC.
-00E03B PROMINET CORPORATION
-00E03C AdvanSys
-00E03D FOCON ELECTRONIC SYSTEMS A/S
-00E03E ALFATECH, INC.
-00E03F JATON CORPORATION
-00E040 DeskStation Technology, Inc.
-00E041 CSPI
-00E042 Pacom Systems Ltd.
-00E043 VitalCom
-00E044 LSICS CORPORATION
-00E045 TOUCHWAVE, INC.
-00E046 BENTLY NEVADA CORP.
-00E047 INFOCUS SYSTEMS
-00E048 SDL COMMUNICATIONS, INC.
-00E049 MICROWI ELECTRONIC GmbH
-00E04A ENHANCED MESSAGING SYSTEMS, INC
-00E04B JUMP INDUSTRIELLE COMPUTERTECHNIK GmbH
-00E04C REALTEK SEMICONDUCTOR CORP.
-00E04D INTERNET INITIATIVE JAPAN, INC
-00E04E SANYO DENKI CO., LTD.
-00E04F CISCO SYSTEMS, INC.
-00E050 EXECUTONE INFORMATION SYSTEMS, INC.
-00E051 TALX CORPORATION
-00E052 FOUNDRY NETWORKS, INC.
-00E053 CELLPORT LABS, INC.
-00E054 KODAI HITEC CO., LTD.
-00E055 INGENIERIA ELECTRONICA COMERCIAL INELCOM S.A.
-00E056 HOLONTECH CORPORATION
-00E057 HAN MICROTELECOM. CO., LTD.
-00E058 PHASE ONE DENMARK A/S
-00E059 CONTROLLED ENVIRONMENTS, LTD.
-00E05A GALEA NETWORK SECURITY
-00E05B WEST END SYSTEMS CORP.
-00E05C MATSUSHITA KOTOBUKI ELECTRONICS INDUSTRIES, LTD.
-00E05D UNITEC CO., LTD.
-00E05E JAPAN AVIATION ELECTRONICS INDUSTRY, LTD.
-00E05F e-Net, Inc.
-00E060 SHERWOOD
-00E061 EdgePoint Networks, Inc.
-00E062 HOST ENGINEERING
-00E063 CABLETRON - YAGO SYSTEMS, INC.
-00E064 SAMSUNG ELECTRONICS
-00E065 OPTICAL ACCESS INTERNATIONAL
-00E066 ProMax Systems, Inc.
-00E067 eac AUTOMATION-CONSULTING GmbH
-00E068 MERRIMAC SYSTEMS INC.
-00E069 JAYCOR
-00E06A KAPSCH AG
-00E06B W&G SPECIAL PRODUCTS
-00E06C AEP Systems International Ltd
-00E06D COMPUWARE CORPORATION
-00E06E FAR SYSTEMS S.p.A.
-00E06F Terayon Communications Systems
-00E070 DH TECHNOLOGY
-00E071 EPIS MICROCOMPUTER
-00E072 LYNK
-00E073 NATIONAL AMUSEMENT NETWORK, INC.
-00E074 TIERNAN COMMUNICATIONS, INC.
-00E075 Verilink Corporation
-00E076 DEVELOPMENT CONCEPTS, INC.
-00E077 WEBGEAR, INC.
-00E078 BERKELEY NETWORKS
-00E079 A.T.N.R.
-00E07A MIKRODIDAKT AB
-00E07B BAY NETWORKS
-00E07C METTLER-TOLEDO, INC.
-00E07D NETRONIX, INC.
-00E07E WALT DISNEY IMAGINEERING
-00E07F LOGISTISTEM s.r.l.
-00E080 CONTROL RESOURCES CORPORATION
-00E081 TYAN COMPUTER CORP.
-00E082 ANERMA
-00E083 JATO TECHNOLOGIES, INC.
-00E084 COMPULITE R&D
-00E085 GLOBAL MAINTECH, INC.
-00E086 CYBEX COMPUTER PRODUCTS
-00E087 LeCroy - Networking Productions Division
-00E088 LTX CORPORATION
-00E089 ION Networks, Inc.
-00E08A GEC AVERY, LTD.
-00E08B QLogic Corp.
-00E08C NEOPARADIGM LABS, INC.
-00E08D PRESSURE SYSTEMS, INC.
-00E08E UTSTARCOM
-00E08F CISCO SYSTEMS, INC.
-00E090 BECKMAN LAB. AUTOMATION DIV.
-00E091 LG ELECTRONICS, INC.
-00E092 ADMTEK INCORPORATED
-00E093 ACKFIN NETWORKS
-00E094 OSAI SRL
-00E095 ADVANCED-VISION TECHNOLGIES CORP.
-00E096 SHIMADZU CORPORATION
-00E097 CARRIER ACCESS CORPORATION
-00E098 AboCom Systems, Inc.
-00E099 SAMSON AG
-00E09A POSITRON INDUSTRIES, INC.
-00E09B ENGAGE NETWORKS, INC.
-00E09C MII
-00E09D SARNOFF CORPORATION
-00E09E QUANTUM CORPORATION
-00E09F PIXEL VISION
-00E0A0 WILTRON CO.
-00E0A1 HIMA PAUL HILDEBRANDT GmbH Co. KG
-00E0A2 MICROSLATE INC.
-00E0A3 CISCO SYSTEMS, INC.
-00E0A4 ESAOTE S.p.A.
-00E0A5 ComCore Semiconductor, Inc.
-00E0A6 TELOGY NETWORKS, INC.
-00E0A7 IPC INFORMATION SYSTEMS, INC.
-00E0A8 SAT GmbH & Co.
-00E0A9 FUNAI ELECTRIC CO., LTD.
-00E0AA ELECTROSONIC LTD.
-00E0AB DIMAT S.A.
-00E0AC MIDSCO, INC.
-00E0AD EES TECHNOLOGY, LTD.
-00E0AE XAQTI CORPORATION
-00E0AF GENERAL DYNAMICS INFORMATION SYSTEMS
-00E0B0 CISCO SYSTEMS, INC.
-00E0B1 PACKET ENGINES, INC.
-00E0B2 TELMAX COMMUNICATIONS CORP.
-00E0B3 EtherWAN Systems, Inc.
-00E0B4 TECHNO SCOPE CO., LTD.
-00E0B5 ARDENT COMMUNICATIONS CORP.
-00E0B6 Entrada Networks
-00E0B7 PI GROUP, LTD.
-00E0B8 GATEWAY 2000
-00E0B9 BYAS SYSTEMS
-00E0BA BERGHOF AUTOMATIONSTECHNIK GmbH
-00E0BB NBX CORPORATION
-00E0BC SYMON COMMUNICATIONS, INC.
-00E0BD INTERFACE SYSTEMS, INC.
-00E0BE GENROCO INTERNATIONAL, INC.
-00E0BF TORRENT NETWORKING TECHNOLOGIES CORP.
-00E0C0 SEIWA ELECTRIC MFG. CO., LTD.
-00E0C1 MEMOREX TELEX JAPAN, LTD.
-00E0C2 NECSY S.p.A.
-00E0C3 SAKAI SYSTEM DEVELOPMENT CORP.
-00E0C4 HORNER ELECTRIC, INC.
-00E0C5 BCOM ELECTRONICS INC.
-00E0C6 LINK2IT, L.L.C.
-00E0C7 EUROTECH SRL
-00E0C8 VIRTUAL ACCESS, LTD.
-00E0C9 AutomatedLogic Corporation
-00E0CA BEST DATA PRODUCTS
-00E0CB RESON, INC.
-00E0CC HERO SYSTEMS, LTD.
-00E0CD SENSIS CORPORATION
-00E0CE ARN
-00E0CF INTEGRATED DEVICE TECHNOLOGY, INC.
-00E0D0 NETSPEED, INC.
-00E0D1 TELSIS LIMITED
-00E0D2 VERSANET COMMUNICATIONS, INC.
-00E0D3 DATENTECHNIK GmbH
-00E0D4 EXCELLENT COMPUTER
-00E0D5 ARCXEL TECHNOLOGIES, INC.
-00E0D6 COMPUTER & COMMUNICATION RESEARCH LAB.
-00E0D7 SUNSHINE ELECTRONICS, INC.
-00E0D8 LANBit Computer, Inc.
-00E0D9 TAZMO CO., LTD.
-00E0DA ASSURED ACCESS TECHNOLOGY, INC.
-00E0DB ViaVideo Communications, Inc.
-00E0DC NEXWARE CORP.
-00E0DD ZENITH ELECTRONICS CORPORATION
-00E0DE DATAX NV
-00E0DF KE KOMMUNIKATIONS-ELECTRONIK
-00E0E0 SI ELECTRONICS, LTD.
-00E0E1 G2 NETWORKS, INC.
-00E0E2 INNOVA CORP.
-00E0E3 SK-ELEKTRONIK GmbH
-00E0E4 FANUC ROBOTICS NORTH AMERICA, Inc.
-00E0E5 CINCO NETWORKS, INC.
-00E0E6 INCAA DATACOM B.V.
-00E0E7 RAYTHEON E-SYSTEMS, INC.
-00E0E8 GRETACODER Data Systems AG
-00E0E9 DATA LABS, INC.
-00E0EA INNOVAT COMMUNICATIONS, INC.
-00E0EB DIGICOM SYSTEMS, INCORPORATED
-00E0EC CELESTICA INC.
-00E0ED SILICOM, LTD.
-00E0EE MAREL HF
-00E0EF DIONEX
-00E0F0 ABLER TECHNOLOGY, INC.
-00E0F1 THAT CORPORATION
-00E0F2 ARLOTTO COMNET, INC.
-00E0F3 WebSprint Communications, Inc.
-00E0F4 INSIDE Technology A/S
-00E0F5 TELES AG
-00E0F6 DECISION EUROPE
-00E0F7 CISCO SYSTEMS, INC.
-00E0F8 DICNA CONTROL AB
-00E0F9 CISCO SYSTEMS, INC.
-00E0FA TRL TECHNOLOGY, LTD.
-00E0FB LEIGHTRONIX, INC.
-00E0FC HUAWEI TECHNOLOGIES CO., LTD.
-00E0FD A-TREND TECHNOLOGY CO., LTD.
-00E0FE CISCO SYSTEMS, INC.
-00E0FF SECURITY DYNAMICS TECHNOLOGIES, Inc.
-00E6D3 NIXDORF COMPUTER CORP.
-020701 RACAL-DATACOM
-021C7C PERQ SYSTEMS CORPORATION
-026086 LOGIC REPLACEMENT TECH. LTD.
-02608C 3COM CORPORATION
-027001 RACAL-DATACOM
-0270B0 M/A-COM INC. COMPANIES
-0270B3 DATA RECALL LTD
-029D8E CARDIAC RECORDERS INC.
-02AA3C OLIVETTI TELECOMM SPA (OLTECO)
-02BB01 OCTOTHORPE CORP.
-02C08C 3COM CORPORATION
-02CF1C COMMUNICATION MACHINERY CORP.
-02E6D3 NIXDORF COMPUTER CORPORATION
-040AE0 XMIT AG COMPUTER NETWORKS
-04E0C4 TRIUMPH-ADLER AG
-080001 COMPUTERVISION CORPORATION
-080002 BRIDGE COMMUNICATIONS INC.
-080003 ADVANCED COMPUTER COMM.
-080004 CROMEMCO INCORPORATED
-080005 SYMBOLICS INC.
-080006 SIEMENS AG
-080007 APPLE COMPUTER INC.
-080008 BOLT BERANEK AND NEWMAN INC.
-080009 HEWLETT PACKARD
-08000A NESTAR SYSTEMS INCORPORATED
-08000B UNISYS CORPORATION
-08000C MIKLYN DEVELOPMENT CO.
-08000D INTERNATIONAL COMPUTERS LTD.
-08000E NCR CORPORATION
-08000F MITEL CORPORATION
-080011 TEKTRONIX INC.
-080012 BELL ATLANTIC INTEGRATED SYST.
-080013 EXXON
-080014 EXCELAN
-080015 STC BUSINESS SYSTEMS
-080016 BARRISTER INFO SYS CORP
-080017 NATIONAL SEMICONDUCTOR
-080018 PIRELLI FOCOM NETWORKS
-080019 GENERAL ELECTRIC CORPORATION
-08001A TIARA/ 10NET
-08001B DATA GENERAL
-08001C KDD-KOKUSAI DEBNSIN DENWA CO.
-08001D ABLE COMMUNICATIONS INC.
-08001E APOLLO COMPUTER INC.
-08001F SHARP CORPORATION
-080020 SUN MICROSYSTEMS INC.
-080021 3M COMPANY
-080022 NBI INC.
-080023 Panasonic Communications Co., Ltd.
-080024 10NET COMMUNICATIONS/DCA
-080025 CONTROL DATA
-080026 NORSK DATA A.S.
-080027 CADMUS COMPUTER SYSTEMS
-080028 Texas Instruments
-080029 MEGATEK CORPORATION
-08002A MOSAIC TECHNOLOGIES INC.
-08002B DIGITAL EQUIPMENT CORPORATION
-08002C BRITTON LEE INC.
-08002D LAN-TEC INC.
-08002E METAPHOR COMPUTER SYSTEMS
-08002F PRIME COMPUTER INC.
-080030 NETWORK RESEARCH CORPORATION
-080030 CERN
-080030 ROYAL MELBOURNE INST OF TECH
-080031 LITTLE MACHINES INC.
-080032 TIGAN INCORPORATED
-080033 BAUSCH & LOMB
-080034 FILENET CORPORATION
-080035 MICROFIVE CORPORATION
-080036 INTERGRAPH CORPORATION
-080037 FUJI-XEROX CO. LTD.
-080038 CII HONEYWELL BULL
-080039 SPIDER SYSTEMS LIMITED
-08003A ORCATECH INC.
-08003B TORUS SYSTEMS LIMITED
-08003C SCHLUMBERGER WELL SERVICES
-08003D CADNETIX CORPORATIONS
-08003E CODEX CORPORATION
-08003F FRED KOSCHARA ENTERPRISES
-080040 FERRANTI COMPUTER SYS. LIMITED
-080041 RACAL-MILGO INFORMATION SYS..
-080042 JAPAN MACNICS CORP.
-080043 PIXEL COMPUTER INC.
-080044 DAVID SYSTEMS INC.
-080045 CONCURRENT COMPUTER CORP.
-080046 SONY CORPORATION LTD.
-080047 SEQUENT COMPUTER SYSTEMS INC.
-080048 EUROTHERM GAUGING SYSTEMS
-080049 UNIVATION
-08004A BANYAN SYSTEMS INC.
-08004B PLANNING RESEARCH CORP.
-08004C HYDRA COMPUTER SYSTEMS INC.
-08004D CORVUS SYSTEMS INC.
-08004E 3COM EUROPE LTD.
-08004F CYGNET SYSTEMS
-080050 DAISY SYSTEMS CORP.
-080051 EXPERDATA
-080052 INSYSTEC
-080053 MIDDLE EAST TECH. UNIVERSITY
-080055 STANFORD TELECOMM. INC.
-080056 STANFORD LINEAR ACCEL. CENTER
-080057 EVANS & SUTHERLAND
-080058 SYSTEMS CONCEPTS
-080059 A/S MYCRON
-08005A IBM CORPORATION
-08005B VTA TECHNOLOGIES INC.
-08005C FOUR PHASE SYSTEMS
-08005D GOULD INC.
-08005E COUNTERPOINT COMPUTER INC.
-08005F SABER TECHNOLOGY CORP.
-080060 INDUSTRIAL NETWORKING INC.
-080061 JAROGATE LTD.
-080062 GENERAL DYNAMICS
-080063 PLESSEY
-080064 AUTOPHON AG
-080065 GENRAD INC.
-080066 AGFA CORPORATION
-080067 COMDESIGN
-080068 RIDGE COMPUTERS
-080069 SILICON GRAPHICS INC.
-08006A ATT BELL LABORATORIES
-08006B ACCEL TECHNOLOGIES INC.
-08006C SUNTEK TECHNOLOGY INT'L
-08006D WHITECHAPEL COMPUTER WORKS
-08006E MASSCOMP
-08006F PHILIPS APELDOORN B.V.
-080070 MITSUBISHI ELECTRIC CORP.
-080071 MATRA (DSIE)
-080072 XEROX CORP UNIV GRANT PROGRAM
-080073 TECMAR INC.
-080074 CASIO COMPUTER CO. LTD.
-080075 DANSK DATA ELECTRONIK
-080076 PC LAN TECHNOLOGIES
-080077 TSL COMMUNICATIONS LTD.
-080078 ACCELL CORPORATION
-080079 THE DROID WORKS
-08007A INDATA
-08007B SANYO ELECTRIC CO. LTD.
-08007C VITALINK COMMUNICATIONS CORP.
-08007E AMALGAMATED WIRELESS(AUS) LTD
-08007F CARNEGIE-MELLON UNIVERSITY
-080080 AES DATA INC.
-080081 ,ASTECH INC.
-080082 VERITAS SOFTWARE
-080083 Seiko Instruments Inc.
-080084 TOMEN ELECTRONICS CORP.
-080085 ELXSI
-080086 KONICA MINOLTA HOLDINGS, INC.
-080087 XYPLEX
-080088 MCDATA CORPORATION
-080089 KINETICS
-08008A PERFORMANCE TECHNOLOGY
-08008B PYRAMID TECHNOLOGY CORP.
-08008C NETWORK RESEARCH CORPORATION
-08008D XYVISION INC.
-08008E TANDEM COMPUTERS
-08008F CHIPCOM CORPORATION
-080090 SONOMA SYSTEMS
-081443 UNIBRAIN S.A.
-08BBCC AK-NORD EDV VERTRIEBSGES. mbH
-10005A IBM CORPORATION
-1000E8 NATIONAL SEMICONDUCTOR
-800010 ATT BELL LABORATORIES
-A06A00 Verilink Corporation
-AA0000 DIGITAL EQUIPMENT CORPORATION
-AA0001 DIGITAL EQUIPMENT CORPORATION
-AA0002 DIGITAL EQUIPMENT CORPORATION
-AA0003 DIGITAL EQUIPMENT CORPORATION
-AA0004 DIGITAL EQUIPMENT CORPORATION
diff --git a/drivers/ieee1394/oui2c.sh b/drivers/ieee1394/oui2c.sh
deleted file mode 100644
index b9d0e8f..0000000
--- a/drivers/ieee1394/oui2c.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-
-cat <<EOF
-/* Generated file for OUI database */
-
-
-#ifdef CONFIG_IEEE1394_OUI_DB
-struct oui_list_struct {
-	int oui;
-	char *name;
-} oui_list[] = {
-EOF
-
-while read oui name; do
-	echo "	{ 0x$oui, \"$name\" },"
-done
-
-cat <<EOF
-};
-
-#endif /* CONFIG_IEEE1394_OUI_DB */
-EOF
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index ad2108f..a77a832 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -636,27 +636,32 @@
 
 	case RAW1394_REQ_SET_CARD:
 		spin_lock_irqsave(&host_info_lock, flags);
-		if (req->req.misc < host_count) {
-			list_for_each_entry(hi, &host_info_list, list) {
-				if (!req->req.misc--)
-					break;
-			}
-			get_device(&hi->host->device);	// XXX Need to handle failure case
-			list_add_tail(&fi->list, &hi->file_info_list);
-			fi->host = hi->host;
-			fi->state = connected;
-
-			req->req.error = RAW1394_ERROR_NONE;
-			req->req.generation = get_hpsb_generation(fi->host);
-			req->req.misc = (fi->host->node_id << 16)
-			    | fi->host->node_count;
-			if (fi->protocol_version > 3) {
-				req->req.misc |=
-				    NODEID_TO_NODE(fi->host->irm_id) << 8;
-			}
-		} else {
+		if (req->req.misc >= host_count) {
 			req->req.error = RAW1394_ERROR_INVALID_ARG;
+			goto out_set_card;
 		}
+		list_for_each_entry(hi, &host_info_list, list)
+			if (!req->req.misc--)
+				break;
+		get_device(&hi->host->device); /* FIXME handle failure case */
+		list_add_tail(&fi->list, &hi->file_info_list);
+
+		/* prevent unloading of the host's low-level driver */
+		if (!try_module_get(hi->host->driver->owner)) {
+			req->req.error = RAW1394_ERROR_ABORTED;
+			goto out_set_card;
+		}
+		WARN_ON(fi->host);
+		fi->host = hi->host;
+		fi->state = connected;
+
+		req->req.error = RAW1394_ERROR_NONE;
+		req->req.generation = get_hpsb_generation(fi->host);
+		req->req.misc = (fi->host->node_id << 16)
+				| fi->host->node_count;
+		if (fi->protocol_version > 3)
+			req->req.misc |= NODEID_TO_NODE(fi->host->irm_id) << 8;
+out_set_card:
 		spin_unlock_irqrestore(&host_info_lock, flags);
 
 		req->req.length = 0;
@@ -2955,6 +2960,11 @@
 		put_device(&fi->host->device);
 	}
 
+	spin_lock_irqsave(&host_info_lock, flags);
+	if (fi->host)
+		module_put(fi->host->driver->owner);
+	spin_unlock_irqrestore(&host_info_lock, flags);
+
 	kfree(fi);
 
 	return 0;
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index 4325aac..4edfff4 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -51,7 +51,6 @@
  * Grep for inline FIXME comments below.
  */
 
-#include <linux/blkdev.h>
 #include <linux/compiler.h>
 #include <linux/delay.h>
 #include <linux/device.h>
@@ -304,10 +303,11 @@
 	.use_clustering		 = ENABLE_CLUSTERING,
 	.cmd_per_lun		 = SBP2_MAX_CMDS,
 	.can_queue		 = SBP2_MAX_CMDS,
-	.emulated		 = 1,
 	.sdev_attrs		 = sbp2_sysfs_sdev_attrs,
 };
 
+/* for match-all entries in sbp2_workarounds_table */
+#define SBP2_ROM_VALUE_WILDCARD 0x1000000
 
 /*
  * List of devices with known bugs.
@@ -329,22 +329,14 @@
 	},
 	/* Initio bridges, actually only needed for some older ones */ {
 		.firmware_revision	= 0x000200,
+		.model_id		= SBP2_ROM_VALUE_WILDCARD,
 		.workarounds		= SBP2_WORKAROUND_INQUIRY_36,
 	},
 	/* Symbios bridge */ {
 		.firmware_revision	= 0xa0b800,
+		.model_id		= SBP2_ROM_VALUE_WILDCARD,
 		.workarounds		= SBP2_WORKAROUND_128K_MAX_TRANS,
 	},
-	/*
-	 * Note about the following Apple iPod blacklist entries:
-	 *
-	 * There are iPods (2nd gen, 3rd gen) with model_id==0.  Since our
-	 * matching logic treats 0 as a wildcard, we cannot match this ID
-	 * without rewriting the matching routine.  Fortunately these iPods
-	 * do not feature the read_capacity bug according to one report.
-	 * Read_capacity behaviour as well as model_id could change due to
-	 * Apple-supplied firmware updates though.
-	 */
 	/* iPod 4th generation */ {
 		.firmware_revision	= 0x0a2700,
 		.model_id		= 0x000021,
@@ -1307,11 +1299,13 @@
 
 	if (!(workarounds & SBP2_WORKAROUND_OVERRIDE))
 		for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) {
-			if (sbp2_workarounds_table[i].firmware_revision &&
+			if (sbp2_workarounds_table[i].firmware_revision !=
+			    SBP2_ROM_VALUE_WILDCARD &&
 			    sbp2_workarounds_table[i].firmware_revision !=
 			    (firmware_revision & 0xffff00))
 				continue;
-			if (sbp2_workarounds_table[i].model_id &&
+			if (sbp2_workarounds_table[i].model_id !=
+			    SBP2_ROM_VALUE_WILDCARD &&
 			    sbp2_workarounds_table[i].model_id != ud->model_id)
 				continue;
 			workarounds |= sbp2_workarounds_table[i].workarounds;
@@ -2017,7 +2011,6 @@
 {
 	struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0];
 
-	blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
 	sdev->use_10_for_rw = 1;
 
 	if (sdev->type == TYPE_ROM)
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
index 598b19f..f4d1ec0 100644
--- a/drivers/ieee1394/video1394.c
+++ b/drivers/ieee1394/video1394.c
@@ -489,6 +489,9 @@
 			reset_ir_status(d, i);
 			d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY;
 			do_gettimeofday(&d->buffer_time[d->buffer_prg_assignment[i]]);
+			dma_region_sync_for_cpu(&d->dma,
+				d->buffer_prg_assignment[i] * d->buf_size,
+				d->buf_size);
 		}
 	}
 
@@ -1096,6 +1099,8 @@
 			DBGMSG(ohci->host->id, "Starting iso transmit DMA ctx=%d",
 			       d->ctx);
 			put_timestamp(ohci, d, d->last_buffer);
+			dma_region_sync_for_device(&d->dma,
+				v.buffer * d->buf_size, d->buf_size);
 
 			/* Tell the controller where the first program is */
 			reg_write(ohci, d->cmdPtr,
@@ -1111,6 +1116,9 @@
 				      "Waking up iso transmit dma ctx=%d",
 				      d->ctx);
 				put_timestamp(ohci, d, d->last_buffer);
+				dma_region_sync_for_device(&d->dma,
+					v.buffer * d->buf_size, d->buf_size);
+
 				reg_write(ohci, d->ctrlSet, 0x1000);
 			}
 		}
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index af93979..d2bb5a9 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -360,8 +360,7 @@
 	if (event == NETEVENT_NEIGH_UPDATE) {
 		struct neighbour *neigh = ctx;
 
-		if (neigh->dev->type == ARPHRD_INFINIBAND &&
-		    (neigh->nud_state & NUD_VALID)) {
+		if (neigh->nud_state & NUD_VALID) {
 			set_timeout(jiffies);
 		}
 	}
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 5ed141e..13efd41 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -642,7 +642,8 @@
 	spin_unlock_irqrestore(&qp_info->snoop_lock, flags);
 }
 
-static void build_smp_wc(u64 wr_id, u16 slid, u16 pkey_index, u8 port_num,
+static void build_smp_wc(struct ib_qp *qp,
+			 u64 wr_id, u16 slid, u16 pkey_index, u8 port_num,
 			 struct ib_wc *wc)
 {
 	memset(wc, 0, sizeof *wc);
@@ -652,7 +653,7 @@
 	wc->pkey_index = pkey_index;
 	wc->byte_len = sizeof(struct ib_mad) + sizeof(struct ib_grh);
 	wc->src_qp = IB_QP0;
-	wc->qp_num = IB_QP0;
+	wc->qp = qp;
 	wc->slid = slid;
 	wc->sl = 0;
 	wc->dlid_path_bits = 0;
@@ -713,7 +714,8 @@
 		goto out;
 	}
 
-	build_smp_wc(send_wr->wr_id, be16_to_cpu(smp->dr_slid),
+	build_smp_wc(mad_agent_priv->agent.qp,
+		     send_wr->wr_id, be16_to_cpu(smp->dr_slid),
 		     send_wr->wr.ud.pkey_index,
 		     send_wr->wr.ud.port_num, &mad_wc);
 
@@ -2355,7 +2357,8 @@
 			 * Defined behavior is to complete response
 			 * before request
 			 */
-			build_smp_wc((unsigned long) local->mad_send_wr,
+			build_smp_wc(recv_mad_agent->agent.qp,
+				     (unsigned long) local->mad_send_wr,
 				     be16_to_cpu(IB_LID_PERMISSIVE),
 				     0, recv_mad_agent->agent.port_num, &wc);
 
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 743247e..df1efbc 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -933,7 +933,7 @@
 		resp->wc[i].vendor_err 	   = wc[i].vendor_err;
 		resp->wc[i].byte_len 	   = wc[i].byte_len;
 		resp->wc[i].imm_data 	   = (__u32 __force) wc[i].imm_data;
-		resp->wc[i].qp_num 	   = wc[i].qp_num;
+		resp->wc[i].qp_num 	   = wc[i].qp->qp_num;
 		resp->wc[i].src_qp 	   = wc[i].src_qp;
 		resp->wc[i].wc_flags 	   = wc[i].wc_flags;
 		resp->wc[i].pkey_index 	   = wc[i].pkey_index;
diff --git a/drivers/infiniband/hw/amso1100/c2_cq.c b/drivers/infiniband/hw/amso1100/c2_cq.c
index 05c9154..5175c99 100644
--- a/drivers/infiniband/hw/amso1100/c2_cq.c
+++ b/drivers/infiniband/hw/amso1100/c2_cq.c
@@ -153,7 +153,7 @@
 
 	entry->status = c2_cqe_status_to_openib(c2_wr_get_result(ce));
 	entry->wr_id = ce->hdr.context;
-	entry->qp_num = ce->handle;
+	entry->qp = &qp->ibqp;
 	entry->wc_flags = 0;
 	entry->slid = 0;
 	entry->sl = 0;
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 1c72203..cf95ee4 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -119,13 +119,14 @@
 	struct ipz_qp_handle ipz_qp_handle;
 	struct ehca_pfqp pf;
 	struct ib_qp_init_attr init_attr;
-	u64 uspace_squeue;
-	u64 uspace_rqueue;
-	u64 uspace_fwh;
 	struct ehca_cq *send_cq;
 	struct ehca_cq *recv_cq;
 	unsigned int sqerr_purgeflag;
 	struct hlist_node list_entries;
+	/* mmap counter for resources mapped into user space */
+	u32 mm_count_squeue;
+	u32 mm_count_rqueue;
+	u32 mm_count_galpa;
 };
 
 /* must be power of 2 */
@@ -142,13 +143,14 @@
 	struct ipz_cq_handle ipz_cq_handle;
 	struct ehca_pfcq pf;
 	spinlock_t cb_lock;
-	u64 uspace_queue;
-	u64 uspace_fwh;
 	struct hlist_head qp_hashtab[QP_HASHTAB_LEN];
 	struct list_head entry;
 	u32 nr_callbacks;
 	spinlock_t task_lock;
 	u32 ownpid;
+	/* mmap counter for resources mapped into user space */
+	u32 mm_count_queue;
+	u32 mm_count_galpa;
 };
 
 enum ehca_mr_flag {
@@ -248,20 +250,6 @@
 	struct ib_ucontext ib_ucontext;
 };
 
-struct ehca_module *ehca_module_new(void);
-
-int ehca_module_delete(struct ehca_module *me);
-
-int ehca_eq_ctor(struct ehca_eq *eq);
-
-int ehca_eq_dtor(struct ehca_eq *eq);
-
-struct ehca_shca *ehca_shca_new(void);
-
-int ehca_shca_delete(struct ehca_shca *me);
-
-struct ehca_sport *ehca_sport_new(struct ehca_shca *anchor);
-
 int ehca_init_pd_cache(void);
 void ehca_cleanup_pd_cache(void);
 int ehca_init_cq_cache(void);
@@ -283,7 +271,6 @@
 extern int ehca_use_hp_mr;
 
 struct ipzu_queue_resp {
-	u64 queue;        /* points to first queue entry */
 	u32 qe_size;      /* queue entry size */
 	u32 act_nr_of_sg;
 	u32 queue_length; /* queue length allocated in bytes */
@@ -296,7 +283,6 @@
 	u32 cq_number;
 	u32 token;
 	struct ipzu_queue_resp ipz_queue;
-	struct h_galpas galpas;
 };
 
 struct ehca_create_qp_resp {
@@ -309,7 +295,6 @@
 	u32 dummy; /* padding for 8 byte alignment */
 	struct ipzu_queue_resp ipz_squeue;
 	struct ipzu_queue_resp ipz_rqueue;
-	struct h_galpas galpas;
 };
 
 struct ehca_alloc_cq_parms {
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index 6074c89..9291a86 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -267,7 +267,6 @@
 	if (context) {
 		struct ipz_queue *ipz_queue = &my_cq->ipz_queue;
 		struct ehca_create_cq_resp resp;
-		struct vm_area_struct *vma;
 		memset(&resp, 0, sizeof(resp));
 		resp.cq_number = my_cq->cq_number;
 		resp.token = my_cq->token;
@@ -276,40 +275,14 @@
 		resp.ipz_queue.queue_length = ipz_queue->queue_length;
 		resp.ipz_queue.pagesize = ipz_queue->pagesize;
 		resp.ipz_queue.toggle_state = ipz_queue->toggle_state;
-		ret = ehca_mmap_nopage(((u64)(my_cq->token) << 32) | 0x12000000,
-				       ipz_queue->queue_length,
-				       (void**)&resp.ipz_queue.queue,
-				       &vma);
-		if (ret) {
-			ehca_err(device, "Could not mmap queue pages");
-			cq = ERR_PTR(ret);
-			goto create_cq_exit4;
-		}
-		my_cq->uspace_queue = resp.ipz_queue.queue;
-		resp.galpas = my_cq->galpas;
-		ret = ehca_mmap_register(my_cq->galpas.user.fw_handle,
-					 (void**)&resp.galpas.kernel.fw_handle,
-					 &vma);
-		if (ret) {
-			ehca_err(device, "Could not mmap fw_handle");
-			cq = ERR_PTR(ret);
-			goto create_cq_exit5;
-		}
-		my_cq->uspace_fwh = (u64)resp.galpas.kernel.fw_handle;
 		if (ib_copy_to_udata(udata, &resp, sizeof(resp))) {
 			ehca_err(device, "Copy to udata failed.");
-			goto create_cq_exit6;
+			goto create_cq_exit4;
 		}
 	}
 
 	return cq;
 
-create_cq_exit6:
-	ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE);
-
-create_cq_exit5:
-	ehca_munmap(my_cq->uspace_queue, my_cq->ipz_queue.queue_length);
-
 create_cq_exit4:
 	ipz_queue_dtor(&my_cq->ipz_queue);
 
@@ -333,7 +306,6 @@
 int ehca_destroy_cq(struct ib_cq *cq)
 {
 	u64 h_ret;
-	int ret;
 	struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
 	int cq_num = my_cq->cq_number;
 	struct ib_device *device = cq->device;
@@ -343,6 +315,20 @@
 	u32 cur_pid = current->tgid;
 	unsigned long flags;
 
+	if (cq->uobject) {
+		if (my_cq->mm_count_galpa || my_cq->mm_count_queue) {
+			ehca_err(device, "Resources still referenced in "
+				 "user space cq_num=%x", my_cq->cq_number);
+			return -EINVAL;
+		}
+		if (my_cq->ownpid != cur_pid) {
+			ehca_err(device, "Invalid caller pid=%x ownpid=%x "
+				 "cq_num=%x",
+				 cur_pid, my_cq->ownpid, my_cq->cq_number);
+			return -EINVAL;
+		}
+	}
+
 	spin_lock_irqsave(&ehca_cq_idr_lock, flags);
 	while (my_cq->nr_callbacks) {
 		spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
@@ -353,25 +339,6 @@
 	idr_remove(&ehca_cq_idr, my_cq->token);
 	spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
 
-	if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) {
-		ehca_err(device, "Invalid caller pid=%x ownpid=%x",
-			 cur_pid, my_cq->ownpid);
-		return -EINVAL;
-	}
-
-	/* un-mmap if vma alloc */
-	if (my_cq->uspace_queue ) {
-		ret = ehca_munmap(my_cq->uspace_queue,
-				  my_cq->ipz_queue.queue_length);
-		if (ret)
-			ehca_err(device, "Could not munmap queue ehca_cq=%p "
-				 "cq_num=%x", my_cq, cq_num);
-		ret = ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE);
-		if (ret)
-			ehca_err(device, "Could not munmap fwh ehca_cq=%p "
-				 "cq_num=%x", my_cq, cq_num);
-	}
-
 	h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 0);
 	if (h_ret == H_R_STATE) {
 		/* cq in err: read err data and destroy it forcibly */
@@ -400,7 +367,7 @@
 	struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
 	u32 cur_pid = current->tgid;
 
-	if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) {
+	if (cq->uobject && my_cq->ownpid != cur_pid) {
 		ehca_err(cq->device, "Invalid caller pid=%x ownpid=%x",
 			 cur_pid, my_cq->ownpid);
 		return -EINVAL;
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
index cd7789f..95fd59f 100644
--- a/drivers/infiniband/hw/ehca/ehca_iverbs.h
+++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
@@ -171,14 +171,6 @@
 
 void ehca_poll_eqs(unsigned long data);
 
-int ehca_mmap_nopage(u64 foffset,u64 length,void **mapped,
-		     struct vm_area_struct **vma);
-
-int ehca_mmap_register(u64 physical,void **mapped,
-		       struct vm_area_struct **vma);
-
-int ehca_munmap(unsigned long addr, size_t len);
-
 #ifdef CONFIG_PPC_64K_PAGES
 void *ehca_alloc_fw_ctrlblock(gfp_t flags);
 void ehca_free_fw_ctrlblock(void *ptr);
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 6574fbb..1155bcf 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -52,7 +52,7 @@
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
 MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver");
-MODULE_VERSION("SVNEHCA_0019");
+MODULE_VERSION("SVNEHCA_0020");
 
 int ehca_open_aqp1     = 0;
 int ehca_debug_level   = 0;
@@ -288,7 +288,7 @@
 	strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX);
 	shca->ib_device.owner               = THIS_MODULE;
 
-	shca->ib_device.uverbs_abi_ver	    = 5;
+	shca->ib_device.uverbs_abi_ver	    = 6;
 	shca->ib_device.uverbs_cmd_mask	    =
 		(1ull << IB_USER_VERBS_CMD_GET_CONTEXT)		|
 		(1ull << IB_USER_VERBS_CMD_QUERY_DEVICE)	|
@@ -790,7 +790,7 @@
 	int ret;
 
 	printk(KERN_INFO "eHCA Infiniband Device Driver "
-	                 "(Rel.: SVNEHCA_0019)\n");
+	                 "(Rel.: SVNEHCA_0020)\n");
 	idr_init(&ehca_qp_idr);
 	idr_init(&ehca_cq_idr);
 	spin_lock_init(&ehca_qp_idr_lock);
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index 34b8555..95efef9 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -637,7 +637,6 @@
 		struct ipz_queue *ipz_rqueue = &my_qp->ipz_rqueue;
 		struct ipz_queue *ipz_squeue = &my_qp->ipz_squeue;
 		struct ehca_create_qp_resp resp;
-		struct vm_area_struct * vma;
 		memset(&resp, 0, sizeof(resp));
 
 		resp.qp_num = my_qp->real_qp_num;
@@ -651,59 +650,21 @@
 		resp.ipz_rqueue.queue_length = ipz_rqueue->queue_length;
 		resp.ipz_rqueue.pagesize = ipz_rqueue->pagesize;
 		resp.ipz_rqueue.toggle_state = ipz_rqueue->toggle_state;
-		ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x22000000,
-				       ipz_rqueue->queue_length,
-				       (void**)&resp.ipz_rqueue.queue,
-				       &vma);
-		if (ret) {
-			ehca_err(pd->device, "Could not mmap rqueue pages");
-			goto create_qp_exit3;
-		}
-		my_qp->uspace_rqueue = resp.ipz_rqueue.queue;
 		/* squeue properties */
 		resp.ipz_squeue.qe_size = ipz_squeue->qe_size;
 		resp.ipz_squeue.act_nr_of_sg = ipz_squeue->act_nr_of_sg;
 		resp.ipz_squeue.queue_length = ipz_squeue->queue_length;
 		resp.ipz_squeue.pagesize = ipz_squeue->pagesize;
 		resp.ipz_squeue.toggle_state = ipz_squeue->toggle_state;
-		ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x23000000,
-				       ipz_squeue->queue_length,
-				       (void**)&resp.ipz_squeue.queue,
-				       &vma);
-		if (ret) {
-			ehca_err(pd->device, "Could not mmap squeue pages");
-			goto create_qp_exit4;
-		}
-		my_qp->uspace_squeue = resp.ipz_squeue.queue;
-		/* fw_handle */
-		resp.galpas = my_qp->galpas;
-		ret = ehca_mmap_register(my_qp->galpas.user.fw_handle,
-					 (void**)&resp.galpas.kernel.fw_handle,
-					 &vma);
-		if (ret) {
-			ehca_err(pd->device, "Could not mmap fw_handle");
-			goto create_qp_exit5;
-		}
-		my_qp->uspace_fwh = (u64)resp.galpas.kernel.fw_handle;
-
 		if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
 			ehca_err(pd->device, "Copy to udata failed");
 			ret = -EINVAL;
-			goto create_qp_exit6;
+			goto create_qp_exit3;
 		}
 	}
 
 	return &my_qp->ib_qp;
 
-create_qp_exit6:
-	ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE);
-
-create_qp_exit5:
-	ehca_munmap(my_qp->uspace_squeue, my_qp->ipz_squeue.queue_length);
-
-create_qp_exit4:
-	ehca_munmap(my_qp->uspace_rqueue, my_qp->ipz_rqueue.queue_length);
-
 create_qp_exit3:
 	ipz_queue_dtor(&my_qp->ipz_rqueue);
 	ipz_queue_dtor(&my_qp->ipz_squeue);
@@ -931,7 +892,7 @@
 	     my_qp->qp_type == IB_QPT_SMI) &&
 	    statetrans == IB_QPST_SQE2RTS) {
 		/* mark next free wqe if kernel */
-		if (my_qp->uspace_squeue == 0) {
+		if (!ibqp->uobject) {
 			struct ehca_wqe *wqe;
 			/* lock send queue */
 			spin_lock_irqsave(&my_qp->spinlock_s, spl_flags);
@@ -1417,11 +1378,18 @@
 	enum ib_qp_type	qp_type;
 	unsigned long flags;
 
-	if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
-	    my_pd->ownpid != cur_pid) {
-		ehca_err(ibqp->device, "Invalid caller pid=%x ownpid=%x",
-			 cur_pid, my_pd->ownpid);
-		return -EINVAL;
+	if (ibqp->uobject) {
+		if (my_qp->mm_count_galpa ||
+		    my_qp->mm_count_rqueue || my_qp->mm_count_squeue) {
+			ehca_err(ibqp->device, "Resources still referenced in "
+				 "user space qp_num=%x", ibqp->qp_num);
+			return -EINVAL;
+		}
+		if (my_pd->ownpid != cur_pid) {
+			ehca_err(ibqp->device, "Invalid caller pid=%x ownpid=%x",
+				 cur_pid, my_pd->ownpid);
+			return -EINVAL;
+		}
 	}
 
 	if (my_qp->send_cq) {
@@ -1439,24 +1407,6 @@
 	idr_remove(&ehca_qp_idr, my_qp->token);
 	spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
 
-	/* un-mmap if vma alloc */
-	if (my_qp->uspace_rqueue) {
-		ret = ehca_munmap(my_qp->uspace_rqueue,
-				  my_qp->ipz_rqueue.queue_length);
-		if (ret)
-			ehca_err(ibqp->device, "Could not munmap rqueue "
-				 "qp_num=%x", qp_num);
-		ret = ehca_munmap(my_qp->uspace_squeue,
-				  my_qp->ipz_squeue.queue_length);
-		if (ret)
-			ehca_err(ibqp->device, "Could not munmap squeue "
-				 "qp_num=%x", qp_num);
-		ret = ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE);
-		if (ret)
-			ehca_err(ibqp->device, "Could not munmap fwh qp_num=%x",
-				 qp_num);
-	}
-
 	h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
 	if (h_ret != H_SUCCESS) {
 		ehca_err(ibqp->device, "hipz_h_destroy_qp() failed rc=%lx "
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index b46bda1..08d3f89 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -579,7 +579,7 @@
 	} else
 		wc->status = IB_WC_SUCCESS;
 
-	wc->qp_num = cqe->local_qp_number;
+	wc->qp = NULL;
 	wc->byte_len = cqe->nr_bytes_transferred;
 	wc->pkey_index = cqe->pkey_index;
 	wc->slid = cqe->rlid;
diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c
index e08764e..73db920 100644
--- a/drivers/infiniband/hw/ehca/ehca_uverbs.c
+++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c
@@ -68,104 +68,182 @@
 	return 0;
 }
 
-struct page *ehca_nopage(struct vm_area_struct *vma,
-			 unsigned long address, int *type)
+static void ehca_mm_open(struct vm_area_struct *vma)
 {
-	struct page *mypage = NULL;
-	u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
-	u32 idr_handle = fileoffset >> 32;
-	u32 q_type = (fileoffset >> 28) & 0xF;	  /* CQ, QP,...        */
-	u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
-	u32 cur_pid = current->tgid;
-	unsigned long flags;
-	struct ehca_cq *cq;
-	struct ehca_qp *qp;
-	struct ehca_pd *pd;
-	u64 offset;
-	void *vaddr;
+	u32 *count = (u32*)vma->vm_private_data;
+	if (!count) {
+		ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
+			     vma->vm_start, vma->vm_end);
+		return;
+	}
+	(*count)++;
+	if (!(*count))
+		ehca_gen_err("Use count overflow vm_start=%lx vm_end=%lx",
+			     vma->vm_start, vma->vm_end);
+	ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x",
+		     vma->vm_start, vma->vm_end, *count);
+}
 
-	switch (q_type) {
-	case 1: /* CQ */
-		spin_lock_irqsave(&ehca_cq_idr_lock, flags);
-		cq = idr_find(&ehca_cq_idr, idr_handle);
-		spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+static void ehca_mm_close(struct vm_area_struct *vma)
+{
+	u32 *count = (u32*)vma->vm_private_data;
+	if (!count) {
+		ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
+			     vma->vm_start, vma->vm_end);
+		return;
+	}
+	(*count)--;
+	ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x",
+		     vma->vm_start, vma->vm_end, *count);
+}
 
-		/* make sure this mmap really belongs to the authorized user */
-		if (!cq) {
-			ehca_gen_err("cq is NULL ret=NOPAGE_SIGBUS");
-			return NOPAGE_SIGBUS;
+static struct vm_operations_struct vm_ops = {
+	.open =	ehca_mm_open,
+	.close = ehca_mm_close,
+};
+
+static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas,
+			u32 *mm_count)
+{
+	int ret;
+	u64 vsize, physical;
+
+	vsize = vma->vm_end - vma->vm_start;
+	if (vsize != EHCA_PAGESIZE) {
+		ehca_gen_err("invalid vsize=%lx", vma->vm_end - vma->vm_start);
+		return -EINVAL;
+	}
+
+	physical = galpas->user.fw_handle;
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	ehca_gen_dbg("vsize=%lx physical=%lx", vsize, physical);
+	/* VM_IO | VM_RESERVED are set by remap_pfn_range() */
+	ret = remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT,
+			      vsize, vma->vm_page_prot);
+	if (unlikely(ret)) {
+		ehca_gen_err("remap_pfn_range() failed ret=%x", ret);
+		return -ENOMEM;
+	}
+
+	vma->vm_private_data = mm_count;
+	(*mm_count)++;
+	vma->vm_ops = &vm_ops;
+
+	return 0;
+}
+
+static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue,
+			   u32 *mm_count)
+{
+	int ret;
+	u64 start, ofs;
+	struct page *page;
+
+	vma->vm_flags |= VM_RESERVED;
+	start = vma->vm_start;
+	for (ofs = 0; ofs < queue->queue_length; ofs += PAGE_SIZE) {
+		u64 virt_addr = (u64)ipz_qeit_calc(queue, ofs);
+		page = virt_to_page(virt_addr);
+		ret = vm_insert_page(vma, start, page);
+		if (unlikely(ret)) {
+			ehca_gen_err("vm_insert_page() failed rc=%x", ret);
+			return ret;
 		}
+		start +=  PAGE_SIZE;
+	}
+	vma->vm_private_data = mm_count;
+	(*mm_count)++;
+	vma->vm_ops = &vm_ops;
 
-		if (cq->ownpid != cur_pid) {
+	return 0;
+}
+
+static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq,
+			u32 rsrc_type)
+{
+	int ret;
+
+	switch (rsrc_type) {
+	case 1: /* galpa fw handle */
+		ehca_dbg(cq->ib_cq.device, "cq_num=%x fw", cq->cq_number);
+		ret = ehca_mmap_fw(vma, &cq->galpas, &cq->mm_count_galpa);
+		if (unlikely(ret)) {
 			ehca_err(cq->ib_cq.device,
-				 "Invalid caller pid=%x ownpid=%x",
-				 cur_pid, cq->ownpid);
-			return NOPAGE_SIGBUS;
-		}
-
-		if (rsrc_type == 2) {
-			ehca_dbg(cq->ib_cq.device, "cq=%p cq queuearea", cq);
-			offset = address - vma->vm_start;
-			vaddr = ipz_qeit_calc(&cq->ipz_queue, offset);
-			ehca_dbg(cq->ib_cq.device, "offset=%lx vaddr=%p",
-				 offset, vaddr);
-			mypage = virt_to_page(vaddr);
+				 "ehca_mmap_fw() failed rc=%x cq_num=%x",
+				 ret, cq->cq_number);
+			return ret;
 		}
 		break;
 
-	case 2: /* QP */
-		spin_lock_irqsave(&ehca_qp_idr_lock, flags);
-		qp = idr_find(&ehca_qp_idr, idr_handle);
-		spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
-
-		/* make sure this mmap really belongs to the authorized user */
-		if (!qp) {
-			ehca_gen_err("qp is NULL ret=NOPAGE_SIGBUS");
-			return NOPAGE_SIGBUS;
-		}
-
-		pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd);
-		if (pd->ownpid != cur_pid) {
-			ehca_err(qp->ib_qp.device,
-				 "Invalid caller pid=%x ownpid=%x",
-				 cur_pid, pd->ownpid);
-			return NOPAGE_SIGBUS;
-		}
-
-		if (rsrc_type == 2) {	/* rqueue */
-			ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueuearea", qp);
-			offset = address - vma->vm_start;
-			vaddr = ipz_qeit_calc(&qp->ipz_rqueue, offset);
-			ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p",
-				 offset, vaddr);
-			mypage = virt_to_page(vaddr);
-		} else if (rsrc_type == 3) {	/* squeue */
-			ehca_dbg(qp->ib_qp.device, "qp=%p qp squeuearea", qp);
-			offset = address - vma->vm_start;
-			vaddr = ipz_qeit_calc(&qp->ipz_squeue, offset);
-			ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p",
-				 offset, vaddr);
-			mypage = virt_to_page(vaddr);
+	case 2: /* cq queue_addr */
+		ehca_dbg(cq->ib_cq.device, "cq_num=%x queue", cq->cq_number);
+		ret = ehca_mmap_queue(vma, &cq->ipz_queue, &cq->mm_count_queue);
+		if (unlikely(ret)) {
+			ehca_err(cq->ib_cq.device,
+				 "ehca_mmap_queue() failed rc=%x cq_num=%x",
+				 ret, cq->cq_number);
+			return ret;
 		}
 		break;
 
 	default:
-		ehca_gen_err("bad queue type %x", q_type);
-		return NOPAGE_SIGBUS;
+		ehca_err(cq->ib_cq.device, "bad resource type=%x cq_num=%x",
+			 rsrc_type, cq->cq_number);
+		return -EINVAL;
 	}
 
-	if (!mypage) {
-		ehca_gen_err("Invalid page adr==NULL ret=NOPAGE_SIGBUS");
-		return NOPAGE_SIGBUS;
-	}
-	get_page(mypage);
-
-	return mypage;
+	return 0;
 }
 
-static struct vm_operations_struct ehcau_vm_ops = {
-	.nopage = ehca_nopage,
-};
+static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
+			u32 rsrc_type)
+{
+	int ret;
+
+	switch (rsrc_type) {
+	case 1: /* galpa fw handle */
+		ehca_dbg(qp->ib_qp.device, "qp_num=%x fw", qp->ib_qp.qp_num);
+		ret = ehca_mmap_fw(vma, &qp->galpas, &qp->mm_count_galpa);
+		if (unlikely(ret)) {
+			ehca_err(qp->ib_qp.device,
+				 "remap_pfn_range() failed ret=%x qp_num=%x",
+				 ret, qp->ib_qp.qp_num);
+			return -ENOMEM;
+		}
+		break;
+
+	case 2: /* qp rqueue_addr */
+		ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue",
+			 qp->ib_qp.qp_num);
+		ret = ehca_mmap_queue(vma, &qp->ipz_rqueue, &qp->mm_count_rqueue);
+		if (unlikely(ret)) {
+			ehca_err(qp->ib_qp.device,
+				 "ehca_mmap_queue(rq) failed rc=%x qp_num=%x",
+				 ret, qp->ib_qp.qp_num);
+			return ret;
+		}
+		break;
+
+	case 3: /* qp squeue_addr */
+		ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue",
+			 qp->ib_qp.qp_num);
+		ret = ehca_mmap_queue(vma, &qp->ipz_squeue, &qp->mm_count_squeue);
+		if (unlikely(ret)) {
+			ehca_err(qp->ib_qp.device,
+				 "ehca_mmap_queue(sq) failed rc=%x qp_num=%x",
+				 ret, qp->ib_qp.qp_num);
+			return ret;
+		}
+		break;
+
+	default:
+		ehca_err(qp->ib_qp.device, "bad resource type=%x qp=num=%x",
+			 rsrc_type, qp->ib_qp.qp_num);
+		return -EINVAL;
+	}
+
+	return 0;
+}
 
 int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
 {
@@ -175,7 +253,6 @@
 	u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
 	u32 cur_pid = current->tgid;
 	u32 ret;
-	u64 vsize, physical;
 	unsigned long flags;
 	struct ehca_cq *cq;
 	struct ehca_qp *qp;
@@ -201,44 +278,12 @@
 		if (!cq->ib_cq.uobject || cq->ib_cq.uobject->context != context)
 			return -EINVAL;
 
-		switch (rsrc_type) {
-		case 1: /* galpa fw handle */
-			ehca_dbg(cq->ib_cq.device, "cq=%p cq triggerarea", cq);
-			vma->vm_flags |= VM_RESERVED;
-			vsize = vma->vm_end - vma->vm_start;
-			if (vsize != EHCA_PAGESIZE) {
-				ehca_err(cq->ib_cq.device, "invalid vsize=%lx",
-					 vma->vm_end - vma->vm_start);
-				return -EINVAL;
-			}
-
-			physical = cq->galpas.user.fw_handle;
-			vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-			vma->vm_flags |= VM_IO | VM_RESERVED;
-
-			ehca_dbg(cq->ib_cq.device,
-				 "vsize=%lx physical=%lx", vsize, physical);
-			ret = remap_pfn_range(vma, vma->vm_start,
-					      physical >> PAGE_SHIFT, vsize,
-					      vma->vm_page_prot);
-			if (ret) {
-				ehca_err(cq->ib_cq.device,
-					 "remap_pfn_range() failed ret=%x",
-					 ret);
-				return -ENOMEM;
-			}
-			break;
-
-		case 2: /* cq queue_addr */
-			ehca_dbg(cq->ib_cq.device, "cq=%p cq q_addr", cq);
-			vma->vm_flags |= VM_RESERVED;
-			vma->vm_ops = &ehcau_vm_ops;
-			break;
-
-		default:
-			ehca_err(cq->ib_cq.device, "bad resource type %x",
-				 rsrc_type);
-			return -EINVAL;
+		ret = ehca_mmap_cq(vma, cq, rsrc_type);
+		if (unlikely(ret)) {
+			ehca_err(cq->ib_cq.device,
+				 "ehca_mmap_cq() failed rc=%x cq_num=%x",
+				 ret, cq->cq_number);
+			return ret;
 		}
 		break;
 
@@ -262,50 +307,12 @@
 		if (!qp->ib_qp.uobject || qp->ib_qp.uobject->context != context)
 			return -EINVAL;
 
-		switch (rsrc_type) {
-		case 1: /* galpa fw handle */
-			ehca_dbg(qp->ib_qp.device, "qp=%p qp triggerarea", qp);
-			vma->vm_flags |= VM_RESERVED;
-			vsize = vma->vm_end - vma->vm_start;
-			if (vsize != EHCA_PAGESIZE) {
-				ehca_err(qp->ib_qp.device, "invalid vsize=%lx",
-					 vma->vm_end - vma->vm_start);
-				return -EINVAL;
-			}
-
-			physical = qp->galpas.user.fw_handle;
-			vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-			vma->vm_flags |= VM_IO | VM_RESERVED;
-
-			ehca_dbg(qp->ib_qp.device, "vsize=%lx physical=%lx",
-				 vsize, physical);
-			ret = remap_pfn_range(vma, vma->vm_start,
-					      physical >> PAGE_SHIFT, vsize,
-					      vma->vm_page_prot);
-			if (ret) {
-				ehca_err(qp->ib_qp.device,
-					 "remap_pfn_range() failed ret=%x",
-					 ret);
-				return -ENOMEM;
-			}
-			break;
-
-		case 2: /* qp rqueue_addr */
-			ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueue_addr", qp);
-			vma->vm_flags |= VM_RESERVED;
-			vma->vm_ops = &ehcau_vm_ops;
-			break;
-
-		case 3: /* qp squeue_addr */
-			ehca_dbg(qp->ib_qp.device, "qp=%p qp squeue_addr", qp);
-			vma->vm_flags |= VM_RESERVED;
-			vma->vm_ops = &ehcau_vm_ops;
-			break;
-
-		default:
-			ehca_err(qp->ib_qp.device, "bad resource type %x",
-				 rsrc_type);
-			return -EINVAL;
+		ret = ehca_mmap_qp(vma, qp, rsrc_type);
+		if (unlikely(ret)) {
+			ehca_err(qp->ib_qp.device,
+				 "ehca_mmap_qp() failed rc=%x qp_num=%x",
+				 ret, qp->ib_qp.qp_num);
+			return ret;
 		}
 		break;
 
@@ -316,77 +323,3 @@
 
 	return 0;
 }
-
-int ehca_mmap_nopage(u64 foffset, u64 length, void **mapped,
-		     struct vm_area_struct **vma)
-{
-	down_write(&current->mm->mmap_sem);
-	*mapped = (void*)do_mmap(NULL,0, length, PROT_WRITE,
-				 MAP_SHARED | MAP_ANONYMOUS,
-				 foffset);
-	up_write(&current->mm->mmap_sem);
-	if (!(*mapped)) {
-		ehca_gen_err("couldn't mmap foffset=%lx length=%lx",
-			     foffset, length);
-		return -EINVAL;
-	}
-
-	*vma = find_vma(current->mm, (u64)*mapped);
-	if (!(*vma)) {
-		down_write(&current->mm->mmap_sem);
-		do_munmap(current->mm, 0, length);
-		up_write(&current->mm->mmap_sem);
-		ehca_gen_err("couldn't find vma queue=%p", *mapped);
-		return -EINVAL;
-	}
-	(*vma)->vm_flags |= VM_RESERVED;
-	(*vma)->vm_ops = &ehcau_vm_ops;
-
-	return 0;
-}
-
-int ehca_mmap_register(u64 physical, void **mapped,
-		       struct vm_area_struct **vma)
-{
-	int ret;
-	unsigned long vsize;
-	/* ehca hw supports only 4k page */
-	ret = ehca_mmap_nopage(0, EHCA_PAGESIZE, mapped, vma);
-	if (ret) {
-		ehca_gen_err("could'nt mmap physical=%lx", physical);
-		return ret;
-	}
-
-	(*vma)->vm_flags |= VM_RESERVED;
-	vsize = (*vma)->vm_end - (*vma)->vm_start;
-	if (vsize != EHCA_PAGESIZE) {
-		ehca_gen_err("invalid vsize=%lx",
-			     (*vma)->vm_end - (*vma)->vm_start);
-		return -EINVAL;
-	}
-
-	(*vma)->vm_page_prot = pgprot_noncached((*vma)->vm_page_prot);
-	(*vma)->vm_flags |= VM_IO | VM_RESERVED;
-
-	ret = remap_pfn_range((*vma), (*vma)->vm_start,
-			      physical >> PAGE_SHIFT, vsize,
-			      (*vma)->vm_page_prot);
-	if (ret) {
-		ehca_gen_err("remap_pfn_range() failed ret=%x", ret);
-		return -ENOMEM;
-	}
-
-	return 0;
-
-}
-
-int ehca_munmap(unsigned long addr, size_t len) {
-	int ret = 0;
-	struct mm_struct *mm = current->mm;
-	if (mm) {
-		down_write(&mm->mmap_sem);
-		ret = do_munmap(mm, addr, len);
-		up_write(&mm->mmap_sem);
-	}
-	return ret;
-}
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
index 46c1c89..64f07b1 100644
--- a/drivers/infiniband/hw/ipath/ipath_qp.c
+++ b/drivers/infiniband/hw/ipath/ipath_qp.c
@@ -379,7 +379,7 @@
 	wc.vendor_err = 0;
 	wc.byte_len = 0;
 	wc.imm_data = 0;
-	wc.qp_num = qp->ibqp.qp_num;
+	wc.qp = &qp->ibqp;
 	wc.src_qp = 0;
 	wc.wc_flags = 0;
 	wc.pkey_index = 0;
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index ce60387..5ff20cb 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -702,7 +702,7 @@
 		wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
 		wc->vendor_err = 0;
 		wc->byte_len = 0;
-		wc->qp_num = qp->ibqp.qp_num;
+		wc->qp = &qp->ibqp;
 		wc->src_qp = qp->remote_qpn;
 		wc->pkey_index = 0;
 		wc->slid = qp->remote_ah_attr.dlid;
@@ -836,7 +836,7 @@
 			wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
 			wc.vendor_err = 0;
 			wc.byte_len = wqe->length;
-			wc.qp_num = qp->ibqp.qp_num;
+			wc.qp = &qp->ibqp;
 			wc.src_qp = qp->remote_qpn;
 			wc.pkey_index = 0;
 			wc.slid = qp->remote_ah_attr.dlid;
@@ -951,7 +951,7 @@
 			wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
 			wc.vendor_err = 0;
 			wc.byte_len = 0;
-			wc.qp_num = qp->ibqp.qp_num;
+			wc.qp = &qp->ibqp;
 			wc.src_qp = qp->remote_qpn;
 			wc.pkey_index = 0;
 			wc.slid = qp->remote_ah_attr.dlid;
@@ -1511,7 +1511,7 @@
 		wc.status = IB_WC_SUCCESS;
 		wc.opcode = IB_WC_RECV;
 		wc.vendor_err = 0;
-		wc.qp_num = qp->ibqp.qp_num;
+		wc.qp = &qp->ibqp;
 		wc.src_qp = qp->remote_qpn;
 		wc.pkey_index = 0;
 		wc.slid = qp->remote_ah_attr.dlid;
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index f753051..e86cb17 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -137,7 +137,7 @@
 	wc.vendor_err = 0;
 	wc.byte_len = 0;
 	wc.imm_data = 0;
-	wc.qp_num = qp->ibqp.qp_num;
+	wc.qp = &qp->ibqp;
 	wc.src_qp = 0;
 	wc.wc_flags = 0;
 	wc.pkey_index = 0;
@@ -336,7 +336,7 @@
 			wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
 			wc.vendor_err = 0;
 			wc.byte_len = 0;
-			wc.qp_num = sqp->ibqp.qp_num;
+			wc.qp = &sqp->ibqp;
 			wc.src_qp = sqp->remote_qpn;
 			wc.pkey_index = 0;
 			wc.slid = sqp->remote_ah_attr.dlid;
@@ -426,7 +426,7 @@
 	wc.status = IB_WC_SUCCESS;
 	wc.vendor_err = 0;
 	wc.byte_len = wqe->length;
-	wc.qp_num = qp->ibqp.qp_num;
+	wc.qp = &qp->ibqp;
 	wc.src_qp = qp->remote_qpn;
 	/* XXX do we know which pkey matched? Only needed for GSI. */
 	wc.pkey_index = 0;
@@ -447,7 +447,7 @@
 		wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
 		wc.vendor_err = 0;
 		wc.byte_len = wqe->length;
-		wc.qp_num = sqp->ibqp.qp_num;
+		wc.qp = &sqp->ibqp;
 		wc.src_qp = 0;
 		wc.pkey_index = 0;
 		wc.slid = 0;
diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c
index e636cfd..325d663 100644
--- a/drivers/infiniband/hw/ipath/ipath_uc.c
+++ b/drivers/infiniband/hw/ipath/ipath_uc.c
@@ -49,7 +49,7 @@
 		wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
 		wc->vendor_err = 0;
 		wc->byte_len = wqe->length;
-		wc->qp_num = qp->ibqp.qp_num;
+		wc->qp = &qp->ibqp;
 		wc->src_qp = qp->remote_qpn;
 		wc->pkey_index = 0;
 		wc->slid = qp->remote_ah_attr.dlid;
@@ -411,7 +411,7 @@
 		wc.status = IB_WC_SUCCESS;
 		wc.opcode = IB_WC_RECV;
 		wc.vendor_err = 0;
-		wc.qp_num = qp->ibqp.qp_num;
+		wc.qp = &qp->ibqp;
 		wc.src_qp = qp->remote_qpn;
 		wc.pkey_index = 0;
 		wc.slid = qp->remote_ah_attr.dlid;
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
index 49f1102..9a3e546 100644
--- a/drivers/infiniband/hw/ipath/ipath_ud.c
+++ b/drivers/infiniband/hw/ipath/ipath_ud.c
@@ -66,7 +66,7 @@
 	wc.vendor_err = 0;
 	wc.byte_len = 0;
 	wc.imm_data = 0;
-	wc.qp_num = qp->ibqp.qp_num;
+	wc.qp = &qp->ibqp;
 	wc.src_qp = 0;
 	wc.wc_flags = 0;
 	wc.pkey_index = 0;
@@ -255,7 +255,7 @@
 	wc->status = IB_WC_SUCCESS;
 	wc->opcode = IB_WC_RECV;
 	wc->vendor_err = 0;
-	wc->qp_num = qp->ibqp.qp_num;
+	wc->qp = &qp->ibqp;
 	wc->src_qp = sqp->ibqp.qp_num;
 	/* XXX do we know which pkey matched? Only needed for GSI. */
 	wc->pkey_index = 0;
@@ -474,7 +474,7 @@
 		wc.vendor_err = 0;
 		wc.opcode = IB_WC_SEND;
 		wc.byte_len = len;
-		wc.qp_num = qp->ibqp.qp_num;
+		wc.qp = &qp->ibqp;
 		wc.src_qp = 0;
 		wc.wc_flags = 0;
 		/* XXX initialize other fields? */
@@ -651,7 +651,7 @@
 	wc.status = IB_WC_SUCCESS;
 	wc.opcode = IB_WC_RECV;
 	wc.vendor_err = 0;
-	wc.qp_num = qp->ibqp.qp_num;
+	wc.qp = &qp->ibqp;
 	wc.src_qp = src_qp;
 	/* XXX do we know which pkey matched? Only needed for GSI. */
 	wc.pkey_index = 0;
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index 768df72..968d151 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -1854,7 +1854,7 @@
 
 		memset(inbox + 256, 0, 256);
 
-		MTHCA_PUT(inbox, in_wc->qp_num,     MAD_IFC_MY_QPN_OFFSET);
+		MTHCA_PUT(inbox, in_wc->qp->qp_num, MAD_IFC_MY_QPN_OFFSET);
 		MTHCA_PUT(inbox, in_wc->src_qp,     MAD_IFC_RQPN_OFFSET);
 
 		val = in_wc->sl << 4;
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index 1159c8a..efd79ef 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -534,7 +534,7 @@
 		}
 	}
 
-	entry->qp_num = (*cur_qp)->qpn;
+	entry->qp = &(*cur_qp)->ibqp;
 
 	if (is_send) {
 		wq = &(*cur_qp)->sq;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 705eb1d..af5ee2e 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -958,16 +958,17 @@
 	return netdev_priv(dev);
 }
 
-static ssize_t show_pkey(struct class_device *cdev, char *buf)
+static ssize_t show_pkey(struct device *dev,
+			 struct device_attribute *attr, char *buf)
 {
-	struct ipoib_dev_priv *priv =
-		netdev_priv(container_of(cdev, struct net_device, class_dev));
+	struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev));
 
 	return sprintf(buf, "0x%04x\n", priv->pkey);
 }
-static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
+static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
 
-static ssize_t create_child(struct class_device *cdev,
+static ssize_t create_child(struct device *dev,
+			    struct device_attribute *attr,
 			    const char *buf, size_t count)
 {
 	int pkey;
@@ -985,14 +986,14 @@
 	 */
 	pkey |= 0x8000;
 
-	ret = ipoib_vlan_add(container_of(cdev, struct net_device, class_dev),
-			     pkey);
+	ret = ipoib_vlan_add(to_net_dev(dev), pkey);
 
 	return ret ? ret : count;
 }
-static CLASS_DEVICE_ATTR(create_child, S_IWUGO, NULL, create_child);
+static DEVICE_ATTR(create_child, S_IWUGO, NULL, create_child);
 
-static ssize_t delete_child(struct class_device *cdev,
+static ssize_t delete_child(struct device *dev,
+			    struct device_attribute *attr,
 			    const char *buf, size_t count)
 {
 	int pkey;
@@ -1004,18 +1005,16 @@
 	if (pkey < 0 || pkey > 0xffff)
 		return -EINVAL;
 
-	ret = ipoib_vlan_delete(container_of(cdev, struct net_device, class_dev),
-				pkey);
+	ret = ipoib_vlan_delete(to_net_dev(dev), pkey);
 
 	return ret ? ret : count;
 
 }
-static CLASS_DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child);
+static DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child);
 
 int ipoib_add_pkey_attr(struct net_device *dev)
 {
-	return class_device_create_file(&dev->class_dev,
-					&class_device_attr_pkey);
+	return device_create_file(&dev->dev, &dev_attr_pkey);
 }
 
 static struct net_device *ipoib_add_port(const char *format,
@@ -1083,11 +1082,9 @@
 
 	if (ipoib_add_pkey_attr(priv->dev))
 		goto sysfs_failed;
-	if (class_device_create_file(&priv->dev->class_dev,
-				     &class_device_attr_create_child))
+	if (device_create_file(&priv->dev->dev, &dev_attr_create_child))
 		goto sysfs_failed;
-	if (class_device_create_file(&priv->dev->class_dev,
-				     &class_device_attr_delete_child))
+	if (device_create_file(&priv->dev->dev, &dev_attr_delete_child))
 		goto sysfs_failed;
 
 	return priv->dev;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index f887780..085eafe 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -42,15 +42,15 @@
 
 #include "ipoib.h"
 
-static ssize_t show_parent(struct class_device *class_dev, char *buf)
+static ssize_t show_parent(struct device *d, struct device_attribute *attr,
+			   char *buf)
 {
-	struct net_device *dev =
-		container_of(class_dev, struct net_device, class_dev);
+	struct net_device *dev = to_net_dev(d);
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 
 	return sprintf(buf, "%s\n", priv->parent->name);
 }
-static CLASS_DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL);
+static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL);
 
 int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
 {
@@ -118,8 +118,7 @@
 	if (ipoib_add_pkey_attr(priv->dev))
 		goto sysfs_failed;
 
-	if (class_device_create_file(&priv->dev->class_dev,
-				     &class_device_attr_parent))
+	if (device_create_file(&priv->dev->dev, &dev_attr_parent))
 		goto sysfs_failed;
 
 	list_add_tail(&priv->list, &ppriv->child_intfs);
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 0a7d1ab..89e3728 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -567,7 +567,7 @@
 	opcode = hdr->opcode & ISCSI_OPCODE_MASK;
 
 	if (opcode == ISCSI_OP_SCSI_CMD_RSP) {
-	        itt = hdr->itt & ISCSI_ITT_MASK; /* mask out cid and age bits */
+	        itt = get_itt(hdr->itt); /* mask out cid and age bits */
 		if (!(itt < session->cmds_max))
 			iser_err("itt can't be matched to task!!!"
 				 "conn %p opcode %d cmds_max %d itt %d\n",
@@ -625,7 +625,7 @@
 		/* this arithmetic is legal by libiscsi dd_data allocation */
 		mtask = (void *) ((long)(void *)tx_desc -
 				  sizeof(struct iscsi_mgmt_task));
-		if (mtask->hdr->itt == cpu_to_be32(ISCSI_RESERVED_TAG)) {
+		if (mtask->hdr->itt == RESERVED_ITT) {
 			struct iscsi_session *session = conn->session;
 
 			spin_lock(&conn->session->lock);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 72611fd..5e8ac57 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -548,6 +548,7 @@
 	target->tx_head	 = 0;
 	target->tx_tail  = 0;
 
+	target->qp_in_error = 0;
 	ret = srp_connect_target(target);
 	if (ret)
 		goto err;
@@ -878,6 +879,7 @@
 			printk(KERN_ERR PFX "failed %s status %d\n",
 			       wc.wr_id & SRP_OP_RECV ? "receive" : "send",
 			       wc.status);
+			target->qp_in_error = 1;
 			break;
 		}
 
@@ -1337,6 +1339,8 @@
 
 	printk(KERN_ERR "SRP abort called\n");
 
+	if (target->qp_in_error)
+		return FAILED;
 	if (srp_find_req(target, scmnd, &req))
 		return FAILED;
 	if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK))
@@ -1365,6 +1369,8 @@
 
 	printk(KERN_ERR "SRP reset_device called\n");
 
+	if (target->qp_in_error)
+		return FAILED;
 	if (srp_find_req(target, scmnd, &req))
 		return FAILED;
 	if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET))
@@ -1801,6 +1807,7 @@
 		goto err_free;
 	}
 
+	target->qp_in_error = 0;
 	ret = srp_connect_target(target);
 	if (ret) {
 		printk(KERN_ERR PFX "Connection failed\n");
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index c217723..2f3319c 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -158,6 +158,7 @@
 	struct completion	done;
 	int			status;
 	enum srp_target_state	state;
+	int			qp_in_error;
 };
 
 struct srp_iu {
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index f0ce822..17c8c63 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -45,7 +45,7 @@
 EXPORT_SYMBOL(__serio_register_port);
 EXPORT_SYMBOL(serio_unregister_port);
 EXPORT_SYMBOL(serio_unregister_child_port);
-EXPORT_SYMBOL(serio_register_driver);
+EXPORT_SYMBOL(__serio_register_driver);
 EXPORT_SYMBOL(serio_unregister_driver);
 EXPORT_SYMBOL(serio_open);
 EXPORT_SYMBOL(serio_close);
@@ -789,12 +789,14 @@
 			drv->driver.name, error);
 }
 
-int serio_register_driver(struct serio_driver *drv)
+int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name)
 {
 	int manual_bind = drv->manual_bind;
 	int error;
 
 	drv->driver.bus = &serio_bus;
+	drv->driver.owner = owner;
+	drv->driver.mod_name = mod_name;
 
 	/*
 	 * Temporarily disable automatic binding because probing
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c
index 4358a0a..c7db403 100644
--- a/drivers/input/touchscreen/ucb1400_ts.c
+++ b/drivers/input/touchscreen/ucb1400_ts.c
@@ -83,7 +83,7 @@
 
 
 struct ucb1400 {
-	ac97_t			*ac97;
+	struct snd_ac97		*ac97;
 	struct input_dev	*ts_idev;
 
 	int			irq;
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index b10972e..099f0af 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -62,7 +62,7 @@
 	{ "halt_exits", &kvm_stat.halt_exits },
 	{ "request_irq", &kvm_stat.request_irq_exits },
 	{ "irq_exits", &kvm_stat.irq_exits },
-	{ 0, 0 }
+	{ NULL, NULL }
 };
 
 static struct dentry *debugfs_dir;
@@ -205,7 +205,7 @@
 	mutex_lock(&vcpu->mutex);
 	if (unlikely(!vcpu->vmcs)) {
 		mutex_unlock(&vcpu->mutex);
-		return 0;
+		return NULL;
 	}
 	return kvm_arch_ops->vcpu_load(vcpu);
 }
@@ -257,9 +257,9 @@
 	if (!dont || free->dirty_bitmap != dont->dirty_bitmap)
 		vfree(free->dirty_bitmap);
 
-	free->phys_mem = 0;
+	free->phys_mem = NULL;
 	free->npages = 0;
-	free->dirty_bitmap = 0;
+	free->dirty_bitmap = NULL;
 }
 
 static void kvm_free_physmem(struct kvm *kvm)
@@ -267,7 +267,7 @@
 	int i;
 
 	for (i = 0; i < kvm->nmemslots; ++i)
-		kvm_free_physmem_slot(&kvm->memslots[i], 0);
+		kvm_free_physmem_slot(&kvm->memslots[i], NULL);
 }
 
 static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
@@ -640,11 +640,11 @@
 
 	/* Deallocate if slot is being removed */
 	if (!npages)
-		new.phys_mem = 0;
+		new.phys_mem = NULL;
 
 	/* Free page dirty bitmap if unneeded */
 	if (!(new.flags & KVM_MEM_LOG_DIRTY_PAGES))
-		new.dirty_bitmap = 0;
+		new.dirty_bitmap = NULL;
 
 	r = -ENOMEM;
 
@@ -799,14 +799,14 @@
 		    && gfn < memslot->base_gfn + memslot->npages)
 			return memslot;
 	}
-	return 0;
+	return NULL;
 }
 EXPORT_SYMBOL_GPL(gfn_to_memslot);
 
 void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
 {
 	int i;
-	struct kvm_memory_slot *memslot = 0;
+	struct kvm_memory_slot *memslot = NULL;
 	unsigned long rel_gfn;
 
 	for (i = 0; i < kvm->nmemslots; ++i) {
@@ -1778,6 +1778,7 @@
 			  unsigned int ioctl, unsigned long arg)
 {
 	struct kvm *kvm = filp->private_data;
+	void __user *argp = (void __user *)arg;
 	int r = -EINVAL;
 
 	switch (ioctl) {
@@ -1794,12 +1795,12 @@
 		struct kvm_run kvm_run;
 
 		r = -EFAULT;
-		if (copy_from_user(&kvm_run, (void *)arg, sizeof kvm_run))
+		if (copy_from_user(&kvm_run, argp, sizeof kvm_run))
 			goto out;
 		r = kvm_dev_ioctl_run(kvm, &kvm_run);
 		if (r < 0 &&  r != -EINTR)
 			goto out;
-		if (copy_to_user((void *)arg, &kvm_run, sizeof kvm_run)) {
+		if (copy_to_user(argp, &kvm_run, sizeof kvm_run)) {
 			r = -EFAULT;
 			goto out;
 		}
@@ -1809,13 +1810,13 @@
 		struct kvm_regs kvm_regs;
 
 		r = -EFAULT;
-		if (copy_from_user(&kvm_regs, (void *)arg, sizeof kvm_regs))
+		if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs))
 			goto out;
 		r = kvm_dev_ioctl_get_regs(kvm, &kvm_regs);
 		if (r)
 			goto out;
 		r = -EFAULT;
-		if (copy_to_user((void *)arg, &kvm_regs, sizeof kvm_regs))
+		if (copy_to_user(argp, &kvm_regs, sizeof kvm_regs))
 			goto out;
 		r = 0;
 		break;
@@ -1824,7 +1825,7 @@
 		struct kvm_regs kvm_regs;
 
 		r = -EFAULT;
-		if (copy_from_user(&kvm_regs, (void *)arg, sizeof kvm_regs))
+		if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs))
 			goto out;
 		r = kvm_dev_ioctl_set_regs(kvm, &kvm_regs);
 		if (r)
@@ -1836,13 +1837,13 @@
 		struct kvm_sregs kvm_sregs;
 
 		r = -EFAULT;
-		if (copy_from_user(&kvm_sregs, (void *)arg, sizeof kvm_sregs))
+		if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs))
 			goto out;
 		r = kvm_dev_ioctl_get_sregs(kvm, &kvm_sregs);
 		if (r)
 			goto out;
 		r = -EFAULT;
-		if (copy_to_user((void *)arg, &kvm_sregs, sizeof kvm_sregs))
+		if (copy_to_user(argp, &kvm_sregs, sizeof kvm_sregs))
 			goto out;
 		r = 0;
 		break;
@@ -1851,7 +1852,7 @@
 		struct kvm_sregs kvm_sregs;
 
 		r = -EFAULT;
-		if (copy_from_user(&kvm_sregs, (void *)arg, sizeof kvm_sregs))
+		if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs))
 			goto out;
 		r = kvm_dev_ioctl_set_sregs(kvm, &kvm_sregs);
 		if (r)
@@ -1863,13 +1864,13 @@
 		struct kvm_translation tr;
 
 		r = -EFAULT;
-		if (copy_from_user(&tr, (void *)arg, sizeof tr))
+		if (copy_from_user(&tr, argp, sizeof tr))
 			goto out;
 		r = kvm_dev_ioctl_translate(kvm, &tr);
 		if (r)
 			goto out;
 		r = -EFAULT;
-		if (copy_to_user((void *)arg, &tr, sizeof tr))
+		if (copy_to_user(argp, &tr, sizeof tr))
 			goto out;
 		r = 0;
 		break;
@@ -1878,7 +1879,7 @@
 		struct kvm_interrupt irq;
 
 		r = -EFAULT;
-		if (copy_from_user(&irq, (void *)arg, sizeof irq))
+		if (copy_from_user(&irq, argp, sizeof irq))
 			goto out;
 		r = kvm_dev_ioctl_interrupt(kvm, &irq);
 		if (r)
@@ -1890,7 +1891,7 @@
 		struct kvm_debug_guest dbg;
 
 		r = -EFAULT;
-		if (copy_from_user(&dbg, (void *)arg, sizeof dbg))
+		if (copy_from_user(&dbg, argp, sizeof dbg))
 			goto out;
 		r = kvm_dev_ioctl_debug_guest(kvm, &dbg);
 		if (r)
@@ -1902,7 +1903,7 @@
 		struct kvm_memory_region kvm_mem;
 
 		r = -EFAULT;
-		if (copy_from_user(&kvm_mem, (void *)arg, sizeof kvm_mem))
+		if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem))
 			goto out;
 		r = kvm_dev_ioctl_set_memory_region(kvm, &kvm_mem);
 		if (r)
@@ -1913,7 +1914,7 @@
 		struct kvm_dirty_log log;
 
 		r = -EFAULT;
-		if (copy_from_user(&log, (void *)arg, sizeof log))
+		if (copy_from_user(&log, argp, sizeof log))
 			goto out;
 		r = kvm_dev_ioctl_get_dirty_log(kvm, &log);
 		if (r)
@@ -1921,13 +1922,13 @@
 		break;
 	}
 	case KVM_GET_MSRS:
-		r = msr_io(kvm, (void __user *)arg, get_msr, 1);
+		r = msr_io(kvm, argp, get_msr, 1);
 		break;
 	case KVM_SET_MSRS:
-		r = msr_io(kvm, (void __user *)arg, do_set_msr, 0);
+		r = msr_io(kvm, argp, do_set_msr, 0);
 		break;
 	case KVM_GET_MSR_INDEX_LIST: {
-		struct kvm_msr_list __user *user_msr_list = (void __user *)arg;
+		struct kvm_msr_list __user *user_msr_list = argp;
 		struct kvm_msr_list msr_list;
 		unsigned n;
 
@@ -2014,7 +2015,7 @@
 		 * in vmx root mode.
 		 */
 		printk(KERN_INFO "kvm: exiting hardware virtualization\n");
-		on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1);
+		on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
 	}
 	return NOTIFY_OK;
 }
@@ -2028,7 +2029,7 @@
 {
 	struct kvm_stats_debugfs_item *p;
 
-	debugfs_dir = debugfs_create_dir("kvm", 0);
+	debugfs_dir = debugfs_create_dir("kvm", NULL);
 	for (p = debugfs_entries; p->name; ++p)
 		p->dentry = debugfs_create_u32(p->name, 0444, debugfs_dir,
 					       p->data);
@@ -2069,7 +2070,7 @@
 	if (r < 0)
 	    return r;
 
-	on_each_cpu(kvm_arch_ops->hardware_enable, 0, 0, 1);
+	on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1);
 	register_reboot_notifier(&kvm_reboot_notifier);
 
 	kvm_chardev_ops.owner = module;
@@ -2084,7 +2085,7 @@
 
 out_free:
 	unregister_reboot_notifier(&kvm_reboot_notifier);
-	on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1);
+	on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
 	kvm_arch_ops->hardware_unsetup();
 	return r;
 }
@@ -2094,7 +2095,7 @@
 	misc_deregister(&kvm_dev);
 
 	unregister_reboot_notifier(&kvm_reboot_notifier);
-	on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1);
+	on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
 	kvm_arch_ops->hardware_unsetup();
 	kvm_arch_ops = NULL;
 }
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index 22c426c..be79377 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -333,7 +333,7 @@
 	for (j = RMAP_EXT - 1; !desc->shadow_ptes[j] && j > i; --j)
 		;
 	desc->shadow_ptes[i] = desc->shadow_ptes[j];
-	desc->shadow_ptes[j] = 0;
+	desc->shadow_ptes[j] = NULL;
 	if (j != 0)
 		return;
 	if (!prev_desc && !desc->more)
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index c79df79..85f61dd 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -274,7 +274,7 @@
 		wrmsrl(MSR_VM_HSAVE_PA, 0);
 		rdmsrl(MSR_EFER, efer);
 		wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK);
-		per_cpu(svm_data, raw_smp_processor_id()) = 0;
+		per_cpu(svm_data, raw_smp_processor_id()) = NULL;
 		__free_page(svm_data->save_area);
 		kfree(svm_data);
 	}
@@ -642,7 +642,7 @@
 	case VCPU_SREG_LDTR: return &save->ldtr;
 	}
 	BUG();
-	return 0;
+	return NULL;
 }
 
 static u64 svm_get_segment_base(struct kvm_vcpu *vcpu, int seg)
@@ -934,7 +934,7 @@
 		return 0;
 
 	*addr_override = 0;
-	*seg = 0;
+	*seg = NULL;
 	for (i = 0; i < ins_length; i++)
 		switch (inst[i]) {
 		case 0xf0:
@@ -1087,7 +1087,7 @@
 
 static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
-	if (emulate_instruction(vcpu, 0, 0, 0) != EMULATE_DONE)
+	if (emulate_instruction(vcpu, NULL, 0, 0) != EMULATE_DONE)
 		printk(KERN_ERR "%s: failed\n", __FUNCTION__);
 	return 1;
 }
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index 54c35c0..27e05a7 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -98,7 +98,7 @@
 	for (i = 0; i < vcpu->nmsrs; ++i)
 		if (vcpu->guest_msrs[i].index == msr)
 			return &vcpu->guest_msrs[i];
-	return 0;
+	return NULL;
 }
 
 static void vmcs_clear(struct vmcs *vmcs)
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index a9e747c..1a86387 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -1,6 +1,6 @@
 
 menu "Macintosh device drivers"
-	depends on PPC || MAC
+	depends on PPC || MAC || X86
 
 config ADB
 	bool "Apple Desktop Bus (ADB) support"
diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c
index 5ed41fe..f83fad2 100644
--- a/drivers/macintosh/rack-meter.c
+++ b/drivers/macintosh/rack-meter.c
@@ -171,11 +171,11 @@
 	/* Make sure dbdma is reset */
 	DBDMA_DO_RESET(rm->dma_regs);
 
-	pr_debug("rackmeter: mark offset=0x%lx\n",
+	pr_debug("rackmeter: mark offset=0x%zx\n",
 		 offsetof(struct rackmeter_dma, mark));
-	pr_debug("rackmeter: buf1 offset=0x%lx\n",
+	pr_debug("rackmeter: buf1 offset=0x%zx\n",
 		 offsetof(struct rackmeter_dma, buf1));
-	pr_debug("rackmeter: buf2 offset=0x%lx\n",
+	pr_debug("rackmeter: buf2 offset=0x%zx\n",
 		 offsetof(struct rackmeter_dma, buf2));
 
 	/* Prepare 4 dbdma commands for the 2 buffers */
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index e947af9..94c117e 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -94,8 +94,6 @@
 	DBG("wf: thread started\n");
 
 	while(!kthread_should_stop()) {
-		try_to_freeze();
-
 		if (time_after_eq(jiffies, next)) {
 			wf_notify(WF_EVENT_TICK, NULL);
 			if (wf_overtemp) {
@@ -118,8 +116,8 @@
 		if (delay <= HZ)
 			schedule_timeout_interruptible(delay);
 
-		/* there should be no signal, but oh well */
-		if (signal_pending(current)) {
+		/* there should be no non-suspend signal, but oh well */
+		if (signal_pending(current) && !try_to_freeze()) {
 			printk(KERN_WARNING "windfarm: thread got sigl !\n");
 			break;
 		}
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 1110816..059704f 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -1160,6 +1160,22 @@
 			return 0;
 		}
 
+		if (unlikely((*bmc & COUNTER_MAX) == COUNTER_MAX)) {
+			DEFINE_WAIT(__wait);
+			/* note that it is safe to do the prepare_to_wait
+			 * after the test as long as we do it before dropping
+			 * the spinlock.
+			 */
+			prepare_to_wait(&bitmap->overflow_wait, &__wait,
+					TASK_UNINTERRUPTIBLE);
+			spin_unlock_irq(&bitmap->lock);
+			bitmap->mddev->queue
+				->unplug_fn(bitmap->mddev->queue);
+			schedule();
+			finish_wait(&bitmap->overflow_wait, &__wait);
+			continue;
+		}
+
 		switch(*bmc) {
 		case 0:
 			bitmap_file_set_bit(bitmap, offset);
@@ -1169,7 +1185,7 @@
 		case 1:
 			*bmc = 2;
 		}
-		BUG_ON((*bmc & COUNTER_MAX) == COUNTER_MAX);
+
 		(*bmc)++;
 
 		spin_unlock_irq(&bitmap->lock);
@@ -1207,6 +1223,9 @@
 		if (!success && ! (*bmc & NEEDED_MASK))
 			*bmc |= NEEDED_MASK;
 
+		if ((*bmc & COUNTER_MAX) == COUNTER_MAX)
+			wake_up(&bitmap->overflow_wait);
+
 		(*bmc)--;
 		if (*bmc <= 2) {
 			set_page_attr(bitmap,
@@ -1431,6 +1450,7 @@
 	spin_lock_init(&bitmap->lock);
 	atomic_set(&bitmap->pending_writes, 0);
 	init_waitqueue_head(&bitmap->write_wait);
+	init_waitqueue_head(&bitmap->overflow_wait);
 
 	bitmap->mddev = mddev;
 
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 467c169..11c3d7b 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -2620,7 +2620,7 @@
 	}
 	bi = conf->retry_read_aligned_list;
 	if(bi) {
-		conf->retry_read_aligned = bi->bi_next;
+		conf->retry_read_aligned_list = bi->bi_next;
 		bi->bi_next = NULL;
 		bi->bi_phys_segments = 1; /* biased count of active stripes */
 		bi->bi_hw_segments = 0; /* count of processed stripes */
@@ -2669,6 +2669,27 @@
 	return 0;
 }
 
+static int bio_fits_rdev(struct bio *bi)
+{
+	request_queue_t *q = bdev_get_queue(bi->bi_bdev);
+
+	if ((bi->bi_size>>9) > q->max_sectors)
+		return 0;
+	blk_recount_segments(q, bi);
+	if (bi->bi_phys_segments > q->max_phys_segments ||
+	    bi->bi_hw_segments > q->max_hw_segments)
+		return 0;
+
+	if (q->merge_bvec_fn)
+		/* it's too hard to apply the merge_bvec_fn at this stage,
+		 * just just give up
+		 */
+		return 0;
+
+	return 1;
+}
+
+
 static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio)
 {
 	mddev_t *mddev = q->queuedata;
@@ -2715,6 +2736,13 @@
 		align_bi->bi_flags &= ~(1 << BIO_SEG_VALID);
 		align_bi->bi_sector += rdev->data_offset;
 
+		if (!bio_fits_rdev(align_bi)) {
+			/* too big in some way */
+			bio_put(align_bi);
+			rdev_dec_pending(rdev, mddev);
+			return 0;
+		}
+
 		spin_lock_irq(&conf->device_lock);
 		wait_event_lock_irq(conf->wait_for_stripe,
 				    conf->quiesce == 0,
@@ -3107,7 +3135,9 @@
 	last_sector = raid_bio->bi_sector + (raid_bio->bi_size>>9);
 
 	for (; logical_sector < last_sector;
-	     logical_sector += STRIPE_SECTORS, scnt++) {
+	     logical_sector += STRIPE_SECTORS,
+		     sector += STRIPE_SECTORS,
+		     scnt++) {
 
 		if (scnt < raid_bio->bi_hw_segments)
 			/* already done this stripe */
@@ -3123,7 +3153,13 @@
 		}
 
 		set_bit(R5_ReadError, &sh->dev[dd_idx].flags);
-		add_stripe_bio(sh, raid_bio, dd_idx, 0);
+		if (!add_stripe_bio(sh, raid_bio, dd_idx, 0)) {
+			release_stripe(sh);
+			raid_bio->bi_hw_segments = scnt;
+			conf->retry_read_aligned = raid_bio;
+			return handled;
+		}
+
 		handle_stripe(sh, NULL);
 		release_stripe(sh);
 		handled++;
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index f51e02fe..0e948a5 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -698,7 +698,6 @@
 	[ 0x29 ] = KEY_TEXT,
 	[ 0x2a ] = KEY_MEDIA,
 	[ 0x18 ] = KEY_EPG,
-	[ 0x27 ] = KEY_RECORD,
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_pinnacle_grey);
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index 7243337..bdd6301 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -1072,7 +1072,7 @@
 }
 
 
-static ssize_t usbvision_v4l2_read(struct file *file, char *buf,
+static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
 		      size_t count, loff_t *ppos)
 {
 	struct video_device *dev = video_devdata(file);
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
index 4363a91..3daf049 100644
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ b/drivers/media/video/zc0301/zc0301_sensor.h
@@ -75,7 +75,6 @@
 	{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
 	{ ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */           \
 	{ ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */           \
-	{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
 	{ ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), },                         \
 	{ ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */    \
 	{ ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */           \
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 00db31c..bedae4a 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -42,7 +42,7 @@
 
 config TIFM_CORE
 	tristate "TI Flash Media interface support (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
+	depends on EXPERIMENTAL && PCI
 	help
 	  If you want support for Texas Instruments(R) Flash Media adapters
 	  you should select this option and then also choose an appropriate
@@ -69,6 +69,25 @@
           To compile this driver as a module, choose M here: the module will
 	  be called tifm_7xx1.
 
+config ASUS_LAPTOP
+        tristate "Asus Laptop Extras (EXPERIMENTAL)"
+        depends on X86
+        depends on ACPI
+	depends on EXPERIMENTAL && !ACPI_ASUS
+	depends on LEDS_CLASS
+	depends on BACKLIGHT_CLASS_DEVICE
+        ---help---
+	  This is the new Linux driver for Asus laptops. It may also support some
+	  MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate
+	  standard ACPI events that go through /proc/acpi/events. It also adds
+	  support for video output switching, LCD backlight control, Bluetooth and
+	  Wlan control, and most importantly, allows you to blink those fancy LEDs.
+
+	  For more information and a userspace daemon for handling the extra
+	  buttons see <http://acpi4asus.sf.net/>.
+
+	  If you have an ACPI-compatible ASUS laptop, say Y or M here.
+
 config MSI_LAPTOP
         tristate "MSI Laptop Extras"
         depends on X86
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c9e98ab..35da53c 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -6,6 +6,7 @@
 obj-$(CONFIG_IBM_ASM)		+= ibmasm/
 obj-$(CONFIG_HDPU_FEATURES)	+= hdpuftrs/
 obj-$(CONFIG_MSI_LAPTOP)     += msi-laptop.o
+obj-$(CONFIG_ASUS_LAPTOP)     += asus-laptop.o
 obj-$(CONFIG_LKDTM)		+= lkdtm.o
 obj-$(CONFIG_TIFM_CORE)       	+= tifm_core.o
 obj-$(CONFIG_TIFM_7XX1)       	+= tifm_7xx1.o
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
new file mode 100644
index 0000000..861c399
--- /dev/null
+++ b/drivers/misc/asus-laptop.c
@@ -0,0 +1,1165 @@
+/*
+ *  asus-laptop.c - Asus Laptop Support
+ *
+ *
+ *  Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
+ *  Copyright (C) 2006 Corentin Chary
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ *  The development page for this driver is located at
+ *  http://sourceforge.net/projects/acpi4asus/
+ *
+ *  Credits:
+ *  Pontus Fuchs   - Helper functions, cleanup
+ *  Johann Wiesner - Small compile fixes
+ *  John Belmonte  - ACPI code for Toshiba laptop was a good starting point.
+ *  Eric Burghard  - LED display support for W1N
+ *  Josh Green     - Light Sens support
+ *  Thomas Tuttle  - His first patch for led support was very helpfull
+ *
+ */
+
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/proc_fs.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_bus.h>
+#include <asm/uaccess.h>
+
+#define ASUS_LAPTOP_VERSION "0.40"
+
+#define ASUS_HOTK_NAME          "Asus Laptop Support"
+#define ASUS_HOTK_CLASS         "hotkey"
+#define ASUS_HOTK_DEVICE_NAME   "Hotkey"
+#define ASUS_HOTK_HID           "ATK0100"
+#define ASUS_HOTK_FILE          "asus-laptop"
+#define ASUS_HOTK_PREFIX        "\\_SB.ATKD."
+
+/*
+ * Some events we use, same for all Asus
+ */
+#define ATKD_BR_UP       0x10
+#define ATKD_BR_DOWN     0x20
+#define ATKD_LCD_ON      0x33
+#define ATKD_LCD_OFF     0x34
+
+/*
+ * Known bits returned by \_SB.ATKD.HWRS
+ */
+#define WL_HWRS     0x80
+#define BT_HWRS     0x100
+
+/*
+ * Flags for hotk status
+ * WL_ON and BT_ON are also used for wireless_status()
+ */
+#define WL_ON       0x01	//internal Wifi
+#define BT_ON       0x02	//internal Bluetooth
+#define MLED_ON     0x04	//mail LED
+#define TLED_ON     0x08	//touchpad LED
+#define RLED_ON     0x10	//Record LED
+#define PLED_ON     0x20	//Phone LED
+#define LCD_ON      0x40	//LCD backlight
+
+#define ASUS_LOG    ASUS_HOTK_FILE ": "
+#define ASUS_ERR    KERN_ERR    ASUS_LOG
+#define ASUS_WARNING    KERN_WARNING    ASUS_LOG
+#define ASUS_NOTICE KERN_NOTICE ASUS_LOG
+#define ASUS_INFO   KERN_INFO   ASUS_LOG
+#define ASUS_DEBUG  KERN_DEBUG  ASUS_LOG
+
+MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
+MODULE_DESCRIPTION(ASUS_HOTK_NAME);
+MODULE_LICENSE("GPL");
+
+#define ASUS_HANDLE(object, paths...)					\
+	static acpi_handle  object##_handle = NULL;			\
+	static char *object##_paths[] = { paths }
+
+/* LED */
+ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "MLED");
+ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED");
+ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED");	/* W1JC */
+ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED");	/* A7J */
+
+/* LEDD */
+ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM");
+
+/* Bluetooth and WLAN
+ * WLED and BLED are not handled like other XLED, because in some dsdt
+ * they also control the WLAN/Bluetooth device.
+ */
+ASUS_HANDLE(wl_switch, ASUS_HOTK_PREFIX "WLED");
+ASUS_HANDLE(bt_switch, ASUS_HOTK_PREFIX "BLED");
+ASUS_HANDLE(wireless_status, ASUS_HOTK_PREFIX "RSTS");	/* All new models */
+
+/* Brightness */
+ASUS_HANDLE(brightness_set, ASUS_HOTK_PREFIX "SPLV");
+ASUS_HANDLE(brightness_get, ASUS_HOTK_PREFIX "GPLV");
+
+/* Backlight */
+ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10",	/* All new models */
+	    "\\_SB.PCI0.ISA.EC0._Q10",	/* A1x */
+	    "\\_SB.PCI0.PX40.ECD0._Q10",	/* L3C */
+	    "\\_SB.PCI0.PX40.EC0.Q10",	/* M1A */
+	    "\\_SB.PCI0.LPCB.EC0._Q10",	/* P30 */
+	    "\\_SB.PCI0.PX40.Q10",	/* S1x */
+	    "\\Q10");		/* A2x, L2D, L3D, M2E */
+
+/* Display */
+ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP");
+ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD",	/*  A6B, A6K A6R A7D F3JM L4R M6R A3G
+							   M6A M6V VX-1 V6J V6V W3Z */
+	    "\\_SB.PCI0.P0P2.VGA.GETD",	/* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V
+					   S5A M5A z33A W1Jc W2V */
+	    "\\_SB.PCI0.P0P3.VGA.GETD",	/* A6V A6Q */
+	    "\\_SB.PCI0.P0PA.VGA.GETD",	/* A6T, A6M */
+	    "\\_SB.PCI0.PCI1.VGAC.NMAP",	/* L3C */
+	    "\\_SB.PCI0.VGA.GETD",	/* Z96F */
+	    "\\ACTD",		/* A2D */
+	    "\\ADVG",		/* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
+	    "\\DNXT",		/* P30 */
+	    "\\INFB",		/* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
+	    "\\SSTE");		/* A3F A6F A3N A3L M6N W3N W6A */
+
+ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC");	/* Z71A Z71V */
+ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL");	/* Z71A Z71V */
+
+/*
+ * This is the main structure, we can use it to store anything interesting
+ * about the hotk device
+ */
+struct asus_hotk {
+	char *name;		//laptop name
+	struct acpi_device *device;	//the device we are in
+	acpi_handle handle;	//the handle of the hotk device
+	char status;		//status of the hotk, for LEDs, ...
+	u32 ledd_status;	//status of the LED display
+	u8 light_level;		//light sensor level
+	u8 light_switch;	//light sensor switch value
+	u16 event_count[128];	//count for each event TODO make this better
+};
+
+/*
+ * This header is made available to allow proper configuration given model,
+ * revision number , ... this info cannot go in struct asus_hotk because it is
+ * available before the hotk
+ */
+static struct acpi_table_header *asus_info;
+
+/* The actual device the driver binds to */
+static struct asus_hotk *hotk;
+
+/*
+ * The hotkey driver declaration
+ */
+static int asus_hotk_add(struct acpi_device *device);
+static int asus_hotk_remove(struct acpi_device *device, int type);
+static struct acpi_driver asus_hotk_driver = {
+	.name = ASUS_HOTK_NAME,
+	.class = ASUS_HOTK_CLASS,
+	.ids = ASUS_HOTK_HID,
+	.ops = {
+		.add = asus_hotk_add,
+		.remove = asus_hotk_remove,
+		},
+};
+
+/* The backlight device /sys/class/backlight */
+static struct backlight_device *asus_backlight_device;
+
+/*
+ * The backlight class declaration
+ */
+static int read_brightness(struct backlight_device *bd);
+static int update_bl_status(struct backlight_device *bd);
+static struct backlight_properties asusbl_data = {
+	.owner = THIS_MODULE,
+	.get_brightness = read_brightness,
+	.update_status = update_bl_status,
+	.max_brightness = 15,
+};
+
+/* These functions actually update the LED's, and are called from a
+ * workqueue. By doing this as separate work rather than when the LED
+ * subsystem asks, we avoid messing with the Asus ACPI stuff during a
+ * potentially bad time, such as a timer interrupt. */
+static struct workqueue_struct *led_workqueue;
+
+#define ASUS_LED(object, ledname)					\
+	static void object##_led_set(struct led_classdev *led_cdev,	\
+				     enum led_brightness value);	\
+	static void object##_led_update(struct work_struct *ignored);	\
+	static int object##_led_wk;					\
+	DECLARE_WORK(object##_led_work, object##_led_update);		\
+	static struct led_classdev object##_led = {			\
+		.name           = "asus:" ledname,			\
+		.brightness_set = object##_led_set,			\
+	}
+
+ASUS_LED(mled, "mail");
+ASUS_LED(tled, "touchpad");
+ASUS_LED(rled, "record");
+ASUS_LED(pled, "phone");
+
+/*
+ * This function evaluates an ACPI method, given an int as parameter, the
+ * method is searched within the scope of the handle, can be NULL. The output
+ * of the method is written is output, which can also be NULL
+ *
+ * returns 1 if write is successful, 0 else.
+ */
+static int write_acpi_int(acpi_handle handle, const char *method, int val,
+			  struct acpi_buffer *output)
+{
+	struct acpi_object_list params;	//list of input parameters (an int here)
+	union acpi_object in_obj;	//the only param we use
+	acpi_status status;
+
+	params.count = 1;
+	params.pointer = &in_obj;
+	in_obj.type = ACPI_TYPE_INTEGER;
+	in_obj.integer.value = val;
+
+	status = acpi_evaluate_object(handle, (char *)method, &params, output);
+	return (status == AE_OK);
+}
+
+static int read_acpi_int(acpi_handle handle, const char *method, int *val,
+			 struct acpi_object_list *params)
+{
+	struct acpi_buffer output;
+	union acpi_object out_obj;
+	acpi_status status;
+
+	output.length = sizeof(out_obj);
+	output.pointer = &out_obj;
+
+	status = acpi_evaluate_object(handle, (char *)method, params, &output);
+	*val = out_obj.integer.value;
+	return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
+}
+
+static int read_wireless_status(int mask)
+{
+	int status;
+
+	if (!wireless_status_handle)
+		return (hotk->status & mask) ? 1 : 0;
+
+	if (read_acpi_int(wireless_status_handle, NULL, &status, NULL)) {
+		return (status & mask) ? 1 : 0;
+	} else
+		printk(ASUS_WARNING "Error reading Wireless status\n");
+
+	return (hotk->status & mask) ? 1 : 0;
+}
+
+/* Generic LED functions */
+static int read_status(int mask)
+{
+	/* There is a special method for both wireless devices */
+	if (mask == BT_ON || mask == WL_ON)
+		return read_wireless_status(mask);
+
+	return (hotk->status & mask) ? 1 : 0;
+}
+
+static void write_status(acpi_handle handle, int out, int mask, int invert)
+{
+	hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask);
+
+	if (invert)		/* invert target value */
+		out = !out & 0x1;
+
+	if (handle && !write_acpi_int(handle, NULL, out, NULL))
+		printk(ASUS_WARNING " write failed\n");
+}
+
+/* /sys/class/led handlers */
+#define ASUS_LED_HANDLER(object, mask, invert)				\
+	static void object##_led_set(struct led_classdev *led_cdev,	\
+				     enum led_brightness value)		\
+	{								\
+		object##_led_wk = value;				\
+		queue_work(led_workqueue, &object##_led_work);		\
+	}								\
+	static void object##_led_update(struct work_struct *ignored)	\
+	{								\
+		int value = object##_led_wk;				\
+		write_status(object##_set_handle, value, (mask), (invert)); \
+	}
+
+ASUS_LED_HANDLER(mled, MLED_ON, 1);
+ASUS_LED_HANDLER(pled, PLED_ON, 0);
+ASUS_LED_HANDLER(rled, RLED_ON, 0);
+ASUS_LED_HANDLER(tled, TLED_ON, 0);
+
+static int get_lcd_state(void)
+{
+	return read_status(LCD_ON);
+}
+
+static int set_lcd_state(int value)
+{
+	int lcd = 0;
+	acpi_status status = 0;
+
+	lcd = value ? 1 : 0;
+
+	if (lcd == get_lcd_state())
+		return 0;
+
+	if (lcd_switch_handle) {
+		status = acpi_evaluate_object(lcd_switch_handle,
+					      NULL, NULL, NULL);
+
+		if (ACPI_FAILURE(status))
+			printk(ASUS_WARNING "Error switching LCD\n");
+	}
+
+	write_status(NULL, lcd, LCD_ON, 0);
+	return 0;
+}
+
+static void lcd_blank(int blank)
+{
+	struct backlight_device *bd = asus_backlight_device;
+
+	if (bd) {
+		down(&bd->sem);
+		if (likely(bd->props)) {
+			bd->props->power = blank;
+			if (likely(bd->props->update_status))
+				bd->props->update_status(bd);
+		}
+		up(&bd->sem);
+	}
+}
+
+static int read_brightness(struct backlight_device *bd)
+{
+	int value;
+
+	if (!read_acpi_int(brightness_get_handle, NULL, &value, NULL))
+		printk(ASUS_WARNING "Error reading brightness\n");
+
+	return value;
+}
+
+static int set_brightness(struct backlight_device *bd, int value)
+{
+	int ret = 0;
+
+	value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
+	/* 0 <= value <= 15 */
+
+	if (!write_acpi_int(brightness_set_handle, NULL, value, NULL)) {
+		printk(ASUS_WARNING "Error changing brightness\n");
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int update_bl_status(struct backlight_device *bd)
+{
+	int rv;
+	int value = bd->props->brightness;
+
+	rv = set_brightness(bd, value);
+	if (rv)
+		return rv;
+
+	value = (bd->props->power == FB_BLANK_UNBLANK) ? 1 : 0;
+	return set_lcd_state(value);
+}
+
+/*
+ * Platform device handlers
+ */
+
+/*
+ * We write our info in page, we begin at offset off and cannot write more
+ * than count bytes. We set eof to 1 if we handle those 2 values. We return the
+ * number of bytes written in page
+ */
+static ssize_t show_infos(struct device *dev,
+			  struct device_attribute *attr, char *page)
+{
+	int len = 0;
+	int temp;
+	char buf[16];		//enough for all info
+	/*
+	 * We use the easy way, we don't care of off and count, so we don't set eof
+	 * to 1
+	 */
+
+	len += sprintf(page, ASUS_HOTK_NAME " " ASUS_LAPTOP_VERSION "\n");
+	len += sprintf(page + len, "Model reference    : %s\n", hotk->name);
+	/*
+	 * The SFUN method probably allows the original driver to get the list
+	 * of features supported by a given model. For now, 0x0100 or 0x0800
+	 * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
+	 * The significance of others is yet to be found.
+	 */
+	if (read_acpi_int(hotk->handle, "SFUN", &temp, NULL))
+		len +=
+		    sprintf(page + len, "SFUN value         : 0x%04x\n", temp);
+	/*
+	 * Another value for userspace: the ASYM method returns 0x02 for
+	 * battery low and 0x04 for battery critical, its readings tend to be
+	 * more accurate than those provided by _BST.
+	 * Note: since not all the laptops provide this method, errors are
+	 * silently ignored.
+	 */
+	if (read_acpi_int(hotk->handle, "ASYM", &temp, NULL))
+		len +=
+		    sprintf(page + len, "ASYM value         : 0x%04x\n", temp);
+	if (asus_info) {
+		snprintf(buf, 16, "%d", asus_info->length);
+		len += sprintf(page + len, "DSDT length        : %s\n", buf);
+		snprintf(buf, 16, "%d", asus_info->checksum);
+		len += sprintf(page + len, "DSDT checksum      : %s\n", buf);
+		snprintf(buf, 16, "%d", asus_info->revision);
+		len += sprintf(page + len, "DSDT revision      : %s\n", buf);
+		snprintf(buf, 7, "%s", asus_info->oem_id);
+		len += sprintf(page + len, "OEM id             : %s\n", buf);
+		snprintf(buf, 9, "%s", asus_info->oem_table_id);
+		len += sprintf(page + len, "OEM table id       : %s\n", buf);
+		snprintf(buf, 16, "%x", asus_info->oem_revision);
+		len += sprintf(page + len, "OEM revision       : 0x%s\n", buf);
+		snprintf(buf, 5, "%s", asus_info->asl_compiler_id);
+		len += sprintf(page + len, "ASL comp vendor id : %s\n", buf);
+		snprintf(buf, 16, "%x", asus_info->asl_compiler_revision);
+		len += sprintf(page + len, "ASL comp revision  : 0x%s\n", buf);
+	}
+
+	return len;
+}
+
+static int parse_arg(const char *buf, unsigned long count, int *val)
+{
+	if (!count)
+		return 0;
+	if (count > 31)
+		return -EINVAL;
+	if (sscanf(buf, "%i", val) != 1)
+		return -EINVAL;
+	return count;
+}
+
+static ssize_t store_status(const char *buf, size_t count,
+			    acpi_handle handle, int mask, int invert)
+{
+	int rv, value;
+	int out = 0;
+
+	rv = parse_arg(buf, count, &value);
+	if (rv > 0)
+		out = value ? 1 : 0;
+
+	write_status(handle, out, mask, invert);
+
+	return rv;
+}
+
+/*
+ * LEDD display
+ */
+static ssize_t show_ledd(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "0x%08x\n", hotk->ledd_status);
+}
+
+static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	int rv, value;
+
+	rv = parse_arg(buf, count, &value);
+	if (rv > 0) {
+		if (!write_acpi_int(ledd_set_handle, NULL, value, NULL))
+			printk(ASUS_WARNING "LED display write failed\n");
+		else
+			hotk->ledd_status = (u32) value;
+	}
+	return rv;
+}
+
+/*
+ * WLAN
+ */
+static ssize_t show_wlan(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", read_status(WL_ON));
+}
+
+static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	return store_status(buf, count, wl_switch_handle, WL_ON, 0);
+}
+
+/*
+ * Bluetooth
+ */
+static ssize_t show_bluetooth(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", read_status(BT_ON));
+}
+
+static ssize_t store_bluetooth(struct device *dev,
+			       struct device_attribute *attr, const char *buf,
+			       size_t count)
+{
+	return store_status(buf, count, bt_switch_handle, BT_ON, 0);
+}
+
+/*
+ * Display
+ */
+static void set_display(int value)
+{
+	/* no sanity check needed for now */
+	if (!write_acpi_int(display_set_handle, NULL, value, NULL))
+		printk(ASUS_WARNING "Error setting display\n");
+	return;
+}
+
+static int read_display(void)
+{
+	int value = 0;
+
+	/* In most of the case, we know how to set the display, but sometime
+	   we can't read it */
+	if (display_get_handle) {
+		if (!read_acpi_int(display_get_handle, NULL, &value, NULL))
+			printk(ASUS_WARNING "Error reading display status\n");
+	}
+
+	value &= 0x0F;		/* needed for some models, shouldn't hurt others */
+
+	return value;
+}
+
+/*
+ * Now, *this* one could be more user-friendly, but so far, no-one has
+ * complained. The significance of bits is the same as in store_disp()
+ */
+static ssize_t show_disp(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", read_display());
+}
+
+/*
+ * Experimental support for display switching. As of now: 1 should activate
+ * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI.
+ * Any combination (bitwise) of these will suffice. I never actually tested 4
+ * displays hooked up simultaneously, so be warned. See the acpi4asus README
+ * for more info.
+ */
+static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	int rv, value;
+
+	rv = parse_arg(buf, count, &value);
+	if (rv > 0)
+		set_display(value);
+	return rv;
+}
+
+/*
+ * Light Sens
+ */
+static void set_light_sens_switch(int value)
+{
+	if (!write_acpi_int(ls_switch_handle, NULL, value, NULL))
+		printk(ASUS_WARNING "Error setting light sensor switch\n");
+	hotk->light_switch = value;
+}
+
+static ssize_t show_lssw(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", hotk->light_switch);
+}
+
+static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	int rv, value;
+
+	rv = parse_arg(buf, count, &value);
+	if (rv > 0)
+		set_light_sens_switch(value ? 1 : 0);
+
+	return rv;
+}
+
+static void set_light_sens_level(int value)
+{
+	if (!write_acpi_int(ls_level_handle, NULL, value, NULL))
+		printk(ASUS_WARNING "Error setting light sensor level\n");
+	hotk->light_level = value;
+}
+
+static ssize_t show_lslvl(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", hotk->light_level);
+}
+
+static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	int rv, value;
+
+	rv = parse_arg(buf, count, &value);
+	if (rv > 0) {
+		value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
+		/* 0 <= value <= 15 */
+		set_light_sens_level(value);
+	}
+
+	return rv;
+}
+
+static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
+{
+	/* TODO Find a better way to handle events count. */
+	if (!hotk)
+		return;
+
+	/*
+	 * We need to tell the backlight device when the backlight power is
+	 * switched
+	 */
+	if (event == ATKD_LCD_ON) {
+		write_status(NULL, 1, LCD_ON, 0);
+		lcd_blank(FB_BLANK_UNBLANK);
+	} else if (event == ATKD_LCD_OFF) {
+		write_status(NULL, 0, LCD_ON, 0);
+		lcd_blank(FB_BLANK_POWERDOWN);
+	}
+
+	acpi_bus_generate_event(hotk->device, event,
+				hotk->event_count[event % 128]++);
+
+	return;
+}
+
+#define ASUS_CREATE_DEVICE_ATTR(_name)					\
+	struct device_attribute dev_attr_##_name = {			\
+		.attr = {						\
+			.name = __stringify(_name),			\
+			.mode = 0,					\
+			.owner = THIS_MODULE },				\
+		.show   = NULL,						\
+		.store  = NULL,						\
+	}
+
+#define ASUS_SET_DEVICE_ATTR(_name, _mode, _show, _store)		\
+	do {								\
+		dev_attr_##_name.attr.mode = _mode;			\
+		dev_attr_##_name.show = _show;				\
+		dev_attr_##_name.store = _store;			\
+	} while(0)
+
+static ASUS_CREATE_DEVICE_ATTR(infos);
+static ASUS_CREATE_DEVICE_ATTR(wlan);
+static ASUS_CREATE_DEVICE_ATTR(bluetooth);
+static ASUS_CREATE_DEVICE_ATTR(display);
+static ASUS_CREATE_DEVICE_ATTR(ledd);
+static ASUS_CREATE_DEVICE_ATTR(ls_switch);
+static ASUS_CREATE_DEVICE_ATTR(ls_level);
+
+static struct attribute *asuspf_attributes[] = {
+	&dev_attr_infos.attr,
+	&dev_attr_wlan.attr,
+	&dev_attr_bluetooth.attr,
+	&dev_attr_display.attr,
+	&dev_attr_ledd.attr,
+	&dev_attr_ls_switch.attr,
+	&dev_attr_ls_level.attr,
+	NULL
+};
+
+static struct attribute_group asuspf_attribute_group = {
+	.attrs = asuspf_attributes
+};
+
+static struct platform_driver asuspf_driver = {
+	.driver = {
+		   .name = ASUS_HOTK_FILE,
+		   .owner = THIS_MODULE,
+		   }
+};
+
+static struct platform_device *asuspf_device;
+
+static void asus_hotk_add_fs(void)
+{
+	ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL);
+
+	if (wl_switch_handle)
+		ASUS_SET_DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan);
+
+	if (bt_switch_handle)
+		ASUS_SET_DEVICE_ATTR(bluetooth, 0644,
+				     show_bluetooth, store_bluetooth);
+
+	if (display_set_handle && display_get_handle)
+		ASUS_SET_DEVICE_ATTR(display, 0644, show_disp, store_disp);
+	else if (display_set_handle)
+		ASUS_SET_DEVICE_ATTR(display, 0200, NULL, store_disp);
+
+	if (ledd_set_handle)
+		ASUS_SET_DEVICE_ATTR(ledd, 0644, show_ledd, store_ledd);
+
+	if (ls_switch_handle && ls_level_handle) {
+		ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl);
+		ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw);
+	}
+}
+
+static int asus_handle_init(char *name, acpi_handle * handle,
+			    char **paths, int num_paths)
+{
+	int i;
+	acpi_status status;
+
+	for (i = 0; i < num_paths; i++) {
+		status = acpi_get_handle(NULL, paths[i], handle);
+		if (ACPI_SUCCESS(status))
+			return 0;
+	}
+
+	*handle = NULL;
+	return -ENODEV;
+}
+
+#define ASUS_HANDLE_INIT(object)					\
+	asus_handle_init(#object, &object##_handle, object##_paths,	\
+			 ARRAY_SIZE(object##_paths))
+
+/*
+ * This function is used to initialize the hotk with right values. In this
+ * method, we can make all the detection we want, and modify the hotk struct
+ */
+static int asus_hotk_get_info(void)
+{
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *model = NULL;
+	int bsts_result, hwrs_result;
+	char *string = NULL;
+	acpi_status status;
+
+	/*
+	 * Get DSDT headers early enough to allow for differentiating between
+	 * models, but late enough to allow acpi_bus_register_driver() to fail
+	 * before doing anything ACPI-specific. Should we encounter a machine,
+	 * which needs special handling (i.e. its hotkey device has a different
+	 * HID), this bit will be moved. A global variable asus_info contains
+	 * the DSDT header.
+	 */
+	status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
+	if (ACPI_FAILURE(status))
+		printk(ASUS_WARNING "Couldn't get the DSDT table header\n");
+
+	/* We have to write 0 on init this far for all ASUS models */
+	if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
+		printk(ASUS_ERR "Hotkey initialization failed\n");
+		return -ENODEV;
+	}
+
+	/* This needs to be called for some laptops to init properly */
+	if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result, NULL))
+		printk(ASUS_WARNING "Error calling BSTS\n");
+	else if (bsts_result)
+		printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n",
+		       bsts_result);
+
+	/*
+	 * Try to match the object returned by INIT to the specific model.
+	 * Handle every possible object (or the lack of thereof) the DSDT
+	 * writers might throw at us. When in trouble, we pass NULL to
+	 * asus_model_match() and try something completely different.
+	 */
+	if (buffer.pointer) {
+		model = buffer.pointer;
+		switch (model->type) {
+		case ACPI_TYPE_STRING:
+			string = model->string.pointer;
+			break;
+		case ACPI_TYPE_BUFFER:
+			string = model->buffer.pointer;
+			break;
+		default:
+			string = "";
+			break;
+		}
+	}
+	hotk->name = kstrdup(string, GFP_KERNEL);
+	if (!hotk->name)
+		return -ENOMEM;
+
+	if (*string)
+		printk(ASUS_NOTICE "  %s model detected\n", string);
+
+	ASUS_HANDLE_INIT(mled_set);
+	ASUS_HANDLE_INIT(tled_set);
+	ASUS_HANDLE_INIT(rled_set);
+	ASUS_HANDLE_INIT(pled_set);
+
+	ASUS_HANDLE_INIT(ledd_set);
+
+	/*
+	 * The HWRS method return informations about the hardware.
+	 * 0x80 bit is for WLAN, 0x100 for Bluetooth.
+	 * The significance of others is yet to be found.
+	 * If we don't find the method, we assume the device are present.
+	 */
+	if (!read_acpi_int(hotk->handle, "HRWS", &hwrs_result, NULL))
+		hwrs_result = WL_HWRS | BT_HWRS;
+
+	if (hwrs_result & WL_HWRS)
+		ASUS_HANDLE_INIT(wl_switch);
+	if (hwrs_result & BT_HWRS)
+		ASUS_HANDLE_INIT(bt_switch);
+
+	ASUS_HANDLE_INIT(wireless_status);
+
+	ASUS_HANDLE_INIT(brightness_set);
+	ASUS_HANDLE_INIT(brightness_get);
+
+	ASUS_HANDLE_INIT(lcd_switch);
+
+	ASUS_HANDLE_INIT(display_set);
+	ASUS_HANDLE_INIT(display_get);
+
+	/* There is a lot of models with "ALSL", but a few get
+	   a real light sens, so we need to check it. */
+	if (ASUS_HANDLE_INIT(ls_switch))
+		ASUS_HANDLE_INIT(ls_level);
+
+	kfree(model);
+
+	return AE_OK;
+}
+
+static int asus_hotk_check(void)
+{
+	int result = 0;
+
+	result = acpi_bus_get_status(hotk->device);
+	if (result)
+		return result;
+
+	if (hotk->device->status.present) {
+		result = asus_hotk_get_info();
+	} else {
+		printk(ASUS_ERR "Hotkey device not present, aborting\n");
+		return -EINVAL;
+	}
+
+	return result;
+}
+
+static int asus_hotk_found;
+
+static int asus_hotk_add(struct acpi_device *device)
+{
+	acpi_status status = AE_OK;
+	int result;
+
+	if (!device)
+		return -EINVAL;
+
+	printk(ASUS_NOTICE "Asus Laptop Support version %s\n",
+	       ASUS_LAPTOP_VERSION);
+
+	hotk = kmalloc(sizeof(struct asus_hotk), GFP_KERNEL);
+	if (!hotk)
+		return -ENOMEM;
+	memset(hotk, 0, sizeof(struct asus_hotk));
+
+	hotk->handle = device->handle;
+	strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME);
+	strcpy(acpi_device_class(device), ASUS_HOTK_CLASS);
+	acpi_driver_data(device) = hotk;
+	hotk->device = device;
+
+	result = asus_hotk_check();
+	if (result)
+		goto end;
+
+	asus_hotk_add_fs();
+
+	/*
+	 * We install the handler, it will receive the hotk in parameter, so, we
+	 * could add other data to the hotk struct
+	 */
+	status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+					     asus_hotk_notify, hotk);
+	if (ACPI_FAILURE(status))
+		printk(ASUS_ERR "Error installing notify handler\n");
+
+	asus_hotk_found = 1;
+
+	/* WLED and BLED are on by default */
+	write_status(bt_switch_handle, 1, BT_ON, 0);
+	write_status(wl_switch_handle, 1, WL_ON, 0);
+
+	/* LCD Backlight is on by default */
+	write_status(NULL, 1, LCD_ON, 0);
+
+	/* LED display is off by default */
+	hotk->ledd_status = 0xFFF;
+
+	/* Set initial values of light sensor and level */
+	hotk->light_switch = 1;	/* Default to light sensor disabled */
+	hotk->light_level = 0;	/* level 5 for sensor sensitivity */
+
+	if (ls_switch_handle)
+		set_light_sens_switch(hotk->light_switch);
+
+	if (ls_level_handle)
+		set_light_sens_level(hotk->light_level);
+
+      end:
+	if (result) {
+		kfree(hotk->name);
+		kfree(hotk);
+	}
+
+	return result;
+}
+
+static int asus_hotk_remove(struct acpi_device *device, int type)
+{
+	acpi_status status = 0;
+
+	if (!device || !acpi_driver_data(device))
+		return -EINVAL;
+
+	status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+					    asus_hotk_notify);
+	if (ACPI_FAILURE(status))
+		printk(ASUS_ERR "Error removing notify handler\n");
+
+	kfree(hotk->name);
+	kfree(hotk);
+
+	return 0;
+}
+
+static void asus_backlight_exit(void)
+{
+	if (asus_backlight_device)
+		backlight_device_unregister(asus_backlight_device);
+}
+
+#define  ASUS_LED_UNREGISTER(object)				\
+	if(object##_led.class_dev				\
+	   && !IS_ERR(object##_led.class_dev))			\
+		led_classdev_unregister(&object##_led)
+
+static void asus_led_exit(void)
+{
+	ASUS_LED_UNREGISTER(mled);
+	ASUS_LED_UNREGISTER(tled);
+	ASUS_LED_UNREGISTER(pled);
+	ASUS_LED_UNREGISTER(rled);
+
+	destroy_workqueue(led_workqueue);
+}
+
+static void __exit asus_laptop_exit(void)
+{
+	asus_backlight_exit();
+	asus_led_exit();
+
+	acpi_bus_unregister_driver(&asus_hotk_driver);
+	sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group);
+	platform_device_unregister(asuspf_device);
+	platform_driver_unregister(&asuspf_driver);
+}
+
+static int asus_backlight_init(struct device *dev)
+{
+	struct backlight_device *bd;
+
+	if (brightness_set_handle && lcd_switch_handle) {
+		bd = backlight_device_register(ASUS_HOTK_FILE, dev,
+					       NULL, &asusbl_data);
+		if (IS_ERR(bd)) {
+			printk(ASUS_ERR
+			       "Could not register asus backlight device\n");
+			asus_backlight_device = NULL;
+			return PTR_ERR(bd);
+		}
+
+		asus_backlight_device = bd;
+
+		down(&bd->sem);
+		if (likely(bd->props)) {
+			bd->props->brightness = read_brightness(NULL);
+			bd->props->power = FB_BLANK_UNBLANK;
+			if (likely(bd->props->update_status))
+				bd->props->update_status(bd);
+		}
+		up(&bd->sem);
+	}
+	return 0;
+}
+
+static int asus_led_register(acpi_handle handle,
+			     struct led_classdev *ldev, struct device *dev)
+{
+	if (!handle)
+		return 0;
+
+	return led_classdev_register(dev, ldev);
+}
+
+#define ASUS_LED_REGISTER(object, device)				\
+	asus_led_register(object##_set_handle, &object##_led, device)
+
+static int asus_led_init(struct device *dev)
+{
+	int rv;
+
+	rv = ASUS_LED_REGISTER(mled, dev);
+	if (rv)
+		return rv;
+
+	rv = ASUS_LED_REGISTER(tled, dev);
+	if (rv)
+		return rv;
+
+	rv = ASUS_LED_REGISTER(rled, dev);
+	if (rv)
+		return rv;
+
+	rv = ASUS_LED_REGISTER(pled, dev);
+	if (rv)
+		return rv;
+
+	led_workqueue = create_singlethread_workqueue("led_workqueue");
+	if (!led_workqueue)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int __init asus_laptop_init(void)
+{
+	struct device *dev;
+	int result;
+
+	if (acpi_disabled)
+		return -ENODEV;
+
+	if (!acpi_specific_hotkey_enabled) {
+		printk(ASUS_ERR "Using generic hotkey driver\n");
+		return -ENODEV;
+	}
+
+	result = acpi_bus_register_driver(&asus_hotk_driver);
+	if (result < 0)
+		return result;
+
+	/*
+	 * This is a bit of a kludge.  We only want this module loaded
+	 * for ASUS systems, but there's currently no way to probe the
+	 * ACPI namespace for ASUS HIDs.  So we just return failure if
+	 * we didn't find one, which will cause the module to be
+	 * unloaded.
+	 */
+	if (!asus_hotk_found) {
+		acpi_bus_unregister_driver(&asus_hotk_driver);
+		return -ENODEV;
+	}
+
+	dev = acpi_get_physical_device(hotk->device->handle);
+
+	result = asus_backlight_init(dev);
+	if (result)
+		goto fail_backlight;
+
+	result = asus_led_init(dev);
+	if (result)
+		goto fail_led;
+
+	/* Register platform stuff */
+	result = platform_driver_register(&asuspf_driver);
+	if (result)
+		goto fail_platform_driver;
+
+	asuspf_device = platform_device_alloc(ASUS_HOTK_FILE, -1);
+	if (!asuspf_device) {
+		result = -ENOMEM;
+		goto fail_platform_device1;
+	}
+
+	result = platform_device_add(asuspf_device);
+	if (result)
+		goto fail_platform_device2;
+
+	result = sysfs_create_group(&asuspf_device->dev.kobj,
+				    &asuspf_attribute_group);
+	if (result)
+		goto fail_sysfs;
+
+	return 0;
+
+      fail_sysfs:
+	platform_device_del(asuspf_device);
+
+      fail_platform_device2:
+	platform_device_put(asuspf_device);
+
+      fail_platform_device1:
+	platform_driver_unregister(&asuspf_driver);
+
+      fail_platform_driver:
+	asus_led_exit();
+
+      fail_led:
+	asus_backlight_exit();
+
+      fail_backlight:
+
+	return result;
+}
+
+module_init(asus_laptop_init);
+module_exit(asus_laptop_exit);
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
index db9d7df..552b795 100644
--- a/drivers/misc/lkdtm.c
+++ b/drivers/misc/lkdtm.c
@@ -108,8 +108,8 @@
 static int lkdtm_parse_commandline(void);
 static void lkdtm_handler(void);
 
-static char* cpoint_name = INVALID;
-static char* cpoint_type = NONE;
+static char* cpoint_name;
+static char* cpoint_type;
 static int cpoint_count = DEFAULT_COUNT;
 static int recur_count = REC_NUM_DEFAULT;
 
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
index 2ab7add..e21e490 100644
--- a/drivers/misc/tifm_7xx1.c
+++ b/drivers/misc/tifm_7xx1.c
@@ -11,66 +11,25 @@
 
 #include <linux/tifm.h>
 #include <linux/dma-mapping.h>
+#include <linux/freezer.h>
 
 #define DRIVER_NAME "tifm_7xx1"
-#define DRIVER_VERSION "0.6"
+#define DRIVER_VERSION "0.7"
 
 static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
 {
-	int cnt;
 	unsigned long flags;
 
 	spin_lock_irqsave(&fm->lock, flags);
-	if (!fm->inhibit_new_cards) {
-		for (cnt = 0; cnt < fm->max_sockets; cnt++) {
-			if (fm->sockets[cnt] == sock) {
-				fm->remove_mask |= (1 << cnt);
-				queue_work(fm->wq, &fm->media_remover);
-				break;
-			}
-		}
-	}
+	fm->socket_change_set |= 1 << sock->socket_id;
+	wake_up_all(&fm->change_set_notify);
 	spin_unlock_irqrestore(&fm->lock, flags);
 }
 
-static void tifm_7xx1_remove_media(struct work_struct *work)
-{
-	struct tifm_adapter *fm =
-		container_of(work, struct tifm_adapter, media_remover);
-	unsigned long flags;
-	int cnt;
-	struct tifm_dev *sock;
-
-	if (!class_device_get(&fm->cdev))
-		return;
-	spin_lock_irqsave(&fm->lock, flags);
-	for (cnt = 0; cnt < fm->max_sockets; cnt++) {
-		if (fm->sockets[cnt] && (fm->remove_mask & (1 << cnt))) {
-			printk(KERN_INFO DRIVER_NAME
-			       ": demand removing card from socket %d\n", cnt);
-			sock = fm->sockets[cnt];
-			fm->sockets[cnt] = NULL;
-			fm->remove_mask &= ~(1 << cnt);
-
-			writel(0x0e00, sock->addr + SOCK_CONTROL);
-
-			writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
-				fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
-			writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
-				fm->addr + FM_SET_INTERRUPT_ENABLE);
-
-			spin_unlock_irqrestore(&fm->lock, flags);
-			device_unregister(&sock->dev);
-			spin_lock_irqsave(&fm->lock, flags);
-		}
-	}
-	spin_unlock_irqrestore(&fm->lock, flags);
-	class_device_put(&fm->cdev);
-}
-
 static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
 {
 	struct tifm_adapter *fm = dev_id;
+	struct tifm_dev *sock;
 	unsigned int irq_status;
 	unsigned int sock_irq_status, cnt;
 
@@ -84,42 +43,32 @@
 	if (irq_status & TIFM_IRQ_ENABLE) {
 		writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
 
-		for (cnt = 0; cnt <  fm->max_sockets; cnt++) {
-			sock_irq_status = (irq_status >> cnt) &
-					(TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK);
+		for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+			sock = fm->sockets[cnt];
+			sock_irq_status = (irq_status >> cnt)
+					  & (TIFM_IRQ_FIFOMASK(1)
+					     | TIFM_IRQ_CARDMASK(1));
 
-			if (fm->sockets[cnt]) {
-				if (sock_irq_status &&
-						fm->sockets[cnt]->signal_irq)
-					sock_irq_status = fm->sockets[cnt]->
-						signal_irq(fm->sockets[cnt],
-							sock_irq_status);
-
-				if (irq_status & (1 << cnt))
-					fm->remove_mask |= 1 << cnt;
-			} else {
-				if (irq_status & (1 << cnt))
-					fm->insert_mask |= 1 << cnt;
-			}
+			if (sock && sock_irq_status)
+				sock->signal_irq(sock, sock_irq_status);
 		}
+
+		fm->socket_change_set |= irq_status
+					 & ((1 << fm->num_sockets) - 1);
 	}
 	writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);
 
-	if (!fm->inhibit_new_cards) {
-		if (!fm->remove_mask && !fm->insert_mask) {
-			writel(TIFM_IRQ_ENABLE,
-				fm->addr + FM_SET_INTERRUPT_ENABLE);
-		} else {
-			queue_work(fm->wq, &fm->media_remover);
-			queue_work(fm->wq, &fm->media_inserter);
-		}
-	}
+	if (!fm->socket_change_set)
+		writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
+	else
+		wake_up_all(&fm->change_set_notify);
 
 	spin_unlock(&fm->lock);
 	return IRQ_HANDLED;
 }
 
-static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is_x2)
+static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr,
+						 int is_x2)
 {
 	unsigned int s_state;
 	int cnt;
@@ -127,8 +76,8 @@
 	writel(0x0e00, sock_addr + SOCK_CONTROL);
 
 	for (cnt = 0; cnt < 100; cnt++) {
-		if (!(TIFM_SOCK_STATE_POWERED &
-				readl(sock_addr + SOCK_PRESENT_STATE)))
+		if (!(TIFM_SOCK_STATE_POWERED
+		      & readl(sock_addr + SOCK_PRESENT_STATE)))
 			break;
 		msleep(10);
 	}
@@ -151,8 +100,8 @@
 	}
 
 	for (cnt = 0; cnt < 100; cnt++) {
-		if ((TIFM_SOCK_STATE_POWERED &
-				readl(sock_addr + SOCK_PRESENT_STATE)))
+		if ((TIFM_SOCK_STATE_POWERED
+		     & readl(sock_addr + SOCK_PRESENT_STATE)))
 			break;
 		msleep(10);
 	}
@@ -170,130 +119,209 @@
 	return base_addr + ((sock_num + 1) << 10);
 }
 
-static void tifm_7xx1_insert_media(struct work_struct *work)
+static int tifm_7xx1_switch_media(void *data)
 {
-	struct tifm_adapter *fm =
-		container_of(work, struct tifm_adapter, media_inserter);
+	struct tifm_adapter *fm = data;
 	unsigned long flags;
 	tifm_media_id media_id;
 	char *card_name = "xx";
-	int cnt, ok_to_register;
-	unsigned int insert_mask;
-	struct tifm_dev *new_sock = NULL;
+	int cnt, rc;
+	struct tifm_dev *sock;
+	unsigned int socket_change_set;
 
-	if (!class_device_get(&fm->cdev))
-		return;
-	spin_lock_irqsave(&fm->lock, flags);
-	insert_mask = fm->insert_mask;
-	fm->insert_mask = 0;
-	if (fm->inhibit_new_cards) {
+	while (1) {
+		rc = wait_event_interruptible(fm->change_set_notify,
+					      fm->socket_change_set);
+		if (rc == -ERESTARTSYS)
+			try_to_freeze();
+
+		spin_lock_irqsave(&fm->lock, flags);
+		socket_change_set = fm->socket_change_set;
+		fm->socket_change_set = 0;
+
+		dev_dbg(fm->dev, "checking media set %x\n",
+			socket_change_set);
+
+		if (kthread_should_stop())
+			socket_change_set = (1 << fm->num_sockets) - 1;
 		spin_unlock_irqrestore(&fm->lock, flags);
-		class_device_put(&fm->cdev);
-		return;
-	}
-	spin_unlock_irqrestore(&fm->lock, flags);
 
-	for (cnt = 0; cnt < fm->max_sockets; cnt++) {
-		if (!(insert_mask & (1 << cnt)))
+		if (!socket_change_set)
 			continue;
 
-		media_id = tifm_7xx1_toggle_sock_power(tifm_7xx1_sock_addr(fm->addr, cnt),
-						       fm->max_sockets == 2);
-		if (media_id) {
-			ok_to_register = 0;
-			new_sock = tifm_alloc_device(fm, cnt);
-			if (new_sock) {
-				new_sock->addr = tifm_7xx1_sock_addr(fm->addr,
-									cnt);
-				new_sock->media_id = media_id;
-				switch (media_id) {
-				case 1:
-					card_name = "xd";
-					break;
-				case 2:
-					card_name = "ms";
-					break;
-				case 3:
-					card_name = "sd";
-					break;
-				default:
-					break;
-				}
-				snprintf(new_sock->dev.bus_id, BUS_ID_SIZE,
-					"tifm_%s%u:%u", card_name, fm->id, cnt);
+		spin_lock_irqsave(&fm->lock, flags);
+		for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+			if (!(socket_change_set & (1 << cnt)))
+				continue;
+			sock = fm->sockets[cnt];
+			if (sock) {
 				printk(KERN_INFO DRIVER_NAME
-					": %s card detected in socket %d\n",
-					card_name, cnt);
-				spin_lock_irqsave(&fm->lock, flags);
-				if (!fm->sockets[cnt]) {
-					fm->sockets[cnt] = new_sock;
-					ok_to_register = 1;
-				}
+				       ": demand removing card from socket %d\n",
+				       cnt);
+				fm->sockets[cnt] = NULL;
 				spin_unlock_irqrestore(&fm->lock, flags);
-				if (!ok_to_register ||
-					    device_register(&new_sock->dev)) {
-					spin_lock_irqsave(&fm->lock, flags);
-					fm->sockets[cnt] = NULL;
-					spin_unlock_irqrestore(&fm->lock,
-								flags);
-					tifm_free_device(&new_sock->dev);
+				device_unregister(&sock->dev);
+				spin_lock_irqsave(&fm->lock, flags);
+				writel(0x0e00,
+				       tifm_7xx1_sock_addr(fm->addr, cnt)
+				       + SOCK_CONTROL);
+			}
+			if (kthread_should_stop())
+				continue;
+
+			spin_unlock_irqrestore(&fm->lock, flags);
+			media_id = tifm_7xx1_toggle_sock_power(
+					tifm_7xx1_sock_addr(fm->addr, cnt),
+					fm->num_sockets == 2);
+			if (media_id) {
+				sock = tifm_alloc_device(fm);
+				if (sock) {
+					sock->addr = tifm_7xx1_sock_addr(fm->addr,
+									 cnt);
+					sock->media_id = media_id;
+					sock->socket_id = cnt;
+					switch (media_id) {
+					case 1:
+						card_name = "xd";
+						break;
+					case 2:
+						card_name = "ms";
+						break;
+					case 3:
+						card_name = "sd";
+						break;
+					default:
+						tifm_free_device(&sock->dev);
+						spin_lock_irqsave(&fm->lock, flags);
+						continue;
+					}
+					snprintf(sock->dev.bus_id, BUS_ID_SIZE,
+						 "tifm_%s%u:%u", card_name,
+						 fm->id, cnt);
+					printk(KERN_INFO DRIVER_NAME
+					       ": %s card detected in socket %d\n",
+					       card_name, cnt);
+					if (!device_register(&sock->dev)) {
+						spin_lock_irqsave(&fm->lock, flags);
+						if (!fm->sockets[cnt]) {
+							fm->sockets[cnt] = sock;
+							sock = NULL;
+						}
+						spin_unlock_irqrestore(&fm->lock, flags);
+					}
+					if (sock)
+						tifm_free_device(&sock->dev);
 				}
+				spin_lock_irqsave(&fm->lock, flags);
 			}
 		}
-		writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
-		       fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
-		writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
-		       fm->addr + FM_SET_INTERRUPT_ENABLE);
-	}
 
-	writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
-	class_device_put(&fm->cdev);
+		if (!kthread_should_stop()) {
+			writel(TIFM_IRQ_FIFOMASK(socket_change_set)
+			       | TIFM_IRQ_CARDMASK(socket_change_set),
+			       fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+			writel(TIFM_IRQ_FIFOMASK(socket_change_set)
+			       | TIFM_IRQ_CARDMASK(socket_change_set),
+			       fm->addr + FM_SET_INTERRUPT_ENABLE);
+			writel(TIFM_IRQ_ENABLE,
+			       fm->addr + FM_SET_INTERRUPT_ENABLE);
+			spin_unlock_irqrestore(&fm->lock, flags);
+		} else {
+			for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+				if (fm->sockets[cnt])
+					fm->socket_change_set |= 1 << cnt;
+			}
+			if (!fm->socket_change_set) {
+				spin_unlock_irqrestore(&fm->lock, flags);
+				return 0;
+			} else {
+				spin_unlock_irqrestore(&fm->lock, flags);
+			}
+		}
+	}
+	return 0;
 }
 
+#ifdef CONFIG_PM
+
 static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
 {
-	struct tifm_adapter *fm = pci_get_drvdata(dev);
-	unsigned long flags;
+	dev_dbg(&dev->dev, "suspending host\n");
 
-	spin_lock_irqsave(&fm->lock, flags);
-	fm->inhibit_new_cards = 1;
-	fm->remove_mask = 0xf;
-	fm->insert_mask = 0;
-	writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
-	spin_unlock_irqrestore(&fm->lock, flags);
-	flush_workqueue(fm->wq);
-
-	tifm_7xx1_remove_media(&fm->media_remover);
-
-	pci_set_power_state(dev, PCI_D3hot);
-        pci_disable_device(dev);
-        pci_save_state(dev);
+	pci_save_state(dev);
+	pci_enable_wake(dev, pci_choose_state(dev, state), 0);
+	pci_disable_device(dev);
+	pci_set_power_state(dev, pci_choose_state(dev, state));
 	return 0;
 }
 
 static int tifm_7xx1_resume(struct pci_dev *dev)
 {
 	struct tifm_adapter *fm = pci_get_drvdata(dev);
+	int cnt, rc;
 	unsigned long flags;
+	tifm_media_id new_ids[fm->num_sockets];
 
+	pci_set_power_state(dev, PCI_D0);
 	pci_restore_state(dev);
-        pci_enable_device(dev);
-        pci_set_power_state(dev, PCI_D0);
-        pci_set_master(dev);
+	rc = pci_enable_device(dev);
+	if (rc)
+		return rc;
+	pci_set_master(dev);
+
+	dev_dbg(&dev->dev, "resuming host\n");
+
+	for (cnt = 0; cnt < fm->num_sockets; cnt++)
+		new_ids[cnt] = tifm_7xx1_toggle_sock_power(
+					tifm_7xx1_sock_addr(fm->addr, cnt),
+					fm->num_sockets == 2);
+	spin_lock_irqsave(&fm->lock, flags);
+	fm->socket_change_set = 0;
+	for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+		if (fm->sockets[cnt]) {
+			if (fm->sockets[cnt]->media_id == new_ids[cnt])
+				fm->socket_change_set |= 1 << cnt;
+
+			fm->sockets[cnt]->media_id = new_ids[cnt];
+		}
+	}
+
+	writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
+	       fm->addr + FM_SET_INTERRUPT_ENABLE);
+	if (!fm->socket_change_set) {
+		spin_unlock_irqrestore(&fm->lock, flags);
+		return 0;
+	} else {
+		fm->socket_change_set = 0;
+		spin_unlock_irqrestore(&fm->lock, flags);
+	}
+
+	wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ);
 
 	spin_lock_irqsave(&fm->lock, flags);
-	fm->inhibit_new_cards = 0;
-	writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS);
-	writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
-	writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
-		fm->addr + FM_SET_INTERRUPT_ENABLE);
-	fm->insert_mask = 0xf;
+	writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
+	       | TIFM_IRQ_CARDMASK(fm->socket_change_set),
+	       fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+	writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
+	       | TIFM_IRQ_CARDMASK(fm->socket_change_set),
+	       fm->addr + FM_SET_INTERRUPT_ENABLE);
+	writel(TIFM_IRQ_ENABLE,
+	       fm->addr + FM_SET_INTERRUPT_ENABLE);
+	fm->socket_change_set = 0;
+
 	spin_unlock_irqrestore(&fm->lock, flags);
 	return 0;
 }
 
+#else
+
+#define tifm_7xx1_suspend NULL
+#define tifm_7xx1_resume NULL
+
+#endif /* CONFIG_PM */
+
 static int tifm_7xx1_probe(struct pci_dev *dev,
-			const struct pci_device_id *dev_id)
+			   const struct pci_device_id *dev_id)
 {
 	struct tifm_adapter *fm;
 	int pci_dev_busy = 0;
@@ -324,19 +352,18 @@
 	}
 
 	fm->dev = &dev->dev;
-	fm->max_sockets = (dev->device == 0x803B) ? 2 : 4;
-	fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->max_sockets,
-				GFP_KERNEL);
+	fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM)
+			  ? 4 : 2;
+	fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets,
+			      GFP_KERNEL);
 	if (!fm->sockets)
 		goto err_out_free;
 
-	INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media);
-	INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media);
 	fm->eject = tifm_7xx1_eject;
 	pci_set_drvdata(dev, fm);
 
 	fm->addr = ioremap(pci_resource_start(dev, 0),
-				pci_resource_len(dev, 0));
+			   pci_resource_len(dev, 0));
 	if (!fm->addr)
 		goto err_out_free;
 
@@ -344,16 +371,15 @@
 	if (rc)
 		goto err_out_unmap;
 
-	rc = tifm_add_adapter(fm);
+	init_waitqueue_head(&fm->change_set_notify);
+	rc = tifm_add_adapter(fm, tifm_7xx1_switch_media);
 	if (rc)
 		goto err_out_irq;
 
 	writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
-	writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
-		fm->addr + FM_SET_INTERRUPT_ENABLE);
-
-	fm->insert_mask = 0xf;
-
+	writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
+	       fm->addr + FM_SET_INTERRUPT_ENABLE);
+	wake_up_process(fm->media_switcher);
 	return 0;
 
 err_out_irq:
@@ -377,19 +403,15 @@
 	struct tifm_adapter *fm = pci_get_drvdata(dev);
 	unsigned long flags;
 
+	writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+	mmiowb();
+	free_irq(dev->irq, fm);
+
 	spin_lock_irqsave(&fm->lock, flags);
-	fm->inhibit_new_cards = 1;
-	fm->remove_mask = 0xf;
-	fm->insert_mask = 0;
-	writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+	fm->socket_change_set = (1 << fm->num_sockets) - 1;
 	spin_unlock_irqrestore(&fm->lock, flags);
 
-	flush_workqueue(fm->wq);
-
-	tifm_7xx1_remove_media(&fm->media_remover);
-
-	writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
-	free_irq(dev->irq, fm);
+	kthread_stop(fm->media_switcher);
 
 	tifm_remove_adapter(fm);
 
@@ -404,10 +426,12 @@
 }
 
 static struct pci_device_id tifm_7xx1_pci_tbl [] = {
-	{ PCI_VENDOR_ID_TI, 0x8033, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  0 }, /* xx21 - the one I have */
-        { PCI_VENDOR_ID_TI, 0x803B, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  0 }, /* xx12 - should be also supported */
+	{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11_FM, PCI_ANY_ID,
+	  PCI_ANY_ID, 0, 0, 0 }, /* xx21 - the one I have */
+        { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12_FM, PCI_ANY_ID,
+	  PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX20_FM, PCI_ANY_ID,
+	  PCI_ANY_ID, 0, 0, 0 },
 	{ }
 };
 
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index d61df5c..6b10ebe 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -14,7 +14,7 @@
 #include <linux/idr.h>
 
 #define DRIVER_NAME "tifm_core"
-#define DRIVER_VERSION "0.6"
+#define DRIVER_VERSION "0.7"
 
 static DEFINE_IDR(tifm_adapter_idr);
 static DEFINE_SPINLOCK(tifm_adapter_lock);
@@ -60,10 +60,41 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
+
+static int tifm_device_suspend(struct device *dev, pm_message_t state)
+{
+	struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+	struct tifm_driver *drv = fm_dev->drv;
+
+	if (drv && drv->suspend)
+		return drv->suspend(fm_dev, state);
+	return 0;
+}
+
+static int tifm_device_resume(struct device *dev)
+{
+	struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+	struct tifm_driver *drv = fm_dev->drv;
+
+	if (drv && drv->resume)
+		return drv->resume(fm_dev);
+	return 0;
+}
+
+#else
+
+#define tifm_device_suspend NULL
+#define tifm_device_resume NULL
+
+#endif /* CONFIG_PM */
+
 static struct bus_type tifm_bus_type = {
 	.name    = "tifm",
 	.match   = tifm_match,
 	.uevent  = tifm_uevent,
+	.suspend = tifm_device_suspend,
+	.resume  = tifm_device_resume
 };
 
 static void tifm_free(struct class_device *cdev)
@@ -71,8 +102,6 @@
 	struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
 
 	kfree(fm->sockets);
-	if (fm->wq)
-		destroy_workqueue(fm->wq);
 	kfree(fm);
 }
 
@@ -101,7 +130,8 @@
 }
 EXPORT_SYMBOL(tifm_free_adapter);
 
-int tifm_add_adapter(struct tifm_adapter *fm)
+int tifm_add_adapter(struct tifm_adapter *fm,
+		     int (*mediathreadfn)(void *data))
 {
 	int rc;
 
@@ -113,10 +143,10 @@
 	spin_unlock(&tifm_adapter_lock);
 	if (!rc) {
 		snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
-		strncpy(fm->wq_name, fm->cdev.class_id, KOBJ_NAME_LEN);
+		fm->media_switcher = kthread_create(mediathreadfn,
+						    fm, "tifm/%u", fm->id);
 
-		fm->wq = create_singlethread_workqueue(fm->wq_name);
-		if (fm->wq)
+		if (!IS_ERR(fm->media_switcher))
 			return class_device_add(&fm->cdev);
 
 		spin_lock(&tifm_adapter_lock);
@@ -141,27 +171,27 @@
 void tifm_free_device(struct device *dev)
 {
 	struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
-	if (fm_dev->wq)
-		destroy_workqueue(fm_dev->wq);
 	kfree(fm_dev);
 }
 EXPORT_SYMBOL(tifm_free_device);
 
-struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id)
+static void tifm_dummy_signal_irq(struct tifm_dev *sock,
+				  unsigned int sock_irq_status)
+{
+	return;
+}
+
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm)
 {
 	struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
 
 	if (dev) {
 		spin_lock_init(&dev->lock);
-		snprintf(dev->wq_name, KOBJ_NAME_LEN, "tifm%u:%u", fm->id, id);
-		dev->wq = create_singlethread_workqueue(dev->wq_name);
-		if (!dev->wq) {
-			kfree(dev);
-			return NULL;
-		}
+
 		dev->dev.parent = fm->dev;
 		dev->dev.bus = &tifm_bus_type;
 		dev->dev.release = tifm_free_device;
+		dev->signal_irq = tifm_dummy_signal_irq;
 	}
 	return dev;
 }
@@ -219,6 +249,7 @@
 	struct tifm_driver *drv = fm_dev->drv;
 
 	if (drv) {
+		fm_dev->signal_irq = tifm_dummy_signal_irq;
 		if (drv->remove)
 			drv->remove(fm_dev);
 		fm_dev->drv = NULL;
@@ -233,6 +264,8 @@
 	drv->driver.bus = &tifm_bus_type;
 	drv->driver.probe = tifm_device_probe;
 	drv->driver.remove = tifm_device_remove;
+	drv->driver.suspend = tifm_device_suspend;
+	drv->driver.resume = tifm_device_resume;
 
 	return driver_register(&drv->driver);
 }
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 4224686..12af9c7 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -111,7 +111,7 @@
 
 config MMC_TIFM_SD
 	tristate "TI Flash Media MMC/SD Interface support  (EXPERIMENTAL)"
-	depends on MMC && EXPERIMENTAL
+	depends on MMC && EXPERIMENTAL && PCI
 	select TIFM_CORE
 	help
 	  Say Y here if you want to be able to access MMC/SD cards with
diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c
index aa152f3..2ce50f3 100644
--- a/drivers/mmc/at91_mci.c
+++ b/drivers/mmc/at91_mci.c
@@ -823,6 +823,9 @@
 	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
 	mmc->caps = MMC_CAP_BYTEBLOCK;
 
+	mmc->max_blk_size = 4095;
+	mmc->max_blk_count = mmc->max_req_size;
+
 	host = mmc_priv(mmc);
 	host->mmc = mmc;
 	host->buffer = NULL;
diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c
index 800527c..b834be2 100644
--- a/drivers/mmc/au1xmmc.c
+++ b/drivers/mmc/au1xmmc.c
@@ -152,8 +152,9 @@
 		? 1 : 0;
 }
 
-static inline int au1xmmc_card_readonly(struct au1xmmc_host *host)
+static int au1xmmc_card_readonly(struct mmc_host *mmc)
 {
+	struct au1xmmc_host *host = mmc_priv(mmc);
 	return (bcsr->status & au1xmmc_card_table[host->id].wpstatus)
 		? 1 : 0;
 }
@@ -193,6 +194,8 @@
 	u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
 
 	switch (mmc_resp_type(cmd)) {
+	case MMC_RSP_NONE:
+		break;
 	case MMC_RSP_R1:
 		mmccmd |= SD_CMD_RT_1;
 		break;
@@ -205,6 +208,10 @@
 	case MMC_RSP_R3:
 		mmccmd |= SD_CMD_RT_3;
 		break;
+	default:
+		printk(KERN_INFO "au1xmmc: unhandled response type %02x\n",
+			mmc_resp_type(cmd));
+		return MMC_ERR_INVALID;
 	}
 
 	switch(cmd->opcode) {
@@ -878,6 +885,7 @@
 static const struct mmc_host_ops au1xmmc_ops = {
 	.request	= au1xmmc_request,
 	.set_ios	= au1xmmc_set_ios,
+	.get_ro		= au1xmmc_card_readonly,
 };
 
 static int __devinit au1xmmc_probe(struct platform_device *pdev)
@@ -914,6 +922,9 @@
 		mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
 		mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
 
+		mmc->max_blk_size = 2048;
+		mmc->max_blk_count = 512;
+
 		mmc->ocr_avail = AU1XMMC_OCR;
 
 		host = mmc_priv(mmc);
diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c
index bfb9ff6..b060d4b 100644
--- a/drivers/mmc/imxmmc.c
+++ b/drivers/mmc/imxmmc.c
@@ -958,8 +958,10 @@
 	/* MMC core transfer sizes tunable parameters */
 	mmc->max_hw_segs = 64;
 	mmc->max_phys_segs = 64;
-	mmc->max_sectors = 64;		/* default 1 << (PAGE_CACHE_SHIFT - 9) */
 	mmc->max_seg_size = 64*512;	/* default PAGE_CACHE_SIZE */
+	mmc->max_req_size = 64*512;	/* default PAGE_CACHE_SIZE */
+	mmc->max_blk_size = 2048;
+	mmc->max_blk_count = 65535;
 
 	host = mmc_priv(mmc);
 	host->mmc = mmc;
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 6f2a282..5046a16 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -103,11 +103,16 @@
 		 mmc_hostname(host), mrq->cmd->opcode,
 		 mrq->cmd->arg, mrq->cmd->flags);
 
-	WARN_ON(host->card_busy == NULL);
+	WARN_ON(!host->claimed);
 
 	mrq->cmd->error = 0;
 	mrq->cmd->mrq = mrq;
 	if (mrq->data) {
+		BUG_ON(mrq->data->blksz > host->max_blk_size);
+		BUG_ON(mrq->data->blocks > host->max_blk_count);
+		BUG_ON(mrq->data->blocks * mrq->data->blksz >
+			host->max_req_size);
+
 		mrq->cmd->data = mrq->data;
 		mrq->data->error = 0;
 		mrq->data->mrq = mrq;
@@ -157,7 +162,7 @@
 {
 	struct mmc_request mrq;
 
-	BUG_ON(host->card_busy == NULL);
+	BUG_ON(!host->claimed);
 
 	memset(&mrq, 0, sizeof(struct mmc_request));
 
@@ -195,7 +200,7 @@
 
 	int i, err;
 
-	BUG_ON(host->card_busy == NULL);
+	BUG_ON(!host->claimed);
 	BUG_ON(retries < 0);
 
 	err = MMC_ERR_INVALID;
@@ -289,7 +294,10 @@
 		else
 			limit_us = 100000;
 
-		if (timeout_us > limit_us) {
+		/*
+		 * SDHC cards always use these fixed values.
+		 */
+		if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
 			data->timeout_ns = limit_us * 1000;
 			data->timeout_clks = 0;
 		}
@@ -320,14 +328,14 @@
 	spin_lock_irqsave(&host->lock, flags);
 	while (1) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
-		if (host->card_busy == NULL)
+		if (!host->claimed)
 			break;
 		spin_unlock_irqrestore(&host->lock, flags);
 		schedule();
 		spin_lock_irqsave(&host->lock, flags);
 	}
 	set_current_state(TASK_RUNNING);
-	host->card_busy = card;
+	host->claimed = 1;
 	spin_unlock_irqrestore(&host->lock, flags);
 	remove_wait_queue(&host->wq, &wait);
 
@@ -353,10 +361,10 @@
 {
 	unsigned long flags;
 
-	BUG_ON(host->card_busy == NULL);
+	BUG_ON(!host->claimed);
 
 	spin_lock_irqsave(&host->lock, flags);
-	host->card_busy = NULL;
+	host->claimed = 0;
 	spin_unlock_irqrestore(&host->lock, flags);
 
 	wake_up(&host->wq);
@@ -372,7 +380,7 @@
 		 mmc_hostname(host), ios->clock, ios->bus_mode,
 		 ios->power_mode, ios->chip_select, ios->vdd,
 		 ios->bus_width);
-	
+
 	host->ops->set_ios(host, ios);
 }
 
@@ -381,7 +389,7 @@
 	int err;
 	struct mmc_command cmd;
 
-	BUG_ON(host->card_busy == NULL);
+	BUG_ON(!host->claimed);
 
 	if (host->card_selected == card)
 		return MMC_ERR_NONE;
@@ -588,34 +596,65 @@
 
 	if (mmc_card_sd(card)) {
 		csd_struct = UNSTUFF_BITS(resp, 126, 2);
-		if (csd_struct != 0) {
+
+		switch (csd_struct) {
+		case 0:
+			m = UNSTUFF_BITS(resp, 115, 4);
+			e = UNSTUFF_BITS(resp, 112, 3);
+			csd->tacc_ns	 = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+			csd->tacc_clks	 = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+			m = UNSTUFF_BITS(resp, 99, 4);
+			e = UNSTUFF_BITS(resp, 96, 3);
+			csd->max_dtr	  = tran_exp[e] * tran_mant[m];
+			csd->cmdclass	  = UNSTUFF_BITS(resp, 84, 12);
+
+			e = UNSTUFF_BITS(resp, 47, 3);
+			m = UNSTUFF_BITS(resp, 62, 12);
+			csd->capacity	  = (1 + m) << (e + 2);
+
+			csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+			csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
+			csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
+			csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+			csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
+			csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
+			csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
+			break;
+		case 1:
+			/*
+			 * This is a block-addressed SDHC card. Most
+			 * interesting fields are unused and have fixed
+			 * values. To avoid getting tripped by buggy cards,
+			 * we assume those fixed values ourselves.
+			 */
+			mmc_card_set_blockaddr(card);
+
+			csd->tacc_ns	 = 0; /* Unused */
+			csd->tacc_clks	 = 0; /* Unused */
+
+			m = UNSTUFF_BITS(resp, 99, 4);
+			e = UNSTUFF_BITS(resp, 96, 3);
+			csd->max_dtr	  = tran_exp[e] * tran_mant[m];
+			csd->cmdclass	  = UNSTUFF_BITS(resp, 84, 12);
+
+			m = UNSTUFF_BITS(resp, 48, 22);
+			csd->capacity     = (1 + m) << 10;
+
+			csd->read_blkbits = 9;
+			csd->read_partial = 0;
+			csd->write_misalign = 0;
+			csd->read_misalign = 0;
+			csd->r2w_factor = 4; /* Unused */
+			csd->write_blkbits = 9;
+			csd->write_partial = 0;
+			break;
+		default:
 			printk("%s: unrecognised CSD structure version %d\n",
 				mmc_hostname(card->host), csd_struct);
 			mmc_card_set_bad(card);
 			return;
 		}
-
-		m = UNSTUFF_BITS(resp, 115, 4);
-		e = UNSTUFF_BITS(resp, 112, 3);
-		csd->tacc_ns	 = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
-		csd->tacc_clks	 = UNSTUFF_BITS(resp, 104, 8) * 100;
-
-		m = UNSTUFF_BITS(resp, 99, 4);
-		e = UNSTUFF_BITS(resp, 96, 3);
-		csd->max_dtr	  = tran_exp[e] * tran_mant[m];
-		csd->cmdclass	  = UNSTUFF_BITS(resp, 84, 12);
-
-		e = UNSTUFF_BITS(resp, 47, 3);
-		m = UNSTUFF_BITS(resp, 62, 12);
-		csd->capacity	  = (1 + m) << (e + 2);
-
-		csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
-		csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
-		csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
-		csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
-		csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
-		csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
-		csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
 	} else {
 		/*
 		 * We only understand CSD structure v1.1 and v1.2.
@@ -848,6 +887,41 @@
 	return err;
 }
 
+static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2)
+{
+	struct mmc_command cmd;
+	int err, sd2;
+	static const u8 test_pattern = 0xAA;
+
+	/*
+	* To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
+	* before SD_APP_OP_COND. This command will harmlessly fail for
+	* SD 1.0 cards.
+	*/
+	cmd.opcode = SD_SEND_IF_COND;
+	cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
+	cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
+
+	err = mmc_wait_for_cmd(host, &cmd, 0);
+	if (err == MMC_ERR_NONE) {
+		if ((cmd.resp[0] & 0xFF) == test_pattern) {
+			sd2 = 1;
+		} else {
+			sd2 = 0;
+			err = MMC_ERR_FAILED;
+		}
+	} else {
+		/*
+		 * Treat errors as SD 1.0 card.
+		 */
+		sd2 = 0;
+		err = MMC_ERR_NONE;
+	}
+	if (rsd2)
+		*rsd2 = sd2;
+	return err;
+}
+
 /*
  * Discover cards by requesting their CID.  If this command
  * times out, it is not an error; there are no further cards
@@ -1018,7 +1092,8 @@
 		mmc_wait_for_req(host, &mrq);
 
 		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
-			mmc_card_set_dead(card);
+			printk("%s: unable to read EXT_CSD, performance "
+				"might suffer.\n", mmc_hostname(card->host));
 			continue;
 		}
 
@@ -1034,7 +1109,6 @@
 			printk("%s: card is mmc v4 but doesn't support "
 			       "any high-speed modes.\n",
 				mmc_hostname(card->host));
-			mmc_card_set_bad(card);
 			continue;
 		}
 
@@ -1215,7 +1289,9 @@
 		mmc_wait_for_req(host, &mrq);
 
 		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
-			mmc_card_set_dead(card);
+			printk("%s: unable to read switch capabilities, "
+				"performance might suffer.\n",
+				mmc_hostname(card->host));
 			continue;
 		}
 
@@ -1247,12 +1323,8 @@
 
 		mmc_wait_for_req(host, &mrq);
 
-		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
-			mmc_card_set_dead(card);
-			continue;
-		}
-
-		if ((status[16] & 0xF) != 1) {
+		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE ||
+			(status[16] & 0xF) != 1) {
 			printk(KERN_WARNING "%s: Problem switching card "
 				"into high-speed mode!\n",
 				mmc_hostname(host));
@@ -1334,6 +1406,10 @@
 		mmc_power_up(host);
 		mmc_idle_cards(host);
 
+		err = mmc_send_if_cond(host, host->ocr_avail, NULL);
+		if (err != MMC_ERR_NONE) {
+			return;
+		}
 		err = mmc_send_app_op_cond(host, 0, &ocr);
 
 		/*
@@ -1386,10 +1462,21 @@
 	 * all get the idea that they should be ready for CMD2.
 	 * (My SanDisk card seems to need this.)
 	 */
-	if (host->mode == MMC_MODE_SD)
-		mmc_send_app_op_cond(host, host->ocr, NULL);
-	else
+	if (host->mode == MMC_MODE_SD) {
+		int err, sd2;
+		err = mmc_send_if_cond(host, host->ocr, &sd2);
+		if (err == MMC_ERR_NONE) {
+			/*
+			* If SD_SEND_IF_COND indicates an SD 2.0
+			* compliant card and we should set bit 30
+			* of the ocr to indicate that we can handle
+			* block-addressed SDHC cards.
+			*/
+			mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL);
+		}
+	} else {
 		mmc_send_op_cond(host, host->ocr, NULL);
+	}
 
 	mmc_discover_cards(host);
 
@@ -1519,8 +1606,11 @@
 		 */
 		host->max_hw_segs = 1;
 		host->max_phys_segs = 1;
-		host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
 		host->max_seg_size = PAGE_CACHE_SIZE;
+
+		host->max_req_size = PAGE_CACHE_SIZE;
+		host->max_blk_size = 512;
+		host->max_blk_count = PAGE_CACHE_SIZE / 512;
 	}
 
 	return host;
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index 8771357..05ba8ac 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -237,13 +237,17 @@
 		brq.mrq.cmd = &brq.cmd;
 		brq.mrq.data = &brq.data;
 
-		brq.cmd.arg = req->sector << 9;
+		brq.cmd.arg = req->sector;
+		if (!mmc_card_blockaddr(card))
+			brq.cmd.arg <<= 9;
 		brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
 		brq.data.blksz = 1 << md->block_bits;
-		brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
 		brq.stop.opcode = MMC_STOP_TRANSMISSION;
 		brq.stop.arg = 0;
 		brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+		brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
+		if (brq.data.blocks > card->host->max_blk_count)
+			brq.data.blocks = card->host->max_blk_count;
 
 		mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
 
@@ -375,9 +379,10 @@
 		spin_unlock_irq(&md->lock);
 	}
 
+flush_queue:
+
 	mmc_card_release_host(card);
 
-flush_queue:
 	spin_lock_irq(&md->lock);
 	while (ret) {
 		ret = end_that_request_chunk(req, 0,
@@ -494,6 +499,10 @@
 	struct mmc_command cmd;
 	int err;
 
+	/* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
+	if (mmc_card_blockaddr(card))
+		return 0;
+
 	mmc_card_claim_host(card);
 	cmd.opcode = MMC_SET_BLOCKLEN;
 	cmd.arg = 1 << md->block_bits;
diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c
index 3e35a43..c27e426 100644
--- a/drivers/mmc/mmc_queue.c
+++ b/drivers/mmc/mmc_queue.c
@@ -147,7 +147,7 @@
 
 	blk_queue_prep_rq(mq->queue, mmc_prep_request);
 	blk_queue_bounce_limit(mq->queue, limit);
-	blk_queue_max_sectors(mq->queue, host->max_sectors);
+	blk_queue_max_sectors(mq->queue, host->max_req_size / 512);
 	blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
 	blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
 	blk_queue_max_segment_size(mq->queue, host->max_seg_size);
diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c
index e334acd..d32698b 100644
--- a/drivers/mmc/mmc_sysfs.c
+++ b/drivers/mmc/mmc_sysfs.c
@@ -199,7 +199,7 @@
 	memset(card, 0, sizeof(struct mmc_card));
 	card->host = host;
 	device_initialize(&card->dev);
-	card->dev.parent = mmc_dev(host);
+	card->dev.parent = mmc_classdev(host);
 	card->dev.bus = &mmc_bus_type;
 	card->dev.release = mmc_release_card;
 }
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
index ccfe656..5941dd9 100644
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/mmci.c
@@ -524,15 +524,24 @@
 	/*
 	 * Since we only have a 16-bit data length register, we must
 	 * ensure that we don't exceed 2^16-1 bytes in a single request.
-	 * Choose 64 (512-byte) sectors as the limit.
 	 */
-	mmc->max_sectors = 64;
+	mmc->max_req_size = 65535;
 
 	/*
 	 * Set the maximum segment size.  Since we aren't doing DMA
 	 * (yet) we are only limited by the data length register.
 	 */
-	mmc->max_seg_size = mmc->max_sectors << 9;
+	mmc->max_seg_size = mmc->max_req_size;
+
+	/*
+	 * Block size can be up to 2048 bytes, but must be a power of two.
+	 */
+	mmc->max_blk_size = 2048;
+
+	/*
+	 * No limit on the number of blocks transferred.
+	 */
+	mmc->max_blk_count = mmc->max_req_size;
 
 	spin_lock_init(&host->lock);
 
diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c
index d30540b..1e96a2f 100644
--- a/drivers/mmc/omap.c
+++ b/drivers/mmc/omap.c
@@ -1099,8 +1099,10 @@
 	 */
 	mmc->max_phys_segs = 32;
 	mmc->max_hw_segs = 32;
-	mmc->max_sectors = 256; /* NBLK max 11-bits, OMAP also limited by DMA */
-	mmc->max_seg_size = mmc->max_sectors * 512;
+	mmc->max_blk_size = 2048;	/* BLEN is 11 bits (+1) */
+	mmc->max_blk_count = 2048;	/* NBLK is 11 bits (+1) */
+	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+	mmc->max_seg_size = mmc->max_req_size;
 
 	if (host->power_pin >= 0) {
 		if ((ret = omap_request_gpio(host->power_pin)) != 0) {
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
index 6073d99..9774fc6 100644
--- a/drivers/mmc/pxamci.c
+++ b/drivers/mmc/pxamci.c
@@ -450,6 +450,16 @@
 	 */
 	mmc->max_seg_size = PAGE_SIZE;
 
+	/*
+	 * Block length register is 10 bits.
+	 */
+	mmc->max_blk_size = 1023;
+
+	/*
+	 * Block count register is 16 bits.
+	 */
+	mmc->max_blk_count = 65535;
+
 	host = mmc_priv(mmc);
 	host->mmc = mmc;
 	host->dma = -1;
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index c2d13d7..4bf1fea 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -37,6 +37,7 @@
 #define SDHCI_QUIRK_FORCE_DMA				(1<<1)
 /* Controller doesn't like some resets when there is no card inserted. */
 #define SDHCI_QUIRK_NO_CARD_NO_RESET			(1<<2)
+#define SDHCI_QUIRK_SINGLE_POWER_WRITE			(1<<3)
 
 static const struct pci_device_id pci_ids[] __devinitdata = {
 	{
@@ -65,6 +66,14 @@
 		.driver_data	= SDHCI_QUIRK_FORCE_DMA,
 	},
 
+	{
+		.vendor		= PCI_VENDOR_ID_ENE,
+		.device		= PCI_DEVICE_ID_ENE_CB712_SD,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE,
+	},
+
 	{	/* Generic SD host controller */
 		PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
 	},
@@ -197,15 +206,9 @@
  *                                                                           *
 \*****************************************************************************/
 
-static inline char* sdhci_kmap_sg(struct sdhci_host* host)
+static inline char* sdhci_sg_to_buffer(struct sdhci_host* host)
 {
-	host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ);
-	return host->mapped_sg + host->cur_sg->offset;
-}
-
-static inline void sdhci_kunmap_sg(struct sdhci_host* host)
-{
-	kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
+	return page_address(host->cur_sg->page) + host->cur_sg->offset;
 }
 
 static inline int sdhci_next_sg(struct sdhci_host* host)
@@ -240,7 +243,7 @@
 	chunk_remain = 0;
 	data = 0;
 
-	buffer = sdhci_kmap_sg(host) + host->offset;
+	buffer = sdhci_sg_to_buffer(host) + host->offset;
 
 	while (blksize) {
 		if (chunk_remain == 0) {
@@ -264,16 +267,13 @@
 		}
 
 		if (host->remain == 0) {
-			sdhci_kunmap_sg(host);
 			if (sdhci_next_sg(host) == 0) {
 				BUG_ON(blksize != 0);
 				return;
 			}
-			buffer = sdhci_kmap_sg(host);
+			buffer = sdhci_sg_to_buffer(host);
 		}
 	}
-
-	sdhci_kunmap_sg(host);
 }
 
 static void sdhci_write_block_pio(struct sdhci_host *host)
@@ -290,7 +290,7 @@
 	data = 0;
 
 	bytes = 0;
-	buffer = sdhci_kmap_sg(host) + host->offset;
+	buffer = sdhci_sg_to_buffer(host) + host->offset;
 
 	while (blksize) {
 		size = min(host->size, host->remain);
@@ -314,16 +314,13 @@
 		}
 
 		if (host->remain == 0) {
-			sdhci_kunmap_sg(host);
 			if (sdhci_next_sg(host) == 0) {
 				BUG_ON(blksize != 0);
 				return;
 			}
-			buffer = sdhci_kmap_sg(host);
+			buffer = sdhci_sg_to_buffer(host);
 		}
 	}
-
-	sdhci_kunmap_sg(host);
 }
 
 static void sdhci_transfer_pio(struct sdhci_host *host)
@@ -372,7 +369,7 @@
 
 	/* Sanity checks */
 	BUG_ON(data->blksz * data->blocks > 524288);
-	BUG_ON(data->blksz > host->max_block);
+	BUG_ON(data->blksz > host->mmc->max_blk_size);
 	BUG_ON(data->blocks > 65535);
 
 	/* timeout in us */
@@ -674,10 +671,17 @@
 	if (host->power == power)
 		return;
 
-	writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
-
-	if (power == (unsigned short)-1)
+	if (power == (unsigned short)-1) {
+		writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
 		goto out;
+	}
+
+	/*
+	 * Spec says that we should clear the power reg before setting
+	 * a new value. Some controllers don't seem to like this though.
+	 */
+	if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
+		writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
 
 	pwr = SDHCI_POWER_ON;
 
@@ -1109,7 +1113,9 @@
 
 	pci_set_power_state(pdev, PCI_D0);
 	pci_restore_state(pdev);
-	pci_enable_device(pdev);
+	ret = pci_enable_device(pdev);
+	if (ret)
+		return ret;
 
 	for (i = 0;i < chip->num_slots;i++) {
 		if (!chip->hosts[i])
@@ -1274,15 +1280,6 @@
 	if (caps & SDHCI_TIMEOUT_CLK_UNIT)
 		host->timeout_clk *= 1000;
 
-	host->max_block = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
-	if (host->max_block >= 3) {
-		printk(KERN_ERR "%s: Invalid maximum block size.\n",
-			host->slot_descr);
-		ret = -ENODEV;
-		goto unmap;
-	}
-	host->max_block = 512 << host->max_block;
-
 	/*
 	 * Set host parameters.
 	 */
@@ -1294,9 +1291,9 @@
 	mmc->ocr_avail = 0;
 	if (caps & SDHCI_CAN_VDD_330)
 		mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
-	else if (caps & SDHCI_CAN_VDD_300)
+	if (caps & SDHCI_CAN_VDD_300)
 		mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
-	else if (caps & SDHCI_CAN_VDD_180)
+	if (caps & SDHCI_CAN_VDD_180)
 		mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19;
 
 	if ((host->max_clk > 25000000) && !(caps & SDHCI_CAN_DO_HISPD)) {
@@ -1326,15 +1323,33 @@
 
 	/*
 	 * Maximum number of sectors in one transfer. Limited by DMA boundary
-	 * size (512KiB), which means (512 KiB/512=) 1024 entries.
+	 * size (512KiB).
 	 */
-	mmc->max_sectors = 1024;
+	mmc->max_req_size = 524288;
 
 	/*
 	 * Maximum segment size. Could be one segment with the maximum number
-	 * of sectors.
+	 * of bytes.
 	 */
-	mmc->max_seg_size = mmc->max_sectors * 512;
+	mmc->max_seg_size = mmc->max_req_size;
+
+	/*
+	 * Maximum block size. This varies from controller to controller and
+	 * is specified in the capabilities register.
+	 */
+	mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
+	if (mmc->max_blk_size >= 3) {
+		printk(KERN_ERR "%s: Invalid maximum block size.\n",
+			host->slot_descr);
+		ret = -ENODEV;
+		goto unmap;
+	}
+	mmc->max_blk_size = 512 << mmc->max_blk_size;
+
+	/*
+	 * Maximum block count.
+	 */
+	mmc->max_blk_count = 65535;
 
 	/*
 	 * Init tasklets.
diff --git a/drivers/mmc/sdhci.h b/drivers/mmc/sdhci.h
index f9d1a0a..e324f0a 100644
--- a/drivers/mmc/sdhci.h
+++ b/drivers/mmc/sdhci.h
@@ -174,7 +174,6 @@
 
 	unsigned int		max_clk;	/* Max possible freq (MHz) */
 	unsigned int		timeout_clk;	/* Timeout freq (KHz) */
-	unsigned int		max_block;	/* Max block size (bytes) */
 
 	unsigned int		clock;		/* Current clock (MHz) */
 	unsigned short		power;		/* Current voltage */
@@ -184,7 +183,6 @@
 	struct mmc_data		*data;		/* Current data request */
 
 	struct scatterlist	*cur_sg;	/* We're working on this */
-	char			*mapped_sg;	/* This is where it's mapped */
 	int			num_sg;		/* Entries left */
 	int			offset;		/* Offset into current sg */
 	int			remain;		/* Bytes left in current */
diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c
index fa4a528..e65f8a0 100644
--- a/drivers/mmc/tifm_sd.c
+++ b/drivers/mmc/tifm_sd.c
@@ -17,7 +17,7 @@
 #include <asm/io.h>
 
 #define DRIVER_NAME "tifm_sd"
-#define DRIVER_VERSION "0.6"
+#define DRIVER_VERSION "0.7"
 
 static int no_dma = 0;
 static int fixed_timeout = 0;
@@ -79,7 +79,6 @@
 
 enum {
 	FIFO_RDY   = 0x0001,     /* hardware dependent value */
-	HOST_REG   = 0x0002,
 	EJECT      = 0x0004,
 	EJECT_DONE = 0x0008,
 	CARD_BUSY  = 0x0010,
@@ -95,46 +94,53 @@
 	card_state_t        state;
 	unsigned int        clk_freq;
 	unsigned int        clk_div;
-	unsigned long       timeout_jiffies; // software timeout - 2 sec
+	unsigned long       timeout_jiffies;
 
+	struct tasklet_struct finish_tasklet;
+	struct timer_list     timer;
 	struct mmc_request    *req;
-	struct work_struct    cmd_handler;
-	struct delayed_work   abort_handler;
-	wait_queue_head_t     can_eject;
+	wait_queue_head_t     notify;
 
 	size_t                written_blocks;
-	char                  *buffer;
 	size_t                buffer_size;
 	size_t                buffer_pos;
 
 };
 
+static char* tifm_sd_data_buffer(struct mmc_data *data)
+{
+	return page_address(data->sg->page) + data->sg->offset;
+}
+
 static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
-					unsigned int host_status)
+				 unsigned int host_status)
 {
 	struct mmc_command *cmd = host->req->cmd;
 	unsigned int t_val = 0, cnt = 0;
+	char *buffer;
 
 	if (host_status & TIFM_MMCSD_BRS) {
 		/* in non-dma rx mode BRS fires when fifo is still not empty */
-		if (host->buffer && (cmd->data->flags & MMC_DATA_READ)) {
+		if (no_dma && (cmd->data->flags & MMC_DATA_READ)) {
+			buffer = tifm_sd_data_buffer(host->req->data);
 			while (host->buffer_size > host->buffer_pos) {
 				t_val = readl(sock->addr + SOCK_MMCSD_DATA);
-				host->buffer[host->buffer_pos++] = t_val & 0xff;
-				host->buffer[host->buffer_pos++] =
+				buffer[host->buffer_pos++] = t_val & 0xff;
+				buffer[host->buffer_pos++] =
 							(t_val >> 8) & 0xff;
 			}
 		}
 		return 1;
-	} else if (host->buffer) {
+	} else if (no_dma) {
+		buffer = tifm_sd_data_buffer(host->req->data);
 		if ((cmd->data->flags & MMC_DATA_READ) &&
 				(host_status & TIFM_MMCSD_AF)) {
 			for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
 				t_val = readl(sock->addr + SOCK_MMCSD_DATA);
 				if (host->buffer_size > host->buffer_pos) {
-					host->buffer[host->buffer_pos++] =
+					buffer[host->buffer_pos++] =
 							t_val & 0xff;
-					host->buffer[host->buffer_pos++] =
+					buffer[host->buffer_pos++] =
 							(t_val >> 8) & 0xff;
 				}
 			}
@@ -142,11 +148,12 @@
 			   && (host_status & TIFM_MMCSD_AE)) {
 			for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
 				if (host->buffer_size > host->buffer_pos) {
-					t_val = host->buffer[host->buffer_pos++] & 0x00ff;
-					t_val |= ((host->buffer[host->buffer_pos++]) << 8)
-						 & 0xff00;
+					t_val = buffer[host->buffer_pos++]
+						& 0x00ff;
+					t_val |= ((buffer[host->buffer_pos++])
+						  << 8) & 0xff00;
 					writel(t_val,
-						sock->addr + SOCK_MMCSD_DATA);
+					       sock->addr + SOCK_MMCSD_DATA);
 				}
 			}
 		}
@@ -206,7 +213,7 @@
 		cmd_mask |= TIFM_MMCSD_READ;
 
 	dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n",
-				cmd->opcode, cmd->arg, cmd_mask);
+		cmd->opcode, cmd->arg, cmd_mask);
 
 	writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH);
 	writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW);
@@ -239,65 +246,78 @@
 			tifm_sd_fetch_resp(cmd, sock);
 			if (cmd->data) {
 				host->state = BRS;
-			} else
+			} else {
 				host->state = READY;
+			}
 			goto change_state;
 		}
 		break;
 	case BRS:
 		if (tifm_sd_transfer_data(sock, host, host_status)) {
-			if (!host->req->stop) {
-				if (cmd->data->flags & MMC_DATA_WRITE) {
-					host->state = CARD;
+			if (cmd->data->flags & MMC_DATA_WRITE) {
+				host->state = CARD;
+			} else {
+				if (no_dma) {
+					if (host->req->stop) {
+						tifm_sd_exec(host, host->req->stop);
+						host->state = SCMD;
+					} else {
+						host->state = READY;
+					}
 				} else {
-					host->state =
-						host->buffer ? READY : FIFO;
+					host->state = FIFO;
 				}
-				goto change_state;
 			}
-			tifm_sd_exec(host, host->req->stop);
-			host->state = SCMD;
+			goto change_state;
 		}
 		break;
 	case SCMD:
 		if (host_status & TIFM_MMCSD_EOC) {
 			tifm_sd_fetch_resp(host->req->stop, sock);
-			if (cmd->error) {
-				host->state = READY;
-			} else if (cmd->data->flags & MMC_DATA_WRITE) {
-				host->state = CARD;
-			} else {
-				host->state = host->buffer ? READY : FIFO;
-			}
+			host->state = READY;
 			goto change_state;
 		}
 		break;
 	case CARD:
+		dev_dbg(&sock->dev, "waiting for CARD, have %zd blocks\n",
+			host->written_blocks);
 		if (!(host->flags & CARD_BUSY)
 		    && (host->written_blocks == cmd->data->blocks)) {
-			host->state = host->buffer ? READY : FIFO;
+			if (no_dma) {
+				if (host->req->stop) {
+					tifm_sd_exec(host, host->req->stop);
+					host->state = SCMD;
+				} else {
+					host->state = READY;
+				}
+			} else {
+				host->state = FIFO;
+			}
 			goto change_state;
 		}
 		break;
 	case FIFO:
 		if (host->flags & FIFO_RDY) {
-			host->state = READY;
 			host->flags &= ~FIFO_RDY;
+			if (host->req->stop) {
+				tifm_sd_exec(host, host->req->stop);
+				host->state = SCMD;
+			} else {
+				host->state = READY;
+			}
 			goto change_state;
 		}
 		break;
 	case READY:
-		queue_work(sock->wq, &host->cmd_handler);
+		tasklet_schedule(&host->finish_tasklet);
 		return;
 	}
 
-	queue_delayed_work(sock->wq, &host->abort_handler,
-				host->timeout_jiffies);
 }
 
 /* Called from interrupt handler */
-static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
-					unsigned int sock_irq_status)
+static void tifm_sd_signal_irq(struct tifm_dev *sock,
+			       unsigned int sock_irq_status)
 {
 	struct tifm_sd *host;
 	unsigned int host_status = 0, fifo_status = 0;
@@ -305,7 +325,6 @@
 
 	spin_lock(&sock->lock);
 	host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
-	cancel_delayed_work(&host->abort_handler);
 
 	if (sock_irq_status & FIFO_EVENT) {
 		fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
@@ -318,19 +337,17 @@
 		host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
 		writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
 
-		if (!(host->flags & HOST_REG))
-			queue_work(sock->wq, &host->cmd_handler);
 		if (!host->req)
 			goto done;
 
 		if (host_status & TIFM_MMCSD_ERRMASK) {
 			if (host_status & TIFM_MMCSD_CERR)
 				error_code = MMC_ERR_FAILED;
-			else if (host_status &
-					(TIFM_MMCSD_CTO | TIFM_MMCSD_DTO))
+			else if (host_status
+				 & (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO))
 				error_code = MMC_ERR_TIMEOUT;
-			else if (host_status &
-					(TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
+			else if (host_status
+				 & (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
 				error_code = MMC_ERR_BADCRC;
 
 			writel(TIFM_FIFO_INT_SETALL,
@@ -340,12 +357,11 @@
 			if (host->req->stop) {
 				if (host->state == SCMD) {
 					host->req->stop->error = error_code;
-				} else if(host->state == BRS) {
+				} else if (host->state == BRS
+					   || host->state == CARD
+					   || host->state == FIFO) {
 					host->req->cmd->error = error_code;
 					tifm_sd_exec(host, host->req->stop);
-					queue_delayed_work(sock->wq,
-						&host->abort_handler,
-						host->timeout_jiffies);
 					host->state = SCMD;
 					goto done;
 				} else {
@@ -359,8 +375,8 @@
 
 		if (host_status & TIFM_MMCSD_CB)
 			host->flags |= CARD_BUSY;
-		if ((host_status & TIFM_MMCSD_EOFB) &&
-				(host->flags & CARD_BUSY)) {
+		if ((host_status & TIFM_MMCSD_EOFB)
+		    && (host->flags & CARD_BUSY)) {
 			host->written_blocks++;
 			host->flags &= ~CARD_BUSY;
 		}
@@ -370,22 +386,22 @@
 		tifm_sd_process_cmd(sock, host, host_status);
 done:
 	dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n",
-			host_status, fifo_status);
+		host_status, fifo_status);
 	spin_unlock(&sock->lock);
-	return sock_irq_status;
 }
 
-static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
+static void tifm_sd_prepare_data(struct tifm_sd *host, struct mmc_command *cmd)
 {
-	struct tifm_dev *sock = card->dev;
+	struct tifm_dev *sock = host->dev;
 	unsigned int dest_cnt;
 
 	/* DMA style IO */
-
+	dev_dbg(&sock->dev, "setting dma for %d blocks\n",
+		cmd->data->blocks);
 	writel(TIFM_FIFO_INT_SETALL,
-		sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+	       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
 	writel(ilog2(cmd->data->blksz) - 2,
-			sock->addr + SOCK_FIFO_PAGE_SIZE);
+	       sock->addr + SOCK_FIFO_PAGE_SIZE);
 	writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL);
 	writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
 
@@ -399,7 +415,7 @@
 	if (cmd->data->flags & MMC_DATA_WRITE) {
 		writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
 		writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN,
-			sock->addr + SOCK_DMA_CONTROL);
+		       sock->addr + SOCK_DMA_CONTROL);
 	} else {
 		writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
 		writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL);
@@ -407,7 +423,7 @@
 }
 
 static void tifm_sd_set_data_timeout(struct tifm_sd *host,
-					struct mmc_data *data)
+				     struct mmc_data *data)
 {
 	struct tifm_dev *sock = host->dev;
 	unsigned int data_timeout = data->timeout_clks;
@@ -416,22 +432,21 @@
 		return;
 
 	data_timeout += data->timeout_ns /
-			((1000000000 / host->clk_freq) * host->clk_div);
-	data_timeout *= 10; // call it fudge factor for now
+			((1000000000UL / host->clk_freq) * host->clk_div);
 
 	if (data_timeout < 0xffff) {
-		writel((~TIFM_MMCSD_DPE) &
-				readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
-		       sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
 		writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+		writel((~TIFM_MMCSD_DPE)
+		       & readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+		       sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
 	} else {
-		writel(TIFM_MMCSD_DPE |
-				readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
-			sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
 		data_timeout = (data_timeout >> 10) + 1;
-		if(data_timeout > 0xffff)
+		if (data_timeout > 0xffff)
 			data_timeout = 0;	/* set to unlimited */
 		writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+		writel(TIFM_MMCSD_DPE
+		       | readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+		       sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
 	}
 }
 
@@ -474,11 +489,10 @@
 	}
 
 	host->req = mrq;
+	mod_timer(&host->timer, jiffies + host->timeout_jiffies);
 	host->state = CMD;
-	queue_delayed_work(sock->wq, &host->abort_handler,
-				host->timeout_jiffies);
 	writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
-		sock->addr + SOCK_CONTROL);
+	       sock->addr + SOCK_CONTROL);
 	tifm_sd_exec(host, mrq->cmd);
 	spin_unlock_irqrestore(&sock->lock, flags);
 	return;
@@ -493,9 +507,9 @@
 	mmc_request_done(mmc, mrq);
 }
 
-static void tifm_sd_end_cmd(struct work_struct *work)
+static void tifm_sd_end_cmd(unsigned long data)
 {
-	struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler);
+	struct tifm_sd *host = (struct tifm_sd*)data;
 	struct tifm_dev *sock = host->dev;
 	struct mmc_host *mmc = tifm_get_drvdata(sock);
 	struct mmc_request *mrq;
@@ -504,6 +518,7 @@
 
 	spin_lock_irqsave(&sock->lock, flags);
 
+	del_timer(&host->timer);
 	mrq = host->req;
 	host->req = NULL;
 	host->state = IDLE;
@@ -517,8 +532,8 @@
 	r_data = mrq->cmd->data;
 	if (r_data) {
 		if (r_data->flags & MMC_DATA_WRITE) {
-			r_data->bytes_xfered = host->written_blocks *
-						r_data->blksz;
+			r_data->bytes_xfered = host->written_blocks
+					       * r_data->blksz;
 		} else {
 			r_data->bytes_xfered = r_data->blocks -
 				readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
@@ -532,7 +547,7 @@
 	}
 
 	writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
-			sock->addr + SOCK_CONTROL);
+	       sock->addr + SOCK_CONTROL);
 
 	spin_unlock_irqrestore(&sock->lock, flags);
 	mmc_request_done(mmc, mrq);
@@ -544,15 +559,6 @@
 	struct tifm_dev *sock = host->dev;
 	unsigned long flags;
 	struct mmc_data *r_data = mrq->cmd->data;
-	char *t_buffer = NULL;
-
-	if (r_data) {
-		t_buffer = kmap(r_data->sg->page);
-		if (!t_buffer) {
-			printk(KERN_ERR DRIVER_NAME ": kmap failed\n");
-			goto err_out;
-		}
-	}
 
 	spin_lock_irqsave(&sock->lock, flags);
 	if (host->flags & EJECT) {
@@ -569,15 +575,14 @@
 	if (r_data) {
 		tifm_sd_set_data_timeout(host, r_data);
 
-		host->buffer = t_buffer + r_data->sg->offset;
-		host->buffer_size = mrq->cmd->data->blocks *
-					mrq->cmd->data->blksz;
+		host->buffer_size = mrq->cmd->data->blocks
+				    * mrq->cmd->data->blksz;
 
-		writel(TIFM_MMCSD_BUFINT |
-				readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+		writel(TIFM_MMCSD_BUFINT
+		       | readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
 		       sock->addr + SOCK_MMCSD_INT_ENABLE);
-		writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) |
-				(TIFM_MMCSD_FIFO_SIZE - 1),
+		writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8)
+		       | (TIFM_MMCSD_FIFO_SIZE - 1),
 		       sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
 
 		host->written_blocks = 0;
@@ -588,26 +593,22 @@
 	}
 
 	host->req = mrq;
+	mod_timer(&host->timer, jiffies + host->timeout_jiffies);
 	host->state = CMD;
-	queue_delayed_work(sock->wq, &host->abort_handler,
-				host->timeout_jiffies);
 	writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
-		sock->addr + SOCK_CONTROL);
+	       sock->addr + SOCK_CONTROL);
 	tifm_sd_exec(host, mrq->cmd);
 	spin_unlock_irqrestore(&sock->lock, flags);
 	return;
 
 err_out:
-	if (t_buffer)
-		kunmap(r_data->sg->page);
-
 	mrq->cmd->error = MMC_ERR_TIMEOUT;
 	mmc_request_done(mmc, mrq);
 }
 
-static void tifm_sd_end_cmd_nodma(struct work_struct *work)
+static void tifm_sd_end_cmd_nodma(unsigned long data)
 {
-	struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler);
+	struct tifm_sd *host = (struct tifm_sd*)data;
 	struct tifm_dev *sock = host->dev;
 	struct mmc_host *mmc = tifm_get_drvdata(sock);
 	struct mmc_request *mrq;
@@ -616,6 +617,7 @@
 
 	spin_lock_irqsave(&sock->lock, flags);
 
+	del_timer(&host->timer);
 	mrq = host->req;
 	host->req = NULL;
 	host->state = IDLE;
@@ -633,8 +635,8 @@
 			sock->addr + SOCK_MMCSD_INT_ENABLE);
 
 		if (r_data->flags & MMC_DATA_WRITE) {
-			r_data->bytes_xfered = host->written_blocks *
-						r_data->blksz;
+			r_data->bytes_xfered = host->written_blocks
+					       * r_data->blksz;
 		} else {
 			r_data->bytes_xfered = r_data->blocks -
 				readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
@@ -642,29 +644,44 @@
 			r_data->bytes_xfered += r_data->blksz -
 				readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
 		}
-		host->buffer = NULL;
 		host->buffer_pos = 0;
 		host->buffer_size = 0;
 	}
 
 	writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
-			sock->addr + SOCK_CONTROL);
+	       sock->addr + SOCK_CONTROL);
 
 	spin_unlock_irqrestore(&sock->lock, flags);
 
-        if (r_data)
-		kunmap(r_data->sg->page);
-
 	mmc_request_done(mmc, mrq);
 }
 
-static void tifm_sd_abort(struct work_struct *work)
+static void tifm_sd_terminate(struct tifm_sd *host)
 {
-	struct tifm_sd *host =
-		container_of(work, struct tifm_sd, abort_handler.work);
+	struct tifm_dev *sock = host->dev;
+	unsigned long flags;
+
+	writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+	mmiowb();
+	spin_lock_irqsave(&sock->lock, flags);
+	host->flags |= EJECT;
+	if (host->req) {
+		writel(TIFM_FIFO_INT_SETALL,
+		       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+		writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+		tasklet_schedule(&host->finish_tasklet);
+	}
+	spin_unlock_irqrestore(&sock->lock, flags);
+}
+
+static void tifm_sd_abort(unsigned long data)
+{
+	struct tifm_sd *host = (struct tifm_sd*)data;
 
 	printk(KERN_ERR DRIVER_NAME
-		": card failed to respond for a long period of time");
+	       ": card failed to respond for a long period of time");
+
+	tifm_sd_terminate(host);
 	tifm_eject(host->dev);
 }
 
@@ -683,9 +700,9 @@
 		writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG),
 		       sock->addr + SOCK_MMCSD_CONFIG);
 	} else {
-		writel((~TIFM_MMCSD_4BBUS) &
-				readl(sock->addr + SOCK_MMCSD_CONFIG),
-			sock->addr + SOCK_MMCSD_CONFIG);
+		writel((~TIFM_MMCSD_4BBUS)
+		       & readl(sock->addr + SOCK_MMCSD_CONFIG),
+		       sock->addr + SOCK_MMCSD_CONFIG);
 	}
 
 	if (ios->clock) {
@@ -704,23 +721,24 @@
 		if ((20000000 / clk_div1) > (24000000 / clk_div2)) {
 			host->clk_freq = 20000000;
 			host->clk_div = clk_div1;
-			writel((~TIFM_CTRL_FAST_CLK) &
-					readl(sock->addr + SOCK_CONTROL),
-				sock->addr + SOCK_CONTROL);
+			writel((~TIFM_CTRL_FAST_CLK)
+			       & readl(sock->addr + SOCK_CONTROL),
+			       sock->addr + SOCK_CONTROL);
 		} else {
 			host->clk_freq = 24000000;
 			host->clk_div = clk_div2;
-			writel(TIFM_CTRL_FAST_CLK |
-					readl(sock->addr + SOCK_CONTROL),
-				sock->addr + SOCK_CONTROL);
+			writel(TIFM_CTRL_FAST_CLK
+			       | readl(sock->addr + SOCK_CONTROL),
+			       sock->addr + SOCK_CONTROL);
 		}
 	} else {
 		host->clk_div = 0;
 	}
 	host->clk_div &= TIFM_MMCSD_CLKMASK;
-	writel(host->clk_div | ((~TIFM_MMCSD_CLKMASK) &
-			readl(sock->addr + SOCK_MMCSD_CONFIG)),
-		sock->addr + SOCK_MMCSD_CONFIG);
+	writel(host->clk_div
+	       | ((~TIFM_MMCSD_CLKMASK)
+		  & readl(sock->addr + SOCK_MMCSD_CONFIG)),
+	       sock->addr + SOCK_MMCSD_CONFIG);
 
 	if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
 		host->flags |= OPENDRAIN;
@@ -734,7 +752,7 @@
 	// allow removal.
 	if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) {
 		host->flags |= EJECT_DONE;
-		wake_up_all(&host->can_eject);
+		wake_up_all(&host->notify);
 	}
 
 	spin_unlock_irqrestore(&sock->lock, flags);
@@ -762,20 +780,67 @@
 	.get_ro  = tifm_sd_ro
 };
 
-static void tifm_sd_register_host(struct work_struct *work)
+static int tifm_sd_initialize_host(struct tifm_sd *host)
 {
-	struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler);
+	int rc;
+	unsigned int host_status = 0;
 	struct tifm_dev *sock = host->dev;
-	struct mmc_host *mmc = tifm_get_drvdata(sock);
-	unsigned long flags;
 
-	spin_lock_irqsave(&sock->lock, flags);
-	host->flags |= HOST_REG;
-	PREPARE_WORK(&host->cmd_handler,
-			no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd);
-	spin_unlock_irqrestore(&sock->lock, flags);
-	dev_dbg(&sock->dev, "adding host\n");
-	mmc_add_host(mmc);
+	writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+	mmiowb();
+	host->clk_div = 61;
+	host->clk_freq = 20000000;
+	writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
+	writel(host->clk_div | TIFM_MMCSD_POWER,
+	       sock->addr + SOCK_MMCSD_CONFIG);
+
+	/* wait up to 0.51 sec for reset */
+	for (rc = 2; rc <= 256; rc <<= 1) {
+		if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
+			rc = 0;
+			break;
+		}
+		msleep(rc);
+	}
+
+	if (rc) {
+		printk(KERN_ERR DRIVER_NAME
+		       ": controller failed to reset\n");
+		return -ENODEV;
+	}
+
+	writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
+	writel(host->clk_div | TIFM_MMCSD_POWER,
+	       sock->addr + SOCK_MMCSD_CONFIG);
+	writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+
+	// command timeout fixed to 64 clocks for now
+	writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO);
+	writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
+
+	/* INAB should take much less than reset */
+	for (rc = 1; rc <= 16; rc <<= 1) {
+		host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
+		writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
+		if (!(host_status & TIFM_MMCSD_ERRMASK)
+		    && (host_status & TIFM_MMCSD_EOC)) {
+			rc = 0;
+			break;
+		}
+		msleep(rc);
+	}
+
+	if (rc) {
+		printk(KERN_ERR DRIVER_NAME
+		       ": card not ready - probe failed on initialization\n");
+		return -ENODEV;
+	}
+
+	writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK,
+	       sock->addr + SOCK_MMCSD_INT_ENABLE);
+	mmiowb();
+
+	return 0;
 }
 
 static int tifm_sd_probe(struct tifm_dev *sock)
@@ -784,8 +849,8 @@
 	struct tifm_sd *host;
 	int rc = -EIO;
 
-	if (!(TIFM_SOCK_STATE_OCCUPIED &
-			readl(sock->addr + SOCK_PRESENT_STATE))) {
+	if (!(TIFM_SOCK_STATE_OCCUPIED
+	      & readl(sock->addr + SOCK_PRESENT_STATE))) {
 		printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n");
 		return rc;
 	}
@@ -795,78 +860,42 @@
 		return -ENOMEM;
 
 	host = mmc_priv(mmc);
-	host->dev = sock;
-	host->clk_div = 61;
-	init_waitqueue_head(&host->can_eject);
-	INIT_WORK(&host->cmd_handler, tifm_sd_register_host);
-	INIT_DELAYED_WORK(&host->abort_handler, tifm_sd_abort);
-
 	tifm_set_drvdata(sock, mmc);
-	sock->signal_irq = tifm_sd_signal_irq;
-
-	host->clk_freq = 20000000;
+	host->dev = sock;
 	host->timeout_jiffies = msecs_to_jiffies(1000);
 
+	init_waitqueue_head(&host->notify);
+	tasklet_init(&host->finish_tasklet,
+		     no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd,
+		     (unsigned long)host);
+	setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host);
+
 	tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request;
 	mmc->ops = &tifm_sd_ops;
 	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-	mmc->caps = MMC_CAP_4_BIT_DATA;
+	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE;
 	mmc->f_min = 20000000 / 60;
 	mmc->f_max = 24000000;
 	mmc->max_hw_segs = 1;
 	mmc->max_phys_segs = 1;
-	mmc->max_sectors = 127;
-	mmc->max_seg_size = mmc->max_sectors << 11; //2k maximum hw block length
+	// limited by DMA counter - it's safer to stick with
+	// block counter has 11 bits though
+	mmc->max_blk_count = 256;
+	// 2k maximum hw block length
+	mmc->max_blk_size = 2048;
+	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+	mmc->max_seg_size = mmc->max_req_size;
+	sock->signal_irq = tifm_sd_signal_irq;
+	rc = tifm_sd_initialize_host(host);
 
-	writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
-	writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
-	writel(host->clk_div | TIFM_MMCSD_POWER,
-			sock->addr + SOCK_MMCSD_CONFIG);
-
-	for (rc = 0; rc < 50; rc++) {
-		/* Wait for reset ack */
-		if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
-			rc = 0;
-			break;
-		}
-		msleep(10);
-        }
-
-	if (rc) {
-		printk(KERN_ERR DRIVER_NAME
-			": card not ready - probe failed\n");
-		mmc_free_host(mmc);
-		return -ENODEV;
-	}
-
-	writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
-	writel(host->clk_div | TIFM_MMCSD_POWER,
-			sock->addr + SOCK_MMCSD_CONFIG);
-	writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
-	writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK,
-			sock->addr + SOCK_MMCSD_INT_ENABLE);
-
-	writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); // command timeout 64 clocks for now
-	writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
-	writel(host->clk_div | TIFM_MMCSD_POWER,
-			sock->addr + SOCK_MMCSD_CONFIG);
-
-	queue_delayed_work(sock->wq, &host->abort_handler,
-			host->timeout_jiffies);
+	if (!rc)
+		rc = mmc_add_host(mmc);
+	if (rc)
+		goto out_free_mmc;
 
 	return 0;
-}
-
-static int tifm_sd_host_is_down(struct tifm_dev *sock)
-{
-	struct mmc_host *mmc = tifm_get_drvdata(sock);
-	struct tifm_sd *host = mmc_priv(mmc);
-	unsigned long flags;
-	int rc = 0;
-
-	spin_lock_irqsave(&sock->lock, flags);
-	rc = (host->flags & EJECT_DONE);
-	spin_unlock_irqrestore(&sock->lock, flags);
+out_free_mmc:
+	mmc_free_host(mmc);
 	return rc;
 }
 
@@ -874,31 +903,57 @@
 {
 	struct mmc_host *mmc = tifm_get_drvdata(sock);
 	struct tifm_sd *host = mmc_priv(mmc);
-	unsigned long flags;
 
-	spin_lock_irqsave(&sock->lock, flags);
-	host->flags |= EJECT;
-	if (host->req)
-		queue_work(sock->wq, &host->cmd_handler);
-	spin_unlock_irqrestore(&sock->lock, flags);
-	wait_event_timeout(host->can_eject, tifm_sd_host_is_down(sock),
-				host->timeout_jiffies);
-
-	if (host->flags & HOST_REG)
-		mmc_remove_host(mmc);
+	del_timer_sync(&host->timer);
+	tifm_sd_terminate(host);
+	wait_event_timeout(host->notify, host->flags & EJECT_DONE,
+			   host->timeout_jiffies);
+	tasklet_kill(&host->finish_tasklet);
+	mmc_remove_host(mmc);
 
 	/* The meaning of the bit majority in this constant is unknown. */
 	writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
-		sock->addr + SOCK_CONTROL);
-	writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
-	writel(TIFM_FIFO_INT_SETALL,
-		sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
-	writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+	       sock->addr + SOCK_CONTROL);
 
 	tifm_set_drvdata(sock, NULL);
 	mmc_free_host(mmc);
 }
 
+#ifdef CONFIG_PM
+
+static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
+{
+	struct mmc_host *mmc = tifm_get_drvdata(sock);
+	int rc;
+
+	rc = mmc_suspend_host(mmc, state);
+	/* The meaning of the bit majority in this constant is unknown. */
+	writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
+	       sock->addr + SOCK_CONTROL);
+	return rc;
+}
+
+static int tifm_sd_resume(struct tifm_dev *sock)
+{
+	struct mmc_host *mmc = tifm_get_drvdata(sock);
+	struct tifm_sd *host = mmc_priv(mmc);
+
+	if (sock->media_id != FM_SD
+	    || tifm_sd_initialize_host(host)) {
+		tifm_eject(sock);
+		return 0;
+	} else {
+		return mmc_resume_host(mmc);
+	}
+}
+
+#else
+
+#define tifm_sd_suspend NULL
+#define tifm_sd_resume NULL
+
+#endif /* CONFIG_PM */
+
 static tifm_media_id tifm_sd_id_tbl[] = {
 	FM_SD, 0
 };
@@ -910,7 +965,9 @@
 	},
 	.id_table = tifm_sd_id_tbl,
 	.probe    = tifm_sd_probe,
-	.remove   = tifm_sd_remove
+	.remove   = tifm_sd_remove,
+	.suspend  = tifm_sd_suspend,
+	.resume   = tifm_sd_resume
 };
 
 static int __init tifm_sd_init(void)
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
index 7a28267..a44d877 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -1,7 +1,7 @@
 /*
  *  linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver
  *
- *  Copyright (C) 2004-2005 Pierre Ossman, All Rights Reserved.
+ *  Copyright (C) 2004-2006 Pierre Ossman, All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -272,16 +272,9 @@
 	return host->num_sg;
 }
 
-static inline char *wbsd_kmap_sg(struct wbsd_host *host)
+static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
 {
-	host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ) +
-		host->cur_sg->offset;
-	return host->mapped_sg;
-}
-
-static inline void wbsd_kunmap_sg(struct wbsd_host *host)
-{
-	kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
+	return page_address(host->cur_sg->page) + host->cur_sg->offset;
 }
 
 static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
@@ -302,12 +295,11 @@
 	 * we do not transfer too much.
 	 */
 	for (i = 0; i < len; i++) {
-		sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset;
+		sgbuf = page_address(sg[i].page) + sg[i].offset;
 		if (size < sg[i].length)
 			memcpy(dmabuf, sgbuf, size);
 		else
 			memcpy(dmabuf, sgbuf, sg[i].length);
-		kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ);
 		dmabuf += sg[i].length;
 
 		if (size < sg[i].length)
@@ -347,7 +339,7 @@
 	 * we do not transfer too much.
 	 */
 	for (i = 0; i < len; i++) {
-		sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset;
+		sgbuf = page_address(sg[i].page) + sg[i].offset;
 		if (size < sg[i].length)
 			memcpy(sgbuf, dmabuf, size);
 		else
@@ -497,7 +489,7 @@
 	if (data->bytes_xfered == host->size)
 		return;
 
-	buffer = wbsd_kmap_sg(host) + host->offset;
+	buffer = wbsd_sg_to_buffer(host) + host->offset;
 
 	/*
 	 * Drain the fifo. This has a tendency to loop longer
@@ -526,17 +518,13 @@
 			/*
 			 * Transfer done?
 			 */
-			if (data->bytes_xfered == host->size) {
-				wbsd_kunmap_sg(host);
+			if (data->bytes_xfered == host->size)
 				return;
-			}
 
 			/*
 			 * End of scatter list entry?
 			 */
 			if (host->remain == 0) {
-				wbsd_kunmap_sg(host);
-
 				/*
 				 * Get next entry. Check if last.
 				 */
@@ -554,13 +542,11 @@
 					return;
 				}
 
-				buffer = wbsd_kmap_sg(host);
+				buffer = wbsd_sg_to_buffer(host);
 			}
 		}
 	}
 
-	wbsd_kunmap_sg(host);
-
 	/*
 	 * This is a very dirty hack to solve a
 	 * hardware problem. The chip doesn't trigger
@@ -583,7 +569,7 @@
 	if (data->bytes_xfered == host->size)
 		return;
 
-	buffer = wbsd_kmap_sg(host) + host->offset;
+	buffer = wbsd_sg_to_buffer(host) + host->offset;
 
 	/*
 	 * Fill the fifo. This has a tendency to loop longer
@@ -612,17 +598,13 @@
 			/*
 			 * Transfer done?
 			 */
-			if (data->bytes_xfered == host->size) {
-				wbsd_kunmap_sg(host);
+			if (data->bytes_xfered == host->size)
 				return;
-			}
 
 			/*
 			 * End of scatter list entry?
 			 */
 			if (host->remain == 0) {
-				wbsd_kunmap_sg(host);
-
 				/*
 				 * Get next entry. Check if last.
 				 */
@@ -640,13 +622,11 @@
 					return;
 				}
 
-				buffer = wbsd_kmap_sg(host);
+				buffer = wbsd_sg_to_buffer(host);
 			}
 		}
 	}
 
-	wbsd_kunmap_sg(host);
-
 	/*
 	 * The controller stops sending interrupts for
 	 * 'FIFO empty' under certain conditions. So we
@@ -910,6 +890,45 @@
 	 */
 	if (cmd->data && (cmd->error == MMC_ERR_NONE)) {
 		/*
+		 * The hardware is so delightfully stupid that it has a list
+		 * of "data" commands. If a command isn't on this list, it'll
+		 * just go back to the idle state and won't send any data
+		 * interrupts.
+		 */
+		switch (cmd->opcode) {
+		case 11:
+		case 17:
+		case 18:
+		case 20:
+		case 24:
+		case 25:
+		case 26:
+		case 27:
+		case 30:
+		case 42:
+		case 56:
+			break;
+
+		/* ACMDs. We don't keep track of state, so we just treat them
+		 * like any other command. */
+		case 51:
+			break;
+
+		default:
+#ifdef CONFIG_MMC_DEBUG
+			printk(KERN_WARNING "%s: Data command %d is not "
+				"supported by this controller.\n",
+				mmc_hostname(host->mmc), cmd->opcode);
+#endif
+			cmd->data->error = MMC_ERR_INVALID;
+
+			if (cmd->data->stop)
+				wbsd_send_command(host, cmd->data->stop);
+
+			goto done;
+		};
+
+		/*
 		 * Dirty fix for hardware bug.
 		 */
 		if (host->dma == -1)
@@ -1343,16 +1362,27 @@
 	mmc->max_phys_segs = 128;
 
 	/*
-	 * Maximum number of sectors in one transfer. Also limited by 64kB
-	 * buffer.
+	 * Maximum request size. Also limited by 64KiB buffer.
 	 */
-	mmc->max_sectors = 128;
+	mmc->max_req_size = 65536;
 
 	/*
 	 * Maximum segment size. Could be one segment with the maximum number
-	 * of segments.
+	 * of bytes.
 	 */
-	mmc->max_seg_size = mmc->max_sectors * 512;
+	mmc->max_seg_size = mmc->max_req_size;
+
+	/*
+	 * Maximum block size. We have 12 bits (= 4095) but have to subtract
+	 * space for CRC. So the maximum is 4095 - 4*2 = 4087.
+	 */
+	mmc->max_blk_size = 4087;
+
+	/*
+	 * Maximum block count. There is no real limit so the maximum
+	 * request size will be the only restriction.
+	 */
+	mmc->max_blk_count = mmc->max_req_size;
 
 	dev_set_drvdata(dev, mmc);
 
diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h
index 6072993..d06718b 100644
--- a/drivers/mmc/wbsd.h
+++ b/drivers/mmc/wbsd.h
@@ -154,7 +154,6 @@
 
 	struct scatterlist*	cur_sg;		/* Current SG entry */
 	unsigned int		num_sg;		/* Number of entries left */
-	void*			mapped_sg;	/* vaddr of mapped sg */
 
 	unsigned int		offset;		/* Offset into current entry */
 	unsigned int		remain;		/* Data left in curren entry */
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index 7e34c4f..bc7e906 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -600,8 +600,7 @@
 	    count -= semi_count;
 	    memcpy_fromio(skb->data + semi_count, base + ei_status.priv, count);
 	} else {
-		/* Packet is in one chunk -- we can copy + cksum. */
-		eth_io_copy_and_sum(skb, base + ring_offset, count, 0);
+		memcpy_fromio(skb->data, base + ring_offset, count);
 	}
 	return;
     }
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 80bdcf8..716a472 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -792,8 +792,7 @@
 {
 	struct vortex_private *vp = netdev_priv(dev);
 	unsigned long flags;
-	local_save_flags(flags);
-	local_irq_disable();
+	local_irq_save(flags);
 	(vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev);
 	local_irq_restore(flags);
 }
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 8aa8dd0..38f41a5 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -190,7 +190,7 @@
 
 config MACB
 	tristate "Atmel MACB support"
-	depends on NET_ETHERNET && AVR32
+	depends on NET_ETHERNET && (AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263)
 	select MII
 	help
 	  The Atmel MACB ethernet interface is found on many AT32 and AT91
@@ -235,16 +235,6 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called bmac.
 
-config OAKNET
-	tristate "National DP83902AV (Oak ethernet) support"
-	depends on NET_ETHERNET && PPC && BROKEN
-	select CRC32
-	help
-	  Say Y if your machine has this type of Ethernet network card.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called oaknet.
-
 config ARIADNE
 	tristate "Ariadne support"
 	depends on NET_ETHERNET && ZORRO
@@ -1155,21 +1145,6 @@
 	  <file:Documentation/networking/net-modules.txt>. The module
 	  will be called seeq8005.
 
-config SKMC
-	tristate "SKnet MCA support"
-	depends on NET_ETHERNET && MCA && BROKEN
-	---help---
-	  These are Micro Channel Ethernet adapters. You need to say Y to "MCA
-	  support" in order to use this driver.  Supported cards are the SKnet
-	  Junior MC2 and the SKnet MC2(+).  The driver automatically
-	  distinguishes between the two cards. Note that using multiple boards
-	  of different type hasn't been tested with this driver.  Say Y if you
-	  have one of these Ethernet adapters.
-
-	  To compile this driver as a module, choose M here and read
-	  <file:Documentation/networking/net-modules.txt>. The module
-	  will be called sk_mca.
-
 config NE2_MCA
 	tristate "NE/2 (ne2000 MCA version) support"
 	depends on NET_ETHERNET && MCA_LEGACY
@@ -1788,6 +1763,18 @@
 	  workstations.
 	  See <http://www.semiconductors.philips.com/pip/SAA9730_flyer_1>.
 
+config SC92031
+	tristate "Silan SC92031 PCI Fast Ethernet Adapter driver (EXPERIMENTAL)"
+	depends on NET_PCI && PCI && EXPERIMENTAL
+	select CRC32
+	---help---
+	  This is a driver for the Fast Ethernet PCI network cards based on
+	  the Silan SC92031 chip (sometimes also called Rsltek 8139D). If you
+	  have one of these, say Y here.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called sc92031.  This is recommended.
+
 config NET_POCKET
 	bool "Pocket and portable adapters"
 	depends on NET_ETHERNET && PARPORT
@@ -2348,6 +2335,17 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called qla3xxx.
 
+config ATL1
+	tristate "Attansic L1 Gigabit Ethernet support (EXPERIMENTAL)"
+	depends on NET_PCI && PCI && EXPERIMENTAL
+	select CRC32
+	select MII
+	help
+	  This driver supports the Attansic L1 gigabit ethernet adapter.
+
+	  To compile this driver as a module, choose M here.  The module
+	  will be called atl1.
+
 endmenu
 
 #
@@ -2392,6 +2390,24 @@
 	  NAPI is a driver API designed to reduce CPU and interrupt load
 	  when the driver is receiving lots of packets from the card.
 
+config CHELSIO_T3
+        tristate "Chelsio Communications T3 10Gb Ethernet support"
+        depends on PCI
+        help
+          This driver supports Chelsio T3-based gigabit and 10Gb Ethernet
+          adapters.
+
+          For general information about Chelsio and our products, visit
+          our website at <http://www.chelsio.com>.
+
+          For customer support, please visit our customer support page at
+          <http://www.chelsio.com/support.htm>.
+
+          Please send feedback to <linux-bugs@chelsio.com>.
+
+          To compile this driver as a module, choose M here: the module
+          will be called cxgb3.
+
 config EHEA
 	tristate "eHEA Ethernet support"
 	depends on IBMEBUS
@@ -2488,6 +2504,13 @@
 	help
 	  This enables the support for NetXen's Gigabit Ethernet card.
 
+config PASEMI_MAC
+	tristate "PA Semi 1/10Gbit MAC"
+	depends on PPC64 && PCI
+	help
+	  This driver supports the on-chip 1/10Gbit Ethernet controller on
+	  PA Semi's PWRficient line of chips.
+
 endmenu
 
 source "drivers/net/tokenring/Kconfig"
@@ -2522,7 +2545,7 @@
 
 config FDDI
 	bool "FDDI driver support"
-	depends on (PCI || EISA)
+	depends on (PCI || EISA || TC)
 	help
 	  Fiber Distributed Data Interface is a high speed local area network
 	  design; essentially a replacement for high speed Ethernet. FDDI can
@@ -2532,15 +2555,36 @@
 	  will say N.
 
 config DEFXX
-	tristate "Digital DEFEA and DEFPA adapter support"
-	depends on FDDI && (PCI || EISA)
-	help
-	  This is support for the DIGITAL series of EISA (DEFEA) and PCI
-	  (DEFPA) controllers which can connect you to a local FDDI network.
+	tristate "Digital DEFTA/DEFEA/DEFPA adapter support"
+	depends on FDDI && (PCI || EISA || TC)
+	---help---
+	  This is support for the DIGITAL series of TURBOchannel (DEFTA),
+	  EISA (DEFEA) and PCI (DEFPA) controllers which can connect you
+	  to a local FDDI network.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called defxx.  If unsure, say N.
+
+config DEFXX_MMIO
+	bool
+	prompt "Use MMIO instead of PIO" if PCI || EISA
+	depends on DEFXX
+	default n if PCI || EISA
+	default y
+	---help---
+	  This instructs the driver to use EISA or PCI memory-mapped I/O
+	  (MMIO) as appropriate instead of programmed I/O ports (PIO).
+	  Enabling this gives an improvement in processing time in parts
+	  of the driver, but it may cause problems with EISA (DEFEA)
+	  adapters.  TURBOchannel does not have the concept of I/O ports,
+	  so MMIO is always used for these (DEFTA) adapters.
+
+	  If unsure, say N.
 
 config SKFP
 	tristate "SysKonnect FDDI PCI support"
 	depends on FDDI && PCI
+	select BITREVERSE
 	---help---
 	  Say Y here if you have a SysKonnect FDDI PCI adapter.
 	  The following adapters are supported by this driver:
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 4c0d4e5..33af833 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -6,8 +6,10 @@
 obj-$(CONFIG_IBM_EMAC) += ibm_emac/
 obj-$(CONFIG_IXGB) += ixgb/
 obj-$(CONFIG_CHELSIO_T1) += chelsio/
+obj-$(CONFIG_CHELSIO_T3) += cxgb3/
 obj-$(CONFIG_EHEA) += ehea/
 obj-$(CONFIG_BONDING) += bonding/
+obj-$(CONFIG_ATL1) += atl1/
 obj-$(CONFIG_GIANFAR) += gianfar_driver.o
 
 gianfar_driver-objs := gianfar.o \
@@ -36,8 +38,6 @@
 obj-$(CONFIG_MACE) += mace.o
 obj-$(CONFIG_BMAC) += bmac.o
 
-obj-$(CONFIG_OAKNET) += oaknet.o 8390.o
-
 obj-$(CONFIG_DGRS) += dgrs.o
 obj-$(CONFIG_VORTEX) += 3c59x.o
 obj-$(CONFIG_TYPHOON) += typhoon.o
@@ -137,7 +137,6 @@
 obj-$(CONFIG_EL1) += 3c501.o
 obj-$(CONFIG_EL16) += 3c507.o
 obj-$(CONFIG_ELMC) += 3c523.o
-obj-$(CONFIG_SKMC) += sk_mca.o
 obj-$(CONFIG_IBMLANA) += ibmlana.o
 obj-$(CONFIG_ELMC_II) += 3c527.o
 obj-$(CONFIG_EL3) += 3c509.o
@@ -160,6 +159,7 @@
 obj-$(CONFIG_LASI_82596) += lasi_82596.o
 obj-$(CONFIG_MVME16x_NET) += 82596.o
 obj-$(CONFIG_BVME6000_NET) += 82596.o
+obj-$(CONFIG_SC92031) += sc92031.o
 
 # This is also a 82596 and should probably be merged
 obj-$(CONFIG_LP486E) += lp486e.o
@@ -196,6 +196,7 @@
 obj-$(CONFIG_SMC911X) += smc911x.o
 obj-$(CONFIG_DM9000) += dm9000.o
 obj-$(CONFIG_FEC_8XX) += fec_8xx/
+obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o
 
 obj-$(CONFIG_MACB) += macb.o
 
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 9305eb9..dd8ed45 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -59,7 +59,6 @@
 extern struct net_device *arlan_probe(int unit);
 extern struct net_device *el16_probe(int unit);
 extern struct net_device *elmc_probe(int unit);
-extern struct net_device *skmca_probe(int unit);
 extern struct net_device *elplus_probe(int unit);
 extern struct net_device *ac3200_probe(int unit);
 extern struct net_device *es_probe(int unit);
@@ -153,9 +152,6 @@
 #ifdef CONFIG_ELMC_II		/* 3c527 */
 	{mc32_probe, 0},
 #endif
-#ifdef CONFIG_SKMC              /* SKnet Microchannel */
-        {skmca_probe, 0},
-#endif
 	{NULL, 0},
 };
 
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index c01f87f..644c408 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -327,8 +327,7 @@
 		memcpy_fromio(skb->data + semi_count,
 				ei_status.mem + TX_PAGES*256, count);
 	} else {
-		/* Packet is in one chunk -- we can copy + cksum. */
-		eth_io_copy_and_sum(skb, start, count, 0);
+		memcpy_fromio(skb->data, start, count);
 	}
 }
 
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index 18896f2..9c399aa 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -1334,8 +1334,7 @@
 static void amd8111e_poll(struct net_device *dev)
 {
 	unsigned long flags;
-	local_save_flags(flags);
-	local_irq_disable();
+	local_irq_save(flags);
 	amd8111e_interrupt(0, dev);
 	local_irq_restore(flags);
 }
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index fada15d..1621b8f 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -641,7 +641,7 @@
 {
 	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
 	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
-	strlcpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+	strlcpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info));
 }
 
 static const struct ethtool_ops at91ether_ethtool_ops = {
diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c
index f3faa4f..72c41f5 100644
--- a/drivers/net/arm/etherh.c
+++ b/drivers/net/arm/etherh.c
@@ -587,7 +587,7 @@
 {
 	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
 	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
-	strlcpy(info->bus_info, dev->class_dev.dev->bus_id,
+	strlcpy(info->bus_info, dev->dev.parent->bus_id,
 		sizeof(info->bus_info));
 }
 
diff --git a/drivers/net/atl1/Makefile b/drivers/net/atl1/Makefile
new file mode 100644
index 0000000..a6b707e
--- /dev/null
+++ b/drivers/net/atl1/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_ATL1)	+= atl1.o
+atl1-y			+= atl1_main.o atl1_hw.o atl1_ethtool.o atl1_param.o
diff --git a/drivers/net/atl1/atl1.h b/drivers/net/atl1/atl1.h
new file mode 100644
index 0000000..b1c6034
--- /dev/null
+++ b/drivers/net/atl1/atl1.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _ATL1_H_
+#define _ATL1_H_
+
+#include <linux/types.h>
+#include <linux/if_vlan.h>
+
+#include "atl1_hw.h"
+
+/* function prototypes needed by multiple files */
+s32 atl1_up(struct atl1_adapter *adapter);
+void atl1_down(struct atl1_adapter *adapter);
+int atl1_reset(struct atl1_adapter *adapter);
+s32 atl1_setup_ring_resources(struct atl1_adapter *adapter);
+void atl1_free_ring_resources(struct atl1_adapter *adapter);
+
+extern char atl1_driver_name[];
+extern char atl1_driver_version[];
+extern const struct ethtool_ops atl1_ethtool_ops;
+
+struct atl1_adapter;
+
+#define ATL1_MAX_INTR		3
+
+#define ATL1_DEFAULT_TPD	256
+#define ATL1_MAX_TPD		1024
+#define ATL1_MIN_TPD		64
+#define ATL1_DEFAULT_RFD	512
+#define ATL1_MIN_RFD		128
+#define ATL1_MAX_RFD		2048
+
+#define ATL1_GET_DESC(R, i, type)	(&(((type *)((R)->desc))[i]))
+#define ATL1_RFD_DESC(R, i)	ATL1_GET_DESC(R, i, struct rx_free_desc)
+#define ATL1_TPD_DESC(R, i)	ATL1_GET_DESC(R, i, struct tx_packet_desc)
+#define ATL1_RRD_DESC(R, i)	ATL1_GET_DESC(R, i, struct rx_return_desc)
+
+/*
+ * Some workarounds require millisecond delays and are run during interrupt
+ * context.  Most notably, when establishing link, the phy may need tweaking
+ * but cannot process phy register reads/writes faster than millisecond
+ * intervals...and we establish link due to a "link status change" interrupt.
+ */
+
+/*
+ * wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer
+ */
+struct atl1_buffer {
+	struct sk_buff *skb;
+	u16 length;
+	u16 alloced;
+	dma_addr_t dma;
+};
+
+#define MAX_TX_BUF_LEN		0x3000	/* 12KB */
+
+struct atl1_tpd_ring {
+	void *desc;		/* pointer to the descriptor ring memory */
+	dma_addr_t dma;		/* physical adress of the descriptor ring */
+	u16 size;		/* length of descriptor ring in bytes */
+	u16 count;		/* number of descriptors in the ring */
+	u16 hw_idx;		/* hardware index */
+	atomic_t next_to_clean;
+	atomic_t next_to_use;
+	struct atl1_buffer *buffer_info;
+};
+
+struct atl1_rfd_ring {
+	void *desc;
+	dma_addr_t dma;
+	u16 size;
+	u16 count;
+	atomic_t next_to_use;
+	u16 next_to_clean;
+	struct atl1_buffer *buffer_info;
+};
+
+struct atl1_rrd_ring {
+	void *desc;
+	dma_addr_t dma;
+	unsigned int size;
+	u16 count;
+	u16 next_to_use;
+	atomic_t next_to_clean;
+};
+
+struct atl1_ring_header {
+	void *desc;		/* pointer to the descriptor ring memory */
+	dma_addr_t dma;		/* physical adress of the descriptor ring */
+	unsigned int size;	/* length of descriptor ring in bytes */
+};
+
+struct atl1_cmb {
+	struct coals_msg_block *cmb;
+	dma_addr_t dma;
+};
+
+struct atl1_smb {
+	struct stats_msg_block *smb;
+	dma_addr_t dma;
+};
+
+/* Statistics counters */
+struct atl1_sft_stats {
+	u64 rx_packets;
+	u64 tx_packets;
+	u64 rx_bytes;
+	u64 tx_bytes;
+	u64 multicast;
+	u64 collisions;
+	u64 rx_errors;
+	u64 rx_length_errors;
+	u64 rx_crc_errors;
+	u64 rx_frame_errors;
+	u64 rx_fifo_errors;
+	u64 rx_missed_errors;
+	u64 tx_errors;
+	u64 tx_fifo_errors;
+	u64 tx_aborted_errors;
+	u64 tx_window_errors;
+	u64 tx_carrier_errors;
+
+	u64 tx_pause;		/* num Pause packet transmitted. */
+	u64 excecol;		/* num tx packets aborted due to excessive collisions. */
+	u64 deffer;		/* num deferred tx packets */
+	u64 scc;		/* num packets subsequently transmitted successfully w/ single prior collision. */
+	u64 mcc;		/* num packets subsequently transmitted successfully w/ multiple prior collisions. */
+	u64 latecol;		/* num tx packets  w/ late collisions. */
+	u64 tx_underun;		/* num tx packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */
+	u64 tx_trunc;		/* num tx packets truncated due to size exceeding MTU, regardless whether truncated by Selene or not. (The name doesn't really reflect the meaning in this case.) */
+	u64 rx_pause;		/* num Pause packets received. */
+	u64 rx_rrd_ov;
+	u64 rx_trunc;
+};
+
+/* board specific private data structure */
+#define ATL1_REGS_LEN	8
+
+/* Structure containing variables used by the shared code */
+struct atl1_hw {
+	u8 __iomem *hw_addr;
+	struct atl1_adapter *back;
+	enum atl1_dma_order dma_ord;
+	enum atl1_dma_rcb rcb_value;
+	enum atl1_dma_req_block dmar_block;
+	enum atl1_dma_req_block dmaw_block;
+	u8 preamble_len;
+	u8 max_retry;		/* Retransmission maximum, after which the packet will be discarded */
+	u8 jam_ipg;		/* IPG to start JAM for collision based flow control in half-duplex mode. In units of 8-bit time */
+	u8 ipgt;		/* Desired back to back inter-packet gap. The default is 96-bit time */
+	u8 min_ifg;		/* Minimum number of IFG to enforce in between RX frames. Frame gap below such IFP is dropped */
+	u8 ipgr1;		/* 64bit Carrier-Sense window */
+	u8 ipgr2;		/* 96-bit IPG window */
+	u8 tpd_burst;		/* Number of TPD to prefetch in cache-aligned burst. Each TPD is 16 bytes long */
+	u8 rfd_burst;		/* Number of RFD to prefetch in cache-aligned burst. Each RFD is 12 bytes long */
+	u8 rfd_fetch_gap;
+	u8 rrd_burst;		/* Threshold number of RRDs that can be retired in a burst. Each RRD is 16 bytes long */
+	u8 tpd_fetch_th;
+	u8 tpd_fetch_gap;
+	u16 tx_jumbo_task_th;
+	u16 txf_burst;		/* Number of data bytes to read in a cache-aligned burst. Each SRAM entry is
+				   8 bytes long */
+	u16 rx_jumbo_th;	/* Jumbo packet size for non-VLAN packet. VLAN packets should add 4 bytes */
+	u16 rx_jumbo_lkah;
+	u16 rrd_ret_timer;	/* RRD retirement timer. Decrement by 1 after every 512ns passes. */
+	u16 lcol;		/* Collision Window */
+
+	u16 cmb_tpd;
+	u16 cmb_rrd;
+	u16 cmb_rx_timer;
+	u16 cmb_tx_timer;
+	u32 smb_timer;
+	u16 media_type;
+	u16 autoneg_advertised;
+	u16 pci_cmd_word;
+
+	u16 mii_autoneg_adv_reg;
+	u16 mii_1000t_ctrl_reg;
+
+	u32 mem_rang;
+	u32 txcw;
+	u32 max_frame_size;
+	u32 min_frame_size;
+	u32 mc_filter_type;
+	u32 num_mc_addrs;
+	u32 collision_delta;
+	u32 tx_packet_delta;
+	u16 phy_spd_default;
+
+	u16 dev_rev;
+	u8 revision_id;
+
+	/* spi flash */
+	u8 flash_vendor;
+
+	u8 dma_fairness;
+	u8 mac_addr[ETH_ALEN];
+	u8 perm_mac_addr[ETH_ALEN];
+
+	/* bool phy_preamble_sup; */
+	bool phy_configured;
+};
+
+struct atl1_adapter {
+	/* OS defined structs */
+	struct net_device *netdev;
+	struct pci_dev *pdev;
+	struct net_device_stats net_stats;
+	struct atl1_sft_stats soft_stats;
+
+	struct vlan_group *vlgrp;
+	u32 rx_buffer_len;
+	u32 wol;
+	u16 link_speed;
+	u16 link_duplex;
+	spinlock_t lock;
+	atomic_t irq_sem;
+	struct work_struct tx_timeout_task;
+	struct work_struct link_chg_task;
+	struct work_struct pcie_dma_to_rst_task;
+	struct timer_list watchdog_timer;
+	struct timer_list phy_config_timer;
+	bool phy_timer_pending;
+
+	bool mac_disabled;
+
+	/* All descriptor rings' memory */
+	struct atl1_ring_header ring_header;
+
+	/* TX */
+	struct atl1_tpd_ring tpd_ring;
+	spinlock_t mb_lock;
+
+	/* RX */
+	struct atl1_rfd_ring rfd_ring;
+	struct atl1_rrd_ring rrd_ring;
+	u64 hw_csum_err;
+	u64 hw_csum_good;
+
+	u32 gorcl;
+	u64 gorcl_old;
+
+	/* Interrupt Moderator timer ( 2us resolution) */
+	u16 imt;
+	/* Interrupt Clear timer (2us resolution) */
+	u16 ict;
+
+	/* MII interface info */
+	struct mii_if_info mii;
+
+	/* structs defined in atl1_hw.h */
+	u32 bd_number;		/* board number */
+	bool pci_using_64;
+	struct atl1_hw hw;
+	struct atl1_smb smb;
+	struct atl1_cmb cmb;
+
+	u32 pci_state[16];
+};
+
+#endif	/* _ATL1_H_ */
diff --git a/drivers/net/atl1/atl1_ethtool.c b/drivers/net/atl1/atl1_ethtool.c
new file mode 100644
index 0000000..c11c277
--- /dev/null
+++ b/drivers/net/atl1/atl1_ethtool.c
@@ -0,0 +1,508 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/mii.h>
+#include <asm/uaccess.h>
+
+#include "atl1.h"
+
+struct atl1_stats {
+	char stat_string[ETH_GSTRING_LEN];
+	int sizeof_stat;
+	int stat_offset;
+};
+
+#define ATL1_STAT(m) sizeof(((struct atl1_adapter *)0)->m), \
+	offsetof(struct atl1_adapter, m)
+
+static struct atl1_stats atl1_gstrings_stats[] = {
+	{"rx_packets", ATL1_STAT(soft_stats.rx_packets)},
+	{"tx_packets", ATL1_STAT(soft_stats.tx_packets)},
+	{"rx_bytes", ATL1_STAT(soft_stats.rx_bytes)},
+	{"tx_bytes", ATL1_STAT(soft_stats.tx_bytes)},
+	{"rx_errors", ATL1_STAT(soft_stats.rx_errors)},
+	{"tx_errors", ATL1_STAT(soft_stats.tx_errors)},
+	{"rx_dropped", ATL1_STAT(net_stats.rx_dropped)},
+	{"tx_dropped", ATL1_STAT(net_stats.tx_dropped)},
+	{"multicast", ATL1_STAT(soft_stats.multicast)},
+	{"collisions", ATL1_STAT(soft_stats.collisions)},
+	{"rx_length_errors", ATL1_STAT(soft_stats.rx_length_errors)},
+	{"rx_over_errors", ATL1_STAT(soft_stats.rx_missed_errors)},
+	{"rx_crc_errors", ATL1_STAT(soft_stats.rx_crc_errors)},
+	{"rx_frame_errors", ATL1_STAT(soft_stats.rx_frame_errors)},
+	{"rx_fifo_errors", ATL1_STAT(soft_stats.rx_fifo_errors)},
+	{"rx_missed_errors", ATL1_STAT(soft_stats.rx_missed_errors)},
+	{"tx_aborted_errors", ATL1_STAT(soft_stats.tx_aborted_errors)},
+	{"tx_carrier_errors", ATL1_STAT(soft_stats.tx_carrier_errors)},
+	{"tx_fifo_errors", ATL1_STAT(soft_stats.tx_fifo_errors)},
+	{"tx_window_errors", ATL1_STAT(soft_stats.tx_window_errors)},
+	{"tx_abort_exce_coll", ATL1_STAT(soft_stats.excecol)},
+	{"tx_abort_late_coll", ATL1_STAT(soft_stats.latecol)},
+	{"tx_deferred_ok", ATL1_STAT(soft_stats.deffer)},
+	{"tx_single_coll_ok", ATL1_STAT(soft_stats.scc)},
+	{"tx_multi_coll_ok", ATL1_STAT(soft_stats.mcc)},
+	{"tx_underun", ATL1_STAT(soft_stats.tx_underun)},
+	{"tx_trunc", ATL1_STAT(soft_stats.tx_trunc)},
+	{"tx_pause", ATL1_STAT(soft_stats.tx_pause)},
+	{"rx_pause", ATL1_STAT(soft_stats.rx_pause)},
+	{"rx_rrd_ov", ATL1_STAT(soft_stats.rx_rrd_ov)},
+	{"rx_trunc", ATL1_STAT(soft_stats.rx_trunc)}
+};
+
+static void atl1_get_ethtool_stats(struct net_device *netdev,
+				struct ethtool_stats *stats, u64 *data)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	int i;
+	char *p;
+
+	for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) {
+		p = (char *)adapter+atl1_gstrings_stats[i].stat_offset;
+		data[i] = (atl1_gstrings_stats[i].sizeof_stat ==
+			sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+	}
+
+}
+
+static int atl1_get_stats_count(struct net_device *netdev)
+{
+	return ARRAY_SIZE(atl1_gstrings_stats);
+}
+
+static int atl1_get_settings(struct net_device *netdev,
+				struct ethtool_cmd *ecmd)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	struct atl1_hw *hw = &adapter->hw;
+
+	ecmd->supported = (SUPPORTED_10baseT_Half |
+			   SUPPORTED_10baseT_Full |
+			   SUPPORTED_100baseT_Half |
+			   SUPPORTED_100baseT_Full |
+			   SUPPORTED_1000baseT_Full |
+			   SUPPORTED_Autoneg | SUPPORTED_TP);
+	ecmd->advertising = ADVERTISED_TP;
+	if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+	    hw->media_type == MEDIA_TYPE_1000M_FULL) {
+		ecmd->advertising |= ADVERTISED_Autoneg;
+		if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR) {
+			ecmd->advertising |= ADVERTISED_Autoneg;
+			ecmd->advertising |=
+			    (ADVERTISED_10baseT_Half |
+			     ADVERTISED_10baseT_Full |
+			     ADVERTISED_100baseT_Half |
+			     ADVERTISED_100baseT_Full |
+			     ADVERTISED_1000baseT_Full);
+		}
+		else
+			ecmd->advertising |= (ADVERTISED_1000baseT_Full);
+	}
+	ecmd->port = PORT_TP;
+	ecmd->phy_address = 0;
+	ecmd->transceiver = XCVR_INTERNAL;
+
+	if (netif_carrier_ok(adapter->netdev)) {
+		u16 link_speed, link_duplex;
+		atl1_get_speed_and_duplex(hw, &link_speed, &link_duplex);
+		ecmd->speed = link_speed;
+		if (link_duplex == FULL_DUPLEX)
+			ecmd->duplex = DUPLEX_FULL;
+		else
+			ecmd->duplex = DUPLEX_HALF;
+	} else {
+		ecmd->speed = -1;
+		ecmd->duplex = -1;
+	}
+	if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+	    hw->media_type == MEDIA_TYPE_1000M_FULL)
+		ecmd->autoneg = AUTONEG_ENABLE;
+	else
+		ecmd->autoneg = AUTONEG_DISABLE;
+
+	return 0;
+}
+
+static int atl1_set_settings(struct net_device *netdev,
+				struct ethtool_cmd *ecmd)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	struct atl1_hw *hw = &adapter->hw;
+	u16 phy_data;
+	int ret_val = 0;
+	u16 old_media_type = hw->media_type;
+
+	if (netif_running(adapter->netdev)) {
+		printk(KERN_DEBUG "%s: ethtool shutting down adapter\n",
+			atl1_driver_name);
+		atl1_down(adapter);
+	}
+
+	if (ecmd->autoneg == AUTONEG_ENABLE)
+		hw->media_type = MEDIA_TYPE_AUTO_SENSOR;
+	else {
+		if (ecmd->speed == SPEED_1000) {
+			if (ecmd->duplex != DUPLEX_FULL) {
+				printk(KERN_WARNING
+				       "%s: can't force to 1000M half duplex\n",
+					atl1_driver_name);
+				ret_val = -EINVAL;
+				goto exit_sset;
+			}
+			hw->media_type = MEDIA_TYPE_1000M_FULL;
+		} else if (ecmd->speed == SPEED_100) {
+			if (ecmd->duplex == DUPLEX_FULL) {
+				hw->media_type = MEDIA_TYPE_100M_FULL;
+			} else
+				hw->media_type = MEDIA_TYPE_100M_HALF;
+		} else {
+			if (ecmd->duplex == DUPLEX_FULL)
+				hw->media_type = MEDIA_TYPE_10M_FULL;
+			else
+				hw->media_type = MEDIA_TYPE_10M_HALF;
+		}
+	}
+	switch (hw->media_type) {
+	case MEDIA_TYPE_AUTO_SENSOR:
+		ecmd->advertising =
+		    ADVERTISED_10baseT_Half |
+		    ADVERTISED_10baseT_Full |
+		    ADVERTISED_100baseT_Half |
+		    ADVERTISED_100baseT_Full |
+		    ADVERTISED_1000baseT_Full |
+		    ADVERTISED_Autoneg | ADVERTISED_TP;
+		break;
+	case MEDIA_TYPE_1000M_FULL:
+		ecmd->advertising =
+		    ADVERTISED_1000baseT_Full |
+		    ADVERTISED_Autoneg | ADVERTISED_TP;
+		break;
+	default:
+		ecmd->advertising = 0;
+		break;
+	}
+	if (atl1_phy_setup_autoneg_adv(hw)) {
+		ret_val = -EINVAL;
+		printk(KERN_WARNING
+			"%s: invalid ethtool speed/duplex setting\n",
+			atl1_driver_name);
+		goto exit_sset;
+	}
+	if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+	    hw->media_type == MEDIA_TYPE_1000M_FULL)
+		phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN;
+	else {
+		switch (hw->media_type) {
+		case MEDIA_TYPE_100M_FULL:
+			phy_data =
+			    MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 |
+			    MII_CR_RESET;
+			break;
+		case MEDIA_TYPE_100M_HALF:
+			phy_data = MII_CR_SPEED_100 | MII_CR_RESET;
+			break;
+		case MEDIA_TYPE_10M_FULL:
+			phy_data =
+			    MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET;
+			break;
+		default:	/* MEDIA_TYPE_10M_HALF: */
+			phy_data = MII_CR_SPEED_10 | MII_CR_RESET;
+			break;
+		}
+	}
+	atl1_write_phy_reg(hw, MII_BMCR, phy_data);
+exit_sset:
+	if (ret_val)
+		hw->media_type = old_media_type;
+
+	if (netif_running(adapter->netdev)) {
+		printk(KERN_DEBUG "%s: ethtool starting adapter\n",
+			atl1_driver_name);
+		atl1_up(adapter);
+	} else if (!ret_val) {
+		printk(KERN_DEBUG "%s: ethtool resetting adapter\n",
+			atl1_driver_name);
+		atl1_reset(adapter);
+	}
+	return ret_val;
+}
+
+static void atl1_get_drvinfo(struct net_device *netdev,
+				struct ethtool_drvinfo *drvinfo)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+
+	strncpy(drvinfo->driver, atl1_driver_name, sizeof(drvinfo->driver));
+	strncpy(drvinfo->version, atl1_driver_version,
+		sizeof(drvinfo->version));
+	strncpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+	strncpy(drvinfo->bus_info, pci_name(adapter->pdev),
+		sizeof(drvinfo->bus_info));
+	drvinfo->eedump_len = ATL1_EEDUMP_LEN;
+}
+
+static void atl1_get_wol(struct net_device *netdev,
+			    struct ethtool_wolinfo *wol)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+
+	wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
+	wol->wolopts = 0;
+	if (adapter->wol & ATL1_WUFC_EX)
+		wol->wolopts |= WAKE_UCAST;
+	if (adapter->wol & ATL1_WUFC_MC)
+		wol->wolopts |= WAKE_MCAST;
+	if (adapter->wol & ATL1_WUFC_BC)
+		wol->wolopts |= WAKE_BCAST;
+	if (adapter->wol & ATL1_WUFC_MAG)
+		wol->wolopts |= WAKE_MAGIC;
+	return;
+}
+
+static int atl1_set_wol(struct net_device *netdev,
+			struct ethtool_wolinfo *wol)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+
+	if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+		return -EOPNOTSUPP;
+	adapter->wol = 0;
+	if (wol->wolopts & WAKE_UCAST)
+		adapter->wol |= ATL1_WUFC_EX;
+	if (wol->wolopts & WAKE_MCAST)
+		adapter->wol |= ATL1_WUFC_MC;
+	if (wol->wolopts & WAKE_BCAST)
+		adapter->wol |= ATL1_WUFC_BC;
+	if (wol->wolopts & WAKE_MAGIC)
+		adapter->wol |= ATL1_WUFC_MAG;
+	return 0;
+}
+
+static void atl1_get_ringparam(struct net_device *netdev,
+			    struct ethtool_ringparam *ring)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	struct atl1_tpd_ring *txdr = &adapter->tpd_ring;
+	struct atl1_rfd_ring *rxdr = &adapter->rfd_ring;
+
+	ring->rx_max_pending = ATL1_MAX_RFD;
+	ring->tx_max_pending = ATL1_MAX_TPD;
+	ring->rx_mini_max_pending = 0;
+	ring->rx_jumbo_max_pending = 0;
+	ring->rx_pending = rxdr->count;
+	ring->tx_pending = txdr->count;
+	ring->rx_mini_pending = 0;
+	ring->rx_jumbo_pending = 0;
+}
+
+static int atl1_set_ringparam(struct net_device *netdev,
+				struct ethtool_ringparam *ring)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	struct atl1_tpd_ring *tpdr = &adapter->tpd_ring;
+	struct atl1_rrd_ring *rrdr = &adapter->rrd_ring;
+	struct atl1_rfd_ring *rfdr = &adapter->rfd_ring;
+
+	struct atl1_tpd_ring tpd_old, tpd_new;
+	struct atl1_rfd_ring rfd_old, rfd_new;
+	struct atl1_rrd_ring rrd_old, rrd_new;
+	struct atl1_ring_header rhdr_old, rhdr_new;
+	int err;
+
+	tpd_old = adapter->tpd_ring;
+	rfd_old = adapter->rfd_ring;
+	rrd_old = adapter->rrd_ring;
+	rhdr_old = adapter->ring_header;
+
+	if (netif_running(adapter->netdev))
+		atl1_down(adapter);
+
+	rfdr->count = (u16) max(ring->rx_pending, (u32) ATL1_MIN_RFD);
+	rfdr->count = rfdr->count > ATL1_MAX_RFD ? ATL1_MAX_RFD :
+			rfdr->count;
+	rfdr->count = (rfdr->count + 3) & ~3;
+	rrdr->count = rfdr->count;
+
+	tpdr->count = (u16) max(ring->tx_pending, (u32) ATL1_MIN_TPD);
+	tpdr->count = tpdr->count > ATL1_MAX_TPD ? ATL1_MAX_TPD :
+			tpdr->count;
+	tpdr->count = (tpdr->count + 3) & ~3;
+
+	if (netif_running(adapter->netdev)) {
+		/* try to get new resources before deleting old */
+		err = atl1_setup_ring_resources(adapter);
+		if (err)
+			goto err_setup_ring;
+
+		/*
+		 * save the new, restore the old in order to free it,
+		 * then restore the new back again
+		 */
+
+		rfd_new = adapter->rfd_ring;
+		rrd_new = adapter->rrd_ring;
+		tpd_new = adapter->tpd_ring;
+		rhdr_new = adapter->ring_header;
+		adapter->rfd_ring = rfd_old;
+		adapter->rrd_ring = rrd_old;
+		adapter->tpd_ring = tpd_old;
+		adapter->ring_header = rhdr_old;
+		atl1_free_ring_resources(adapter);
+		adapter->rfd_ring = rfd_new;
+		adapter->rrd_ring = rrd_new;
+		adapter->tpd_ring = tpd_new;
+		adapter->ring_header = rhdr_new;
+
+		err = atl1_up(adapter);
+		if (err)
+			return err;
+	}
+	return 0;
+
+err_setup_ring:
+	adapter->rfd_ring = rfd_old;
+	adapter->rrd_ring = rrd_old;
+	adapter->tpd_ring = tpd_old;
+	adapter->ring_header = rhdr_old;
+	atl1_up(adapter);
+	return err;
+}
+
+static void atl1_get_pauseparam(struct net_device *netdev,
+			     struct ethtool_pauseparam *epause)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	struct atl1_hw *hw = &adapter->hw;
+
+	if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+	    hw->media_type == MEDIA_TYPE_1000M_FULL) {
+		epause->autoneg = AUTONEG_ENABLE;
+	} else {
+		epause->autoneg = AUTONEG_DISABLE;
+	}
+	epause->rx_pause = 1;
+	epause->tx_pause = 1;
+}
+
+static int atl1_set_pauseparam(struct net_device *netdev,
+			     struct ethtool_pauseparam *epause)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	struct atl1_hw *hw = &adapter->hw;
+
+	if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+	    hw->media_type == MEDIA_TYPE_1000M_FULL) {
+		epause->autoneg = AUTONEG_ENABLE;
+	} else {
+		epause->autoneg = AUTONEG_DISABLE;
+	}
+
+	epause->rx_pause = 1;
+	epause->tx_pause = 1;
+
+	return 0;
+}
+
+static u32 atl1_get_rx_csum(struct net_device *netdev)
+{
+	return 1;
+}
+
+static void atl1_get_strings(struct net_device *netdev, u32 stringset,
+				u8 *data)
+{
+	u8 *p = data;
+	int i;
+
+	switch (stringset) {
+	case ETH_SS_STATS:
+		for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) {
+			memcpy(p, atl1_gstrings_stats[i].stat_string,
+				ETH_GSTRING_LEN);
+			p += ETH_GSTRING_LEN;
+		}
+		break;
+	}
+}
+
+static int atl1_nway_reset(struct net_device *netdev)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	struct atl1_hw *hw = &adapter->hw;
+
+	if (netif_running(netdev)) {
+		u16 phy_data;
+		atl1_down(adapter);
+
+		if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+			hw->media_type == MEDIA_TYPE_1000M_FULL) {
+			phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN;
+		} else {
+			switch (hw->media_type) {
+			case MEDIA_TYPE_100M_FULL:
+				phy_data = MII_CR_FULL_DUPLEX |
+					MII_CR_SPEED_100 | MII_CR_RESET;
+				break;
+			case MEDIA_TYPE_100M_HALF:
+				phy_data = MII_CR_SPEED_100 | MII_CR_RESET;
+				break;
+			case MEDIA_TYPE_10M_FULL:
+				phy_data = MII_CR_FULL_DUPLEX |
+					MII_CR_SPEED_10 | MII_CR_RESET;
+				break;
+			default:  /* MEDIA_TYPE_10M_HALF */
+				phy_data = MII_CR_SPEED_10 | MII_CR_RESET;
+			}
+		}
+		atl1_write_phy_reg(hw, MII_BMCR, phy_data);
+		atl1_up(adapter);
+	}
+	return 0;
+}
+
+const struct ethtool_ops atl1_ethtool_ops = {
+	.get_settings		= atl1_get_settings,
+	.set_settings		= atl1_set_settings,
+	.get_drvinfo		= atl1_get_drvinfo,
+	.get_wol		= atl1_get_wol,
+	.set_wol		= atl1_set_wol,
+	.get_ringparam		= atl1_get_ringparam,
+	.set_ringparam		= atl1_set_ringparam,
+	.get_pauseparam		= atl1_get_pauseparam,
+	.set_pauseparam 	= atl1_set_pauseparam,
+	.get_rx_csum		= atl1_get_rx_csum,
+	.get_tx_csum		= ethtool_op_get_tx_csum,
+	.set_tx_csum		= ethtool_op_set_tx_hw_csum,
+	.get_link		= ethtool_op_get_link,
+	.get_sg			= ethtool_op_get_sg,
+	.set_sg			= ethtool_op_set_sg,
+	.get_strings		= atl1_get_strings,
+	.nway_reset		= atl1_nway_reset,
+	.get_ethtool_stats	= atl1_get_ethtool_stats,
+	.get_stats_count	= atl1_get_stats_count,
+	.get_tso		= ethtool_op_get_tso,
+	.set_tso		= ethtool_op_set_tso,
+};
diff --git a/drivers/net/atl1/atl1_hw.c b/drivers/net/atl1/atl1_hw.c
new file mode 100644
index 0000000..08b2d78
--- /dev/null
+++ b/drivers/net/atl1/atl1_hw.c
@@ -0,0 +1,718 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ * 
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/if_vlan.h>
+#include <linux/etherdevice.h>
+#include <linux/crc32.h>
+#include <asm/byteorder.h>
+
+#include "atl1.h"
+
+/*
+ * Reset the transmit and receive units; mask and clear all interrupts.
+ * hw - Struct containing variables accessed by shared code
+ * return : ATL1_SUCCESS  or  idle status (if error)
+ */
+s32 atl1_reset_hw(struct atl1_hw *hw)
+{
+	u32 icr;
+	int i;
+
+	/* 
+	 * Clear Interrupt mask to stop board from generating
+	 * interrupts & Clear any pending interrupt events 
+	 */
+	/*
+	 * iowrite32(0, hw->hw_addr + REG_IMR);
+	 * iowrite32(0xffffffff, hw->hw_addr + REG_ISR);
+	 */
+
+	/*
+	 * Issue Soft Reset to the MAC.  This will reset the chip's
+	 * transmit, receive, DMA.  It will not effect
+	 * the current PCI configuration.  The global reset bit is self-
+	 * clearing, and should clear within a microsecond.
+	 */
+	iowrite32(MASTER_CTRL_SOFT_RST, hw->hw_addr + REG_MASTER_CTRL);
+	ioread32(hw->hw_addr + REG_MASTER_CTRL);
+
+	iowrite16(1, hw->hw_addr + REG_GPHY_ENABLE);
+	ioread16(hw->hw_addr + REG_GPHY_ENABLE);
+
+	msleep(1);		/* delay about 1ms */
+
+	/* Wait at least 10ms for All module to be Idle */
+	for (i = 0; i < 10; i++) {
+		icr = ioread32(hw->hw_addr + REG_IDLE_STATUS);
+		if (!icr)
+			break;
+		msleep(1);	/* delay 1 ms */
+		cpu_relax();	/* FIXME: is this still the right way to do this? */
+	}
+
+	if (icr) {
+		printk (KERN_DEBUG "icr = %x\n", icr); 
+		return icr;
+	}
+
+	return ATL1_SUCCESS;
+}
+
+/* function about EEPROM
+ *
+ * check_eeprom_exist
+ * return 0 if eeprom exist
+ */
+static int atl1_check_eeprom_exist(struct atl1_hw *hw)
+{
+	u32 value;
+	value = ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL);
+	if (value & SPI_FLASH_CTRL_EN_VPD) {
+		value &= ~SPI_FLASH_CTRL_EN_VPD;
+		iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL);
+	}
+
+	value = ioread16(hw->hw_addr + REG_PCIE_CAP_LIST);
+	return ((value & 0xFF00) == 0x6C00) ? 0 : 1;
+}
+
+static bool atl1_read_eeprom(struct atl1_hw *hw, u32 offset, u32 *p_value)
+{
+	int i;
+	u32 control;
+
+	if (offset & 3)
+		return false;	/* address do not align */
+
+	iowrite32(0, hw->hw_addr + REG_VPD_DATA);
+	control = (offset & VPD_CAP_VPD_ADDR_MASK) << VPD_CAP_VPD_ADDR_SHIFT;
+	iowrite32(control, hw->hw_addr + REG_VPD_CAP);
+	ioread32(hw->hw_addr + REG_VPD_CAP);
+
+	for (i = 0; i < 10; i++) {
+		msleep(2);
+		control = ioread32(hw->hw_addr + REG_VPD_CAP);
+		if (control & VPD_CAP_VPD_FLAG)
+			break;
+	}
+	if (control & VPD_CAP_VPD_FLAG) {
+		*p_value = ioread32(hw->hw_addr + REG_VPD_DATA);
+		return true;
+	}
+	return false;		/* timeout */
+}
+
+/*
+ * Reads the value from a PHY register
+ * hw - Struct containing variables accessed by shared code
+ * reg_addr - address of the PHY register to read
+ */
+s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data)
+{
+	u32 val;
+	int i;
+
+	val = ((u32) (reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT |
+	    	MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW | MDIO_CLK_25_4 <<
+ 		MDIO_CLK_SEL_SHIFT;
+	iowrite32(val, hw->hw_addr + REG_MDIO_CTRL);
+	ioread32(hw->hw_addr + REG_MDIO_CTRL);
+
+	for (i = 0; i < MDIO_WAIT_TIMES; i++) {
+		udelay(2);
+		val = ioread32(hw->hw_addr + REG_MDIO_CTRL);
+		if (!(val & (MDIO_START | MDIO_BUSY)))
+			break;
+	}
+	if (!(val & (MDIO_START | MDIO_BUSY))) {
+		*phy_data = (u16) val;
+		return ATL1_SUCCESS;
+	}
+	return ATL1_ERR_PHY;
+}
+
+#define CUSTOM_SPI_CS_SETUP	2
+#define CUSTOM_SPI_CLK_HI	2
+#define CUSTOM_SPI_CLK_LO	2
+#define CUSTOM_SPI_CS_HOLD	2
+#define CUSTOM_SPI_CS_HI	3
+
+static bool atl1_spi_read(struct atl1_hw *hw, u32 addr, u32 *buf)
+{
+	int i;
+	u32 value;
+
+	iowrite32(0, hw->hw_addr + REG_SPI_DATA);
+	iowrite32(addr, hw->hw_addr + REG_SPI_ADDR);
+
+	value = SPI_FLASH_CTRL_WAIT_READY |
+	    (CUSTOM_SPI_CS_SETUP & SPI_FLASH_CTRL_CS_SETUP_MASK) <<
+	    SPI_FLASH_CTRL_CS_SETUP_SHIFT | (CUSTOM_SPI_CLK_HI &
+					     SPI_FLASH_CTRL_CLK_HI_MASK) <<
+	    SPI_FLASH_CTRL_CLK_HI_SHIFT | (CUSTOM_SPI_CLK_LO &
+					   SPI_FLASH_CTRL_CLK_LO_MASK) <<
+	    SPI_FLASH_CTRL_CLK_LO_SHIFT | (CUSTOM_SPI_CS_HOLD &
+					   SPI_FLASH_CTRL_CS_HOLD_MASK) <<
+	    SPI_FLASH_CTRL_CS_HOLD_SHIFT | (CUSTOM_SPI_CS_HI &
+					    SPI_FLASH_CTRL_CS_HI_MASK) <<
+	    SPI_FLASH_CTRL_CS_HI_SHIFT | (1 & SPI_FLASH_CTRL_INS_MASK) <<
+	    SPI_FLASH_CTRL_INS_SHIFT;
+
+	iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL);
+
+	value |= SPI_FLASH_CTRL_START;
+	iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL);
+	ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL);
+
+	for (i = 0; i < 10; i++) {
+		msleep(1);	/* 1ms */
+		value = ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL);
+		if (!(value & SPI_FLASH_CTRL_START))
+			break;
+	}
+
+	if (value & SPI_FLASH_CTRL_START)
+		return false;
+
+	*buf = ioread32(hw->hw_addr + REG_SPI_DATA);
+
+	return true;
+}
+
+/*
+ * get_permanent_address
+ * return 0 if get valid mac address, 
+ */
+static int atl1_get_permanent_address(struct atl1_hw *hw)
+{
+	u32 addr[2];
+	u32 i, control;
+	u16 reg;
+	u8 eth_addr[ETH_ALEN];
+	bool key_valid;
+
+	if (is_valid_ether_addr(hw->perm_mac_addr))
+		return 0;
+
+	/* init */
+	addr[0] = addr[1] = 0;
+
+	if (!atl1_check_eeprom_exist(hw)) {	/* eeprom exist */
+		reg = 0;
+		key_valid = false;
+		/* Read out all EEPROM content */
+		i = 0;
+		while (1) {
+			if (atl1_read_eeprom(hw, i + 0x100, &control)) {
+				if (key_valid) {
+					if (reg == REG_MAC_STA_ADDR)
+						addr[0] = control;
+					else if (reg == (REG_MAC_STA_ADDR + 4))
+						addr[1] = control;
+					key_valid = false;
+				} else if ((control & 0xff) == 0x5A) {
+					key_valid = true;
+					reg = (u16) (control >> 16);
+				} else
+					break;	/* assume data end while encount an invalid KEYWORD */
+			} else
+				break;	/* read error */
+			i += 4;
+		}
+
+/*
+ * The following 2 lines are the Attansic originals.  Saving for posterity.
+ *		*(u32 *) & eth_addr[2] = LONGSWAP(addr[0]);
+ *		*(u16 *) & eth_addr[0] = SHORTSWAP(*(u16 *) & addr[1]);
+ */
+		*(u32 *) & eth_addr[2] = swab32(addr[0]);
+		*(u16 *) & eth_addr[0] = swab16(*(u16 *) & addr[1]);
+
+		if (is_valid_ether_addr(eth_addr)) {
+			memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN);
+			return 0;
+		}
+		return 1;
+	}
+
+	/* see if SPI FLAGS exist ? */
+	addr[0] = addr[1] = 0;
+	reg = 0;
+	key_valid = false;
+	i = 0;
+	while (1) {
+		if (atl1_spi_read(hw, i + 0x1f000, &control)) {
+			if (key_valid) {
+				if (reg == REG_MAC_STA_ADDR)
+					addr[0] = control;
+				else if (reg == (REG_MAC_STA_ADDR + 4))
+					addr[1] = control;
+				key_valid = false;
+			} else if ((control & 0xff) == 0x5A) {
+				key_valid = true;
+				reg = (u16) (control >> 16);
+			} else
+				break;	/* data end */
+		} else
+			break;	/* read error */
+		i += 4;
+	}
+
+/*
+ * The following 2 lines are the Attansic originals.  Saving for posterity.
+ *	*(u32 *) & eth_addr[2] = LONGSWAP(addr[0]);
+ *	*(u16 *) & eth_addr[0] = SHORTSWAP(*(u16 *) & addr[1]);
+ */
+	*(u32 *) & eth_addr[2] = swab32(addr[0]);
+	*(u16 *) & eth_addr[0] = swab16(*(u16 *) & addr[1]);
+	if (is_valid_ether_addr(eth_addr)) {
+		memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN);
+		return 0;
+	}
+	return 1;
+}
+
+/*
+ * Reads the adapter's MAC address from the EEPROM 
+ * hw - Struct containing variables accessed by shared code
+ */
+s32 atl1_read_mac_addr(struct atl1_hw *hw)
+{
+	u16 i;
+
+	if (atl1_get_permanent_address(hw))
+		random_ether_addr(hw->perm_mac_addr);
+
+	for (i = 0; i < ETH_ALEN; i++)
+		hw->mac_addr[i] = hw->perm_mac_addr[i];
+	return ATL1_SUCCESS;
+}
+
+/*
+ * Hashes an address to determine its location in the multicast table
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr - the multicast address to hash
+ *
+ * atl1_hash_mc_addr
+ *  purpose
+ *      set hash value for a multicast address
+ *      hash calcu processing :
+ *          1. calcu 32bit CRC for multicast address
+ *          2. reverse crc with MSB to LSB
+ */
+u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr)
+{
+	u32 crc32, value = 0;
+	int i;
+
+	crc32 = ether_crc_le(6, mc_addr);
+	crc32 = ~crc32;
+	for (i = 0; i < 32; i++)
+		value |= (((crc32 >> i) & 1) << (31 - i));
+
+	return value;
+}
+
+/*
+ * Sets the bit in the multicast table corresponding to the hash value.
+ * hw - Struct containing variables accessed by shared code
+ * hash_value - Multicast address hash value
+ */
+void atl1_hash_set(struct atl1_hw *hw, u32 hash_value)
+{
+	u32 hash_bit, hash_reg;
+	u32 mta;
+
+	/*
+	 * The HASH Table  is a register array of 2 32-bit registers.
+	 * It is treated like an array of 64 bits.  We want to set
+	 * bit BitArray[hash_value]. So we figure out what register
+	 * the bit is in, read it, OR in the new bit, then write
+	 * back the new value.  The register is determined by the
+	 * upper 7 bits of the hash value and the bit within that
+	 * register are determined by the lower 5 bits of the value.
+	 */
+	hash_reg = (hash_value >> 31) & 0x1;
+	hash_bit = (hash_value >> 26) & 0x1F;
+	mta = ioread32((hw + REG_RX_HASH_TABLE) + (hash_reg << 2));
+	mta |= (1 << hash_bit);
+	iowrite32(mta, (hw->hw_addr + REG_RX_HASH_TABLE) + (hash_reg << 2));
+}
+
+/*
+ * Writes a value to a PHY register
+ * hw - Struct containing variables accessed by shared code
+ * reg_addr - address of the PHY register to write
+ * data - data to write to the PHY
+ */
+s32 atl1_write_phy_reg(struct atl1_hw *hw, u32 reg_addr, u16 phy_data)
+{
+	int i;
+	u32 val;
+
+	val = ((u32) (phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT |
+	    (reg_addr & MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT |
+	    MDIO_SUP_PREAMBLE |
+	    MDIO_START | MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT;
+	iowrite32(val, hw->hw_addr + REG_MDIO_CTRL);
+	ioread32(hw->hw_addr + REG_MDIO_CTRL);
+
+	for (i = 0; i < MDIO_WAIT_TIMES; i++) {
+		udelay(2);
+		val = ioread32(hw->hw_addr + REG_MDIO_CTRL);
+		if (!(val & (MDIO_START | MDIO_BUSY)))
+			break;
+	}
+
+	if (!(val & (MDIO_START | MDIO_BUSY)))
+		return ATL1_SUCCESS;
+
+	return ATL1_ERR_PHY;
+}
+
+/*
+ * Make L001's PHY out of Power Saving State (bug)
+ * hw - Struct containing variables accessed by shared code
+ * when power on, L001's PHY always on Power saving State
+ * (Gigabit Link forbidden)
+ */
+static s32 atl1_phy_leave_power_saving(struct atl1_hw *hw)
+{
+	s32 ret;
+	ret = atl1_write_phy_reg(hw, 29, 0x0029);
+	if (ret)
+		return ret;
+	return atl1_write_phy_reg(hw, 30, 0);
+}
+
+/*
+ *TODO: do something or get rid of this
+ */
+s32 atl1_phy_enter_power_saving(struct atl1_hw *hw)
+{
+/*    s32 ret_val;
+ *    u16 phy_data;
+ */
+
+/*
+    ret_val = atl1_write_phy_reg(hw, ...);
+    ret_val = atl1_write_phy_reg(hw, ...);
+    ....
+*/
+	return ATL1_SUCCESS;
+}
+
+/*
+ * Resets the PHY and make all config validate
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sets bit 15 and 12 of the MII Control regiser (for F001 bug)
+ */
+static s32 atl1_phy_reset(struct atl1_hw *hw)
+{
+	s32 ret_val;
+	u16 phy_data;
+
+	if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+	    hw->media_type == MEDIA_TYPE_1000M_FULL)
+		phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN;
+	else {
+		switch (hw->media_type) {
+		case MEDIA_TYPE_100M_FULL:
+			phy_data =
+			    MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 |
+			    MII_CR_RESET;
+			break;
+		case MEDIA_TYPE_100M_HALF:
+			phy_data = MII_CR_SPEED_100 | MII_CR_RESET;
+			break;
+		case MEDIA_TYPE_10M_FULL:
+			phy_data =
+			    MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET;
+			break;
+		default:	/* MEDIA_TYPE_10M_HALF: */
+			phy_data = MII_CR_SPEED_10 | MII_CR_RESET;
+			break;
+		}
+	}
+
+	ret_val = atl1_write_phy_reg(hw, MII_BMCR, phy_data);
+	if (ret_val) {
+		u32 val;
+		int i;
+		/* pcie serdes link may be down! */
+		printk(KERN_DEBUG "%s: autoneg caused pcie phy link down\n", 
+			atl1_driver_name);
+
+		for (i = 0; i < 25; i++) {
+			msleep(1);
+			val = ioread32(hw->hw_addr + REG_MDIO_CTRL);
+			if (!(val & (MDIO_START | MDIO_BUSY)))
+				break;
+		}
+
+		if ((val & (MDIO_START | MDIO_BUSY)) != 0) {
+			printk(KERN_WARNING 
+				"%s: pcie link down at least for 25ms\n", 
+				atl1_driver_name);
+			return ret_val;
+		}
+	}
+	return ATL1_SUCCESS;
+}
+
+/*
+ * Configures PHY autoneg and flow control advertisement settings
+ * hw - Struct containing variables accessed by shared code
+ */
+s32 atl1_phy_setup_autoneg_adv(struct atl1_hw *hw)
+{
+	s32 ret_val;
+	s16 mii_autoneg_adv_reg;
+	s16 mii_1000t_ctrl_reg;
+
+	/* Read the MII Auto-Neg Advertisement Register (Address 4). */
+	mii_autoneg_adv_reg = MII_AR_DEFAULT_CAP_MASK;
+
+	/* Read the MII 1000Base-T Control Register (Address 9). */
+	mii_1000t_ctrl_reg = MII_AT001_CR_1000T_DEFAULT_CAP_MASK;
+
+	/*
+	 * First we clear all the 10/100 mb speed bits in the Auto-Neg
+	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
+	 * the  1000Base-T Control Register (Address 9).
+	 */
+	mii_autoneg_adv_reg &= ~MII_AR_SPEED_MASK;
+	mii_1000t_ctrl_reg &= ~MII_AT001_CR_1000T_SPEED_MASK;
+
+	/*
+	 * Need to parse media_type  and set up
+	 * the appropriate PHY registers.
+	 */
+	switch (hw->media_type) {
+	case MEDIA_TYPE_AUTO_SENSOR:
+		mii_autoneg_adv_reg |= (MII_AR_10T_HD_CAPS |
+					MII_AR_10T_FD_CAPS |
+					MII_AR_100TX_HD_CAPS |
+					MII_AR_100TX_FD_CAPS);
+		mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS;
+		break;
+
+	case MEDIA_TYPE_1000M_FULL:
+		mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS;
+		break;
+
+	case MEDIA_TYPE_100M_FULL:
+		mii_autoneg_adv_reg |= MII_AR_100TX_FD_CAPS;
+		break;
+
+	case MEDIA_TYPE_100M_HALF:
+		mii_autoneg_adv_reg |= MII_AR_100TX_HD_CAPS;
+		break;
+
+	case MEDIA_TYPE_10M_FULL:
+		mii_autoneg_adv_reg |= MII_AR_10T_FD_CAPS;
+		break;
+
+	default:
+		mii_autoneg_adv_reg |= MII_AR_10T_HD_CAPS;
+		break;
+	}
+
+	/* flow control fixed to enable all */
+	mii_autoneg_adv_reg |= (MII_AR_ASM_DIR | MII_AR_PAUSE);
+
+	hw->mii_autoneg_adv_reg = mii_autoneg_adv_reg;
+	hw->mii_1000t_ctrl_reg = mii_1000t_ctrl_reg;
+
+	ret_val = atl1_write_phy_reg(hw, MII_ADVERTISE, mii_autoneg_adv_reg);
+	if (ret_val)
+		return ret_val;
+
+	ret_val = atl1_write_phy_reg(hw, MII_AT001_CR, mii_1000t_ctrl_reg);
+	if (ret_val)
+		return ret_val;
+
+	return ATL1_SUCCESS;
+}
+
+/*
+ * Configures link settings.
+ * hw - Struct containing variables accessed by shared code
+ * Assumes the hardware has previously been reset and the
+ * transmitter and receiver are not enabled.
+ */
+static s32 atl1_setup_link(struct atl1_hw *hw)
+{
+	s32 ret_val;
+
+	/*
+	 * Options:
+	 *  PHY will advertise value(s) parsed from
+	 *  autoneg_advertised and fc
+	 *  no matter what autoneg is , We will not wait link result.
+	 */
+	ret_val = atl1_phy_setup_autoneg_adv(hw);
+	if (ret_val) {
+		printk(KERN_DEBUG "%s: error setting up autonegotiation\n", 
+			atl1_driver_name);
+		return ret_val;
+	}
+	/* SW.Reset , En-Auto-Neg if needed */
+	ret_val = atl1_phy_reset(hw);
+	if (ret_val) {
+		printk(KERN_DEBUG "%s: error resetting the phy\n", 
+			atl1_driver_name);
+		return ret_val;
+	}
+	hw->phy_configured = true;
+	return ret_val;
+}
+
+static struct atl1_spi_flash_dev flash_table[] = {
+/*	MFR_NAME  WRSR  READ  PRGM  WREN  WRDI  RDSR  RDID  SECTOR_ERASE CHIP_ERASE */
+	{"Atmel", 0x00, 0x03, 0x02, 0x06, 0x04, 0x05, 0x15, 0x52,        0x62},
+	{"SST",   0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0x90, 0x20,        0x60},
+	{"ST",    0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0xAB, 0xD8,        0xC7},
+};
+
+static void atl1_init_flash_opcode(struct atl1_hw *hw)
+{
+	if (hw->flash_vendor >= sizeof(flash_table) / sizeof(flash_table[0]))
+		hw->flash_vendor = 0;	/* ATMEL */
+
+	/* Init OP table */
+	iowrite8(flash_table[hw->flash_vendor].cmd_program,
+		hw->hw_addr + REG_SPI_FLASH_OP_PROGRAM);
+	iowrite8(flash_table[hw->flash_vendor].cmd_sector_erase,
+		hw->hw_addr + REG_SPI_FLASH_OP_SC_ERASE);
+	iowrite8(flash_table[hw->flash_vendor].cmd_chip_erase,
+		hw->hw_addr + REG_SPI_FLASH_OP_CHIP_ERASE);
+	iowrite8(flash_table[hw->flash_vendor].cmd_rdid,
+		hw->hw_addr + REG_SPI_FLASH_OP_RDID);
+	iowrite8(flash_table[hw->flash_vendor].cmd_wren,
+		hw->hw_addr + REG_SPI_FLASH_OP_WREN);
+	iowrite8(flash_table[hw->flash_vendor].cmd_rdsr,
+		hw->hw_addr + REG_SPI_FLASH_OP_RDSR);
+	iowrite8(flash_table[hw->flash_vendor].cmd_wrsr,
+		hw->hw_addr + REG_SPI_FLASH_OP_WRSR);
+	iowrite8(flash_table[hw->flash_vendor].cmd_read,
+		hw->hw_addr + REG_SPI_FLASH_OP_READ);
+}
+
+/*
+ * Performs basic configuration of the adapter.
+ * hw - Struct containing variables accessed by shared code
+ * Assumes that the controller has previously been reset and is in a
+ * post-reset uninitialized state. Initializes multicast table, 
+ * and  Calls routines to setup link
+ * Leaves the transmit and receive units disabled and uninitialized.
+ */
+s32 atl1_init_hw(struct atl1_hw *hw)
+{
+	u32 ret_val = 0;
+
+	/* Zero out the Multicast HASH table */
+	iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE);
+	/* clear the old settings from the multicast hash table */
+	iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2));
+
+	atl1_init_flash_opcode(hw);
+
+	if (!hw->phy_configured) {
+		/* enable GPHY LinkChange Interrrupt */
+		ret_val = atl1_write_phy_reg(hw, 18, 0xC00);
+		if (ret_val)
+			return ret_val;
+		/* make PHY out of power-saving state */
+		ret_val = atl1_phy_leave_power_saving(hw);
+		if (ret_val)
+			return ret_val;
+		/* Call a subroutine to configure the link */
+		ret_val = atl1_setup_link(hw);
+	}
+	return ret_val;
+}
+
+/*
+ * Detects the current speed and duplex settings of the hardware.
+ * hw - Struct containing variables accessed by shared code
+ * speed - Speed of the connection
+ * duplex - Duplex setting of the connection
+ */
+s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex)
+{
+	s32 ret_val;
+	u16 phy_data;
+
+	/* ; --- Read   PHY Specific Status Register (17) */
+	ret_val = atl1_read_phy_reg(hw, MII_AT001_PSSR, &phy_data);
+	if (ret_val)
+		return ret_val;
+
+	if (!(phy_data & MII_AT001_PSSR_SPD_DPLX_RESOLVED))
+		return ATL1_ERR_PHY_RES;
+
+	switch (phy_data & MII_AT001_PSSR_SPEED) {
+	case MII_AT001_PSSR_1000MBS:
+		*speed = SPEED_1000;
+		break;
+	case MII_AT001_PSSR_100MBS:
+		*speed = SPEED_100;
+		break;
+	case MII_AT001_PSSR_10MBS:
+		*speed = SPEED_10;
+		break;
+	default:
+		printk(KERN_DEBUG "%s: error getting speed\n", 
+			atl1_driver_name);
+		return ATL1_ERR_PHY_SPEED;
+		break;
+	}
+	if (phy_data & MII_AT001_PSSR_DPLX)
+		*duplex = FULL_DUPLEX;
+	else
+		*duplex = HALF_DUPLEX;
+
+	return ATL1_SUCCESS;
+}
+
+void atl1_set_mac_addr(struct atl1_hw *hw)
+{
+	u32 value;
+	/*
+	 * 00-0B-6A-F6-00-DC
+	 * 0:  6AF600DC   1: 000B
+	 * low dword
+	 */
+	value = (((u32) hw->mac_addr[2]) << 24) |
+	    (((u32) hw->mac_addr[3]) << 16) |
+	    (((u32) hw->mac_addr[4]) << 8) | (((u32) hw->mac_addr[5]));
+	iowrite32(value, hw->hw_addr + REG_MAC_STA_ADDR);
+	/* high dword */
+	value = (((u32) hw->mac_addr[0]) << 8) | (((u32) hw->mac_addr[1]));
+	iowrite32(value, (hw->hw_addr + REG_MAC_STA_ADDR) + (1 << 2));
+}
diff --git a/drivers/net/atl1/atl1_hw.h b/drivers/net/atl1/atl1_hw.h
new file mode 100644
index 0000000..100c09c
--- /dev/null
+++ b/drivers/net/atl1/atl1_hw.h
@@ -0,0 +1,951 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * There are a lot of defines in here that are unused and/or have cryptic
+ * names.  Please leave them alone, as they're the closest thing we have
+ * to a spec from Attansic at present. *ahem* -- CHS
+ */
+
+#ifndef _ATL1_HW_H_
+#define _ATL1_HW_H_
+
+#include <linux/types.h>
+#include <linux/mii.h>
+
+struct atl1_adapter;
+struct atl1_hw;
+
+/* function prototypes needed by multiple files */
+s32 atl1_phy_setup_autoneg_adv(struct atl1_hw *hw);
+s32 atl1_write_phy_reg(struct atl1_hw *hw, u32 reg_addr, u16 phy_data);
+s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex);
+s32 atl1_read_mac_addr(struct atl1_hw *hw);
+s32 atl1_init_hw(struct atl1_hw *hw);
+s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex);
+s32 atl1_set_speed_and_duplex(struct atl1_hw *hw, u16 speed, u16 duplex);
+u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr);
+void atl1_hash_set(struct atl1_hw *hw, u32 hash_value);
+s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data);
+void atl1_set_mac_addr(struct atl1_hw *hw);
+s32 atl1_phy_enter_power_saving(struct atl1_hw *hw);
+s32 atl1_reset_hw(struct atl1_hw *hw);
+void atl1_check_options(struct atl1_adapter *adapter);
+
+/* register definitions */
+#define REG_PCIE_CAP_LIST			0x58
+
+#define REG_VPD_CAP				0x6C
+#define VPD_CAP_ID_MASK				0xff
+#define VPD_CAP_ID_SHIFT			0
+#define VPD_CAP_NEXT_PTR_MASK			0xFF
+#define VPD_CAP_NEXT_PTR_SHIFT			8
+#define VPD_CAP_VPD_ADDR_MASK			0x7FFF
+#define VPD_CAP_VPD_ADDR_SHIFT			16
+#define VPD_CAP_VPD_FLAG			0x80000000
+
+#define REG_VPD_DATA				0x70
+
+#define REG_SPI_FLASH_CTRL			0x200
+#define SPI_FLASH_CTRL_STS_NON_RDY		0x1
+#define SPI_FLASH_CTRL_STS_WEN			0x2
+#define SPI_FLASH_CTRL_STS_WPEN			0x80
+#define SPI_FLASH_CTRL_DEV_STS_MASK		0xFF
+#define SPI_FLASH_CTRL_DEV_STS_SHIFT		0
+#define SPI_FLASH_CTRL_INS_MASK			0x7
+#define SPI_FLASH_CTRL_INS_SHIFT		8
+#define SPI_FLASH_CTRL_START			0x800
+#define SPI_FLASH_CTRL_EN_VPD			0x2000
+#define SPI_FLASH_CTRL_LDSTART			0x8000
+#define SPI_FLASH_CTRL_CS_HI_MASK		0x3
+#define SPI_FLASH_CTRL_CS_HI_SHIFT		16
+#define SPI_FLASH_CTRL_CS_HOLD_MASK		0x3
+#define SPI_FLASH_CTRL_CS_HOLD_SHIFT		18
+#define SPI_FLASH_CTRL_CLK_LO_MASK		0x3
+#define SPI_FLASH_CTRL_CLK_LO_SHIFT		20
+#define SPI_FLASH_CTRL_CLK_HI_MASK		0x3
+#define SPI_FLASH_CTRL_CLK_HI_SHIFT		22
+#define SPI_FLASH_CTRL_CS_SETUP_MASK		0x3
+#define SPI_FLASH_CTRL_CS_SETUP_SHIFT		24
+#define SPI_FLASH_CTRL_EROM_PGSZ_MASK		0x3
+#define SPI_FLASH_CTRL_EROM_PGSZ_SHIFT		26
+#define SPI_FLASH_CTRL_WAIT_READY		0x10000000
+
+#define REG_SPI_ADDR				0x204
+
+#define REG_SPI_DATA				0x208
+
+#define REG_SPI_FLASH_CONFIG			0x20C
+#define SPI_FLASH_CONFIG_LD_ADDR_MASK		0xFFFFFF
+#define SPI_FLASH_CONFIG_LD_ADDR_SHIFT		0
+#define SPI_FLASH_CONFIG_VPD_ADDR_MASK		0x3
+#define SPI_FLASH_CONFIG_VPD_ADDR_SHIFT		24
+#define SPI_FLASH_CONFIG_LD_EXIST		0x4000000
+
+#define REG_SPI_FLASH_OP_PROGRAM		0x210
+#define REG_SPI_FLASH_OP_SC_ERASE		0x211
+#define REG_SPI_FLASH_OP_CHIP_ERASE		0x212
+#define REG_SPI_FLASH_OP_RDID			0x213
+#define REG_SPI_FLASH_OP_WREN			0x214
+#define REG_SPI_FLASH_OP_RDSR			0x215
+#define REG_SPI_FLASH_OP_WRSR			0x216
+#define REG_SPI_FLASH_OP_READ			0x217
+
+#define REG_TWSI_CTRL				0x218
+#define TWSI_CTRL_LD_OFFSET_MASK		0xFF
+#define TWSI_CTRL_LD_OFFSET_SHIFT		0
+#define TWSI_CTRL_LD_SLV_ADDR_MASK		0x7
+#define TWSI_CTRL_LD_SLV_ADDR_SHIFT		8
+#define TWSI_CTRL_SW_LDSTART			0x800
+#define TWSI_CTRL_HW_LDSTART			0x1000
+#define TWSI_CTRL_SMB_SLV_ADDR_MASK		0x7F
+#define TWSI_CTRL_SMB_SLV_ADDR_SHIFT		15
+#define TWSI_CTRL_LD_EXIST			0x400000
+#define TWSI_CTRL_READ_FREQ_SEL_MASK		0x3
+#define TWSI_CTRL_READ_FREQ_SEL_SHIFT		23
+#define TWSI_CTRL_FREQ_SEL_100K			0
+#define TWSI_CTRL_FREQ_SEL_200K			1
+#define TWSI_CTRL_FREQ_SEL_300K			2
+#define TWSI_CTRL_FREQ_SEL_400K			3
+#define TWSI_CTRL_SMB_SLV_ADDR
+#define TWSI_CTRL_WRITE_FREQ_SEL_MASK		0x3
+#define TWSI_CTRL_WRITE_FREQ_SEL_SHIFT		24
+
+#define REG_PCIE_DEV_MISC_CTRL			0x21C
+#define PCIE_DEV_MISC_CTRL_EXT_PIPE		0x2
+#define PCIE_DEV_MISC_CTRL_RETRY_BUFDIS		0x1
+#define PCIE_DEV_MISC_CTRL_SPIROM_EXIST		0x4
+#define PCIE_DEV_MISC_CTRL_SERDES_ENDIAN	0x8
+#define PCIE_DEV_MISC_CTRL_SERDES_SEL_DIN	0x10
+
+/* Selene Master Control Register */
+#define REG_MASTER_CTRL				0x1400
+#define MASTER_CTRL_SOFT_RST			0x1
+#define MASTER_CTRL_MTIMER_EN			0x2
+#define MASTER_CTRL_ITIMER_EN			0x4
+#define MASTER_CTRL_MANUAL_INT			0x8
+#define MASTER_CTRL_REV_NUM_SHIFT		16
+#define MASTER_CTRL_REV_NUM_MASK		0xff
+#define MASTER_CTRL_DEV_ID_SHIFT		24
+#define MASTER_CTRL_DEV_ID_MASK			0xff
+
+/* Timer Initial Value Register */
+#define REG_MANUAL_TIMER_INIT			0x1404
+
+/* IRQ ModeratorTimer Initial Value Register */
+#define REG_IRQ_MODU_TIMER_INIT			0x1408
+
+#define REG_GPHY_ENABLE				0x140C
+
+/* IRQ Anti-Lost Timer Initial Value Register */
+#define REG_CMBDISDMA_TIMER			0x140E
+
+/* Block IDLE Status Register */
+#define REG_IDLE_STATUS				0x1410
+#define IDLE_STATUS_RXMAC			1
+#define IDLE_STATUS_TXMAC			2
+#define IDLE_STATUS_RXQ				4
+#define IDLE_STATUS_TXQ				8
+#define IDLE_STATUS_DMAR			0x10
+#define IDLE_STATUS_DMAW			0x20
+#define IDLE_STATUS_SMB				0x40
+#define IDLE_STATUS_CMB				0x80
+
+/* MDIO Control Register */
+#define REG_MDIO_CTRL				0x1414
+#define MDIO_DATA_MASK				0xffff
+#define MDIO_DATA_SHIFT				0
+#define MDIO_REG_ADDR_MASK			0x1f
+#define MDIO_REG_ADDR_SHIFT			16
+#define MDIO_RW					0x200000
+#define MDIO_SUP_PREAMBLE			0x400000
+#define MDIO_START				0x800000
+#define MDIO_CLK_SEL_SHIFT			24
+#define MDIO_CLK_25_4				0
+#define MDIO_CLK_25_6				2
+#define MDIO_CLK_25_8				3
+#define MDIO_CLK_25_10				4
+#define MDIO_CLK_25_14				5
+#define MDIO_CLK_25_20				6
+#define MDIO_CLK_25_28				7
+#define MDIO_BUSY				0x8000000
+#define MDIO_WAIT_TIMES				30
+
+/* MII PHY Status Register */
+#define REG_PHY_STATUS				0x1418
+
+/* BIST Control and Status Register0 (for the Packet Memory) */
+#define REG_BIST0_CTRL				0x141c
+#define BIST0_NOW				0x1
+#define BIST0_SRAM_FAIL				0x2
+#define BIST0_FUSE_FLAG				0x4
+#define REG_BIST1_CTRL				0x1420
+#define BIST1_NOW				0x1
+#define BIST1_SRAM_FAIL				0x2
+#define BIST1_FUSE_FLAG				0x4
+
+/* MAC Control Register */
+#define REG_MAC_CTRL				0x1480
+#define MAC_CTRL_TX_EN				1
+#define MAC_CTRL_RX_EN				2
+#define MAC_CTRL_TX_FLOW			4
+#define MAC_CTRL_RX_FLOW			8
+#define MAC_CTRL_LOOPBACK			0x10
+#define MAC_CTRL_DUPLX				0x20
+#define MAC_CTRL_ADD_CRC			0x40
+#define MAC_CTRL_PAD				0x80
+#define MAC_CTRL_LENCHK				0x100
+#define MAC_CTRL_HUGE_EN			0x200
+#define MAC_CTRL_PRMLEN_SHIFT			10
+#define MAC_CTRL_PRMLEN_MASK			0xf
+#define MAC_CTRL_RMV_VLAN			0x4000
+#define MAC_CTRL_PROMIS_EN			0x8000
+#define MAC_CTRL_TX_PAUSE			0x10000
+#define MAC_CTRL_SCNT				0x20000
+#define MAC_CTRL_SRST_TX			0x40000
+#define MAC_CTRL_TX_SIMURST			0x80000
+#define MAC_CTRL_SPEED_SHIFT			20
+#define MAC_CTRL_SPEED_MASK			0x300000
+#define MAC_CTRL_SPEED_1000			2
+#define MAC_CTRL_SPEED_10_100			1
+#define MAC_CTRL_DBG_TX_BKPRESURE		0x400000
+#define MAC_CTRL_TX_HUGE			0x800000
+#define MAC_CTRL_RX_CHKSUM_EN			0x1000000
+#define MAC_CTRL_MC_ALL_EN			0x2000000
+#define MAC_CTRL_BC_EN				0x4000000
+#define MAC_CTRL_DBG				0x8000000
+
+/* MAC IPG/IFG Control Register */
+#define REG_MAC_IPG_IFG				0x1484
+#define MAC_IPG_IFG_IPGT_SHIFT			0
+#define MAC_IPG_IFG_IPGT_MASK			0x7f
+#define MAC_IPG_IFG_MIFG_SHIFT			8
+#define MAC_IPG_IFG_MIFG_MASK			0xff
+#define MAC_IPG_IFG_IPGR1_SHIFT			16
+#define MAC_IPG_IFG_IPGR1_MASK			0x7f
+#define MAC_IPG_IFG_IPGR2_SHIFT			24
+#define MAC_IPG_IFG_IPGR2_MASK			0x7f
+
+/* MAC STATION ADDRESS */
+#define REG_MAC_STA_ADDR			0x1488
+
+/* Hash table for multicast address */
+#define REG_RX_HASH_TABLE			0x1490
+
+/* MAC Half-Duplex Control Register */
+#define REG_MAC_HALF_DUPLX_CTRL			0x1498
+#define MAC_HALF_DUPLX_CTRL_LCOL_SHIFT		0
+#define MAC_HALF_DUPLX_CTRL_LCOL_MASK		0x3ff
+#define MAC_HALF_DUPLX_CTRL_RETRY_SHIFT		12
+#define MAC_HALF_DUPLX_CTRL_RETRY_MASK		0xf
+#define MAC_HALF_DUPLX_CTRL_EXC_DEF_EN		0x10000
+#define MAC_HALF_DUPLX_CTRL_NO_BACK_C		0x20000
+#define MAC_HALF_DUPLX_CTRL_NO_BACK_P		0x40000
+#define MAC_HALF_DUPLX_CTRL_ABEBE		0x80000
+#define MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT		20
+#define MAC_HALF_DUPLX_CTRL_ABEBT_MASK		0xf
+#define MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT	24
+#define MAC_HALF_DUPLX_CTRL_JAMIPG_MASK		0xf
+
+/* Maximum Frame Length Control Register */
+#define REG_MTU					0x149c
+
+/* Wake-On-Lan control register */
+#define REG_WOL_CTRL				0x14a0
+#define WOL_PATTERN_EN				0x00000001
+#define WOL_PATTERN_PME_EN			0x00000002
+#define WOL_MAGIC_EN				0x00000004
+#define WOL_MAGIC_PME_EN			0x00000008
+#define WOL_LINK_CHG_EN				0x00000010
+#define WOL_LINK_CHG_PME_EN			0x00000020
+#define WOL_PATTERN_ST				0x00000100
+#define WOL_MAGIC_ST				0x00000200
+#define WOL_LINKCHG_ST				0x00000400
+#define WOL_CLK_SWITCH_EN			0x00008000
+#define WOL_PT0_EN				0x00010000
+#define WOL_PT1_EN				0x00020000
+#define WOL_PT2_EN				0x00040000
+#define WOL_PT3_EN				0x00080000
+#define WOL_PT4_EN				0x00100000
+#define WOL_PT5_EN				0x00200000
+#define WOL_PT6_EN				0x00400000
+
+/* WOL Length ( 2 DWORD ) */
+#define REG_WOL_PATTERN_LEN			0x14a4
+#define WOL_PT_LEN_MASK				0x7f
+#define WOL_PT0_LEN_SHIFT			0
+#define WOL_PT1_LEN_SHIFT			8
+#define WOL_PT2_LEN_SHIFT			16
+#define WOL_PT3_LEN_SHIFT			24
+#define WOL_PT4_LEN_SHIFT			0
+#define WOL_PT5_LEN_SHIFT			8
+#define WOL_PT6_LEN_SHIFT			16
+
+/* Internal SRAM Partition Register */
+#define REG_SRAM_RFD_ADDR			0x1500
+#define REG_SRAM_RFD_LEN			(REG_SRAM_RFD_ADDR+ 4)
+#define REG_SRAM_RRD_ADDR			(REG_SRAM_RFD_ADDR+ 8)
+#define REG_SRAM_RRD_LEN			(REG_SRAM_RFD_ADDR+12)
+#define REG_SRAM_TPD_ADDR			(REG_SRAM_RFD_ADDR+16)
+#define REG_SRAM_TPD_LEN			(REG_SRAM_RFD_ADDR+20)
+#define REG_SRAM_TRD_ADDR			(REG_SRAM_RFD_ADDR+24)
+#define REG_SRAM_TRD_LEN			(REG_SRAM_RFD_ADDR+28)
+#define REG_SRAM_RXF_ADDR			(REG_SRAM_RFD_ADDR+32)
+#define REG_SRAM_RXF_LEN			(REG_SRAM_RFD_ADDR+36)
+#define REG_SRAM_TXF_ADDR			(REG_SRAM_RFD_ADDR+40)
+#define REG_SRAM_TXF_LEN			(REG_SRAM_RFD_ADDR+44)
+#define REG_SRAM_TCPH_PATH_ADDR			(REG_SRAM_RFD_ADDR+48)
+#define SRAM_TCPH_ADDR_MASK			0x0fff
+#define SRAM_TCPH_ADDR_SHIFT			0
+#define SRAM_PATH_ADDR_MASK			0x0fff
+#define SRAM_PATH_ADDR_SHIFT			16
+
+/* Load Ptr Register */
+#define REG_LOAD_PTR				(REG_SRAM_RFD_ADDR+52)
+
+/* Descriptor Control register */
+#define REG_DESC_BASE_ADDR_HI			0x1540
+#define REG_DESC_RFD_ADDR_LO			(REG_DESC_BASE_ADDR_HI+4)
+#define REG_DESC_RRD_ADDR_LO			(REG_DESC_BASE_ADDR_HI+8)
+#define REG_DESC_TPD_ADDR_LO			(REG_DESC_BASE_ADDR_HI+12)
+#define REG_DESC_CMB_ADDR_LO			(REG_DESC_BASE_ADDR_HI+16)
+#define REG_DESC_SMB_ADDR_LO			(REG_DESC_BASE_ADDR_HI+20)
+#define REG_DESC_RFD_RRD_RING_SIZE		(REG_DESC_BASE_ADDR_HI+24)
+#define DESC_RFD_RING_SIZE_MASK			0x7ff
+#define DESC_RFD_RING_SIZE_SHIFT		0
+#define DESC_RRD_RING_SIZE_MASK			0x7ff
+#define DESC_RRD_RING_SIZE_SHIFT		16
+#define REG_DESC_TPD_RING_SIZE			(REG_DESC_BASE_ADDR_HI+28)
+#define DESC_TPD_RING_SIZE_MASK			0x3ff
+#define DESC_TPD_RING_SIZE_SHIFT		0
+
+/* TXQ Control Register */
+#define REG_TXQ_CTRL				0x1580
+#define TXQ_CTRL_TPD_BURST_NUM_SHIFT		0
+#define TXQ_CTRL_TPD_BURST_NUM_MASK		0x1f
+#define TXQ_CTRL_EN				0x20
+#define TXQ_CTRL_ENH_MODE			0x40
+#define TXQ_CTRL_TPD_FETCH_TH_SHIFT		8
+#define TXQ_CTRL_TPD_FETCH_TH_MASK		0x3f
+#define TXQ_CTRL_TXF_BURST_NUM_SHIFT		16
+#define TXQ_CTRL_TXF_BURST_NUM_MASK		0xffff
+
+/* Jumbo packet Threshold for task offload */
+#define REG_TX_JUMBO_TASK_TH_TPD_IPG		0x1584
+#define TX_JUMBO_TASK_TH_MASK			0x7ff
+#define TX_JUMBO_TASK_TH_SHIFT			0
+#define TX_TPD_MIN_IPG_MASK			0x1f
+#define TX_TPD_MIN_IPG_SHIFT			16
+
+/* RXQ Control Register */
+#define REG_RXQ_CTRL				0x15a0
+#define RXQ_CTRL_RFD_BURST_NUM_SHIFT		0
+#define RXQ_CTRL_RFD_BURST_NUM_MASK		0xff
+#define RXQ_CTRL_RRD_BURST_THRESH_SHIFT		8
+#define RXQ_CTRL_RRD_BURST_THRESH_MASK		0xff
+#define RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT		16
+#define RXQ_CTRL_RFD_PREF_MIN_IPG_MASK		0x1f
+#define RXQ_CTRL_CUT_THRU_EN			0x40000000
+#define RXQ_CTRL_EN				0x80000000
+
+/* Rx jumbo packet threshold and rrd  retirement timer */
+#define REG_RXQ_JMBOSZ_RRDTIM			(REG_RXQ_CTRL+ 4)
+#define RXQ_JMBOSZ_TH_MASK			0x7ff
+#define RXQ_JMBOSZ_TH_SHIFT			0
+#define RXQ_JMBO_LKAH_MASK			0xf
+#define RXQ_JMBO_LKAH_SHIFT			11
+#define RXQ_RRD_TIMER_MASK			0xffff
+#define RXQ_RRD_TIMER_SHIFT			16
+
+/* RFD flow control register */
+#define REG_RXQ_RXF_PAUSE_THRESH		(REG_RXQ_CTRL+ 8)
+#define RXQ_RXF_PAUSE_TH_HI_SHIFT		16
+#define RXQ_RXF_PAUSE_TH_HI_MASK		0xfff
+#define RXQ_RXF_PAUSE_TH_LO_SHIFT		0
+#define RXQ_RXF_PAUSE_TH_LO_MASK		0xfff
+
+/* RRD flow control register */
+#define REG_RXQ_RRD_PAUSE_THRESH		(REG_RXQ_CTRL+12)
+#define RXQ_RRD_PAUSE_TH_HI_SHIFT		0
+#define RXQ_RRD_PAUSE_TH_HI_MASK		0xfff
+#define RXQ_RRD_PAUSE_TH_LO_SHIFT		16
+#define RXQ_RRD_PAUSE_TH_LO_MASK		0xfff
+
+/* DMA Engine Control Register */
+#define REG_DMA_CTRL				0x15c0
+#define DMA_CTRL_DMAR_IN_ORDER			0x1
+#define DMA_CTRL_DMAR_ENH_ORDER			0x2
+#define DMA_CTRL_DMAR_OUT_ORDER			0x4
+#define DMA_CTRL_RCB_VALUE			0x8
+#define DMA_CTRL_DMAR_BURST_LEN_SHIFT		4
+#define DMA_CTRL_DMAR_BURST_LEN_MASK		7
+#define DMA_CTRL_DMAW_BURST_LEN_SHIFT		7
+#define DMA_CTRL_DMAW_BURST_LEN_MASK		7
+#define DMA_CTRL_DMAR_EN				0x400
+#define DMA_CTRL_DMAW_EN				0x800
+
+/* CMB/SMB Control Register */
+#define REG_CSMB_CTRL				0x15d0
+#define CSMB_CTRL_CMB_NOW			1
+#define CSMB_CTRL_SMB_NOW			2
+#define CSMB_CTRL_CMB_EN			4
+#define CSMB_CTRL_SMB_EN			8
+
+/* CMB DMA Write Threshold Register */
+#define REG_CMB_WRITE_TH			(REG_CSMB_CTRL+ 4)
+#define CMB_RRD_TH_SHIFT			0
+#define CMB_RRD_TH_MASK				0x7ff
+#define CMB_TPD_TH_SHIFT			16
+#define CMB_TPD_TH_MASK				0x7ff
+
+/* RX/TX count-down timer to trigger CMB-write. 2us resolution. */
+#define REG_CMB_WRITE_TIMER			(REG_CSMB_CTRL+ 8)
+#define CMB_RX_TM_SHIFT				0
+#define CMB_RX_TM_MASK				0xffff
+#define CMB_TX_TM_SHIFT				16
+#define CMB_TX_TM_MASK				0xffff
+
+/* Number of packet received since last CMB write */
+#define REG_CMB_RX_PKT_CNT			(REG_CSMB_CTRL+12)
+
+/* Number of packet transmitted since last CMB write */
+#define REG_CMB_TX_PKT_CNT			(REG_CSMB_CTRL+16)
+
+/* SMB auto DMA timer register */
+#define REG_SMB_TIMER				(REG_CSMB_CTRL+20)
+
+/* Mailbox Register */
+#define REG_MAILBOX				0x15f0
+#define MB_RFD_PROD_INDX_SHIFT			0
+#define MB_RFD_PROD_INDX_MASK			0x7ff
+#define MB_RRD_CONS_INDX_SHIFT			11
+#define MB_RRD_CONS_INDX_MASK			0x7ff
+#define MB_TPD_PROD_INDX_SHIFT			22
+#define MB_TPD_PROD_INDX_MASK			0x3ff
+
+/* Interrupt Status Register */
+#define REG_ISR					0x1600
+#define ISR_SMB					1
+#define ISR_TIMER				2
+#define ISR_MANUAL				4
+#define ISR_RXF_OV				8
+#define ISR_RFD_UNRUN				0x10
+#define ISR_RRD_OV				0x20
+#define ISR_TXF_UNRUN				0x40
+#define ISR_LINK				0x80
+#define ISR_HOST_RFD_UNRUN			0x100
+#define ISR_HOST_RRD_OV				0x200
+#define ISR_DMAR_TO_RST				0x400
+#define ISR_DMAW_TO_RST				0x800
+#define ISR_GPHY				0x1000
+#define ISR_RX_PKT				0x10000
+#define ISR_TX_PKT				0x20000
+#define ISR_TX_DMA				0x40000
+#define ISR_RX_DMA				0x80000
+#define ISR_CMB_RX				0x100000
+#define ISR_CMB_TX				0x200000
+#define ISR_MAC_RX				0x400000
+#define ISR_MAC_TX				0x800000
+#define ISR_UR_DETECTED				0x1000000
+#define ISR_FERR_DETECTED			0x2000000
+#define ISR_NFERR_DETECTED			0x4000000
+#define ISR_CERR_DETECTED			0x8000000
+#define ISR_PHY_LINKDOWN			0x10000000
+#define ISR_DIS_SMB				0x20000000
+#define ISR_DIS_DMA				0x40000000
+#define ISR_DIS_INT				0x80000000
+
+/* Interrupt Mask Register */
+#define REG_IMR					0x1604
+
+/* Normal Interrupt mask  */
+#define IMR_NORMAL_MASK	(\
+	ISR_SMB		|\
+	ISR_GPHY	|\
+	ISR_PHY_LINKDOWN|\
+	ISR_DMAR_TO_RST	|\
+	ISR_DMAW_TO_RST	|\
+	ISR_CMB_TX	|\
+	ISR_CMB_RX	)
+
+/* Debug Interrupt Mask  (enable all interrupt) */
+#define IMR_DEBUG_MASK	(\
+	ISR_SMB		|\
+	ISR_TIMER	|\
+	ISR_MANUAL	|\
+	ISR_RXF_OV	|\
+	ISR_RFD_UNRUN	|\
+	ISR_RRD_OV	|\
+	ISR_TXF_UNRUN	|\
+	ISR_LINK	|\
+	ISR_CMB_TX	|\
+	ISR_CMB_RX	|\
+	ISR_RX_PKT	|\
+	ISR_TX_PKT	|\
+	ISR_MAC_RX	|\
+	ISR_MAC_TX	)
+
+/* Interrupt Status Register */
+#define REG_RFD_RRD_IDX				0x1800
+#define REG_TPD_IDX				0x1804
+
+/*  MII definition */
+/* PHY Common Register */
+#define MII_AT001_CR					0x09
+#define MII_AT001_SR					0x0A
+#define MII_AT001_ESR					0x0F
+#define MII_AT001_PSCR					0x10
+#define MII_AT001_PSSR					0x11
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB				0x0040	/* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE				0x0080	/* Collision test enable */
+#define MII_CR_FULL_DUPLEX				0x0100	/* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG				0x0200	/* Restart auto negotiation */
+#define MII_CR_ISOLATE					0x0400	/* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN				0x0800	/* Power down */
+#define MII_CR_AUTO_NEG_EN				0x1000	/* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB				0x2000	/* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK					0x4000	/* 0 = normal, 1 = loopback */
+#define MII_CR_RESET					0x8000	/* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_MASK				0x2040
+#define MII_CR_SPEED_1000				0x0040
+#define MII_CR_SPEED_100				0x2000
+#define MII_CR_SPEED_10					0x0000
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS				0x0001	/* Extended register capabilities */
+#define MII_SR_JABBER_DETECT				0x0002	/* Jabber Detected */
+#define MII_SR_LINK_STATUS				0x0004	/* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS				0x0008	/* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT				0x0010	/* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE				0x0020	/* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS			0x0040	/* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS				0x0100	/* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS				0x0200	/* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS				0x0400	/* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS				0x0800	/* 10T   Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS				0x1000	/* 10T   Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS				0x2000	/* 100X  Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS				0x4000	/* 100X  Full Duplex Capable */
+#define MII_SR_100T4_CAPS				0x8000	/* 100T4 Capable */
+
+/* Link partner ability register. */
+#define MII_LPA_SLCT					0x001f	/* Same as advertise selector  */
+#define MII_LPA_10HALF					0x0020	/* Can do 10mbps half-duplex   */
+#define MII_LPA_10FULL					0x0040	/* Can do 10mbps full-duplex   */
+#define MII_LPA_100HALF					0x0080	/* Can do 100mbps half-duplex  */
+#define MII_LPA_100FULL					0x0100	/* Can do 100mbps full-duplex  */
+#define MII_LPA_100BASE4				0x0200	/* 100BASE-T4  */
+#define MII_LPA_PAUSE					0x0400	/* PAUSE */
+#define MII_LPA_ASYPAUSE				0x0800	/* Asymmetrical PAUSE */
+#define MII_LPA_RFAULT					0x2000	/* Link partner faulted        */
+#define MII_LPA_LPACK					0x4000	/* Link partner acked us       */
+#define MII_LPA_NPAGE					0x8000	/* Next page bit               */
+
+/* Autoneg Advertisement Register */
+#define MII_AR_SELECTOR_FIELD				0x0001	/* indicates IEEE 802.3 CSMA/CD */
+#define MII_AR_10T_HD_CAPS				0x0020	/* 10T   Half Duplex Capable */
+#define MII_AR_10T_FD_CAPS				0x0040	/* 10T   Full Duplex Capable */
+#define MII_AR_100TX_HD_CAPS				0x0080	/* 100TX Half Duplex Capable */
+#define MII_AR_100TX_FD_CAPS				0x0100	/* 100TX Full Duplex Capable */
+#define MII_AR_100T4_CAPS				0x0200	/* 100T4 Capable */
+#define MII_AR_PAUSE					0x0400	/* Pause operation desired */
+#define MII_AR_ASM_DIR					0x0800	/* Asymmetric Pause Direction bit */
+#define MII_AR_REMOTE_FAULT				0x2000	/* Remote Fault detected */
+#define MII_AR_NEXT_PAGE				0x8000	/* Next Page ability supported */
+#define MII_AR_SPEED_MASK				0x01E0
+#define MII_AR_DEFAULT_CAP_MASK				0x0DE0
+
+/* 1000BASE-T Control Register */
+#define MII_AT001_CR_1000T_HD_CAPS			0x0100	/* Advertise 1000T HD capability */
+#define MII_AT001_CR_1000T_FD_CAPS			0x0200	/* Advertise 1000T FD capability  */
+#define MII_AT001_CR_1000T_REPEATER_DTE			0x0400	/* 1=Repeater/switch device port, 0=DTE device */
+#define MII_AT001_CR_1000T_MS_VALUE			0x0800	/* 1=Configure PHY as Master, 0=Configure PHY as Slave */
+#define MII_AT001_CR_1000T_MS_ENABLE			0x1000	/* 1=Master/Slave manual config value, 0=Automatic Master/Slave config */
+#define MII_AT001_CR_1000T_TEST_MODE_NORMAL		0x0000	/* Normal Operation */
+#define MII_AT001_CR_1000T_TEST_MODE_1			0x2000	/* Transmit Waveform test */
+#define MII_AT001_CR_1000T_TEST_MODE_2			0x4000	/* Master Transmit Jitter test */
+#define MII_AT001_CR_1000T_TEST_MODE_3			0x6000	/* Slave Transmit Jitter test */
+#define MII_AT001_CR_1000T_TEST_MODE_4			0x8000	/* Transmitter Distortion test */
+#define MII_AT001_CR_1000T_SPEED_MASK			0x0300
+#define MII_AT001_CR_1000T_DEFAULT_CAP_MASK		0x0300
+
+/* 1000BASE-T Status Register */
+#define MII_AT001_SR_1000T_LP_HD_CAPS			0x0400	/* LP is 1000T HD capable */
+#define MII_AT001_SR_1000T_LP_FD_CAPS			0x0800	/* LP is 1000T FD capable */
+#define MII_AT001_SR_1000T_REMOTE_RX_STATUS		0x1000	/* Remote receiver OK */
+#define MII_AT001_SR_1000T_LOCAL_RX_STATUS		0x2000	/* Local receiver OK */
+#define MII_AT001_SR_1000T_MS_CONFIG_RES		0x4000	/* 1=Local TX is Master, 0=Slave */
+#define MII_AT001_SR_1000T_MS_CONFIG_FAULT		0x8000	/* Master/Slave config fault */
+#define MII_AT001_SR_1000T_REMOTE_RX_STATUS_SHIFT	12
+#define MII_AT001_SR_1000T_LOCAL_RX_STATUS_SHIFT	13
+
+/* Extended Status Register */
+#define MII_AT001_ESR_1000T_HD_CAPS			0x1000	/* 1000T HD capable */
+#define MII_AT001_ESR_1000T_FD_CAPS			0x2000	/* 1000T FD capable */
+#define MII_AT001_ESR_1000X_HD_CAPS			0x4000	/* 1000X HD capable */
+#define MII_AT001_ESR_1000X_FD_CAPS			0x8000	/* 1000X FD capable */
+
+/* AT001 PHY Specific Control Register */
+#define MII_AT001_PSCR_JABBER_DISABLE			0x0001	/* 1=Jabber Function disabled */
+#define MII_AT001_PSCR_POLARITY_REVERSAL		0x0002	/* 1=Polarity Reversal enabled */
+#define MII_AT001_PSCR_SQE_TEST				0x0004	/* 1=SQE Test enabled */
+#define MII_AT001_PSCR_MAC_POWERDOWN			0x0008
+#define MII_AT001_PSCR_CLK125_DISABLE			0x0010	/* 1=CLK125 low, 0=CLK125 toggling */
+#define MII_AT001_PSCR_MDI_MANUAL_MODE			0x0000	/* MDI Crossover Mode bits 6:5, Manual MDI configuration */
+#define MII_AT001_PSCR_MDIX_MANUAL_MODE			0x0020	/* Manual MDIX configuration */
+#define MII_AT001_PSCR_AUTO_X_1000T			0x0040	/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */
+#define MII_AT001_PSCR_AUTO_X_MODE			0x0060	/* Auto crossover enabled all speeds. */
+#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE		0x0080	/* 1=Enable Extended 10BASE-T distance (Lower 10BASE-T RX Threshold), 0=Normal 10BASE-T RX Threshold */
+#define MII_AT001_PSCR_MII_5BIT_ENABLE			0x0100	/* 1=5-Bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */
+#define MII_AT001_PSCR_SCRAMBLER_DISABLE		0x0200	/* 1=Scrambler disable */
+#define MII_AT001_PSCR_FORCE_LINK_GOOD			0x0400	/* 1=Force link good */
+#define MII_AT001_PSCR_ASSERT_CRS_ON_TX			0x0800	/* 1=Assert CRS on Transmit */
+#define MII_AT001_PSCR_POLARITY_REVERSAL_SHIFT		1
+#define MII_AT001_PSCR_AUTO_X_MODE_SHIFT		5
+#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE_SHIFT	7
+
+/* AT001 PHY Specific Status Register */
+#define MII_AT001_PSSR_SPD_DPLX_RESOLVED		0x0800	/* 1=Speed & Duplex resolved */
+#define MII_AT001_PSSR_DPLX				0x2000	/* 1=Duplex 0=Half Duplex */
+#define MII_AT001_PSSR_SPEED				0xC000	/* Speed, bits 14:15 */
+#define MII_AT001_PSSR_10MBS				0x0000	/* 00=10Mbs */
+#define MII_AT001_PSSR_100MBS				0x4000	/* 01=100Mbs */
+#define MII_AT001_PSSR_1000MBS				0x8000	/* 10=1000Mbs */
+
+/* PCI Command Register Bit Definitions */
+#define PCI_REG_COMMAND					0x04	/* PCI Command Register */
+#define CMD_IO_SPACE					0x0001
+#define CMD_MEMORY_SPACE				0x0002
+#define CMD_BUS_MASTER					0x0004
+
+/* Wake Up Filter Control */
+#define ATL1_WUFC_LNKC	0x00000001	/* Link Status Change Wakeup Enable */
+#define ATL1_WUFC_MAG	0x00000002	/* Magic Packet Wakeup Enable */
+#define ATL1_WUFC_EX	0x00000004	/* Directed Exact Wakeup Enable */
+#define ATL1_WUFC_MC	0x00000008	/* Multicast Wakeup Enable */
+#define ATL1_WUFC_BC	0x00000010	/* Broadcast Wakeup Enable */
+
+/* Error Codes */
+#define ATL1_SUCCESS			0
+#define ATL1_ERR_EEPROM			1
+#define ATL1_ERR_PHY			2
+#define ATL1_ERR_CONFIG			3
+#define ATL1_ERR_PARAM			4
+#define ATL1_ERR_MAC_TYPE		5
+#define ATL1_ERR_PHY_TYPE		6
+#define ATL1_ERR_PHY_SPEED		7
+#define ATL1_ERR_PHY_RES		8
+
+#define SPEED_0		0xffff
+#define SPEED_10	10
+#define SPEED_100	100
+#define SPEED_1000	1000
+#define HALF_DUPLEX	1
+#define FULL_DUPLEX	2
+
+#define MEDIA_TYPE_AUTO_SENSOR	0
+#define MEDIA_TYPE_1000M_FULL	1
+#define MEDIA_TYPE_100M_FULL	2
+#define MEDIA_TYPE_100M_HALF	3
+#define MEDIA_TYPE_10M_FULL	4
+#define MEDIA_TYPE_10M_HALF	5
+
+#define ADVERTISE_10_HALF		0x0001
+#define ADVERTISE_10_FULL		0x0002
+#define ADVERTISE_100_HALF		0x0004
+#define ADVERTISE_100_FULL		0x0008
+#define ADVERTISE_1000_HALF		0x0010
+#define ADVERTISE_1000_FULL		0x0020
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT	0x002F	/* Everything but 1000-Half */
+#define AUTONEG_ADVERTISE_10_100_ALL	0x000F	/* All 10/100 speeds */
+#define AUTONEG_ADVERTISE_10_ALL	0x0003	/* 10Mbps Full & Half speeds */
+
+/* The size (in bytes) of a ethernet packet */
+#define ENET_HEADER_SIZE		14
+#define MAXIMUM_ETHERNET_FRAME_SIZE	1518	/* with FCS */
+#define MINIMUM_ETHERNET_FRAME_SIZE	64	/* with FCS */
+#define ETHERNET_FCS_SIZE		4
+#define MAX_JUMBO_FRAME_SIZE		0x2800
+
+#define PHY_AUTO_NEG_TIME	45	/* 4.5 Seconds */
+#define PHY_FORCE_TIME		20	/* 2.0 Seconds */
+
+/* For checksumming , the sum of all words in the EEPROM should equal 0xBABA */
+#define EEPROM_SUM		0xBABA
+
+#define ATL1_EEDUMP_LEN		48
+
+/* Statistics counters collected by the MAC */
+struct stats_msg_block {
+	/* rx */
+	u32 rx_ok;		/* The number of good packet received. */
+	u32 rx_bcast;		/* The number of good broadcast packet received. */
+	u32 rx_mcast;		/* The number of good multicast packet received. */
+	u32 rx_pause;		/* The number of Pause packet received. */
+	u32 rx_ctrl;		/* The number of Control packet received other than Pause frame. */
+	u32 rx_fcs_err;		/* The number of packets with bad FCS. */
+	u32 rx_len_err;		/* The number of packets with mismatch of length field and actual size. */
+	u32 rx_byte_cnt;	/* The number of bytes of good packet received. FCS is NOT included. */
+	u32 rx_runt;		/* The number of packets received that are less than 64 byte long and with good FCS. */
+	u32 rx_frag;		/* The number of packets received that are less than 64 byte long and with bad FCS. */
+	u32 rx_sz_64;		/* The number of good and bad packets received that are 64 byte long. */
+	u32 rx_sz_65_127;	/* The number of good and bad packets received that are between 65 and 127-byte long. */
+	u32 rx_sz_128_255;	/* The number of good and bad packets received that are between 128 and 255-byte long. */
+	u32 rx_sz_256_511;	/* The number of good and bad packets received that are between 256 and 511-byte long. */
+	u32 rx_sz_512_1023;	/* The number of good and bad packets received that are between 512 and 1023-byte long. */
+	u32 rx_sz_1024_1518;	/* The number of good and bad packets received that are between 1024 and 1518-byte long. */
+	u32 rx_sz_1519_max;	/* The number of good and bad packets received that are between 1519-byte and MTU. */
+	u32 rx_sz_ov;		/* The number of good and bad packets received that are more than MTU size šC truncated by Selene. */
+	u32 rx_rxf_ov;		/* The number of frame dropped due to occurrence of RX FIFO overflow. */
+	u32 rx_rrd_ov;		/* The number of frame dropped due to occurrence of RRD overflow. */
+	u32 rx_align_err;	/* Alignment Error */
+	u32 rx_bcast_byte_cnt;	/* The byte count of broadcast packet received, excluding FCS. */
+	u32 rx_mcast_byte_cnt;	/* The byte count of multicast packet received, excluding FCS. */
+	u32 rx_err_addr;	/* The number of packets dropped due to address filtering. */
+
+	/* tx */
+	u32 tx_ok;		/* The number of good packet transmitted. */
+	u32 tx_bcast;		/* The number of good broadcast packet transmitted. */
+	u32 tx_mcast;		/* The number of good multicast packet transmitted. */
+	u32 tx_pause;		/* The number of Pause packet transmitted. */
+	u32 tx_exc_defer;	/* The number of packets transmitted with excessive deferral. */
+	u32 tx_ctrl;		/* The number of packets transmitted is a control frame, excluding Pause frame. */
+	u32 tx_defer;		/* The number of packets transmitted that is deferred. */
+	u32 tx_byte_cnt;	/* The number of bytes of data transmitted. FCS is NOT included. */
+	u32 tx_sz_64;		/* The number of good and bad packets transmitted that are 64 byte long. */
+	u32 tx_sz_65_127;	/* The number of good and bad packets transmitted that are between 65 and 127-byte long. */
+	u32 tx_sz_128_255;	/* The number of good and bad packets transmitted that are between 128 and 255-byte long. */
+	u32 tx_sz_256_511;	/* The number of good and bad packets transmitted that are between 256 and 511-byte long. */
+	u32 tx_sz_512_1023;	/* The number of good and bad packets transmitted that are between 512 and 1023-byte long. */
+	u32 tx_sz_1024_1518;	/* The number of good and bad packets transmitted that are between 1024 and 1518-byte long. */
+	u32 tx_sz_1519_max;	/* The number of good and bad packets transmitted that are between 1519-byte and MTU. */
+	u32 tx_1_col;		/* The number of packets subsequently transmitted successfully with a single prior collision. */
+	u32 tx_2_col;		/* The number of packets subsequently transmitted successfully with multiple prior collisions. */
+	u32 tx_late_col;	/* The number of packets transmitted with late collisions. */
+	u32 tx_abort_col;	/* The number of transmit packets aborted due to excessive collisions. */
+	u32 tx_underrun;	/* The number of transmit packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */
+	u32 tx_rd_eop;		/* The number of times that read beyond the EOP into the next frame area when TRD was not written timely */
+	u32 tx_len_err;		/* The number of transmit packets with length field does NOT match the actual frame size. */
+	u32 tx_trunc;		/* The number of transmit packets truncated due to size exceeding MTU. */
+	u32 tx_bcast_byte;	/* The byte count of broadcast packet transmitted, excluding FCS. */
+	u32 tx_mcast_byte;	/* The byte count of multicast packet transmitted, excluding FCS. */
+	u32 smb_updated;	/* 1: SMB Updated. This is used by software as the indication of the statistics update.
+				 * Software should clear this bit as soon as retrieving the statistics information. */
+};
+
+/* Coalescing Message Block */
+struct coals_msg_block {
+	u32 int_stats;		/* interrupt status */
+	u16 rrd_prod_idx;	/* TRD Producer Index. */
+	u16 rfd_cons_idx;	/* RFD Consumer Index. */
+	u16 update;		/* Selene sets this bit every time it DMA the CMB to host memory.
+				 * Software supposes to clear this bit when CMB information is processed. */
+	u16 tpd_cons_idx;	/* TPD Consumer Index. */
+};
+
+/* RRD descriptor */
+struct rx_return_desc {
+	u8 num_buf;		/* Number of RFD buffers used by the received packet */
+	u8 resved;
+	u16 buf_indx;		/* RFD Index of the first buffer */
+	union {
+		u32 valid;
+		struct {
+			u16 rx_chksum;
+			u16 pkt_size;
+		} xsum_sz;
+	} xsz;
+
+	u16 pkt_flg;		/* Packet flags */
+	u16 err_flg;		/* Error flags */
+	u16 resved2;
+	u16 vlan_tag;		/* VLAN TAG */
+};
+
+#define PACKET_FLAG_ETH_TYPE	0x0080
+#define PACKET_FLAG_VLAN_INS	0x0100
+#define PACKET_FLAG_ERR		0x0200
+#define PACKET_FLAG_IPV4	0x0400
+#define PACKET_FLAG_UDP		0x0800
+#define PACKET_FLAG_TCP		0x1000
+#define PACKET_FLAG_BCAST	0x2000
+#define PACKET_FLAG_MCAST	0x4000
+#define PACKET_FLAG_PAUSE	0x8000
+
+#define ERR_FLAG_CRC		0x0001
+#define ERR_FLAG_CODE		0x0002
+#define ERR_FLAG_DRIBBLE	0x0004
+#define ERR_FLAG_RUNT		0x0008
+#define ERR_FLAG_OV		0x0010
+#define ERR_FLAG_TRUNC		0x0020
+#define ERR_FLAG_IP_CHKSUM	0x0040
+#define ERR_FLAG_L4_CHKSUM	0x0080
+#define ERR_FLAG_LEN		0x0100
+#define ERR_FLAG_DES_ADDR	0x0200
+
+/* RFD descriptor */
+struct rx_free_desc {
+	__le64 buffer_addr;	/* Address of the descriptor's data buffer */
+	__le16 buf_len;		/* Size of the receive buffer in host memory, in byte */
+	u16 coalese;		/* Update consumer index to host after the reception of this frame */
+	/* __attribute__ ((packed)) is required */
+} __attribute__ ((packed));
+
+/* tsopu defines */
+#define TSO_PARAM_BUFLEN_MASK           0x3FFF
+#define TSO_PARAM_BUFLEN_SHIFT          0
+#define TSO_PARAM_DMAINT_MASK           0x0001
+#define TSO_PARAM_DMAINT_SHIFT          14
+#define TSO_PARAM_PKTNT_MASK            0x0001
+#define TSO_PARAM_PKTINT_SHIFT          15
+#define TSO_PARAM_VLANTAG_MASK          0xFFFF
+#define TSO_PARAM_VLAN_SHIFT            16
+
+/* tsopl defines */
+#define TSO_PARAM_EOP_MASK              0x0001
+#define TSO_PARAM_EOP_SHIFT             0
+#define TSO_PARAM_COALESCE_MASK         0x0001
+#define TSO_PARAM_COALESCE_SHIFT        1
+#define TSO_PARAM_INSVLAG_MASK          0x0001
+#define TSO_PARAM_INSVLAG_SHIFT         2
+#define TSO_PARAM_CUSTOMCKSUM_MASK      0x0001
+#define TSO_PARAM_CUSTOMCKSUM_SHIFT     3
+#define TSO_PARAM_SEGMENT_MASK          0x0001
+#define TSO_PARAM_SEGMENT_SHIFT         4
+#define TSO_PARAM_IPCKSUM_MASK          0x0001
+#define TSO_PARAM_IPCKSUM_SHIFT         5
+#define TSO_PARAM_TCPCKSUM_MASK         0x0001
+#define TSO_PARAM_TCPCKSUM_SHIFT        6
+#define TSO_PARAM_UDPCKSUM_MASK         0x0001
+#define TSO_PARAM_UDPCKSUM_SHIFT        7
+#define TSO_PARAM_VLANTAGGED_MASK       0x0001
+#define TSO_PARAM_VLANTAGGED_SHIFT      8
+#define TSO_PARAM_ETHTYPE_MASK          0x0001
+#define TSO_PARAM_ETHTYPE_SHIFT         9
+#define TSO_PARAM_IPHL_MASK             0x000F
+#define TSO_PARAM_IPHL_SHIFT            10
+#define TSO_PARAM_TCPHDRLEN_MASK        0x000F
+#define TSO_PARAM_TCPHDRLEN_SHIFT       14
+#define TSO_PARAM_HDRFLAG_MASK          0x0001
+#define TSO_PARAM_HDRFLAG_SHIFT         18
+#define TSO_PARAM_MSS_MASK              0x1FFF
+#define TSO_PARAM_MSS_SHIFT             19
+
+/* csumpu defines */
+#define CSUM_PARAM_BUFLEN_MASK          0x3FFF
+#define CSUM_PARAM_BUFLEN_SHIFT         0
+#define CSUM_PARAM_DMAINT_MASK          0x0001
+#define CSUM_PARAM_DMAINT_SHIFT         14
+#define CSUM_PARAM_PKTINT_MASK          0x0001
+#define CSUM_PARAM_PKTINT_SHIFT         15
+#define CSUM_PARAM_VALANTAG_MASK        0xFFFF
+#define CSUM_PARAM_VALAN_SHIFT          16
+
+/* csumpl defines*/
+#define CSUM_PARAM_EOP_MASK             0x0001
+#define CSUM_PARAM_EOP_SHIFT            0
+#define CSUM_PARAM_COALESCE_MASK        0x0001
+#define CSUM_PARAM_COALESCE_SHIFT       1
+#define CSUM_PARAM_INSVLAG_MASK         0x0001
+#define CSUM_PARAM_INSVLAG_SHIFT        2
+#define CSUM_PARAM_CUSTOMCKSUM_MASK     0x0001
+#define CSUM_PARAM_CUSTOMCKSUM_SHIFT    3
+#define CSUM_PARAM_SEGMENT_MASK         0x0001
+#define CSUM_PARAM_SEGMENT_SHIFT        4
+#define CSUM_PARAM_IPCKSUM_MASK         0x0001
+#define CSUM_PARAM_IPCKSUM_SHIFT        5
+#define CSUM_PARAM_TCPCKSUM_MASK        0x0001
+#define CSUM_PARAM_TCPCKSUM_SHIFT       6
+#define CSUM_PARAM_UDPCKSUM_MASK        0x0001
+#define CSUM_PARAM_UDPCKSUM_SHIFT       7
+#define CSUM_PARAM_VLANTAGGED_MASK      0x0001
+#define CSUM_PARAM_VLANTAGGED_SHIFT     8
+#define CSUM_PARAM_ETHTYPE_MASK         0x0001
+#define CSUM_PARAM_ETHTYPE_SHIFT        9
+#define CSUM_PARAM_IPHL_MASK            0x000F
+#define CSUM_PARAM_IPHL_SHIFT           10
+#define CSUM_PARAM_PLOADOFFSET_MASK     0x00FF
+#define CSUM_PARAM_PLOADOFFSET_SHIFT    16
+#define CSUM_PARAM_XSUMOFFSET_MASK      0x00FF
+#define CSUM_PARAM_XSUMOFFSET_SHIFT     24
+
+/* TPD descriptor */
+struct tso_param {
+        /* The order of these declarations is important -- don't change it */
+        u32 tsopu;      /* tso_param upper word */
+        u32 tsopl;      /* tso_param lower word */
+};
+
+struct csum_param {
+        /* The order of these declarations is important -- don't change it */
+        u32 csumpu;     /* csum_param upper word */
+        u32 csumpl;     /* csum_param lower word */
+};
+
+union tpd_descr {
+	u64 data;
+	struct csum_param csum;
+	struct tso_param tso;
+};
+
+struct tx_packet_desc {
+	__le64 buffer_addr;
+	union tpd_descr desc;
+};
+
+/* DMA Order Settings */
+enum atl1_dma_order {
+	atl1_dma_ord_in = 1,
+	atl1_dma_ord_enh = 2,
+	atl1_dma_ord_out = 4
+};
+
+enum atl1_dma_rcb {
+	atl1_rcb_64 = 0,
+	atl1_rcb_128 = 1
+};
+
+enum atl1_dma_req_block {
+	atl1_dma_req_128 = 0,
+	atl1_dma_req_256 = 1,
+	atl1_dma_req_512 = 2,
+	atl1_dam_req_1024 = 3,
+	atl1_dam_req_2048 = 4,
+	atl1_dma_req_4096 = 5
+};
+
+struct atl1_spi_flash_dev {
+	const char *manu_name;	/* manufacturer id */
+	/* op-code */
+	u8 cmd_wrsr;
+	u8 cmd_read;
+	u8 cmd_program;
+	u8 cmd_wren;
+	u8 cmd_wrdi;
+	u8 cmd_rdsr;
+	u8 cmd_rdid;
+	u8 cmd_sector_erase;
+	u8 cmd_chip_erase;
+};
+
+#endif	/* _ATL1_HW_H_ */
diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c
new file mode 100644
index 0000000..6655640
--- /dev/null
+++ b/drivers/net/atl1/atl1_main.c
@@ -0,0 +1,2468 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ *
+ * Contact Information:
+ * Xiong Huang <xiong_huang@attansic.com>
+ * Attansic Technology Corp. 3F 147, Xianzheng 9th Road, Zhubei,
+ * Xinzhu  302, TAIWAN, REPUBLIC OF CHINA
+ *
+ * Chris Snook <csnook@redhat.com>
+ * Jay Cliburn <jcliburn@gmail.com>
+ *
+ * This version is adapted from the Attansic reference driver for
+ * inclusion in the Linux kernel.  It is currently under heavy development.
+ * A very incomplete list of things that need to be dealt with:
+ *
+ * TODO:
+ * Fix TSO; tx performance is horrible with TSO enabled.
+ * Wake on LAN.
+ * Add more ethtool functions, including set ring parameters.
+ * Fix abstruse irq enable/disable condition described here:
+ *	http://marc.theaimsgroup.com/?l=linux-netdev&m=116398508500553&w=2
+ *
+ * NEEDS TESTING:
+ * VLAN
+ * multicast
+ * promiscuous mode
+ * interrupt coalescing
+ * SMP torture testing
+ */
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/irqreturn.h>
+#include <linux/workqueue.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/hardirq.h>
+#include <linux/interrupt.h>
+#include <linux/irqflags.h>
+#include <linux/dma-mapping.h>
+#include <linux/net.h>
+#include <linux/pm.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/compiler.h>
+#include <linux/delay.h>
+#include <linux/mii.h>
+#include <net/checksum.h>
+
+#include <asm/atomic.h>
+#include <asm/byteorder.h>
+
+#include "atl1.h"
+
+#define RUN_REALTIME 0
+#define DRIVER_VERSION "2.0.6"
+
+char atl1_driver_name[] = "atl1";
+static const char atl1_driver_string[] = "Attansic L1 Ethernet Network Driver";
+static const char atl1_copyright[] = "Copyright(c) 2005-2006 Attansic Corporation.";
+char atl1_driver_version[] = DRIVER_VERSION;
+
+MODULE_AUTHOR
+    ("Attansic Corporation <xiong_huang@attansic.com>, Chris Snook <csnook@redhat.com>, Jay Cliburn <jcliburn@gmail.com>");
+MODULE_DESCRIPTION("Attansic 1000M Ethernet Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
+
+/*
+ * atl1_pci_tbl - PCI Device ID Table
+ */
+static const struct pci_device_id atl1_pci_tbl[] = {
+	{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, 0x1048)},
+	/* required last entry */
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci, atl1_pci_tbl);
+
+/*
+ * atl1_sw_init - Initialize general software structures (struct atl1_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * atl1_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ */
+static int __devinit atl1_sw_init(struct atl1_adapter *adapter)
+{
+	struct atl1_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+
+	/* PCI config space info */
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
+
+	hw->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+	hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
+
+	adapter->wol = 0;
+	adapter->rx_buffer_len = (hw->max_frame_size + 7) & ~7;
+	adapter->ict = 50000;	/* 100ms */
+	adapter->link_speed = SPEED_0;	/* hardware init */
+	adapter->link_duplex = FULL_DUPLEX;
+
+	hw->phy_configured = false;
+	hw->preamble_len = 7;
+	hw->ipgt = 0x60;
+	hw->min_ifg = 0x50;
+	hw->ipgr1 = 0x40;
+	hw->ipgr2 = 0x60;
+	hw->max_retry = 0xf;
+	hw->lcol = 0x37;
+	hw->jam_ipg = 7;
+	hw->rfd_burst = 8;
+	hw->rrd_burst = 8;
+	hw->rfd_fetch_gap = 1;
+	hw->rx_jumbo_th = adapter->rx_buffer_len / 8;
+	hw->rx_jumbo_lkah = 1;
+	hw->rrd_ret_timer = 16;
+	hw->tpd_burst = 4;
+	hw->tpd_fetch_th = 16;
+	hw->txf_burst = 0x100;
+	hw->tx_jumbo_task_th = (hw->max_frame_size + 7) >> 3;
+	hw->tpd_fetch_gap = 1;
+	hw->rcb_value = atl1_rcb_64;
+	hw->dma_ord = atl1_dma_ord_enh;
+	hw->dmar_block = atl1_dma_req_256;
+	hw->dmaw_block = atl1_dma_req_256;
+	hw->cmb_rrd = 4;
+	hw->cmb_tpd = 4;
+	hw->cmb_rx_timer = 1;	/* about 2us */
+	hw->cmb_tx_timer = 1;	/* about 2us */
+	hw->smb_timer = 100000;	/* about 200ms */
+
+	atomic_set(&adapter->irq_sem, 0);
+	spin_lock_init(&adapter->lock);
+	spin_lock_init(&adapter->mb_lock);
+
+	return 0;
+}
+
+/*
+ * atl1_setup_mem_resources - allocate Tx / RX descriptor resources
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ */
+s32 atl1_setup_ring_resources(struct atl1_adapter *adapter)
+{
+	struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+	struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+	struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
+	struct atl1_ring_header *ring_header = &adapter->ring_header;
+	struct pci_dev *pdev = adapter->pdev;
+	int size;
+	u8 offset = 0;
+
+	size = sizeof(struct atl1_buffer) * (tpd_ring->count + rfd_ring->count);
+	tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL);
+	if (unlikely(!tpd_ring->buffer_info)) {
+		printk(KERN_WARNING "%s: kzalloc failed , size = D%d\n",
+			atl1_driver_name, size);
+		goto err_nomem;
+	}
+	rfd_ring->buffer_info =
+	    (struct atl1_buffer *)(tpd_ring->buffer_info + tpd_ring->count);
+
+	/* real ring DMA buffer */
+	ring_header->size = size = sizeof(struct tx_packet_desc) *
+					tpd_ring->count
+	    + sizeof(struct rx_free_desc) * rfd_ring->count
+	    + sizeof(struct rx_return_desc) * rrd_ring->count
+	    + sizeof(struct coals_msg_block)
+	    + sizeof(struct stats_msg_block)
+	    + 40;		/* "40: for 8 bytes align" huh? -- CHS */
+
+	ring_header->desc = pci_alloc_consistent(pdev, ring_header->size,
+						&ring_header->dma);
+	if (unlikely(!ring_header->desc)) {
+		printk(KERN_WARNING
+			"%s: pci_alloc_consistent failed, size = D%d\n",
+			atl1_driver_name, size);
+		goto err_nomem;
+	}
+
+	memset(ring_header->desc, 0, ring_header->size);
+
+	/* init TPD ring */
+	tpd_ring->dma = ring_header->dma;
+	offset = (tpd_ring->dma & 0x7) ? (8 - (ring_header->dma & 0x7)) : 0;
+	tpd_ring->dma += offset;
+	tpd_ring->desc = (u8 *) ring_header->desc + offset;
+	tpd_ring->size = sizeof(struct tx_packet_desc) * tpd_ring->count;
+	atomic_set(&tpd_ring->next_to_use, 0);
+	atomic_set(&tpd_ring->next_to_clean, 0);
+
+	/* init RFD ring */
+	rfd_ring->dma = tpd_ring->dma + tpd_ring->size;
+	offset = (rfd_ring->dma & 0x7) ? (8 - (rfd_ring->dma & 0x7)) : 0;
+	rfd_ring->dma += offset;
+	rfd_ring->desc = (u8 *) tpd_ring->desc + (tpd_ring->size + offset);
+	rfd_ring->size = sizeof(struct rx_free_desc) * rfd_ring->count;
+	rfd_ring->next_to_clean = 0;
+	/* rfd_ring->next_to_use = rfd_ring->count - 1; */
+	atomic_set(&rfd_ring->next_to_use, 0);
+
+	/* init RRD ring */
+	rrd_ring->dma = rfd_ring->dma + rfd_ring->size;
+	offset = (rrd_ring->dma & 0x7) ? (8 - (rrd_ring->dma & 0x7)) : 0;
+	rrd_ring->dma += offset;
+	rrd_ring->desc = (u8 *) rfd_ring->desc + (rfd_ring->size + offset);
+	rrd_ring->size = sizeof(struct rx_return_desc) * rrd_ring->count;
+	rrd_ring->next_to_use = 0;
+	atomic_set(&rrd_ring->next_to_clean, 0);
+
+	/* init CMB */
+	adapter->cmb.dma = rrd_ring->dma + rrd_ring->size;
+	offset = (adapter->cmb.dma & 0x7) ? (8 - (adapter->cmb.dma & 0x7)) : 0;
+	adapter->cmb.dma += offset;
+	adapter->cmb.cmb =
+	    (struct coals_msg_block *) ((u8 *) rrd_ring->desc +
+				   (rrd_ring->size + offset));
+
+	/* init SMB */
+	adapter->smb.dma = adapter->cmb.dma + sizeof(struct coals_msg_block);
+	offset = (adapter->smb.dma & 0x7) ? (8 - (adapter->smb.dma & 0x7)) : 0;
+	adapter->smb.dma += offset;
+	adapter->smb.smb = (struct stats_msg_block *)
+	    ((u8 *) adapter->cmb.cmb + (sizeof(struct coals_msg_block) + offset));
+
+	return ATL1_SUCCESS;
+
+err_nomem:
+	kfree(tpd_ring->buffer_info);
+	return -ENOMEM;
+}
+
+/*
+ * atl1_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ */
+static void atl1_irq_enable(struct atl1_adapter *adapter)
+{
+	if (likely(!atomic_dec_and_test(&adapter->irq_sem)))
+		iowrite32(IMR_NORMAL_MASK, adapter->hw.hw_addr + REG_IMR);
+}
+
+static void atl1_clear_phy_int(struct atl1_adapter *adapter)
+{
+	u16 phy_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->lock, flags);
+	atl1_read_phy_reg(&adapter->hw, 19, &phy_data);
+	spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+static void atl1_inc_smb(struct atl1_adapter *adapter)
+{
+	struct stats_msg_block *smb = adapter->smb.smb;
+
+	/* Fill out the OS statistics structure */
+	adapter->soft_stats.rx_packets += smb->rx_ok;
+	adapter->soft_stats.tx_packets += smb->tx_ok;
+	adapter->soft_stats.rx_bytes += smb->rx_byte_cnt;
+	adapter->soft_stats.tx_bytes += smb->tx_byte_cnt;
+	adapter->soft_stats.multicast += smb->rx_mcast;
+	adapter->soft_stats.collisions += (smb->tx_1_col +
+					   smb->tx_2_col * 2 +
+					   smb->tx_late_col +
+					   smb->tx_abort_col *
+					   adapter->hw.max_retry);
+
+	/* Rx Errors */
+	adapter->soft_stats.rx_errors += (smb->rx_frag +
+					  smb->rx_fcs_err +
+					  smb->rx_len_err +
+					  smb->rx_sz_ov +
+					  smb->rx_rxf_ov +
+					  smb->rx_rrd_ov + smb->rx_align_err);
+	adapter->soft_stats.rx_fifo_errors += smb->rx_rxf_ov;
+	adapter->soft_stats.rx_length_errors += smb->rx_len_err;
+	adapter->soft_stats.rx_crc_errors += smb->rx_fcs_err;
+	adapter->soft_stats.rx_frame_errors += smb->rx_align_err;
+	adapter->soft_stats.rx_missed_errors += (smb->rx_rrd_ov +
+						 smb->rx_rxf_ov);
+
+	adapter->soft_stats.rx_pause += smb->rx_pause;
+	adapter->soft_stats.rx_rrd_ov += smb->rx_rrd_ov;
+	adapter->soft_stats.rx_trunc += smb->rx_sz_ov;
+
+	/* Tx Errors */
+	adapter->soft_stats.tx_errors += (smb->tx_late_col +
+					  smb->tx_abort_col +
+					  smb->tx_underrun + smb->tx_trunc);
+	adapter->soft_stats.tx_fifo_errors += smb->tx_underrun;
+	adapter->soft_stats.tx_aborted_errors += smb->tx_abort_col;
+	adapter->soft_stats.tx_window_errors += smb->tx_late_col;
+
+	adapter->soft_stats.excecol += smb->tx_abort_col;
+	adapter->soft_stats.deffer += smb->tx_defer;
+	adapter->soft_stats.scc += smb->tx_1_col;
+	adapter->soft_stats.mcc += smb->tx_2_col;
+	adapter->soft_stats.latecol += smb->tx_late_col;
+	adapter->soft_stats.tx_underun += smb->tx_underrun;
+	adapter->soft_stats.tx_trunc += smb->tx_trunc;
+	adapter->soft_stats.tx_pause += smb->tx_pause;
+
+	adapter->net_stats.rx_packets = adapter->soft_stats.rx_packets;
+	adapter->net_stats.tx_packets = adapter->soft_stats.tx_packets;
+	adapter->net_stats.rx_bytes = adapter->soft_stats.rx_bytes;
+	adapter->net_stats.tx_bytes = adapter->soft_stats.tx_bytes;
+	adapter->net_stats.multicast = adapter->soft_stats.multicast;
+	adapter->net_stats.collisions = adapter->soft_stats.collisions;
+	adapter->net_stats.rx_errors = adapter->soft_stats.rx_errors;
+	adapter->net_stats.rx_over_errors =
+	    adapter->soft_stats.rx_missed_errors;
+	adapter->net_stats.rx_length_errors =
+	    adapter->soft_stats.rx_length_errors;
+	adapter->net_stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors;
+	adapter->net_stats.rx_frame_errors =
+	    adapter->soft_stats.rx_frame_errors;
+	adapter->net_stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors;
+	adapter->net_stats.rx_missed_errors =
+	    adapter->soft_stats.rx_missed_errors;
+	adapter->net_stats.tx_errors = adapter->soft_stats.tx_errors;
+	adapter->net_stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors;
+	adapter->net_stats.tx_aborted_errors =
+	    adapter->soft_stats.tx_aborted_errors;
+	adapter->net_stats.tx_window_errors =
+	    adapter->soft_stats.tx_window_errors;
+	adapter->net_stats.tx_carrier_errors =
+	    adapter->soft_stats.tx_carrier_errors;
+}
+
+static void atl1_rx_checksum(struct atl1_adapter *adapter,
+					struct rx_return_desc *rrd,
+					struct sk_buff *skb)
+{
+	skb->ip_summed = CHECKSUM_NONE;
+
+	if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) {
+		if (rrd->err_flg & (ERR_FLAG_CRC | ERR_FLAG_TRUNC |
+					ERR_FLAG_CODE | ERR_FLAG_OV)) {
+			adapter->hw_csum_err++;
+			printk(KERN_DEBUG "%s: rx checksum error\n",
+				atl1_driver_name);
+			return;
+		}
+	}
+
+	/* not IPv4 */
+	if (!(rrd->pkt_flg & PACKET_FLAG_IPV4))
+		/* checksum is invalid, but it's not an IPv4 pkt, so ok */
+		return;
+
+	/* IPv4 packet */
+	if (likely(!(rrd->err_flg &
+		(ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM)))) {
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+		adapter->hw_csum_good++;
+		return;
+	}
+
+	/* IPv4, but hardware thinks its checksum is wrong */
+	printk(KERN_DEBUG "%s: hw csum wrong pkt_flag:%x, err_flag:%x\n",
+		atl1_driver_name, rrd->pkt_flg, rrd->err_flg);
+	skb->ip_summed = CHECKSUM_COMPLETE;
+	skb->csum = htons(rrd->xsz.xsum_sz.rx_chksum);
+	adapter->hw_csum_err++;
+	return;
+}
+
+/*
+ * atl1_alloc_rx_buffers - Replace used receive buffers
+ * @adapter: address of board private structure
+ */
+static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter)
+{
+	struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	struct page *page;
+	unsigned long offset;
+	struct atl1_buffer *buffer_info, *next_info;
+	struct sk_buff *skb;
+	u16 num_alloc = 0;
+	u16 rfd_next_to_use, next_next;
+	struct rx_free_desc *rfd_desc;
+
+	next_next = rfd_next_to_use = atomic_read(&rfd_ring->next_to_use);
+	if (++next_next == rfd_ring->count)
+		next_next = 0;
+	buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
+	next_info = &rfd_ring->buffer_info[next_next];
+
+	while (!buffer_info->alloced && !next_info->alloced) {
+		if (buffer_info->skb) {
+			buffer_info->alloced = 1;
+			goto next;
+		}
+
+		rfd_desc = ATL1_RFD_DESC(rfd_ring, rfd_next_to_use);
+
+		skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN);
+		if (unlikely(!skb)) {	/* Better luck next round */
+			adapter->net_stats.rx_dropped++;
+			break;
+		}
+
+		/*
+		 * Make buffer alignment 2 beyond a 16 byte boundary
+		 * this will result in a 16 byte aligned IP header after
+		 * the 14 byte MAC header is removed
+		 */
+		skb_reserve(skb, NET_IP_ALIGN);
+		skb->dev = netdev;
+
+		buffer_info->alloced = 1;
+		buffer_info->skb = skb;
+		buffer_info->length = (u16) adapter->rx_buffer_len;
+		page = virt_to_page(skb->data);
+		offset = (unsigned long)skb->data & ~PAGE_MASK;
+		buffer_info->dma = pci_map_page(pdev, page, offset,
+						adapter->rx_buffer_len,
+						PCI_DMA_FROMDEVICE);
+		rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+		rfd_desc->buf_len = cpu_to_le16(adapter->rx_buffer_len);
+		rfd_desc->coalese = 0;
+
+next:
+		rfd_next_to_use = next_next;
+		if (unlikely(++next_next == rfd_ring->count))
+			next_next = 0;
+
+		buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
+		next_info = &rfd_ring->buffer_info[next_next];
+		num_alloc++;
+	}
+
+	if (num_alloc) {
+		/*
+		 * Force memory writes to complete before letting h/w
+		 * know there are new descriptors to fetch.  (Only
+		 * applicable for weak-ordered memory model archs,
+		 * such as IA-64).
+		 */
+		wmb();
+		atomic_set(&rfd_ring->next_to_use, (int)rfd_next_to_use);
+	}
+	return num_alloc;
+}
+
+static void atl1_intr_rx(struct atl1_adapter *adapter)
+{
+	int i, count;
+	u16 length;
+	u16 rrd_next_to_clean;
+	u32 value;
+	struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+	struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
+	struct atl1_buffer *buffer_info;
+	struct rx_return_desc *rrd;
+	struct sk_buff *skb;
+
+	count = 0;
+
+	rrd_next_to_clean = atomic_read(&rrd_ring->next_to_clean);
+
+	while (1) {
+		rrd = ATL1_RRD_DESC(rrd_ring, rrd_next_to_clean);
+		i = 1;
+		if (likely(rrd->xsz.valid)) {	/* packet valid */
+chk_rrd:
+			/* check rrd status */
+			if (likely(rrd->num_buf == 1))
+				goto rrd_ok;
+
+			/* rrd seems to be bad */
+			if (unlikely(i-- > 0)) {
+				/* rrd may not be DMAed completely */
+				printk(KERN_DEBUG
+					"%s: RRD may not be DMAed completely\n",
+					atl1_driver_name);
+				udelay(1);
+				goto chk_rrd;
+			}
+			/* bad rrd */
+			printk(KERN_DEBUG "%s: bad RRD\n", atl1_driver_name);
+			/* see if update RFD index */
+			if (rrd->num_buf > 1) {
+				u16 num_buf;
+				num_buf =
+				    (rrd->xsz.xsum_sz.pkt_size +
+				     adapter->rx_buffer_len -
+				     1) / adapter->rx_buffer_len;
+				if (rrd->num_buf == num_buf) {
+					/* clean alloc flag for bad rrd */
+					while (rfd_ring->next_to_clean !=
+					       (rrd->buf_indx + num_buf)) {
+						rfd_ring->buffer_info[rfd_ring->
+								      next_to_clean].alloced = 0;
+						if (++rfd_ring->next_to_clean ==
+						    rfd_ring->count) {
+							rfd_ring->
+							    next_to_clean = 0;
+						}
+					}
+				}
+			}
+
+			/* update rrd */
+			rrd->xsz.valid = 0;
+			if (++rrd_next_to_clean == rrd_ring->count)
+				rrd_next_to_clean = 0;
+			count++;
+			continue;
+		} else {	/* current rrd still not be updated */
+
+			break;
+		}
+rrd_ok:
+		/* clean alloc flag for bad rrd */
+		while (rfd_ring->next_to_clean != rrd->buf_indx) {
+			rfd_ring->buffer_info[rfd_ring->next_to_clean].alloced =
+			    0;
+			if (++rfd_ring->next_to_clean == rfd_ring->count)
+				rfd_ring->next_to_clean = 0;
+		}
+
+		buffer_info = &rfd_ring->buffer_info[rrd->buf_indx];
+		if (++rfd_ring->next_to_clean == rfd_ring->count)
+			rfd_ring->next_to_clean = 0;
+
+		/* update rrd next to clean */
+		if (++rrd_next_to_clean == rrd_ring->count)
+			rrd_next_to_clean = 0;
+		count++;
+
+		if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) {
+			if (!(rrd->err_flg &
+				(ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM
+				| ERR_FLAG_LEN))) {
+				/* packet error, don't need upstream */
+				buffer_info->alloced = 0;
+				rrd->xsz.valid = 0;
+				continue;
+			}
+		}
+
+		/* Good Receive */
+		pci_unmap_page(adapter->pdev, buffer_info->dma,
+			       buffer_info->length, PCI_DMA_FROMDEVICE);
+		skb = buffer_info->skb;
+		length = le16_to_cpu(rrd->xsz.xsum_sz.pkt_size);
+
+		skb_put(skb, length - ETHERNET_FCS_SIZE);
+
+		/* Receive Checksum Offload */
+		atl1_rx_checksum(adapter, rrd, skb);
+		skb->protocol = eth_type_trans(skb, adapter->netdev);
+
+		if (adapter->vlgrp && (rrd->pkt_flg & PACKET_FLAG_VLAN_INS)) {
+			u16 vlan_tag = (rrd->vlan_tag >> 4) |
+					((rrd->vlan_tag & 7) << 13) |
+					((rrd->vlan_tag & 8) << 9);
+			vlan_hwaccel_rx(skb, adapter->vlgrp, vlan_tag);
+		} else
+			netif_rx(skb);
+
+		/* let protocol layer free skb */
+		buffer_info->skb = NULL;
+		buffer_info->alloced = 0;
+		rrd->xsz.valid = 0;
+
+		adapter->netdev->last_rx = jiffies;
+	}
+
+	atomic_set(&rrd_ring->next_to_clean, rrd_next_to_clean);
+
+	atl1_alloc_rx_buffers(adapter);
+
+	/* update mailbox ? */
+	if (count) {
+		u32 tpd_next_to_use;
+		u32 rfd_next_to_use;
+		u32 rrd_next_to_clean;
+
+		spin_lock(&adapter->mb_lock);
+
+		tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use);
+		rfd_next_to_use =
+		    atomic_read(&adapter->rfd_ring.next_to_use);
+		rrd_next_to_clean =
+		    atomic_read(&adapter->rrd_ring.next_to_clean);
+		value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) <<
+			MB_RFD_PROD_INDX_SHIFT) |
+                        ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) <<
+			MB_RRD_CONS_INDX_SHIFT) |
+                        ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) <<
+			MB_TPD_PROD_INDX_SHIFT);
+		iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX);
+		spin_unlock(&adapter->mb_lock);
+	}
+}
+
+static void atl1_intr_tx(struct atl1_adapter *adapter)
+{
+	struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+	struct atl1_buffer *buffer_info;
+	u16 sw_tpd_next_to_clean;
+	u16 cmb_tpd_next_to_clean;
+	u8 update = 0;
+
+	sw_tpd_next_to_clean = atomic_read(&tpd_ring->next_to_clean);
+	cmb_tpd_next_to_clean = le16_to_cpu(adapter->cmb.cmb->tpd_cons_idx);
+
+	while (cmb_tpd_next_to_clean != sw_tpd_next_to_clean) {
+		struct tx_packet_desc *tpd;
+		update = 1;
+		tpd = ATL1_TPD_DESC(tpd_ring, sw_tpd_next_to_clean);
+		buffer_info = &tpd_ring->buffer_info[sw_tpd_next_to_clean];
+		if (buffer_info->dma) {
+			pci_unmap_page(adapter->pdev, buffer_info->dma,
+				       buffer_info->length, PCI_DMA_TODEVICE);
+			buffer_info->dma = 0;
+		}
+
+		if (buffer_info->skb) {
+			dev_kfree_skb_irq(buffer_info->skb);
+			buffer_info->skb = NULL;
+		}
+		tpd->buffer_addr = 0;
+		tpd->desc.data = 0;
+
+		if (++sw_tpd_next_to_clean == tpd_ring->count)
+			sw_tpd_next_to_clean = 0;
+	}
+	atomic_set(&tpd_ring->next_to_clean, sw_tpd_next_to_clean);
+
+	if (netif_queue_stopped(adapter->netdev)
+	    && netif_carrier_ok(adapter->netdev))
+		netif_wake_queue(adapter->netdev);
+}
+
+static void atl1_check_for_link(struct atl1_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	u16 phy_data = 0;
+
+	spin_lock(&adapter->lock);
+	adapter->phy_timer_pending = false;
+	atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
+	atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
+	spin_unlock(&adapter->lock);
+
+	/* notify upper layer link down ASAP */
+	if (!(phy_data & BMSR_LSTATUS)) {	/* Link Down */
+		if (netif_carrier_ok(netdev)) {	/* old link state: Up */
+			printk(KERN_INFO "%s: %s link is down\n",
+			       atl1_driver_name, netdev->name);
+			adapter->link_speed = SPEED_0;
+			netif_carrier_off(netdev);
+			netif_stop_queue(netdev);
+		}
+	}
+	schedule_work(&adapter->link_chg_task);
+}
+
+/*
+ * atl1_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ * @pt_regs: CPU registers structure
+ */
+static irqreturn_t atl1_intr(int irq, void *data)
+{
+	/*struct atl1_adapter *adapter = ((struct net_device *)data)->priv;*/
+	struct atl1_adapter *adapter = netdev_priv(data);
+	u32 status;
+	u8 update_rx;
+	int max_ints = 10;
+
+	status = adapter->cmb.cmb->int_stats;
+	if (!status)
+		return IRQ_NONE;
+
+	update_rx = 0;
+
+	do {
+		/* clear CMB interrupt status at once */
+		adapter->cmb.cmb->int_stats = 0;
+
+		if (status & ISR_GPHY)	/* clear phy status */
+			atl1_clear_phy_int(adapter);
+
+		/* clear ISR status, and Enable CMB DMA/Disable Interrupt */
+		iowrite32(status | ISR_DIS_INT, adapter->hw.hw_addr + REG_ISR);
+
+		/* check if SMB intr */
+		if (status & ISR_SMB)
+			atl1_inc_smb(adapter);
+
+		/* check if PCIE PHY Link down */
+		if (status & ISR_PHY_LINKDOWN) {
+			printk(KERN_DEBUG "%s: pcie phy link down %x\n",
+				atl1_driver_name, status);
+			if (netif_running(adapter->netdev)) {	/* reset MAC */
+				iowrite32(0, adapter->hw.hw_addr + REG_IMR);
+				schedule_work(&adapter->pcie_dma_to_rst_task);
+				return IRQ_HANDLED;
+			}
+		}
+
+		/* check if DMA read/write error ? */
+		if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) {
+			printk(KERN_DEBUG
+				"%s: pcie DMA r/w error (status = 0x%x)\n",
+				atl1_driver_name, status);
+			iowrite32(0, adapter->hw.hw_addr + REG_IMR);
+			schedule_work(&adapter->pcie_dma_to_rst_task);
+			return IRQ_HANDLED;
+		}
+
+		/* link event */
+		if (status & ISR_GPHY) {
+			adapter->soft_stats.tx_carrier_errors++;
+			atl1_check_for_link(adapter);
+		}
+
+		/* transmit event */
+		if (status & ISR_CMB_TX)
+			atl1_intr_tx(adapter);
+
+		/* rx exception */
+		if (unlikely(status & (ISR_RXF_OV | ISR_RFD_UNRUN |
+				ISR_RRD_OV | ISR_HOST_RFD_UNRUN |
+				ISR_HOST_RRD_OV | ISR_CMB_RX))) {
+			if (status &
+			    (ISR_RXF_OV | ISR_RFD_UNRUN | ISR_RRD_OV |
+			     ISR_HOST_RFD_UNRUN | ISR_HOST_RRD_OV))
+				printk(KERN_INFO
+					"%s: rx exception: status = 0x%x\n",
+					atl1_driver_name, status);
+			atl1_intr_rx(adapter);
+		}
+
+		if (--max_ints < 0)
+			break;
+
+	} while ((status = adapter->cmb.cmb->int_stats));
+
+	/* re-enable Interrupt */
+	iowrite32(ISR_DIS_SMB | ISR_DIS_DMA, adapter->hw.hw_addr + REG_ISR);
+	return IRQ_HANDLED;
+}
+
+/*
+ * atl1_set_multi - Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_multi entry point is called whenever the multicast address
+ * list or the network interface flags are updated.  This routine is
+ * responsible for configuring the hardware for proper multicast,
+ * promiscuous mode, and all-multi behavior.
+ */
+static void atl1_set_multi(struct net_device *netdev)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	struct atl1_hw *hw = &adapter->hw;
+	struct dev_mc_list *mc_ptr;
+	u32 rctl;
+	u32 hash_value;
+
+	/* Check for Promiscuous and All Multicast modes */
+	rctl = ioread32(hw->hw_addr + REG_MAC_CTRL);
+	if (netdev->flags & IFF_PROMISC)
+		rctl |= MAC_CTRL_PROMIS_EN;
+	else if (netdev->flags & IFF_ALLMULTI) {
+		rctl |= MAC_CTRL_MC_ALL_EN;
+		rctl &= ~MAC_CTRL_PROMIS_EN;
+	} else
+		rctl &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN);
+
+	iowrite32(rctl, hw->hw_addr + REG_MAC_CTRL);
+
+	/* clear the old settings from the multicast hash table */
+	iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE);
+	iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2));
+
+	/* compute mc addresses' hash value ,and put it into hash table */
+	for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
+		hash_value = atl1_hash_mc_addr(hw, mc_ptr->dmi_addr);
+		atl1_hash_set(hw, hash_value);
+	}
+}
+
+static void atl1_setup_mac_ctrl(struct atl1_adapter *adapter)
+{
+	u32 value;
+	struct atl1_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+	/* Config MAC CTRL Register */
+	value = MAC_CTRL_TX_EN | MAC_CTRL_RX_EN;
+	/* duplex */
+	if (FULL_DUPLEX == adapter->link_duplex)
+		value |= MAC_CTRL_DUPLX;
+	/* speed */
+	value |= ((u32) ((SPEED_1000 == adapter->link_speed) ?
+			 MAC_CTRL_SPEED_1000 : MAC_CTRL_SPEED_10_100) <<
+		  MAC_CTRL_SPEED_SHIFT);
+	/* flow control */
+	value |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW);
+	/* PAD & CRC */
+	value |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD);
+	/* preamble length */
+	value |= (((u32) adapter->hw.preamble_len
+		   & MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT);
+	/* vlan */
+	if (adapter->vlgrp)
+		value |= MAC_CTRL_RMV_VLAN;
+	/* rx checksum
+	   if (adapter->rx_csum)
+	   value |= MAC_CTRL_RX_CHKSUM_EN;
+	 */
+	/* filter mode */
+	value |= MAC_CTRL_BC_EN;
+	if (netdev->flags & IFF_PROMISC)
+		value |= MAC_CTRL_PROMIS_EN;
+	else if (netdev->flags & IFF_ALLMULTI)
+		value |= MAC_CTRL_MC_ALL_EN;
+	/* value |= MAC_CTRL_LOOPBACK; */
+	iowrite32(value, hw->hw_addr + REG_MAC_CTRL);
+}
+
+static u32 atl1_check_link(struct atl1_adapter *adapter)
+{
+	struct atl1_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+	u32 ret_val;
+	u16 speed, duplex, phy_data;
+	int reconfig = 0;
+
+	/* MII_BMSR must read twice */
+	atl1_read_phy_reg(hw, MII_BMSR, &phy_data);
+	atl1_read_phy_reg(hw, MII_BMSR, &phy_data);
+	if (!(phy_data & BMSR_LSTATUS)) {	/* link down */
+		if (netif_carrier_ok(netdev)) {	/* old link state: Up */
+			printk(KERN_INFO "%s: link is down\n",
+				atl1_driver_name);
+			adapter->link_speed = SPEED_0;
+			netif_carrier_off(netdev);
+			netif_stop_queue(netdev);
+		}
+		return ATL1_SUCCESS;
+	}
+
+	/* Link Up */
+	ret_val = atl1_get_speed_and_duplex(hw, &speed, &duplex);
+	if (ret_val)
+		return ret_val;
+
+	switch (hw->media_type) {
+	case MEDIA_TYPE_1000M_FULL:
+		if (speed != SPEED_1000 || duplex != FULL_DUPLEX)
+			reconfig = 1;
+		break;
+	case MEDIA_TYPE_100M_FULL:
+		if (speed != SPEED_100 || duplex != FULL_DUPLEX)
+			reconfig = 1;
+		break;
+	case MEDIA_TYPE_100M_HALF:
+		if (speed != SPEED_100 || duplex != HALF_DUPLEX)
+			reconfig = 1;
+		break;
+	case MEDIA_TYPE_10M_FULL:
+		if (speed != SPEED_10 || duplex != FULL_DUPLEX)
+			reconfig = 1;
+		break;
+	case MEDIA_TYPE_10M_HALF:
+		if (speed != SPEED_10 || duplex != HALF_DUPLEX)
+			reconfig = 1;
+		break;
+	}
+
+	/* link result is our setting */
+	if (!reconfig) {
+		if (adapter->link_speed != speed
+		    || adapter->link_duplex != duplex) {
+			adapter->link_speed = speed;
+			adapter->link_duplex = duplex;
+			atl1_setup_mac_ctrl(adapter);
+			printk(KERN_INFO "%s: %s link is up %d Mbps %s\n",
+			       atl1_driver_name, netdev->name,
+			       adapter->link_speed,
+			       adapter->link_duplex ==
+			       FULL_DUPLEX ? "full duplex" : "half duplex");
+		}
+		if (!netif_carrier_ok(netdev)) {	/* Link down -> Up */
+			netif_carrier_on(netdev);
+			netif_wake_queue(netdev);
+		}
+		return ATL1_SUCCESS;
+	}
+
+	/* change orignal link status */
+	if (netif_carrier_ok(netdev)) {
+		adapter->link_speed = SPEED_0;
+		netif_carrier_off(netdev);
+		netif_stop_queue(netdev);
+	}
+
+	if (hw->media_type != MEDIA_TYPE_AUTO_SENSOR &&
+	    hw->media_type != MEDIA_TYPE_1000M_FULL) {
+		switch (hw->media_type) {
+		case MEDIA_TYPE_100M_FULL:
+			phy_data = MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 |
+			           MII_CR_RESET;
+			break;
+		case MEDIA_TYPE_100M_HALF:
+			phy_data = MII_CR_SPEED_100 | MII_CR_RESET;
+			break;
+		case MEDIA_TYPE_10M_FULL:
+			phy_data =
+			    MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET;
+			break;
+		default:	/* MEDIA_TYPE_10M_HALF: */
+			phy_data = MII_CR_SPEED_10 | MII_CR_RESET;
+			break;
+		}
+		atl1_write_phy_reg(hw, MII_BMCR, phy_data);
+		return ATL1_SUCCESS;
+	}
+
+	/* auto-neg, insert timer to re-config phy */
+	if (!adapter->phy_timer_pending) {
+		adapter->phy_timer_pending = true;
+		mod_timer(&adapter->phy_config_timer, jiffies + 3 * HZ);
+	}
+
+	return ATL1_SUCCESS;
+}
+
+static void set_flow_ctrl_old(struct atl1_adapter *adapter)
+{
+	u32 hi, lo, value;
+
+	/* RFD Flow Control */
+	value = adapter->rfd_ring.count;
+	hi = value / 16;
+	if (hi < 2)
+		hi = 2;
+	lo = value * 7 / 8;
+
+	value = ((hi & RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT) |
+	    ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT);
+	iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RXF_PAUSE_THRESH);
+
+	/* RRD Flow Control */
+	value = adapter->rrd_ring.count;
+	lo = value / 16;
+	hi = value * 7 / 8;
+	if (lo < 2)
+		lo = 2;
+	value = ((hi & RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT) |
+	    ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT);
+	iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RRD_PAUSE_THRESH);
+}
+
+static void set_flow_ctrl_new(struct atl1_hw *hw)
+{
+	u32 hi, lo, value;
+
+	/* RXF Flow Control */
+	value = ioread32(hw->hw_addr + REG_SRAM_RXF_LEN);
+	lo = value / 16;
+	if (lo < 192)
+		lo = 192;
+	hi = value * 7 / 8;
+	if (hi < lo)
+		hi = lo + 16;
+	value = ((hi & RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT) |
+	    ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT);
+	iowrite32(value, hw->hw_addr + REG_RXQ_RXF_PAUSE_THRESH);
+
+	/* RRD Flow Control */
+	value = ioread32(hw->hw_addr + REG_SRAM_RRD_LEN);
+	lo = value / 8;
+	hi = value * 7 / 8;
+	if (lo < 2)
+		lo = 2;
+	if (hi < lo)
+		hi = lo + 3;
+	value = ((hi & RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT) |
+	    ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT);
+	iowrite32(value, hw->hw_addr + REG_RXQ_RRD_PAUSE_THRESH);
+}
+
+/*
+ * atl1_configure - Configure Transmit&Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx /Rx unit of the MAC after a reset.
+ */
+static u32 atl1_configure(struct atl1_adapter *adapter)
+{
+	struct atl1_hw *hw = &adapter->hw;
+	u32 value;
+
+	/* clear interrupt status */
+	iowrite32(0xffffffff, adapter->hw.hw_addr + REG_ISR);
+
+	/* set MAC Address */
+	value = (((u32) hw->mac_addr[2]) << 24) |
+		(((u32) hw->mac_addr[3]) << 16) |
+		(((u32) hw->mac_addr[4]) << 8) |
+		(((u32) hw->mac_addr[5]));
+	iowrite32(value, hw->hw_addr + REG_MAC_STA_ADDR);
+	value = (((u32) hw->mac_addr[0]) << 8) | (((u32) hw->mac_addr[1]));
+	iowrite32(value, hw->hw_addr + (REG_MAC_STA_ADDR + 4));
+
+	/* tx / rx ring */
+
+	/* HI base address */
+	iowrite32((u32) ((adapter->tpd_ring.dma & 0xffffffff00000000ULL) >> 32),
+		hw->hw_addr + REG_DESC_BASE_ADDR_HI);
+	/* LO base address */
+	iowrite32((u32) (adapter->rfd_ring.dma & 0x00000000ffffffffULL),
+		hw->hw_addr + REG_DESC_RFD_ADDR_LO);
+	iowrite32((u32) (adapter->rrd_ring.dma & 0x00000000ffffffffULL),
+		hw->hw_addr + REG_DESC_RRD_ADDR_LO);
+	iowrite32((u32) (adapter->tpd_ring.dma & 0x00000000ffffffffULL),
+		hw->hw_addr + REG_DESC_TPD_ADDR_LO);
+	iowrite32((u32) (adapter->cmb.dma & 0x00000000ffffffffULL),
+		hw->hw_addr + REG_DESC_CMB_ADDR_LO);
+	iowrite32((u32) (adapter->smb.dma & 0x00000000ffffffffULL),
+		hw->hw_addr + REG_DESC_SMB_ADDR_LO);
+
+	/* element count */
+	value = adapter->rrd_ring.count;
+	value <<= 16;
+	value += adapter->rfd_ring.count;
+	iowrite32(value, hw->hw_addr + REG_DESC_RFD_RRD_RING_SIZE);
+	iowrite32(adapter->tpd_ring.count, hw->hw_addr + REG_DESC_TPD_RING_SIZE);
+
+	/* Load Ptr */
+	iowrite32(1, hw->hw_addr + REG_LOAD_PTR);
+
+	/* config Mailbox */
+	value = ((atomic_read(&adapter->tpd_ring.next_to_use)
+		  & MB_TPD_PROD_INDX_MASK) << MB_TPD_PROD_INDX_SHIFT) |
+	    ((atomic_read(&adapter->rrd_ring.next_to_clean)
+	      & MB_RRD_CONS_INDX_MASK) << MB_RRD_CONS_INDX_SHIFT) |
+	    ((atomic_read(&adapter->rfd_ring.next_to_use)
+	      & MB_RFD_PROD_INDX_MASK) << MB_RFD_PROD_INDX_SHIFT);
+	iowrite32(value, hw->hw_addr + REG_MAILBOX);
+
+	/* config IPG/IFG */
+	value = (((u32) hw->ipgt & MAC_IPG_IFG_IPGT_MASK)
+		 << MAC_IPG_IFG_IPGT_SHIFT) |
+	    (((u32) hw->min_ifg & MAC_IPG_IFG_MIFG_MASK)
+	     << MAC_IPG_IFG_MIFG_SHIFT) |
+	    (((u32) hw->ipgr1 & MAC_IPG_IFG_IPGR1_MASK)
+	     << MAC_IPG_IFG_IPGR1_SHIFT) |
+	    (((u32) hw->ipgr2 & MAC_IPG_IFG_IPGR2_MASK)
+	     << MAC_IPG_IFG_IPGR2_SHIFT);
+	iowrite32(value, hw->hw_addr + REG_MAC_IPG_IFG);
+
+	/* config  Half-Duplex Control */
+	value = ((u32) hw->lcol & MAC_HALF_DUPLX_CTRL_LCOL_MASK) |
+	    (((u32) hw->max_retry & MAC_HALF_DUPLX_CTRL_RETRY_MASK)
+	     << MAC_HALF_DUPLX_CTRL_RETRY_SHIFT) |
+	    MAC_HALF_DUPLX_CTRL_EXC_DEF_EN |
+	    (0xa << MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT) |
+	    (((u32) hw->jam_ipg & MAC_HALF_DUPLX_CTRL_JAMIPG_MASK)
+	     << MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT);
+	iowrite32(value, hw->hw_addr + REG_MAC_HALF_DUPLX_CTRL);
+
+	/* set Interrupt Moderator Timer */
+	iowrite16(adapter->imt, hw->hw_addr + REG_IRQ_MODU_TIMER_INIT);
+	iowrite32(MASTER_CTRL_ITIMER_EN, hw->hw_addr + REG_MASTER_CTRL);
+
+	/* set Interrupt Clear Timer */
+	iowrite16(adapter->ict, hw->hw_addr + REG_CMBDISDMA_TIMER);
+
+	/* set MTU, 4 : VLAN */
+	iowrite32(hw->max_frame_size + 4, hw->hw_addr + REG_MTU);
+
+	/* jumbo size & rrd retirement timer */
+	value = (((u32) hw->rx_jumbo_th & RXQ_JMBOSZ_TH_MASK)
+		 << RXQ_JMBOSZ_TH_SHIFT) |
+	    (((u32) hw->rx_jumbo_lkah & RXQ_JMBO_LKAH_MASK)
+	     << RXQ_JMBO_LKAH_SHIFT) |
+	    (((u32) hw->rrd_ret_timer & RXQ_RRD_TIMER_MASK)
+	     << RXQ_RRD_TIMER_SHIFT);
+	iowrite32(value, hw->hw_addr + REG_RXQ_JMBOSZ_RRDTIM);
+
+	/* Flow Control */
+	switch (hw->dev_rev) {
+	case 0x8001:
+	case 0x9001:
+	case 0x9002:
+	case 0x9003:
+		set_flow_ctrl_old(adapter);
+		break;
+	default:
+		set_flow_ctrl_new(hw);
+		break;
+	}
+
+	/* config TXQ */
+	value = (((u32) hw->tpd_burst & TXQ_CTRL_TPD_BURST_NUM_MASK)
+		 << TXQ_CTRL_TPD_BURST_NUM_SHIFT) |
+	    (((u32) hw->txf_burst & TXQ_CTRL_TXF_BURST_NUM_MASK)
+	     << TXQ_CTRL_TXF_BURST_NUM_SHIFT) |
+	    (((u32) hw->tpd_fetch_th & TXQ_CTRL_TPD_FETCH_TH_MASK)
+	     << TXQ_CTRL_TPD_FETCH_TH_SHIFT) | TXQ_CTRL_ENH_MODE | TXQ_CTRL_EN;
+	iowrite32(value, hw->hw_addr + REG_TXQ_CTRL);
+
+	/* min tpd fetch gap & tx jumbo packet size threshold for taskoffload */
+	value = (((u32) hw->tx_jumbo_task_th & TX_JUMBO_TASK_TH_MASK)
+		 << TX_JUMBO_TASK_TH_SHIFT) |
+	    (((u32) hw->tpd_fetch_gap & TX_TPD_MIN_IPG_MASK)
+	     << TX_TPD_MIN_IPG_SHIFT);
+	iowrite32(value, hw->hw_addr + REG_TX_JUMBO_TASK_TH_TPD_IPG);
+
+	/* config RXQ */
+	value = (((u32) hw->rfd_burst & RXQ_CTRL_RFD_BURST_NUM_MASK)
+		 << RXQ_CTRL_RFD_BURST_NUM_SHIFT) |
+	    (((u32) hw->rrd_burst & RXQ_CTRL_RRD_BURST_THRESH_MASK)
+	     << RXQ_CTRL_RRD_BURST_THRESH_SHIFT) |
+	    (((u32) hw->rfd_fetch_gap & RXQ_CTRL_RFD_PREF_MIN_IPG_MASK)
+	     << RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT) |
+	    RXQ_CTRL_CUT_THRU_EN | RXQ_CTRL_EN;
+	iowrite32(value, hw->hw_addr + REG_RXQ_CTRL);
+
+	/* config DMA Engine */
+	value = ((((u32) hw->dmar_block) & DMA_CTRL_DMAR_BURST_LEN_MASK)
+		 << DMA_CTRL_DMAR_BURST_LEN_SHIFT) |
+	    ((((u32) hw->dmaw_block) & DMA_CTRL_DMAR_BURST_LEN_MASK)
+	     << DMA_CTRL_DMAR_BURST_LEN_SHIFT) |
+	    DMA_CTRL_DMAR_EN | DMA_CTRL_DMAW_EN;
+	value |= (u32) hw->dma_ord;
+	if (atl1_rcb_128 == hw->rcb_value)
+		value |= DMA_CTRL_RCB_VALUE;
+	iowrite32(value, hw->hw_addr + REG_DMA_CTRL);
+
+	/* config CMB / SMB */
+	value = hw->cmb_rrd | ((u32) hw->cmb_tpd << 16);
+	iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TH);
+	value = hw->cmb_rx_timer | ((u32) hw->cmb_tx_timer << 16);
+	iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TIMER);
+	iowrite32(hw->smb_timer, hw->hw_addr + REG_SMB_TIMER);
+
+	/* --- enable CMB / SMB */
+	value = CSMB_CTRL_CMB_EN | CSMB_CTRL_SMB_EN;
+	iowrite32(value, hw->hw_addr + REG_CSMB_CTRL);
+
+	value = ioread32(adapter->hw.hw_addr + REG_ISR);
+	if (unlikely((value & ISR_PHY_LINKDOWN) != 0))
+		value = 1;	/* config failed */
+	else
+		value = 0;
+
+	/* clear all interrupt status */
+	iowrite32(0x3fffffff, adapter->hw.hw_addr + REG_ISR);
+	iowrite32(0, adapter->hw.hw_addr + REG_ISR);
+	return value;
+}
+
+/*
+ * atl1_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ */
+static void atl1_irq_disable(struct atl1_adapter *adapter)
+{
+	atomic_inc(&adapter->irq_sem);
+	iowrite32(0, adapter->hw.hw_addr + REG_IMR);
+	ioread32(adapter->hw.hw_addr + REG_IMR);
+	synchronize_irq(adapter->pdev->irq);
+}
+
+static void atl1_vlan_rx_register(struct net_device *netdev,
+				struct vlan_group *grp)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	unsigned long flags;
+	u32 ctrl;
+
+	spin_lock_irqsave(&adapter->lock, flags);
+	/* atl1_irq_disable(adapter); */
+	adapter->vlgrp = grp;
+
+	if (grp) {
+		/* enable VLAN tag insert/strip */
+		ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL);
+		ctrl |= MAC_CTRL_RMV_VLAN;
+		iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL);
+	} else {
+		/* disable VLAN tag insert/strip */
+		ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL);
+		ctrl &= ~MAC_CTRL_RMV_VLAN;
+		iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL);
+	}
+
+	/* atl1_irq_enable(adapter); */
+	spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+/* FIXME: justify or remove -- CHS */
+static void atl1_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+	/* We don't do Vlan filtering */
+	return;
+}
+
+/* FIXME: this looks wrong too -- CHS */
+static void atl1_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->lock, flags);
+	/* atl1_irq_disable(adapter); */
+	if (adapter->vlgrp)
+		adapter->vlgrp->vlan_devices[vid] = NULL;
+	/* atl1_irq_enable(adapter); */
+	spin_unlock_irqrestore(&adapter->lock, flags);
+	/* We don't do Vlan filtering */
+	return;
+}
+
+static void atl1_restore_vlan(struct atl1_adapter *adapter)
+{
+	atl1_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+	if (adapter->vlgrp) {
+		u16 vid;
+		for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+			if (!adapter->vlgrp->vlan_devices[vid])
+				continue;
+			atl1_vlan_rx_add_vid(adapter->netdev, vid);
+		}
+	}
+}
+
+static u16 tpd_avail(struct atl1_tpd_ring *tpd_ring)
+{
+	u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean);
+	u16 next_to_use = atomic_read(&tpd_ring->next_to_use);
+	return ((next_to_clean >
+		 next_to_use) ? next_to_clean - next_to_use -
+		1 : tpd_ring->count + next_to_clean - next_to_use - 1);
+}
+
+static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb,
+			 struct tso_param *tso)
+{
+	/* We enter this function holding a spinlock. */
+	u8 ipofst;
+	int err;
+
+	if (skb_shinfo(skb)->gso_size) {
+		if (skb_header_cloned(skb)) {
+			err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+			if (unlikely(err))
+				return err;
+		}
+
+		if (skb->protocol == ntohs(ETH_P_IP)) {
+			skb->nh.iph->tot_len = 0;
+			skb->nh.iph->check = 0;
+			skb->h.th->check =
+			    ~csum_tcpudp_magic(skb->nh.iph->saddr,
+					       skb->nh.iph->daddr, 0,
+					       IPPROTO_TCP, 0);
+			ipofst = skb->nh.raw - skb->data;
+			if (ipofst != ENET_HEADER_SIZE) /* 802.3 frame */
+				tso->tsopl |= 1 << TSO_PARAM_ETHTYPE_SHIFT;
+
+			tso->tsopl |= (skb->nh.iph->ihl &
+				CSUM_PARAM_IPHL_MASK) << CSUM_PARAM_IPHL_SHIFT;
+			tso->tsopl |= ((skb->h.th->doff << 2) &
+				TSO_PARAM_TCPHDRLEN_MASK) << TSO_PARAM_TCPHDRLEN_SHIFT;
+			tso->tsopl |= (skb_shinfo(skb)->gso_size &
+				TSO_PARAM_MSS_MASK) << TSO_PARAM_MSS_SHIFT;
+			tso->tsopl |= 1 << TSO_PARAM_IPCKSUM_SHIFT;
+			tso->tsopl |= 1 << TSO_PARAM_TCPCKSUM_SHIFT;
+			tso->tsopl |= 1 << TSO_PARAM_SEGMENT_SHIFT;
+			return true;
+		}
+	}
+	return false;
+}
+
+static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb,
+			struct csum_param *csum)
+{
+	u8 css, cso;
+
+	if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
+		cso = skb->h.raw - skb->data;
+		css = (skb->h.raw + skb->csum) - skb->data;
+		if (unlikely(cso & 0x1)) {
+			printk(KERN_DEBUG "%s: payload offset != even number\n",
+				atl1_driver_name);
+			return -1;
+		}
+		csum->csumpl |= (cso & CSUM_PARAM_PLOADOFFSET_MASK) <<
+			CSUM_PARAM_PLOADOFFSET_SHIFT;
+		csum->csumpl |= (css & CSUM_PARAM_XSUMOFFSET_MASK) <<
+			CSUM_PARAM_XSUMOFFSET_SHIFT;
+		csum->csumpl |= 1 << CSUM_PARAM_CUSTOMCKSUM_SHIFT;
+		return true;
+	}
+
+	return true;
+}
+
+static void atl1_tx_map(struct atl1_adapter *adapter,
+				struct sk_buff *skb, bool tcp_seg)
+{
+	/* We enter this function holding a spinlock. */
+	struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+	struct atl1_buffer *buffer_info;
+	struct page *page;
+	int first_buf_len = skb->len;
+	unsigned long offset;
+	unsigned int nr_frags;
+	unsigned int f;
+	u16 tpd_next_to_use;
+	u16 proto_hdr_len;
+	u16 i, m, len12;
+
+	first_buf_len -= skb->data_len;
+	nr_frags = skb_shinfo(skb)->nr_frags;
+	tpd_next_to_use = atomic_read(&tpd_ring->next_to_use);
+	buffer_info = &tpd_ring->buffer_info[tpd_next_to_use];
+	if (unlikely(buffer_info->skb))
+		BUG();
+	buffer_info->skb = NULL;	/* put skb in last TPD */
+
+	if (tcp_seg) {
+		/* TSO/GSO */
+		proto_hdr_len =
+		    ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
+		buffer_info->length = proto_hdr_len;
+		page = virt_to_page(skb->data);
+		offset = (unsigned long)skb->data & ~PAGE_MASK;
+		buffer_info->dma = pci_map_page(adapter->pdev, page,
+						offset, proto_hdr_len,
+						PCI_DMA_TODEVICE);
+
+		if (++tpd_next_to_use == tpd_ring->count)
+			tpd_next_to_use = 0;
+
+		if (first_buf_len > proto_hdr_len) {
+			len12 = first_buf_len - proto_hdr_len;
+			m = (len12 + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+			for (i = 0; i < m; i++) {
+				buffer_info =
+				    &tpd_ring->buffer_info[tpd_next_to_use];
+				buffer_info->skb = NULL;
+				buffer_info->length =
+				    (MAX_TX_BUF_LEN >=
+				     len12) ? MAX_TX_BUF_LEN : len12;
+				len12 -= buffer_info->length;
+				page = virt_to_page(skb->data +
+						 (proto_hdr_len +
+						  i * MAX_TX_BUF_LEN));
+				offset = (unsigned long)(skb->data +
+							(proto_hdr_len +
+							i * MAX_TX_BUF_LEN)) &
+							~PAGE_MASK;
+				buffer_info->dma =
+				    pci_map_page(adapter->pdev, page, offset,
+						 buffer_info->length,
+						 PCI_DMA_TODEVICE);
+				if (++tpd_next_to_use == tpd_ring->count)
+					tpd_next_to_use = 0;
+			}
+		}
+	} else {
+		/* not TSO/GSO */
+		buffer_info->length = first_buf_len;
+		page = virt_to_page(skb->data);
+		offset = (unsigned long)skb->data & ~PAGE_MASK;
+		buffer_info->dma = pci_map_page(adapter->pdev, page,
+						offset, first_buf_len,
+						PCI_DMA_TODEVICE);
+		if (++tpd_next_to_use == tpd_ring->count)
+			tpd_next_to_use = 0;
+	}
+
+	for (f = 0; f < nr_frags; f++) {
+		struct skb_frag_struct *frag;
+		u16 lenf, i, m;
+
+		frag = &skb_shinfo(skb)->frags[f];
+		lenf = frag->size;
+
+		m = (lenf + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+		for (i = 0; i < m; i++) {
+			buffer_info = &tpd_ring->buffer_info[tpd_next_to_use];
+			if (unlikely(buffer_info->skb))
+				BUG();
+			buffer_info->skb = NULL;
+			buffer_info->length =
+			    (lenf > MAX_TX_BUF_LEN) ? MAX_TX_BUF_LEN : lenf;
+			lenf -= buffer_info->length;
+			buffer_info->dma =
+			    pci_map_page(adapter->pdev, frag->page,
+					 frag->page_offset + i * MAX_TX_BUF_LEN,
+					 buffer_info->length, PCI_DMA_TODEVICE);
+
+			if (++tpd_next_to_use == tpd_ring->count)
+				tpd_next_to_use = 0;
+		}
+	}
+
+	/* last tpd's buffer-info */
+	buffer_info->skb = skb;
+}
+
+static void atl1_tx_queue(struct atl1_adapter *adapter, int count,
+			       union tpd_descr *descr)
+{
+	/* We enter this function holding a spinlock. */
+	struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+	int j;
+	u32 val;
+	struct atl1_buffer *buffer_info;
+	struct tx_packet_desc *tpd;
+	u16 tpd_next_to_use = atomic_read(&tpd_ring->next_to_use);
+
+	for (j = 0; j < count; j++) {
+		buffer_info = &tpd_ring->buffer_info[tpd_next_to_use];
+		tpd = ATL1_TPD_DESC(&adapter->tpd_ring, tpd_next_to_use);
+		tpd->desc.csum.csumpu = descr->csum.csumpu;
+		tpd->desc.csum.csumpl = descr->csum.csumpl;
+		tpd->desc.tso.tsopu = descr->tso.tsopu;
+		tpd->desc.tso.tsopl = descr->tso.tsopl;
+		tpd->buffer_addr = cpu_to_le64(buffer_info->dma);
+		tpd->desc.data = descr->data;
+		tpd->desc.csum.csumpu |= (cpu_to_le16(buffer_info->length) &
+			CSUM_PARAM_BUFLEN_MASK) << CSUM_PARAM_BUFLEN_SHIFT;
+
+		val = (descr->tso.tsopl >> TSO_PARAM_SEGMENT_SHIFT) &
+			TSO_PARAM_SEGMENT_MASK;
+		if (val && !j)
+			tpd->desc.tso.tsopl |= 1 << TSO_PARAM_HDRFLAG_SHIFT;
+
+		if (j == (count - 1))
+			tpd->desc.csum.csumpl |= 1 << CSUM_PARAM_EOP_SHIFT;
+
+		if (++tpd_next_to_use == tpd_ring->count)
+			tpd_next_to_use = 0;
+	}
+	/*
+	 * Force memory writes to complete before letting h/w
+	 * know there are new descriptors to fetch.  (Only
+	 * applicable for weak-ordered memory model archs,
+	 * such as IA-64).
+	 */
+	wmb();
+
+	atomic_set(&tpd_ring->next_to_use, (int)tpd_next_to_use);
+}
+
+static void atl1_update_mailbox(struct atl1_adapter *adapter)
+{
+	unsigned long flags;
+	u32 tpd_next_to_use;
+	u32 rfd_next_to_use;
+	u32 rrd_next_to_clean;
+	u32 value;
+
+	spin_lock_irqsave(&adapter->mb_lock, flags);
+
+	tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use);
+	rfd_next_to_use = atomic_read(&adapter->rfd_ring.next_to_use);
+	rrd_next_to_clean = atomic_read(&adapter->rrd_ring.next_to_clean);
+
+	value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) <<
+		MB_RFD_PROD_INDX_SHIFT) |
+		((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) <<
+		MB_RRD_CONS_INDX_SHIFT) |
+		((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) <<
+		MB_TPD_PROD_INDX_SHIFT);
+	iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX);
+
+	spin_unlock_irqrestore(&adapter->mb_lock, flags);
+}
+
+static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	int len = skb->len;
+	int tso;
+	int count = 1;
+	int ret_val;
+	u32 val;
+	union tpd_descr param;
+	u16 frag_size;
+	u16 vlan_tag;
+	unsigned long flags;
+	unsigned int nr_frags = 0;
+	unsigned int mss = 0;
+	unsigned int f;
+	unsigned int proto_hdr_len;
+
+	len -= skb->data_len;
+
+	if (unlikely(skb->len == 0)) {
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	param.data = 0;
+	param.tso.tsopu = 0;
+	param.tso.tsopl = 0;
+	param.csum.csumpu = 0;
+	param.csum.csumpl = 0;
+
+	/* nr_frags will be nonzero if we're doing scatter/gather (SG) */
+	nr_frags = skb_shinfo(skb)->nr_frags;
+	for (f = 0; f < nr_frags; f++) {
+		frag_size = skb_shinfo(skb)->frags[f].size;
+		if (frag_size)
+			count +=
+			    (frag_size + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+	}
+
+	/* mss will be nonzero if we're doing segment offload (TSO/GSO) */
+	mss = skb_shinfo(skb)->gso_size;
+	if (mss) {
+		if (skb->protocol == ntohs(ETH_P_IP)) {
+			proto_hdr_len = ((skb->h.raw - skb->data) +
+					 (skb->h.th->doff << 2));
+			if (unlikely(proto_hdr_len > len)) {
+				dev_kfree_skb_any(skb);
+				return NETDEV_TX_OK;
+			}
+			/* need additional TPD ? */
+			if (proto_hdr_len != len)
+				count += (len - proto_hdr_len +
+					MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+		}
+	}
+
+	local_irq_save(flags);
+	if (!spin_trylock(&adapter->lock)) {
+		/* Can't get lock - tell upper layer to requeue */
+		local_irq_restore(flags);
+		printk(KERN_DEBUG "%s: TX locked\n", atl1_driver_name);
+		return NETDEV_TX_LOCKED;
+	}
+
+	if (tpd_avail(&adapter->tpd_ring) < count) {
+		/* not enough descriptors */
+		netif_stop_queue(netdev);
+		spin_unlock_irqrestore(&adapter->lock, flags);
+		printk(KERN_DEBUG "%s: TX busy\n", atl1_driver_name);
+		return NETDEV_TX_BUSY;
+	}
+
+	param.data = 0;
+
+	if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+		vlan_tag = vlan_tx_tag_get(skb);
+		vlan_tag = (vlan_tag << 4) | (vlan_tag >> 13) |
+			((vlan_tag >> 9) & 0x8);
+		param.csum.csumpl |= 1 << CSUM_PARAM_INSVLAG_SHIFT;
+		param.csum.csumpu |= (vlan_tag & CSUM_PARAM_VALANTAG_MASK) <<
+			CSUM_PARAM_VALAN_SHIFT;
+	}
+
+	tso = atl1_tso(adapter, skb, &param.tso);
+	if (tso < 0) {
+		spin_unlock_irqrestore(&adapter->lock, flags);
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	if (!tso) {
+		ret_val = atl1_tx_csum(adapter, skb, &param.csum);
+		if (ret_val < 0) {
+			spin_unlock_irqrestore(&adapter->lock, flags);
+			dev_kfree_skb_any(skb);
+			return NETDEV_TX_OK;
+		}
+	}
+
+	val = (param.csum.csumpl >> CSUM_PARAM_SEGMENT_SHIFT) &
+		CSUM_PARAM_SEGMENT_MASK;
+	atl1_tx_map(adapter, skb, 1 == val);
+	atl1_tx_queue(adapter, count, &param);
+	netdev->trans_start = jiffies;
+	spin_unlock_irqrestore(&adapter->lock, flags);
+	atl1_update_mailbox(adapter);
+	return NETDEV_TX_OK;
+}
+
+/*
+ * atl1_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ */
+static struct net_device_stats *atl1_get_stats(struct net_device *netdev)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	return &adapter->net_stats;
+}
+
+/*
+ * atl1_clean_rx_ring - Free RFD Buffers
+ * @adapter: board private structure
+ */
+static void atl1_clean_rx_ring(struct atl1_adapter *adapter)
+{
+	struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+	struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
+	struct atl1_buffer *buffer_info;
+	struct pci_dev *pdev = adapter->pdev;
+	unsigned long size;
+	unsigned int i;
+
+	/* Free all the Rx ring sk_buffs */
+	for (i = 0; i < rfd_ring->count; i++) {
+		buffer_info = &rfd_ring->buffer_info[i];
+		if (buffer_info->dma) {
+			pci_unmap_page(pdev,
+					buffer_info->dma,
+					buffer_info->length,
+					PCI_DMA_FROMDEVICE);
+			buffer_info->dma = 0;
+		}
+		if (buffer_info->skb) {
+			dev_kfree_skb(buffer_info->skb);
+			buffer_info->skb = NULL;
+		}
+	}
+
+	size = sizeof(struct atl1_buffer) * rfd_ring->count;
+	memset(rfd_ring->buffer_info, 0, size);
+
+	/* Zero out the descriptor ring */
+	memset(rfd_ring->desc, 0, rfd_ring->size);
+
+	rfd_ring->next_to_clean = 0;
+	atomic_set(&rfd_ring->next_to_use, 0);
+
+	rrd_ring->next_to_use = 0;
+	atomic_set(&rrd_ring->next_to_clean, 0);
+}
+
+/*
+ * atl1_clean_tx_ring - Free Tx Buffers
+ * @adapter: board private structure
+ */
+static void atl1_clean_tx_ring(struct atl1_adapter *adapter)
+{
+	struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+	struct atl1_buffer *buffer_info;
+	struct pci_dev *pdev = adapter->pdev;
+	unsigned long size;
+	unsigned int i;
+
+	/* Free all the Tx ring sk_buffs */
+	for (i = 0; i < tpd_ring->count; i++) {
+		buffer_info = &tpd_ring->buffer_info[i];
+		if (buffer_info->dma) {
+			pci_unmap_page(pdev, buffer_info->dma,
+				       buffer_info->length, PCI_DMA_TODEVICE);
+			buffer_info->dma = 0;
+		}
+	}
+
+	for (i = 0; i < tpd_ring->count; i++) {
+		buffer_info = &tpd_ring->buffer_info[i];
+		if (buffer_info->skb) {
+			dev_kfree_skb_any(buffer_info->skb);
+			buffer_info->skb = NULL;
+		}
+	}
+
+	size = sizeof(struct atl1_buffer) * tpd_ring->count;
+	memset(tpd_ring->buffer_info, 0, size);
+
+	/* Zero out the descriptor ring */
+	memset(tpd_ring->desc, 0, tpd_ring->size);
+
+	atomic_set(&tpd_ring->next_to_use, 0);
+	atomic_set(&tpd_ring->next_to_clean, 0);
+}
+
+/*
+ * atl1_free_ring_resources - Free Tx / RX descriptor Resources
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ */
+void atl1_free_ring_resources(struct atl1_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+	struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+	struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
+	struct atl1_ring_header *ring_header = &adapter->ring_header;
+
+	atl1_clean_tx_ring(adapter);
+	atl1_clean_rx_ring(adapter);
+
+	kfree(tpd_ring->buffer_info);
+	pci_free_consistent(pdev, ring_header->size, ring_header->desc,
+			    ring_header->dma);
+
+	tpd_ring->buffer_info = NULL;
+	tpd_ring->desc = NULL;
+	tpd_ring->dma = 0;
+
+	rfd_ring->buffer_info = NULL;
+	rfd_ring->desc = NULL;
+	rfd_ring->dma = 0;
+
+	rrd_ring->desc = NULL;
+	rrd_ring->dma = 0;
+}
+
+s32 atl1_up(struct atl1_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	int err;
+	int irq_flags = IRQF_SAMPLE_RANDOM;
+
+	/* hardware has been reset, we need to reload some things */
+	atl1_set_multi(netdev);
+	atl1_restore_vlan(adapter);
+	err = atl1_alloc_rx_buffers(adapter);
+	if (unlikely(!err))		/* no RX BUFFER allocated */
+		return -ENOMEM;
+
+	if (unlikely(atl1_configure(adapter))) {
+		err = -EIO;
+		goto err_up;
+	}
+
+	err = pci_enable_msi(adapter->pdev);
+	if (err) {
+		dev_info(&adapter->pdev->dev,
+			"Unable to enable MSI: %d\n", err);
+		irq_flags |= IRQF_SHARED;
+	}
+
+	err = request_irq(adapter->pdev->irq, &atl1_intr, irq_flags,
+			netdev->name, netdev);
+	if (unlikely(err))
+		goto err_up;
+
+	mod_timer(&adapter->watchdog_timer, jiffies);
+	atl1_irq_enable(adapter);
+	atl1_check_link(adapter);
+	return 0;
+
+	/* FIXME: unreachable code! -- CHS */
+	/* free irq disable any interrupt */
+	iowrite32(0, adapter->hw.hw_addr + REG_IMR);
+	free_irq(adapter->pdev->irq, netdev);
+
+err_up:
+	pci_disable_msi(adapter->pdev);
+	/* free rx_buffers */
+	atl1_clean_rx_ring(adapter);
+	return err;
+}
+
+void atl1_down(struct atl1_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	del_timer_sync(&adapter->watchdog_timer);
+	del_timer_sync(&adapter->phy_config_timer);
+	adapter->phy_timer_pending = false;
+
+	atl1_irq_disable(adapter);
+	free_irq(adapter->pdev->irq, netdev);
+	pci_disable_msi(adapter->pdev);
+	atl1_reset_hw(&adapter->hw);
+	adapter->cmb.cmb->int_stats = 0;
+
+	adapter->link_speed = SPEED_0;
+	adapter->link_duplex = -1;
+	netif_carrier_off(netdev);
+	netif_stop_queue(netdev);
+
+	atl1_clean_tx_ring(adapter);
+	atl1_clean_rx_ring(adapter);
+}
+
+/*
+ * atl1_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int atl1_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	int old_mtu = netdev->mtu;
+	int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+
+	if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
+	    (max_frame > MAX_JUMBO_FRAME_SIZE)) {
+		printk(KERN_WARNING "%s: invalid MTU setting\n",
+			atl1_driver_name);
+		return -EINVAL;
+	}
+
+	adapter->hw.max_frame_size = max_frame;
+	adapter->hw.tx_jumbo_task_th = (max_frame + 7) >> 3;
+	adapter->rx_buffer_len = (max_frame + 7) & ~7;
+	adapter->hw.rx_jumbo_th = adapter->rx_buffer_len / 8;
+
+	netdev->mtu = new_mtu;
+	if ((old_mtu != new_mtu) && netif_running(netdev)) {
+		atl1_down(adapter);
+		atl1_up(adapter);
+	}
+
+	return 0;
+}
+
+/*
+ * atl1_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int atl1_set_mac(struct net_device *netdev, void *p)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	struct sockaddr *addr = p;
+
+	if (netif_running(netdev))
+		return -EBUSY;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+	memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
+
+	atl1_set_mac_addr(&adapter->hw);
+	return 0;
+}
+
+/*
+ * atl1_watchdog - Timer Call-back
+ * @data: pointer to netdev cast into an unsigned long
+ */
+static void atl1_watchdog(unsigned long data)
+{
+	struct atl1_adapter *adapter = (struct atl1_adapter *)data;
+
+	/* Reset the timer */
+	mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
+}
+
+static int mdio_read(struct net_device *netdev, int phy_id, int reg_num)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	u16 result;
+
+	atl1_read_phy_reg(&adapter->hw, reg_num & 0x1f, &result);
+
+	return result;
+}
+
+static void mdio_write(struct net_device *netdev, int phy_id, int reg_num, int val)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+
+	atl1_write_phy_reg(&adapter->hw, reg_num, val);
+}
+
+/*
+ * atl1_mii_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ */
+static int atl1_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	unsigned long flags;
+	int retval;
+
+	if (!netif_running(netdev))
+		return -EINVAL;
+
+	spin_lock_irqsave(&adapter->lock, flags);
+	retval = generic_mii_ioctl(&adapter->mii, if_mii(ifr), cmd, NULL);
+	spin_unlock_irqrestore(&adapter->lock, flags);
+
+	return retval;
+}
+
+/*
+ * atl1_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ */
+static int atl1_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	switch (cmd) {
+	case SIOCGMIIPHY:
+	case SIOCGMIIREG:
+	case SIOCSMIIREG:
+		return atl1_mii_ioctl(netdev, ifr, cmd);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+/*
+ * atl1_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ */
+static void atl1_tx_timeout(struct net_device *netdev)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	/* Do the reset outside of interrupt context */
+	schedule_work(&adapter->tx_timeout_task);
+}
+
+/*
+ * atl1_phy_config - Timer Call-back
+ * @data: pointer to netdev cast into an unsigned long
+ */
+static void atl1_phy_config(unsigned long data)
+{
+	struct atl1_adapter *adapter = (struct atl1_adapter *)data;
+	struct atl1_hw *hw = &adapter->hw;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->lock, flags);
+	adapter->phy_timer_pending = false;
+	atl1_write_phy_reg(hw, MII_ADVERTISE, hw->mii_autoneg_adv_reg);
+	atl1_write_phy_reg(hw, MII_AT001_CR, hw->mii_1000t_ctrl_reg);
+	atl1_write_phy_reg(hw, MII_BMCR, MII_CR_RESET | MII_CR_AUTO_NEG_EN);
+	spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+int atl1_reset(struct atl1_adapter *adapter)
+{
+	int ret;
+
+	ret = atl1_reset_hw(&adapter->hw);
+	if (ret != ATL1_SUCCESS)
+		return ret;
+	return atl1_init_hw(&adapter->hw);
+}
+
+/*
+ * atl1_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ */
+static int atl1_open(struct net_device *netdev)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	int err;
+
+	/* allocate transmit descriptors */
+	err = atl1_setup_ring_resources(adapter);
+	if (err)
+		return err;
+
+	err = atl1_up(adapter);
+	if (err)
+		goto err_up;
+
+	return 0;
+
+err_up:
+	atl1_reset(adapter);
+	return err;
+}
+
+/*
+ * atl1_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the drivers control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ */
+static int atl1_close(struct net_device *netdev)
+{
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	atl1_down(adapter);
+	atl1_free_ring_resources(adapter);
+	return 0;
+}
+
+/*
+ * If TPD Buffer size equal to 0, PCIE DMAR_TO_INT
+ * will assert. We do soft reset <0x1400=1> according
+ * with the SPEC. BUT, it seemes that PCIE or DMA
+ * state-machine will not be reset. DMAR_TO_INT will
+ * assert again and again.
+ */
+static void atl1_tx_timeout_task(struct work_struct *work)
+{
+	struct atl1_adapter *adapter =
+		container_of(work, struct atl1_adapter, tx_timeout_task);
+	struct net_device *netdev = adapter->netdev;
+
+	netif_device_detach(netdev);
+	atl1_down(adapter);
+	atl1_up(adapter);
+	netif_device_attach(netdev);
+}
+
+/*
+ * atl1_link_chg_task - deal with link change event Out of interrupt context
+ */
+static void atl1_link_chg_task(struct work_struct *work)
+{
+	struct atl1_adapter *adapter =
+               container_of(work, struct atl1_adapter, link_chg_task);
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->lock, flags);
+	atl1_check_link(adapter);
+	spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+/*
+ * atl1_pcie_patch - Patch for PCIE module
+ */
+static void atl1_pcie_patch(struct atl1_adapter *adapter)
+{
+	u32 value;
+	value = 0x6500;
+	iowrite32(value, adapter->hw.hw_addr + 0x12FC);
+	/* pcie flow control mode change */
+	value = ioread32(adapter->hw.hw_addr + 0x1008);
+	value |= 0x8000;
+	iowrite32(value, adapter->hw.hw_addr + 0x1008);
+}
+
+/*
+ * When ACPI resume on some VIA MotherBoard, the Interrupt Disable bit/0x400
+ * on PCI Command register is disable.
+ * The function enable this bit.
+ * Brackett, 2006/03/15
+ */
+static void atl1_via_workaround(struct atl1_adapter *adapter)
+{
+	unsigned long value;
+
+	value = ioread16(adapter->hw.hw_addr + PCI_COMMAND);
+	if (value & PCI_COMMAND_INTX_DISABLE)
+		value &= ~PCI_COMMAND_INTX_DISABLE;
+	iowrite32(value, adapter->hw.hw_addr + PCI_COMMAND);
+}
+
+/*
+ * atl1_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in atl1_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * atl1_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ */
+static int __devinit atl1_probe(struct pci_dev *pdev,
+			      const struct pci_device_id *ent)
+{
+	struct net_device *netdev;
+	struct atl1_adapter *adapter;
+	static int cards_found = 0;
+	bool pci_using_64 = true;
+	int err;
+
+	err = pci_enable_device(pdev);
+	if (err)
+		return err;
+
+	err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+	if (err) {
+		err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+		if (err) {
+			printk(KERN_DEBUG
+				"%s: no usable DMA configuration, aborting\n",
+				atl1_driver_name);
+			goto err_dma;
+		}
+		pci_using_64 = false;
+	}
+	/* Mark all PCI regions associated with PCI device
+	 * pdev as being reserved by owner atl1_driver_name
+	 */
+	err = pci_request_regions(pdev, atl1_driver_name);
+	if (err)
+		goto err_request_regions;
+
+	/* Enables bus-mastering on the device and calls
+	 * pcibios_set_master to do the needed arch specific settings
+	 */
+	pci_set_master(pdev);
+
+	netdev = alloc_etherdev(sizeof(struct atl1_adapter));
+	if (!netdev) {
+		err = -ENOMEM;
+		goto err_alloc_etherdev;
+	}
+	SET_MODULE_OWNER(netdev);
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+
+	pci_set_drvdata(pdev, netdev);
+	adapter = netdev_priv(netdev);
+	adapter->netdev = netdev;
+	adapter->pdev = pdev;
+	adapter->hw.back = adapter;
+
+	adapter->hw.hw_addr = pci_iomap(pdev, 0, 0);
+	if (!adapter->hw.hw_addr) {
+		err = -EIO;
+		goto err_pci_iomap;
+	}
+	/* get device revision number */
+	adapter->hw.dev_rev = ioread16(adapter->hw.hw_addr + (REG_MASTER_CTRL + 2));
+
+	/* set default ring resource counts */
+	adapter->rfd_ring.count = adapter->rrd_ring.count = ATL1_DEFAULT_RFD;
+	adapter->tpd_ring.count = ATL1_DEFAULT_TPD;
+
+	adapter->mii.dev = netdev;
+	adapter->mii.mdio_read = mdio_read;
+	adapter->mii.mdio_write = mdio_write;
+	adapter->mii.phy_id_mask = 0x1f;
+	adapter->mii.reg_num_mask = 0x1f;
+
+	netdev->open = &atl1_open;
+	netdev->stop = &atl1_close;
+	netdev->hard_start_xmit = &atl1_xmit_frame;
+	netdev->get_stats = &atl1_get_stats;
+	netdev->set_multicast_list = &atl1_set_multi;
+	netdev->set_mac_address = &atl1_set_mac;
+	netdev->change_mtu = &atl1_change_mtu;
+	netdev->do_ioctl = &atl1_ioctl;
+	netdev->tx_timeout = &atl1_tx_timeout;
+	netdev->watchdog_timeo = 5 * HZ;
+	netdev->vlan_rx_register = atl1_vlan_rx_register;
+	netdev->vlan_rx_add_vid = atl1_vlan_rx_add_vid;
+	netdev->vlan_rx_kill_vid = atl1_vlan_rx_kill_vid;
+	netdev->ethtool_ops = &atl1_ethtool_ops;
+	adapter->bd_number = cards_found;
+	adapter->pci_using_64 = pci_using_64;
+
+	/* setup the private structure */
+	err = atl1_sw_init(adapter);
+	if (err)
+		goto err_common;
+
+	netdev->features = NETIF_F_HW_CSUM;
+	netdev->features |= NETIF_F_SG;
+	netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
+
+	/*
+	 * FIXME - Until tso performance gets fixed, disable the feature.
+	 * Enable it with ethtool -K if desired.
+	 */
+	/* netdev->features |= NETIF_F_TSO; */
+
+	if (pci_using_64)
+		netdev->features |= NETIF_F_HIGHDMA;
+
+	netdev->features |= NETIF_F_LLTX;
+
+	/*
+	 * patch for some L1 of old version,
+	 * the final version of L1 may not need these
+	 * patches
+	 */
+	/* atl1_pcie_patch(adapter); */
+
+	/* really reset GPHY core */
+	iowrite16(0, adapter->hw.hw_addr + REG_GPHY_ENABLE);
+
+	/*
+	 * reset the controller to
+	 * put the device in a known good starting state
+	 */
+	if (atl1_reset_hw(&adapter->hw)) {
+		err = -EIO;
+		goto err_common;
+	}
+
+	/* copy the MAC address out of the EEPROM */
+	atl1_read_mac_addr(&adapter->hw);
+	memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
+
+	if (!is_valid_ether_addr(netdev->dev_addr)) {
+		err = -EIO;
+		goto err_common;
+	}
+
+	atl1_check_options(adapter);
+
+	/* pre-init the MAC, and setup link */
+	err = atl1_init_hw(&adapter->hw);
+	if (err) {
+		err = -EIO;
+		goto err_common;
+	}
+
+	atl1_pcie_patch(adapter);
+	/* assume we have no link for now */
+	netif_carrier_off(netdev);
+	netif_stop_queue(netdev);
+
+	init_timer(&adapter->watchdog_timer);
+	adapter->watchdog_timer.function = &atl1_watchdog;
+	adapter->watchdog_timer.data = (unsigned long)adapter;
+
+	init_timer(&adapter->phy_config_timer);
+	adapter->phy_config_timer.function = &atl1_phy_config;
+	adapter->phy_config_timer.data = (unsigned long)adapter;
+	adapter->phy_timer_pending = false;
+
+	INIT_WORK(&adapter->tx_timeout_task, atl1_tx_timeout_task);
+
+	INIT_WORK(&adapter->link_chg_task, atl1_link_chg_task);
+
+	INIT_WORK(&adapter->pcie_dma_to_rst_task, atl1_tx_timeout_task);
+
+	err = register_netdev(netdev);
+	if (err)
+		goto err_common;
+
+	cards_found++;
+	atl1_via_workaround(adapter);
+	return 0;
+
+err_common:
+	pci_iounmap(pdev, adapter->hw.hw_addr);
+err_pci_iomap:
+	free_netdev(netdev);
+err_alloc_etherdev:
+	pci_release_regions(pdev);
+err_dma:
+err_request_regions:
+	pci_disable_device(pdev);
+	return err;
+}
+
+/*
+ * atl1_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * atl1_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.  The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ */
+static void __devexit atl1_remove(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct atl1_adapter *adapter;
+	/* Device not available. Return. */
+	if (!netdev)
+		return;
+
+	adapter = netdev_priv(netdev);
+	iowrite16(0, adapter->hw.hw_addr + REG_GPHY_ENABLE);
+	unregister_netdev(netdev);
+	pci_iounmap(pdev, adapter->hw.hw_addr);
+	pci_release_regions(pdev);
+	free_netdev(netdev);
+	pci_disable_device(pdev);
+}
+
+#ifdef CONFIG_PM
+static int atl1_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	struct atl1_hw *hw = &adapter->hw;
+	u32 ctrl = 0;
+	u32 wufc = adapter->wol;
+
+	netif_device_detach(netdev);
+	if (netif_running(netdev))
+		atl1_down(adapter);
+
+	atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl);
+	atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl);
+	if (ctrl & BMSR_LSTATUS)
+		wufc &= ~ATL1_WUFC_LNKC;
+
+	/* reduce speed to 10/100M */
+	if (wufc) {
+		atl1_phy_enter_power_saving(hw);
+		/* if resume, let driver to re- setup link */
+		hw->phy_configured = false;
+		atl1_set_mac_addr(hw);
+		atl1_set_multi(netdev);
+
+		ctrl = 0;
+		/* turn on magic packet wol */
+		if (wufc & ATL1_WUFC_MAG)
+			ctrl = WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
+
+		/* turn on Link change WOL */
+		if (wufc & ATL1_WUFC_LNKC)
+			ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN);
+		iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL);
+
+		/* turn on all-multi mode if wake on multicast is enabled */
+		ctrl = ioread32(hw->hw_addr + REG_MAC_CTRL);
+		ctrl &= ~MAC_CTRL_DBG;
+		ctrl &= ~MAC_CTRL_PROMIS_EN;
+		if (wufc & ATL1_WUFC_MC)
+			ctrl |= MAC_CTRL_MC_ALL_EN;
+		else
+			ctrl &= ~MAC_CTRL_MC_ALL_EN;
+
+		/* turn on broadcast mode if wake on-BC is enabled */
+		if (wufc & ATL1_WUFC_BC)
+			ctrl |= MAC_CTRL_BC_EN;
+		else
+			ctrl &= ~MAC_CTRL_BC_EN;
+
+		/* enable RX */
+		ctrl |= MAC_CTRL_RX_EN;
+		iowrite32(ctrl, hw->hw_addr + REG_MAC_CTRL);
+		pci_enable_wake(pdev, PCI_D3hot, 1);
+		pci_enable_wake(pdev, PCI_D3cold, 1);	/* 4 == D3 cold */
+	} else {
+		iowrite32(0, hw->hw_addr + REG_WOL_CTRL);
+		pci_enable_wake(pdev, PCI_D3hot, 0);
+		pci_enable_wake(pdev, PCI_D3cold, 0);	/* 4 == D3 cold */
+	}
+
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+
+	pci_set_power_state(pdev, PCI_D3hot);
+
+	return 0;
+}
+
+static int atl1_resume(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct atl1_adapter *adapter = netdev_priv(netdev);
+	u32 ret_val;
+
+	pci_set_power_state(pdev, 0);
+	pci_restore_state(pdev);
+
+	ret_val = pci_enable_device(pdev);
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+	pci_enable_wake(pdev, PCI_D3cold, 0);
+
+	iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL);
+	atl1_reset(adapter);
+
+	if (netif_running(netdev))
+		atl1_up(adapter);
+	netif_device_attach(netdev);
+
+	atl1_via_workaround(adapter);
+
+	return 0;
+}
+#else
+#define atl1_suspend NULL
+#define atl1_resume NULL
+#endif
+
+static struct pci_driver atl1_driver = {
+	.name = atl1_driver_name,
+	.id_table = atl1_pci_tbl,
+	.probe = atl1_probe,
+	.remove = __devexit_p(atl1_remove),
+	/* Power Managment Hooks */
+	/* probably broken right now -- CHS */
+	.suspend = atl1_suspend,
+	.resume = atl1_resume
+};
+
+/*
+ * atl1_exit_module - Driver Exit Cleanup Routine
+ *
+ * atl1_exit_module is called just before the driver is removed
+ * from memory.
+ */
+static void __exit atl1_exit_module(void)
+{
+	pci_unregister_driver(&atl1_driver);
+}
+
+/*
+ * atl1_init_module - Driver Registration Routine
+ *
+ * atl1_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ */
+static int __init atl1_init_module(void)
+{
+	printk(KERN_INFO "%s - version %s\n", atl1_driver_string, DRIVER_VERSION);
+	printk(KERN_INFO "%s\n", atl1_copyright);
+	return pci_register_driver(&atl1_driver);
+}
+
+module_init(atl1_init_module);
+module_exit(atl1_exit_module);
diff --git a/drivers/net/atl1/atl1_param.c b/drivers/net/atl1/atl1_param.c
new file mode 100644
index 0000000..c407214
--- /dev/null
+++ b/drivers/net/atl1/atl1_param.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/moduleparam.h>
+#include "atl1.h"
+
+/*
+ * This is the only thing that needs to be changed to adjust the
+ * maximum number of ports that the driver can manage.
+ */
+#define ATL1_MAX_NIC 4
+
+#define OPTION_UNSET    -1
+#define OPTION_DISABLED 0
+#define OPTION_ENABLED  1
+
+#define ATL1_PARAM_INIT { [0 ... ATL1_MAX_NIC] = OPTION_UNSET }
+
+/*
+ * Interrupt Moderate Timer in units of 2 us
+ *
+ * Valid Range: 10-65535
+ *
+ * Default Value: 100 (200us)
+ */
+static int __devinitdata int_mod_timer[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT;
+static int num_int_mod_timer = 0;
+module_param_array_named(int_mod_timer, int_mod_timer, int, &num_int_mod_timer, 0);
+MODULE_PARM_DESC(int_mod_timer, "Interrupt moderator timer");
+
+/*
+ * flash_vendor
+ *
+ * Valid Range: 0-2
+ *
+ * 0 - Atmel
+ * 1 - SST
+ * 2 - ST
+ *
+ * Default Value: 0
+ */
+static int __devinitdata flash_vendor[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT;
+static int num_flash_vendor = 0;
+module_param_array_named(flash_vendor, flash_vendor, int, &num_flash_vendor, 0);
+MODULE_PARM_DESC(flash_vendor, "SPI flash vendor");
+
+#define DEFAULT_INT_MOD_CNT	100	/* 200us */
+#define MAX_INT_MOD_CNT		65000
+#define MIN_INT_MOD_CNT		50
+
+#define FLASH_VENDOR_DEFAULT	0
+#define FLASH_VENDOR_MIN	0
+#define FLASH_VENDOR_MAX	2
+
+struct atl1_option {
+	enum { enable_option, range_option, list_option } type;
+	char *name;
+	char *err;
+	int def;
+	union {
+		struct {	/* range_option info */
+			int min;
+			int max;
+		} r;
+		struct {	/* list_option info */
+			int nr;
+			struct atl1_opt_list {
+				int i;
+				char *str;
+			} *p;
+		} l;
+	} arg;
+};
+
+static int __devinit atl1_validate_option(int *value, struct atl1_option *opt)
+{
+	if (*value == OPTION_UNSET) {
+		*value = opt->def;
+		return 0;
+	}
+
+	switch (opt->type) {
+	case enable_option:
+		switch (*value) {
+		case OPTION_ENABLED:
+			printk(KERN_INFO "%s: %s Enabled\n", atl1_driver_name,
+				opt->name);
+			return 0;
+		case OPTION_DISABLED:
+			printk(KERN_INFO "%s: %s Disabled\n", atl1_driver_name,
+				opt->name);
+			return 0;
+		}
+		break;
+	case range_option:
+		if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
+			printk(KERN_INFO "%s: %s set to %i\n",
+				atl1_driver_name, opt->name, *value);
+			return 0;
+		}
+		break;
+	case list_option:{
+			int i;
+			struct atl1_opt_list *ent;
+
+			for (i = 0; i < opt->arg.l.nr; i++) {
+				ent = &opt->arg.l.p[i];
+				if (*value == ent->i) {
+					if (ent->str[0] != '\0')
+						printk(KERN_INFO "%s: %s\n",
+						       atl1_driver_name, ent->str);
+					return 0;
+				}
+			}
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	printk(KERN_INFO "%s: invalid %s specified (%i) %s\n",
+	       atl1_driver_name, opt->name, *value, opt->err);
+	*value = opt->def;
+	return -1;
+}
+
+/*
+ * atl1_check_options - Range Checking for Command Line Parameters
+ * @adapter: board private structure
+ *
+ * This routine checks all command line parameters for valid user
+ * input.  If an invalid value is given, or if no user specified
+ * value exists, a default value is used.  The final value is stored
+ * in a variable in the adapter structure.
+ */
+void __devinit atl1_check_options(struct atl1_adapter *adapter)
+{
+	int bd = adapter->bd_number;
+	if (bd >= ATL1_MAX_NIC) {
+		printk(KERN_NOTICE "%s: warning: no configuration for board #%i\n",
+			atl1_driver_name, bd);
+		printk(KERN_NOTICE "%s: using defaults for all values\n",
+			atl1_driver_name);
+	}
+	{			/* Interrupt Moderate Timer */
+		struct atl1_option opt = {
+			.type = range_option,
+			.name = "Interrupt Moderator Timer",
+			.err = "using default of "
+				__MODULE_STRING(DEFAULT_INT_MOD_CNT),
+			.def = DEFAULT_INT_MOD_CNT,
+			.arg = {.r =
+				{.min = MIN_INT_MOD_CNT,.max = MAX_INT_MOD_CNT}}
+		};
+		int val;
+		if (num_int_mod_timer > bd) {
+			val = int_mod_timer[bd];
+			atl1_validate_option(&val, &opt);
+			adapter->imt = (u16) val;
+		} else
+			adapter->imt = (u16) (opt.def);
+	}
+
+	{			/* Flash Vendor */
+		struct atl1_option opt = {
+			.type = range_option,
+			.name = "SPI Flash Vendor",
+			.err = "using default of "
+				__MODULE_STRING(FLASH_VENDOR_DEFAULT),
+			.def = DEFAULT_INT_MOD_CNT,
+			.arg = {.r =
+				{.min = FLASH_VENDOR_MIN,.max =
+				 FLASH_VENDOR_MAX}}
+		};
+		int val;
+		if (num_flash_vendor > bd) {
+			val = flash_vendor[bd];
+			atl1_validate_option(&val, &opt);
+			adapter->hw.flash_vendor = (u8) val;
+		} else
+			adapter->hw.flash_vendor = (u8) (opt.def);
+	}
+}
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 303a8d9..5ff7882 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -721,7 +721,7 @@
 	struct ring_info *src_map, *dest_map;
 	struct rx_header *rh;
 	int dest_idx;
-	u32 ctrl;
+	__le32 ctrl;
 
 	dest_idx = dest_idx_unmasked & (B44_RX_RING_SIZE - 1);
 	dest_desc = &bp->rx_ring[dest_idx];
@@ -783,7 +783,7 @@
 					    RX_PKT_BUF_SZ,
 					    PCI_DMA_FROMDEVICE);
 		rh = (struct rx_header *) skb->data;
-		len = cpu_to_le16(rh->len);
+		len = le16_to_cpu(rh->len);
 		if ((len > (RX_PKT_BUF_SZ - bp->rx_offset)) ||
 		    (rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) {
 		drop_it:
@@ -799,7 +799,7 @@
 			do {
 				udelay(2);
 				barrier();
-				len = cpu_to_le16(rh->len);
+				len = le16_to_cpu(rh->len);
 			} while (len == 0 && i++ < 5);
 			if (len == 0)
 				goto drop_it;
@@ -2061,7 +2061,7 @@
 static int b44_read_eeprom(struct b44 *bp, u8 *data)
 {
 	long i;
-	u16 *ptr = (u16 *) data;
+	__le16 *ptr = (__le16 *) data;
 
 	for (i = 0; i < 128; i += 2)
 		ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i));
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
index 4944507..18fc133 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -308,8 +308,8 @@
 #define  MII_TLEDCTRL_ENABLE	0x0040
 
 struct dma_desc {
-	u32	ctrl;
-	u32	addr;
+	__le32	ctrl;
+	__le32	addr;
 };
 
 /* There are only 12 bits in the DMA engine for descriptor offsetting
@@ -327,9 +327,9 @@
 #define RX_COPY_THRESHOLD  	256
 
 struct rx_header {
-	u16	len;
-	u16	flags;
-	u16	pad[12];
+	__le16	len;
+	__le16	flags;
+	__le16	pad[12];
 };
 #define RX_HEADER_LEN	28
 
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 4528ce9..c143304d 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/crc32.h>
+#include <linux/bitrev.h>
 #include <asm/prom.h>
 #include <asm/dbdma.h>
 #include <asm/io.h>
@@ -140,7 +141,6 @@
 	+ (N_RX_RING + N_TX_RING + 4) * sizeof(struct dbdma_cmd) \
 	+ sizeof(struct sk_buff_head))
 
-static unsigned char bitrev(unsigned char b);
 static int bmac_open(struct net_device *dev);
 static int bmac_close(struct net_device *dev);
 static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev);
@@ -586,18 +586,6 @@
 		     virt_to_bus(addr), 0);
 }
 
-/* Bit-reverse one byte of an ethernet hardware address. */
-static unsigned char
-bitrev(unsigned char b)
-{
-	int d = 0, i;
-
-	for (i = 0; i < 8; ++i, b >>= 1)
-		d = (d << 1) | (b & 1);
-	return d;
-}
-
-
 static void
 bmac_init_tx_ring(struct bmac_data *bp)
 {
@@ -1224,8 +1212,8 @@
 		{
 			reset_and_select_srom(dev);
 			data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits);
-			ea[2*i]   = bitrev(data & 0x0ff);
-			ea[2*i+1] = bitrev((data >> 8) & 0x0ff);
+			ea[2*i]   = bitrev8(data & 0x0ff);
+			ea[2*i+1] = bitrev8((data >> 8) & 0x0ff);
 		}
 }
 
@@ -1315,7 +1303,7 @@
 
 	rev = addr[0] == 0 && addr[1] == 0xA0;
 	for (j = 0; j < 6; ++j)
-		dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
+		dev->dev_addr[j] = rev ? bitrev8(addr[j]): addr[j];
 
 	/* Enable chip without interrupts for now */
 	bmac_enable_and_reset_chip(dev);
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index ee7b75b..5a96d76 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -39,12 +39,9 @@
 #include <linux/if_vlan.h>
 #define BCM_VLAN 1
 #endif
-#ifdef NETIF_F_TSO
 #include <net/ip.h>
 #include <net/tcp.h>
 #include <net/checksum.h>
-#define BCM_TSO 1
-#endif
 #include <linux/workqueue.h>
 #include <linux/crc32.h>
 #include <linux/prefetch.h>
@@ -1728,7 +1725,7 @@
 
 		tx_buf = &bp->tx_buf_ring[sw_ring_cons];
 		skb = tx_buf->skb;
-#ifdef BCM_TSO
+
 		/* partial BD completions possible with TSO packets */
 		if (skb_is_gso(skb)) {
 			u16 last_idx, last_ring_idx;
@@ -1744,7 +1741,7 @@
 				break;
 			}
 		}
-#endif
+
 		pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
 			skb_headlen(skb), PCI_DMA_TODEVICE);
 
@@ -4514,7 +4511,6 @@
 		vlan_tag_flags |=
 			(TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
 	}
-#ifdef BCM_TSO
 	if ((mss = skb_shinfo(skb)->gso_size) &&
 		(skb->len > (bp->dev->mtu + ETH_HLEN))) {
 		u32 tcp_opt_len, ip_tcp_len;
@@ -4547,7 +4543,6 @@
 		}
 	}
 	else
-#endif
 	{
 		mss = 0;
 	}
@@ -5544,10 +5539,8 @@
 	.set_tx_csum		= ethtool_op_set_tx_csum,
 	.get_sg			= ethtool_op_get_sg,
 	.set_sg			= ethtool_op_set_sg,
-#ifdef BCM_TSO
 	.get_tso		= ethtool_op_get_tso,
 	.set_tso		= bnx2_set_tso,
-#endif
 	.self_test_count	= bnx2_self_test_count,
 	.self_test		= bnx2_self_test,
 	.get_strings		= bnx2_get_strings,
@@ -5954,8 +5947,7 @@
 	 * responding after a while.
 	 *
 	 * AMD believes this incompatibility is unique to the 5706, and
-	 * prefers to locally disable MSI rather than globally disabling it
-	 * using pci_msi_quirk.
+	 * prefers to locally disable MSI rather than globally disabling it.
 	 */
 	if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
 		struct pci_dev *amd_8132 = NULL;
@@ -6104,9 +6096,7 @@
 #ifdef BCM_VLAN
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
 #endif
-#ifdef BCM_TSO
 	dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
-#endif
 
 	netif_carrier_off(bp->dev);
 
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 3292316..217a2ee 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -184,7 +184,7 @@
 
 	spin_lock_init(&(bond_info->tx_hashtbl_lock));
 
-	new_hashtbl = kmalloc(size, GFP_KERNEL);
+	new_hashtbl = kzalloc(size, GFP_KERNEL);
 	if (!new_hashtbl) {
 		printk(KERN_ERR DRV_NAME
 		       ": %s: Error: Failed to allocate TLB hash table\n",
@@ -195,8 +195,6 @@
 
 	bond_info->tx_hashtbl = new_hashtbl;
 
-	memset(bond_info->tx_hashtbl, 0, size);
-
 	for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) {
 		tlb_init_table_entry(&bond_info->tx_hashtbl[i], 1);
 	}
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 6482aed..8ce8fec 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1343,14 +1343,12 @@
 			"inaccurate.\n", bond_dev->name, slave_dev->name);
 	}
 
-	new_slave = kmalloc(sizeof(struct slave), GFP_KERNEL);
+	new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
 	if (!new_slave) {
 		res = -ENOMEM;
 		goto err_undo_flags;
 	}
 
-	memset(new_slave, 0, sizeof(struct slave));
-
 	/* save slave's original flags before calling
 	 * netdev_set_master and dev_open
 	 */
@@ -4704,6 +4702,7 @@
 static struct lock_class_key bonding_netdev_xmit_lock_key;
 
 /* Create a new bond based on the specified name and bonding parameters.
+ * If name is NULL, obtain a suitable "bond%d" name for us.
  * Caller must NOT hold rtnl_lock; we need to release it here before we
  * set up our sysfs entries.
  */
@@ -4713,7 +4712,8 @@
 	int res;
 
 	rtnl_lock();
-	bond_dev = alloc_netdev(sizeof(struct bonding), name, ether_setup);
+	bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "",
+				ether_setup);
 	if (!bond_dev) {
 		printk(KERN_ERR DRV_NAME
 		       ": %s: eek! can't alloc netdev!\n",
@@ -4722,6 +4722,12 @@
 		goto out_rtnl;
 	}
 
+	if (!name) {
+		res = dev_alloc_name(bond_dev, "bond%d");
+		if (res < 0)
+			goto out_netdev;
+	}
+
 	/* bond_init() must be called after dev_alloc_name() (for the
 	 * /proc files), but before register_netdevice(), because we
 	 * need to set function pointers.
@@ -4748,14 +4754,19 @@
 
 	rtnl_unlock(); /* allows sysfs registration of net device */
 	res = bond_create_sysfs_entry(bond_dev->priv);
-	goto done;
+	if (res < 0) {
+		rtnl_lock();
+		goto out_bond;
+	}
+
+	return 0;
+
 out_bond:
 	bond_deinit(bond_dev);
 out_netdev:
 	free_netdev(bond_dev);
 out_rtnl:
 	rtnl_unlock();
-done:
 	return res;
 }
 
@@ -4763,7 +4774,6 @@
 {
 	int i;
 	int res;
-	char new_bond_name[8];  /* Enough room for 999 bonds at init. */
 
 	printk(KERN_INFO "%s", version);
 
@@ -4776,8 +4786,7 @@
 	bond_create_proc_dir();
 #endif
 	for (i = 0; i < max_bonds; i++) {
-		sprintf(new_bond_name, "bond%d",i);
-		res = bond_create(new_bond_name,&bonding_defaults, NULL);
+		res = bond_create(NULL, &bonding_defaults, NULL);
 		if (res)
 			goto err;
 	}
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index ced9ed8..878f7aa 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -39,8 +39,7 @@
 
 /* #define BONDING_DEBUG 1 */
 #include "bonding.h"
-#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)
+#define to_dev(obj)	container_of(obj,struct device,kobj)
 #define to_bond(cd)	((struct bonding *)(to_net_dev(cd)->priv))
 
 /*---------------------------- Declarations -------------------------------*/
@@ -154,7 +153,7 @@
 				 * If it's > expected, then there's a file open,
 				 * and we have to fail.
 				 */
-				if (atomic_read(&bond->dev->class_dev.kobj.kref.refcount)
+				if (atomic_read(&bond->dev->dev.kobj.kref.refcount)
 							> expected_refcount){
 					rtnl_unlock();
 					printk(KERN_INFO DRV_NAME
@@ -201,13 +200,13 @@
 	int ret = 0;
 
 	/* first, create a link from the slave back to the master */
-	ret = sysfs_create_link(&(slave->class_dev.kobj), &(master->class_dev.kobj),
+	ret = sysfs_create_link(&(slave->dev.kobj), &(master->dev.kobj),
 				"master");
 	if (ret)
 		return ret;
 	/* next, create a link from the master to the slave */
 	sprintf(linkname,"slave_%s",slave->name);
-	ret = sysfs_create_link(&(master->class_dev.kobj), &(slave->class_dev.kobj),
+	ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj),
 				linkname);
 	return ret;
 
@@ -217,20 +216,21 @@
 {
 	char linkname[IFNAMSIZ+7];
 
-	sysfs_remove_link(&(slave->class_dev.kobj), "master");
+	sysfs_remove_link(&(slave->dev.kobj), "master");
 	sprintf(linkname,"slave_%s",slave->name);
-	sysfs_remove_link(&(master->class_dev.kobj), linkname);
+	sysfs_remove_link(&(master->dev.kobj), linkname);
 }
 
 
 /*
  * Show the slaves in the current bond.
  */
-static ssize_t bonding_show_slaves(struct class_device *cd, char *buf)
+static ssize_t bonding_show_slaves(struct device *d,
+				   struct device_attribute *attr, char *buf)
 {
 	struct slave *slave;
 	int i, res = 0;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	read_lock_bh(&bond->lock);
 	bond_for_each_slave(bond, slave, i) {
@@ -254,14 +254,16 @@
  * up for this to succeed.
  * This function is largely the same flow as bonding_update_bonds().
  */
-static ssize_t bonding_store_slaves(struct class_device *cd, const char *buffer, size_t count)
+static ssize_t bonding_store_slaves(struct device *d,
+				    struct device_attribute *attr,
+				    const char *buffer, size_t count)
 {
 	char command[IFNAMSIZ + 1] = { 0, };
 	char *ifname;
 	int i, res, found, ret = count;
 	struct slave *slave;
 	struct net_device *dev = NULL;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	/* Quick sanity check -- is the bond interface up? */
 	if (!(bond->dev->flags & IFF_UP)) {
@@ -387,25 +389,28 @@
 	return ret;
 }
 
-static CLASS_DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves);
+static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves);
 
 /*
  * Show and set the bonding mode.  The bond interface must be down to
  * change the mode.
  */
-static ssize_t bonding_show_mode(struct class_device *cd, char *buf)
+static ssize_t bonding_show_mode(struct device *d,
+				 struct device_attribute *attr, char *buf)
 {
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	return sprintf(buf, "%s %d\n",
 			bond_mode_tbl[bond->params.mode].modename,
 			bond->params.mode) + 1;
 }
 
-static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_mode(struct device *d,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
 {
 	int new_value, ret = count;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	if (bond->dev->flags & IFF_UP) {
 		printk(KERN_ERR DRV_NAME
@@ -438,16 +443,18 @@
 out:
 	return ret;
 }
-static CLASS_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode);
+static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode);
 
 /*
  * Show and set the bonding transmit hash method.  The bond interface must be down to
  * change the xmit hash policy.
  */
-static ssize_t bonding_show_xmit_hash(struct class_device *cd, char *buf)
+static ssize_t bonding_show_xmit_hash(struct device *d,
+				      struct device_attribute *attr,
+				      char *buf)
 {
 	int count;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	if ((bond->params.mode != BOND_MODE_XOR) &&
 	    (bond->params.mode != BOND_MODE_8023AD)) {
@@ -462,10 +469,12 @@
 	return count;
 }
 
-static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_xmit_hash(struct device *d,
+				       struct device_attribute *attr,
+				       const char *buf, size_t count)
 {
 	int new_value, ret = count;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	if (bond->dev->flags & IFF_UP) {
 		printk(KERN_ERR DRV_NAME
@@ -501,24 +510,28 @@
 out:
 	return ret;
 }
-static CLASS_DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash);
+static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash);
 
 /*
  * Show and set arp_validate.
  */
-static ssize_t bonding_show_arp_validate(struct class_device *cd, char *buf)
+static ssize_t bonding_show_arp_validate(struct device *d,
+					 struct device_attribute *attr,
+					 char *buf)
 {
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	return sprintf(buf, "%s %d\n",
 		       arp_validate_tbl[bond->params.arp_validate].modename,
 		       bond->params.arp_validate) + 1;
 }
 
-static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_arp_validate(struct device *d,
+					  struct device_attribute *attr,
+					  const char *buf, size_t count)
 {
 	int new_value;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	new_value = bond_parse_parm((char *)buf, arp_validate_tbl);
 	if (new_value < 0) {
@@ -548,7 +561,7 @@
 	return count;
 }
 
-static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate);
+static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate);
 
 /*
  * Show and set the arp timer interval.  There are two tricky bits
@@ -556,17 +569,21 @@
  * MII monitoring.  Second, if the ARP timer isn't running, we must
  * start it.
  */
-static ssize_t bonding_show_arp_interval(struct class_device *cd, char *buf)
+static ssize_t bonding_show_arp_interval(struct device *d,
+					 struct device_attribute *attr,
+					 char *buf)
 {
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	return sprintf(buf, "%d\n", bond->params.arp_interval) + 1;
 }
 
-static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_arp_interval(struct device *d,
+					  struct device_attribute *attr,
+					  const char *buf, size_t count)
 {
 	int new_value, ret = count;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	if (sscanf(buf, "%d", &new_value) != 1) {
 		printk(KERN_ERR DRV_NAME
@@ -638,15 +655,17 @@
 out:
 	return ret;
 }
-static CLASS_DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval);
+static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval);
 
 /*
  * Show and set the arp targets.
  */
-static ssize_t bonding_show_arp_targets(struct class_device *cd, char *buf)
+static ssize_t bonding_show_arp_targets(struct device *d,
+					struct device_attribute *attr,
+					char *buf)
 {
 	int i, res = 0;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
 		if (bond->params.arp_targets[i])
@@ -660,11 +679,13 @@
 	return res;
 }
 
-static ssize_t bonding_store_arp_targets(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_arp_targets(struct device *d,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count)
 {
 	u32 newtarget;
 	int i = 0, done = 0, ret = count;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 	u32 *targets;
 
 	targets = bond->params.arp_targets;
@@ -742,24 +763,28 @@
 out:
 	return ret;
 }
-static CLASS_DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets);
+static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets);
 
 /*
  * Show and set the up and down delays.  These must be multiples of the
  * MII monitoring value, and are stored internally as the multiplier.
  * Thus, we must translate to MS for the real world.
  */
-static ssize_t bonding_show_downdelay(struct class_device *cd, char *buf)
+static ssize_t bonding_show_downdelay(struct device *d,
+				      struct device_attribute *attr,
+				      char *buf)
 {
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	return sprintf(buf, "%d\n", bond->params.downdelay * bond->params.miimon) + 1;
 }
 
-static ssize_t bonding_store_downdelay(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_downdelay(struct device *d,
+				       struct device_attribute *attr,
+				       const char *buf, size_t count)
 {
 	int new_value, ret = count;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	if (!(bond->params.miimon)) {
 		printk(KERN_ERR DRV_NAME
@@ -800,20 +825,24 @@
 out:
 	return ret;
 }
-static CLASS_DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay);
+static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay);
 
-static ssize_t bonding_show_updelay(struct class_device *cd, char *buf)
+static ssize_t bonding_show_updelay(struct device *d,
+				    struct device_attribute *attr,
+				    char *buf)
 {
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	return sprintf(buf, "%d\n", bond->params.updelay * bond->params.miimon) + 1;
 
 }
 
-static ssize_t bonding_store_updelay(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_updelay(struct device *d,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
 {
 	int new_value, ret = count;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	if (!(bond->params.miimon)) {
 		printk(KERN_ERR DRV_NAME
@@ -854,25 +883,29 @@
 out:
 	return ret;
 }
-static CLASS_DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay);
+static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay);
 
 /*
  * Show and set the LACP interval.  Interface must be down, and the mode
  * must be set to 802.3ad mode.
  */
-static ssize_t bonding_show_lacp(struct class_device *cd, char *buf)
+static ssize_t bonding_show_lacp(struct device *d,
+				 struct device_attribute *attr,
+				 char *buf)
 {
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	return sprintf(buf, "%s %d\n",
 		bond_lacp_tbl[bond->params.lacp_fast].modename,
 		bond->params.lacp_fast) + 1;
 }
 
-static ssize_t bonding_store_lacp(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_lacp(struct device *d,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
 {
 	int new_value, ret = count;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	if (bond->dev->flags & IFF_UP) {
 		printk(KERN_ERR DRV_NAME
@@ -906,7 +939,7 @@
 out:
 	return ret;
 }
-static CLASS_DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp);
+static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp);
 
 /*
  * Show and set the MII monitor interval.  There are two tricky bits
@@ -914,17 +947,21 @@
  * ARP monitoring.  Second, if the timer isn't running, we must
  * start it.
  */
-static ssize_t bonding_show_miimon(struct class_device *cd, char *buf)
+static ssize_t bonding_show_miimon(struct device *d,
+				   struct device_attribute *attr,
+				   char *buf)
 {
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	return sprintf(buf, "%d\n", bond->params.miimon) + 1;
 }
 
-static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_miimon(struct device *d,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
 {
 	int new_value, ret = count;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	if (sscanf(buf, "%d", &new_value) != 1) {
 		printk(KERN_ERR DRV_NAME
@@ -1000,7 +1037,7 @@
 out:
 	return ret;
 }
-static CLASS_DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon);
+static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon);
 
 /*
  * Show and set the primary slave.  The store function is much
@@ -1009,10 +1046,12 @@
  * The bond must be a mode that supports a primary for this be
  * set.
  */
-static ssize_t bonding_show_primary(struct class_device *cd, char *buf)
+static ssize_t bonding_show_primary(struct device *d,
+				    struct device_attribute *attr,
+				    char *buf)
 {
 	int count = 0;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	if (bond->primary_slave)
 		count = sprintf(buf, "%s\n", bond->primary_slave->dev->name) + 1;
@@ -1022,11 +1061,13 @@
 	return count;
 }
 
-static ssize_t bonding_store_primary(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_primary(struct device *d,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
 {
 	int i;
 	struct slave *slave;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	write_lock_bh(&bond->lock);
 	if (!USES_PRIMARY(bond->params.mode)) {
@@ -1065,22 +1106,26 @@
 	write_unlock_bh(&bond->lock);
 	return count;
 }
-static CLASS_DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary);
+static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary);
 
 /*
  * Show and set the use_carrier flag.
  */
-static ssize_t bonding_show_carrier(struct class_device *cd, char *buf)
+static ssize_t bonding_show_carrier(struct device *d,
+				    struct device_attribute *attr,
+				    char *buf)
 {
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	return sprintf(buf, "%d\n", bond->params.use_carrier) + 1;
 }
 
-static ssize_t bonding_store_carrier(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_carrier(struct device *d,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
 {
 	int new_value, ret = count;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 
 	if (sscanf(buf, "%d", &new_value) != 1) {
@@ -1102,16 +1147,18 @@
 out:
 	return count;
 }
-static CLASS_DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier);
+static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier);
 
 
 /*
  * Show and set currently active_slave.
  */
-static ssize_t bonding_show_active_slave(struct class_device *cd, char *buf)
+static ssize_t bonding_show_active_slave(struct device *d,
+					 struct device_attribute *attr,
+					 char *buf)
 {
 	struct slave *curr;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 	int count;
 
 
@@ -1126,13 +1173,15 @@
 	return count;
 }
 
-static ssize_t bonding_store_active_slave(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_active_slave(struct device *d,
+					  struct device_attribute *attr,
+					  const char *buf, size_t count)
 {
 	int i;
 	struct slave *slave;
         struct slave *old_active = NULL;
         struct slave *new_active = NULL;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	write_lock_bh(&bond->lock);
 	if (!USES_PRIMARY(bond->params.mode)) {
@@ -1194,16 +1243,18 @@
 	return count;
 
 }
-static CLASS_DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave);
+static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave);
 
 
 /*
  * Show link status of the bond interface.
  */
-static ssize_t bonding_show_mii_status(struct class_device *cd, char *buf)
+static ssize_t bonding_show_mii_status(struct device *d,
+				       struct device_attribute *attr,
+				       char *buf)
 {
 	struct slave *curr;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	read_lock(&bond->curr_slave_lock);
 	curr = bond->curr_active_slave;
@@ -1211,16 +1262,18 @@
 
 	return sprintf(buf, "%s\n", (curr) ? "up" : "down") + 1;
 }
-static CLASS_DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL);
+static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL);
 
 
 /*
  * Show current 802.3ad aggregator ID.
  */
-static ssize_t bonding_show_ad_aggregator(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_aggregator(struct device *d,
+					  struct device_attribute *attr,
+					  char *buf)
 {
 	int count = 0;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	if (bond->params.mode == BOND_MODE_8023AD) {
 		struct ad_info ad_info;
@@ -1231,16 +1284,18 @@
 
 	return count;
 }
-static CLASS_DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL);
+static DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL);
 
 
 /*
  * Show number of active 802.3ad ports.
  */
-static ssize_t bonding_show_ad_num_ports(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_num_ports(struct device *d,
+					 struct device_attribute *attr,
+					 char *buf)
 {
 	int count = 0;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	if (bond->params.mode == BOND_MODE_8023AD) {
 		struct ad_info ad_info;
@@ -1251,16 +1306,18 @@
 
 	return count;
 }
-static CLASS_DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL);
+static DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL);
 
 
 /*
  * Show current 802.3ad actor key.
  */
-static ssize_t bonding_show_ad_actor_key(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_actor_key(struct device *d,
+					 struct device_attribute *attr,
+					 char *buf)
 {
 	int count = 0;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	if (bond->params.mode == BOND_MODE_8023AD) {
 		struct ad_info ad_info;
@@ -1271,16 +1328,18 @@
 
 	return count;
 }
-static CLASS_DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL);
+static DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL);
 
 
 /*
  * Show current 802.3ad partner key.
  */
-static ssize_t bonding_show_ad_partner_key(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_partner_key(struct device *d,
+					   struct device_attribute *attr,
+					   char *buf)
 {
 	int count = 0;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	if (bond->params.mode == BOND_MODE_8023AD) {
 		struct ad_info ad_info;
@@ -1291,16 +1350,18 @@
 
 	return count;
 }
-static CLASS_DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL);
+static DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL);
 
 
 /*
  * Show current 802.3ad partner mac.
  */
-static ssize_t bonding_show_ad_partner_mac(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_partner_mac(struct device *d,
+					   struct device_attribute *attr,
+					   char *buf)
 {
 	int count = 0;
-	struct bonding *bond = to_bond(cd);
+	struct bonding *bond = to_bond(d);
 
 	if (bond->params.mode == BOND_MODE_8023AD) {
 		struct ad_info ad_info;
@@ -1319,30 +1380,30 @@
 
 	return count;
 }
-static CLASS_DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL);
+static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL);
 
 
 
 static struct attribute *per_bond_attrs[] = {
-	&class_device_attr_slaves.attr,
-	&class_device_attr_mode.attr,
-	&class_device_attr_arp_validate.attr,
-	&class_device_attr_arp_interval.attr,
-	&class_device_attr_arp_ip_target.attr,
-	&class_device_attr_downdelay.attr,
-	&class_device_attr_updelay.attr,
-	&class_device_attr_lacp_rate.attr,
-	&class_device_attr_xmit_hash_policy.attr,
-	&class_device_attr_miimon.attr,
-	&class_device_attr_primary.attr,
-	&class_device_attr_use_carrier.attr,
-	&class_device_attr_active_slave.attr,
-	&class_device_attr_mii_status.attr,
-	&class_device_attr_ad_aggregator.attr,
-	&class_device_attr_ad_num_ports.attr,
-	&class_device_attr_ad_actor_key.attr,
-	&class_device_attr_ad_partner_key.attr,
-	&class_device_attr_ad_partner_mac.attr,
+	&dev_attr_slaves.attr,
+	&dev_attr_mode.attr,
+	&dev_attr_arp_validate.attr,
+	&dev_attr_arp_interval.attr,
+	&dev_attr_arp_ip_target.attr,
+	&dev_attr_downdelay.attr,
+	&dev_attr_updelay.attr,
+	&dev_attr_lacp_rate.attr,
+	&dev_attr_xmit_hash_policy.attr,
+	&dev_attr_miimon.attr,
+	&dev_attr_primary.attr,
+	&dev_attr_use_carrier.attr,
+	&dev_attr_active_slave.attr,
+	&dev_attr_mii_status.attr,
+	&dev_attr_ad_aggregator.attr,
+	&dev_attr_ad_num_ports.attr,
+	&dev_attr_ad_actor_key.attr,
+	&dev_attr_ad_partner_key.attr,
+	&dev_attr_ad_partner_mac.attr,
 	NULL,
 };
 
@@ -1367,11 +1428,26 @@
 	if (!firstbond)
 		return -ENODEV;
 
-	netdev_class = firstbond->dev->class_dev.class;
+	netdev_class = firstbond->dev->dev.class;
 	if (!netdev_class)
 		return -ENODEV;
 
 	ret = class_create_file(netdev_class, &class_attr_bonding_masters);
+	/*
+	 * Permit multiple loads of the module by ignoring failures to
+	 * create the bonding_masters sysfs file.  Bonding devices
+	 * created by second or subsequent loads of the module will
+	 * not be listed in, or controllable by, bonding_masters, but
+	 * will have the usual "bonding" sysfs directory.
+	 *
+	 * This is done to preserve backwards compatibility for
+	 * initscripts/sysconfig, which load bonding multiple times to
+	 * configure multiple bonding devices.
+	 */
+	if (ret == -EEXIST) {
+		netdev_class = NULL;
+		return 0;
+	}
 
 	return ret;
 
@@ -1395,13 +1471,13 @@
 	struct net_device *dev = bond->dev;
 	int err;
 
-	err = sysfs_create_group(&(dev->class_dev.kobj), &bonding_group);
+	err = sysfs_create_group(&(dev->dev.kobj), &bonding_group);
 	if (err) {
 		printk(KERN_EMERG "eek! didn't create group!\n");
 	}
 
 	if (expected_refcount < 1)
-		expected_refcount = atomic_read(&bond->dev->class_dev.kobj.kref.refcount);
+		expected_refcount = atomic_read(&bond->dev->dev.kobj.kref.refcount);
 
 	return err;
 }
@@ -1412,6 +1488,6 @@
 {
 	struct net_device *dev = bond->dev;
 
-	sysfs_remove_group(&(dev->class_dev.kobj), &bonding_group);
+	sysfs_remove_group(&(dev->dev.kobj), &bonding_group);
 }
 
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 0978c9a..41aa78b 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -22,8 +22,8 @@
 #include "bond_3ad.h"
 #include "bond_alb.h"
 
-#define DRV_VERSION	"3.1.1"
-#define DRV_RELDATE	"September 26, 2006"
+#define DRV_VERSION	"3.1.2"
+#define DRV_RELDATE	"January 20, 2007"
 #define DRV_NAME	"bonding"
 #define DRV_DESCRIPTION	"Ethernet Channel Bonding Driver"
 
@@ -237,12 +237,13 @@
 #define BOND_ARP_VALIDATE_ALL		(BOND_ARP_VALIDATE_ACTIVE | \
 					 BOND_ARP_VALIDATE_BACKUP)
 
-extern inline int slave_do_arp_validate(struct bonding *bond, struct slave *slave)
+static inline int slave_do_arp_validate(struct bonding *bond,
+					struct slave *slave)
 {
 	return bond->params.arp_validate & (1 << slave->state);
 }
 
-extern inline unsigned long slave_last_rx(struct bonding *bond,
+static inline unsigned long slave_last_rx(struct bonding *bond,
 					struct slave *slave)
 {
 	if (slave_do_arp_validate(bond, slave))
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index 74758d2..787f2f2 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -324,7 +324,7 @@
 	unsigned char           mdio_phybaseaddr;
 	struct gmac            *gmac;
 	struct gphy            *gphy;
-	struct mdio_ops	       *mdio_ops;
+	struct mdio_ops        *mdio_ops;
 	const char             *desc;
 };
 
diff --git a/drivers/net/chelsio/cpl5_cmd.h b/drivers/net/chelsio/cpl5_cmd.h
index 35f565b..e36d45b 100644
--- a/drivers/net/chelsio/cpl5_cmd.h
+++ b/drivers/net/chelsio/cpl5_cmd.h
@@ -103,7 +103,7 @@
 	CPL_MIGRATE_C2T_RPL   = 0xDD,
 	CPL_ERROR             = 0xD7,
 
-    /* internal: driver -> TOM */
+	/* internal: driver -> TOM */
 	CPL_MSS_CHANGE        = 0xE1
 };
 
@@ -159,8 +159,8 @@
 };
 
 union opcode_tid {
-    u32 opcode_tid;
-    u8 opcode;
+	u32 opcode_tid;
+	u8 opcode;
 };
 
 #define S_OPCODE 24
@@ -234,7 +234,7 @@
 	u32 local_ip;
 	u32 peer_ip;
 	u32 tos_tid;
-    struct tcp_options tcp_options;
+	struct tcp_options tcp_options;
 	u8  dst_mac[6];
 	u16 vlan_tag;
 	u8  src_mac[6];
@@ -250,12 +250,12 @@
 	u32 peer_ip;
 	u32 opt0h;
 	union {
-	u32 opt0l;
-	struct {
-	    u8 rsvd[3];
-	    u8 status;
+		u32 opt0l;
+		struct {
+		    u8 rsvd[3];
+		    u8 status;
+		};
 	};
-    };
 };
 
 struct cpl_act_open_req {
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index fd5d821..7d0f24f 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -69,14 +69,14 @@
 	cancel_delayed_work(&ap->stats_update_task);
 }
 
-#define MAX_CMDQ_ENTRIES 16384
-#define MAX_CMDQ1_ENTRIES 1024
-#define MAX_RX_BUFFERS 16384
-#define MAX_RX_JUMBO_BUFFERS 16384
+#define MAX_CMDQ_ENTRIES	16384
+#define MAX_CMDQ1_ENTRIES	1024
+#define MAX_RX_BUFFERS		16384
+#define MAX_RX_JUMBO_BUFFERS	16384
 #define MAX_TX_BUFFERS_HIGH	16384U
 #define MAX_TX_BUFFERS_LOW	1536U
 #define MAX_TX_BUFFERS		1460U
-#define MIN_FL_ENTRIES 32
+#define MIN_FL_ENTRIES		32
 
 #define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
 			 NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
@@ -143,7 +143,7 @@
 			case SPEED_100:   s = "100Mbps"; break;
 		}
 
-	printk(KERN_INFO "%s: link up, %s, %s-duplex\n",
+		printk(KERN_INFO "%s: link up, %s, %s-duplex\n",
 		       p->dev->name, s,
 		       p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
 	}
@@ -233,7 +233,7 @@
 
 	t1_sge_start(adapter->sge);
 	t1_interrupts_enable(adapter);
- out_err:
+out_err:
 	return err;
 }
 
@@ -454,51 +454,21 @@
 	const struct cmac_statistics *s;
 	const struct sge_intr_counts *t;
 	struct sge_port_stats ss;
+	unsigned int len;
 
 	s = mac->ops->statistics_update(mac, MAC_STATS_UPDATE_FULL);
 
-	*data++ = s->TxOctetsOK;
-	*data++ = s->TxOctetsBad;
-	*data++ = s->TxUnicastFramesOK;
-	*data++ = s->TxMulticastFramesOK;
-	*data++ = s->TxBroadcastFramesOK;
-	*data++ = s->TxPauseFrames;
-	*data++ = s->TxFramesWithDeferredXmissions;
-	*data++ = s->TxLateCollisions;
-	*data++ = s->TxTotalCollisions;
-	*data++ = s->TxFramesAbortedDueToXSCollisions;
-	*data++ = s->TxUnderrun;
-	*data++ = s->TxLengthErrors;
-	*data++ = s->TxInternalMACXmitError;
-	*data++ = s->TxFramesWithExcessiveDeferral;
-	*data++ = s->TxFCSErrors;
+	len = sizeof(u64)*(&s->TxFCSErrors + 1 - &s->TxOctetsOK);
+	memcpy(data, &s->TxOctetsOK, len);
+	data += len;
 
-	*data++ = s->RxOctetsOK;
-	*data++ = s->RxOctetsBad;
-	*data++ = s->RxUnicastFramesOK;
-	*data++ = s->RxMulticastFramesOK;
-	*data++ = s->RxBroadcastFramesOK;
-	*data++ = s->RxPauseFrames;
-	*data++ = s->RxFCSErrors;
-	*data++ = s->RxAlignErrors;
-	*data++ = s->RxSymbolErrors;
-	*data++ = s->RxDataErrors;
-	*data++ = s->RxSequenceErrors;
-	*data++ = s->RxRuntErrors;
-	*data++ = s->RxJabberErrors;
-	*data++ = s->RxInternalMACRcvError;
-	*data++ = s->RxInRangeLengthErrors;
-	*data++ = s->RxOutOfRangeLengthField;
-	*data++ = s->RxFrameTooLongErrors;
+	len = sizeof(u64)*(&s->RxFrameTooLongErrors + 1 - &s->RxOctetsOK);
+	memcpy(data, &s->RxOctetsOK, len);
+	data += len;
 
 	t1_sge_get_port_stats(adapter->sge, dev->if_port, &ss);
-	*data++ = ss.rx_packets;
-	*data++ = ss.rx_cso_good;
-	*data++ = ss.tx_packets;
-	*data++ = ss.tx_cso;
-	*data++ = ss.tx_tso;
-	*data++ = ss.vlan_xtract;
-	*data++ = ss.vlan_insert;
+	memcpy(data, &ss, sizeof(ss));
+	data += sizeof(ss);
 
 	t = t1_sge_get_intr_counts(adapter->sge);
 	*data++ = t->rx_drops;
@@ -749,7 +719,7 @@
 		return -EINVAL;
 
 	if (adapter->flags & FULL_INIT_DONE)
-	return -EBUSY;
+		return -EBUSY;
 
 	adapter->params.sge.freelQ_size[!jumbo_fl] = e->rx_pending;
 	adapter->params.sge.freelQ_size[jumbo_fl] = e->rx_jumbo_pending;
@@ -764,7 +734,7 @@
 	struct adapter *adapter = dev->priv;
 
 	adapter->params.sge.rx_coalesce_usecs = c->rx_coalesce_usecs;
- 	adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce;
+	adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce;
 	adapter->params.sge.sample_interval_usecs = c->rate_sample_interval;
 	t1_sge_set_coalesce_params(adapter->sge, &adapter->params.sge);
 	return 0;
@@ -782,9 +752,9 @@
 
 static int get_eeprom_len(struct net_device *dev)
 {
- 	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->priv;
 
- 	return t1_is_asic(adapter) ? EEPROM_SIZE : 0;
+	return t1_is_asic(adapter) ? EEPROM_SIZE : 0;
 }
 
 #define EEPROM_MAGIC(ap) \
@@ -848,7 +818,7 @@
 		u32 val;
 
 		if (!phy->mdio_read)
-	    return -EOPNOTSUPP;
+			return -EOPNOTSUPP;
 		phy->mdio_read(adapter, data->phy_id, 0, data->reg_num & 0x1f,
 			       &val);
 		data->val_out = val;
@@ -860,7 +830,7 @@
 		if (!capable(CAP_NET_ADMIN))
 		    return -EPERM;
 		if (!phy->mdio_write)
-	    return -EOPNOTSUPP;
+			return -EOPNOTSUPP;
 		phy->mdio_write(adapter, data->phy_id, 0, data->reg_num & 0x1f,
 			        data->val_in);
 		break;
@@ -879,9 +849,9 @@
 	struct cmac *mac = adapter->port[dev->if_port].mac;
 
 	if (!mac->ops->set_mtu)
-	return -EOPNOTSUPP;
+		return -EOPNOTSUPP;
 	if (new_mtu < 68)
-	return -EINVAL;
+		return -EINVAL;
 	if ((ret = mac->ops->set_mtu(mac, new_mtu)))
 		return ret;
 	dev->mtu = new_mtu;
@@ -1211,9 +1181,9 @@
 
 	return 0;
 
- out_release_adapter_res:
+out_release_adapter_res:
 	t1_free_sw_modules(adapter);
- out_free_dev:
+out_free_dev:
 	if (adapter) {
 		if (adapter->regs)
 			iounmap(adapter->regs);
@@ -1222,7 +1192,7 @@
 				free_netdev(adapter->port[i].dev);
 	}
 	pci_release_regions(pdev);
- out_disable_pdev:
+out_disable_pdev:
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
 	return err;
@@ -1273,28 +1243,27 @@
 	int M_MEM_VAL;
 
 	enum {
-		M_CORE_BITS = 9,
-		T_CORE_VAL = 0,
-		T_CORE_BITS = 2,
-		N_CORE_VAL = 0,
-		N_CORE_BITS = 2,
-		M_MEM_BITS = 9,
-		T_MEM_VAL = 0,
-		T_MEM_BITS = 2,
-		N_MEM_VAL = 0,
-		N_MEM_BITS = 2,
-		NP_LOAD = 1 << 17,
-		S_LOAD_MEM = 1 << 5,
-		S_LOAD_CORE = 1 << 6,
-		S_CLOCK = 1 << 3
+		M_CORE_BITS	= 9,
+		T_CORE_VAL	= 0,
+		T_CORE_BITS	= 2,
+		N_CORE_VAL	= 0,
+		N_CORE_BITS	= 2,
+		M_MEM_BITS	= 9,
+		T_MEM_VAL	= 0,
+		T_MEM_BITS	= 2,
+		N_MEM_VAL	= 0,
+		N_MEM_BITS	= 2,
+		NP_LOAD		= 1 << 17,
+		S_LOAD_MEM	= 1 << 5,
+		S_LOAD_CORE	= 1 << 6,
+		S_CLOCK		= 1 << 3
 	};
 
 	if (!t1_is_T1B(adapter))
 		return -ENODEV;	/* Can't re-clock this chip. */
 
-	if (mode & 2) {
+	if (mode & 2)
 		return 0;	/* show current mode. */
-	}
 
 	if ((adapter->t1powersave & 1) == (mode & 1))
 		return -EALREADY;	/* ASIC already running in mode. */
@@ -1386,26 +1355,26 @@
 static void __devexit remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
+	struct adapter *adapter = dev->priv;
+	int i;
 
-	if (dev) {
-		int i;
-		struct adapter *adapter = dev->priv;
-
-		for_each_port(adapter, i)
-			if (test_bit(i, &adapter->registered_device_map))
-				unregister_netdev(adapter->port[i].dev);
-
-		t1_free_sw_modules(adapter);
-		iounmap(adapter->regs);
-		while (--i >= 0)
-			if (adapter->port[i].dev)
-				free_netdev(adapter->port[i].dev);
-
-		pci_release_regions(pdev);
-		pci_disable_device(pdev);
-		pci_set_drvdata(pdev, NULL);
-		t1_sw_reset(pdev);
+	for_each_port(adapter, i) {
+		if (test_bit(i, &adapter->registered_device_map))
+			unregister_netdev(adapter->port[i].dev);
 	}
+
+	t1_free_sw_modules(adapter);
+	iounmap(adapter->regs);
+
+	while (--i >= 0) {
+		if (adapter->port[i].dev)
+			free_netdev(adapter->port[i].dev);
+	}
+
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+	t1_sw_reset(pdev);
 }
 
 static struct pci_driver driver = {
diff --git a/drivers/net/chelsio/elmer0.h b/drivers/net/chelsio/elmer0.h
index 9ebecaa..eef655c 100644
--- a/drivers/net/chelsio/elmer0.h
+++ b/drivers/net/chelsio/elmer0.h
@@ -46,14 +46,14 @@
 };
 
 /* ELMER0 registers */
-#define A_ELMER0_VERSION 0x100000
-#define A_ELMER0_PHY_CFG 0x100004
-#define A_ELMER0_INT_ENABLE 0x100008
-#define A_ELMER0_INT_CAUSE 0x10000c
-#define A_ELMER0_GPI_CFG 0x100010
-#define A_ELMER0_GPI_STAT 0x100014
-#define A_ELMER0_GPO 0x100018
-#define A_ELMER0_PORT0_MI1_CFG 0x400000
+#define A_ELMER0_VERSION	0x100000
+#define A_ELMER0_PHY_CFG	0x100004
+#define A_ELMER0_INT_ENABLE	0x100008
+#define A_ELMER0_INT_CAUSE	0x10000c
+#define A_ELMER0_GPI_CFG	0x100010
+#define A_ELMER0_GPI_STAT	0x100014
+#define A_ELMER0_GPO		0x100018
+#define A_ELMER0_PORT0_MI1_CFG	0x400000
 
 #define S_MI1_MDI_ENABLE    0
 #define V_MI1_MDI_ENABLE(x) ((x) << S_MI1_MDI_ENABLE)
@@ -111,18 +111,18 @@
 #define V_MI1_OP_BUSY(x) ((x) << S_MI1_OP_BUSY)
 #define F_MI1_OP_BUSY    V_MI1_OP_BUSY(1U)
 
-#define A_ELMER0_PORT1_MI1_CFG 0x500000
-#define A_ELMER0_PORT1_MI1_ADDR 0x500004
-#define A_ELMER0_PORT1_MI1_DATA 0x500008
-#define A_ELMER0_PORT1_MI1_OP 0x50000c
-#define A_ELMER0_PORT2_MI1_CFG 0x600000
-#define A_ELMER0_PORT2_MI1_ADDR 0x600004
-#define A_ELMER0_PORT2_MI1_DATA 0x600008
-#define A_ELMER0_PORT2_MI1_OP 0x60000c
-#define A_ELMER0_PORT3_MI1_CFG 0x700000
-#define A_ELMER0_PORT3_MI1_ADDR 0x700004
-#define A_ELMER0_PORT3_MI1_DATA 0x700008
-#define A_ELMER0_PORT3_MI1_OP 0x70000c
+#define A_ELMER0_PORT1_MI1_CFG	0x500000
+#define A_ELMER0_PORT1_MI1_ADDR	0x500004
+#define A_ELMER0_PORT1_MI1_DATA	0x500008
+#define A_ELMER0_PORT1_MI1_OP	0x50000c
+#define A_ELMER0_PORT2_MI1_CFG	0x600000
+#define A_ELMER0_PORT2_MI1_ADDR	0x600004
+#define A_ELMER0_PORT2_MI1_DATA	0x600008
+#define A_ELMER0_PORT2_MI1_OP	0x60000c
+#define A_ELMER0_PORT3_MI1_CFG	0x700000
+#define A_ELMER0_PORT3_MI1_ADDR	0x700004
+#define A_ELMER0_PORT3_MI1_DATA	0x700008
+#define A_ELMER0_PORT3_MI1_OP	0x70000c
 
 /* Simple bit definition for GPI and GP0 registers. */
 #define     ELMER0_GP_BIT0              0x0001
diff --git a/drivers/net/chelsio/espi.c b/drivers/net/chelsio/espi.c
index 4192f0f..d7c5406 100644
--- a/drivers/net/chelsio/espi.c
+++ b/drivers/net/chelsio/espi.c
@@ -202,9 +202,9 @@
 
 static void espi_setup_for_vsc7321(adapter_t *adapter)
 {
-        writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0);
-        writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1);
-        writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2);
+	writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0);
+	writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1);
+	writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2);
 	writel(0xa00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK);
 	writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK);
 	writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH);
@@ -247,10 +247,10 @@
 		writel(V_OUT_OF_SYNC_COUNT(4) |
 		       V_DIP2_PARITY_ERR_THRES(3) |
 		       V_DIP4_THRES(1), adapter->regs + A_ESPI_MISC_CONTROL);
-        	writel(nports == 4 ? 0x200040 : 0x1000080,
+		writel(nports == 4 ? 0x200040 : 0x1000080,
 		       adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
 	} else
-        	writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
+		writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
 
 	if (mac_type == CHBT_MAC_PM3393)
 		espi_setup_for_pm3393(adapter);
@@ -301,7 +301,8 @@
 {
 	struct peespi *espi = adapter->espi;
 
-	if (!is_T2(adapter)) return;
+	if (!is_T2(adapter))
+		return;
 	spin_lock(&espi->lock);
 	espi->misc_ctrl = (val & ~MON_MASK) |
 			  (espi->misc_ctrl & MON_MASK);
@@ -340,32 +341,31 @@
  * compare with t1_espi_get_mon(), it reads espiInTxSop[0 ~ 3] in
  * one shot, since there is no per port counter on the out side.
  */
-int
-t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait)
+int t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait)
 {
-        struct peespi *espi = adapter->espi;
+	struct peespi *espi = adapter->espi;
 	u8 i, nport = (u8)adapter->params.nports;
 
-        if (!wait) {
-                if (!spin_trylock(&espi->lock))
-                        return -1;
-        } else
-                spin_lock(&espi->lock);
+	if (!wait) {
+		if (!spin_trylock(&espi->lock))
+			return -1;
+	} else
+		spin_lock(&espi->lock);
 
-	if ( (espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION ) {
+	if ((espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION) {
 		espi->misc_ctrl = (espi->misc_ctrl & ~MON_MASK) |
 					F_MONITORED_DIRECTION;
-                writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
- 	}
+		writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
+	}
 	for (i = 0 ; i < nport; i++, valp++) {
 		if (i) {
 			writel(espi->misc_ctrl | V_MONITORED_PORT_NUM(i),
 			       adapter->regs + A_ESPI_MISC_CONTROL);
 		}
-                *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
-        }
+		*valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
+	}
 
-        writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
-        spin_unlock(&espi->lock);
-        return 0;
+	writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
+	spin_unlock(&espi->lock);
+	return 0;
 }
diff --git a/drivers/net/chelsio/fpga_defs.h b/drivers/net/chelsio/fpga_defs.h
index 17a3c2b..ccdb2bc 100644
--- a/drivers/net/chelsio/fpga_defs.h
+++ b/drivers/net/chelsio/fpga_defs.h
@@ -98,9 +98,9 @@
 #define A_MI0_DATA_INT 0xb10
 
 /* GMAC registers */
-#define A_GMAC_MACID_LO 0x28
-#define A_GMAC_MACID_HI 0x2c
-#define A_GMAC_CSR 0x30
+#define A_GMAC_MACID_LO	0x28
+#define A_GMAC_MACID_HI	0x2c
+#define A_GMAC_CSR	0x30
 
 #define S_INTERFACE    0
 #define M_INTERFACE    0x3
diff --git a/drivers/net/chelsio/gmac.h b/drivers/net/chelsio/gmac.h
index a2b8ad9..006a2eb 100644
--- a/drivers/net/chelsio/gmac.h
+++ b/drivers/net/chelsio/gmac.h
@@ -42,8 +42,15 @@
 
 #include "common.h"
 
-enum { MAC_STATS_UPDATE_FAST, MAC_STATS_UPDATE_FULL };
-enum { MAC_DIRECTION_RX = 1, MAC_DIRECTION_TX = 2 };
+enum {
+	MAC_STATS_UPDATE_FAST,
+	MAC_STATS_UPDATE_FULL
+};
+
+enum {
+	MAC_DIRECTION_RX = 1,
+	MAC_DIRECTION_TX = 2
+};
 
 struct cmac_statistics {
 	/* Transmit */
diff --git a/drivers/net/chelsio/ixf1010.c b/drivers/net/chelsio/ixf1010.c
index 5b8f144..10b2a9a 100644
--- a/drivers/net/chelsio/ixf1010.c
+++ b/drivers/net/chelsio/ixf1010.c
@@ -145,48 +145,61 @@
 	t1_tpi_write(mac->adapter, REG_PORT_ENABLE, val);
 }
 
-#define RMON_UPDATE(mac, name, stat_name) \
-	t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \
-	(mac)->stats.stat_name += val;
-
 /*
  * Read the current values of the RMON counters and add them to the cumulative
  * port statistics.  The HW RMON counters are cleared by this operation.
  */
 static void port_stats_update(struct cmac *mac)
 {
-	u32 val;
+	static struct {
+		unsigned int reg;
+		unsigned int offset;
+	} hw_stats[] = {
 
-	/* Rx stats */
-	RMON_UPDATE(mac, RxOctetsTotalOK, RxOctetsOK);
-	RMON_UPDATE(mac, RxOctetsBad, RxOctetsBad);
-	RMON_UPDATE(mac, RxUCPkts, RxUnicastFramesOK);
-	RMON_UPDATE(mac, RxMCPkts, RxMulticastFramesOK);
-	RMON_UPDATE(mac, RxBCPkts, RxBroadcastFramesOK);
-	RMON_UPDATE(mac, RxJumboPkts, RxJumboFramesOK);
-	RMON_UPDATE(mac, RxFCSErrors, RxFCSErrors);
-	RMON_UPDATE(mac, RxAlignErrors, RxAlignErrors);
-	RMON_UPDATE(mac, RxLongErrors, RxFrameTooLongErrors);
-	RMON_UPDATE(mac, RxVeryLongErrors, RxFrameTooLongErrors);
-	RMON_UPDATE(mac, RxPauseMacControlCounter, RxPauseFrames);
-	RMON_UPDATE(mac, RxDataErrors, RxDataErrors);
-	RMON_UPDATE(mac, RxJabberErrors, RxJabberErrors);
-	RMON_UPDATE(mac, RxRuntErrors, RxRuntErrors);
-	RMON_UPDATE(mac, RxShortErrors, RxRuntErrors);
-	RMON_UPDATE(mac, RxSequenceErrors, RxSequenceErrors);
-	RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors);
+#define HW_STAT(name, stat_name) \
+	{ REG_##name, \
+	  (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
 
-	/* Tx stats (skip collision stats as we are full-duplex only) */
-	RMON_UPDATE(mac, TxOctetsTotalOK, TxOctetsOK);
-	RMON_UPDATE(mac, TxOctetsBad, TxOctetsBad);
-	RMON_UPDATE(mac, TxUCPkts, TxUnicastFramesOK);
-	RMON_UPDATE(mac, TxMCPkts, TxMulticastFramesOK);
-	RMON_UPDATE(mac, TxBCPkts, TxBroadcastFramesOK);
-	RMON_UPDATE(mac, TxJumboPkts, TxJumboFramesOK);
-	RMON_UPDATE(mac, TxPauseFrames, TxPauseFrames);
-	RMON_UPDATE(mac, TxExcessiveLengthDrop, TxLengthErrors);
-	RMON_UPDATE(mac, TxUnderrun, TxUnderrun);
-	RMON_UPDATE(mac, TxCRCErrors, TxFCSErrors);
+		/* Rx stats */
+		HW_STAT(RxOctetsTotalOK, RxOctetsOK),
+		HW_STAT(RxOctetsBad, RxOctetsBad),
+		HW_STAT(RxUCPkts, RxUnicastFramesOK),
+		HW_STAT(RxMCPkts, RxMulticastFramesOK),
+		HW_STAT(RxBCPkts, RxBroadcastFramesOK),
+		HW_STAT(RxJumboPkts, RxJumboFramesOK),
+		HW_STAT(RxFCSErrors, RxFCSErrors),
+		HW_STAT(RxAlignErrors, RxAlignErrors),
+		HW_STAT(RxLongErrors, RxFrameTooLongErrors),
+		HW_STAT(RxVeryLongErrors, RxFrameTooLongErrors),
+		HW_STAT(RxPauseMacControlCounter, RxPauseFrames),
+		HW_STAT(RxDataErrors, RxDataErrors),
+		HW_STAT(RxJabberErrors, RxJabberErrors),
+		HW_STAT(RxRuntErrors, RxRuntErrors),
+		HW_STAT(RxShortErrors, RxRuntErrors),
+		HW_STAT(RxSequenceErrors, RxSequenceErrors),
+		HW_STAT(RxSymbolErrors, RxSymbolErrors),
+
+		/* Tx stats (skip collision stats as we are full-duplex only) */
+		HW_STAT(TxOctetsTotalOK, TxOctetsOK),
+		HW_STAT(TxOctetsBad, TxOctetsBad),
+		HW_STAT(TxUCPkts, TxUnicastFramesOK),
+		HW_STAT(TxMCPkts, TxMulticastFramesOK),
+		HW_STAT(TxBCPkts, TxBroadcastFramesOK),
+		HW_STAT(TxJumboPkts, TxJumboFramesOK),
+		HW_STAT(TxPauseFrames, TxPauseFrames),
+		HW_STAT(TxExcessiveLengthDrop, TxLengthErrors),
+		HW_STAT(TxUnderrun, TxUnderrun),
+		HW_STAT(TxCRCErrors, TxFCSErrors)
+	}, *p = hw_stats;
+	u64 *stats = (u64 *) &mac->stats;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(hw_stats); i++) {
+		u32 val;
+
+		t1_tpi_read(mac->adapter, MACREG(mac, p->reg), &val);
+		stats[p->offset] += val;
+	}
 }
 
 /* No-op interrupt operation as this MAC does not support interrupts */
@@ -273,7 +286,8 @@
 static int mac_set_mtu(struct cmac *mac, int mtu)
 {
 	/* MAX_FRAME_SIZE inludes header + FCS, mtu doesn't */
-	if (mtu > (MAX_FRAME_SIZE - 14 - 4)) return -EINVAL;
+	if (mtu > (MAX_FRAME_SIZE - 14 - 4))
+		return -EINVAL;
 	t1_tpi_write(mac->adapter, MACREG(mac, REG_MAX_FRAME_SIZE),
 		     mtu + 14 + 4);
 	return 0;
@@ -357,8 +371,8 @@
 	val |= (1 << index);
 	t1_tpi_write(adapter, REG_PORT_ENABLE, val);
 
-       	index <<= 2;
-        if (is_T2(adapter)) {
+	index <<= 2;
+	if (is_T2(adapter)) {
 		/* T204: set the Fifo water level & threshold */
 		t1_tpi_write(adapter, RX_FIFO_HIGH_WATERMARK_BASE + index, 0x740);
 		t1_tpi_write(adapter, RX_FIFO_LOW_WATERMARK_BASE + index, 0x730);
@@ -389,6 +403,10 @@
 	return 0;
 }
 
+#define RMON_UPDATE(mac, name, stat_name) \
+	t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \
+	(mac)->stats.stat_name += val;
+
 /*
  * This function is called periodically to accumulate the current values of the
  * RMON counters into the port statistics.  Since the counters are only 32 bits
@@ -460,10 +478,12 @@
 	struct cmac *mac;
 	u32 val;
 
-	if (index > 9) return NULL;
+	if (index > 9)
+		return NULL;
 
 	mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
-	if (!mac) return NULL;
+	if (!mac)
+		return NULL;
 
 	mac->ops = &ixf1010_ops;
 	mac->instance = (cmac_instance *)(mac + 1);
diff --git a/drivers/net/chelsio/mv88e1xxx.c b/drivers/net/chelsio/mv88e1xxx.c
index 28ac93f..5867e3b 100644
--- a/drivers/net/chelsio/mv88e1xxx.c
+++ b/drivers/net/chelsio/mv88e1xxx.c
@@ -73,9 +73,8 @@
 
 		t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
 		elmer |= ELMER0_GP_BIT1;
-		if (is_T2(cphy->adapter)) {
-		    elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
-                }
+		if (is_T2(cphy->adapter))
+		    elmer |= ELMER0_GP_BIT2 | ELMER0_GP_BIT3 | ELMER0_GP_BIT4;
 		t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
 	}
 	return 0;
@@ -92,9 +91,8 @@
 
 		t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
 		elmer &= ~ELMER0_GP_BIT1;
-		if (is_T2(cphy->adapter)) {
+		if (is_T2(cphy->adapter))
 		    elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
-                }
 		t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
 	}
 	return 0;
@@ -112,9 +110,8 @@
 	if (t1_is_asic(cphy->adapter)) {
 		t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
 		elmer |= ELMER0_GP_BIT1;
-		if (is_T2(cphy->adapter)) {
+		if (is_T2(cphy->adapter))
 		    elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
-                }
 		t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
 	}
 	return 0;
@@ -300,7 +297,7 @@
 
 	/*
 	 * Loop until cause reads zero. Need to handle bouncing interrupts.
-         */
+	 */
 	while (1) {
 		u32 cause;
 
@@ -308,15 +305,16 @@
 				MV88E1XXX_INTERRUPT_STATUS_REGISTER,
 				&cause);
 		cause &= INTR_ENABLE_MASK;
-		if (!cause) break;
+		if (!cause)
+			break;
 
 		if (cause & MV88E1XXX_INTR_LINK_CHNG) {
 			(void) simple_mdio_read(cphy,
 				MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status);
 
-			if (status & MV88E1XXX_INTR_LINK_CHNG) {
+			if (status & MV88E1XXX_INTR_LINK_CHNG)
 				cphy->state |= PHY_LINK_UP;
-			} else {
+			else {
 				cphy->state &= ~PHY_LINK_UP;
 				if (cphy->state & PHY_AUTONEG_EN)
 					cphy->state &= ~PHY_AUTONEG_RDY;
@@ -360,7 +358,8 @@
 {
 	struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
 
-	if (!cphy) return NULL;
+	if (!cphy)
+		return NULL;
 
 	cphy_init(cphy, adapter, phy_addr, &mv88e1xxx_ops, mdio_ops);
 
@@ -377,11 +376,11 @@
 	}
 	(void) mv88e1xxx_downshift_set(cphy, 1);   /* Enable downshift */
 
-        /* LED */
+	/* LED */
 	if (is_T2(adapter)) {
 		(void) simple_mdio_write(cphy,
 				MV88E1XXX_LED_CONTROL_REGISTER, 0x1);
-        }
+	}
 
 	return cphy;
 }
diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c
index 82fed1d..87dde3e 100644
--- a/drivers/net/chelsio/my3126.c
+++ b/drivers/net/chelsio/my3126.c
@@ -10,25 +10,25 @@
 	 * This can be done through registers.  It is not required since
 	 * a full chip reset is used.
 	 */
-	return (0);
+	return 0;
 }
 
 static int my3126_interrupt_enable(struct cphy *cphy)
 {
 	schedule_delayed_work(&cphy->phy_update, HZ/30);
 	t1_tpi_read(cphy->adapter, A_ELMER0_GPO, &cphy->elmer_gpo);
-	return (0);
+	return 0;
 }
 
 static int my3126_interrupt_disable(struct cphy *cphy)
 {
 	cancel_rearming_delayed_work(&cphy->phy_update);
-	return (0);
+	return 0;
 }
 
 static int my3126_interrupt_clear(struct cphy *cphy)
 {
-	return (0);
+	return 0;
 }
 
 #define OFFSET(REG_ADDR)    (REG_ADDR << 2)
@@ -102,7 +102,7 @@
 
 static int my3126_set_loopback(struct cphy *cphy, int on)
 {
-	return (0);
+	return 0;
 }
 
 /* To check the activity LED */
@@ -146,7 +146,7 @@
 	if (fc)
 		*fc = PAUSE_RX | PAUSE_TX;
 
-	return (0);
+	return 0;
 }
 
 static void my3126_destroy(struct cphy *cphy)
@@ -177,7 +177,7 @@
 	INIT_DELAYED_WORK(&cphy->phy_update, my3216_poll);
 	cphy->bmsr = 0;
 
-	return (cphy);
+	return cphy;
 }
 
 /* Chip Reset */
@@ -198,7 +198,7 @@
 	val |= 0x8000;
 	t1_tpi_write(adapter, A_ELMER0_GPO, val);
 	udelay(100);
-	return (0);
+	return 0;
 }
 
 struct gphy t1_my3126_ops = {
diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/chelsio/pm3393.c
index 63cabeb..69129ed 100644
--- a/drivers/net/chelsio/pm3393.c
+++ b/drivers/net/chelsio/pm3393.c
@@ -446,17 +446,51 @@
 		*val += 1ull << 40;
 }
 
-#define RMON_UPDATE(mac, name, stat_name) \
-	pm3393_rmon_update((mac)->adapter, OFFSET(name), 		\
-			   &(mac)->stats.stat_name,			\
-		   (ro &((name - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW) >> 2)))
-
-
 static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac,
 							      int flag)
 {
-	u64	ro;
-	u32	val0, val1, val2, val3;
+	static struct {
+		unsigned int reg;
+		unsigned int offset;
+	} hw_stats [] = {
+
+#define HW_STAT(name, stat_name) \
+	{ name, (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
+
+		/* Rx stats */
+		HW_STAT(RxOctetsReceivedOK, RxOctetsOK),
+		HW_STAT(RxUnicastFramesReceivedOK, RxUnicastFramesOK),
+		HW_STAT(RxMulticastFramesReceivedOK, RxMulticastFramesOK),
+		HW_STAT(RxBroadcastFramesReceivedOK, RxBroadcastFramesOK),
+		HW_STAT(RxPAUSEMACCtrlFramesReceived, RxPauseFrames),
+		HW_STAT(RxFrameCheckSequenceErrors, RxFCSErrors),
+		HW_STAT(RxFramesLostDueToInternalMACErrors,
+				RxInternalMACRcvError),
+		HW_STAT(RxSymbolErrors, RxSymbolErrors),
+		HW_STAT(RxInRangeLengthErrors, RxInRangeLengthErrors),
+		HW_STAT(RxFramesTooLongErrors , RxFrameTooLongErrors),
+		HW_STAT(RxJabbers, RxJabberErrors),
+		HW_STAT(RxFragments, RxRuntErrors),
+		HW_STAT(RxUndersizedFrames, RxRuntErrors),
+		HW_STAT(RxJumboFramesReceivedOK, RxJumboFramesOK),
+		HW_STAT(RxJumboOctetsReceivedOK, RxJumboOctetsOK),
+
+		/* Tx stats */
+		HW_STAT(TxOctetsTransmittedOK, TxOctetsOK),
+		HW_STAT(TxFramesLostDueToInternalMACTransmissionError,
+				TxInternalMACXmitError),
+		HW_STAT(TxTransmitSystemError, TxFCSErrors),
+		HW_STAT(TxUnicastFramesTransmittedOK, TxUnicastFramesOK),
+		HW_STAT(TxMulticastFramesTransmittedOK, TxMulticastFramesOK),
+		HW_STAT(TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK),
+		HW_STAT(TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames),
+		HW_STAT(TxJumboFramesReceivedOK, TxJumboFramesOK),
+		HW_STAT(TxJumboOctetsReceivedOK, TxJumboOctetsOK)
+	}, *p = hw_stats;
+	u64 ro;
+	u32 val0, val1, val2, val3;
+	u64 *stats = (u64 *) &mac->stats;
+	unsigned int i;
 
 	/* Snap the counters */
 	pmwrite(mac, SUNI1x10GEXP_REG_MSTAT_CONTROL,
@@ -470,35 +504,14 @@
 	ro = ((u64)val0 & 0xffff) | (((u64)val1 & 0xffff) << 16) |
 		(((u64)val2 & 0xffff) << 32) | (((u64)val3 & 0xffff) << 48);
 
-	/* Rx stats */
-	RMON_UPDATE(mac, RxOctetsReceivedOK, RxOctetsOK);
-	RMON_UPDATE(mac, RxUnicastFramesReceivedOK, RxUnicastFramesOK);
-	RMON_UPDATE(mac, RxMulticastFramesReceivedOK, RxMulticastFramesOK);
-	RMON_UPDATE(mac, RxBroadcastFramesReceivedOK, RxBroadcastFramesOK);
-	RMON_UPDATE(mac, RxPAUSEMACCtrlFramesReceived, RxPauseFrames);
-	RMON_UPDATE(mac, RxFrameCheckSequenceErrors, RxFCSErrors);
-	RMON_UPDATE(mac, RxFramesLostDueToInternalMACErrors,
-				RxInternalMACRcvError);
-	RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors);
-	RMON_UPDATE(mac, RxInRangeLengthErrors, RxInRangeLengthErrors);
-	RMON_UPDATE(mac, RxFramesTooLongErrors , RxFrameTooLongErrors);
-	RMON_UPDATE(mac, RxJabbers, RxJabberErrors);
-	RMON_UPDATE(mac, RxFragments, RxRuntErrors);
-	RMON_UPDATE(mac, RxUndersizedFrames, RxRuntErrors);
-	RMON_UPDATE(mac, RxJumboFramesReceivedOK, RxJumboFramesOK);
-	RMON_UPDATE(mac, RxJumboOctetsReceivedOK, RxJumboOctetsOK);
+	for (i = 0; i < ARRAY_SIZE(hw_stats); i++) {
+		unsigned reg = p->reg - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW;
 
-	/* Tx stats */
-	RMON_UPDATE(mac, TxOctetsTransmittedOK, TxOctetsOK);
-	RMON_UPDATE(mac, TxFramesLostDueToInternalMACTransmissionError,
-				TxInternalMACXmitError);
-	RMON_UPDATE(mac, TxTransmitSystemError, TxFCSErrors);
-	RMON_UPDATE(mac, TxUnicastFramesTransmittedOK, TxUnicastFramesOK);
-	RMON_UPDATE(mac, TxMulticastFramesTransmittedOK, TxMulticastFramesOK);
-	RMON_UPDATE(mac, TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK);
-	RMON_UPDATE(mac, TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames);
-	RMON_UPDATE(mac, TxJumboFramesReceivedOK, TxJumboFramesOK);
-	RMON_UPDATE(mac, TxJumboOctetsReceivedOK, TxJumboOctetsOK);
+		pm3393_rmon_update((mac)->adapter, OFFSET(p->reg),
+				   stats + p->offset, ro & (reg >> 2));
+	}
+
+
 
 	return &mac->stats;
 }
@@ -534,9 +547,9 @@
 	/* Store local copy */
 	memcpy(cmac->instance->mac_addr, ma, 6);
 
-	lo = ((u32) ma[1] << 8) | (u32) ma[0];
+	lo  = ((u32) ma[1] << 8) | (u32) ma[0];
 	mid = ((u32) ma[3] << 8) | (u32) ma[2];
-	hi = ((u32) ma[5] << 8) | (u32) ma[4];
+	hi  = ((u32) ma[5] << 8) | (u32) ma[4];
 
 	/* Disable Rx/Tx MAC before configuring it. */
 	if (enabled)
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index 659cb22..89a6827 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -71,12 +71,9 @@
 #define SGE_FREEL_REFILL_THRESH	16
 #define SGE_RESPQ_E_N		1024
 #define SGE_INTRTIMER_NRES	1000
-#define SGE_RX_COPY_THRES	256
 #define SGE_RX_SM_BUF_SIZE	1536
 #define SGE_TX_DESC_MAX_PLEN	16384
 
-# define SGE_RX_DROP_THRES 2
-
 #define SGE_RESPQ_REPLENISH_THRES (SGE_RESPQ_E_N / 4)
 
 /*
@@ -85,10 +82,6 @@
  */
 #define TX_RECLAIM_PERIOD (HZ / 4)
 
-#ifndef NET_IP_ALIGN
-# define NET_IP_ALIGN 2
-#endif
-
 #define M_CMD_LEN       0x7fffffff
 #define V_CMD_LEN(v)    (v)
 #define G_CMD_LEN(v)    ((v) & M_CMD_LEN)
@@ -195,7 +188,7 @@
 	struct cmdQ_e  *entries;        /* HW command descriptor Q */
 	struct cmdQ_ce *centries;       /* SW command context descriptor Q */
 	dma_addr_t	dma_addr;       /* DMA addr HW command descriptor Q */
- 	spinlock_t	lock;           /* Lock to protect cmdQ enqueuing */
+	spinlock_t	lock;           /* Lock to protect cmdQ enqueuing */
 };
 
 struct freelQ {
@@ -241,9 +234,9 @@
 /* Per T204 device */
 struct sched {
 	ktime_t         last_updated;   /* last time quotas were computed */
-	unsigned int 	max_avail;	/* max bits to be sent to any port */
-	unsigned int 	port;		/* port index (round robin ports) */
-	unsigned int 	num;		/* num skbs in per port queues */
+	unsigned int	max_avail;	/* max bits to be sent to any port */
+	unsigned int	port;		/* port index (round robin ports) */
+	unsigned int	num;		/* num skbs in per port queues */
 	struct sched_port p[MAX_NPORTS];
 	struct tasklet_struct sched_tsk;/* tasklet used to run scheduler */
 };
@@ -259,10 +252,10 @@
  * contention.
  */
 struct sge {
-	struct adapter *adapter; 	/* adapter backpointer */
+	struct adapter *adapter;	/* adapter backpointer */
 	struct net_device *netdev;      /* netdevice backpointer */
-	struct freelQ 	freelQ[SGE_FREELQ_N]; /* buffer free lists */
-	struct respQ 	respQ;		/* response Q */
+	struct freelQ	freelQ[SGE_FREELQ_N]; /* buffer free lists */
+	struct respQ	respQ;		/* response Q */
 	unsigned long   stopped_tx_queues; /* bitmap of suspended Tx queues */
 	unsigned int	rx_pkt_pad;     /* RX padding for L2 packets */
 	unsigned int	jumbo_fl;       /* jumbo freelist Q index */
@@ -460,7 +453,7 @@
 	if (credits < MAX_SKB_FRAGS + 1)
 		goto out;
 
- again:
+again:
 	for (i = 0; i < MAX_NPORTS; i++) {
 		s->port = ++s->port & (MAX_NPORTS - 1);
 		skbq = &s->p[s->port].skbq;
@@ -483,8 +476,8 @@
 	if (update-- && sched_update_avail(sge))
 		goto again;
 
- out:
- 	/* If there are more pending skbs, we use the hardware to schedule us
+out:
+	/* If there are more pending skbs, we use the hardware to schedule us
 	 * again.
 	 */
 	if (s->num && !skb) {
@@ -575,11 +568,10 @@
 		q->size = p->freelQ_size[i];
 		q->dma_offset = sge->rx_pkt_pad ? 0 : NET_IP_ALIGN;
 		size = sizeof(struct freelQ_e) * q->size;
-		q->entries = (struct freelQ_e *)
-			      pci_alloc_consistent(pdev, size, &q->dma_addr);
+		q->entries = pci_alloc_consistent(pdev, size, &q->dma_addr);
 		if (!q->entries)
 			goto err_no_mem;
-		memset(q->entries, 0, size);
+
 		size = sizeof(struct freelQ_ce) * q->size;
 		q->centries = kzalloc(size, GFP_KERNEL);
 		if (!q->centries)
@@ -613,11 +605,10 @@
 	sge->respQ.size = SGE_RESPQ_E_N;
 	sge->respQ.credits = 0;
 	size = sizeof(struct respQ_e) * sge->respQ.size;
-	sge->respQ.entries = (struct respQ_e *)
+	sge->respQ.entries =
 		pci_alloc_consistent(pdev, size, &sge->respQ.dma_addr);
 	if (!sge->respQ.entries)
 		goto err_no_mem;
-	memset(sge->respQ.entries, 0, size);
 	return 0;
 
 err_no_mem:
@@ -637,20 +628,12 @@
 	q->in_use -= n;
 	ce = &q->centries[cidx];
 	while (n--) {
-		if (q->sop) {
-			if (likely(pci_unmap_len(ce, dma_len))) {
-				pci_unmap_single(pdev,
-						 pci_unmap_addr(ce, dma_addr),
-			 			 pci_unmap_len(ce, dma_len),
-						 PCI_DMA_TODEVICE);
+		if (likely(pci_unmap_len(ce, dma_len))) {
+			pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr),
+					 pci_unmap_len(ce, dma_len),
+					 PCI_DMA_TODEVICE);
+			if (q->sop)
 				q->sop = 0;
-			}
-		} else {
-			if (likely(pci_unmap_len(ce, dma_len))) {
-				pci_unmap_page(pdev, pci_unmap_addr(ce, dma_addr),
-			 		       pci_unmap_len(ce, dma_len),
-					       PCI_DMA_TODEVICE);
-			}
 		}
 		if (ce->skb) {
 			dev_kfree_skb_any(ce->skb);
@@ -711,11 +694,10 @@
 		q->stop_thres = 0;
 		spin_lock_init(&q->lock);
 		size = sizeof(struct cmdQ_e) * q->size;
-		q->entries = (struct cmdQ_e *)
-			      pci_alloc_consistent(pdev, size, &q->dma_addr);
+		q->entries = pci_alloc_consistent(pdev, size, &q->dma_addr);
 		if (!q->entries)
 			goto err_no_mem;
-		memset(q->entries, 0, size);
+
 		size = sizeof(struct cmdQ_ce) * q->size;
 		q->centries = kzalloc(size, GFP_KERNEL);
 		if (!q->centries)
@@ -770,7 +752,7 @@
 static void configure_sge(struct sge *sge, struct sge_params *p)
 {
 	struct adapter *ap = sge->adapter;
-	
+
 	writel(0, ap->regs + A_SG_CONTROL);
 	setup_ring_params(ap, sge->cmdQ[0].dma_addr, sge->cmdQ[0].size,
 			  A_SG_CMD0BASELWR, A_SG_CMD0BASEUPR, A_SG_CMD0SIZE);
@@ -850,7 +832,6 @@
 	struct freelQ_e *e = &q->entries[q->pidx];
 	unsigned int dma_len = q->rx_buffer_size - q->dma_offset;
 
-
 	while (q->credits < q->size) {
 		struct sk_buff *skb;
 		dma_addr_t mapping;
@@ -862,6 +843,8 @@
 		skb_reserve(skb, q->dma_offset);
 		mapping = pci_map_single(pdev, skb->data, dma_len,
 					 PCI_DMA_FROMDEVICE);
+		skb_reserve(skb, sge->rx_pkt_pad);
+
 		ce->skb = skb;
 		pci_unmap_addr_set(ce, dma_addr, mapping);
 		pci_unmap_len_set(ce, dma_len, dma_len);
@@ -881,7 +864,6 @@
 		}
 		q->credits++;
 	}
-
 }
 
 /*
@@ -1041,6 +1023,10 @@
 	}
 }
 
+static int copybreak __read_mostly = 256;
+module_param(copybreak, int, 0);
+MODULE_PARM_DESC(copybreak, "Receive copy threshold");
+
 /**
  *	get_packet - return the next ingress packet buffer
  *	@pdev: the PCI device that received the packet
@@ -1060,45 +1046,42 @@
  *	be copied but there is no memory for the copy.
  */
 static inline struct sk_buff *get_packet(struct pci_dev *pdev,
-					 struct freelQ *fl, unsigned int len,
-					 int dma_pad, int skb_pad,
-					 unsigned int copy_thres,
-					 unsigned int drop_thres)
+					 struct freelQ *fl, unsigned int len)
 {
 	struct sk_buff *skb;
-	struct freelQ_ce *ce = &fl->centries[fl->cidx];
+	const struct freelQ_ce *ce = &fl->centries[fl->cidx];
 
-	if (len < copy_thres) {
-		skb = alloc_skb(len + skb_pad, GFP_ATOMIC);
-		if (likely(skb != NULL)) {
-			skb_reserve(skb, skb_pad);
-			skb_put(skb, len);
-			pci_dma_sync_single_for_cpu(pdev,
-					    pci_unmap_addr(ce, dma_addr),
- 					    pci_unmap_len(ce, dma_len),
-					    PCI_DMA_FROMDEVICE);
-			memcpy(skb->data, ce->skb->data + dma_pad, len);
-			pci_dma_sync_single_for_device(pdev,
-					    pci_unmap_addr(ce, dma_addr),
- 					    pci_unmap_len(ce, dma_len),
-					    PCI_DMA_FROMDEVICE);
-		} else if (!drop_thres)
+	if (len < copybreak) {
+		skb = alloc_skb(len + 2, GFP_ATOMIC);
+		if (!skb)
 			goto use_orig_buf;
 
+		skb_reserve(skb, 2);	/* align IP header */
+		skb_put(skb, len);
+		pci_dma_sync_single_for_cpu(pdev,
+					    pci_unmap_addr(ce, dma_addr),
+					    pci_unmap_len(ce, dma_len),
+					    PCI_DMA_FROMDEVICE);
+		memcpy(skb->data, ce->skb->data, len);
+		pci_dma_sync_single_for_device(pdev,
+					       pci_unmap_addr(ce, dma_addr),
+					       pci_unmap_len(ce, dma_len),
+					       PCI_DMA_FROMDEVICE);
 		recycle_fl_buf(fl, fl->cidx);
 		return skb;
 	}
 
-	if (fl->credits < drop_thres) {
+use_orig_buf:
+	if (fl->credits < 2) {
 		recycle_fl_buf(fl, fl->cidx);
 		return NULL;
 	}
 
-use_orig_buf:
 	pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr),
 			 pci_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE);
 	skb = ce->skb;
-	skb_reserve(skb, dma_pad);
+	prefetch(skb->data);
+
 	skb_put(skb, len);
 	return skb;
 }
@@ -1137,6 +1120,7 @@
 static inline unsigned int compute_large_page_tx_descs(struct sk_buff *skb)
 {
 	unsigned int count = 0;
+
 	if (PAGE_SIZE > SGE_TX_DESC_MAX_PLEN) {
 		unsigned int nfrags = skb_shinfo(skb)->nr_frags;
 		unsigned int i, len = skb->len - skb->data_len;
@@ -1343,7 +1327,7 @@
 	while ((skb = sched_skb(sge, NULL, credits)) != NULL) {
 		unsigned int genbit, pidx, count;
 	        count = 1 + skb_shinfo(skb)->nr_frags;
-       		count += compute_large_page_tx_descs(skb);
+		count += compute_large_page_tx_descs(skb);
 		q->in_use += count;
 		genbit = q->genbit;
 		pidx = q->pidx;
@@ -1375,27 +1359,25 @@
  *
  *	Process an ingress ethernet pakcet and deliver it to the stack.
  */
-static int sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
+static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
 {
 	struct sk_buff *skb;
-	struct cpl_rx_pkt *p;
+	const struct cpl_rx_pkt *p;
 	struct adapter *adapter = sge->adapter;
 	struct sge_port_stats *st;
 
-	skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad,
-			 sge->rx_pkt_pad, 2, SGE_RX_COPY_THRES,
-			 SGE_RX_DROP_THRES);
+	skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad);
 	if (unlikely(!skb)) {
 		sge->stats.rx_drops++;
-		return 0;
+		return;
 	}
 
-	p = (struct cpl_rx_pkt *)skb->data;
-	skb_pull(skb, sizeof(*p));
+	p = (const struct cpl_rx_pkt *) skb->data;
 	if (p->iff >= adapter->params.nports) {
 		kfree_skb(skb);
-		return 0;
+		return;
 	}
+	__skb_pull(skb, sizeof(*p));
 
 	skb->dev = adapter->port[p->iff].dev;
 	skb->dev->last_rx = jiffies;
@@ -1427,7 +1409,6 @@
 		netif_rx(skb);
 #endif
 	}
-	return 0;
 }
 
 /*
@@ -1448,29 +1429,28 @@
 static void restart_tx_queues(struct sge *sge)
 {
 	struct adapter *adap = sge->adapter;
+	int i;
 
-	if (enough_free_Tx_descs(&sge->cmdQ[0])) {
-		int i;
+	if (!enough_free_Tx_descs(&sge->cmdQ[0]))
+		return;
 
-		for_each_port(adap, i) {
-			struct net_device *nd = adap->port[i].dev;
+	for_each_port(adap, i) {
+		struct net_device *nd = adap->port[i].dev;
 
-			if (test_and_clear_bit(nd->if_port,
-					       &sge->stopped_tx_queues) &&
-			    netif_running(nd)) {
-				sge->stats.cmdQ_restarted[2]++;
-				netif_wake_queue(nd);
-			}
+		if (test_and_clear_bit(nd->if_port, &sge->stopped_tx_queues) &&
+		    netif_running(nd)) {
+			sge->stats.cmdQ_restarted[2]++;
+			netif_wake_queue(nd);
 		}
 	}
 }
 
 /*
- * update_tx_info is called from the interrupt handler/NAPI to return cmdQ0 
+ * update_tx_info is called from the interrupt handler/NAPI to return cmdQ0
  * information.
  */
-static unsigned int update_tx_info(struct adapter *adapter, 
-					  unsigned int flags, 
+static unsigned int update_tx_info(struct adapter *adapter,
+					  unsigned int flags,
 					  unsigned int pr0)
 {
 	struct sge *sge = adapter->sge;
@@ -1510,29 +1490,30 @@
 	struct sge *sge = adapter->sge;
 	struct respQ *q = &sge->respQ;
 	struct respQ_e *e = &q->entries[q->cidx];
-	int budget_left = budget;
+	int done = 0;
 	unsigned int flags = 0;
 	unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0};
-	
 
-	while (likely(budget_left && e->GenerationBit == q->genbit)) {
+	while (done < budget && e->GenerationBit == q->genbit) {
 		flags |= e->Qsleeping;
-		
+
 		cmdq_processed[0] += e->Cmdq0CreditReturn;
 		cmdq_processed[1] += e->Cmdq1CreditReturn;
-		
+
 		/* We batch updates to the TX side to avoid cacheline
 		 * ping-pong of TX state information on MP where the sender
 		 * might run on a different CPU than this function...
 		 */
-		if (unlikely(flags & F_CMDQ0_ENABLE || cmdq_processed[0] > 64)) {
+		if (unlikely((flags & F_CMDQ0_ENABLE) || cmdq_processed[0] > 64)) {
 			flags = update_tx_info(adapter, flags, cmdq_processed[0]);
 			cmdq_processed[0] = 0;
 		}
+
 		if (unlikely(cmdq_processed[1] > 16)) {
 			sge->cmdQ[1].processed += cmdq_processed[1];
 			cmdq_processed[1] = 0;
 		}
+
 		if (likely(e->DataValid)) {
 			struct freelQ *fl = &sge->freelQ[e->FreelistQid];
 
@@ -1542,12 +1523,16 @@
 			else
 				sge_rx(sge, fl, e->BufferLength);
 
+			++done;
+
 			/*
 			 * Note: this depends on each packet consuming a
 			 * single free-list buffer; cf. the BUG above.
 			 */
 			if (++fl->cidx == fl->size)
 				fl->cidx = 0;
+			prefetch(fl->centries[fl->cidx].skb);
+
 			if (unlikely(--fl->credits <
 				     fl->size - SGE_FREEL_REFILL_THRESH))
 				refill_free_list(sge, fl);
@@ -1566,14 +1551,20 @@
 			writel(q->credits, adapter->regs + A_SG_RSPQUEUECREDIT);
 			q->credits = 0;
 		}
-		--budget_left;
 	}
 
-	flags = update_tx_info(adapter, flags, cmdq_processed[0]); 
+	flags = update_tx_info(adapter, flags, cmdq_processed[0]);
 	sge->cmdQ[1].processed += cmdq_processed[1];
 
-	budget -= budget_left;
-	return budget;
+	return done;
+}
+
+static inline int responses_pending(const struct adapter *adapter)
+{
+	const struct respQ *Q = &adapter->sge->respQ;
+	const struct respQ_e *e = &Q->entries[Q->cidx];
+
+	return (e->GenerationBit == Q->genbit);
 }
 
 #ifdef CONFIG_CHELSIO_T1_NAPI
@@ -1585,19 +1576,25 @@
  * which the caller must ensure is a valid pure response.  Returns 1 if it
  * encounters a valid data-carrying response, 0 otherwise.
  */
-static int process_pure_responses(struct adapter *adapter, struct respQ_e *e)
+static int process_pure_responses(struct adapter *adapter)
 {
 	struct sge *sge = adapter->sge;
 	struct respQ *q = &sge->respQ;
+	struct respQ_e *e = &q->entries[q->cidx];
+	const struct freelQ *fl = &sge->freelQ[e->FreelistQid];
 	unsigned int flags = 0;
 	unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0};
 
+	prefetch(fl->centries[fl->cidx].skb);
+	if (e->DataValid)
+		return 1;
+
 	do {
 		flags |= e->Qsleeping;
 
 		cmdq_processed[0] += e->Cmdq0CreditReturn;
 		cmdq_processed[1] += e->Cmdq1CreditReturn;
-		
+
 		e++;
 		if (unlikely(++q->cidx == q->size)) {
 			q->cidx = 0;
@@ -1613,7 +1610,7 @@
 		sge->stats.pure_rsps++;
 	} while (e->GenerationBit == q->genbit && !e->DataValid);
 
-	flags = update_tx_info(adapter, flags, cmdq_processed[0]); 
+	flags = update_tx_info(adapter, flags, cmdq_processed[0]);
 	sge->cmdQ[1].processed += cmdq_processed[1];
 
 	return e->GenerationBit == q->genbit;
@@ -1627,23 +1624,20 @@
 int t1_poll(struct net_device *dev, int *budget)
 {
 	struct adapter *adapter = dev->priv;
-	int effective_budget = min(*budget, dev->quota);
-	int work_done = process_responses(adapter, effective_budget);
+	int work_done;
 
+	work_done = process_responses(adapter, min(*budget, dev->quota));
 	*budget -= work_done;
 	dev->quota -= work_done;
 
-	if (work_done >= effective_budget)
+	if (unlikely(responses_pending(adapter)))
 		return 1;
 
- 	spin_lock_irq(&adapter->async_lock);
-	__netif_rx_complete(dev);
+	netif_rx_complete(dev);
 	writel(adapter->sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
-	writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA,
-	       adapter->regs + A_PL_ENABLE);
- 	spin_unlock_irq(&adapter->async_lock);
 
 	return 0;
+
 }
 
 /*
@@ -1652,44 +1646,33 @@
 irqreturn_t t1_interrupt(int irq, void *data)
 {
 	struct adapter *adapter = data;
- 	struct net_device *dev = adapter->sge->netdev;
 	struct sge *sge = adapter->sge;
- 	u32 cause;
-	int handled = 0;
+	int handled;
 
-	cause = readl(adapter->regs + A_PL_CAUSE);
-	if (cause == 0 || cause == ~0)
-		return IRQ_NONE;
+	if (likely(responses_pending(adapter))) {
+		struct net_device *dev = sge->netdev;
+
+		writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
+
+		if (__netif_rx_schedule_prep(dev)) {
+			if (process_pure_responses(adapter))
+				__netif_rx_schedule(dev);
+			else {
+				/* no data, no NAPI needed */
+				writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
+				netif_poll_enable(dev);	/* undo schedule_prep */
+			}
+		}
+		return IRQ_HANDLED;
+	}
 
 	spin_lock(&adapter->async_lock);
- 	if (cause & F_PL_INTR_SGE_DATA) {
-		struct respQ *q = &adapter->sge->respQ;
-		struct respQ_e *e = &q->entries[q->cidx];
-
- 		handled = 1;
- 		writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
-
-		if (e->GenerationBit == q->genbit &&
-		    __netif_rx_schedule_prep(dev)) {
-			if (e->DataValid || process_pure_responses(adapter, e)) {
-				/* mask off data IRQ */
-				writel(adapter->slow_intr_mask,
-				       adapter->regs + A_PL_ENABLE);
-				__netif_rx_schedule(sge->netdev);
-				goto unlock;
-			}
-			/* no data, no NAPI needed */
-			netif_poll_enable(dev);
-
-		}
-		writel(q->cidx, adapter->regs + A_SG_SLEEPING);
-	} else
-		handled = t1_slow_intr_handler(adapter);
+	handled = t1_slow_intr_handler(adapter);
+	spin_unlock(&adapter->async_lock);
 
 	if (!handled)
 		sge->stats.unhandled_irqs++;
-unlock:
-	spin_unlock(&adapter->async_lock);
+
 	return IRQ_RETVAL(handled != 0);
 }
 
@@ -1712,17 +1695,13 @@
 irqreturn_t t1_interrupt(int irq, void *cookie)
 {
 	int work_done;
-	struct respQ_e *e;
 	struct adapter *adapter = cookie;
-	struct respQ *Q = &adapter->sge->respQ;
 
 	spin_lock(&adapter->async_lock);
-	e = &Q->entries[Q->cidx];
-	prefetch(e);
 
 	writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
 
-	if (likely(e->GenerationBit == Q->genbit))
+	if (likely(responses_pending(adapter)))
 		work_done = process_responses(adapter, -1);
 	else
 		work_done = t1_slow_intr_handler(adapter);
@@ -1796,7 +1775,7 @@
 	 * through the scheduler.
 	 */
 	if (sge->tx_sched && !qid && skb->dev) {
-	use_sched:
+use_sched:
 		use_sched_skb = 1;
 		/* Note that the scheduler might return a different skb than
 		 * the one passed in.
@@ -1900,7 +1879,7 @@
 		cpl = (struct cpl_tx_pkt *)hdr;
 	} else {
 		/*
-	 	 * Packets shorter than ETH_HLEN can break the MAC, drop them
+		 * Packets shorter than ETH_HLEN can break the MAC, drop them
 		 * early.  Also, we may get oversized packets because some
 		 * parts of the kernel don't handle our unusual hard_header_len
 		 * right, drop those too.
@@ -1984,9 +1963,9 @@
 	 * then silently discard to avoid leak.
 	 */
 	if (unlikely(ret != NETDEV_TX_OK && skb != orig_skb)) {
- 		dev_kfree_skb_any(skb);
+		dev_kfree_skb_any(skb);
 		ret = NETDEV_TX_OK;
- 	}
+	}
 	return ret;
 }
 
@@ -2099,31 +2078,35 @@
 
 	if (adapter->open_device_map & PORT_MASK) {
 		int i;
-		if (t1_espi_get_mon_t204(adapter, &(seop[0]), 0) < 0) {
-			return;
-		}
-		for (i = 0; i < nports; i++) {
-	        	struct sk_buff *skb = sge->espibug_skb[i];
-			if ( (netif_running(adapter->port[i].dev)) &&
-			     !(netif_queue_stopped(adapter->port[i].dev)) &&
-			     (seop[i] && ((seop[i] & 0xfff) == 0)) &&
-			     skb ) {
-	                	if (!skb->cb[0]) {
-	                        	u8 ch_mac_addr[ETH_ALEN] =
-	                            	{0x0, 0x7, 0x43, 0x0, 0x0, 0x0};
-	                        	memcpy(skb->data + sizeof(struct cpl_tx_pkt),
-	                               	ch_mac_addr, ETH_ALEN);
-	                        	memcpy(skb->data + skb->len - 10,
-						ch_mac_addr, ETH_ALEN);
-	                        	skb->cb[0] = 0xff;
-	                	}
 
-	                	/* bump the reference count to avoid freeing of
-	                 	 * the skb once the DMA has completed.
-	                 	 */
-	                	skb = skb_get(skb);
-	                	t1_sge_tx(skb, adapter, 0, adapter->port[i].dev);
+		if (t1_espi_get_mon_t204(adapter, &(seop[0]), 0) < 0)
+			return;
+
+		for (i = 0; i < nports; i++) {
+			struct sk_buff *skb = sge->espibug_skb[i];
+
+			if (!netif_running(adapter->port[i].dev) ||
+			    netif_queue_stopped(adapter->port[i].dev) ||
+			    !seop[i] || ((seop[i] & 0xfff) != 0) || !skb)
+				continue;
+
+			if (!skb->cb[0]) {
+				u8 ch_mac_addr[ETH_ALEN] = {
+					0x0, 0x7, 0x43, 0x0, 0x0, 0x0
+				};
+
+				memcpy(skb->data + sizeof(struct cpl_tx_pkt),
+					ch_mac_addr, ETH_ALEN);
+				memcpy(skb->data + skb->len - 10,
+					ch_mac_addr, ETH_ALEN);
+				skb->cb[0] = 0xff;
 			}
+
+			/* bump the reference count to avoid freeing of
+			 * the skb once the DMA has completed.
+			 */
+			skb = skb_get(skb);
+			t1_sge_tx(skb, adapter, 0, adapter->port[i].dev);
 		}
 	}
 	mod_timer(&sge->espibug_timer, jiffies + sge->espibug_timeout);
@@ -2192,9 +2175,8 @@
 		if (adapter->params.nports > 1) {
 			tx_sched_init(sge);
 			sge->espibug_timer.function = espibug_workaround_t204;
-		} else {
+		} else
 			sge->espibug_timer.function = espibug_workaround;
-		}
 		sge->espibug_timer.data = (unsigned long)sge->adapter;
 
 		sge->espibug_timeout = 1;
@@ -2202,7 +2184,7 @@
 		if (adapter->params.nports > 1)
 			sge->espibug_timeout = HZ/100;
 	}
-	 
+
 
 	p->cmdQ_size[0] = SGE_CMDQ0_E_N;
 	p->cmdQ_size[1] = SGE_CMDQ1_E_N;
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
index 22ed9a3..c2522cd 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -223,13 +223,13 @@
 		t1_sge_intr_error_handler(adapter->sge);
 
 	if (cause & FPGA_PCIX_INTERRUPT_GMAC)
-                fpga_phy_intr_handler(adapter);
+		fpga_phy_intr_handler(adapter);
 
 	if (cause & FPGA_PCIX_INTERRUPT_TP) {
-                /*
+		/*
 		 * FPGA doesn't support MC4 interrupts and it requires
 		 * this odd layer of indirection for MC5.
-                 */
+		 */
 		u32 tp_cause = readl(adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE);
 
 		/* Clear TP interrupt */
@@ -262,8 +262,7 @@
 			udelay(10);
 	} while (busy && --attempts);
 	if (busy)
-		CH_ALERT("%s: MDIO operation timed out\n",
-			 adapter->name);
+		CH_ALERT("%s: MDIO operation timed out\n", adapter->name);
 	return busy;
 }
 
@@ -605,22 +604,23 @@
 
 	switch (board_info(adapter)->board) {
 #ifdef CONFIG_CHELSIO_T1_1G
-        case CHBT_BOARD_CHT204:
-        case CHBT_BOARD_CHT204E:
-        case CHBT_BOARD_CHN204:
-        case CHBT_BOARD_CHT204V: {
-                int i, port_bit;
+	case CHBT_BOARD_CHT204:
+	case CHBT_BOARD_CHT204E:
+	case CHBT_BOARD_CHN204:
+	case CHBT_BOARD_CHT204V: {
+		int i, port_bit;
 		for_each_port(adapter, i) {
 			port_bit = i + 1;
-			if (!(cause & (1 << port_bit))) continue;
+			if (!(cause & (1 << port_bit)))
+				continue;
 
-	                phy = adapter->port[i].phy;
+			phy = adapter->port[i].phy;
 			phy_cause = phy->ops->interrupt_handler(phy);
 			if (phy_cause & cphy_cause_link_change)
 				t1_link_changed(adapter, i);
 		}
-                break;
-        }
+		break;
+	}
 	case CHBT_BOARD_CHT101:
 		if (cause & ELMER0_GP_BIT1) { /* Marvell 88E1111 interrupt */
 			phy = adapter->port[0].phy;
@@ -631,13 +631,13 @@
 		break;
 	case CHBT_BOARD_7500: {
 		int p;
-    		/*
+		/*
 		 * Elmer0's interrupt cause isn't useful here because there is
 		 * only one bit that can be set for all 4 ports.  This means
 		 * we are forced to check every PHY's interrupt status
 		 * register to see who initiated the interrupt.
-     		 */
-    		for_each_port(adapter, p) {
+		 */
+		for_each_port(adapter, p) {
 			phy = adapter->port[p].phy;
 			phy_cause = phy->ops->interrupt_handler(phy);
 			if (phy_cause & cphy_cause_link_change)
@@ -658,7 +658,7 @@
 		break;
 	case CHBT_BOARD_8000:
 	case CHBT_BOARD_CHT110:
-    		CH_DBG(adapter, INTR, "External interrupt cause 0x%x\n",
+		CH_DBG(adapter, INTR, "External interrupt cause 0x%x\n",
 		       cause);
 		if (cause & ELMER0_GP_BIT1) {        /* PMC3393 INTB */
 			struct cmac *mac = adapter->port[0].mac;
@@ -670,9 +670,9 @@
 
 			t1_tpi_read(adapter,
 					A_ELMER0_GPI_STAT, &mod_detect);
-	    		CH_MSG(adapter, INFO, LINK, "XPAK %s\n",
+			CH_MSG(adapter, INFO, LINK, "XPAK %s\n",
 			       mod_detect ? "removed" : "inserted");
-    		}
+		}
 		break;
 #ifdef CONFIG_CHELSIO_T1_COUGAR
 	case CHBT_BOARD_COUGAR:
@@ -688,7 +688,8 @@
 
 			for_each_port(adapter, i) {
 				port_bit = i ? i + 1 : 0;
-				if (!(cause & (1 << port_bit))) continue;
+				if (!(cause & (1 << port_bit)))
+					continue;
 
 				phy = adapter->port[i].phy;
 				phy_cause = phy->ops->interrupt_handler(phy);
@@ -755,7 +756,7 @@
 
 	/* Disable PCIX & external chip interrupts. */
 	if (t1_is_asic(adapter))
-	    	writel(0, adapter->regs + A_PL_ENABLE);
+		writel(0, adapter->regs + A_PL_ENABLE);
 
 	/* PCI-X interrupts */
 	pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE, 0);
@@ -830,11 +831,11 @@
 /* Power sequencing is a work-around for Intel's XPAKs. */
 static void power_sequence_xpak(adapter_t* adapter)
 {
-    	u32 mod_detect;
-    	u32 gpo;
+	u32 mod_detect;
+	u32 gpo;
 
-    	/* Check for XPAK */
-    	t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect);
+	/* Check for XPAK */
+	t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect);
 	if (!(ELMER0_GP_BIT5 & mod_detect)) {
 		/* XPAK is present */
 		t1_tpi_read(adapter, A_ELMER0_GPO, &gpo);
@@ -877,31 +878,31 @@
 	case CHBT_BOARD_N210:
 	case CHBT_BOARD_CHT210:
 	case CHBT_BOARD_COUGAR:
-    		t1_tpi_par(adapter, 0xf);
-    		t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);
+		t1_tpi_par(adapter, 0xf);
+		t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);
 		break;
 	case CHBT_BOARD_CHT110:
-    		t1_tpi_par(adapter, 0xf);
-    		t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800);
+		t1_tpi_par(adapter, 0xf);
+		t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800);
 
-    		/* TBD XXX Might not need.  This fixes a problem
-     		 *         described in the Intel SR XPAK errata.
-     		 */
-    		power_sequence_xpak(adapter);
+		/* TBD XXX Might not need.  This fixes a problem
+		 *         described in the Intel SR XPAK errata.
+		 */
+		power_sequence_xpak(adapter);
 		break;
 #ifdef CONFIG_CHELSIO_T1_1G
-    case CHBT_BOARD_CHT204E:
-		        /* add config space write here */
+	case CHBT_BOARD_CHT204E:
+		/* add config space write here */
 	case CHBT_BOARD_CHT204:
 	case CHBT_BOARD_CHT204V:
 	case CHBT_BOARD_CHN204:
-                t1_tpi_par(adapter, 0xf);
-                t1_tpi_write(adapter, A_ELMER0_GPO, 0x804);
-                break;
+		t1_tpi_par(adapter, 0xf);
+		t1_tpi_write(adapter, A_ELMER0_GPO, 0x804);
+		break;
 	case CHBT_BOARD_CHT101:
 	case CHBT_BOARD_7500:
-    		t1_tpi_par(adapter, 0xf);
-    		t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804);
+		t1_tpi_par(adapter, 0xf);
+		t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804);
 		break;
 #endif
 	}
@@ -941,7 +942,7 @@
 		goto out_err;
 
 	err = 0;
- out_err:
+out_err:
 	return err;
 }
 
@@ -983,7 +984,7 @@
 	if (adapter->espi)
 		t1_espi_destroy(adapter->espi);
 #ifdef CONFIG_CHELSIO_T1_COUGAR
-        if (adapter->cspi)
+	if (adapter->cspi)
 		t1_cspi_destroy(adapter->cspi);
 #endif
 }
@@ -1010,7 +1011,7 @@
 		CH_ERR("%s: CSPI initialization failed\n",
 		       adapter->name);
 		goto error;
-        }
+	}
 #endif
 
 /*
diff --git a/drivers/net/chelsio/tp.c b/drivers/net/chelsio/tp.c
index 0ca0b6e..6222d58 100644
--- a/drivers/net/chelsio/tp.c
+++ b/drivers/net/chelsio/tp.c
@@ -17,39 +17,36 @@
 static void tp_init(adapter_t * ap, const struct tp_params *p,
 		    unsigned int tp_clk)
 {
-	if (t1_is_asic(ap)) {
-		u32 val;
+	u32 val;
 
-		val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM |
-		    F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET;
-		if (!p->pm_size)
-			val |= F_OFFLOAD_DISABLE;
-		else
-			val |= F_TP_IN_ESPI_CHECK_IP_CSUM |
-			    F_TP_IN_ESPI_CHECK_TCP_CSUM;
-		writel(val, ap->regs + A_TP_IN_CONFIG);
-		writel(F_TP_OUT_CSPI_CPL |
-		       F_TP_OUT_ESPI_ETHERNET |
-		       F_TP_OUT_ESPI_GENERATE_IP_CSUM |
-		       F_TP_OUT_ESPI_GENERATE_TCP_CSUM,
-		       ap->regs + A_TP_OUT_CONFIG);
-		writel(V_IP_TTL(64) |
-		       F_PATH_MTU /* IP DF bit */  |
-		       V_5TUPLE_LOOKUP(p->use_5tuple_mode) |
-		       V_SYN_COOKIE_PARAMETER(29),
-		       ap->regs + A_TP_GLOBAL_CONFIG);
-		/*
-		 * Enable pause frame deadlock prevention.
-		 */
-		if (is_T2(ap) && ap->params.nports > 1) {
-			u32 drop_ticks = DROP_MSEC * (tp_clk / 1000);
+	if (!t1_is_asic(ap))
+		return;
 
-			writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR |
-			       V_DROP_TICKS_CNT(drop_ticks) |
-			       V_NUM_PKTS_DROPPED(DROP_PKTS_CNT),
-			       ap->regs + A_TP_TX_DROP_CONFIG);
-		}
+	val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM |
+		F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET;
+	if (!p->pm_size)
+		val |= F_OFFLOAD_DISABLE;
+	else
+		val |= F_TP_IN_ESPI_CHECK_IP_CSUM | F_TP_IN_ESPI_CHECK_TCP_CSUM;
+	writel(val, ap->regs + A_TP_IN_CONFIG);
+	writel(F_TP_OUT_CSPI_CPL |
+	       F_TP_OUT_ESPI_ETHERNET |
+	       F_TP_OUT_ESPI_GENERATE_IP_CSUM |
+	       F_TP_OUT_ESPI_GENERATE_TCP_CSUM, ap->regs + A_TP_OUT_CONFIG);
+	writel(V_IP_TTL(64) |
+	       F_PATH_MTU /* IP DF bit */  |
+	       V_5TUPLE_LOOKUP(p->use_5tuple_mode) |
+	       V_SYN_COOKIE_PARAMETER(29), ap->regs + A_TP_GLOBAL_CONFIG);
+	/*
+	 * Enable pause frame deadlock prevention.
+	 */
+	if (is_T2(ap) && ap->params.nports > 1) {
+		u32 drop_ticks = DROP_MSEC * (tp_clk / 1000);
 
+		writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR |
+		       V_DROP_TICKS_CNT(drop_ticks) |
+		       V_NUM_PKTS_DROPPED(DROP_PKTS_CNT),
+		       ap->regs + A_TP_TX_DROP_CONFIG);
 	}
 }
 
@@ -61,6 +58,7 @@
 struct petp *__devinit t1_tp_create(adapter_t * adapter, struct tp_params *p)
 {
 	struct petp *tp = kzalloc(sizeof(*tp), GFP_KERNEL);
+
 	if (!tp)
 		return NULL;
 
diff --git a/drivers/net/chelsio/vsc7326.c b/drivers/net/chelsio/vsc7326.c
index 85dc3b1..534ffa0 100644
--- a/drivers/net/chelsio/vsc7326.c
+++ b/drivers/net/chelsio/vsc7326.c
@@ -226,22 +226,21 @@
 		if (ib[i].addr == INITBLOCK_SLEEP) {
 			udelay( ib[i].data );
 			CH_ERR("sleep %d us\n",ib[i].data);
-		} else {
+		} else
 			vsc_write( adapter, ib[i].addr, ib[i].data );
-		}
 	}
 }
 
 static int bist_rd(adapter_t *adapter, int moduleid, int address)
 {
-	int data=0;
-	u32 result=0;
+	int data = 0;
+	u32 result = 0;
 
-	if(	(address != 0x0) &&
-		(address != 0x1) &&
-		(address != 0x2) &&
-		(address != 0xd) &&
-		(address != 0xe))
+	if ((address != 0x0) &&
+	    (address != 0x1) &&
+	    (address != 0x2) &&
+	    (address != 0xd) &&
+	    (address != 0xe))
 			CH_ERR("No bist address: 0x%x\n", address);
 
 	data = ((0x00 << 24) | ((address & 0xff) << 16) | (0x00 << 8) |
@@ -251,27 +250,27 @@
 	udelay(10);
 
 	vsc_read(adapter, REG_RAM_BIST_RESULT, &result);
-	if((result & (1<<9)) != 0x0)
+	if ((result & (1 << 9)) != 0x0)
 		CH_ERR("Still in bist read: 0x%x\n", result);
-	else if((result & (1<<8)) != 0x0)
+	else if ((result & (1 << 8)) != 0x0)
 		CH_ERR("bist read error: 0x%x\n", result);
 
-	return(result & 0xff);
+	return (result & 0xff);
 }
 
 static int bist_wr(adapter_t *adapter, int moduleid, int address, int value)
 {
-	int data=0;
-	u32 result=0;
+	int data = 0;
+	u32 result = 0;
 
-	if(	(address != 0x0) &&
-		(address != 0x1) &&
-		(address != 0x2) &&
-		(address != 0xd) &&
-		(address != 0xe))
+	if ((address != 0x0) &&
+	    (address != 0x1) &&
+	    (address != 0x2) &&
+	    (address != 0xd) &&
+	    (address != 0xe))
 			CH_ERR("No bist address: 0x%x\n", address);
 
-	if( value>255 )
+	if (value > 255)
 		CH_ERR("Suspicious write out of range value: 0x%x\n", value);
 
 	data = ((0x01 << 24) | ((address & 0xff) << 16) | (value << 8) |
@@ -281,12 +280,12 @@
 	udelay(5);
 
 	vsc_read(adapter, REG_RAM_BIST_CMD, &result);
-	if((result & (1<<27)) != 0x0)
+	if ((result & (1 << 27)) != 0x0)
 		CH_ERR("Still in bist write: 0x%x\n", result);
-	else if((result & (1<<26)) != 0x0)
+	else if ((result & (1 << 26)) != 0x0)
 		CH_ERR("bist write error: 0x%x\n", result);
 
-	return(0);
+	return 0;
 }
 
 static int run_bist(adapter_t *adapter, int moduleid)
@@ -295,7 +294,7 @@
 	(void) bist_wr(adapter,moduleid, 0x00, 0x02);
 	(void) bist_wr(adapter,moduleid, 0x01, 0x01);
 
-	return(0);
+	return 0;
 }
 
 static int check_bist(adapter_t *adapter, int moduleid)
@@ -309,27 +308,26 @@
 	if ((result & 3) != 0x3)
 		CH_ERR("Result: 0x%x  BIST error in ram %d, column: 0x%04x\n",
 			result, moduleid, column);
-	return(0);
+	return 0;
 }
 
 static int enable_mem(adapter_t *adapter, int moduleid)
 {
 	/*enable mem*/
 	(void) bist_wr(adapter,moduleid, 0x00, 0x00);
-	return(0);
+	return 0;
 }
 
 static int run_bist_all(adapter_t *adapter)
 {
-	int port=0;
-	u32 val=0;
+	int port = 0;
+	u32 val = 0;
 
 	vsc_write(adapter, REG_MEM_BIST, 0x5);
 	vsc_read(adapter, REG_MEM_BIST, &val);
 
-	for(port=0; port<12; port++){
+	for (port = 0; port < 12; port++)
 		vsc_write(adapter, REG_DEV_SETUP(port), 0x0);
-	}
 
 	udelay(300);
 	vsc_write(adapter, REG_SPI4_MISC, 0x00040409);
@@ -352,13 +350,13 @@
 	udelay(300);
 	vsc_write(adapter, REG_SPI4_MISC, 0x60040400);
 	udelay(300);
-	for(port=0; port<12; port++){
+	for (port = 0; port < 12; port++)
 		vsc_write(adapter, REG_DEV_SETUP(port), 0x1);
-	}
+
 	udelay(300);
 	vsc_write(adapter, REG_MEM_BIST, 0x0);
 	mdelay(10);
-	return(0);
+	return 0;
 }
 
 static int mac_intr_handler(struct cmac *mac)
@@ -591,40 +589,46 @@
 
 static void port_stats_update(struct cmac *mac)
 {
-	int port = mac->instance->index;
+	struct {
+		unsigned int reg;
+		unsigned int offset;
+	} hw_stats[] = {
 
-	/* Rx stats */
+#define HW_STAT(reg, stat_name) \
+	{ reg, (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
+
+		/* Rx stats */
+		HW_STAT(RxUnicast, RxUnicastFramesOK),
+		HW_STAT(RxMulticast, RxMulticastFramesOK),
+		HW_STAT(RxBroadcast, RxBroadcastFramesOK),
+		HW_STAT(Crc, RxFCSErrors),
+		HW_STAT(RxAlignment, RxAlignErrors),
+		HW_STAT(RxOversize, RxFrameTooLongErrors),
+		HW_STAT(RxPause, RxPauseFrames),
+		HW_STAT(RxJabbers, RxJabberErrors),
+		HW_STAT(RxFragments, RxRuntErrors),
+		HW_STAT(RxUndersize, RxRuntErrors),
+		HW_STAT(RxSymbolCarrier, RxSymbolErrors),
+		HW_STAT(RxSize1519ToMax, RxJumboFramesOK),
+
+		/* Tx stats (skip collision stats as we are full-duplex only) */
+		HW_STAT(TxUnicast, TxUnicastFramesOK),
+		HW_STAT(TxMulticast, TxMulticastFramesOK),
+		HW_STAT(TxBroadcast, TxBroadcastFramesOK),
+		HW_STAT(TxPause, TxPauseFrames),
+		HW_STAT(TxUnderrun, TxUnderrun),
+		HW_STAT(TxSize1519ToMax, TxJumboFramesOK),
+	}, *p = hw_stats;
+	unsigned int port = mac->instance->index;
+	u64 *stats = (u64 *)&mac->stats;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(hw_stats); i++)
+		rmon_update(mac, CRA(0x4, port, p->reg), stats + p->offset);
+
+	rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK);
 	rmon_update(mac, REG_RX_OK_BYTES(port), &mac->stats.RxOctetsOK);
 	rmon_update(mac, REG_RX_BAD_BYTES(port), &mac->stats.RxOctetsBad);
-	rmon_update(mac, REG_RX_UNICAST(port), &mac->stats.RxUnicastFramesOK);
-	rmon_update(mac, REG_RX_MULTICAST(port),
-		    &mac->stats.RxMulticastFramesOK);
-	rmon_update(mac, REG_RX_BROADCAST(port),
-		    &mac->stats.RxBroadcastFramesOK);
-	rmon_update(mac, REG_CRC(port), &mac->stats.RxFCSErrors);
-	rmon_update(mac, REG_RX_ALIGNMENT(port), &mac->stats.RxAlignErrors);
-	rmon_update(mac, REG_RX_OVERSIZE(port),
-		    &mac->stats.RxFrameTooLongErrors);
-	rmon_update(mac, REG_RX_PAUSE(port), &mac->stats.RxPauseFrames);
-	rmon_update(mac, REG_RX_JABBERS(port), &mac->stats.RxJabberErrors);
-	rmon_update(mac, REG_RX_FRAGMENTS(port), &mac->stats.RxRuntErrors);
-	rmon_update(mac, REG_RX_UNDERSIZE(port), &mac->stats.RxRuntErrors);
-	rmon_update(mac, REG_RX_SYMBOL_CARRIER(port),
-		    &mac->stats.RxSymbolErrors);
-	rmon_update(mac, REG_RX_SIZE_1519_TO_MAX(port),
-            &mac->stats.RxJumboFramesOK);
-
-	/* Tx stats (skip collision stats as we are full-duplex only) */
-	rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK);
-	rmon_update(mac, REG_TX_UNICAST(port), &mac->stats.TxUnicastFramesOK);
-	rmon_update(mac, REG_TX_MULTICAST(port),
-		    &mac->stats.TxMulticastFramesOK);
-	rmon_update(mac, REG_TX_BROADCAST(port),
-		    &mac->stats.TxBroadcastFramesOK);
-	rmon_update(mac, REG_TX_PAUSE(port), &mac->stats.TxPauseFrames);
-	rmon_update(mac, REG_TX_UNDERRUN(port), &mac->stats.TxUnderrun);
-	rmon_update(mac, REG_TX_SIZE_1519_TO_MAX(port),
-            &mac->stats.TxJumboFramesOK);
 }
 
 /*
@@ -686,7 +690,8 @@
 	int i;
 
 	mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
-	if (!mac) return NULL;
+	if (!mac)
+		return NULL;
 
 	mac->ops = &vsc7326_ops;
 	mac->instance = (cmac_instance *)(mac + 1);
diff --git a/drivers/net/chelsio/vsc7326_reg.h b/drivers/net/chelsio/vsc7326_reg.h
index 491bcf7..479edbc 100644
--- a/drivers/net/chelsio/vsc7326_reg.h
+++ b/drivers/net/chelsio/vsc7326_reg.h
@@ -192,73 +192,84 @@
 #define REG_HDX(pn)		CRA(0x1,pn,0x19)	/* Half-duplex config */
 
 /* Statistics */
+/* CRA(0x4,pn,reg) */
+/* reg below */
 /* pn = port number, 0-a, a = 10GbE */
-#define REG_RX_IN_BYTES(pn)	CRA(0x4,pn,0x00)	/* # Rx in octets */
-#define REG_RX_SYMBOL_CARRIER(pn) CRA(0x4,pn,0x01)	/* Frames w/ symbol errors */
-#define REG_RX_PAUSE(pn)	CRA(0x4,pn,0x02)	/* # pause frames received */
-#define REG_RX_UNSUP_OPCODE(pn)	CRA(0x4,pn,0x03)	/* # control frames with unsupported opcode */
-#define REG_RX_OK_BYTES(pn)	CRA(0x4,pn,0x04)	/* # octets in good frames */
-#define REG_RX_BAD_BYTES(pn)	CRA(0x4,pn,0x05)	/* # octets in bad frames */
-#define REG_RX_UNICAST(pn)	CRA(0x4,pn,0x06)	/* # good unicast frames */
-#define REG_RX_MULTICAST(pn)	CRA(0x4,pn,0x07)	/* # good multicast frames */
-#define REG_RX_BROADCAST(pn)	CRA(0x4,pn,0x08)	/* # good broadcast frames */
-#define REG_CRC(pn)		CRA(0x4,pn,0x09)	/* # frames w/ bad CRC only */
-#define REG_RX_ALIGNMENT(pn)	CRA(0x4,pn,0x0a)	/* # frames w/ alignment err */
-#define REG_RX_UNDERSIZE(pn)	CRA(0x4,pn,0x0b)	/* # frames undersize */
-#define REG_RX_FRAGMENTS(pn)	CRA(0x4,pn,0x0c)	/* # frames undersize w/ crc err */
-#define REG_RX_IN_RANGE_LENGTH_ERROR(pn) CRA(0x4,pn,0x0d)	/* # frames with length error */
-#define REG_RX_OUT_OF_RANGE_ERROR(pn) CRA(0x4,pn,0x0e)	/* # frames with illegal length field */
-#define REG_RX_OVERSIZE(pn)	CRA(0x4,pn,0x0f)	/* # frames oversize */
-#define REG_RX_JABBERS(pn)	CRA(0x4,pn,0x10)	/* # frames oversize w/ crc err */
-#define REG_RX_SIZE_64(pn)	CRA(0x4,pn,0x11)	/* # frames 64 octets long */
-#define REG_RX_SIZE_65_TO_127(pn) CRA(0x4,pn,0x12)	/* # frames 65-127 octets */
-#define REG_RX_SIZE_128_TO_255(pn) CRA(0x4,pn,0x13)	/* # frames 128-255 */
-#define REG_RX_SIZE_256_TO_511(pn) CRA(0x4,pn,0x14)	/* # frames 256-511 */
-#define REG_RX_SIZE_512_TO_1023(pn) CRA(0x4,pn,0x15)	/* # frames 512-1023 */
-#define REG_RX_SIZE_1024_TO_1518(pn) CRA(0x4,pn,0x16)	/* # frames 1024-1518 */
-#define REG_RX_SIZE_1519_TO_MAX(pn) CRA(0x4,pn,0x17)	/* # frames 1519-max */
 
-#define REG_TX_OUT_BYTES(pn)	CRA(0x4,pn,0x18)	/* # octets tx */
-#define REG_TX_PAUSE(pn)	CRA(0x4,pn,0x19)	/* # pause frames sent */
-#define REG_TX_OK_BYTES(pn)	CRA(0x4,pn,0x1a)	/* # octets tx OK */
-#define REG_TX_UNICAST(pn)	CRA(0x4,pn,0x1b)	/* # frames unicast */
-#define REG_TX_MULTICAST(pn)	CRA(0x4,pn,0x1c)	/* # frames multicast */
-#define REG_TX_BROADCAST(pn)	CRA(0x4,pn,0x1d)	/* # frames broadcast */
-#define REG_TX_MULTIPLE_COLL(pn) CRA(0x4,pn,0x1e)	/* # frames tx after multiple collisions */
-#define REG_TX_LATE_COLL(pn)	CRA(0x4,pn,0x1f)	/* # late collisions detected */
-#define REG_TX_XCOLL(pn)	CRA(0x4,pn,0x20)	/* # frames lost, excessive collisions */
-#define REG_TX_DEFER(pn)	CRA(0x4,pn,0x21)	/* # frames deferred on first tx attempt */
-#define REG_TX_XDEFER(pn)	CRA(0x4,pn,0x22)	/* # frames excessively deferred */
-#define REG_TX_CSENSE(pn)	CRA(0x4,pn,0x23)	/* carrier sense errors at frame end */
-#define REG_TX_SIZE_64(pn)	CRA(0x4,pn,0x24)	/* # frames 64 octets long */
-#define REG_TX_SIZE_65_TO_127(pn) CRA(0x4,pn,0x25)	/* # frames 65-127 octets */
-#define REG_TX_SIZE_128_TO_255(pn) CRA(0x4,pn,0x26)	/* # frames 128-255 */
-#define REG_TX_SIZE_256_TO_511(pn) CRA(0x4,pn,0x27)	/* # frames 256-511 */
-#define REG_TX_SIZE_512_TO_1023(pn) CRA(0x4,pn,0x28)	/* # frames 512-1023 */
-#define REG_TX_SIZE_1024_TO_1518(pn) CRA(0x4,pn,0x29)	/* # frames 1024-1518 */
-#define REG_TX_SIZE_1519_TO_MAX(pn) CRA(0x4,pn,0x2a)	/* # frames 1519-max */
-#define REG_TX_SINGLE_COLL(pn)	CRA(0x4,pn,0x2b)	/* # frames tx after single collision */
-#define REG_TX_BACKOFF2(pn)	CRA(0x4,pn,0x2c)	/* # frames tx ok after 2 backoffs/collisions */
-#define REG_TX_BACKOFF3(pn)	CRA(0x4,pn,0x2d)	/*   after 3 backoffs/collisions */
-#define REG_TX_BACKOFF4(pn)	CRA(0x4,pn,0x2e)	/*   after 4 */
-#define REG_TX_BACKOFF5(pn)	CRA(0x4,pn,0x2f)	/*   after 5 */
-#define REG_TX_BACKOFF6(pn)	CRA(0x4,pn,0x30)	/*   after 6 */
-#define REG_TX_BACKOFF7(pn)	CRA(0x4,pn,0x31)	/*   after 7 */
-#define REG_TX_BACKOFF8(pn)	CRA(0x4,pn,0x32)	/*   after 8 */
-#define REG_TX_BACKOFF9(pn)	CRA(0x4,pn,0x33)	/*   after 9 */
-#define REG_TX_BACKOFF10(pn)	CRA(0x4,pn,0x34)	/*   after 10 */
-#define REG_TX_BACKOFF11(pn)	CRA(0x4,pn,0x35)	/*   after 11 */
-#define REG_TX_BACKOFF12(pn)	CRA(0x4,pn,0x36)	/*   after 12 */
-#define REG_TX_BACKOFF13(pn)	CRA(0x4,pn,0x37)	/*   after 13 */
-#define REG_TX_BACKOFF14(pn)	CRA(0x4,pn,0x38)	/*   after 14 */
-#define REG_TX_BACKOFF15(pn)	CRA(0x4,pn,0x39)	/*   after 15 */
-#define REG_TX_UNDERRUN(pn)	CRA(0x4,pn,0x3a)	/* # frames dropped from underrun */
-#define REG_RX_XGMII_PROT_ERR	CRA(0x4,0xa,0x3b)	/* # protocol errors detected on XGMII interface */
-#define REG_RX_IPG_SHRINK(pn)	CRA(0x4,pn,0x3c)	/* # of IPG shrinks detected */
+enum {
+	RxInBytes		= 0x00,	// # Rx in octets
+	RxSymbolCarrier		= 0x01,	// Frames w/ symbol errors
+	RxPause			= 0x02,	// # pause frames received
+	RxUnsupOpcode		= 0x03,	// # control frames with unsupported opcode
+	RxOkBytes		= 0x04,	// # octets in good frames
+	RxBadBytes		= 0x05,	// # octets in bad frames
+	RxUnicast		= 0x06,	// # good unicast frames
+	RxMulticast		= 0x07,	// # good multicast frames
+	RxBroadcast		= 0x08,	// # good broadcast frames
+	Crc			= 0x09,	// # frames w/ bad CRC only
+	RxAlignment		= 0x0a,	// # frames w/ alignment err
+	RxUndersize		= 0x0b,	// # frames undersize
+	RxFragments		= 0x0c,	// # frames undersize w/ crc err
+	RxInRangeLengthError	= 0x0d,	// # frames with length error
+	RxOutOfRangeError	= 0x0e,	// # frames with illegal length field
+	RxOversize		= 0x0f,	// # frames oversize
+	RxJabbers		= 0x10,	// # frames oversize w/ crc err
+	RxSize64		= 0x11,	// # frames 64 octets long
+	RxSize65To127		= 0x12,	// # frames 65-127 octets
+	RxSize128To255		= 0x13,	// # frames 128-255
+	RxSize256To511		= 0x14,	// # frames 256-511
+	RxSize512To1023		= 0x15,	// # frames 512-1023
+	RxSize1024To1518	= 0x16,	// # frames 1024-1518
+	RxSize1519ToMax		= 0x17,	// # frames 1519-max
 
-#define REG_STAT_STICKY1G(pn)	CRA(0x4,pn,0x3e)	/* tri-speed sticky bits */
-#define REG_STAT_STICKY10G	CRA(0x4,0xa,0x3e)	/* 10GbE sticky bits */
-#define REG_STAT_INIT(pn)	CRA(0x4,pn,0x3f)	/* Clear all statistics */
+	TxOutBytes		= 0x18,	// # octets tx
+	TxPause			= 0x19,	// # pause frames sent
+	TxOkBytes		= 0x1a, // # octets tx OK
+	TxUnicast		= 0x1b,	// # frames unicast
+	TxMulticast		= 0x1c,	// # frames multicast
+	TxBroadcast		= 0x1d,	// # frames broadcast
+	TxMultipleColl		= 0x1e,	// # frames tx after multiple collisions
+	TxLateColl		= 0x1f,	// # late collisions detected
+	TxXcoll			= 0x20,	// # frames lost, excessive collisions
+	TxDefer			= 0x21,	// # frames deferred on first tx attempt
+	TxXdefer		= 0x22,	// # frames excessively deferred
+	TxCsense		= 0x23,	// carrier sense errors at frame end
+	TxSize64		= 0x24,	// # frames 64 octets long
+	TxSize65To127		= 0x25,	// # frames 65-127 octets
+	TxSize128To255		= 0x26,	// # frames 128-255
+	TxSize256To511		= 0x27,	// # frames 256-511
+	TxSize512To1023		= 0x28,	// # frames 512-1023
+	TxSize1024To1518	= 0x29,	// # frames 1024-1518
+	TxSize1519ToMax		= 0x2a,	// # frames 1519-max
+	TxSingleColl		= 0x2b,	// # frames tx after single collision
+	TxBackoff2		= 0x2c,	// # frames tx ok after 2 backoffs/collisions
+	TxBackoff3		= 0x2d,	//   after 3 backoffs/collisions
+	TxBackoff4		= 0x2e,	//   after 4
+	TxBackoff5		= 0x2f,	//   after 5
+	TxBackoff6		= 0x30,	//   after 6
+	TxBackoff7		= 0x31,	//   after 7
+	TxBackoff8		= 0x32,	//   after 8
+	TxBackoff9		= 0x33,	//   after 9
+	TxBackoff10		= 0x34,	//   after 10
+	TxBackoff11		= 0x35,	//   after 11
+	TxBackoff12		= 0x36,	//   after 12
+	TxBackoff13		= 0x37,	//   after 13
+	TxBackoff14		= 0x38,	//   after 14
+	TxBackoff15		= 0x39,	//   after 15
+	TxUnderrun		= 0x3a,	// # frames dropped from underrun
+	// Hole. See REG_RX_XGMII_PROT_ERR below.
+	RxIpgShrink		= 0x3c,	// # of IPG shrinks detected
+	// Duplicate. See REG_STAT_STICKY10G below.
+	StatSticky1G		= 0x3e,	// tri-speed sticky bits
+	StatInit		= 0x3f	// Clear all statistics
+};
+
+#define REG_RX_XGMII_PROT_ERR	CRA(0x4,0xa,0x3b)		/* # protocol errors detected on XGMII interface */
+#define REG_STAT_STICKY10G	CRA(0x4,0xa,StatSticky1G)	/* 10GbE sticky bits */
+
+#define REG_RX_OK_BYTES(pn)	CRA(0x4,pn,RxOkBytes)
+#define REG_RX_BAD_BYTES(pn)	CRA(0x4,pn,RxBadBytes)
+#define REG_TX_OK_BYTES(pn)	CRA(0x4,pn,TxOkBytes)
 
 /* MII-Management Block registers */
 /* These are for MII-M interface 0, which is the bidirectional LVTTL one.  If
diff --git a/drivers/net/chelsio/vsc8244.c b/drivers/net/chelsio/vsc8244.c
index c493e78..251d485 100644
--- a/drivers/net/chelsio/vsc8244.c
+++ b/drivers/net/chelsio/vsc8244.c
@@ -54,7 +54,7 @@
 };
 
 #define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
-	 		   VSC_INTR_NEG_DONE)
+			   VSC_INTR_NEG_DONE)
 #define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
 		   VSC_INTR_ENABLE)
 
@@ -94,19 +94,18 @@
 {
 	simple_mdio_write(cphy, VSC8244_INTR_ENABLE, INTR_MASK);
 
-    /* Enable interrupts through Elmer */
+	/* Enable interrupts through Elmer */
 	if (t1_is_asic(cphy->adapter)) {
 		u32 elmer;
 
 		t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
 		elmer |= ELMER0_GP_BIT1;
-		if (is_T2(cphy->adapter)) {
+		if (is_T2(cphy->adapter))
 		    elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
-                }
 		t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
 	}
 
-    return 0;
+	return 0;
 }
 
 static int vsc8244_intr_disable(struct cphy *cphy)
@@ -118,19 +117,18 @@
 
 		t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
 		elmer &= ~ELMER0_GP_BIT1;
-		if (is_T2(cphy->adapter)) {
+		if (is_T2(cphy->adapter))
 		    elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
-                }
 		t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
 	}
 
-    return 0;
+	return 0;
 }
 
 static int vsc8244_intr_clear(struct cphy *cphy)
 {
 	u32 val;
-    u32 elmer;
+	u32 elmer;
 
 	/* Clear PHY interrupts by reading the register. */
 	simple_mdio_read(cphy, VSC8244_INTR_ENABLE, &val);
@@ -138,13 +136,12 @@
 	if (t1_is_asic(cphy->adapter)) {
 		t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
 		elmer |= ELMER0_GP_BIT1;
-		if (is_T2(cphy->adapter)) {
+		if (is_T2(cphy->adapter))
 		    elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
-                }
 		t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
 	}
 
-    return 0;
+	return 0;
 }
 
 /*
@@ -179,13 +176,13 @@
 
 int t1_mdio_set_bits(struct cphy *phy, int mmd, int reg, unsigned int bits)
 {
-    int ret;
-    unsigned int val;
+	int ret;
+	unsigned int val;
 
-    ret = mdio_read(phy, mmd, reg, &val);
-    if (!ret)
-        ret = mdio_write(phy, mmd, reg, val | bits);
-    return ret;
+	ret = mdio_read(phy, mmd, reg, &val);
+	if (!ret)
+		ret = mdio_write(phy, mmd, reg, val | bits);
+	return ret;
 }
 
 static int vsc8244_autoneg_enable(struct cphy *cphy)
@@ -235,7 +232,7 @@
 }
 
 static int vsc8244_get_link_status(struct cphy *cphy, int *link_ok,
-				     int *speed, int *duplex, int *fc)
+				   int *speed, int *duplex, int *fc)
 {
 	unsigned int bmcr, status, lpa, adv;
 	int err, sp = -1, dplx = -1, pause = 0;
@@ -343,11 +340,13 @@
 	.get_link_status      = vsc8244_get_link_status
 };
 
-static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr, struct mdio_ops *mdio_ops)
+static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr,
+				       struct mdio_ops *mdio_ops)
 {
 	struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
 
-	if (!cphy) return NULL;
+	if (!cphy)
+		return NULL;
 
 	cphy_init(cphy, adapter, phy_addr, &vsc8244_ops, mdio_ops);
 
diff --git a/drivers/net/cxgb3/Makefile b/drivers/net/cxgb3/Makefile
new file mode 100644
index 0000000..3434679
--- /dev/null
+++ b/drivers/net/cxgb3/Makefile
@@ -0,0 +1,8 @@
+#
+# Chelsio T3 driver
+#
+
+obj-$(CONFIG_CHELSIO_T3) += cxgb3.o
+
+cxgb3-objs := cxgb3_main.o ael1002.o vsc8211.o t3_hw.o mc5.o \
+	      xgmac.o sge.o l2t.o cxgb3_offload.o
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
new file mode 100644
index 0000000..5c97a64
--- /dev/null
+++ b/drivers/net/cxgb3/adapter.h
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* This file should not be included directly.  Include common.h instead. */
+
+#ifndef __T3_ADAPTER_H__
+#define __T3_ADAPTER_H__
+
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/cache.h>
+#include <linux/mutex.h>
+#include "t3cdev.h"
+#include <asm/semaphore.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+typedef irqreturn_t(*intr_handler_t) (int, void *);
+
+struct vlan_group;
+
+struct port_info {
+	struct vlan_group *vlan_grp;
+	const struct port_type_info *port_type;
+	u8 port_id;
+	u8 rx_csum_offload;
+	u8 nqsets;
+	u8 first_qset;
+	struct cphy phy;
+	struct cmac mac;
+	struct link_config link_config;
+	struct net_device_stats netstats;
+	int activity;
+};
+
+enum {				/* adapter flags */
+	FULL_INIT_DONE = (1 << 0),
+	USING_MSI = (1 << 1),
+	USING_MSIX = (1 << 2),
+	QUEUES_BOUND = (1 << 3),
+};
+
+struct rx_desc;
+struct rx_sw_desc;
+
+struct sge_fl {			/* SGE per free-buffer list state */
+	unsigned int buf_size;	/* size of each Rx buffer */
+	unsigned int credits;	/* # of available Rx buffers */
+	unsigned int size;	/* capacity of free list */
+	unsigned int cidx;	/* consumer index */
+	unsigned int pidx;	/* producer index */
+	unsigned int gen;	/* free list generation */
+	struct rx_desc *desc;	/* address of HW Rx descriptor ring */
+	struct rx_sw_desc *sdesc;	/* address of SW Rx descriptor ring */
+	dma_addr_t phys_addr;	/* physical address of HW ring start */
+	unsigned int cntxt_id;	/* SGE context id for the free list */
+	unsigned long empty;	/* # of times queue ran out of buffers */
+};
+
+/*
+ * Bundle size for grouping offload RX packets for delivery to the stack.
+ * Don't make this too big as we do prefetch on each packet in a bundle.
+ */
+# define RX_BUNDLE_SIZE 8
+
+struct rsp_desc;
+
+struct sge_rspq {		/* state for an SGE response queue */
+	unsigned int credits;	/* # of pending response credits */
+	unsigned int size;	/* capacity of response queue */
+	unsigned int cidx;	/* consumer index */
+	unsigned int gen;	/* current generation bit */
+	unsigned int polling;	/* is the queue serviced through NAPI? */
+	unsigned int holdoff_tmr;	/* interrupt holdoff timer in 100ns */
+	unsigned int next_holdoff;	/* holdoff time for next interrupt */
+	struct rsp_desc *desc;	/* address of HW response ring */
+	dma_addr_t phys_addr;	/* physical address of the ring */
+	unsigned int cntxt_id;	/* SGE context id for the response q */
+	spinlock_t lock;	/* guards response processing */
+	struct sk_buff *rx_head;	/* offload packet receive queue head */
+	struct sk_buff *rx_tail;	/* offload packet receive queue tail */
+
+	unsigned long offload_pkts;
+	unsigned long offload_bundles;
+	unsigned long eth_pkts;	/* # of ethernet packets */
+	unsigned long pure_rsps;	/* # of pure (non-data) responses */
+	unsigned long imm_data;	/* responses with immediate data */
+	unsigned long rx_drops;	/* # of packets dropped due to no mem */
+	unsigned long async_notif; /* # of asynchronous notification events */
+	unsigned long empty;	/* # of times queue ran out of credits */
+	unsigned long nomem;	/* # of responses deferred due to no mem */
+	unsigned long unhandled_irqs;	/* # of spurious intrs */
+};
+
+struct tx_desc;
+struct tx_sw_desc;
+
+struct sge_txq {		/* state for an SGE Tx queue */
+	unsigned long flags;	/* HW DMA fetch status */
+	unsigned int in_use;	/* # of in-use Tx descriptors */
+	unsigned int size;	/* # of descriptors */
+	unsigned int processed;	/* total # of descs HW has processed */
+	unsigned int cleaned;	/* total # of descs SW has reclaimed */
+	unsigned int stop_thres;	/* SW TX queue suspend threshold */
+	unsigned int cidx;	/* consumer index */
+	unsigned int pidx;	/* producer index */
+	unsigned int gen;	/* current value of generation bit */
+	unsigned int unacked;	/* Tx descriptors used since last COMPL */
+	struct tx_desc *desc;	/* address of HW Tx descriptor ring */
+	struct tx_sw_desc *sdesc;	/* address of SW Tx descriptor ring */
+	spinlock_t lock;	/* guards enqueueing of new packets */
+	unsigned int token;	/* WR token */
+	dma_addr_t phys_addr;	/* physical address of the ring */
+	struct sk_buff_head sendq;	/* List of backpressured offload packets */
+	struct tasklet_struct qresume_tsk;	/* restarts the queue */
+	unsigned int cntxt_id;	/* SGE context id for the Tx q */
+	unsigned long stops;	/* # of times q has been stopped */
+	unsigned long restarts;	/* # of queue restarts */
+};
+
+enum {				/* per port SGE statistics */
+	SGE_PSTAT_TSO,		/* # of TSO requests */
+	SGE_PSTAT_RX_CSUM_GOOD,	/* # of successful RX csum offloads */
+	SGE_PSTAT_TX_CSUM,	/* # of TX checksum offloads */
+	SGE_PSTAT_VLANEX,	/* # of VLAN tag extractions */
+	SGE_PSTAT_VLANINS,	/* # of VLAN tag insertions */
+
+	SGE_PSTAT_MAX		/* must be last */
+};
+
+struct sge_qset {		/* an SGE queue set */
+	struct sge_rspq rspq;
+	struct sge_fl fl[SGE_RXQ_PER_SET];
+	struct sge_txq txq[SGE_TXQ_PER_SET];
+	struct net_device *netdev;	/* associated net device */
+	unsigned long txq_stopped;	/* which Tx queues are stopped */
+	struct timer_list tx_reclaim_timer;	/* reclaims TX buffers */
+	unsigned long port_stats[SGE_PSTAT_MAX];
+} ____cacheline_aligned;
+
+struct sge {
+	struct sge_qset qs[SGE_QSETS];
+	spinlock_t reg_lock;	/* guards non-atomic SGE registers (eg context) */
+};
+
+struct adapter {
+	struct t3cdev tdev;
+	struct list_head adapter_list;
+	void __iomem *regs;
+	struct pci_dev *pdev;
+	unsigned long registered_device_map;
+	unsigned long open_device_map;
+	unsigned long flags;
+
+	const char *name;
+	int msg_enable;
+	unsigned int mmio_len;
+
+	struct adapter_params params;
+	unsigned int slow_intr_mask;
+	unsigned long irq_stats[IRQ_NUM_STATS];
+
+	struct {
+		unsigned short vec;
+		char desc[22];
+	} msix_info[SGE_QSETS + 1];
+
+	/* T3 modules */
+	struct sge sge;
+	struct mc7 pmrx;
+	struct mc7 pmtx;
+	struct mc7 cm;
+	struct mc5 mc5;
+
+	struct net_device *port[MAX_NPORTS];
+	unsigned int check_task_cnt;
+	struct delayed_work adap_check_task;
+	struct work_struct ext_intr_handler_task;
+
+	/*
+	 * Dummy netdevices are needed when using multiple receive queues with
+	 * NAPI as each netdevice can service only one queue.
+	 */
+	struct net_device *dummy_netdev[SGE_QSETS - 1];
+
+	struct dentry *debugfs_root;
+
+	struct mutex mdio_lock;
+	spinlock_t stats_lock;
+	spinlock_t work_lock;
+};
+
+static inline u32 t3_read_reg(struct adapter *adapter, u32 reg_addr)
+{
+	u32 val = readl(adapter->regs + reg_addr);
+
+	CH_DBG(adapter, MMIO, "read register 0x%x value 0x%x\n", reg_addr, val);
+	return val;
+}
+
+static inline void t3_write_reg(struct adapter *adapter, u32 reg_addr, u32 val)
+{
+	CH_DBG(adapter, MMIO, "setting register 0x%x to 0x%x\n", reg_addr, val);
+	writel(val, adapter->regs + reg_addr);
+}
+
+static inline struct port_info *adap2pinfo(struct adapter *adap, int idx)
+{
+	return netdev_priv(adap->port[idx]);
+}
+
+/*
+ * We use the spare atalk_ptr to map a net device to its SGE queue set.
+ * This is a macro so it can be used as l-value.
+ */
+#define dev2qset(netdev) ((netdev)->atalk_ptr)
+
+#define OFFLOAD_DEVMAP_BIT 15
+
+#define tdev2adap(d) container_of(d, struct adapter, tdev)
+
+static inline int offload_running(struct adapter *adapter)
+{
+	return test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
+}
+
+int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb);
+
+void t3_os_ext_intr_handler(struct adapter *adapter);
+void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status,
+			int speed, int duplex, int fc);
+
+void t3_sge_start(struct adapter *adap);
+void t3_sge_stop(struct adapter *adap);
+void t3_free_sge_resources(struct adapter *adap);
+void t3_sge_err_intr_handler(struct adapter *adapter);
+intr_handler_t t3_intr_handler(struct adapter *adap, int polling);
+int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev);
+int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb);
+void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p);
+int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
+		      int irq_vec_idx, const struct qset_params *p,
+		      int ntxq, struct net_device *netdev);
+int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
+		unsigned char *data);
+irqreturn_t t3_sge_intr_msix(int irq, void *cookie);
+
+#endif				/* __T3_ADAPTER_H__ */
diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c
new file mode 100644
index 0000000..73a41e6
--- /dev/null
+++ b/drivers/net/cxgb3/ael1002.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+
+enum {
+	AEL100X_TX_DISABLE = 9,
+	AEL100X_TX_CONFIG1 = 0xc002,
+	AEL1002_PWR_DOWN_HI = 0xc011,
+	AEL1002_PWR_DOWN_LO = 0xc012,
+	AEL1002_XFI_EQL = 0xc015,
+	AEL1002_LB_EN = 0xc017,
+
+	LASI_CTRL = 0x9002,
+	LASI_STAT = 0x9005
+};
+
+static void ael100x_txon(struct cphy *phy)
+{
+	int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
+
+	msleep(100);
+	t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
+	msleep(30);
+}
+
+static int ael1002_power_down(struct cphy *phy, int enable)
+{
+	int err;
+
+	err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable);
+	if (!err)
+		err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
+					  BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
+	return err;
+}
+
+static int ael1002_reset(struct cphy *phy, int wait)
+{
+	int err;
+
+	if ((err = ael1002_power_down(phy, 0)) ||
+	    (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) ||
+	    (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) ||
+	    (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) ||
+	    (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) ||
+	    (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN,
+				       0, 1 << 5)))
+		return err;
+	return 0;
+}
+
+static int ael1002_intr_noop(struct cphy *phy)
+{
+	return 0;
+}
+
+static int ael100x_get_link_status(struct cphy *phy, int *link_ok,
+				   int *speed, int *duplex, int *fc)
+{
+	if (link_ok) {
+		unsigned int status;
+		int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status);
+
+		/*
+		 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
+		 * once more to get the current link state.
+		 */
+		if (!err && !(status & BMSR_LSTATUS))
+			err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR,
+					&status);
+		if (err)
+			return err;
+		*link_ok = !!(status & BMSR_LSTATUS);
+	}
+	if (speed)
+		*speed = SPEED_10000;
+	if (duplex)
+		*duplex = DUPLEX_FULL;
+	return 0;
+}
+
+static struct cphy_ops ael1002_ops = {
+	.reset = ael1002_reset,
+	.intr_enable = ael1002_intr_noop,
+	.intr_disable = ael1002_intr_noop,
+	.intr_clear = ael1002_intr_noop,
+	.intr_handler = ael1002_intr_noop,
+	.get_link_status = ael100x_get_link_status,
+	.power_down = ael1002_power_down,
+};
+
+void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
+			 int phy_addr, const struct mdio_ops *mdio_ops)
+{
+	cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops);
+	ael100x_txon(phy);
+}
+
+static int ael1006_reset(struct cphy *phy, int wait)
+{
+	return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
+}
+
+static int ael1006_intr_enable(struct cphy *phy)
+{
+	return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
+}
+
+static int ael1006_intr_disable(struct cphy *phy)
+{
+	return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
+}
+
+static int ael1006_intr_clear(struct cphy *phy)
+{
+	u32 val;
+
+	return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
+}
+
+static int ael1006_intr_handler(struct cphy *phy)
+{
+	unsigned int status;
+	int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
+
+	if (err)
+		return err;
+	return (status & 1) ? cphy_cause_link_change : 0;
+}
+
+static int ael1006_power_down(struct cphy *phy, int enable)
+{
+	return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
+				   BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
+}
+
+static struct cphy_ops ael1006_ops = {
+	.reset = ael1006_reset,
+	.intr_enable = ael1006_intr_enable,
+	.intr_disable = ael1006_intr_disable,
+	.intr_clear = ael1006_intr_clear,
+	.intr_handler = ael1006_intr_handler,
+	.get_link_status = ael100x_get_link_status,
+	.power_down = ael1006_power_down,
+};
+
+void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
+			 int phy_addr, const struct mdio_ops *mdio_ops)
+{
+	cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops);
+	ael100x_txon(phy);
+}
+
+static struct cphy_ops qt2045_ops = {
+	.reset = ael1006_reset,
+	.intr_enable = ael1006_intr_enable,
+	.intr_disable = ael1006_intr_disable,
+	.intr_clear = ael1006_intr_clear,
+	.intr_handler = ael1006_intr_handler,
+	.get_link_status = ael100x_get_link_status,
+	.power_down = ael1006_power_down,
+};
+
+void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter,
+			int phy_addr, const struct mdio_ops *mdio_ops)
+{
+	unsigned int stat;
+
+	cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops);
+
+	/*
+	 * Some cards where the PHY is supposed to be at address 0 actually
+	 * have it at 1.
+	 */
+	if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) &&
+	    stat == 0xffff)
+		phy->addr = 1;
+}
+
+static int xaui_direct_reset(struct cphy *phy, int wait)
+{
+	return 0;
+}
+
+static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
+				       int *speed, int *duplex, int *fc)
+{
+	if (link_ok) {
+		unsigned int status;
+
+		status = t3_read_reg(phy->adapter,
+				     XGM_REG(A_XGM_SERDES_STAT0, phy->addr));
+		*link_ok = !(status & F_LOWSIG0);
+	}
+	if (speed)
+		*speed = SPEED_10000;
+	if (duplex)
+		*duplex = DUPLEX_FULL;
+	return 0;
+}
+
+static int xaui_direct_power_down(struct cphy *phy, int enable)
+{
+	return 0;
+}
+
+static struct cphy_ops xaui_direct_ops = {
+	.reset = xaui_direct_reset,
+	.intr_enable = ael1002_intr_noop,
+	.intr_disable = ael1002_intr_noop,
+	.intr_clear = ael1002_intr_noop,
+	.intr_handler = ael1002_intr_noop,
+	.get_link_status = xaui_direct_get_link_status,
+	.power_down = xaui_direct_power_down,
+};
+
+void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
+			     int phy_addr, const struct mdio_ops *mdio_ops)
+{
+	cphy_init(phy, adapter, 1, &xaui_direct_ops, mdio_ops);
+}
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
new file mode 100644
index 0000000..e23deeb
--- /dev/null
+++ b/drivers/net/cxgb3/common.h
@@ -0,0 +1,729 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __CHELSIO_COMMON_H
+#define __CHELSIO_COMMON_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include "version.h"
+
+#define CH_ERR(adap, fmt, ...)   dev_err(&adap->pdev->dev, fmt, ## __VA_ARGS__)
+#define CH_WARN(adap, fmt, ...)  dev_warn(&adap->pdev->dev, fmt, ## __VA_ARGS__)
+#define CH_ALERT(adap, fmt, ...) \
+	dev_printk(KERN_ALERT, &adap->pdev->dev, fmt, ## __VA_ARGS__)
+
+/*
+ * More powerful macro that selectively prints messages based on msg_enable.
+ * For info and debugging messages.
+ */
+#define CH_MSG(adapter, level, category, fmt, ...) do { \
+	if ((adapter)->msg_enable & NETIF_MSG_##category) \
+		dev_printk(KERN_##level, &adapter->pdev->dev, fmt, \
+			   ## __VA_ARGS__); \
+} while (0)
+
+#ifdef DEBUG
+# define CH_DBG(adapter, category, fmt, ...) \
+	CH_MSG(adapter, DEBUG, category, fmt, ## __VA_ARGS__)
+#else
+# define CH_DBG(adapter, category, fmt, ...)
+#endif
+
+/* Additional NETIF_MSG_* categories */
+#define NETIF_MSG_MMIO 0x8000000
+
+struct t3_rx_mode {
+	struct net_device *dev;
+	struct dev_mc_list *mclist;
+	unsigned int idx;
+};
+
+static inline void init_rx_mode(struct t3_rx_mode *p, struct net_device *dev,
+				struct dev_mc_list *mclist)
+{
+	p->dev = dev;
+	p->mclist = mclist;
+	p->idx = 0;
+}
+
+static inline u8 *t3_get_next_mcaddr(struct t3_rx_mode *rm)
+{
+	u8 *addr = NULL;
+
+	if (rm->mclist && rm->idx < rm->dev->mc_count) {
+		addr = rm->mclist->dmi_addr;
+		rm->mclist = rm->mclist->next;
+		rm->idx++;
+	}
+	return addr;
+}
+
+enum {
+	MAX_NPORTS = 2,		/* max # of ports */
+	MAX_FRAME_SIZE = 10240,	/* max MAC frame size, including header + FCS */
+	EEPROMSIZE = 8192,	/* Serial EEPROM size */
+	RSS_TABLE_SIZE = 64,	/* size of RSS lookup and mapping tables */
+	TCB_SIZE = 128,		/* TCB size */
+	NMTUS = 16,		/* size of MTU table */
+	NCCTRL_WIN = 32,	/* # of congestion control windows */
+};
+
+#define MAX_RX_COALESCING_LEN 16224U
+
+enum {
+	PAUSE_RX = 1 << 0,
+	PAUSE_TX = 1 << 1,
+	PAUSE_AUTONEG = 1 << 2
+};
+
+enum {
+	SUPPORTED_OFFLOAD = 1 << 24,
+	SUPPORTED_IRQ = 1 << 25
+};
+
+enum {				/* adapter interrupt-maintained statistics */
+	STAT_ULP_CH0_PBL_OOB,
+	STAT_ULP_CH1_PBL_OOB,
+	STAT_PCI_CORR_ECC,
+
+	IRQ_NUM_STATS		/* keep last */
+};
+
+enum {
+	SGE_QSETS = 8,		/* # of SGE Tx/Rx/RspQ sets */
+	SGE_RXQ_PER_SET = 2,	/* # of Rx queues per set */
+	SGE_TXQ_PER_SET = 3	/* # of Tx queues per set */
+};
+
+enum sge_context_type {		/* SGE egress context types */
+	SGE_CNTXT_RDMA = 0,
+	SGE_CNTXT_ETH = 2,
+	SGE_CNTXT_OFLD = 4,
+	SGE_CNTXT_CTRL = 5
+};
+
+enum {
+	AN_PKT_SIZE = 32,	/* async notification packet size */
+	IMMED_PKT_SIZE = 48	/* packet size for immediate data */
+};
+
+struct sg_ent {			/* SGE scatter/gather entry */
+	u32 len[2];
+	u64 addr[2];
+};
+
+#ifndef SGE_NUM_GENBITS
+/* Must be 1 or 2 */
+# define SGE_NUM_GENBITS 2
+#endif
+
+#define TX_DESC_FLITS 16U
+#define WR_FLITS (TX_DESC_FLITS + 1 - SGE_NUM_GENBITS)
+
+struct cphy;
+struct adapter;
+
+struct mdio_ops {
+	int (*read)(struct adapter *adapter, int phy_addr, int mmd_addr,
+		    int reg_addr, unsigned int *val);
+	int (*write)(struct adapter *adapter, int phy_addr, int mmd_addr,
+		     int reg_addr, unsigned int val);
+};
+
+struct adapter_info {
+	unsigned char nports;	/* # of ports */
+	unsigned char phy_base_addr;	/* MDIO PHY base address */
+	unsigned char mdien;
+	unsigned char mdiinv;
+	unsigned int gpio_out;	/* GPIO output settings */
+	unsigned int gpio_intr;	/* GPIO IRQ enable mask */
+	unsigned long caps;	/* adapter capabilities */
+	const struct mdio_ops *mdio_ops;	/* MDIO operations */
+	const char *desc;	/* product description */
+};
+
+struct port_type_info {
+	void (*phy_prep)(struct cphy *phy, struct adapter *adapter,
+			 int phy_addr, const struct mdio_ops *ops);
+	unsigned int caps;
+	const char *desc;
+};
+
+struct mc5_stats {
+	unsigned long parity_err;
+	unsigned long active_rgn_full;
+	unsigned long nfa_srch_err;
+	unsigned long unknown_cmd;
+	unsigned long reqq_parity_err;
+	unsigned long dispq_parity_err;
+	unsigned long del_act_empty;
+};
+
+struct mc7_stats {
+	unsigned long corr_err;
+	unsigned long uncorr_err;
+	unsigned long parity_err;
+	unsigned long addr_err;
+};
+
+struct mac_stats {
+	u64 tx_octets;		/* total # of octets in good frames */
+	u64 tx_octets_bad;	/* total # of octets in error frames */
+	u64 tx_frames;		/* all good frames */
+	u64 tx_mcast_frames;	/* good multicast frames */
+	u64 tx_bcast_frames;	/* good broadcast frames */
+	u64 tx_pause;		/* # of transmitted pause frames */
+	u64 tx_deferred;	/* frames with deferred transmissions */
+	u64 tx_late_collisions;	/* # of late collisions */
+	u64 tx_total_collisions;	/* # of total collisions */
+	u64 tx_excess_collisions;	/* frame errors from excessive collissions */
+	u64 tx_underrun;	/* # of Tx FIFO underruns */
+	u64 tx_len_errs;	/* # of Tx length errors */
+	u64 tx_mac_internal_errs;	/* # of internal MAC errors on Tx */
+	u64 tx_excess_deferral;	/* # of frames with excessive deferral */
+	u64 tx_fcs_errs;	/* # of frames with bad FCS */
+
+	u64 tx_frames_64;	/* # of Tx frames in a particular range */
+	u64 tx_frames_65_127;
+	u64 tx_frames_128_255;
+	u64 tx_frames_256_511;
+	u64 tx_frames_512_1023;
+	u64 tx_frames_1024_1518;
+	u64 tx_frames_1519_max;
+
+	u64 rx_octets;		/* total # of octets in good frames */
+	u64 rx_octets_bad;	/* total # of octets in error frames */
+	u64 rx_frames;		/* all good frames */
+	u64 rx_mcast_frames;	/* good multicast frames */
+	u64 rx_bcast_frames;	/* good broadcast frames */
+	u64 rx_pause;		/* # of received pause frames */
+	u64 rx_fcs_errs;	/* # of received frames with bad FCS */
+	u64 rx_align_errs;	/* alignment errors */
+	u64 rx_symbol_errs;	/* symbol errors */
+	u64 rx_data_errs;	/* data errors */
+	u64 rx_sequence_errs;	/* sequence errors */
+	u64 rx_runt;		/* # of runt frames */
+	u64 rx_jabber;		/* # of jabber frames */
+	u64 rx_short;		/* # of short frames */
+	u64 rx_too_long;	/* # of oversized frames */
+	u64 rx_mac_internal_errs;	/* # of internal MAC errors on Rx */
+
+	u64 rx_frames_64;	/* # of Rx frames in a particular range */
+	u64 rx_frames_65_127;
+	u64 rx_frames_128_255;
+	u64 rx_frames_256_511;
+	u64 rx_frames_512_1023;
+	u64 rx_frames_1024_1518;
+	u64 rx_frames_1519_max;
+
+	u64 rx_cong_drops;	/* # of Rx drops due to SGE congestion */
+
+	unsigned long tx_fifo_parity_err;
+	unsigned long rx_fifo_parity_err;
+	unsigned long tx_fifo_urun;
+	unsigned long rx_fifo_ovfl;
+	unsigned long serdes_signal_loss;
+	unsigned long xaui_pcs_ctc_err;
+	unsigned long xaui_pcs_align_change;
+};
+
+struct tp_mib_stats {
+	u32 ipInReceive_hi;
+	u32 ipInReceive_lo;
+	u32 ipInHdrErrors_hi;
+	u32 ipInHdrErrors_lo;
+	u32 ipInAddrErrors_hi;
+	u32 ipInAddrErrors_lo;
+	u32 ipInUnknownProtos_hi;
+	u32 ipInUnknownProtos_lo;
+	u32 ipInDiscards_hi;
+	u32 ipInDiscards_lo;
+	u32 ipInDelivers_hi;
+	u32 ipInDelivers_lo;
+	u32 ipOutRequests_hi;
+	u32 ipOutRequests_lo;
+	u32 ipOutDiscards_hi;
+	u32 ipOutDiscards_lo;
+	u32 ipOutNoRoutes_hi;
+	u32 ipOutNoRoutes_lo;
+	u32 ipReasmTimeout;
+	u32 ipReasmReqds;
+	u32 ipReasmOKs;
+	u32 ipReasmFails;
+
+	u32 reserved[8];
+
+	u32 tcpActiveOpens;
+	u32 tcpPassiveOpens;
+	u32 tcpAttemptFails;
+	u32 tcpEstabResets;
+	u32 tcpOutRsts;
+	u32 tcpCurrEstab;
+	u32 tcpInSegs_hi;
+	u32 tcpInSegs_lo;
+	u32 tcpOutSegs_hi;
+	u32 tcpOutSegs_lo;
+	u32 tcpRetransSeg_hi;
+	u32 tcpRetransSeg_lo;
+	u32 tcpInErrs_hi;
+	u32 tcpInErrs_lo;
+	u32 tcpRtoMin;
+	u32 tcpRtoMax;
+};
+
+struct tp_params {
+	unsigned int nchan;	/* # of channels */
+	unsigned int pmrx_size;	/* total PMRX capacity */
+	unsigned int pmtx_size;	/* total PMTX capacity */
+	unsigned int cm_size;	/* total CM capacity */
+	unsigned int chan_rx_size;	/* per channel Rx size */
+	unsigned int chan_tx_size;	/* per channel Tx size */
+	unsigned int rx_pg_size;	/* Rx page size */
+	unsigned int tx_pg_size;	/* Tx page size */
+	unsigned int rx_num_pgs;	/* # of Rx pages */
+	unsigned int tx_num_pgs;	/* # of Tx pages */
+	unsigned int ntimer_qs;	/* # of timer queues */
+};
+
+struct qset_params {		/* SGE queue set parameters */
+	unsigned int polling;	/* polling/interrupt service for rspq */
+	unsigned int coalesce_usecs;	/* irq coalescing timer */
+	unsigned int rspq_size;	/* # of entries in response queue */
+	unsigned int fl_size;	/* # of entries in regular free list */
+	unsigned int jumbo_size;	/* # of entries in jumbo free list */
+	unsigned int txq_size[SGE_TXQ_PER_SET];	/* Tx queue sizes */
+	unsigned int cong_thres;	/* FL congestion threshold */
+};
+
+struct sge_params {
+	unsigned int max_pkt_size;	/* max offload pkt size */
+	struct qset_params qset[SGE_QSETS];
+};
+
+struct mc5_params {
+	unsigned int mode;	/* selects MC5 width */
+	unsigned int nservers;	/* size of server region */
+	unsigned int nfilters;	/* size of filter region */
+	unsigned int nroutes;	/* size of routing region */
+};
+
+/* Default MC5 region sizes */
+enum {
+	DEFAULT_NSERVERS = 512,
+	DEFAULT_NFILTERS = 128
+};
+
+/* MC5 modes, these must be non-0 */
+enum {
+	MC5_MODE_144_BIT = 1,
+	MC5_MODE_72_BIT = 2
+};
+
+struct vpd_params {
+	unsigned int cclk;
+	unsigned int mclk;
+	unsigned int uclk;
+	unsigned int mdc;
+	unsigned int mem_timing;
+	u8 eth_base[6];
+	u8 port_type[MAX_NPORTS];
+	unsigned short xauicfg[2];
+};
+
+struct pci_params {
+	unsigned int vpd_cap_addr;
+	unsigned int pcie_cap_addr;
+	unsigned short speed;
+	unsigned char width;
+	unsigned char variant;
+};
+
+enum {
+	PCI_VARIANT_PCI,
+	PCI_VARIANT_PCIX_MODE1_PARITY,
+	PCI_VARIANT_PCIX_MODE1_ECC,
+	PCI_VARIANT_PCIX_266_MODE2,
+	PCI_VARIANT_PCIE
+};
+
+struct adapter_params {
+	struct sge_params sge;
+	struct mc5_params mc5;
+	struct tp_params tp;
+	struct vpd_params vpd;
+	struct pci_params pci;
+
+	const struct adapter_info *info;
+
+	unsigned short mtus[NMTUS];
+	unsigned short a_wnd[NCCTRL_WIN];
+	unsigned short b_wnd[NCCTRL_WIN];
+
+	unsigned int nports;	/* # of ethernet ports */
+	unsigned int stats_update_period;	/* MAC stats accumulation period */
+	unsigned int linkpoll_period;	/* link poll period in 0.1s */
+	unsigned int rev;	/* chip revision */
+};
+
+struct trace_params {
+	u32 sip;
+	u32 sip_mask;
+	u32 dip;
+	u32 dip_mask;
+	u16 sport;
+	u16 sport_mask;
+	u16 dport;
+	u16 dport_mask;
+	u32 vlan:12;
+	u32 vlan_mask:12;
+	u32 intf:4;
+	u32 intf_mask:4;
+	u8 proto;
+	u8 proto_mask;
+};
+
+struct link_config {
+	unsigned int supported;	/* link capabilities */
+	unsigned int advertising;	/* advertised capabilities */
+	unsigned short requested_speed;	/* speed user has requested */
+	unsigned short speed;	/* actual link speed */
+	unsigned char requested_duplex;	/* duplex user has requested */
+	unsigned char duplex;	/* actual link duplex */
+	unsigned char requested_fc;	/* flow control user has requested */
+	unsigned char fc;	/* actual link flow control */
+	unsigned char autoneg;	/* autonegotiating? */
+	unsigned int link_ok;	/* link up? */
+};
+
+#define SPEED_INVALID   0xffff
+#define DUPLEX_INVALID  0xff
+
+struct mc5 {
+	struct adapter *adapter;
+	unsigned int tcam_size;
+	unsigned char part_type;
+	unsigned char parity_enabled;
+	unsigned char mode;
+	struct mc5_stats stats;
+};
+
+static inline unsigned int t3_mc5_size(const struct mc5 *p)
+{
+	return p->tcam_size;
+}
+
+struct mc7 {
+	struct adapter *adapter;	/* backpointer to adapter */
+	unsigned int size;	/* memory size in bytes */
+	unsigned int width;	/* MC7 interface width */
+	unsigned int offset;	/* register address offset for MC7 instance */
+	const char *name;	/* name of MC7 instance */
+	struct mc7_stats stats;	/* MC7 statistics */
+};
+
+static inline unsigned int t3_mc7_size(const struct mc7 *p)
+{
+	return p->size;
+}
+
+struct cmac {
+	struct adapter *adapter;
+	unsigned int offset;
+	unsigned int nucast;	/* # of address filters for unicast MACs */
+	struct mac_stats stats;
+};
+
+enum {
+	MAC_DIRECTION_RX = 1,
+	MAC_DIRECTION_TX = 2,
+	MAC_RXFIFO_SIZE = 32768
+};
+
+/* IEEE 802.3ae specified MDIO devices */
+enum {
+	MDIO_DEV_PMA_PMD = 1,
+	MDIO_DEV_WIS = 2,
+	MDIO_DEV_PCS = 3,
+	MDIO_DEV_XGXS = 4
+};
+
+/* PHY loopback direction */
+enum {
+	PHY_LOOPBACK_TX = 1,
+	PHY_LOOPBACK_RX = 2
+};
+
+/* PHY interrupt types */
+enum {
+	cphy_cause_link_change = 1,
+	cphy_cause_fifo_error = 2
+};
+
+/* PHY operations */
+struct cphy_ops {
+	void (*destroy)(struct cphy *phy);
+	int (*reset)(struct cphy *phy, int wait);
+
+	int (*intr_enable)(struct cphy *phy);
+	int (*intr_disable)(struct cphy *phy);
+	int (*intr_clear)(struct cphy *phy);
+	int (*intr_handler)(struct cphy *phy);
+
+	int (*autoneg_enable)(struct cphy *phy);
+	int (*autoneg_restart)(struct cphy *phy);
+
+	int (*advertise)(struct cphy *phy, unsigned int advertise_map);
+	int (*set_loopback)(struct cphy *phy, int mmd, int dir, int enable);
+	int (*set_speed_duplex)(struct cphy *phy, int speed, int duplex);
+	int (*get_link_status)(struct cphy *phy, int *link_ok, int *speed,
+			       int *duplex, int *fc);
+	int (*power_down)(struct cphy *phy, int enable);
+};
+
+/* A PHY instance */
+struct cphy {
+	int addr;		/* PHY address */
+	struct adapter *adapter;	/* associated adapter */
+	unsigned long fifo_errors;	/* FIFO over/under-flows */
+	const struct cphy_ops *ops;	/* PHY operations */
+	int (*mdio_read)(struct adapter *adapter, int phy_addr, int mmd_addr,
+			 int reg_addr, unsigned int *val);
+	int (*mdio_write)(struct adapter *adapter, int phy_addr, int mmd_addr,
+			  int reg_addr, unsigned int val);
+};
+
+/* Convenience MDIO read/write wrappers */
+static inline int mdio_read(struct cphy *phy, int mmd, int reg,
+			    unsigned int *valp)
+{
+	return phy->mdio_read(phy->adapter, phy->addr, mmd, reg, valp);
+}
+
+static inline int mdio_write(struct cphy *phy, int mmd, int reg,
+			     unsigned int val)
+{
+	return phy->mdio_write(phy->adapter, phy->addr, mmd, reg, val);
+}
+
+/* Convenience initializer */
+static inline void cphy_init(struct cphy *phy, struct adapter *adapter,
+			     int phy_addr, struct cphy_ops *phy_ops,
+			     const struct mdio_ops *mdio_ops)
+{
+	phy->adapter = adapter;
+	phy->addr = phy_addr;
+	phy->ops = phy_ops;
+	if (mdio_ops) {
+		phy->mdio_read = mdio_ops->read;
+		phy->mdio_write = mdio_ops->write;
+	}
+}
+
+/* Accumulate MAC statistics every 180 seconds.  For 1G we multiply by 10. */
+#define MAC_STATS_ACCUM_SECS 180
+
+#define XGM_REG(reg_addr, idx) \
+	((reg_addr) + (idx) * (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR))
+
+struct addr_val_pair {
+	unsigned int reg_addr;
+	unsigned int val;
+};
+
+#include "adapter.h"
+
+#ifndef PCI_VENDOR_ID_CHELSIO
+# define PCI_VENDOR_ID_CHELSIO 0x1425
+#endif
+
+#define for_each_port(adapter, iter) \
+	for (iter = 0; iter < (adapter)->params.nports; ++iter)
+
+#define adapter_info(adap) ((adap)->params.info)
+
+static inline int uses_xaui(const struct adapter *adap)
+{
+	return adapter_info(adap)->caps & SUPPORTED_AUI;
+}
+
+static inline int is_10G(const struct adapter *adap)
+{
+	return adapter_info(adap)->caps & SUPPORTED_10000baseT_Full;
+}
+
+static inline int is_offload(const struct adapter *adap)
+{
+	return adapter_info(adap)->caps & SUPPORTED_OFFLOAD;
+}
+
+static inline unsigned int core_ticks_per_usec(const struct adapter *adap)
+{
+	return adap->params.vpd.cclk / 1000;
+}
+
+static inline unsigned int is_pcie(const struct adapter *adap)
+{
+	return adap->params.pci.variant == PCI_VARIANT_PCIE;
+}
+
+void t3_set_reg_field(struct adapter *adap, unsigned int addr, u32 mask,
+		      u32 val);
+void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p,
+		   int n, unsigned int offset);
+int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask,
+			int polarity, int attempts, int delay, u32 *valp);
+static inline int t3_wait_op_done(struct adapter *adapter, int reg, u32 mask,
+				  int polarity, int attempts, int delay)
+{
+	return t3_wait_op_done_val(adapter, reg, mask, polarity, attempts,
+				   delay, NULL);
+}
+int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear,
+			unsigned int set);
+int t3_phy_reset(struct cphy *phy, int mmd, int wait);
+int t3_phy_advertise(struct cphy *phy, unsigned int advert);
+int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex);
+
+void t3_intr_enable(struct adapter *adapter);
+void t3_intr_disable(struct adapter *adapter);
+void t3_intr_clear(struct adapter *adapter);
+void t3_port_intr_enable(struct adapter *adapter, int idx);
+void t3_port_intr_disable(struct adapter *adapter, int idx);
+void t3_port_intr_clear(struct adapter *adapter, int idx);
+int t3_slow_intr_handler(struct adapter *adapter);
+int t3_phy_intr_handler(struct adapter *adapter);
+
+void t3_link_changed(struct adapter *adapter, int port_id);
+int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc);
+const struct adapter_info *t3_get_adapter_info(unsigned int board_id);
+int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data);
+int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data);
+int t3_seeprom_wp(struct adapter *adapter, int enable);
+int t3_read_flash(struct adapter *adapter, unsigned int addr,
+		  unsigned int nwords, u32 *data, int byte_oriented);
+int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size);
+int t3_get_fw_version(struct adapter *adapter, u32 *vers);
+int t3_check_fw_version(struct adapter *adapter);
+int t3_init_hw(struct adapter *adapter, u32 fw_params);
+void mac_prep(struct cmac *mac, struct adapter *adapter, int index);
+void early_hw_init(struct adapter *adapter, const struct adapter_info *ai);
+int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
+		    int reset);
+void t3_led_ready(struct adapter *adapter);
+void t3_fatal_err(struct adapter *adapter);
+void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on);
+void t3_config_rss(struct adapter *adapter, unsigned int rss_config,
+		   const u8 * cpus, const u16 *rspq);
+int t3_read_rss(struct adapter *adapter, u8 * lkup, u16 *map);
+int t3_mps_set_active_ports(struct adapter *adap, unsigned int port_mask);
+int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr,
+			unsigned int n, unsigned int *valp);
+int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
+		   u64 *buf);
+
+int t3_mac_reset(struct cmac *mac);
+void t3b_pcs_reset(struct cmac *mac);
+int t3_mac_enable(struct cmac *mac, int which);
+int t3_mac_disable(struct cmac *mac, int which);
+int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu);
+int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm);
+int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]);
+int t3_mac_set_num_ucast(struct cmac *mac, int n);
+const struct mac_stats *t3_mac_update_stats(struct cmac *mac);
+int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc);
+
+void t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode);
+int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters,
+		unsigned int nroutes);
+void t3_mc5_intr_handler(struct mc5 *mc5);
+int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start, unsigned int n,
+		      u32 *buf);
+
+int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh);
+void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size);
+void t3_tp_set_offload_mode(struct adapter *adap, int enable);
+void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps);
+void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS],
+		  unsigned short alpha[NCCTRL_WIN],
+		  unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap);
+void t3_read_hw_mtus(struct adapter *adap, unsigned short mtus[NMTUS]);
+void t3_get_cong_cntl_tab(struct adapter *adap,
+			  unsigned short incr[NMTUS][NCCTRL_WIN]);
+void t3_config_trace_filter(struct adapter *adapter,
+			    const struct trace_params *tp, int filter_index,
+			    int invert, int enable);
+int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched);
+
+void t3_sge_prep(struct adapter *adap, struct sge_params *p);
+void t3_sge_init(struct adapter *adap, struct sge_params *p);
+int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable,
+		       enum sge_context_type type, int respq, u64 base_addr,
+		       unsigned int size, unsigned int token, int gen,
+		       unsigned int cidx);
+int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id,
+			int gts_enable, u64 base_addr, unsigned int size,
+			unsigned int esize, unsigned int cong_thres, int gen,
+			unsigned int cidx);
+int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id,
+			 int irq_vec_idx, u64 base_addr, unsigned int size,
+			 unsigned int fl_thres, int gen, unsigned int cidx);
+int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr,
+			unsigned int size, int rspq, int ovfl_mode,
+			unsigned int credits, unsigned int credit_thres);
+int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable);
+int t3_sge_disable_fl(struct adapter *adapter, unsigned int id);
+int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id);
+int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id);
+int t3_sge_read_ecntxt(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_read_fl(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_read_cq(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
+		      unsigned int credits);
+
+void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
+			 int phy_addr, const struct mdio_ops *mdio_ops);
+void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
+			 int phy_addr, const struct mdio_ops *mdio_ops);
+void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
+			 int phy_addr, const struct mdio_ops *mdio_ops);
+void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
+			const struct mdio_ops *mdio_ops);
+void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
+			     int phy_addr, const struct mdio_ops *mdio_ops);
+#endif				/* __CHELSIO_COMMON_H */
diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h
new file mode 100644
index 0000000..2095dda
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CXGB3_OFFLOAD_CTL_DEFS_H
+#define _CXGB3_OFFLOAD_CTL_DEFS_H
+
+enum {
+	GET_MAX_OUTSTANDING_WR,
+	GET_TX_MAX_CHUNK,
+	GET_TID_RANGE,
+	GET_STID_RANGE,
+	GET_RTBL_RANGE,
+	GET_L2T_CAPACITY,
+	GET_MTUS,
+	GET_WR_LEN,
+	GET_IFF_FROM_MAC,
+	GET_DDP_PARAMS,
+	GET_PORTS,
+
+	ULP_ISCSI_GET_PARAMS,
+	ULP_ISCSI_SET_PARAMS,
+
+	RDMA_GET_PARAMS,
+	RDMA_CQ_OP,
+	RDMA_CQ_SETUP,
+	RDMA_CQ_DISABLE,
+	RDMA_CTRL_QP_SETUP,
+	RDMA_GET_MEM,
+};
+
+/*
+ * Structure used to describe a TID range.  Valid TIDs are [base, base+num).
+ */
+struct tid_range {
+	unsigned int base;	/* first TID */
+	unsigned int num;	/* number of TIDs in range */
+};
+
+/*
+ * Structure used to request the size and contents of the MTU table.
+ */
+struct mtutab {
+	unsigned int size;	/* # of entries in the MTU table */
+	const unsigned short *mtus;	/* the MTU table values */
+};
+
+struct net_device;
+
+/*
+ * Structure used to request the adapter net_device owning a given MAC address.
+ */
+struct iff_mac {
+	struct net_device *dev;	/* the net_device */
+	const unsigned char *mac_addr;	/* MAC address to lookup */
+	u16 vlan_tag;
+};
+
+struct pci_dev;
+
+/*
+ * Structure used to request the TCP DDP parameters.
+ */
+struct ddp_params {
+	unsigned int llimit;	/* TDDP region start address */
+	unsigned int ulimit;	/* TDDP region end address */
+	unsigned int tag_mask;	/* TDDP tag mask */
+	struct pci_dev *pdev;
+};
+
+struct adap_ports {
+	unsigned int nports;	/* number of ports on this adapter */
+	struct net_device *lldevs[2];
+};
+
+/*
+ * Structure used to return information to the iscsi layer.
+ */
+struct ulp_iscsi_info {
+	unsigned int offset;
+	unsigned int llimit;
+	unsigned int ulimit;
+	unsigned int tagmask;
+	unsigned int pgsz3;
+	unsigned int pgsz2;
+	unsigned int pgsz1;
+	unsigned int pgsz0;
+	unsigned int max_rxsz;
+	unsigned int max_txsz;
+	struct pci_dev *pdev;
+};
+
+/*
+ * Structure used to return information to the RDMA layer.
+ */
+struct rdma_info {
+	unsigned int tpt_base;	/* TPT base address */
+	unsigned int tpt_top;	/* TPT last entry address */
+	unsigned int pbl_base;	/* PBL base address */
+	unsigned int pbl_top;	/* PBL last entry address */
+	unsigned int rqt_base;	/* RQT base address */
+	unsigned int rqt_top;	/* RQT last entry address */
+	unsigned int udbell_len;	/* user doorbell region length */
+	unsigned long udbell_physbase;	/* user doorbell physical start addr */
+	void __iomem *kdb_addr;	/* kernel doorbell register address */
+	struct pci_dev *pdev;	/* associated PCI device */
+};
+
+/*
+ * Structure used to request an operation on an RDMA completion queue.
+ */
+struct rdma_cq_op {
+	unsigned int id;
+	unsigned int op;
+	unsigned int credits;
+};
+
+/*
+ * Structure used to setup RDMA completion queues.
+ */
+struct rdma_cq_setup {
+	unsigned int id;
+	unsigned long long base_addr;
+	unsigned int size;
+	unsigned int credits;
+	unsigned int credit_thres;
+	unsigned int ovfl_mode;
+};
+
+/*
+ * Structure used to setup the RDMA control egress context.
+ */
+struct rdma_ctrlqp_setup {
+	unsigned long long base_addr;
+	unsigned int size;
+};
+#endif				/* _CXGB3_OFFLOAD_CTL_DEFS_H */
diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h
new file mode 100644
index 0000000..16e0049
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_defs.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CHELSIO_DEFS_H
+#define _CHELSIO_DEFS_H
+
+#include <linux/skbuff.h>
+#include <net/tcp.h>
+
+#include "t3cdev.h"
+
+#include "cxgb3_offload.h"
+
+#define VALIDATE_TID 1
+
+void *cxgb_alloc_mem(unsigned long size);
+void cxgb_free_mem(void *addr);
+void cxgb_neigh_update(struct neighbour *neigh);
+void cxgb_redirect(struct dst_entry *old, struct dst_entry *new);
+
+/*
+ * Map an ATID or STID to their entries in the corresponding TID tables.
+ */
+static inline union active_open_entry *atid2entry(const struct tid_info *t,
+						  unsigned int atid)
+{
+	return &t->atid_tab[atid - t->atid_base];
+}
+
+static inline union listen_entry *stid2entry(const struct tid_info *t,
+					     unsigned int stid)
+{
+	return &t->stid_tab[stid - t->stid_base];
+}
+
+/*
+ * Find the connection corresponding to a TID.
+ */
+static inline struct t3c_tid_entry *lookup_tid(const struct tid_info *t,
+					       unsigned int tid)
+{
+	return tid < t->ntids ? &(t->tid_tab[tid]) : NULL;
+}
+
+/*
+ * Find the connection corresponding to a server TID.
+ */
+static inline struct t3c_tid_entry *lookup_stid(const struct tid_info *t,
+						unsigned int tid)
+{
+	if (tid < t->stid_base || tid >= t->stid_base + t->nstids)
+		return NULL;
+	return &(stid2entry(t, tid)->t3c_tid);
+}
+
+/*
+ * Find the connection corresponding to an active-open TID.
+ */
+static inline struct t3c_tid_entry *lookup_atid(const struct tid_info *t,
+						unsigned int tid)
+{
+	if (tid < t->atid_base || tid >= t->atid_base + t->natids)
+		return NULL;
+	return &(atid2entry(t, tid)->t3c_tid);
+}
+
+int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n);
+int attach_t3cdev(struct t3cdev *dev);
+void detach_t3cdev(struct t3cdev *dev);
+#endif
diff --git a/drivers/net/cxgb3/cxgb3_ioctl.h b/drivers/net/cxgb3/cxgb3_ioctl.h
new file mode 100644
index 0000000..a942818
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_ioctl.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __CHIOCTL_H__
+#define __CHIOCTL_H__
+
+/*
+ * Ioctl commands specific to this driver.
+ */
+enum {
+	CHELSIO_SETREG = 1024,
+	CHELSIO_GETREG,
+	CHELSIO_SETTPI,
+	CHELSIO_GETTPI,
+	CHELSIO_GETMTUTAB,
+	CHELSIO_SETMTUTAB,
+	CHELSIO_GETMTU,
+	CHELSIO_SET_PM,
+	CHELSIO_GET_PM,
+	CHELSIO_GET_TCAM,
+	CHELSIO_SET_TCAM,
+	CHELSIO_GET_TCB,
+	CHELSIO_GET_MEM,
+	CHELSIO_LOAD_FW,
+	CHELSIO_GET_PROTO,
+	CHELSIO_SET_PROTO,
+	CHELSIO_SET_TRACE_FILTER,
+	CHELSIO_SET_QSET_PARAMS,
+	CHELSIO_GET_QSET_PARAMS,
+	CHELSIO_SET_QSET_NUM,
+	CHELSIO_GET_QSET_NUM,
+	CHELSIO_SET_PKTSCHED,
+};
+
+struct ch_reg {
+	uint32_t cmd;
+	uint32_t addr;
+	uint32_t val;
+};
+
+struct ch_cntxt {
+	uint32_t cmd;
+	uint32_t cntxt_type;
+	uint32_t cntxt_id;
+	uint32_t data[4];
+};
+
+/* context types */
+enum { CNTXT_TYPE_EGRESS, CNTXT_TYPE_FL, CNTXT_TYPE_RSP, CNTXT_TYPE_CQ };
+
+struct ch_desc {
+	uint32_t cmd;
+	uint32_t queue_num;
+	uint32_t idx;
+	uint32_t size;
+	uint8_t data[128];
+};
+
+struct ch_mem_range {
+	uint32_t cmd;
+	uint32_t mem_id;
+	uint32_t addr;
+	uint32_t len;
+	uint32_t version;
+	uint8_t buf[0];
+};
+
+struct ch_qset_params {
+	uint32_t cmd;
+	uint32_t qset_idx;
+	int32_t txq_size[3];
+	int32_t rspq_size;
+	int32_t fl_size[2];
+	int32_t intr_lat;
+	int32_t polling;
+	int32_t cong_thres;
+};
+
+struct ch_pktsched_params {
+	uint32_t cmd;
+	uint8_t sched;
+	uint8_t idx;
+	uint8_t min;
+	uint8_t max;
+	uint8_t binding;
+};
+
+#ifndef TCB_SIZE
+# define TCB_SIZE   128
+#endif
+
+/* TCB size in 32-bit words */
+#define TCB_WORDS (TCB_SIZE / 4)
+
+enum { MEM_CM, MEM_PMRX, MEM_PMTX };	/* ch_mem_range.mem_id values */
+
+struct ch_mtus {
+	uint32_t cmd;
+	uint32_t nmtus;
+	uint16_t mtus[NMTUS];
+};
+
+struct ch_pm {
+	uint32_t cmd;
+	uint32_t tx_pg_sz;
+	uint32_t tx_num_pg;
+	uint32_t rx_pg_sz;
+	uint32_t rx_num_pg;
+	uint32_t pm_total;
+};
+
+struct ch_tcam {
+	uint32_t cmd;
+	uint32_t tcam_size;
+	uint32_t nservers;
+	uint32_t nroutes;
+	uint32_t nfilters;
+};
+
+struct ch_tcb {
+	uint32_t cmd;
+	uint32_t tcb_index;
+	uint32_t tcb_data[TCB_WORDS];
+};
+
+struct ch_tcam_word {
+	uint32_t cmd;
+	uint32_t addr;
+	uint32_t buf[3];
+};
+
+struct ch_trace {
+	uint32_t cmd;
+	uint32_t sip;
+	uint32_t sip_mask;
+	uint32_t dip;
+	uint32_t dip_mask;
+	uint16_t sport;
+	uint16_t sport_mask;
+	uint16_t dport;
+	uint16_t dport_mask;
+	uint32_t vlan:12;
+	uint32_t vlan_mask:12;
+	uint32_t intf:4;
+	uint32_t intf_mask:4;
+	uint8_t proto;
+	uint8_t proto_mask;
+	uint8_t invert_match:1;
+	uint8_t config_tx:1;
+	uint8_t config_rx:1;
+	uint8_t trace_tx:1;
+	uint8_t trace_rx:1;
+};
+
+#define SIOCCHIOCTL SIOCDEVPRIVATE
+
+#endif
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
new file mode 100644
index 0000000..c67f7d3
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -0,0 +1,2519 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/mii.h>
+#include <linux/sockios.h>
+#include <linux/workqueue.h>
+#include <linux/proc_fs.h>
+#include <linux/rtnetlink.h>
+#include <asm/uaccess.h>
+
+#include "common.h"
+#include "cxgb3_ioctl.h"
+#include "regs.h"
+#include "cxgb3_offload.h"
+#include "version.h"
+
+#include "cxgb3_ctl_defs.h"
+#include "t3_cpl.h"
+#include "firmware_exports.h"
+
+enum {
+	MAX_TXQ_ENTRIES = 16384,
+	MAX_CTRL_TXQ_ENTRIES = 1024,
+	MAX_RSPQ_ENTRIES = 16384,
+	MAX_RX_BUFFERS = 16384,
+	MAX_RX_JUMBO_BUFFERS = 16384,
+	MIN_TXQ_ENTRIES = 4,
+	MIN_CTRL_TXQ_ENTRIES = 4,
+	MIN_RSPQ_ENTRIES = 32,
+	MIN_FL_ENTRIES = 32
+};
+
+#define PORT_MASK ((1 << MAX_NPORTS) - 1)
+
+#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
+			 NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
+			 NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
+
+#define EEPROM_MAGIC 0x38E2F10C
+
+#define CH_DEVICE(devid, ssid, idx) \
+	{ PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, ssid, 0, 0, idx }
+
+static const struct pci_device_id cxgb3_pci_tbl[] = {
+	CH_DEVICE(0x20, 1, 0),	/* PE9000 */
+	CH_DEVICE(0x21, 1, 1),	/* T302E */
+	CH_DEVICE(0x22, 1, 2),	/* T310E */
+	CH_DEVICE(0x23, 1, 3),	/* T320X */
+	CH_DEVICE(0x24, 1, 1),	/* T302X */
+	CH_DEVICE(0x25, 1, 3),	/* T320E */
+	CH_DEVICE(0x26, 1, 2),	/* T310X */
+	CH_DEVICE(0x30, 1, 2),	/* T3B10 */
+	CH_DEVICE(0x31, 1, 3),	/* T3B20 */
+	CH_DEVICE(0x32, 1, 1),	/* T3B02 */
+	{0,}
+};
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_AUTHOR("Chelsio Communications");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, cxgb3_pci_tbl);
+
+static int dflt_msg_enable = DFLT_MSG_ENABLE;
+
+module_param(dflt_msg_enable, int, 0644);
+MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T3 default message enable bitmap");
+
+/*
+ * The driver uses the best interrupt scheme available on a platform in the
+ * order MSI-X, MSI, legacy pin interrupts.  This parameter determines which
+ * of these schemes the driver may consider as follows:
+ *
+ * msi = 2: choose from among all three options
+ * msi = 1: only consider MSI and pin interrupts
+ * msi = 0: force pin interrupts
+ */
+static int msi = 2;
+
+module_param(msi, int, 0644);
+MODULE_PARM_DESC(msi, "whether to use MSI or MSI-X");
+
+/*
+ * The driver enables offload as a default.
+ * To disable it, use ofld_disable = 1.
+ */
+
+static int ofld_disable = 0;
+
+module_param(ofld_disable, int, 0644);
+MODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not");
+
+/*
+ * We have work elements that we need to cancel when an interface is taken
+ * down.  Normally the work elements would be executed by keventd but that
+ * can deadlock because of linkwatch.  If our close method takes the rtnl
+ * lock and linkwatch is ahead of our work elements in keventd, linkwatch
+ * will block keventd as it needs the rtnl lock, and we'll deadlock waiting
+ * for our work to complete.  Get our own work queue to solve this.
+ */
+static struct workqueue_struct *cxgb3_wq;
+
+/**
+ *	link_report - show link status and link speed/duplex
+ *	@p: the port whose settings are to be reported
+ *
+ *	Shows the link status, speed, and duplex of a port.
+ */
+static void link_report(struct net_device *dev)
+{
+	if (!netif_carrier_ok(dev))
+		printk(KERN_INFO "%s: link down\n", dev->name);
+	else {
+		const char *s = "10Mbps";
+		const struct port_info *p = netdev_priv(dev);
+
+		switch (p->link_config.speed) {
+		case SPEED_10000:
+			s = "10Gbps";
+			break;
+		case SPEED_1000:
+			s = "1000Mbps";
+			break;
+		case SPEED_100:
+			s = "100Mbps";
+			break;
+		}
+
+		printk(KERN_INFO "%s: link up, %s, %s-duplex\n", dev->name, s,
+		       p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
+	}
+}
+
+/**
+ *	t3_os_link_changed - handle link status changes
+ *	@adapter: the adapter associated with the link change
+ *	@port_id: the port index whose limk status has changed
+ *	@link_stat: the new status of the link
+ *	@speed: the new speed setting
+ *	@duplex: the new duplex setting
+ *	@pause: the new flow-control setting
+ *
+ *	This is the OS-dependent handler for link status changes.  The OS
+ *	neutral handler takes care of most of the processing for these events,
+ *	then calls this handler for any OS-specific processing.
+ */
+void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
+			int speed, int duplex, int pause)
+{
+	struct net_device *dev = adapter->port[port_id];
+
+	/* Skip changes from disabled ports. */
+	if (!netif_running(dev))
+		return;
+
+	if (link_stat != netif_carrier_ok(dev)) {
+		if (link_stat)
+			netif_carrier_on(dev);
+		else
+			netif_carrier_off(dev);
+		link_report(dev);
+	}
+}
+
+static void cxgb_set_rxmode(struct net_device *dev)
+{
+	struct t3_rx_mode rm;
+	struct port_info *pi = netdev_priv(dev);
+
+	init_rx_mode(&rm, dev, dev->mc_list);
+	t3_mac_set_rx_mode(&pi->mac, &rm);
+}
+
+/**
+ *	link_start - enable a port
+ *	@dev: the device to enable
+ *
+ *	Performs the MAC and PHY actions needed to enable a port.
+ */
+static void link_start(struct net_device *dev)
+{
+	struct t3_rx_mode rm;
+	struct port_info *pi = netdev_priv(dev);
+	struct cmac *mac = &pi->mac;
+
+	init_rx_mode(&rm, dev, dev->mc_list);
+	t3_mac_reset(mac);
+	t3_mac_set_mtu(mac, dev->mtu);
+	t3_mac_set_address(mac, 0, dev->dev_addr);
+	t3_mac_set_rx_mode(mac, &rm);
+	t3_link_start(&pi->phy, mac, &pi->link_config);
+	t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
+}
+
+static inline void cxgb_disable_msi(struct adapter *adapter)
+{
+	if (adapter->flags & USING_MSIX) {
+		pci_disable_msix(adapter->pdev);
+		adapter->flags &= ~USING_MSIX;
+	} else if (adapter->flags & USING_MSI) {
+		pci_disable_msi(adapter->pdev);
+		adapter->flags &= ~USING_MSI;
+	}
+}
+
+/*
+ * Interrupt handler for asynchronous events used with MSI-X.
+ */
+static irqreturn_t t3_async_intr_handler(int irq, void *cookie)
+{
+	t3_slow_intr_handler(cookie);
+	return IRQ_HANDLED;
+}
+
+/*
+ * Name the MSI-X interrupts.
+ */
+static void name_msix_vecs(struct adapter *adap)
+{
+	int i, j, msi_idx = 1, n = sizeof(adap->msix_info[0].desc) - 1;
+
+	snprintf(adap->msix_info[0].desc, n, "%s", adap->name);
+	adap->msix_info[0].desc[n] = 0;
+
+	for_each_port(adap, j) {
+		struct net_device *d = adap->port[j];
+		const struct port_info *pi = netdev_priv(d);
+
+		for (i = 0; i < pi->nqsets; i++, msi_idx++) {
+			snprintf(adap->msix_info[msi_idx].desc, n,
+				 "%s (queue %d)", d->name, i);
+			adap->msix_info[msi_idx].desc[n] = 0;
+		}
+ 	}
+}
+
+static int request_msix_data_irqs(struct adapter *adap)
+{
+	int i, j, err, qidx = 0;
+
+	for_each_port(adap, i) {
+		int nqsets = adap2pinfo(adap, i)->nqsets;
+
+		for (j = 0; j < nqsets; ++j) {
+			err = request_irq(adap->msix_info[qidx + 1].vec,
+					  t3_intr_handler(adap,
+							  adap->sge.qs[qidx].
+							  rspq.polling), 0,
+					  adap->msix_info[qidx + 1].desc,
+					  &adap->sge.qs[qidx]);
+			if (err) {
+				while (--qidx >= 0)
+					free_irq(adap->msix_info[qidx + 1].vec,
+						 &adap->sge.qs[qidx]);
+				return err;
+			}
+			qidx++;
+		}
+	}
+	return 0;
+}
+
+/**
+ *	setup_rss - configure RSS
+ *	@adap: the adapter
+ *
+ *	Sets up RSS to distribute packets to multiple receive queues.  We
+ *	configure the RSS CPU lookup table to distribute to the number of HW
+ *	receive queues, and the response queue lookup table to narrow that
+ *	down to the response queues actually configured for each port.
+ *	We always configure the RSS mapping for two ports since the mapping
+ *	table has plenty of entries.
+ */
+static void setup_rss(struct adapter *adap)
+{
+	int i;
+	unsigned int nq0 = adap2pinfo(adap, 0)->nqsets;
+	unsigned int nq1 = adap->port[1] ? adap2pinfo(adap, 1)->nqsets : 1;
+	u8 cpus[SGE_QSETS + 1];
+	u16 rspq_map[RSS_TABLE_SIZE];
+
+	for (i = 0; i < SGE_QSETS; ++i)
+		cpus[i] = i;
+	cpus[SGE_QSETS] = 0xff;	/* terminator */
+
+	for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
+		rspq_map[i] = i % nq0;
+		rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq1) + nq0;
+	}
+
+	t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
+		      F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN |
+		      V_RRCPLCPUSIZE(6), cpus, rspq_map);
+}
+
+/*
+ * If we have multiple receive queues per port serviced by NAPI we need one
+ * netdevice per queue as NAPI operates on netdevices.  We already have one
+ * netdevice, namely the one associated with the interface, so we use dummy
+ * ones for any additional queues.  Note that these netdevices exist purely
+ * so that NAPI has something to work with, they do not represent network
+ * ports and are not registered.
+ */
+static int init_dummy_netdevs(struct adapter *adap)
+{
+	int i, j, dummy_idx = 0;
+	struct net_device *nd;
+
+	for_each_port(adap, i) {
+		struct net_device *dev = adap->port[i];
+		const struct port_info *pi = netdev_priv(dev);
+
+		for (j = 0; j < pi->nqsets - 1; j++) {
+			if (!adap->dummy_netdev[dummy_idx]) {
+				nd = alloc_netdev(0, "", ether_setup);
+				if (!nd)
+					goto free_all;
+
+				nd->priv = adap;
+				nd->weight = 64;
+				set_bit(__LINK_STATE_START, &nd->state);
+				adap->dummy_netdev[dummy_idx] = nd;
+			}
+			strcpy(adap->dummy_netdev[dummy_idx]->name, dev->name);
+			dummy_idx++;
+		}
+	}
+	return 0;
+
+free_all:
+	while (--dummy_idx >= 0) {
+		free_netdev(adap->dummy_netdev[dummy_idx]);
+		adap->dummy_netdev[dummy_idx] = NULL;
+	}
+	return -ENOMEM;
+}
+
+/*
+ * Wait until all NAPI handlers are descheduled.  This includes the handlers of
+ * both netdevices representing interfaces and the dummy ones for the extra
+ * queues.
+ */
+static void quiesce_rx(struct adapter *adap)
+{
+	int i;
+	struct net_device *dev;
+
+	for_each_port(adap, i) {
+		dev = adap->port[i];
+		while (test_bit(__LINK_STATE_RX_SCHED, &dev->state))
+			msleep(1);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(adap->dummy_netdev); i++) {
+		dev = adap->dummy_netdev[i];
+		if (dev)
+			while (test_bit(__LINK_STATE_RX_SCHED, &dev->state))
+				msleep(1);
+	}
+}
+
+/**
+ *	setup_sge_qsets - configure SGE Tx/Rx/response queues
+ *	@adap: the adapter
+ *
+ *	Determines how many sets of SGE queues to use and initializes them.
+ *	We support multiple queue sets per port if we have MSI-X, otherwise
+ *	just one queue set per port.
+ */
+static int setup_sge_qsets(struct adapter *adap)
+{
+	int i, j, err, irq_idx = 0, qset_idx = 0, dummy_dev_idx = 0;
+	unsigned int ntxq = is_offload(adap) ? SGE_TXQ_PER_SET : 1;
+
+	if (adap->params.rev > 0 && !(adap->flags & USING_MSI))
+		irq_idx = -1;
+
+	for_each_port(adap, i) {
+		struct net_device *dev = adap->port[i];
+		const struct port_info *pi = netdev_priv(dev);
+
+		for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
+			err = t3_sge_alloc_qset(adap, qset_idx, 1,
+				(adap->flags & USING_MSIX) ? qset_idx + 1 :
+							     irq_idx,
+				&adap->params.sge.qset[qset_idx], ntxq,
+				j == 0 ? dev :
+					 adap-> dummy_netdev[dummy_dev_idx++]);
+			if (err) {
+				t3_free_sge_resources(adap);
+				return err;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static ssize_t attr_show(struct device *d, struct device_attribute *attr,
+			 char *buf,
+			 ssize_t(*format) (struct adapter *, char *))
+{
+	ssize_t len;
+	struct adapter *adap = to_net_dev(d)->priv;
+
+	/* Synchronize with ioctls that may shut down the device */
+	rtnl_lock();
+	len = (*format) (adap, buf);
+	rtnl_unlock();
+	return len;
+}
+
+static ssize_t attr_store(struct device *d, struct device_attribute *attr,
+			  const char *buf, size_t len,
+			  ssize_t(*set) (struct adapter *, unsigned int),
+			  unsigned int min_val, unsigned int max_val)
+{
+	char *endp;
+	ssize_t ret;
+	unsigned int val;
+	struct adapter *adap = to_net_dev(d)->priv;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	val = simple_strtoul(buf, &endp, 0);
+	if (endp == buf || val < min_val || val > max_val)
+		return -EINVAL;
+
+	rtnl_lock();
+	ret = (*set) (adap, val);
+	if (!ret)
+		ret = len;
+	rtnl_unlock();
+	return ret;
+}
+
+#define CXGB3_SHOW(name, val_expr) \
+static ssize_t format_##name(struct adapter *adap, char *buf) \
+{ \
+	return sprintf(buf, "%u\n", val_expr); \
+} \
+static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
+			   char *buf) \
+{ \
+	return attr_show(d, attr, buf, format_##name); \
+}
+
+static ssize_t set_nfilters(struct adapter *adap, unsigned int val)
+{
+	if (adap->flags & FULL_INIT_DONE)
+		return -EBUSY;
+	if (val && adap->params.rev == 0)
+		return -EINVAL;
+	if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers)
+		return -EINVAL;
+	adap->params.mc5.nfilters = val;
+	return 0;
+}
+
+static ssize_t store_nfilters(struct device *d, struct device_attribute *attr,
+			      const char *buf, size_t len)
+{
+	return attr_store(d, attr, buf, len, set_nfilters, 0, ~0);
+}
+
+static ssize_t set_nservers(struct adapter *adap, unsigned int val)
+{
+	if (adap->flags & FULL_INIT_DONE)
+		return -EBUSY;
+	if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nfilters)
+		return -EINVAL;
+	adap->params.mc5.nservers = val;
+	return 0;
+}
+
+static ssize_t store_nservers(struct device *d, struct device_attribute *attr,
+			      const char *buf, size_t len)
+{
+	return attr_store(d, attr, buf, len, set_nservers, 0, ~0);
+}
+
+#define CXGB3_ATTR_R(name, val_expr) \
+CXGB3_SHOW(name, val_expr) \
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+
+#define CXGB3_ATTR_RW(name, val_expr, store_method) \
+CXGB3_SHOW(name, val_expr) \
+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method)
+
+CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5));
+CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters);
+CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers);
+
+static struct attribute *cxgb3_attrs[] = {
+	&dev_attr_cam_size.attr,
+	&dev_attr_nfilters.attr,
+	&dev_attr_nservers.attr,
+	NULL
+};
+
+static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs };
+
+static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr,
+			    char *buf, int sched)
+{
+	ssize_t len;
+	unsigned int v, addr, bpt, cpt;
+	struct adapter *adap = to_net_dev(d)->priv;
+
+	addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
+	rtnl_lock();
+	t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
+	v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
+	if (sched & 1)
+		v >>= 16;
+	bpt = (v >> 8) & 0xff;
+	cpt = v & 0xff;
+	if (!cpt)
+		len = sprintf(buf, "disabled\n");
+	else {
+		v = (adap->params.vpd.cclk * 1000) / cpt;
+		len = sprintf(buf, "%u Kbps\n", (v * bpt) / 125);
+	}
+	rtnl_unlock();
+	return len;
+}
+
+static ssize_t tm_attr_store(struct device *d, struct device_attribute *attr,
+			     const char *buf, size_t len, int sched)
+{
+	char *endp;
+	ssize_t ret;
+	unsigned int val;
+	struct adapter *adap = to_net_dev(d)->priv;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	val = simple_strtoul(buf, &endp, 0);
+	if (endp == buf || val > 10000000)
+		return -EINVAL;
+
+	rtnl_lock();
+	ret = t3_config_sched(adap, val, sched);
+	if (!ret)
+		ret = len;
+	rtnl_unlock();
+	return ret;
+}
+
+#define TM_ATTR(name, sched) \
+static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
+			   char *buf) \
+{ \
+	return tm_attr_show(d, attr, buf, sched); \
+} \
+static ssize_t store_##name(struct device *d, struct device_attribute *attr, \
+			    const char *buf, size_t len) \
+{ \
+	return tm_attr_store(d, attr, buf, len, sched); \
+} \
+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name)
+
+TM_ATTR(sched0, 0);
+TM_ATTR(sched1, 1);
+TM_ATTR(sched2, 2);
+TM_ATTR(sched3, 3);
+TM_ATTR(sched4, 4);
+TM_ATTR(sched5, 5);
+TM_ATTR(sched6, 6);
+TM_ATTR(sched7, 7);
+
+static struct attribute *offload_attrs[] = {
+	&dev_attr_sched0.attr,
+	&dev_attr_sched1.attr,
+	&dev_attr_sched2.attr,
+	&dev_attr_sched3.attr,
+	&dev_attr_sched4.attr,
+	&dev_attr_sched5.attr,
+	&dev_attr_sched6.attr,
+	&dev_attr_sched7.attr,
+	NULL
+};
+
+static struct attribute_group offload_attr_group = {.attrs = offload_attrs };
+
+/*
+ * Sends an sk_buff to an offload queue driver
+ * after dealing with any active network taps.
+ */
+static inline int offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
+{
+	int ret;
+
+	local_bh_disable();
+	ret = t3_offload_tx(tdev, skb);
+	local_bh_enable();
+	return ret;
+}
+
+static int write_smt_entry(struct adapter *adapter, int idx)
+{
+	struct cpl_smt_write_req *req;
+	struct sk_buff *skb = alloc_skb(sizeof(*req), GFP_KERNEL);
+
+	if (!skb)
+		return -ENOMEM;
+
+	req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
+	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
+	req->mtu_idx = NMTUS - 1;	/* should be 0 but there's a T3 bug */
+	req->iff = idx;
+	memset(req->src_mac1, 0, sizeof(req->src_mac1));
+	memcpy(req->src_mac0, adapter->port[idx]->dev_addr, ETH_ALEN);
+	skb->priority = 1;
+	offload_tx(&adapter->tdev, skb);
+	return 0;
+}
+
+static int init_smt(struct adapter *adapter)
+{
+	int i;
+
+	for_each_port(adapter, i)
+	    write_smt_entry(adapter, i);
+	return 0;
+}
+
+static void init_port_mtus(struct adapter *adapter)
+{
+	unsigned int mtus = adapter->port[0]->mtu;
+
+	if (adapter->port[1])
+		mtus |= adapter->port[1]->mtu << 16;
+	t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
+}
+
+static void send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
+			      int hi, int port)
+{
+	struct sk_buff *skb;
+	struct mngt_pktsched_wr *req;
+
+	skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
+	req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req));
+	req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
+	req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
+	req->sched = sched;
+	req->idx = qidx;
+	req->min = lo;
+	req->max = hi;
+	req->binding = port;
+	t3_mgmt_tx(adap, skb);
+}
+
+static void bind_qsets(struct adapter *adap)
+{
+	int i, j;
+
+	for_each_port(adap, i) {
+		const struct port_info *pi = adap2pinfo(adap, i);
+
+		for (j = 0; j < pi->nqsets; ++j)
+			send_pktsched_cmd(adap, 1, pi->first_qset + j, -1,
+					  -1, i);
+	}
+}
+
+/**
+ *	cxgb_up - enable the adapter
+ *	@adapter: adapter being enabled
+ *
+ *	Called when the first port is enabled, this function performs the
+ *	actions necessary to make an adapter operational, such as completing
+ *	the initialization of HW modules, and enabling interrupts.
+ *
+ *	Must be called with the rtnl lock held.
+ */
+static int cxgb_up(struct adapter *adap)
+{
+	int err = 0;
+
+	if (!(adap->flags & FULL_INIT_DONE)) {
+		err = t3_check_fw_version(adap);
+		if (err)
+			goto out;
+
+		err = init_dummy_netdevs(adap);
+		if (err)
+			goto out;
+
+		err = t3_init_hw(adap, 0);
+		if (err)
+			goto out;
+
+		err = setup_sge_qsets(adap);
+		if (err)
+			goto out;
+
+		setup_rss(adap);
+		adap->flags |= FULL_INIT_DONE;
+	}
+
+	t3_intr_clear(adap);
+
+	if (adap->flags & USING_MSIX) {
+		name_msix_vecs(adap);
+		err = request_irq(adap->msix_info[0].vec,
+				  t3_async_intr_handler, 0,
+				  adap->msix_info[0].desc, adap);
+		if (err)
+			goto irq_err;
+
+		if (request_msix_data_irqs(adap)) {
+			free_irq(adap->msix_info[0].vec, adap);
+			goto irq_err;
+		}
+	} else if ((err = request_irq(adap->pdev->irq,
+				      t3_intr_handler(adap,
+						      adap->sge.qs[0].rspq.
+						      polling),
+				      (adap->flags & USING_MSI) ? 0 : SA_SHIRQ,
+				      adap->name, adap)))
+		goto irq_err;
+
+	t3_sge_start(adap);
+	t3_intr_enable(adap);
+
+	if ((adap->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX)
+		bind_qsets(adap);
+	adap->flags |= QUEUES_BOUND;
+
+out:
+	return err;
+irq_err:
+	CH_ERR(adap, "request_irq failed, err %d\n", err);
+	goto out;
+}
+
+/*
+ * Release resources when all the ports and offloading have been stopped.
+ */
+static void cxgb_down(struct adapter *adapter)
+{
+	t3_sge_stop(adapter);
+	spin_lock_irq(&adapter->work_lock);	/* sync with PHY intr task */
+	t3_intr_disable(adapter);
+	spin_unlock_irq(&adapter->work_lock);
+
+	if (adapter->flags & USING_MSIX) {
+		int i, n = 0;
+
+		free_irq(adapter->msix_info[0].vec, adapter);
+		for_each_port(adapter, i)
+		    n += adap2pinfo(adapter, i)->nqsets;
+
+		for (i = 0; i < n; ++i)
+			free_irq(adapter->msix_info[i + 1].vec,
+				 &adapter->sge.qs[i]);
+	} else
+		free_irq(adapter->pdev->irq, adapter);
+
+	flush_workqueue(cxgb3_wq);	/* wait for external IRQ handler */
+	quiesce_rx(adapter);
+}
+
+static void schedule_chk_task(struct adapter *adap)
+{
+	unsigned int timeo;
+
+	timeo = adap->params.linkpoll_period ?
+	    (HZ * adap->params.linkpoll_period) / 10 :
+	    adap->params.stats_update_period * HZ;
+	if (timeo)
+		queue_delayed_work(cxgb3_wq, &adap->adap_check_task, timeo);
+}
+
+static int offload_open(struct net_device *dev)
+{
+	struct adapter *adapter = dev->priv;
+	struct t3cdev *tdev = T3CDEV(dev);
+	int adap_up = adapter->open_device_map & PORT_MASK;
+	int err = 0;
+
+	if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
+		return 0;
+
+	if (!adap_up && (err = cxgb_up(adapter)) < 0)
+		return err;
+
+	t3_tp_set_offload_mode(adapter, 1);
+	tdev->lldev = adapter->port[0];
+	err = cxgb3_offload_activate(adapter);
+	if (err)
+		goto out;
+
+	init_port_mtus(adapter);
+	t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
+		     adapter->params.b_wnd,
+		     adapter->params.rev == 0 ?
+		     adapter->port[0]->mtu : 0xffff);
+	init_smt(adapter);
+
+	/* Never mind if the next step fails */
+	sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group);
+
+	/* Call back all registered clients */
+	cxgb3_add_clients(tdev);
+
+out:
+	/* restore them in case the offload module has changed them */
+	if (err) {
+		t3_tp_set_offload_mode(adapter, 0);
+		clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
+		cxgb3_set_dummy_ops(tdev);
+	}
+	return err;
+}
+
+static int offload_close(struct t3cdev *tdev)
+{
+	struct adapter *adapter = tdev2adap(tdev);
+
+	if (!test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
+		return 0;
+
+	/* Call back all registered clients */
+	cxgb3_remove_clients(tdev);
+
+	sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group);
+
+	tdev->lldev = NULL;
+	cxgb3_set_dummy_ops(tdev);
+	t3_tp_set_offload_mode(adapter, 0);
+	clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
+
+	if (!adapter->open_device_map)
+		cxgb_down(adapter);
+
+	cxgb3_offload_deactivate(adapter);
+	return 0;
+}
+
+static int cxgb_open(struct net_device *dev)
+{
+	int err;
+	struct adapter *adapter = dev->priv;
+	struct port_info *pi = netdev_priv(dev);
+	int other_ports = adapter->open_device_map & PORT_MASK;
+
+	if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
+		return err;
+
+	set_bit(pi->port_id, &adapter->open_device_map);
+	if (!ofld_disable) {
+		err = offload_open(dev);
+		if (err)
+			printk(KERN_WARNING
+			       "Could not initialize offload capabilities\n");
+	}
+
+	link_start(dev);
+	t3_port_intr_enable(adapter, pi->port_id);
+	netif_start_queue(dev);
+	if (!other_ports)
+		schedule_chk_task(adapter);
+
+	return 0;
+}
+
+static int cxgb_close(struct net_device *dev)
+{
+	struct adapter *adapter = dev->priv;
+	struct port_info *p = netdev_priv(dev);
+
+	t3_port_intr_disable(adapter, p->port_id);
+	netif_stop_queue(dev);
+	p->phy.ops->power_down(&p->phy, 1);
+	netif_carrier_off(dev);
+	t3_mac_disable(&p->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
+
+	spin_lock(&adapter->work_lock);	/* sync with update task */
+	clear_bit(p->port_id, &adapter->open_device_map);
+	spin_unlock(&adapter->work_lock);
+
+	if (!(adapter->open_device_map & PORT_MASK))
+		cancel_rearming_delayed_workqueue(cxgb3_wq,
+						  &adapter->adap_check_task);
+
+	if (!adapter->open_device_map)
+		cxgb_down(adapter);
+
+	return 0;
+}
+
+static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
+{
+	struct adapter *adapter = dev->priv;
+	struct port_info *p = netdev_priv(dev);
+	struct net_device_stats *ns = &p->netstats;
+	const struct mac_stats *pstats;
+
+	spin_lock(&adapter->stats_lock);
+	pstats = t3_mac_update_stats(&p->mac);
+	spin_unlock(&adapter->stats_lock);
+
+	ns->tx_bytes = pstats->tx_octets;
+	ns->tx_packets = pstats->tx_frames;
+	ns->rx_bytes = pstats->rx_octets;
+	ns->rx_packets = pstats->rx_frames;
+	ns->multicast = pstats->rx_mcast_frames;
+
+	ns->tx_errors = pstats->tx_underrun;
+	ns->rx_errors = pstats->rx_symbol_errs + pstats->rx_fcs_errs +
+	    pstats->rx_too_long + pstats->rx_jabber + pstats->rx_short +
+	    pstats->rx_fifo_ovfl;
+
+	/* detailed rx_errors */
+	ns->rx_length_errors = pstats->rx_jabber + pstats->rx_too_long;
+	ns->rx_over_errors = 0;
+	ns->rx_crc_errors = pstats->rx_fcs_errs;
+	ns->rx_frame_errors = pstats->rx_symbol_errs;
+	ns->rx_fifo_errors = pstats->rx_fifo_ovfl;
+	ns->rx_missed_errors = pstats->rx_cong_drops;
+
+	/* detailed tx_errors */
+	ns->tx_aborted_errors = 0;
+	ns->tx_carrier_errors = 0;
+	ns->tx_fifo_errors = pstats->tx_underrun;
+	ns->tx_heartbeat_errors = 0;
+	ns->tx_window_errors = 0;
+	return ns;
+}
+
+static u32 get_msglevel(struct net_device *dev)
+{
+	struct adapter *adapter = dev->priv;
+
+	return adapter->msg_enable;
+}
+
+static void set_msglevel(struct net_device *dev, u32 val)
+{
+	struct adapter *adapter = dev->priv;
+
+	adapter->msg_enable = val;
+}
+
+static char stats_strings[][ETH_GSTRING_LEN] = {
+	"TxOctetsOK         ",
+	"TxFramesOK         ",
+	"TxMulticastFramesOK",
+	"TxBroadcastFramesOK",
+	"TxPauseFrames      ",
+	"TxUnderrun         ",
+	"TxExtUnderrun      ",
+
+	"TxFrames64         ",
+	"TxFrames65To127    ",
+	"TxFrames128To255   ",
+	"TxFrames256To511   ",
+	"TxFrames512To1023  ",
+	"TxFrames1024To1518 ",
+	"TxFrames1519ToMax  ",
+
+	"RxOctetsOK         ",
+	"RxFramesOK         ",
+	"RxMulticastFramesOK",
+	"RxBroadcastFramesOK",
+	"RxPauseFrames      ",
+	"RxFCSErrors        ",
+	"RxSymbolErrors     ",
+	"RxShortErrors      ",
+	"RxJabberErrors     ",
+	"RxLengthErrors     ",
+	"RxFIFOoverflow     ",
+
+	"RxFrames64         ",
+	"RxFrames65To127    ",
+	"RxFrames128To255   ",
+	"RxFrames256To511   ",
+	"RxFrames512To1023  ",
+	"RxFrames1024To1518 ",
+	"RxFrames1519ToMax  ",
+
+	"PhyFIFOErrors      ",
+	"TSO                ",
+	"VLANextractions    ",
+	"VLANinsertions     ",
+	"TxCsumOffload      ",
+	"RxCsumGood         ",
+	"RxDrops            "
+};
+
+static int get_stats_count(struct net_device *dev)
+{
+	return ARRAY_SIZE(stats_strings);
+}
+
+#define T3_REGMAP_SIZE (3 * 1024)
+
+static int get_regs_len(struct net_device *dev)
+{
+	return T3_REGMAP_SIZE;
+}
+
+static int get_eeprom_len(struct net_device *dev)
+{
+	return EEPROMSIZE;
+}
+
+static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	u32 fw_vers = 0;
+	struct adapter *adapter = dev->priv;
+
+	t3_get_fw_version(adapter, &fw_vers);
+
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->bus_info, pci_name(adapter->pdev));
+	if (!fw_vers)
+		strcpy(info->fw_version, "N/A");
+	else {
+		snprintf(info->fw_version, sizeof(info->fw_version),
+			 "%s %u.%u.%u",
+			 G_FW_VERSION_TYPE(fw_vers) ? "T" : "N",
+			 G_FW_VERSION_MAJOR(fw_vers),
+			 G_FW_VERSION_MINOR(fw_vers),
+			 G_FW_VERSION_MICRO(fw_vers));
+	}
+}
+
+static void get_strings(struct net_device *dev, u32 stringset, u8 * data)
+{
+	if (stringset == ETH_SS_STATS)
+		memcpy(data, stats_strings, sizeof(stats_strings));
+}
+
+static unsigned long collect_sge_port_stats(struct adapter *adapter,
+					    struct port_info *p, int idx)
+{
+	int i;
+	unsigned long tot = 0;
+
+	for (i = 0; i < p->nqsets; ++i)
+		tot += adapter->sge.qs[i + p->first_qset].port_stats[idx];
+	return tot;
+}
+
+static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
+		      u64 *data)
+{
+	struct adapter *adapter = dev->priv;
+	struct port_info *pi = netdev_priv(dev);
+	const struct mac_stats *s;
+
+	spin_lock(&adapter->stats_lock);
+	s = t3_mac_update_stats(&pi->mac);
+	spin_unlock(&adapter->stats_lock);
+
+	*data++ = s->tx_octets;
+	*data++ = s->tx_frames;
+	*data++ = s->tx_mcast_frames;
+	*data++ = s->tx_bcast_frames;
+	*data++ = s->tx_pause;
+	*data++ = s->tx_underrun;
+	*data++ = s->tx_fifo_urun;
+
+	*data++ = s->tx_frames_64;
+	*data++ = s->tx_frames_65_127;
+	*data++ = s->tx_frames_128_255;
+	*data++ = s->tx_frames_256_511;
+	*data++ = s->tx_frames_512_1023;
+	*data++ = s->tx_frames_1024_1518;
+	*data++ = s->tx_frames_1519_max;
+
+	*data++ = s->rx_octets;
+	*data++ = s->rx_frames;
+	*data++ = s->rx_mcast_frames;
+	*data++ = s->rx_bcast_frames;
+	*data++ = s->rx_pause;
+	*data++ = s->rx_fcs_errs;
+	*data++ = s->rx_symbol_errs;
+	*data++ = s->rx_short;
+	*data++ = s->rx_jabber;
+	*data++ = s->rx_too_long;
+	*data++ = s->rx_fifo_ovfl;
+
+	*data++ = s->rx_frames_64;
+	*data++ = s->rx_frames_65_127;
+	*data++ = s->rx_frames_128_255;
+	*data++ = s->rx_frames_256_511;
+	*data++ = s->rx_frames_512_1023;
+	*data++ = s->rx_frames_1024_1518;
+	*data++ = s->rx_frames_1519_max;
+
+	*data++ = pi->phy.fifo_errors;
+
+	*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TSO);
+	*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANEX);
+	*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS);
+	*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM);
+	*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD);
+	*data++ = s->rx_cong_drops;
+}
+
+static inline void reg_block_dump(struct adapter *ap, void *buf,
+				  unsigned int start, unsigned int end)
+{
+	u32 *p = buf + start;
+
+	for (; start <= end; start += sizeof(u32))
+		*p++ = t3_read_reg(ap, start);
+}
+
+static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
+		     void *buf)
+{
+	struct adapter *ap = dev->priv;
+
+	/*
+	 * Version scheme:
+	 * bits 0..9: chip version
+	 * bits 10..15: chip revision
+	 * bit 31: set for PCIe cards
+	 */
+	regs->version = 3 | (ap->params.rev << 10) | (is_pcie(ap) << 31);
+
+	/*
+	 * We skip the MAC statistics registers because they are clear-on-read.
+	 * Also reading multi-register stats would need to synchronize with the
+	 * periodic mac stats accumulation.  Hard to justify the complexity.
+	 */
+	memset(buf, 0, T3_REGMAP_SIZE);
+	reg_block_dump(ap, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
+	reg_block_dump(ap, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
+	reg_block_dump(ap, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
+	reg_block_dump(ap, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
+	reg_block_dump(ap, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
+	reg_block_dump(ap, buf, A_XGM_SERDES_STATUS0,
+		       XGM_REG(A_XGM_SERDES_STAT3, 1));
+	reg_block_dump(ap, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
+		       XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
+}
+
+static int restart_autoneg(struct net_device *dev)
+{
+	struct port_info *p = netdev_priv(dev);
+
+	if (!netif_running(dev))
+		return -EAGAIN;
+	if (p->link_config.autoneg != AUTONEG_ENABLE)
+		return -EINVAL;
+	p->phy.ops->autoneg_restart(&p->phy);
+	return 0;
+}
+
+static int cxgb3_phys_id(struct net_device *dev, u32 data)
+{
+	int i;
+	struct adapter *adapter = dev->priv;
+
+	if (data == 0)
+		data = 2;
+
+	for (i = 0; i < data * 2; i++) {
+		t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
+				 (i & 1) ? F_GPIO0_OUT_VAL : 0);
+		if (msleep_interruptible(500))
+			break;
+	}
+	t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
+			 F_GPIO0_OUT_VAL);
+	return 0;
+}
+
+static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct port_info *p = netdev_priv(dev);
+
+	cmd->supported = p->link_config.supported;
+	cmd->advertising = p->link_config.advertising;
+
+	if (netif_carrier_ok(dev)) {
+		cmd->speed = p->link_config.speed;
+		cmd->duplex = p->link_config.duplex;
+	} else {
+		cmd->speed = -1;
+		cmd->duplex = -1;
+	}
+
+	cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
+	cmd->phy_address = p->phy.addr;
+	cmd->transceiver = XCVR_EXTERNAL;
+	cmd->autoneg = p->link_config.autoneg;
+	cmd->maxtxpkt = 0;
+	cmd->maxrxpkt = 0;
+	return 0;
+}
+
+static int speed_duplex_to_caps(int speed, int duplex)
+{
+	int cap = 0;
+
+	switch (speed) {
+	case SPEED_10:
+		if (duplex == DUPLEX_FULL)
+			cap = SUPPORTED_10baseT_Full;
+		else
+			cap = SUPPORTED_10baseT_Half;
+		break;
+	case SPEED_100:
+		if (duplex == DUPLEX_FULL)
+			cap = SUPPORTED_100baseT_Full;
+		else
+			cap = SUPPORTED_100baseT_Half;
+		break;
+	case SPEED_1000:
+		if (duplex == DUPLEX_FULL)
+			cap = SUPPORTED_1000baseT_Full;
+		else
+			cap = SUPPORTED_1000baseT_Half;
+		break;
+	case SPEED_10000:
+		if (duplex == DUPLEX_FULL)
+			cap = SUPPORTED_10000baseT_Full;
+	}
+	return cap;
+}
+
+#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
+		      ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
+		      ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \
+		      ADVERTISED_10000baseT_Full)
+
+static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct port_info *p = netdev_priv(dev);
+	struct link_config *lc = &p->link_config;
+
+	if (!(lc->supported & SUPPORTED_Autoneg))
+		return -EOPNOTSUPP;	/* can't change speed/duplex */
+
+	if (cmd->autoneg == AUTONEG_DISABLE) {
+		int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
+
+		if (!(lc->supported & cap) || cmd->speed == SPEED_1000)
+			return -EINVAL;
+		lc->requested_speed = cmd->speed;
+		lc->requested_duplex = cmd->duplex;
+		lc->advertising = 0;
+	} else {
+		cmd->advertising &= ADVERTISED_MASK;
+		cmd->advertising &= lc->supported;
+		if (!cmd->advertising)
+			return -EINVAL;
+		lc->requested_speed = SPEED_INVALID;
+		lc->requested_duplex = DUPLEX_INVALID;
+		lc->advertising = cmd->advertising | ADVERTISED_Autoneg;
+	}
+	lc->autoneg = cmd->autoneg;
+	if (netif_running(dev))
+		t3_link_start(&p->phy, &p->mac, lc);
+	return 0;
+}
+
+static void get_pauseparam(struct net_device *dev,
+			   struct ethtool_pauseparam *epause)
+{
+	struct port_info *p = netdev_priv(dev);
+
+	epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0;
+	epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0;
+	epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0;
+}
+
+static int set_pauseparam(struct net_device *dev,
+			  struct ethtool_pauseparam *epause)
+{
+	struct port_info *p = netdev_priv(dev);
+	struct link_config *lc = &p->link_config;
+
+	if (epause->autoneg == AUTONEG_DISABLE)
+		lc->requested_fc = 0;
+	else if (lc->supported & SUPPORTED_Autoneg)
+		lc->requested_fc = PAUSE_AUTONEG;
+	else
+		return -EINVAL;
+
+	if (epause->rx_pause)
+		lc->requested_fc |= PAUSE_RX;
+	if (epause->tx_pause)
+		lc->requested_fc |= PAUSE_TX;
+	if (lc->autoneg == AUTONEG_ENABLE) {
+		if (netif_running(dev))
+			t3_link_start(&p->phy, &p->mac, lc);
+	} else {
+		lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+		if (netif_running(dev))
+			t3_mac_set_speed_duplex_fc(&p->mac, -1, -1, lc->fc);
+	}
+	return 0;
+}
+
+static u32 get_rx_csum(struct net_device *dev)
+{
+	struct port_info *p = netdev_priv(dev);
+
+	return p->rx_csum_offload;
+}
+
+static int set_rx_csum(struct net_device *dev, u32 data)
+{
+	struct port_info *p = netdev_priv(dev);
+
+	p->rx_csum_offload = data;
+	return 0;
+}
+
+static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
+{
+	struct adapter *adapter = dev->priv;
+
+	e->rx_max_pending = MAX_RX_BUFFERS;
+	e->rx_mini_max_pending = 0;
+	e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS;
+	e->tx_max_pending = MAX_TXQ_ENTRIES;
+
+	e->rx_pending = adapter->params.sge.qset[0].fl_size;
+	e->rx_mini_pending = adapter->params.sge.qset[0].rspq_size;
+	e->rx_jumbo_pending = adapter->params.sge.qset[0].jumbo_size;
+	e->tx_pending = adapter->params.sge.qset[0].txq_size[0];
+}
+
+static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
+{
+	int i;
+	struct adapter *adapter = dev->priv;
+
+	if (e->rx_pending > MAX_RX_BUFFERS ||
+	    e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS ||
+	    e->tx_pending > MAX_TXQ_ENTRIES ||
+	    e->rx_mini_pending > MAX_RSPQ_ENTRIES ||
+	    e->rx_mini_pending < MIN_RSPQ_ENTRIES ||
+	    e->rx_pending < MIN_FL_ENTRIES ||
+	    e->rx_jumbo_pending < MIN_FL_ENTRIES ||
+	    e->tx_pending < adapter->params.nports * MIN_TXQ_ENTRIES)
+		return -EINVAL;
+
+	if (adapter->flags & FULL_INIT_DONE)
+		return -EBUSY;
+
+	for (i = 0; i < SGE_QSETS; ++i) {
+		struct qset_params *q = &adapter->params.sge.qset[i];
+
+		q->rspq_size = e->rx_mini_pending;
+		q->fl_size = e->rx_pending;
+		q->jumbo_size = e->rx_jumbo_pending;
+		q->txq_size[0] = e->tx_pending;
+		q->txq_size[1] = e->tx_pending;
+		q->txq_size[2] = e->tx_pending;
+	}
+	return 0;
+}
+
+static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
+{
+	struct adapter *adapter = dev->priv;
+	struct qset_params *qsp = &adapter->params.sge.qset[0];
+	struct sge_qset *qs = &adapter->sge.qs[0];
+
+	if (c->rx_coalesce_usecs * 10 > M_NEWTIMER)
+		return -EINVAL;
+
+	qsp->coalesce_usecs = c->rx_coalesce_usecs;
+	t3_update_qset_coalesce(qs, qsp);
+	return 0;
+}
+
+static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
+{
+	struct adapter *adapter = dev->priv;
+	struct qset_params *q = adapter->params.sge.qset;
+
+	c->rx_coalesce_usecs = q->coalesce_usecs;
+	return 0;
+}
+
+static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
+		      u8 * data)
+{
+	int i, err = 0;
+	struct adapter *adapter = dev->priv;
+
+	u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	e->magic = EEPROM_MAGIC;
+	for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4)
+		err = t3_seeprom_read(adapter, i, (u32 *) & buf[i]);
+
+	if (!err)
+		memcpy(data, buf + e->offset, e->len);
+	kfree(buf);
+	return err;
+}
+
+static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+		      u8 * data)
+{
+	u8 *buf;
+	int err = 0;
+	u32 aligned_offset, aligned_len, *p;
+	struct adapter *adapter = dev->priv;
+
+	if (eeprom->magic != EEPROM_MAGIC)
+		return -EINVAL;
+
+	aligned_offset = eeprom->offset & ~3;
+	aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3;
+
+	if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) {
+		buf = kmalloc(aligned_len, GFP_KERNEL);
+		if (!buf)
+			return -ENOMEM;
+		err = t3_seeprom_read(adapter, aligned_offset, (u32 *) buf);
+		if (!err && aligned_len > 4)
+			err = t3_seeprom_read(adapter,
+					      aligned_offset + aligned_len - 4,
+					      (u32 *) & buf[aligned_len - 4]);
+		if (err)
+			goto out;
+		memcpy(buf + (eeprom->offset & 3), data, eeprom->len);
+	} else
+		buf = data;
+
+	err = t3_seeprom_wp(adapter, 0);
+	if (err)
+		goto out;
+
+	for (p = (u32 *) buf; !err && aligned_len; aligned_len -= 4, p++) {
+		err = t3_seeprom_write(adapter, aligned_offset, *p);
+		aligned_offset += 4;
+	}
+
+	if (!err)
+		err = t3_seeprom_wp(adapter, 1);
+out:
+	if (buf != data)
+		kfree(buf);
+	return err;
+}
+
+static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	wol->supported = 0;
+	wol->wolopts = 0;
+	memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+
+static const struct ethtool_ops cxgb_ethtool_ops = {
+	.get_settings = get_settings,
+	.set_settings = set_settings,
+	.get_drvinfo = get_drvinfo,
+	.get_msglevel = get_msglevel,
+	.set_msglevel = set_msglevel,
+	.get_ringparam = get_sge_param,
+	.set_ringparam = set_sge_param,
+	.get_coalesce = get_coalesce,
+	.set_coalesce = set_coalesce,
+	.get_eeprom_len = get_eeprom_len,
+	.get_eeprom = get_eeprom,
+	.set_eeprom = set_eeprom,
+	.get_pauseparam = get_pauseparam,
+	.set_pauseparam = set_pauseparam,
+	.get_rx_csum = get_rx_csum,
+	.set_rx_csum = set_rx_csum,
+	.get_tx_csum = ethtool_op_get_tx_csum,
+	.set_tx_csum = ethtool_op_set_tx_csum,
+	.get_sg = ethtool_op_get_sg,
+	.set_sg = ethtool_op_set_sg,
+	.get_link = ethtool_op_get_link,
+	.get_strings = get_strings,
+	.phys_id = cxgb3_phys_id,
+	.nway_reset = restart_autoneg,
+	.get_stats_count = get_stats_count,
+	.get_ethtool_stats = get_stats,
+	.get_regs_len = get_regs_len,
+	.get_regs = get_regs,
+	.get_wol = get_wol,
+	.get_tso = ethtool_op_get_tso,
+	.set_tso = ethtool_op_set_tso,
+	.get_perm_addr = ethtool_op_get_perm_addr
+};
+
+static int in_range(int val, int lo, int hi)
+{
+	return val < 0 || (val <= hi && val >= lo);
+}
+
+static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
+{
+	int ret;
+	u32 cmd;
+	struct adapter *adapter = dev->priv;
+
+	if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
+		return -EFAULT;
+
+	switch (cmd) {
+	case CHELSIO_SETREG:{
+		struct ch_reg edata;
+
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		if ((edata.addr & 3) != 0
+			|| edata.addr >= adapter->mmio_len)
+			return -EINVAL;
+		writel(edata.val, adapter->regs + edata.addr);
+		break;
+	}
+	case CHELSIO_GETREG:{
+		struct ch_reg edata;
+
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		if ((edata.addr & 3) != 0
+			|| edata.addr >= adapter->mmio_len)
+			return -EINVAL;
+		edata.val = readl(adapter->regs + edata.addr);
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		break;
+	}
+	case CHELSIO_SET_QSET_PARAMS:{
+		int i;
+		struct qset_params *q;
+		struct ch_qset_params t;
+
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (copy_from_user(&t, useraddr, sizeof(t)))
+			return -EFAULT;
+		if (t.qset_idx >= SGE_QSETS)
+			return -EINVAL;
+		if (!in_range(t.intr_lat, 0, M_NEWTIMER) ||
+			!in_range(t.cong_thres, 0, 255) ||
+			!in_range(t.txq_size[0], MIN_TXQ_ENTRIES,
+				MAX_TXQ_ENTRIES) ||
+			!in_range(t.txq_size[1], MIN_TXQ_ENTRIES,
+				MAX_TXQ_ENTRIES) ||
+			!in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES,
+				MAX_CTRL_TXQ_ENTRIES) ||
+			!in_range(t.fl_size[0], MIN_FL_ENTRIES,
+				MAX_RX_BUFFERS)
+			|| !in_range(t.fl_size[1], MIN_FL_ENTRIES,
+					MAX_RX_JUMBO_BUFFERS)
+			|| !in_range(t.rspq_size, MIN_RSPQ_ENTRIES,
+					MAX_RSPQ_ENTRIES))
+			return -EINVAL;
+		if ((adapter->flags & FULL_INIT_DONE) &&
+			(t.rspq_size >= 0 || t.fl_size[0] >= 0 ||
+			t.fl_size[1] >= 0 || t.txq_size[0] >= 0 ||
+			t.txq_size[1] >= 0 || t.txq_size[2] >= 0 ||
+			t.polling >= 0 || t.cong_thres >= 0))
+			return -EBUSY;
+
+		q = &adapter->params.sge.qset[t.qset_idx];
+
+		if (t.rspq_size >= 0)
+			q->rspq_size = t.rspq_size;
+		if (t.fl_size[0] >= 0)
+			q->fl_size = t.fl_size[0];
+		if (t.fl_size[1] >= 0)
+			q->jumbo_size = t.fl_size[1];
+		if (t.txq_size[0] >= 0)
+			q->txq_size[0] = t.txq_size[0];
+		if (t.txq_size[1] >= 0)
+			q->txq_size[1] = t.txq_size[1];
+		if (t.txq_size[2] >= 0)
+			q->txq_size[2] = t.txq_size[2];
+		if (t.cong_thres >= 0)
+			q->cong_thres = t.cong_thres;
+		if (t.intr_lat >= 0) {
+			struct sge_qset *qs =
+				&adapter->sge.qs[t.qset_idx];
+
+			q->coalesce_usecs = t.intr_lat;
+			t3_update_qset_coalesce(qs, q);
+		}
+		if (t.polling >= 0) {
+			if (adapter->flags & USING_MSIX)
+				q->polling = t.polling;
+			else {
+				/* No polling with INTx for T3A */
+				if (adapter->params.rev == 0 &&
+					!(adapter->flags & USING_MSI))
+					t.polling = 0;
+
+				for (i = 0; i < SGE_QSETS; i++) {
+					q = &adapter->params.sge.
+						qset[i];
+					q->polling = t.polling;
+				}
+			}
+		}
+		break;
+	}
+	case CHELSIO_GET_QSET_PARAMS:{
+		struct qset_params *q;
+		struct ch_qset_params t;
+
+		if (copy_from_user(&t, useraddr, sizeof(t)))
+			return -EFAULT;
+		if (t.qset_idx >= SGE_QSETS)
+			return -EINVAL;
+
+		q = &adapter->params.sge.qset[t.qset_idx];
+		t.rspq_size = q->rspq_size;
+		t.txq_size[0] = q->txq_size[0];
+		t.txq_size[1] = q->txq_size[1];
+		t.txq_size[2] = q->txq_size[2];
+		t.fl_size[0] = q->fl_size;
+		t.fl_size[1] = q->jumbo_size;
+		t.polling = q->polling;
+		t.intr_lat = q->coalesce_usecs;
+		t.cong_thres = q->cong_thres;
+
+		if (copy_to_user(useraddr, &t, sizeof(t)))
+			return -EFAULT;
+		break;
+	}
+	case CHELSIO_SET_QSET_NUM:{
+		struct ch_reg edata;
+		struct port_info *pi = netdev_priv(dev);
+		unsigned int i, first_qset = 0, other_qsets = 0;
+
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (adapter->flags & FULL_INIT_DONE)
+			return -EBUSY;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		if (edata.val < 1 ||
+			(edata.val > 1 && !(adapter->flags & USING_MSIX)))
+			return -EINVAL;
+
+		for_each_port(adapter, i)
+			if (adapter->port[i] && adapter->port[i] != dev)
+				other_qsets += adap2pinfo(adapter, i)->nqsets;
+
+		if (edata.val + other_qsets > SGE_QSETS)
+			return -EINVAL;
+
+		pi->nqsets = edata.val;
+
+		for_each_port(adapter, i)
+			if (adapter->port[i]) {
+				pi = adap2pinfo(adapter, i);
+				pi->first_qset = first_qset;
+				first_qset += pi->nqsets;
+			}
+		break;
+	}
+	case CHELSIO_GET_QSET_NUM:{
+		struct ch_reg edata;
+		struct port_info *pi = netdev_priv(dev);
+
+		edata.cmd = CHELSIO_GET_QSET_NUM;
+		edata.val = pi->nqsets;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		break;
+	}
+	case CHELSIO_LOAD_FW:{
+		u8 *fw_data;
+		struct ch_mem_range t;
+
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (copy_from_user(&t, useraddr, sizeof(t)))
+			return -EFAULT;
+
+		fw_data = kmalloc(t.len, GFP_KERNEL);
+		if (!fw_data)
+			return -ENOMEM;
+
+		if (copy_from_user
+			(fw_data, useraddr + sizeof(t), t.len)) {
+			kfree(fw_data);
+			return -EFAULT;
+		}
+
+		ret = t3_load_fw(adapter, fw_data, t.len);
+		kfree(fw_data);
+		if (ret)
+			return ret;
+		break;
+	}
+	case CHELSIO_SETMTUTAB:{
+		struct ch_mtus m;
+		int i;
+
+		if (!is_offload(adapter))
+			return -EOPNOTSUPP;
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (offload_running(adapter))
+			return -EBUSY;
+		if (copy_from_user(&m, useraddr, sizeof(m)))
+			return -EFAULT;
+		if (m.nmtus != NMTUS)
+			return -EINVAL;
+		if (m.mtus[0] < 81)	/* accommodate SACK */
+			return -EINVAL;
+
+		/* MTUs must be in ascending order */
+		for (i = 1; i < NMTUS; ++i)
+			if (m.mtus[i] < m.mtus[i - 1])
+				return -EINVAL;
+
+		memcpy(adapter->params.mtus, m.mtus,
+			sizeof(adapter->params.mtus));
+		break;
+	}
+	case CHELSIO_GET_PM:{
+		struct tp_params *p = &adapter->params.tp;
+		struct ch_pm m = {.cmd = CHELSIO_GET_PM };
+
+		if (!is_offload(adapter))
+			return -EOPNOTSUPP;
+		m.tx_pg_sz = p->tx_pg_size;
+		m.tx_num_pg = p->tx_num_pgs;
+		m.rx_pg_sz = p->rx_pg_size;
+		m.rx_num_pg = p->rx_num_pgs;
+		m.pm_total = p->pmtx_size + p->chan_rx_size * p->nchan;
+		if (copy_to_user(useraddr, &m, sizeof(m)))
+			return -EFAULT;
+		break;
+	}
+	case CHELSIO_SET_PM:{
+		struct ch_pm m;
+		struct tp_params *p = &adapter->params.tp;
+
+		if (!is_offload(adapter))
+			return -EOPNOTSUPP;
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (adapter->flags & FULL_INIT_DONE)
+			return -EBUSY;
+		if (copy_from_user(&m, useraddr, sizeof(m)))
+			return -EFAULT;
+		if (!m.rx_pg_sz || (m.rx_pg_sz & (m.rx_pg_sz - 1)) ||
+			!m.tx_pg_sz || (m.tx_pg_sz & (m.tx_pg_sz - 1)))
+			return -EINVAL;	/* not power of 2 */
+		if (!(m.rx_pg_sz & 0x14000))
+			return -EINVAL;	/* not 16KB or 64KB */
+		if (!(m.tx_pg_sz & 0x1554000))
+			return -EINVAL;
+		if (m.tx_num_pg == -1)
+			m.tx_num_pg = p->tx_num_pgs;
+		if (m.rx_num_pg == -1)
+			m.rx_num_pg = p->rx_num_pgs;
+		if (m.tx_num_pg % 24 || m.rx_num_pg % 24)
+			return -EINVAL;
+		if (m.rx_num_pg * m.rx_pg_sz > p->chan_rx_size ||
+			m.tx_num_pg * m.tx_pg_sz > p->chan_tx_size)
+			return -EINVAL;
+		p->rx_pg_size = m.rx_pg_sz;
+		p->tx_pg_size = m.tx_pg_sz;
+		p->rx_num_pgs = m.rx_num_pg;
+		p->tx_num_pgs = m.tx_num_pg;
+		break;
+	}
+	case CHELSIO_GET_MEM:{
+		struct ch_mem_range t;
+		struct mc7 *mem;
+		u64 buf[32];
+
+		if (!is_offload(adapter))
+			return -EOPNOTSUPP;
+		if (!(adapter->flags & FULL_INIT_DONE))
+			return -EIO;	/* need the memory controllers */
+		if (copy_from_user(&t, useraddr, sizeof(t)))
+			return -EFAULT;
+		if ((t.addr & 7) || (t.len & 7))
+			return -EINVAL;
+		if (t.mem_id == MEM_CM)
+			mem = &adapter->cm;
+		else if (t.mem_id == MEM_PMRX)
+			mem = &adapter->pmrx;
+		else if (t.mem_id == MEM_PMTX)
+			mem = &adapter->pmtx;
+		else
+			return -EINVAL;
+
+		/*
+			* Version scheme:
+			* bits 0..9: chip version
+			* bits 10..15: chip revision
+			*/
+		t.version = 3 | (adapter->params.rev << 10);
+		if (copy_to_user(useraddr, &t, sizeof(t)))
+			return -EFAULT;
+
+		/*
+		 * Read 256 bytes at a time as len can be large and we don't
+		 * want to use huge intermediate buffers.
+		 */
+		useraddr += sizeof(t);	/* advance to start of buffer */
+		while (t.len) {
+			unsigned int chunk =
+				min_t(unsigned int, t.len, sizeof(buf));
+
+			ret =
+				t3_mc7_bd_read(mem, t.addr / 8, chunk / 8,
+						buf);
+			if (ret)
+				return ret;
+			if (copy_to_user(useraddr, buf, chunk))
+				return -EFAULT;
+			useraddr += chunk;
+			t.addr += chunk;
+			t.len -= chunk;
+		}
+		break;
+	}
+	case CHELSIO_SET_TRACE_FILTER:{
+		struct ch_trace t;
+		const struct trace_params *tp;
+
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (!offload_running(adapter))
+			return -EAGAIN;
+		if (copy_from_user(&t, useraddr, sizeof(t)))
+			return -EFAULT;
+
+		tp = (const struct trace_params *)&t.sip;
+		if (t.config_tx)
+			t3_config_trace_filter(adapter, tp, 0,
+						t.invert_match,
+						t.trace_tx);
+		if (t.config_rx)
+			t3_config_trace_filter(adapter, tp, 1,
+						t.invert_match,
+						t.trace_rx);
+		break;
+	}
+	case CHELSIO_SET_PKTSCHED:{
+		struct ch_pktsched_params p;
+
+		if (!capable(CAP_NET_ADMIN))
+				return -EPERM;
+		if (!adapter->open_device_map)
+				return -EAGAIN;	/* uP and SGE must be running */
+		if (copy_from_user(&p, useraddr, sizeof(p)))
+				return -EFAULT;
+		send_pktsched_cmd(adapter, p.sched, p.idx, p.min, p.max,
+				  p.binding);
+		break;
+			
+	}
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+	int ret, mmd;
+	struct adapter *adapter = dev->priv;
+	struct port_info *pi = netdev_priv(dev);
+	struct mii_ioctl_data *data = if_mii(req);
+
+	switch (cmd) {
+	case SIOCGMIIPHY:
+		data->phy_id = pi->phy.addr;
+		/* FALLTHRU */
+	case SIOCGMIIREG:{
+		u32 val;
+		struct cphy *phy = &pi->phy;
+
+		if (!phy->mdio_read)
+			return -EOPNOTSUPP;
+		if (is_10G(adapter)) {
+			mmd = data->phy_id >> 8;
+			if (!mmd)
+				mmd = MDIO_DEV_PCS;
+			else if (mmd > MDIO_DEV_XGXS)
+				return -EINVAL;
+
+			ret =
+				phy->mdio_read(adapter, data->phy_id & 0x1f,
+						mmd, data->reg_num, &val);
+		} else
+			ret =
+				phy->mdio_read(adapter, data->phy_id & 0x1f,
+						0, data->reg_num & 0x1f,
+						&val);
+		if (!ret)
+			data->val_out = val;
+		break;
+	}
+	case SIOCSMIIREG:{
+		struct cphy *phy = &pi->phy;
+
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (!phy->mdio_write)
+			return -EOPNOTSUPP;
+		if (is_10G(adapter)) {
+			mmd = data->phy_id >> 8;
+			if (!mmd)
+				mmd = MDIO_DEV_PCS;
+			else if (mmd > MDIO_DEV_XGXS)
+				return -EINVAL;
+
+			ret =
+				phy->mdio_write(adapter,
+						data->phy_id & 0x1f, mmd,
+						data->reg_num,
+						data->val_in);
+		} else
+			ret =
+				phy->mdio_write(adapter,
+						data->phy_id & 0x1f, 0,
+						data->reg_num & 0x1f,
+						data->val_in);
+		break;
+	}
+	case SIOCCHIOCTL:
+		return cxgb_extension_ioctl(dev, req->ifr_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+	return ret;
+}
+
+static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
+{
+	int ret;
+	struct adapter *adapter = dev->priv;
+	struct port_info *pi = netdev_priv(dev);
+
+	if (new_mtu < 81)	/* accommodate SACK */
+		return -EINVAL;
+	if ((ret = t3_mac_set_mtu(&pi->mac, new_mtu)))
+		return ret;
+	dev->mtu = new_mtu;
+	init_port_mtus(adapter);
+	if (adapter->params.rev == 0 && offload_running(adapter))
+		t3_load_mtus(adapter, adapter->params.mtus,
+			     adapter->params.a_wnd, adapter->params.b_wnd,
+			     adapter->port[0]->mtu);
+	return 0;
+}
+
+static int cxgb_set_mac_addr(struct net_device *dev, void *p)
+{
+	struct adapter *adapter = dev->priv;
+	struct port_info *pi = netdev_priv(dev);
+	struct sockaddr *addr = p;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EINVAL;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+	t3_mac_set_address(&pi->mac, 0, dev->dev_addr);
+	if (offload_running(adapter))
+		write_smt_entry(adapter, pi->port_id);
+	return 0;
+}
+
+/**
+ * t3_synchronize_rx - wait for current Rx processing on a port to complete
+ * @adap: the adapter
+ * @p: the port
+ *
+ * Ensures that current Rx processing on any of the queues associated with
+ * the given port completes before returning.  We do this by acquiring and
+ * releasing the locks of the response queues associated with the port.
+ */
+static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p)
+{
+	int i;
+
+	for (i = 0; i < p->nqsets; i++) {
+		struct sge_rspq *q = &adap->sge.qs[i + p->first_qset].rspq;
+
+		spin_lock_irq(&q->lock);
+		spin_unlock_irq(&q->lock);
+	}
+}
+
+static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+{
+	struct adapter *adapter = dev->priv;
+	struct port_info *pi = netdev_priv(dev);
+
+	pi->vlan_grp = grp;
+	if (adapter->params.rev > 0)
+		t3_set_vlan_accel(adapter, 1 << pi->port_id, grp != NULL);
+	else {
+		/* single control for all ports */
+		unsigned int i, have_vlans = 0;
+		for_each_port(adapter, i)
+		    have_vlans |= adap2pinfo(adapter, i)->vlan_grp != NULL;
+
+		t3_set_vlan_accel(adapter, 1, have_vlans);
+	}
+	t3_synchronize_rx(adapter, pi);
+}
+
+static void vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+	/* nothing */
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void cxgb_netpoll(struct net_device *dev)
+{
+	struct adapter *adapter = dev->priv;
+	struct sge_qset *qs = dev2qset(dev);
+
+	t3_intr_handler(adapter, qs->rspq.polling) (adapter->pdev->irq,
+						    adapter);
+}
+#endif
+
+/*
+ * Periodic accumulation of MAC statistics.
+ */
+static void mac_stats_update(struct adapter *adapter)
+{
+	int i;
+
+	for_each_port(adapter, i) {
+		struct net_device *dev = adapter->port[i];
+		struct port_info *p = netdev_priv(dev);
+
+		if (netif_running(dev)) {
+			spin_lock(&adapter->stats_lock);
+			t3_mac_update_stats(&p->mac);
+			spin_unlock(&adapter->stats_lock);
+		}
+	}
+}
+
+static void check_link_status(struct adapter *adapter)
+{
+	int i;
+
+	for_each_port(adapter, i) {
+		struct net_device *dev = adapter->port[i];
+		struct port_info *p = netdev_priv(dev);
+
+		if (!(p->port_type->caps & SUPPORTED_IRQ) && netif_running(dev))
+			t3_link_changed(adapter, i);
+	}
+}
+
+static void t3_adap_check_task(struct work_struct *work)
+{
+	struct adapter *adapter = container_of(work, struct adapter,
+					       adap_check_task.work);
+	const struct adapter_params *p = &adapter->params;
+
+	adapter->check_task_cnt++;
+
+	/* Check link status for PHYs without interrupts */
+	if (p->linkpoll_period)
+		check_link_status(adapter);
+
+	/* Accumulate MAC stats if needed */
+	if (!p->linkpoll_period ||
+	    (adapter->check_task_cnt * p->linkpoll_period) / 10 >=
+	    p->stats_update_period) {
+		mac_stats_update(adapter);
+		adapter->check_task_cnt = 0;
+	}
+
+	/* Schedule the next check update if any port is active. */
+	spin_lock(&adapter->work_lock);
+	if (adapter->open_device_map & PORT_MASK)
+		schedule_chk_task(adapter);
+	spin_unlock(&adapter->work_lock);
+}
+
+/*
+ * Processes external (PHY) interrupts in process context.
+ */
+static void ext_intr_task(struct work_struct *work)
+{
+	struct adapter *adapter = container_of(work, struct adapter,
+					       ext_intr_handler_task);
+
+	t3_phy_intr_handler(adapter);
+
+	/* Now reenable external interrupts */
+	spin_lock_irq(&adapter->work_lock);
+	if (adapter->slow_intr_mask) {
+		adapter->slow_intr_mask |= F_T3DBG;
+		t3_write_reg(adapter, A_PL_INT_CAUSE0, F_T3DBG);
+		t3_write_reg(adapter, A_PL_INT_ENABLE0,
+			     adapter->slow_intr_mask);
+	}
+	spin_unlock_irq(&adapter->work_lock);
+}
+
+/*
+ * Interrupt-context handler for external (PHY) interrupts.
+ */
+void t3_os_ext_intr_handler(struct adapter *adapter)
+{
+	/*
+	 * Schedule a task to handle external interrupts as they may be slow
+	 * and we use a mutex to protect MDIO registers.  We disable PHY
+	 * interrupts in the meantime and let the task reenable them when
+	 * it's done.
+	 */
+	spin_lock(&adapter->work_lock);
+	if (adapter->slow_intr_mask) {
+		adapter->slow_intr_mask &= ~F_T3DBG;
+		t3_write_reg(adapter, A_PL_INT_ENABLE0,
+			     adapter->slow_intr_mask);
+		queue_work(cxgb3_wq, &adapter->ext_intr_handler_task);
+	}
+	spin_unlock(&adapter->work_lock);
+}
+
+void t3_fatal_err(struct adapter *adapter)
+{
+	unsigned int fw_status[4];
+
+	if (adapter->flags & FULL_INIT_DONE) {
+		t3_sge_stop(adapter);
+		t3_intr_disable(adapter);
+	}
+	CH_ALERT(adapter, "encountered fatal error, operation suspended\n");
+	if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status))
+		CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n",
+			 fw_status[0], fw_status[1],
+			 fw_status[2], fw_status[3]);
+
+}
+
+static int __devinit cxgb_enable_msix(struct adapter *adap)
+{
+	struct msix_entry entries[SGE_QSETS + 1];
+	int i, err;
+
+	for (i = 0; i < ARRAY_SIZE(entries); ++i)
+		entries[i].entry = i;
+
+	err = pci_enable_msix(adap->pdev, entries, ARRAY_SIZE(entries));
+	if (!err) {
+		for (i = 0; i < ARRAY_SIZE(entries); ++i)
+			adap->msix_info[i].vec = entries[i].vector;
+	} else if (err > 0)
+		dev_info(&adap->pdev->dev,
+		       "only %d MSI-X vectors left, not using MSI-X\n", err);
+	return err;
+}
+
+static void __devinit print_port_info(struct adapter *adap,
+				      const struct adapter_info *ai)
+{
+	static const char *pci_variant[] = {
+		"PCI", "PCI-X", "PCI-X ECC", "PCI-X 266", "PCI Express"
+	};
+
+	int i;
+	char buf[80];
+
+	if (is_pcie(adap))
+		snprintf(buf, sizeof(buf), "%s x%d",
+			 pci_variant[adap->params.pci.variant],
+			 adap->params.pci.width);
+	else
+		snprintf(buf, sizeof(buf), "%s %dMHz/%d-bit",
+			 pci_variant[adap->params.pci.variant],
+			 adap->params.pci.speed, adap->params.pci.width);
+
+	for_each_port(adap, i) {
+		struct net_device *dev = adap->port[i];
+		const struct port_info *pi = netdev_priv(dev);
+
+		if (!test_bit(i, &adap->registered_device_map))
+			continue;
+		printk(KERN_INFO "%s: %s %s RNIC (rev %d) %s%s\n",
+		       dev->name, ai->desc, pi->port_type->desc,
+		       adap->params.rev, buf,
+		       (adap->flags & USING_MSIX) ? " MSI-X" :
+		       (adap->flags & USING_MSI) ? " MSI" : "");
+		if (adap->name == dev->name && adap->params.vpd.mclk)
+			printk(KERN_INFO "%s: %uMB CM, %uMB PMTX, %uMB PMRX\n",
+			       adap->name, t3_mc7_size(&adap->cm) >> 20,
+			       t3_mc7_size(&adap->pmtx) >> 20,
+			       t3_mc7_size(&adap->pmrx) >> 20);
+	}
+}
+
+static int __devinit init_one(struct pci_dev *pdev,
+			      const struct pci_device_id *ent)
+{
+	static int version_printed;
+
+	int i, err, pci_using_dac = 0;
+	unsigned long mmio_start, mmio_len;
+	const struct adapter_info *ai;
+	struct adapter *adapter = NULL;
+	struct port_info *pi;
+
+	if (!version_printed) {
+		printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
+		++version_printed;
+	}
+
+	if (!cxgb3_wq) {
+		cxgb3_wq = create_singlethread_workqueue(DRV_NAME);
+		if (!cxgb3_wq) {
+			printk(KERN_ERR DRV_NAME
+			       ": cannot initialize work queue\n");
+			return -ENOMEM;
+		}
+	}
+
+	err = pci_request_regions(pdev, DRV_NAME);
+	if (err) {
+		/* Just info, some other driver may have claimed the device. */
+		dev_info(&pdev->dev, "cannot obtain PCI resources\n");
+		return err;
+	}
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		dev_err(&pdev->dev, "cannot enable PCI device\n");
+		goto out_release_regions;
+	}
+
+	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+		pci_using_dac = 1;
+		err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+		if (err) {
+			dev_err(&pdev->dev, "unable to obtain 64-bit DMA for "
+			       "coherent allocations\n");
+			goto out_disable_device;
+		}
+	} else if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) {
+		dev_err(&pdev->dev, "no usable DMA configuration\n");
+		goto out_disable_device;
+	}
+
+	pci_set_master(pdev);
+
+	mmio_start = pci_resource_start(pdev, 0);
+	mmio_len = pci_resource_len(pdev, 0);
+	ai = t3_get_adapter_info(ent->driver_data);
+
+	adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+	if (!adapter) {
+		err = -ENOMEM;
+		goto out_disable_device;
+	}
+
+	adapter->regs = ioremap_nocache(mmio_start, mmio_len);
+	if (!adapter->regs) {
+		dev_err(&pdev->dev, "cannot map device registers\n");
+		err = -ENOMEM;
+		goto out_free_adapter;
+	}
+
+	adapter->pdev = pdev;
+	adapter->name = pci_name(pdev);
+	adapter->msg_enable = dflt_msg_enable;
+	adapter->mmio_len = mmio_len;
+
+	mutex_init(&adapter->mdio_lock);
+	spin_lock_init(&adapter->work_lock);
+	spin_lock_init(&adapter->stats_lock);
+
+	INIT_LIST_HEAD(&adapter->adapter_list);
+	INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
+	INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
+
+	for (i = 0; i < ai->nports; ++i) {
+		struct net_device *netdev;
+
+		netdev = alloc_etherdev(sizeof(struct port_info));
+		if (!netdev) {
+			err = -ENOMEM;
+			goto out_free_dev;
+		}
+
+		SET_MODULE_OWNER(netdev);
+		SET_NETDEV_DEV(netdev, &pdev->dev);
+
+		adapter->port[i] = netdev;
+		pi = netdev_priv(netdev);
+		pi->rx_csum_offload = 1;
+		pi->nqsets = 1;
+		pi->first_qset = i;
+		pi->activity = 0;
+		pi->port_id = i;
+		netif_carrier_off(netdev);
+		netdev->irq = pdev->irq;
+		netdev->mem_start = mmio_start;
+		netdev->mem_end = mmio_start + mmio_len - 1;
+		netdev->priv = adapter;
+		netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
+		netdev->features |= NETIF_F_LLTX;
+		if (pci_using_dac)
+			netdev->features |= NETIF_F_HIGHDMA;
+
+		netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+		netdev->vlan_rx_register = vlan_rx_register;
+		netdev->vlan_rx_kill_vid = vlan_rx_kill_vid;
+
+		netdev->open = cxgb_open;
+		netdev->stop = cxgb_close;
+		netdev->hard_start_xmit = t3_eth_xmit;
+		netdev->get_stats = cxgb_get_stats;
+		netdev->set_multicast_list = cxgb_set_rxmode;
+		netdev->do_ioctl = cxgb_ioctl;
+		netdev->change_mtu = cxgb_change_mtu;
+		netdev->set_mac_address = cxgb_set_mac_addr;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+		netdev->poll_controller = cxgb_netpoll;
+#endif
+		netdev->weight = 64;
+
+		SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
+	}
+
+	pci_set_drvdata(pdev, adapter->port[0]);
+	if (t3_prep_adapter(adapter, ai, 1) < 0) {
+		err = -ENODEV;
+		goto out_free_dev;
+	}
+
+	/*
+	 * The card is now ready to go.  If any errors occur during device
+	 * registration we do not fail the whole card but rather proceed only
+	 * with the ports we manage to register successfully.  However we must
+	 * register at least one net device.
+	 */
+	for_each_port(adapter, i) {
+		err = register_netdev(adapter->port[i]);
+		if (err)
+			dev_warn(&pdev->dev,
+				 "cannot register net device %s, skipping\n",
+				 adapter->port[i]->name);
+		else {
+			/*
+			 * Change the name we use for messages to the name of
+			 * the first successfully registered interface.
+			 */
+			if (!adapter->registered_device_map)
+				adapter->name = adapter->port[i]->name;
+
+			__set_bit(i, &adapter->registered_device_map);
+		}
+	}
+	if (!adapter->registered_device_map) {
+		dev_err(&pdev->dev, "could not register any net devices\n");
+		goto out_free_dev;
+	}
+
+	/* Driver's ready. Reflect it on LEDs */
+	t3_led_ready(adapter);
+
+	if (is_offload(adapter)) {
+		__set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map);
+		cxgb3_adapter_ofld(adapter);
+	}
+
+	/* See what interrupts we'll be using */
+	if (msi > 1 && cxgb_enable_msix(adapter) == 0)
+		adapter->flags |= USING_MSIX;
+	else if (msi > 0 && pci_enable_msi(pdev) == 0)
+		adapter->flags |= USING_MSI;
+
+	err = sysfs_create_group(&adapter->port[0]->dev.kobj,
+				 &cxgb3_attr_group);
+
+	print_port_info(adapter, ai);
+	return 0;
+
+out_free_dev:
+	iounmap(adapter->regs);
+	for (i = ai->nports - 1; i >= 0; --i)
+		if (adapter->port[i])
+			free_netdev(adapter->port[i]);
+
+out_free_adapter:
+	kfree(adapter);
+
+out_disable_device:
+	pci_disable_device(pdev);
+out_release_regions:
+	pci_release_regions(pdev);
+	pci_set_drvdata(pdev, NULL);
+	return err;
+}
+
+static void __devexit remove_one(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+
+	if (dev) {
+		int i;
+		struct adapter *adapter = dev->priv;
+
+		t3_sge_stop(adapter);
+		sysfs_remove_group(&adapter->port[0]->dev.kobj,
+				   &cxgb3_attr_group);
+
+		for_each_port(adapter, i)
+		    if (test_bit(i, &adapter->registered_device_map))
+			unregister_netdev(adapter->port[i]);
+
+		if (is_offload(adapter)) {
+			cxgb3_adapter_unofld(adapter);
+			if (test_bit(OFFLOAD_DEVMAP_BIT,
+				     &adapter->open_device_map))
+				offload_close(&adapter->tdev);
+		}
+
+		t3_free_sge_resources(adapter);
+		cxgb_disable_msi(adapter);
+
+		for (i = 0; i < ARRAY_SIZE(adapter->dummy_netdev); i++)
+			if (adapter->dummy_netdev[i]) {
+				free_netdev(adapter->dummy_netdev[i]);
+				adapter->dummy_netdev[i] = NULL;
+			}
+
+		for_each_port(adapter, i)
+			if (adapter->port[i])
+				free_netdev(adapter->port[i]);
+
+		iounmap(adapter->regs);
+		kfree(adapter);
+		pci_release_regions(pdev);
+		pci_disable_device(pdev);
+		pci_set_drvdata(pdev, NULL);
+	}
+}
+
+static struct pci_driver driver = {
+	.name = DRV_NAME,
+	.id_table = cxgb3_pci_tbl,
+	.probe = init_one,
+	.remove = __devexit_p(remove_one),
+};
+
+static int __init cxgb3_init_module(void)
+{
+	int ret;
+
+	cxgb3_offload_init();
+
+	ret = pci_register_driver(&driver);
+	return ret;
+}
+
+static void __exit cxgb3_cleanup_module(void)
+{
+	pci_unregister_driver(&driver);
+	if (cxgb3_wq)
+		destroy_workqueue(cxgb3_wq);
+}
+
+module_init(cxgb3_init_module);
+module_exit(cxgb3_cleanup_module);
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
new file mode 100644
index 0000000..c6b7266
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -0,0 +1,1222 @@
+/*
+ * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/list.h>
+#include <net/neighbour.h>
+#include <linux/notifier.h>
+#include <asm/atomic.h>
+#include <linux/proc_fs.h>
+#include <linux/if_vlan.h>
+#include <net/netevent.h>
+#include <linux/highmem.h>
+#include <linux/vmalloc.h>
+
+#include "common.h"
+#include "regs.h"
+#include "cxgb3_ioctl.h"
+#include "cxgb3_ctl_defs.h"
+#include "cxgb3_defs.h"
+#include "l2t.h"
+#include "firmware_exports.h"
+#include "cxgb3_offload.h"
+
+static LIST_HEAD(client_list);
+static LIST_HEAD(ofld_dev_list);
+static DEFINE_MUTEX(cxgb3_db_lock);
+
+static DEFINE_RWLOCK(adapter_list_lock);
+static LIST_HEAD(adapter_list);
+
+static const unsigned int MAX_ATIDS = 64 * 1024;
+static const unsigned int ATID_BASE = 0x100000;
+
+static inline int offload_activated(struct t3cdev *tdev)
+{
+	const struct adapter *adapter = tdev2adap(tdev);
+
+	return (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map));
+}
+
+/**
+ *	cxgb3_register_client - register an offload client
+ *	@client: the client
+ *
+ *	Add the client to the client list,
+ *	and call backs the client for each activated offload device
+ */
+void cxgb3_register_client(struct cxgb3_client *client)
+{
+	struct t3cdev *tdev;
+
+	mutex_lock(&cxgb3_db_lock);
+	list_add_tail(&client->client_list, &client_list);
+
+	if (client->add) {
+		list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) {
+			if (offload_activated(tdev))
+				client->add(tdev);
+		}
+	}
+	mutex_unlock(&cxgb3_db_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_register_client);
+
+/**
+ *	cxgb3_unregister_client - unregister an offload client
+ *	@client: the client
+ *
+ *	Remove the client to the client list,
+ *	and call backs the client for each activated offload device.
+ */
+void cxgb3_unregister_client(struct cxgb3_client *client)
+{
+	struct t3cdev *tdev;
+
+	mutex_lock(&cxgb3_db_lock);
+	list_del(&client->client_list);
+
+	if (client->remove) {
+		list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) {
+			if (offload_activated(tdev))
+				client->remove(tdev);
+		}
+	}
+	mutex_unlock(&cxgb3_db_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_unregister_client);
+
+/**
+ *	cxgb3_add_clients - activate registered clients for an offload device
+ *	@tdev: the offload device
+ *
+ *	Call backs all registered clients once a offload device is activated
+ */
+void cxgb3_add_clients(struct t3cdev *tdev)
+{
+	struct cxgb3_client *client;
+
+	mutex_lock(&cxgb3_db_lock);
+	list_for_each_entry(client, &client_list, client_list) {
+		if (client->add)
+			client->add(tdev);
+	}
+	mutex_unlock(&cxgb3_db_lock);
+}
+
+/**
+ *	cxgb3_remove_clients - deactivates registered clients
+ *			       for an offload device
+ *	@tdev: the offload device
+ *
+ *	Call backs all registered clients once a offload device is deactivated
+ */
+void cxgb3_remove_clients(struct t3cdev *tdev)
+{
+	struct cxgb3_client *client;
+
+	mutex_lock(&cxgb3_db_lock);
+	list_for_each_entry(client, &client_list, client_list) {
+		if (client->remove)
+			client->remove(tdev);
+	}
+	mutex_unlock(&cxgb3_db_lock);
+}
+
+static struct net_device *get_iff_from_mac(struct adapter *adapter,
+					   const unsigned char *mac,
+					   unsigned int vlan)
+{
+	int i;
+
+	for_each_port(adapter, i) {
+		const struct vlan_group *grp;
+		struct net_device *dev = adapter->port[i];
+		const struct port_info *p = netdev_priv(dev);
+
+		if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) {
+			if (vlan && vlan != VLAN_VID_MASK) {
+				grp = p->vlan_grp;
+				dev = grp ? grp->vlan_devices[vlan] : NULL;
+			} else
+				while (dev->master)
+					dev = dev->master;
+			return dev;
+		}
+	}
+	return NULL;
+}
+
+static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req,
+			      void *data)
+{
+	int ret = 0;
+	struct ulp_iscsi_info *uiip = data;
+
+	switch (req) {
+	case ULP_ISCSI_GET_PARAMS:
+		uiip->pdev = adapter->pdev;
+		uiip->llimit = t3_read_reg(adapter, A_ULPRX_ISCSI_LLIMIT);
+		uiip->ulimit = t3_read_reg(adapter, A_ULPRX_ISCSI_ULIMIT);
+		uiip->tagmask = t3_read_reg(adapter, A_ULPRX_ISCSI_TAGMASK);
+		/*
+		 * On tx, the iscsi pdu has to be <= tx page size and has to
+		 * fit into the Tx PM FIFO.
+		 */
+		uiip->max_txsz = min(adapter->params.tp.tx_pg_size,
+				     t3_read_reg(adapter, A_PM1_TX_CFG) >> 17);
+		/* on rx, the iscsi pdu has to be < rx page size and the
+		   whole pdu + cpl headers has to fit into one sge buffer */
+		uiip->max_rxsz = min_t(unsigned int,
+				       adapter->params.tp.rx_pg_size,
+				       (adapter->sge.qs[0].fl[1].buf_size -
+					sizeof(struct cpl_rx_data) * 2 -
+					sizeof(struct cpl_rx_data_ddp)));
+		break;
+	case ULP_ISCSI_SET_PARAMS:
+		t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+	return ret;
+}
+
+/* Response queue used for RDMA events. */
+#define ASYNC_NOTIF_RSPQ 0
+
+static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data)
+{
+	int ret = 0;
+
+	switch (req) {
+	case RDMA_GET_PARAMS:{
+		struct rdma_info *req = data;
+		struct pci_dev *pdev = adapter->pdev;
+
+		req->udbell_physbase = pci_resource_start(pdev, 2);
+		req->udbell_len = pci_resource_len(pdev, 2);
+		req->tpt_base =
+			t3_read_reg(adapter, A_ULPTX_TPT_LLIMIT);
+		req->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT);
+		req->pbl_base =
+			t3_read_reg(adapter, A_ULPTX_PBL_LLIMIT);
+		req->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT);
+		req->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT);
+		req->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT);
+		req->kdb_addr = adapter->regs + A_SG_KDOORBELL;
+		req->pdev = pdev;
+		break;
+	}
+	case RDMA_CQ_OP:{
+		unsigned long flags;
+		struct rdma_cq_op *req = data;
+
+		/* may be called in any context */
+		spin_lock_irqsave(&adapter->sge.reg_lock, flags);
+		ret = t3_sge_cqcntxt_op(adapter, req->id, req->op,
+					req->credits);
+		spin_unlock_irqrestore(&adapter->sge.reg_lock, flags);
+		break;
+	}
+	case RDMA_GET_MEM:{
+		struct ch_mem_range *t = data;
+		struct mc7 *mem;
+
+		if ((t->addr & 7) || (t->len & 7))
+			return -EINVAL;
+		if (t->mem_id == MEM_CM)
+			mem = &adapter->cm;
+		else if (t->mem_id == MEM_PMRX)
+			mem = &adapter->pmrx;
+		else if (t->mem_id == MEM_PMTX)
+			mem = &adapter->pmtx;
+		else
+			return -EINVAL;
+
+		ret =
+			t3_mc7_bd_read(mem, t->addr / 8, t->len / 8,
+					(u64 *) t->buf);
+		if (ret)
+			return ret;
+		break;
+	}
+	case RDMA_CQ_SETUP:{
+		struct rdma_cq_setup *req = data;
+
+		spin_lock_irq(&adapter->sge.reg_lock);
+		ret =
+			t3_sge_init_cqcntxt(adapter, req->id,
+					req->base_addr, req->size,
+					ASYNC_NOTIF_RSPQ,
+					req->ovfl_mode, req->credits,
+					req->credit_thres);
+		spin_unlock_irq(&adapter->sge.reg_lock);
+		break;
+	}
+	case RDMA_CQ_DISABLE:
+		spin_lock_irq(&adapter->sge.reg_lock);
+		ret = t3_sge_disable_cqcntxt(adapter, *(unsigned int *)data);
+		spin_unlock_irq(&adapter->sge.reg_lock);
+		break;
+	case RDMA_CTRL_QP_SETUP:{
+		struct rdma_ctrlqp_setup *req = data;
+
+		spin_lock_irq(&adapter->sge.reg_lock);
+		ret = t3_sge_init_ecntxt(adapter, FW_RI_SGEEC_START, 0,
+						SGE_CNTXT_RDMA,
+						ASYNC_NOTIF_RSPQ,
+						req->base_addr, req->size,
+						FW_RI_TID_START, 1, 0);
+		spin_unlock_irq(&adapter->sge.reg_lock);
+		break;
+	}
+	default:
+		ret = -EOPNOTSUPP;
+	}
+	return ret;
+}
+
+static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data)
+{
+	struct adapter *adapter = tdev2adap(tdev);
+	struct tid_range *tid;
+	struct mtutab *mtup;
+	struct iff_mac *iffmacp;
+	struct ddp_params *ddpp;
+	struct adap_ports *ports;
+	int i;
+
+	switch (req) {
+	case GET_MAX_OUTSTANDING_WR:
+		*(unsigned int *)data = FW_WR_NUM;
+		break;
+	case GET_WR_LEN:
+		*(unsigned int *)data = WR_FLITS;
+		break;
+	case GET_TX_MAX_CHUNK:
+		*(unsigned int *)data = 1 << 20;	/* 1MB */
+		break;
+	case GET_TID_RANGE:
+		tid = data;
+		tid->num = t3_mc5_size(&adapter->mc5) -
+		    adapter->params.mc5.nroutes -
+		    adapter->params.mc5.nfilters - adapter->params.mc5.nservers;
+		tid->base = 0;
+		break;
+	case GET_STID_RANGE:
+		tid = data;
+		tid->num = adapter->params.mc5.nservers;
+		tid->base = t3_mc5_size(&adapter->mc5) - tid->num -
+		    adapter->params.mc5.nfilters - adapter->params.mc5.nroutes;
+		break;
+	case GET_L2T_CAPACITY:
+		*(unsigned int *)data = 2048;
+		break;
+	case GET_MTUS:
+		mtup = data;
+		mtup->size = NMTUS;
+		mtup->mtus = adapter->params.mtus;
+		break;
+	case GET_IFF_FROM_MAC:
+		iffmacp = data;
+		iffmacp->dev = get_iff_from_mac(adapter, iffmacp->mac_addr,
+						iffmacp->vlan_tag &
+						VLAN_VID_MASK);
+		break;
+	case GET_DDP_PARAMS:
+		ddpp = data;
+		ddpp->llimit = t3_read_reg(adapter, A_ULPRX_TDDP_LLIMIT);
+		ddpp->ulimit = t3_read_reg(adapter, A_ULPRX_TDDP_ULIMIT);
+		ddpp->tag_mask = t3_read_reg(adapter, A_ULPRX_TDDP_TAGMASK);
+		break;
+	case GET_PORTS:
+		ports = data;
+		ports->nports = adapter->params.nports;
+		for_each_port(adapter, i)
+			ports->lldevs[i] = adapter->port[i];
+		break;
+	case ULP_ISCSI_GET_PARAMS:
+	case ULP_ISCSI_SET_PARAMS:
+		if (!offload_running(adapter))
+			return -EAGAIN;
+		return cxgb_ulp_iscsi_ctl(adapter, req, data);
+	case RDMA_GET_PARAMS:
+	case RDMA_CQ_OP:
+	case RDMA_CQ_SETUP:
+	case RDMA_CQ_DISABLE:
+	case RDMA_CTRL_QP_SETUP:
+	case RDMA_GET_MEM:
+		if (!offload_running(adapter))
+			return -EAGAIN;
+		return cxgb_rdma_ctl(adapter, req, data);
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+/*
+ * Dummy handler for Rx offload packets in case we get an offload packet before
+ * proper processing is setup.  This complains and drops the packet as it isn't
+ * normal to get offload packets at this stage.
+ */
+static int rx_offload_blackhole(struct t3cdev *dev, struct sk_buff **skbs,
+				int n)
+{
+	CH_ERR(tdev2adap(dev), "%d unexpected offload packets, first data %u\n",
+	       n, ntohl(*(__be32 *)skbs[0]->data));
+	while (n--)
+		dev_kfree_skb_any(skbs[n]);
+	return 0;
+}
+
+static void dummy_neigh_update(struct t3cdev *dev, struct neighbour *neigh)
+{
+}
+
+void cxgb3_set_dummy_ops(struct t3cdev *dev)
+{
+	dev->recv = rx_offload_blackhole;
+	dev->neigh_update = dummy_neigh_update;
+}
+
+/*
+ * Free an active-open TID.
+ */
+void *cxgb3_free_atid(struct t3cdev *tdev, int atid)
+{
+	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+	union active_open_entry *p = atid2entry(t, atid);
+	void *ctx = p->t3c_tid.ctx;
+
+	spin_lock_bh(&t->atid_lock);
+	p->next = t->afree;
+	t->afree = p;
+	t->atids_in_use--;
+	spin_unlock_bh(&t->atid_lock);
+
+	return ctx;
+}
+
+EXPORT_SYMBOL(cxgb3_free_atid);
+
+/*
+ * Free a server TID and return it to the free pool.
+ */
+void cxgb3_free_stid(struct t3cdev *tdev, int stid)
+{
+	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+	union listen_entry *p = stid2entry(t, stid);
+
+	spin_lock_bh(&t->stid_lock);
+	p->next = t->sfree;
+	t->sfree = p;
+	t->stids_in_use--;
+	spin_unlock_bh(&t->stid_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_free_stid);
+
+void cxgb3_insert_tid(struct t3cdev *tdev, struct cxgb3_client *client,
+		      void *ctx, unsigned int tid)
+{
+	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+	t->tid_tab[tid].client = client;
+	t->tid_tab[tid].ctx = ctx;
+	atomic_inc(&t->tids_in_use);
+}
+
+EXPORT_SYMBOL(cxgb3_insert_tid);
+
+/*
+ * Populate a TID_RELEASE WR.  The skb must be already propely sized.
+ */
+static inline void mk_tid_release(struct sk_buff *skb, unsigned int tid)
+{
+	struct cpl_tid_release *req;
+
+	skb->priority = CPL_PRIORITY_SETUP;
+	req = (struct cpl_tid_release *)__skb_put(skb, sizeof(*req));
+	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid));
+}
+
+static void t3_process_tid_release_list(struct work_struct *work)
+{
+	struct t3c_data *td = container_of(work, struct t3c_data,
+					   tid_release_task);
+	struct sk_buff *skb;
+	struct t3cdev *tdev = td->dev;
+	
+
+	spin_lock_bh(&td->tid_release_lock);
+	while (td->tid_release_list) {
+		struct t3c_tid_entry *p = td->tid_release_list;
+
+		td->tid_release_list = (struct t3c_tid_entry *)p->ctx;
+		spin_unlock_bh(&td->tid_release_lock);
+
+		skb = alloc_skb(sizeof(struct cpl_tid_release),
+				GFP_KERNEL | __GFP_NOFAIL);
+		mk_tid_release(skb, p - td->tid_maps.tid_tab);
+		cxgb3_ofld_send(tdev, skb);
+		p->ctx = NULL;
+		spin_lock_bh(&td->tid_release_lock);
+	}
+	spin_unlock_bh(&td->tid_release_lock);
+}
+
+/* use ctx as a next pointer in the tid release list */
+void cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid)
+{
+	struct t3c_data *td = T3C_DATA(tdev);
+	struct t3c_tid_entry *p = &td->tid_maps.tid_tab[tid];
+
+	spin_lock_bh(&td->tid_release_lock);
+	p->ctx = (void *)td->tid_release_list;
+	td->tid_release_list = p;
+	if (!p->ctx)
+		schedule_work(&td->tid_release_task);
+	spin_unlock_bh(&td->tid_release_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_queue_tid_release);
+
+/*
+ * Remove a tid from the TID table.  A client may defer processing its last
+ * CPL message if it is locked at the time it arrives, and while the message
+ * sits in the client's backlog the TID may be reused for another connection.
+ * To handle this we atomically switch the TID association if it still points
+ * to the original client context.
+ */
+void cxgb3_remove_tid(struct t3cdev *tdev, void *ctx, unsigned int tid)
+{
+	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+	BUG_ON(tid >= t->ntids);
+	if (tdev->type == T3A)
+		(void)cmpxchg(&t->tid_tab[tid].ctx, ctx, NULL);
+	else {
+		struct sk_buff *skb;
+
+		skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC);
+		if (likely(skb)) {
+			mk_tid_release(skb, tid);
+			cxgb3_ofld_send(tdev, skb);
+			t->tid_tab[tid].ctx = NULL;
+		} else
+			cxgb3_queue_tid_release(tdev, tid);
+	}
+	atomic_dec(&t->tids_in_use);
+}
+
+EXPORT_SYMBOL(cxgb3_remove_tid);
+
+int cxgb3_alloc_atid(struct t3cdev *tdev, struct cxgb3_client *client,
+		     void *ctx)
+{
+	int atid = -1;
+	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+	spin_lock_bh(&t->atid_lock);
+	if (t->afree) {
+		union active_open_entry *p = t->afree;
+
+		atid = (p - t->atid_tab) + t->atid_base;
+		t->afree = p->next;
+		p->t3c_tid.ctx = ctx;
+		p->t3c_tid.client = client;
+		t->atids_in_use++;
+	}
+	spin_unlock_bh(&t->atid_lock);
+	return atid;
+}
+
+EXPORT_SYMBOL(cxgb3_alloc_atid);
+
+int cxgb3_alloc_stid(struct t3cdev *tdev, struct cxgb3_client *client,
+		     void *ctx)
+{
+	int stid = -1;
+	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+	spin_lock_bh(&t->stid_lock);
+	if (t->sfree) {
+		union listen_entry *p = t->sfree;
+
+		stid = (p - t->stid_tab) + t->stid_base;
+		t->sfree = p->next;
+		p->t3c_tid.ctx = ctx;
+		p->t3c_tid.client = client;
+		t->stids_in_use++;
+	}
+	spin_unlock_bh(&t->stid_lock);
+	return stid;
+}
+
+EXPORT_SYMBOL(cxgb3_alloc_stid);
+
+static int do_smt_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+	struct cpl_smt_write_rpl *rpl = cplhdr(skb);
+
+	if (rpl->status != CPL_ERR_NONE)
+		printk(KERN_ERR
+		       "Unexpected SMT_WRITE_RPL status %u for entry %u\n",
+		       rpl->status, GET_TID(rpl));
+
+	return CPL_RET_BUF_DONE;
+}
+
+static int do_l2t_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+	struct cpl_l2t_write_rpl *rpl = cplhdr(skb);
+
+	if (rpl->status != CPL_ERR_NONE)
+		printk(KERN_ERR
+		       "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
+		       rpl->status, GET_TID(rpl));
+
+	return CPL_RET_BUF_DONE;
+}
+
+static int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+	struct cpl_act_open_rpl *rpl = cplhdr(skb);
+	unsigned int atid = G_TID(ntohl(rpl->atid));
+	struct t3c_tid_entry *t3c_tid;
+
+	t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
+	if (t3c_tid->ctx && t3c_tid->client && t3c_tid->client->handlers &&
+	    t3c_tid->client->handlers[CPL_ACT_OPEN_RPL]) {
+		return t3c_tid->client->handlers[CPL_ACT_OPEN_RPL] (dev, skb,
+								    t3c_tid->
+								    ctx);
+	} else {
+		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+		       dev->name, CPL_ACT_OPEN_RPL);
+		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+	}
+}
+
+static int do_stid_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+	union opcode_tid *p = cplhdr(skb);
+	unsigned int stid = G_TID(ntohl(p->opcode_tid));
+	struct t3c_tid_entry *t3c_tid;
+
+	t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid);
+	if (t3c_tid->ctx && t3c_tid->client->handlers &&
+	    t3c_tid->client->handlers[p->opcode]) {
+		return t3c_tid->client->handlers[p->opcode] (dev, skb,
+							     t3c_tid->ctx);
+	} else {
+		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+		       dev->name, p->opcode);
+		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+	}
+}
+
+static int do_hwtid_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+	union opcode_tid *p = cplhdr(skb);
+	unsigned int hwtid = G_TID(ntohl(p->opcode_tid));
+	struct t3c_tid_entry *t3c_tid;
+
+	t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
+	if (t3c_tid->ctx && t3c_tid->client->handlers &&
+	    t3c_tid->client->handlers[p->opcode]) {
+		return t3c_tid->client->handlers[p->opcode]
+		    (dev, skb, t3c_tid->ctx);
+	} else {
+		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+		       dev->name, p->opcode);
+		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+	}
+}
+
+static int do_cr(struct t3cdev *dev, struct sk_buff *skb)
+{
+	struct cpl_pass_accept_req *req = cplhdr(skb);
+	unsigned int stid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
+	struct t3c_tid_entry *t3c_tid;
+
+	t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid);
+	if (t3c_tid->ctx && t3c_tid->client->handlers &&
+	    t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]) {
+		return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]
+		    (dev, skb, t3c_tid->ctx);
+	} else {
+		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+		       dev->name, CPL_PASS_ACCEPT_REQ);
+		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+	}
+}
+
+static int do_abort_req_rss(struct t3cdev *dev, struct sk_buff *skb)
+{
+	union opcode_tid *p = cplhdr(skb);
+	unsigned int hwtid = G_TID(ntohl(p->opcode_tid));
+	struct t3c_tid_entry *t3c_tid;
+
+	t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
+	if (t3c_tid->ctx && t3c_tid->client->handlers &&
+	    t3c_tid->client->handlers[p->opcode]) {
+		return t3c_tid->client->handlers[p->opcode]
+		    (dev, skb, t3c_tid->ctx);
+	} else {
+		struct cpl_abort_req_rss *req = cplhdr(skb);
+		struct cpl_abort_rpl *rpl;
+
+		struct sk_buff *skb =
+		    alloc_skb(sizeof(struct cpl_abort_rpl), GFP_ATOMIC);
+		if (!skb) {
+			printk("do_abort_req_rss: couldn't get skb!\n");
+			goto out;
+		}
+		skb->priority = CPL_PRIORITY_DATA;
+		__skb_put(skb, sizeof(struct cpl_abort_rpl));
+		rpl = cplhdr(skb);
+		rpl->wr.wr_hi =
+		    htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL));
+		rpl->wr.wr_lo = htonl(V_WR_TID(GET_TID(req)));
+		OPCODE_TID(rpl) =
+		    htonl(MK_OPCODE_TID(CPL_ABORT_RPL, GET_TID(req)));
+		rpl->cmd = req->status;
+		cxgb3_ofld_send(dev, skb);
+out:
+		return CPL_RET_BUF_DONE;
+	}
+}
+
+static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb)
+{
+	struct cpl_act_establish *req = cplhdr(skb);
+	unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
+	struct t3c_tid_entry *t3c_tid;
+
+	t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
+	if (t3c_tid->ctx && t3c_tid->client->handlers &&
+	    t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) {
+		return t3c_tid->client->handlers[CPL_ACT_ESTABLISH]
+		    (dev, skb, t3c_tid->ctx);
+	} else {
+		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+		       dev->name, CPL_PASS_ACCEPT_REQ);
+		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+	}
+}
+
+static int do_set_tcb_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+	struct cpl_set_tcb_rpl *rpl = cplhdr(skb);
+
+	if (rpl->status != CPL_ERR_NONE)
+		printk(KERN_ERR
+		       "Unexpected SET_TCB_RPL status %u for tid %u\n",
+		       rpl->status, GET_TID(rpl));
+	return CPL_RET_BUF_DONE;
+}
+
+static int do_trace(struct t3cdev *dev, struct sk_buff *skb)
+{
+	struct cpl_trace_pkt *p = cplhdr(skb);
+
+	skb->protocol = htons(0xffff);
+	skb->dev = dev->lldev;
+	skb_pull(skb, sizeof(*p));
+	skb->mac.raw = skb->data;
+	netif_receive_skb(skb);
+	return 0;
+}
+
+static int do_term(struct t3cdev *dev, struct sk_buff *skb)
+{
+	unsigned int hwtid = ntohl(skb->priority) >> 8 & 0xfffff;
+	unsigned int opcode = G_OPCODE(ntohl(skb->csum));
+	struct t3c_tid_entry *t3c_tid;
+
+	t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
+	if (t3c_tid->ctx && t3c_tid->client->handlers &&
+	    t3c_tid->client->handlers[opcode]) {
+		return t3c_tid->client->handlers[opcode] (dev, skb,
+							  t3c_tid->ctx);
+	} else {
+		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+		       dev->name, opcode);
+		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+	}
+}
+
+static int nb_callback(struct notifier_block *self, unsigned long event,
+		       void *ctx)
+{
+	switch (event) {
+	case (NETEVENT_NEIGH_UPDATE):{
+		cxgb_neigh_update((struct neighbour *)ctx);
+		break;
+	}
+	case (NETEVENT_PMTU_UPDATE):
+		break;
+	case (NETEVENT_REDIRECT):{
+		struct netevent_redirect *nr = ctx;
+		cxgb_redirect(nr->old, nr->new);
+		cxgb_neigh_update(nr->new->neighbour);
+		break;
+	}
+	default:
+		break;
+	}
+	return 0;
+}
+
+static struct notifier_block nb = {
+	.notifier_call = nb_callback
+};
+
+/*
+ * Process a received packet with an unknown/unexpected CPL opcode.
+ */
+static int do_bad_cpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+	printk(KERN_ERR "%s: received bad CPL command 0x%x\n", dev->name,
+	       *skb->data);
+	return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+}
+
+/*
+ * Handlers for each CPL opcode
+ */
+static cpl_handler_func cpl_handlers[NUM_CPL_CMDS];
+
+/*
+ * Add a new handler to the CPL dispatch table.  A NULL handler may be supplied
+ * to unregister an existing handler.
+ */
+void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h)
+{
+	if (opcode < NUM_CPL_CMDS)
+		cpl_handlers[opcode] = h ? h : do_bad_cpl;
+	else
+		printk(KERN_ERR "T3C: handler registration for "
+		       "opcode %x failed\n", opcode);
+}
+
+EXPORT_SYMBOL(t3_register_cpl_handler);
+
+/*
+ * T3CDEV's receive method.
+ */
+int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n)
+{
+	while (n--) {
+		struct sk_buff *skb = *skbs++;
+		unsigned int opcode = G_OPCODE(ntohl(skb->csum));
+		int ret = cpl_handlers[opcode] (dev, skb);
+
+#if VALIDATE_TID
+		if (ret & CPL_RET_UNKNOWN_TID) {
+			union opcode_tid *p = cplhdr(skb);
+
+			printk(KERN_ERR "%s: CPL message (opcode %u) had "
+			       "unknown TID %u\n", dev->name, opcode,
+			       G_TID(ntohl(p->opcode_tid)));
+		}
+#endif
+		if (ret & CPL_RET_BUF_DONE)
+			kfree_skb(skb);
+	}
+	return 0;
+}
+
+/*
+ * Sends an sk_buff to a T3C driver after dealing with any active network taps.
+ */
+int cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb)
+{
+	int r;
+
+	local_bh_disable();
+	r = dev->send(dev, skb);
+	local_bh_enable();
+	return r;
+}
+
+EXPORT_SYMBOL(cxgb3_ofld_send);
+
+static int is_offloading(struct net_device *dev)
+{
+	struct adapter *adapter;
+	int i;
+
+	read_lock_bh(&adapter_list_lock);
+	list_for_each_entry(adapter, &adapter_list, adapter_list) {
+		for_each_port(adapter, i) {
+			if (dev == adapter->port[i]) {
+				read_unlock_bh(&adapter_list_lock);
+				return 1;
+			}
+		}
+	}
+	read_unlock_bh(&adapter_list_lock);
+	return 0;
+}
+
+void cxgb_neigh_update(struct neighbour *neigh)
+{
+	struct net_device *dev = neigh->dev;
+
+	if (dev && (is_offloading(dev))) {
+		struct t3cdev *tdev = T3CDEV(dev);
+
+		BUG_ON(!tdev);
+		t3_l2t_update(tdev, neigh);
+	}
+}
+
+static void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e)
+{
+	struct sk_buff *skb;
+	struct cpl_set_tcb_field *req;
+
+	skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_ERR "%s: cannot allocate skb!\n", __FUNCTION__);
+		return;
+	}
+	skb->priority = CPL_PRIORITY_CONTROL;
+	req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req));
+	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));
+	req->reply = 0;
+	req->cpu_idx = 0;
+	req->word = htons(W_TCB_L2T_IX);
+	req->mask = cpu_to_be64(V_TCB_L2T_IX(M_TCB_L2T_IX));
+	req->val = cpu_to_be64(V_TCB_L2T_IX(e->idx));
+	tdev->send(tdev, skb);
+}
+
+void cxgb_redirect(struct dst_entry *old, struct dst_entry *new)
+{
+	struct net_device *olddev, *newdev;
+	struct tid_info *ti;
+	struct t3cdev *tdev;
+	u32 tid;
+	int update_tcb;
+	struct l2t_entry *e;
+	struct t3c_tid_entry *te;
+
+	olddev = old->neighbour->dev;
+	newdev = new->neighbour->dev;
+	if (!is_offloading(olddev))
+		return;
+	if (!is_offloading(newdev)) {
+		printk(KERN_WARNING "%s: Redirect to non-offload"
+		       "device ignored.\n", __FUNCTION__);
+		return;
+	}
+	tdev = T3CDEV(olddev);
+	BUG_ON(!tdev);
+	if (tdev != T3CDEV(newdev)) {
+		printk(KERN_WARNING "%s: Redirect to different "
+		       "offload device ignored.\n", __FUNCTION__);
+		return;
+	}
+
+	/* Add new L2T entry */
+	e = t3_l2t_get(tdev, new->neighbour, newdev);
+	if (!e) {
+		printk(KERN_ERR "%s: couldn't allocate new l2t entry!\n",
+		       __FUNCTION__);
+		return;
+	}
+
+	/* Walk tid table and notify clients of dst change. */
+	ti = &(T3C_DATA(tdev))->tid_maps;
+	for (tid = 0; tid < ti->ntids; tid++) {
+		te = lookup_tid(ti, tid);
+		BUG_ON(!te);
+		if (te->ctx && te->client && te->client->redirect) {
+			update_tcb = te->client->redirect(te->ctx, old, new, e);
+			if (update_tcb) {
+				l2t_hold(L2DATA(tdev), e);
+				set_l2t_ix(tdev, tid, e);
+			}
+		}
+	}
+	l2t_release(L2DATA(tdev), e);
+}
+
+/*
+ * Allocate a chunk of memory using kmalloc or, if that fails, vmalloc.
+ * The allocated memory is cleared.
+ */
+void *cxgb_alloc_mem(unsigned long size)
+{
+	void *p = kmalloc(size, GFP_KERNEL);
+
+	if (!p)
+		p = vmalloc(size);
+	if (p)
+		memset(p, 0, size);
+	return p;
+}
+
+/*
+ * Free memory allocated through t3_alloc_mem().
+ */
+void cxgb_free_mem(void *addr)
+{
+	unsigned long p = (unsigned long)addr;
+
+	if (p >= VMALLOC_START && p < VMALLOC_END)
+		vfree(addr);
+	else
+		kfree(addr);
+}
+
+/*
+ * Allocate and initialize the TID tables.  Returns 0 on success.
+ */
+static int init_tid_tabs(struct tid_info *t, unsigned int ntids,
+			 unsigned int natids, unsigned int nstids,
+			 unsigned int atid_base, unsigned int stid_base)
+{
+	unsigned long size = ntids * sizeof(*t->tid_tab) +
+	    natids * sizeof(*t->atid_tab) + nstids * sizeof(*t->stid_tab);
+
+	t->tid_tab = cxgb_alloc_mem(size);
+	if (!t->tid_tab)
+		return -ENOMEM;
+
+	t->stid_tab = (union listen_entry *)&t->tid_tab[ntids];
+	t->atid_tab = (union active_open_entry *)&t->stid_tab[nstids];
+	t->ntids = ntids;
+	t->nstids = nstids;
+	t->stid_base = stid_base;
+	t->sfree = NULL;
+	t->natids = natids;
+	t->atid_base = atid_base;
+	t->afree = NULL;
+	t->stids_in_use = t->atids_in_use = 0;
+	atomic_set(&t->tids_in_use, 0);
+	spin_lock_init(&t->stid_lock);
+	spin_lock_init(&t->atid_lock);
+
+	/*
+	 * Setup the free lists for stid_tab and atid_tab.
+	 */
+	if (nstids) {
+		while (--nstids)
+			t->stid_tab[nstids - 1].next = &t->stid_tab[nstids];
+		t->sfree = t->stid_tab;
+	}
+	if (natids) {
+		while (--natids)
+			t->atid_tab[natids - 1].next = &t->atid_tab[natids];
+		t->afree = t->atid_tab;
+	}
+	return 0;
+}
+
+static void free_tid_maps(struct tid_info *t)
+{
+	cxgb_free_mem(t->tid_tab);
+}
+
+static inline void add_adapter(struct adapter *adap)
+{
+	write_lock_bh(&adapter_list_lock);
+	list_add_tail(&adap->adapter_list, &adapter_list);
+	write_unlock_bh(&adapter_list_lock);
+}
+
+static inline void remove_adapter(struct adapter *adap)
+{
+	write_lock_bh(&adapter_list_lock);
+	list_del(&adap->adapter_list);
+	write_unlock_bh(&adapter_list_lock);
+}
+
+int cxgb3_offload_activate(struct adapter *adapter)
+{
+	struct t3cdev *dev = &adapter->tdev;
+	int natids, err;
+	struct t3c_data *t;
+	struct tid_range stid_range, tid_range;
+	struct mtutab mtutab;
+	unsigned int l2t_capacity;
+
+	t = kcalloc(1, sizeof(*t), GFP_KERNEL);
+	if (!t)
+		return -ENOMEM;
+
+	err = -EOPNOTSUPP;
+	if (dev->ctl(dev, GET_TX_MAX_CHUNK, &t->tx_max_chunk) < 0 ||
+	    dev->ctl(dev, GET_MAX_OUTSTANDING_WR, &t->max_wrs) < 0 ||
+	    dev->ctl(dev, GET_L2T_CAPACITY, &l2t_capacity) < 0 ||
+	    dev->ctl(dev, GET_MTUS, &mtutab) < 0 ||
+	    dev->ctl(dev, GET_TID_RANGE, &tid_range) < 0 ||
+	    dev->ctl(dev, GET_STID_RANGE, &stid_range) < 0)
+		goto out_free;
+
+	err = -ENOMEM;
+	L2DATA(dev) = t3_init_l2t(l2t_capacity);
+	if (!L2DATA(dev))
+		goto out_free;
+
+	natids = min(tid_range.num / 2, MAX_ATIDS);
+	err = init_tid_tabs(&t->tid_maps, tid_range.num, natids,
+			    stid_range.num, ATID_BASE, stid_range.base);
+	if (err)
+		goto out_free_l2t;
+
+	t->mtus = mtutab.mtus;
+	t->nmtus = mtutab.size;
+
+	INIT_WORK(&t->tid_release_task, t3_process_tid_release_list);
+	spin_lock_init(&t->tid_release_lock);
+	INIT_LIST_HEAD(&t->list_node);
+	t->dev = dev;
+
+	T3C_DATA(dev) = t;
+	dev->recv = process_rx;
+	dev->neigh_update = t3_l2t_update;
+
+	/* Register netevent handler once */
+	if (list_empty(&adapter_list))
+		register_netevent_notifier(&nb);
+
+	add_adapter(adapter);
+	return 0;
+
+out_free_l2t:
+	t3_free_l2t(L2DATA(dev));
+	L2DATA(dev) = NULL;
+out_free:
+	kfree(t);
+	return err;
+}
+
+void cxgb3_offload_deactivate(struct adapter *adapter)
+{
+	struct t3cdev *tdev = &adapter->tdev;
+	struct t3c_data *t = T3C_DATA(tdev);
+
+	remove_adapter(adapter);
+	if (list_empty(&adapter_list))
+		unregister_netevent_notifier(&nb);
+
+	free_tid_maps(&t->tid_maps);
+	T3C_DATA(tdev) = NULL;
+	t3_free_l2t(L2DATA(tdev));
+	L2DATA(tdev) = NULL;
+	kfree(t);
+}
+
+static inline void register_tdev(struct t3cdev *tdev)
+{
+	static int unit;
+
+	mutex_lock(&cxgb3_db_lock);
+	snprintf(tdev->name, sizeof(tdev->name), "ofld_dev%d", unit++);
+	list_add_tail(&tdev->ofld_dev_list, &ofld_dev_list);
+	mutex_unlock(&cxgb3_db_lock);
+}
+
+static inline void unregister_tdev(struct t3cdev *tdev)
+{
+	mutex_lock(&cxgb3_db_lock);
+	list_del(&tdev->ofld_dev_list);
+	mutex_unlock(&cxgb3_db_lock);
+}
+
+void __devinit cxgb3_adapter_ofld(struct adapter *adapter)
+{
+	struct t3cdev *tdev = &adapter->tdev;
+
+	INIT_LIST_HEAD(&tdev->ofld_dev_list);
+
+	cxgb3_set_dummy_ops(tdev);
+	tdev->send = t3_offload_tx;
+	tdev->ctl = cxgb_offload_ctl;
+	tdev->type = adapter->params.rev == 0 ? T3A : T3B;
+
+	register_tdev(tdev);
+}
+
+void __devexit cxgb3_adapter_unofld(struct adapter *adapter)
+{
+	struct t3cdev *tdev = &adapter->tdev;
+
+	tdev->recv = NULL;
+	tdev->neigh_update = NULL;
+
+	unregister_tdev(tdev);
+}
+
+void __init cxgb3_offload_init(void)
+{
+	int i;
+
+	for (i = 0; i < NUM_CPL_CMDS; ++i)
+		cpl_handlers[i] = do_bad_cpl;
+
+	t3_register_cpl_handler(CPL_SMT_WRITE_RPL, do_smt_write_rpl);
+	t3_register_cpl_handler(CPL_L2T_WRITE_RPL, do_l2t_write_rpl);
+	t3_register_cpl_handler(CPL_PASS_OPEN_RPL, do_stid_rpl);
+	t3_register_cpl_handler(CPL_CLOSE_LISTSRV_RPL, do_stid_rpl);
+	t3_register_cpl_handler(CPL_PASS_ACCEPT_REQ, do_cr);
+	t3_register_cpl_handler(CPL_PASS_ESTABLISH, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_ABORT_RPL_RSS, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_ABORT_RPL, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_RX_URG_NOTIFY, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_RX_DATA, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_TX_DATA_ACK, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_TX_DMA_ACK, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_ACT_OPEN_RPL, do_act_open_rpl);
+	t3_register_cpl_handler(CPL_PEER_CLOSE, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_CLOSE_CON_RPL, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_ABORT_REQ_RSS, do_abort_req_rss);
+	t3_register_cpl_handler(CPL_ACT_ESTABLISH, do_act_establish);
+	t3_register_cpl_handler(CPL_SET_TCB_RPL, do_set_tcb_rpl);
+	t3_register_cpl_handler(CPL_RDMA_TERMINATE, do_term);
+	t3_register_cpl_handler(CPL_RDMA_EC_STATUS, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_TRACE_PKT, do_trace);
+	t3_register_cpl_handler(CPL_RX_DATA_DDP, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_RX_DDP_COMPLETE, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_ISCSI_HDR, do_hwtid_rpl);
+}
diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h
new file mode 100644
index 0000000..0e6beb6
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_offload.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CXGB3_OFFLOAD_H
+#define _CXGB3_OFFLOAD_H
+
+#include <linux/list.h>
+#include <linux/skbuff.h>
+
+#include "l2t.h"
+
+#include "t3cdev.h"
+#include "t3_cpl.h"
+
+struct adapter;
+
+void cxgb3_offload_init(void);
+
+void cxgb3_adapter_ofld(struct adapter *adapter);
+void cxgb3_adapter_unofld(struct adapter *adapter);
+int cxgb3_offload_activate(struct adapter *adapter);
+void cxgb3_offload_deactivate(struct adapter *adapter);
+
+void cxgb3_set_dummy_ops(struct t3cdev *dev);
+
+/*
+ * Client registration.  Users of T3 driver must register themselves.
+ * The T3 driver will call the add function of every client for each T3
+ * adapter activated, passing up the t3cdev ptr.  Each client fills out an
+ * array of callback functions to process CPL messages.
+ */
+
+void cxgb3_register_client(struct cxgb3_client *client);
+void cxgb3_unregister_client(struct cxgb3_client *client);
+void cxgb3_add_clients(struct t3cdev *tdev);
+void cxgb3_remove_clients(struct t3cdev *tdev);
+
+typedef int (*cxgb3_cpl_handler_func)(struct t3cdev *dev,
+				      struct sk_buff *skb, void *ctx);
+
+struct cxgb3_client {
+	char *name;
+	void (*add) (struct t3cdev *);
+	void (*remove) (struct t3cdev *);
+	cxgb3_cpl_handler_func *handlers;
+	int (*redirect)(void *ctx, struct dst_entry *old,
+			struct dst_entry *new, struct l2t_entry *l2t);
+	struct list_head client_list;
+};
+
+/*
+ * TID allocation services.
+ */
+int cxgb3_alloc_atid(struct t3cdev *dev, struct cxgb3_client *client,
+		     void *ctx);
+int cxgb3_alloc_stid(struct t3cdev *dev, struct cxgb3_client *client,
+		     void *ctx);
+void *cxgb3_free_atid(struct t3cdev *dev, int atid);
+void cxgb3_free_stid(struct t3cdev *dev, int stid);
+void cxgb3_insert_tid(struct t3cdev *dev, struct cxgb3_client *client,
+		      void *ctx, unsigned int tid);
+void cxgb3_queue_tid_release(struct t3cdev *dev, unsigned int tid);
+void cxgb3_remove_tid(struct t3cdev *dev, void *ctx, unsigned int tid);
+
+struct t3c_tid_entry {
+	struct cxgb3_client *client;
+	void *ctx;
+};
+
+/* CPL message priority levels */
+enum {
+	CPL_PRIORITY_DATA = 0,	/* data messages */
+	CPL_PRIORITY_SETUP = 1,	/* connection setup messages */
+	CPL_PRIORITY_TEARDOWN = 0,	/* connection teardown messages */
+	CPL_PRIORITY_LISTEN = 1,	/* listen start/stop messages */
+	CPL_PRIORITY_ACK = 1,	/* RX ACK messages */
+	CPL_PRIORITY_CONTROL = 1	/* offload control messages */
+};
+
+/* Flags for return value of CPL message handlers */
+enum {
+	CPL_RET_BUF_DONE = 1, /* buffer processing done, buffer may be freed */
+	CPL_RET_BAD_MSG = 2,  /* bad CPL message (e.g., unknown opcode) */
+	CPL_RET_UNKNOWN_TID = 4	/* unexpected unknown TID */
+};
+
+typedef int (*cpl_handler_func)(struct t3cdev *dev, struct sk_buff *skb);
+
+/*
+ * Returns a pointer to the first byte of the CPL header in an sk_buff that
+ * contains a CPL message.
+ */
+static inline void *cplhdr(struct sk_buff *skb)
+{
+	return skb->data;
+}
+
+void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h);
+
+union listen_entry {
+	struct t3c_tid_entry t3c_tid;
+	union listen_entry *next;
+};
+
+union active_open_entry {
+	struct t3c_tid_entry t3c_tid;
+	union active_open_entry *next;
+};
+
+/*
+ * Holds the size, base address, free list start, etc of the TID, server TID,
+ * and active-open TID tables for a offload device.
+ * The tables themselves are allocated dynamically.
+ */
+struct tid_info {
+	struct t3c_tid_entry *tid_tab;
+	unsigned int ntids;
+	atomic_t tids_in_use;
+
+	union listen_entry *stid_tab;
+	unsigned int nstids;
+	unsigned int stid_base;
+
+	union active_open_entry *atid_tab;
+	unsigned int natids;
+	unsigned int atid_base;
+
+	/*
+	 * The following members are accessed R/W so we put them in their own
+	 * cache lines.
+	 *
+	 * XXX We could combine the atid fields above with the lock here since
+	 * atids are use once (unlike other tids).  OTOH the above fields are
+	 * usually in cache due to tid_tab.
+	 */
+	spinlock_t atid_lock ____cacheline_aligned_in_smp;
+	union active_open_entry *afree;
+	unsigned int atids_in_use;
+
+	spinlock_t stid_lock ____cacheline_aligned;
+	union listen_entry *sfree;
+	unsigned int stids_in_use;
+};
+
+struct t3c_data {
+	struct list_head list_node;
+	struct t3cdev *dev;
+	unsigned int tx_max_chunk;	/* max payload for TX_DATA */
+	unsigned int max_wrs;	/* max in-flight WRs per connection */
+	unsigned int nmtus;
+	const unsigned short *mtus;
+	struct tid_info tid_maps;
+
+	struct t3c_tid_entry *tid_release_list;
+	spinlock_t tid_release_lock;
+	struct work_struct tid_release_task;
+};
+
+/*
+ * t3cdev -> t3c_data accessor
+ */
+#define T3C_DATA(dev) (*(struct t3c_data **)&(dev)->l4opt)
+
+#endif
diff --git a/drivers/net/cxgb3/firmware_exports.h b/drivers/net/cxgb3/firmware_exports.h
new file mode 100644
index 0000000..6a835f6
--- /dev/null
+++ b/drivers/net/cxgb3/firmware_exports.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _FIRMWARE_EXPORTS_H_
+#define _FIRMWARE_EXPORTS_H_
+
+/* WR OPCODES supported by the firmware.
+ */
+#define	FW_WROPCODE_FORWARD			0x01
+#define FW_WROPCODE_BYPASS			0x05
+
+#define FW_WROPCODE_TUNNEL_TX_PKT		0x03
+
+#define FW_WROPOCDE_ULPTX_DATA_SGL		0x00
+#define FW_WROPCODE_ULPTX_MEM_READ		0x02
+#define FW_WROPCODE_ULPTX_PKT			0x04
+#define FW_WROPCODE_ULPTX_INVALIDATE		0x06
+
+#define FW_WROPCODE_TUNNEL_RX_PKT		0x07
+
+#define FW_WROPCODE_OFLD_GETTCB_RPL		0x08
+#define FW_WROPCODE_OFLD_CLOSE_CON		0x09
+#define FW_WROPCODE_OFLD_TP_ABORT_CON_REQ	0x0A
+#define FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL	0x0F
+#define FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ	0x0B
+#define FW_WROPCODE_OFLD_TP_ABORT_CON_RPL	0x0C
+#define FW_WROPCODE_OFLD_TX_DATA		0x0D
+#define FW_WROPCODE_OFLD_TX_DATA_ACK		0x0E
+
+#define FW_WROPCODE_RI_RDMA_INIT		0x10
+#define FW_WROPCODE_RI_RDMA_WRITE		0x11
+#define FW_WROPCODE_RI_RDMA_READ_REQ		0x12
+#define FW_WROPCODE_RI_RDMA_READ_RESP		0x13
+#define FW_WROPCODE_RI_SEND			0x14
+#define FW_WROPCODE_RI_TERMINATE		0x15
+#define FW_WROPCODE_RI_RDMA_READ		0x16
+#define FW_WROPCODE_RI_RECEIVE			0x17
+#define FW_WROPCODE_RI_BIND_MW			0x18
+#define FW_WROPCODE_RI_FASTREGISTER_MR		0x19
+#define FW_WROPCODE_RI_LOCAL_INV		0x1A
+#define FW_WROPCODE_RI_MODIFY_QP		0x1B
+#define FW_WROPCODE_RI_BYPASS			0x1C
+
+#define FW_WROPOCDE_RSVD			0x1E
+
+#define FW_WROPCODE_SGE_EGRESSCONTEXT_RR	0x1F
+
+#define FW_WROPCODE_MNGT			0x1D
+#define FW_MNGTOPCODE_PKTSCHED_SET		0x00
+
+/* Maximum size of a WR sent from the host, limited by the SGE. 
+ *
+ * Note: WR coming from ULP or TP are only limited by CIM. 
+ */
+#define FW_WR_SIZE			128
+
+/* Maximum number of outstanding WRs sent from the host. Value must be
+ * programmed in the CTRL/TUNNEL/QP SGE Egress Context and used by 
+ * offload modules to limit the number of WRs per connection.
+ */
+#define FW_T3_WR_NUM			16
+#define FW_N3_WR_NUM			7
+
+#ifndef N3
+# define FW_WR_NUM			FW_T3_WR_NUM
+#else
+# define FW_WR_NUM			FW_N3_WR_NUM
+#endif
+
+/* FW_TUNNEL_NUM corresponds to the number of supported TUNNEL Queues. These
+ * queues must start at SGE Egress Context FW_TUNNEL_SGEEC_START and must
+ * start at 'TID' (or 'uP Token') FW_TUNNEL_TID_START.
+ *
+ * Ingress Traffic (e.g. DMA completion credit)  for TUNNEL Queue[i] is sent 
+ * to RESP Queue[i].
+ */
+#define FW_TUNNEL_NUM			8
+#define FW_TUNNEL_SGEEC_START		8
+#define FW_TUNNEL_TID_START		65544
+
+/* FW_CTRL_NUM corresponds to the number of supported CTRL Queues. These queues
+ * must start at SGE Egress Context FW_CTRL_SGEEC_START and must start at 'TID'
+ * (or 'uP Token') FW_CTRL_TID_START.
+ *
+ * Ingress Traffic for CTRL Queue[i] is sent to RESP Queue[i].
+ */
+#define FW_CTRL_NUM			8
+#define FW_CTRL_SGEEC_START		65528
+#define FW_CTRL_TID_START		65536
+
+/* FW_OFLD_NUM corresponds to the number of supported OFFLOAD Queues. These 
+ * queues must start at SGE Egress Context FW_OFLD_SGEEC_START. 
+ * 
+ * Note: the 'uP Token' in the SGE Egress Context fields is irrelevant for 
+ * OFFLOAD Queues, as the host is responsible for providing the correct TID in
+ * every WR.
+ *
+ * Ingress Trafffic for OFFLOAD Queue[i] is sent to RESP Queue[i].
+ */
+#define FW_OFLD_NUM			8
+#define FW_OFLD_SGEEC_START		0
+
+/*
+ * 
+ */
+#define FW_RI_NUM			1
+#define FW_RI_SGEEC_START		65527
+#define FW_RI_TID_START			65552
+
+/*
+ * The RX_PKT_TID 
+ */
+#define FW_RX_PKT_NUM			1
+#define FW_RX_PKT_TID_START		65553
+
+/* FW_WRC_NUM corresponds to the number of Work Request Context that supported
+ * by the firmware.
+ */
+#define FW_WRC_NUM			\
+    (65536 + FW_TUNNEL_NUM + FW_CTRL_NUM + FW_RI_NUM + FW_RX_PKT_NUM)
+
+/*
+ * FW type and version.
+ */
+#define S_FW_VERSION_TYPE		28
+#define M_FW_VERSION_TYPE		0xF
+#define V_FW_VERSION_TYPE(x)		((x) << S_FW_VERSION_TYPE)
+#define G_FW_VERSION_TYPE(x)		\
+    (((x) >> S_FW_VERSION_TYPE) & M_FW_VERSION_TYPE)
+
+#define S_FW_VERSION_MAJOR		16
+#define M_FW_VERSION_MAJOR		0xFFF
+#define V_FW_VERSION_MAJOR(x)		((x) << S_FW_VERSION_MAJOR)
+#define G_FW_VERSION_MAJOR(x)		\
+    (((x) >> S_FW_VERSION_MAJOR) & M_FW_VERSION_MAJOR)
+
+#define S_FW_VERSION_MINOR		8
+#define M_FW_VERSION_MINOR		0xFF
+#define V_FW_VERSION_MINOR(x)		((x) << S_FW_VERSION_MINOR)
+#define G_FW_VERSION_MINOR(x)		\
+    (((x) >> S_FW_VERSION_MINOR) & M_FW_VERSION_MINOR)
+
+#define S_FW_VERSION_MICRO		0
+#define M_FW_VERSION_MICRO		0xFF
+#define V_FW_VERSION_MICRO(x)		((x) << S_FW_VERSION_MICRO)
+#define G_FW_VERSION_MICRO(x)		\
+    (((x) >> S_FW_VERSION_MICRO) & M_FW_VERSION_MICRO)
+
+#endif				/* _FIRMWARE_EXPORTS_H_ */
diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c
new file mode 100644
index 0000000..3c0cb85
--- /dev/null
+++ b/drivers/net/cxgb3/l2t.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/if_vlan.h>
+#include <linux/jhash.h>
+#include <net/neighbour.h>
+#include "common.h"
+#include "t3cdev.h"
+#include "cxgb3_defs.h"
+#include "l2t.h"
+#include "t3_cpl.h"
+#include "firmware_exports.h"
+
+#define VLAN_NONE 0xfff
+
+/*
+ * Module locking notes:  There is a RW lock protecting the L2 table as a
+ * whole plus a spinlock per L2T entry.  Entry lookups and allocations happen
+ * under the protection of the table lock, individual entry changes happen
+ * while holding that entry's spinlock.  The table lock nests outside the
+ * entry locks.  Allocations of new entries take the table lock as writers so
+ * no other lookups can happen while allocating new entries.  Entry updates
+ * take the table lock as readers so multiple entries can be updated in
+ * parallel.  An L2T entry can be dropped by decrementing its reference count
+ * and therefore can happen in parallel with entry allocation but no entry
+ * can change state or increment its ref count during allocation as both of
+ * these perform lookups.
+ */
+
+static inline unsigned int vlan_prio(const struct l2t_entry *e)
+{
+	return e->vlan >> 13;
+}
+
+static inline unsigned int arp_hash(u32 key, int ifindex,
+				    const struct l2t_data *d)
+{
+	return jhash_2words(key, ifindex, 0) & (d->nentries - 1);
+}
+
+static inline void neigh_replace(struct l2t_entry *e, struct neighbour *n)
+{
+	neigh_hold(n);
+	if (e->neigh)
+		neigh_release(e->neigh);
+	e->neigh = n;
+}
+
+/*
+ * Set up an L2T entry and send any packets waiting in the arp queue.  The
+ * supplied skb is used for the CPL_L2T_WRITE_REQ.  Must be called with the
+ * entry locked.
+ */
+static int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb,
+				  struct l2t_entry *e)
+{
+	struct cpl_l2t_write_req *req;
+
+	if (!skb) {
+		skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
+		if (!skb)
+			return -ENOMEM;
+	}
+
+	req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req));
+	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx));
+	req->params = htonl(V_L2T_W_IDX(e->idx) | V_L2T_W_IFF(e->smt_idx) |
+			    V_L2T_W_VLAN(e->vlan & VLAN_VID_MASK) |
+			    V_L2T_W_PRIO(vlan_prio(e)));
+	memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac));
+	memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac));
+	skb->priority = CPL_PRIORITY_CONTROL;
+	cxgb3_ofld_send(dev, skb);
+	while (e->arpq_head) {
+		skb = e->arpq_head;
+		e->arpq_head = skb->next;
+		skb->next = NULL;
+		cxgb3_ofld_send(dev, skb);
+	}
+	e->arpq_tail = NULL;
+	e->state = L2T_STATE_VALID;
+
+	return 0;
+}
+
+/*
+ * Add a packet to the an L2T entry's queue of packets awaiting resolution.
+ * Must be called with the entry's lock held.
+ */
+static inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb)
+{
+	skb->next = NULL;
+	if (e->arpq_head)
+		e->arpq_tail->next = skb;
+	else
+		e->arpq_head = skb;
+	e->arpq_tail = skb;
+}
+
+int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb,
+		     struct l2t_entry *e)
+{
+again:
+	switch (e->state) {
+	case L2T_STATE_STALE:	/* entry is stale, kick off revalidation */
+		neigh_event_send(e->neigh, NULL);
+		spin_lock_bh(&e->lock);
+		if (e->state == L2T_STATE_STALE)
+			e->state = L2T_STATE_VALID;
+		spin_unlock_bh(&e->lock);
+	case L2T_STATE_VALID:	/* fast-path, send the packet on */
+		return cxgb3_ofld_send(dev, skb);
+	case L2T_STATE_RESOLVING:
+		spin_lock_bh(&e->lock);
+		if (e->state != L2T_STATE_RESOLVING) {
+			/* ARP already completed */
+			spin_unlock_bh(&e->lock);
+			goto again;
+		}
+		arpq_enqueue(e, skb);
+		spin_unlock_bh(&e->lock);
+
+		/*
+		 * Only the first packet added to the arpq should kick off
+		 * resolution.  However, because the alloc_skb below can fail,
+		 * we allow each packet added to the arpq to retry resolution
+		 * as a way of recovering from transient memory exhaustion.
+		 * A better way would be to use a work request to retry L2T
+		 * entries when there's no memory.
+		 */
+		if (!neigh_event_send(e->neigh, NULL)) {
+			skb = alloc_skb(sizeof(struct cpl_l2t_write_req),
+					GFP_ATOMIC);
+			if (!skb)
+				break;
+
+			spin_lock_bh(&e->lock);
+			if (e->arpq_head)
+				setup_l2e_send_pending(dev, skb, e);
+			else	/* we lost the race */
+				__kfree_skb(skb);
+			spin_unlock_bh(&e->lock);
+		}
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(t3_l2t_send_slow);
+
+void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e)
+{
+again:
+	switch (e->state) {
+	case L2T_STATE_STALE:	/* entry is stale, kick off revalidation */
+		neigh_event_send(e->neigh, NULL);
+		spin_lock_bh(&e->lock);
+		if (e->state == L2T_STATE_STALE) {
+			e->state = L2T_STATE_VALID;
+		}
+		spin_unlock_bh(&e->lock);
+		return;
+	case L2T_STATE_VALID:	/* fast-path, send the packet on */
+		return;
+	case L2T_STATE_RESOLVING:
+		spin_lock_bh(&e->lock);
+		if (e->state != L2T_STATE_RESOLVING) {
+			/* ARP already completed */
+			spin_unlock_bh(&e->lock);
+			goto again;
+		}
+		spin_unlock_bh(&e->lock);
+
+		/*
+		 * Only the first packet added to the arpq should kick off
+		 * resolution.  However, because the alloc_skb below can fail,
+		 * we allow each packet added to the arpq to retry resolution
+		 * as a way of recovering from transient memory exhaustion.
+		 * A better way would be to use a work request to retry L2T
+		 * entries when there's no memory.
+		 */
+		neigh_event_send(e->neigh, NULL);
+	}
+	return;
+}
+
+EXPORT_SYMBOL(t3_l2t_send_event);
+
+/*
+ * Allocate a free L2T entry.  Must be called with l2t_data.lock held.
+ */
+static struct l2t_entry *alloc_l2e(struct l2t_data *d)
+{
+	struct l2t_entry *end, *e, **p;
+
+	if (!atomic_read(&d->nfree))
+		return NULL;
+
+	/* there's definitely a free entry */
+	for (e = d->rover, end = &d->l2tab[d->nentries]; e != end; ++e)
+		if (atomic_read(&e->refcnt) == 0)
+			goto found;
+
+	for (e = &d->l2tab[1]; atomic_read(&e->refcnt); ++e) ;
+found:
+	d->rover = e + 1;
+	atomic_dec(&d->nfree);
+
+	/*
+	 * The entry we found may be an inactive entry that is
+	 * presently in the hash table.  We need to remove it.
+	 */
+	if (e->state != L2T_STATE_UNUSED) {
+		int hash = arp_hash(e->addr, e->ifindex, d);
+
+		for (p = &d->l2tab[hash].first; *p; p = &(*p)->next)
+			if (*p == e) {
+				*p = e->next;
+				break;
+			}
+		e->state = L2T_STATE_UNUSED;
+	}
+	return e;
+}
+
+/*
+ * Called when an L2T entry has no more users.  The entry is left in the hash
+ * table since it is likely to be reused but we also bump nfree to indicate
+ * that the entry can be reallocated for a different neighbor.  We also drop
+ * the existing neighbor reference in case the neighbor is going away and is
+ * waiting on our reference.
+ *
+ * Because entries can be reallocated to other neighbors once their ref count
+ * drops to 0 we need to take the entry's lock to avoid races with a new
+ * incarnation.
+ */
+void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e)
+{
+	spin_lock_bh(&e->lock);
+	if (atomic_read(&e->refcnt) == 0) {	/* hasn't been recycled */
+		if (e->neigh) {
+			neigh_release(e->neigh);
+			e->neigh = NULL;
+		}
+	}
+	spin_unlock_bh(&e->lock);
+	atomic_inc(&d->nfree);
+}
+
+EXPORT_SYMBOL(t3_l2e_free);
+
+/*
+ * Update an L2T entry that was previously used for the same next hop as neigh.
+ * Must be called with softirqs disabled.
+ */
+static inline void reuse_entry(struct l2t_entry *e, struct neighbour *neigh)
+{
+	unsigned int nud_state;
+
+	spin_lock(&e->lock);	/* avoid race with t3_l2t_free */
+
+	if (neigh != e->neigh)
+		neigh_replace(e, neigh);
+	nud_state = neigh->nud_state;
+	if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac)) ||
+	    !(nud_state & NUD_VALID))
+		e->state = L2T_STATE_RESOLVING;
+	else if (nud_state & NUD_CONNECTED)
+		e->state = L2T_STATE_VALID;
+	else
+		e->state = L2T_STATE_STALE;
+	spin_unlock(&e->lock);
+}
+
+struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh,
+			     struct net_device *dev)
+{
+	struct l2t_entry *e;
+	struct l2t_data *d = L2DATA(cdev);
+	u32 addr = *(u32 *) neigh->primary_key;
+	int ifidx = neigh->dev->ifindex;
+	int hash = arp_hash(addr, ifidx, d);
+	struct port_info *p = netdev_priv(dev);
+	int smt_idx = p->port_id;
+
+	write_lock_bh(&d->lock);
+	for (e = d->l2tab[hash].first; e; e = e->next)
+		if (e->addr == addr && e->ifindex == ifidx &&
+		    e->smt_idx == smt_idx) {
+			l2t_hold(d, e);
+			if (atomic_read(&e->refcnt) == 1)
+				reuse_entry(e, neigh);
+			goto done;
+		}
+
+	/* Need to allocate a new entry */
+	e = alloc_l2e(d);
+	if (e) {
+		spin_lock(&e->lock);	/* avoid race with t3_l2t_free */
+		e->next = d->l2tab[hash].first;
+		d->l2tab[hash].first = e;
+		e->state = L2T_STATE_RESOLVING;
+		e->addr = addr;
+		e->ifindex = ifidx;
+		e->smt_idx = smt_idx;
+		atomic_set(&e->refcnt, 1);
+		neigh_replace(e, neigh);
+		if (neigh->dev->priv_flags & IFF_802_1Q_VLAN)
+			e->vlan = VLAN_DEV_INFO(neigh->dev)->vlan_id;
+		else
+			e->vlan = VLAN_NONE;
+		spin_unlock(&e->lock);
+	}
+done:
+	write_unlock_bh(&d->lock);
+	return e;
+}
+
+EXPORT_SYMBOL(t3_l2t_get);
+
+/*
+ * Called when address resolution fails for an L2T entry to handle packets
+ * on the arpq head.  If a packet specifies a failure handler it is invoked,
+ * otherwise the packets is sent to the offload device.
+ *
+ * XXX: maybe we should abandon the latter behavior and just require a failure
+ * handler.
+ */
+static void handle_failed_resolution(struct t3cdev *dev, struct sk_buff *arpq)
+{
+	while (arpq) {
+		struct sk_buff *skb = arpq;
+		struct l2t_skb_cb *cb = L2T_SKB_CB(skb);
+
+		arpq = skb->next;
+		skb->next = NULL;
+		if (cb->arp_failure_handler)
+			cb->arp_failure_handler(dev, skb);
+		else
+			cxgb3_ofld_send(dev, skb);
+	}
+}
+
+/*
+ * Called when the host's ARP layer makes a change to some entry that is
+ * loaded into the HW L2 table.
+ */
+void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh)
+{
+	struct l2t_entry *e;
+	struct sk_buff *arpq = NULL;
+	struct l2t_data *d = L2DATA(dev);
+	u32 addr = *(u32 *) neigh->primary_key;
+	int ifidx = neigh->dev->ifindex;
+	int hash = arp_hash(addr, ifidx, d);
+
+	read_lock_bh(&d->lock);
+	for (e = d->l2tab[hash].first; e; e = e->next)
+		if (e->addr == addr && e->ifindex == ifidx) {
+			spin_lock(&e->lock);
+			goto found;
+		}
+	read_unlock_bh(&d->lock);
+	return;
+
+found:
+	read_unlock(&d->lock);
+	if (atomic_read(&e->refcnt)) {
+		if (neigh != e->neigh)
+			neigh_replace(e, neigh);
+
+		if (e->state == L2T_STATE_RESOLVING) {
+			if (neigh->nud_state & NUD_FAILED) {
+				arpq = e->arpq_head;
+				e->arpq_head = e->arpq_tail = NULL;
+			} else if (neigh_is_connected(neigh))
+				setup_l2e_send_pending(dev, NULL, e);
+		} else {
+			e->state = neigh_is_connected(neigh) ?
+			    L2T_STATE_VALID : L2T_STATE_STALE;
+			if (memcmp(e->dmac, neigh->ha, 6))
+				setup_l2e_send_pending(dev, NULL, e);
+		}
+	}
+	spin_unlock_bh(&e->lock);
+
+	if (arpq)
+		handle_failed_resolution(dev, arpq);
+}
+
+struct l2t_data *t3_init_l2t(unsigned int l2t_capacity)
+{
+	struct l2t_data *d;
+	int i, size = sizeof(*d) + l2t_capacity * sizeof(struct l2t_entry);
+
+	d = cxgb_alloc_mem(size);
+	if (!d)
+		return NULL;
+
+	d->nentries = l2t_capacity;
+	d->rover = &d->l2tab[1];	/* entry 0 is not used */
+	atomic_set(&d->nfree, l2t_capacity - 1);
+	rwlock_init(&d->lock);
+
+	for (i = 0; i < l2t_capacity; ++i) {
+		d->l2tab[i].idx = i;
+		d->l2tab[i].state = L2T_STATE_UNUSED;
+		spin_lock_init(&d->l2tab[i].lock);
+		atomic_set(&d->l2tab[i].refcnt, 0);
+	}
+	return d;
+}
+
+void t3_free_l2t(struct l2t_data *d)
+{
+	cxgb_free_mem(d);
+}
+
diff --git a/drivers/net/cxgb3/l2t.h b/drivers/net/cxgb3/l2t.h
new file mode 100644
index 0000000..ba5d2cb
--- /dev/null
+++ b/drivers/net/cxgb3/l2t.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CHELSIO_L2T_H
+#define _CHELSIO_L2T_H
+
+#include <linux/spinlock.h>
+#include "t3cdev.h"
+#include <asm/atomic.h>
+
+enum {
+	L2T_STATE_VALID,	/* entry is up to date */
+	L2T_STATE_STALE,	/* entry may be used but needs revalidation */
+	L2T_STATE_RESOLVING,	/* entry needs address resolution */
+	L2T_STATE_UNUSED	/* entry not in use */
+};
+
+struct neighbour;
+struct sk_buff;
+
+/*
+ * Each L2T entry plays multiple roles.  First of all, it keeps state for the
+ * corresponding entry of the HW L2 table and maintains a queue of offload
+ * packets awaiting address resolution.  Second, it is a node of a hash table
+ * chain, where the nodes of the chain are linked together through their next
+ * pointer.  Finally, each node is a bucket of a hash table, pointing to the
+ * first element in its chain through its first pointer.
+ */
+struct l2t_entry {
+	u16 state;		/* entry state */
+	u16 idx;		/* entry index */
+	u32 addr;		/* dest IP address */
+	int ifindex;		/* neighbor's net_device's ifindex */
+	u16 smt_idx;		/* SMT index */
+	u16 vlan;		/* VLAN TCI (id: bits 0-11, prio: 13-15 */
+	struct neighbour *neigh;	/* associated neighbour */
+	struct l2t_entry *first;	/* start of hash chain */
+	struct l2t_entry *next;	/* next l2t_entry on chain */
+	struct sk_buff *arpq_head;	/* queue of packets awaiting resolution */
+	struct sk_buff *arpq_tail;
+	spinlock_t lock;
+	atomic_t refcnt;	/* entry reference count */
+	u8 dmac[6];		/* neighbour's MAC address */
+};
+
+struct l2t_data {
+	unsigned int nentries;	/* number of entries */
+	struct l2t_entry *rover;	/* starting point for next allocation */
+	atomic_t nfree;		/* number of free entries */
+	rwlock_t lock;
+	struct l2t_entry l2tab[0];
+};
+
+typedef void (*arp_failure_handler_func)(struct t3cdev * dev,
+					 struct sk_buff * skb);
+
+/*
+ * Callback stored in an skb to handle address resolution failure.
+ */
+struct l2t_skb_cb {
+	arp_failure_handler_func arp_failure_handler;
+};
+
+#define L2T_SKB_CB(skb) ((struct l2t_skb_cb *)(skb)->cb)
+
+static inline void set_arp_failure_handler(struct sk_buff *skb,
+					   arp_failure_handler_func hnd)
+{
+	L2T_SKB_CB(skb)->arp_failure_handler = hnd;
+}
+
+/*
+ * Getting to the L2 data from an offload device.
+ */
+#define L2DATA(dev) ((dev)->l2opt)
+
+#define W_TCB_L2T_IX    0
+#define S_TCB_L2T_IX    7
+#define M_TCB_L2T_IX    0x7ffULL
+#define V_TCB_L2T_IX(x) ((x) << S_TCB_L2T_IX)
+
+void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e);
+void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh);
+struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh,
+			     struct net_device *dev);
+int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb,
+		     struct l2t_entry *e);
+void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e);
+struct l2t_data *t3_init_l2t(unsigned int l2t_capacity);
+void t3_free_l2t(struct l2t_data *d);
+
+int cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb);
+
+static inline int l2t_send(struct t3cdev *dev, struct sk_buff *skb,
+			   struct l2t_entry *e)
+{
+	if (likely(e->state == L2T_STATE_VALID))
+		return cxgb3_ofld_send(dev, skb);
+	return t3_l2t_send_slow(dev, skb, e);
+}
+
+static inline void l2t_release(struct l2t_data *d, struct l2t_entry *e)
+{
+	if (atomic_dec_and_test(&e->refcnt))
+		t3_l2e_free(d, e);
+}
+
+static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e)
+{
+	if (atomic_add_return(1, &e->refcnt) == 1)	/* 0 -> 1 transition */
+		atomic_dec(&d->nfree);
+}
+
+#endif
diff --git a/drivers/net/cxgb3/mc5.c b/drivers/net/cxgb3/mc5.c
new file mode 100644
index 0000000..644d62e
--- /dev/null
+++ b/drivers/net/cxgb3/mc5.c
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+
+enum {
+	IDT75P52100 = 4,
+	IDT75N43102 = 5
+};
+
+/* DBGI command mode */
+enum {
+	DBGI_MODE_MBUS = 0,
+	DBGI_MODE_IDT52100 = 5
+};
+
+/* IDT 75P52100 commands */
+#define IDT_CMD_READ   0
+#define IDT_CMD_WRITE  1
+#define IDT_CMD_SEARCH 2
+#define IDT_CMD_LEARN  3
+
+/* IDT LAR register address and value for 144-bit mode (low 32 bits) */
+#define IDT_LAR_ADR0   	0x180006
+#define IDT_LAR_MODE144	0xffff0000
+
+/* IDT SCR and SSR addresses (low 32 bits) */
+#define IDT_SCR_ADR0  0x180000
+#define IDT_SSR0_ADR0 0x180002
+#define IDT_SSR1_ADR0 0x180004
+
+/* IDT GMR base address (low 32 bits) */
+#define IDT_GMR_BASE_ADR0 0x180020
+
+/* IDT data and mask array base addresses (low 32 bits) */
+#define IDT_DATARY_BASE_ADR0 0
+#define IDT_MSKARY_BASE_ADR0 0x80000
+
+/* IDT 75N43102 commands */
+#define IDT4_CMD_SEARCH144 3
+#define IDT4_CMD_WRITE     4
+#define IDT4_CMD_READ      5
+
+/* IDT 75N43102 SCR address (low 32 bits) */
+#define IDT4_SCR_ADR0  0x3
+
+/* IDT 75N43102 GMR base addresses (low 32 bits) */
+#define IDT4_GMR_BASE0 0x10
+#define IDT4_GMR_BASE1 0x20
+#define IDT4_GMR_BASE2 0x30
+
+/* IDT 75N43102 data and mask array base addresses (low 32 bits) */
+#define IDT4_DATARY_BASE_ADR0 0x1000000
+#define IDT4_MSKARY_BASE_ADR0 0x2000000
+
+#define MAX_WRITE_ATTEMPTS 5
+
+#define MAX_ROUTES 2048
+
+/*
+ * Issue a command to the TCAM and wait for its completion.  The address and
+ * any data required by the command must have been setup by the caller.
+ */
+static int mc5_cmd_write(struct adapter *adapter, u32 cmd)
+{
+	t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_CMD, cmd);
+	return t3_wait_op_done(adapter, A_MC5_DB_DBGI_RSP_STATUS,
+			       F_DBGIRSPVALID, 1, MAX_WRITE_ATTEMPTS, 1);
+}
+
+static inline void dbgi_wr_addr3(struct adapter *adapter, u32 v1, u32 v2,
+				 u32 v3)
+{
+	t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, v1);
+	t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR1, v2);
+	t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR2, v3);
+}
+
+static inline void dbgi_wr_data3(struct adapter *adapter, u32 v1, u32 v2,
+				 u32 v3)
+{
+	t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA0, v1);
+	t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA1, v2);
+	t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA2, v3);
+}
+
+static inline void dbgi_rd_rsp3(struct adapter *adapter, u32 *v1, u32 *v2,
+				u32 *v3)
+{
+	*v1 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA0);
+	*v2 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA1);
+	*v3 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA2);
+}
+
+/*
+ * Write data to the TCAM register at address (0, 0, addr_lo) using the TCAM
+ * command cmd.  The data to be written must have been set up by the caller.
+ * Returns -1 on failure, 0 on success.
+ */
+static int mc5_write(struct adapter *adapter, u32 addr_lo, u32 cmd)
+{
+	t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, addr_lo);
+	if (mc5_cmd_write(adapter, cmd) == 0)
+		return 0;
+	CH_ERR(adapter, "MC5 timeout writing to TCAM address 0x%x\n",
+	       addr_lo);
+	return -1;
+}
+
+static int init_mask_data_array(struct mc5 *mc5, u32 mask_array_base,
+				u32 data_array_base, u32 write_cmd,
+				int addr_shift)
+{
+	unsigned int i;
+	struct adapter *adap = mc5->adapter;
+
+	/*
+	 * We need the size of the TCAM data and mask arrays in terms of
+	 * 72-bit entries.
+	 */
+	unsigned int size72 = mc5->tcam_size;
+	unsigned int server_base = t3_read_reg(adap, A_MC5_DB_SERVER_INDEX);
+
+	if (mc5->mode == MC5_MODE_144_BIT) {
+		size72 *= 2;	/* 1 144-bit entry is 2 72-bit entries */
+		server_base *= 2;
+	}
+
+	/* Clear the data array */
+	dbgi_wr_data3(adap, 0, 0, 0);
+	for (i = 0; i < size72; i++)
+		if (mc5_write(adap, data_array_base + (i << addr_shift),
+			      write_cmd))
+			return -1;
+
+	/* Initialize the mask array. */
+	dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
+	for (i = 0; i < size72; i++) {
+		if (i == server_base)	/* entering server or routing region */
+			t3_write_reg(adap, A_MC5_DB_DBGI_REQ_DATA0,
+				     mc5->mode == MC5_MODE_144_BIT ?
+				     0xfffffff9 : 0xfffffffd);
+		if (mc5_write(adap, mask_array_base + (i << addr_shift),
+			      write_cmd))
+			return -1;
+	}
+	return 0;
+}
+
+static int init_idt52100(struct mc5 *mc5)
+{
+	int i;
+	struct adapter *adap = mc5->adapter;
+
+	t3_write_reg(adap, A_MC5_DB_RSP_LATENCY,
+		     V_RDLAT(0x15) | V_LRNLAT(0x15) | V_SRCHLAT(0x15));
+	t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 2);
+
+	/*
+	 * Use GMRs 14-15 for ELOOKUP, GMRs 12-13 for SYN lookups, and
+	 * GMRs 8-9 for ACK- and AOPEN searches.
+	 */
+	t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT_CMD_WRITE);
+	t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT_CMD_WRITE);
+	t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD, IDT_CMD_SEARCH);
+	t3_write_reg(adap, A_MC5_DB_AOPEN_LRN_CMD, IDT_CMD_LEARN);
+	t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT_CMD_SEARCH | 0x6000);
+	t3_write_reg(adap, A_MC5_DB_SYN_LRN_CMD, IDT_CMD_LEARN);
+	t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT_CMD_SEARCH);
+	t3_write_reg(adap, A_MC5_DB_ACK_LRN_CMD, IDT_CMD_LEARN);
+	t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT_CMD_SEARCH);
+	t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT_CMD_SEARCH | 0x7000);
+	t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT_CMD_WRITE);
+	t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT_CMD_READ);
+
+	/* Set DBGI command mode for IDT TCAM. */
+	t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100);
+
+	/* Set up LAR */
+	dbgi_wr_data3(adap, IDT_LAR_MODE144, 0, 0);
+	if (mc5_write(adap, IDT_LAR_ADR0, IDT_CMD_WRITE))
+		goto err;
+
+	/* Set up SSRs */
+	dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0);
+	if (mc5_write(adap, IDT_SSR0_ADR0, IDT_CMD_WRITE) ||
+	    mc5_write(adap, IDT_SSR1_ADR0, IDT_CMD_WRITE))
+		goto err;
+
+	/* Set up GMRs */
+	for (i = 0; i < 32; ++i) {
+		if (i >= 12 && i < 15)
+			dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff);
+		else if (i == 15)
+			dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff);
+		else
+			dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
+
+		if (mc5_write(adap, IDT_GMR_BASE_ADR0 + i, IDT_CMD_WRITE))
+			goto err;
+	}
+
+	/* Set up SCR */
+	dbgi_wr_data3(adap, 1, 0, 0);
+	if (mc5_write(adap, IDT_SCR_ADR0, IDT_CMD_WRITE))
+		goto err;
+
+	return init_mask_data_array(mc5, IDT_MSKARY_BASE_ADR0,
+				    IDT_DATARY_BASE_ADR0, IDT_CMD_WRITE, 0);
+err:
+	return -EIO;
+}
+
+static int init_idt43102(struct mc5 *mc5)
+{
+	int i;
+	struct adapter *adap = mc5->adapter;
+
+	t3_write_reg(adap, A_MC5_DB_RSP_LATENCY,
+		     adap->params.rev == 0 ? V_RDLAT(0xd) | V_SRCHLAT(0x11) :
+		     V_RDLAT(0xd) | V_SRCHLAT(0x12));
+
+	/*
+	 * Use GMRs 24-25 for ELOOKUP, GMRs 20-21 for SYN lookups, and no mask
+	 * for ACK- and AOPEN searches.
+	 */
+	t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT4_CMD_WRITE);
+	t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT4_CMD_WRITE);
+	t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD,
+		     IDT4_CMD_SEARCH144 | 0x3800);
+	t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT4_CMD_SEARCH144);
+	t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT4_CMD_SEARCH144 | 0x3800);
+	t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x3800);
+	t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x800);
+	t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT4_CMD_WRITE);
+	t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT4_CMD_READ);
+
+	t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 3);
+
+	/* Set DBGI command mode for IDT TCAM. */
+	t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100);
+
+	/* Set up GMRs */
+	dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
+	for (i = 0; i < 7; ++i)
+		if (mc5_write(adap, IDT4_GMR_BASE0 + i, IDT4_CMD_WRITE))
+			goto err;
+
+	for (i = 0; i < 4; ++i)
+		if (mc5_write(adap, IDT4_GMR_BASE2 + i, IDT4_CMD_WRITE))
+			goto err;
+
+	dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff);
+	if (mc5_write(adap, IDT4_GMR_BASE1, IDT4_CMD_WRITE) ||
+	    mc5_write(adap, IDT4_GMR_BASE1 + 1, IDT4_CMD_WRITE) ||
+	    mc5_write(adap, IDT4_GMR_BASE1 + 4, IDT4_CMD_WRITE))
+		goto err;
+
+	dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff);
+	if (mc5_write(adap, IDT4_GMR_BASE1 + 5, IDT4_CMD_WRITE))
+		goto err;
+
+	/* Set up SCR */
+	dbgi_wr_data3(adap, 0xf0000000, 0, 0);
+	if (mc5_write(adap, IDT4_SCR_ADR0, IDT4_CMD_WRITE))
+		goto err;
+
+	return init_mask_data_array(mc5, IDT4_MSKARY_BASE_ADR0,
+				    IDT4_DATARY_BASE_ADR0, IDT4_CMD_WRITE, 1);
+err:
+	return -EIO;
+}
+
+/* Put MC5 in DBGI mode. */
+static inline void mc5_dbgi_mode_enable(const struct mc5 *mc5)
+{
+	t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG,
+		     V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_DBGIEN);
+}
+
+/* Put MC5 in M-Bus mode. */
+static void mc5_dbgi_mode_disable(const struct mc5 *mc5)
+{
+	t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG,
+		     V_TMMODE(mc5->mode == MC5_MODE_72_BIT) |
+		     V_COMPEN(mc5->mode == MC5_MODE_72_BIT) |
+		     V_PRTYEN(mc5->parity_enabled) | F_MBUSEN);
+}
+
+/*
+ * Initialization that requires the OS and protocol layers to already
+ * be intialized goes here.
+ */
+int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters,
+		unsigned int nroutes)
+{
+	u32 cfg;
+	int err;
+	unsigned int tcam_size = mc5->tcam_size;
+	struct adapter *adap = mc5->adapter;
+
+	if (nroutes > MAX_ROUTES || nroutes + nservers + nfilters > tcam_size)
+		return -EINVAL;
+
+	/* Reset the TCAM */
+	cfg = t3_read_reg(adap, A_MC5_DB_CONFIG) & ~F_TMMODE;
+	cfg |= V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_TMRST;
+	t3_write_reg(adap, A_MC5_DB_CONFIG, cfg);
+	if (t3_wait_op_done(adap, A_MC5_DB_CONFIG, F_TMRDY, 1, 500, 0)) {
+		CH_ERR(adap, "TCAM reset timed out\n");
+		return -1;
+	}
+
+	t3_write_reg(adap, A_MC5_DB_ROUTING_TABLE_INDEX, tcam_size - nroutes);
+	t3_write_reg(adap, A_MC5_DB_FILTER_TABLE,
+		     tcam_size - nroutes - nfilters);
+	t3_write_reg(adap, A_MC5_DB_SERVER_INDEX,
+		     tcam_size - nroutes - nfilters - nservers);
+
+	mc5->parity_enabled = 1;
+
+	/* All the TCAM addresses we access have only the low 32 bits non 0 */
+	t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR1, 0);
+	t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR2, 0);
+
+	mc5_dbgi_mode_enable(mc5);
+
+	switch (mc5->part_type) {
+	case IDT75P52100:
+		err = init_idt52100(mc5);
+		break;
+	case IDT75N43102:
+		err = init_idt43102(mc5);
+		break;
+	default:
+		CH_ERR(adap, "Unsupported TCAM type %d\n", mc5->part_type);
+		err = -EINVAL;
+		break;
+	}
+
+	mc5_dbgi_mode_disable(mc5);
+	return err;
+}
+
+/*
+ *	read_mc5_range - dump a part of the memory managed by MC5
+ *	@mc5: the MC5 handle
+ *	@start: the start address for the dump
+ *	@n: number of 72-bit words to read
+ *	@buf: result buffer
+ *
+ *	Read n 72-bit words from MC5 memory from the given start location.
+ */
+int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start,
+		      unsigned int n, u32 *buf)
+{
+	u32 read_cmd;
+	int err = 0;
+	struct adapter *adap = mc5->adapter;
+
+	if (mc5->part_type == IDT75P52100)
+		read_cmd = IDT_CMD_READ;
+	else if (mc5->part_type == IDT75N43102)
+		read_cmd = IDT4_CMD_READ;
+	else
+		return -EINVAL;
+
+	mc5_dbgi_mode_enable(mc5);
+
+	while (n--) {
+		t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR0, start++);
+		if (mc5_cmd_write(adap, read_cmd)) {
+			err = -EIO;
+			break;
+		}
+		dbgi_rd_rsp3(adap, buf + 2, buf + 1, buf);
+		buf += 3;
+	}
+
+	mc5_dbgi_mode_disable(mc5);
+	return 0;
+}
+
+#define MC5_INT_FATAL (F_PARITYERR | F_REQQPARERR | F_DISPQPARERR)
+
+/*
+ * MC5 interrupt handler
+ */
+void t3_mc5_intr_handler(struct mc5 *mc5)
+{
+	struct adapter *adap = mc5->adapter;
+	u32 cause = t3_read_reg(adap, A_MC5_DB_INT_CAUSE);
+
+	if ((cause & F_PARITYERR) && mc5->parity_enabled) {
+		CH_ALERT(adap, "MC5 parity error\n");
+		mc5->stats.parity_err++;
+	}
+
+	if (cause & F_REQQPARERR) {
+		CH_ALERT(adap, "MC5 request queue parity error\n");
+		mc5->stats.reqq_parity_err++;
+	}
+
+	if (cause & F_DISPQPARERR) {
+		CH_ALERT(adap, "MC5 dispatch queue parity error\n");
+		mc5->stats.dispq_parity_err++;
+	}
+
+	if (cause & F_ACTRGNFULL)
+		mc5->stats.active_rgn_full++;
+	if (cause & F_NFASRCHFAIL)
+		mc5->stats.nfa_srch_err++;
+	if (cause & F_UNKNOWNCMD)
+		mc5->stats.unknown_cmd++;
+	if (cause & F_DELACTEMPTY)
+		mc5->stats.del_act_empty++;
+	if (cause & MC5_INT_FATAL)
+		t3_fatal_err(adap);
+
+	t3_write_reg(adap, A_MC5_DB_INT_CAUSE, cause);
+}
+
+void __devinit t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode)
+{
+#define K * 1024
+
+	static unsigned int tcam_part_size[] = {	/* in K 72-bit entries */
+		64 K, 128 K, 256 K, 32 K
+	};
+
+#undef K
+
+	u32 cfg = t3_read_reg(adapter, A_MC5_DB_CONFIG);
+
+	mc5->adapter = adapter;
+	mc5->mode = (unsigned char)mode;
+	mc5->part_type = (unsigned char)G_TMTYPE(cfg);
+	if (cfg & F_TMTYPEHI)
+		mc5->part_type |= 4;
+
+	mc5->tcam_size = tcam_part_size[G_TMPARTSIZE(cfg)];
+	if (mode == MC5_MODE_144_BIT)
+		mc5->tcam_size /= 2;
+}
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h
new file mode 100644
index 0000000..b56c5f5
--- /dev/null
+++ b/drivers/net/cxgb3/regs.h
@@ -0,0 +1,2195 @@
+#define A_SG_CONTROL 0x0
+
+#define S_DROPPKT    20
+#define V_DROPPKT(x) ((x) << S_DROPPKT)
+#define F_DROPPKT    V_DROPPKT(1U)
+
+#define S_EGRGENCTRL    19
+#define V_EGRGENCTRL(x) ((x) << S_EGRGENCTRL)
+#define F_EGRGENCTRL    V_EGRGENCTRL(1U)
+
+#define S_USERSPACESIZE    14
+#define M_USERSPACESIZE    0x1f
+#define V_USERSPACESIZE(x) ((x) << S_USERSPACESIZE)
+
+#define S_HOSTPAGESIZE    11
+#define M_HOSTPAGESIZE    0x7
+#define V_HOSTPAGESIZE(x) ((x) << S_HOSTPAGESIZE)
+
+#define S_FLMODE    9
+#define V_FLMODE(x) ((x) << S_FLMODE)
+#define F_FLMODE    V_FLMODE(1U)
+
+#define S_PKTSHIFT    6
+#define M_PKTSHIFT    0x7
+#define V_PKTSHIFT(x) ((x) << S_PKTSHIFT)
+
+#define S_ONEINTMULTQ    5
+#define V_ONEINTMULTQ(x) ((x) << S_ONEINTMULTQ)
+#define F_ONEINTMULTQ    V_ONEINTMULTQ(1U)
+
+#define S_BIGENDIANINGRESS    2
+#define V_BIGENDIANINGRESS(x) ((x) << S_BIGENDIANINGRESS)
+#define F_BIGENDIANINGRESS    V_BIGENDIANINGRESS(1U)
+
+#define S_ISCSICOALESCING    1
+#define V_ISCSICOALESCING(x) ((x) << S_ISCSICOALESCING)
+#define F_ISCSICOALESCING    V_ISCSICOALESCING(1U)
+
+#define S_GLOBALENABLE    0
+#define V_GLOBALENABLE(x) ((x) << S_GLOBALENABLE)
+#define F_GLOBALENABLE    V_GLOBALENABLE(1U)
+
+#define S_AVOIDCQOVFL    24
+#define V_AVOIDCQOVFL(x) ((x) << S_AVOIDCQOVFL)
+#define F_AVOIDCQOVFL    V_AVOIDCQOVFL(1U)
+
+#define S_OPTONEINTMULTQ    23
+#define V_OPTONEINTMULTQ(x) ((x) << S_OPTONEINTMULTQ)
+#define F_OPTONEINTMULTQ    V_OPTONEINTMULTQ(1U)
+
+#define S_CQCRDTCTRL    22
+#define V_CQCRDTCTRL(x) ((x) << S_CQCRDTCTRL)
+#define F_CQCRDTCTRL    V_CQCRDTCTRL(1U)
+
+#define A_SG_KDOORBELL 0x4
+
+#define S_SELEGRCNTX    31
+#define V_SELEGRCNTX(x) ((x) << S_SELEGRCNTX)
+#define F_SELEGRCNTX    V_SELEGRCNTX(1U)
+
+#define S_EGRCNTX    0
+#define M_EGRCNTX    0xffff
+#define V_EGRCNTX(x) ((x) << S_EGRCNTX)
+
+#define A_SG_GTS 0x8
+
+#define S_RSPQ    29
+#define M_RSPQ    0x7
+#define V_RSPQ(x) ((x) << S_RSPQ)
+#define G_RSPQ(x) (((x) >> S_RSPQ) & M_RSPQ)
+
+#define S_NEWTIMER    16
+#define M_NEWTIMER    0x1fff
+#define V_NEWTIMER(x) ((x) << S_NEWTIMER)
+
+#define S_NEWINDEX    0
+#define M_NEWINDEX    0xffff
+#define V_NEWINDEX(x) ((x) << S_NEWINDEX)
+
+#define A_SG_CONTEXT_CMD 0xc
+
+#define S_CONTEXT_CMD_OPCODE    28
+#define M_CONTEXT_CMD_OPCODE    0xf
+#define V_CONTEXT_CMD_OPCODE(x) ((x) << S_CONTEXT_CMD_OPCODE)
+
+#define S_CONTEXT_CMD_BUSY    27
+#define V_CONTEXT_CMD_BUSY(x) ((x) << S_CONTEXT_CMD_BUSY)
+#define F_CONTEXT_CMD_BUSY    V_CONTEXT_CMD_BUSY(1U)
+
+#define S_CQ_CREDIT    20
+
+#define M_CQ_CREDIT    0x7f
+
+#define V_CQ_CREDIT(x) ((x) << S_CQ_CREDIT)
+
+#define G_CQ_CREDIT(x) (((x) >> S_CQ_CREDIT) & M_CQ_CREDIT)
+
+#define S_CQ    19
+
+#define V_CQ(x) ((x) << S_CQ)
+#define F_CQ    V_CQ(1U)
+
+#define S_RESPONSEQ    18
+#define V_RESPONSEQ(x) ((x) << S_RESPONSEQ)
+#define F_RESPONSEQ    V_RESPONSEQ(1U)
+
+#define S_EGRESS    17
+#define V_EGRESS(x) ((x) << S_EGRESS)
+#define F_EGRESS    V_EGRESS(1U)
+
+#define S_FREELIST    16
+#define V_FREELIST(x) ((x) << S_FREELIST)
+#define F_FREELIST    V_FREELIST(1U)
+
+#define S_CONTEXT    0
+#define M_CONTEXT    0xffff
+#define V_CONTEXT(x) ((x) << S_CONTEXT)
+
+#define G_CONTEXT(x) (((x) >> S_CONTEXT) & M_CONTEXT)
+
+#define A_SG_CONTEXT_DATA0 0x10
+
+#define A_SG_CONTEXT_DATA1 0x14
+
+#define A_SG_CONTEXT_DATA2 0x18
+
+#define A_SG_CONTEXT_DATA3 0x1c
+
+#define A_SG_CONTEXT_MASK0 0x20
+
+#define A_SG_CONTEXT_MASK1 0x24
+
+#define A_SG_CONTEXT_MASK2 0x28
+
+#define A_SG_CONTEXT_MASK3 0x2c
+
+#define A_SG_RSPQ_CREDIT_RETURN 0x30
+
+#define S_CREDITS    0
+#define M_CREDITS    0xffff
+#define V_CREDITS(x) ((x) << S_CREDITS)
+
+#define A_SG_DATA_INTR 0x34
+
+#define S_ERRINTR    31
+#define V_ERRINTR(x) ((x) << S_ERRINTR)
+#define F_ERRINTR    V_ERRINTR(1U)
+
+#define A_SG_HI_DRB_HI_THRSH 0x38
+
+#define A_SG_HI_DRB_LO_THRSH 0x3c
+
+#define A_SG_LO_DRB_HI_THRSH 0x40
+
+#define A_SG_LO_DRB_LO_THRSH 0x44
+
+#define A_SG_RSPQ_FL_STATUS 0x4c
+
+#define S_RSPQ0DISABLED    8
+
+#define A_SG_EGR_RCQ_DRB_THRSH 0x54
+
+#define S_HIRCQDRBTHRSH    16
+#define M_HIRCQDRBTHRSH    0x7ff
+#define V_HIRCQDRBTHRSH(x) ((x) << S_HIRCQDRBTHRSH)
+
+#define S_LORCQDRBTHRSH    0
+#define M_LORCQDRBTHRSH    0x7ff
+#define V_LORCQDRBTHRSH(x) ((x) << S_LORCQDRBTHRSH)
+
+#define A_SG_EGR_CNTX_BADDR 0x58
+
+#define A_SG_INT_CAUSE 0x5c
+
+#define S_RSPQDISABLED    3
+#define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED)
+#define F_RSPQDISABLED    V_RSPQDISABLED(1U)
+
+#define S_RSPQCREDITOVERFOW    2
+#define V_RSPQCREDITOVERFOW(x) ((x) << S_RSPQCREDITOVERFOW)
+#define F_RSPQCREDITOVERFOW    V_RSPQCREDITOVERFOW(1U)
+
+#define A_SG_INT_ENABLE 0x60
+
+#define A_SG_CMDQ_CREDIT_TH 0x64
+
+#define S_TIMEOUT    8
+#define M_TIMEOUT    0xffffff
+#define V_TIMEOUT(x) ((x) << S_TIMEOUT)
+
+#define S_THRESHOLD    0
+#define M_THRESHOLD    0xff
+#define V_THRESHOLD(x) ((x) << S_THRESHOLD)
+
+#define A_SG_TIMER_TICK 0x68
+
+#define A_SG_CQ_CONTEXT_BADDR 0x6c
+
+#define A_SG_OCO_BASE 0x70
+
+#define S_BASE1    16
+#define M_BASE1    0xffff
+#define V_BASE1(x) ((x) << S_BASE1)
+
+#define A_SG_DRB_PRI_THRESH 0x74
+
+#define A_PCIX_INT_ENABLE 0x80
+
+#define S_MSIXPARERR    22
+#define M_MSIXPARERR    0x7
+
+#define V_MSIXPARERR(x) ((x) << S_MSIXPARERR)
+
+#define S_CFPARERR    18
+#define M_CFPARERR    0xf
+
+#define V_CFPARERR(x) ((x) << S_CFPARERR)
+
+#define S_RFPARERR    14
+#define M_RFPARERR    0xf
+
+#define V_RFPARERR(x) ((x) << S_RFPARERR)
+
+#define S_WFPARERR    12
+#define M_WFPARERR    0x3
+
+#define V_WFPARERR(x) ((x) << S_WFPARERR)
+
+#define S_PIOPARERR    11
+#define V_PIOPARERR(x) ((x) << S_PIOPARERR)
+#define F_PIOPARERR    V_PIOPARERR(1U)
+
+#define S_DETUNCECCERR    10
+#define V_DETUNCECCERR(x) ((x) << S_DETUNCECCERR)
+#define F_DETUNCECCERR    V_DETUNCECCERR(1U)
+
+#define S_DETCORECCERR    9
+#define V_DETCORECCERR(x) ((x) << S_DETCORECCERR)
+#define F_DETCORECCERR    V_DETCORECCERR(1U)
+
+#define S_RCVSPLCMPERR    8
+#define V_RCVSPLCMPERR(x) ((x) << S_RCVSPLCMPERR)
+#define F_RCVSPLCMPERR    V_RCVSPLCMPERR(1U)
+
+#define S_UNXSPLCMP    7
+#define V_UNXSPLCMP(x) ((x) << S_UNXSPLCMP)
+#define F_UNXSPLCMP    V_UNXSPLCMP(1U)
+
+#define S_SPLCMPDIS    6
+#define V_SPLCMPDIS(x) ((x) << S_SPLCMPDIS)
+#define F_SPLCMPDIS    V_SPLCMPDIS(1U)
+
+#define S_DETPARERR    5
+#define V_DETPARERR(x) ((x) << S_DETPARERR)
+#define F_DETPARERR    V_DETPARERR(1U)
+
+#define S_SIGSYSERR    4
+#define V_SIGSYSERR(x) ((x) << S_SIGSYSERR)
+#define F_SIGSYSERR    V_SIGSYSERR(1U)
+
+#define S_RCVMSTABT    3
+#define V_RCVMSTABT(x) ((x) << S_RCVMSTABT)
+#define F_RCVMSTABT    V_RCVMSTABT(1U)
+
+#define S_RCVTARABT    2
+#define V_RCVTARABT(x) ((x) << S_RCVTARABT)
+#define F_RCVTARABT    V_RCVTARABT(1U)
+
+#define S_SIGTARABT    1
+#define V_SIGTARABT(x) ((x) << S_SIGTARABT)
+#define F_SIGTARABT    V_SIGTARABT(1U)
+
+#define S_MSTDETPARERR    0
+#define V_MSTDETPARERR(x) ((x) << S_MSTDETPARERR)
+#define F_MSTDETPARERR    V_MSTDETPARERR(1U)
+
+#define A_PCIX_INT_CAUSE 0x84
+
+#define A_PCIX_CFG 0x88
+
+#define S_CLIDECEN    18
+#define V_CLIDECEN(x) ((x) << S_CLIDECEN)
+#define F_CLIDECEN    V_CLIDECEN(1U)
+
+#define A_PCIX_MODE 0x8c
+
+#define S_PCLKRANGE    6
+#define M_PCLKRANGE    0x3
+#define V_PCLKRANGE(x) ((x) << S_PCLKRANGE)
+#define G_PCLKRANGE(x) (((x) >> S_PCLKRANGE) & M_PCLKRANGE)
+
+#define S_PCIXINITPAT    2
+#define M_PCIXINITPAT    0xf
+#define V_PCIXINITPAT(x) ((x) << S_PCIXINITPAT)
+#define G_PCIXINITPAT(x) (((x) >> S_PCIXINITPAT) & M_PCIXINITPAT)
+
+#define S_64BIT    0
+#define V_64BIT(x) ((x) << S_64BIT)
+#define F_64BIT    V_64BIT(1U)
+
+#define A_PCIE_INT_ENABLE 0x80
+
+#define S_BISTERR    15
+#define M_BISTERR    0xff
+
+#define V_BISTERR(x) ((x) << S_BISTERR)
+
+#define S_PCIE_MSIXPARERR    12
+#define M_PCIE_MSIXPARERR    0x7
+
+#define V_PCIE_MSIXPARERR(x) ((x) << S_PCIE_MSIXPARERR)
+
+#define S_PCIE_CFPARERR    11
+#define V_PCIE_CFPARERR(x) ((x) << S_PCIE_CFPARERR)
+#define F_PCIE_CFPARERR    V_PCIE_CFPARERR(1U)
+
+#define S_PCIE_RFPARERR    10
+#define V_PCIE_RFPARERR(x) ((x) << S_PCIE_RFPARERR)
+#define F_PCIE_RFPARERR    V_PCIE_RFPARERR(1U)
+
+#define S_PCIE_WFPARERR    9
+#define V_PCIE_WFPARERR(x) ((x) << S_PCIE_WFPARERR)
+#define F_PCIE_WFPARERR    V_PCIE_WFPARERR(1U)
+
+#define S_PCIE_PIOPARERR    8
+#define V_PCIE_PIOPARERR(x) ((x) << S_PCIE_PIOPARERR)
+#define F_PCIE_PIOPARERR    V_PCIE_PIOPARERR(1U)
+
+#define S_UNXSPLCPLERRC    7
+#define V_UNXSPLCPLERRC(x) ((x) << S_UNXSPLCPLERRC)
+#define F_UNXSPLCPLERRC    V_UNXSPLCPLERRC(1U)
+
+#define S_UNXSPLCPLERRR    6
+#define V_UNXSPLCPLERRR(x) ((x) << S_UNXSPLCPLERRR)
+#define F_UNXSPLCPLERRR    V_UNXSPLCPLERRR(1U)
+
+#define S_PEXERR    0
+#define V_PEXERR(x) ((x) << S_PEXERR)
+#define F_PEXERR    V_PEXERR(1U)
+
+#define A_PCIE_INT_CAUSE 0x84
+
+#define A_PCIE_CFG 0x88
+
+#define S_PCIE_CLIDECEN    16
+#define V_PCIE_CLIDECEN(x) ((x) << S_PCIE_CLIDECEN)
+#define F_PCIE_CLIDECEN    V_PCIE_CLIDECEN(1U)
+
+#define S_CRSTWRMMODE    0
+#define V_CRSTWRMMODE(x) ((x) << S_CRSTWRMMODE)
+#define F_CRSTWRMMODE    V_CRSTWRMMODE(1U)
+
+#define A_PCIE_MODE 0x8c
+
+#define S_NUMFSTTRNSEQRX    10
+#define M_NUMFSTTRNSEQRX    0xff
+#define V_NUMFSTTRNSEQRX(x) ((x) << S_NUMFSTTRNSEQRX)
+#define G_NUMFSTTRNSEQRX(x) (((x) >> S_NUMFSTTRNSEQRX) & M_NUMFSTTRNSEQRX)
+
+#define A_PCIE_PEX_CTRL0 0x98
+
+#define S_NUMFSTTRNSEQ    22
+#define M_NUMFSTTRNSEQ    0xff
+#define V_NUMFSTTRNSEQ(x) ((x) << S_NUMFSTTRNSEQ)
+#define G_NUMFSTTRNSEQ(x) (((x) >> S_NUMFSTTRNSEQ) & M_NUMFSTTRNSEQ)
+
+#define S_REPLAYLMT    2
+#define M_REPLAYLMT    0xfffff
+
+#define V_REPLAYLMT(x) ((x) << S_REPLAYLMT)
+
+#define A_PCIE_PEX_CTRL1 0x9c
+
+#define S_T3A_ACKLAT    0
+#define M_T3A_ACKLAT    0x7ff
+
+#define V_T3A_ACKLAT(x) ((x) << S_T3A_ACKLAT)
+
+#define S_ACKLAT    0
+#define M_ACKLAT    0x1fff
+
+#define V_ACKLAT(x) ((x) << S_ACKLAT)
+
+#define A_PCIE_PEX_ERR 0xa4
+
+#define A_T3DBG_GPIO_EN 0xd0
+
+#define S_GPIO11_OEN    27
+#define V_GPIO11_OEN(x) ((x) << S_GPIO11_OEN)
+#define F_GPIO11_OEN    V_GPIO11_OEN(1U)
+
+#define S_GPIO10_OEN    26
+#define V_GPIO10_OEN(x) ((x) << S_GPIO10_OEN)
+#define F_GPIO10_OEN    V_GPIO10_OEN(1U)
+
+#define S_GPIO7_OEN    23
+#define V_GPIO7_OEN(x) ((x) << S_GPIO7_OEN)
+#define F_GPIO7_OEN    V_GPIO7_OEN(1U)
+
+#define S_GPIO6_OEN    22
+#define V_GPIO6_OEN(x) ((x) << S_GPIO6_OEN)
+#define F_GPIO6_OEN    V_GPIO6_OEN(1U)
+
+#define S_GPIO5_OEN    21
+#define V_GPIO5_OEN(x) ((x) << S_GPIO5_OEN)
+#define F_GPIO5_OEN    V_GPIO5_OEN(1U)
+
+#define S_GPIO4_OEN    20
+#define V_GPIO4_OEN(x) ((x) << S_GPIO4_OEN)
+#define F_GPIO4_OEN    V_GPIO4_OEN(1U)
+
+#define S_GPIO2_OEN    18
+#define V_GPIO2_OEN(x) ((x) << S_GPIO2_OEN)
+#define F_GPIO2_OEN    V_GPIO2_OEN(1U)
+
+#define S_GPIO1_OEN    17
+#define V_GPIO1_OEN(x) ((x) << S_GPIO1_OEN)
+#define F_GPIO1_OEN    V_GPIO1_OEN(1U)
+
+#define S_GPIO0_OEN    16
+#define V_GPIO0_OEN(x) ((x) << S_GPIO0_OEN)
+#define F_GPIO0_OEN    V_GPIO0_OEN(1U)
+
+#define S_GPIO10_OUT_VAL    10
+#define V_GPIO10_OUT_VAL(x) ((x) << S_GPIO10_OUT_VAL)
+#define F_GPIO10_OUT_VAL    V_GPIO10_OUT_VAL(1U)
+
+#define S_GPIO7_OUT_VAL    7
+#define V_GPIO7_OUT_VAL(x) ((x) << S_GPIO7_OUT_VAL)
+#define F_GPIO7_OUT_VAL    V_GPIO7_OUT_VAL(1U)
+
+#define S_GPIO6_OUT_VAL    6
+#define V_GPIO6_OUT_VAL(x) ((x) << S_GPIO6_OUT_VAL)
+#define F_GPIO6_OUT_VAL    V_GPIO6_OUT_VAL(1U)
+
+#define S_GPIO5_OUT_VAL    5
+#define V_GPIO5_OUT_VAL(x) ((x) << S_GPIO5_OUT_VAL)
+#define F_GPIO5_OUT_VAL    V_GPIO5_OUT_VAL(1U)
+
+#define S_GPIO4_OUT_VAL    4
+#define V_GPIO4_OUT_VAL(x) ((x) << S_GPIO4_OUT_VAL)
+#define F_GPIO4_OUT_VAL    V_GPIO4_OUT_VAL(1U)
+
+#define S_GPIO2_OUT_VAL    2
+#define V_GPIO2_OUT_VAL(x) ((x) << S_GPIO2_OUT_VAL)
+#define F_GPIO2_OUT_VAL    V_GPIO2_OUT_VAL(1U)
+
+#define S_GPIO1_OUT_VAL    1
+#define V_GPIO1_OUT_VAL(x) ((x) << S_GPIO1_OUT_VAL)
+#define F_GPIO1_OUT_VAL    V_GPIO1_OUT_VAL(1U)
+
+#define S_GPIO0_OUT_VAL    0
+#define V_GPIO0_OUT_VAL(x) ((x) << S_GPIO0_OUT_VAL)
+#define F_GPIO0_OUT_VAL    V_GPIO0_OUT_VAL(1U)
+
+#define A_T3DBG_INT_ENABLE 0xd8
+
+#define S_GPIO11    11
+#define V_GPIO11(x) ((x) << S_GPIO11)
+#define F_GPIO11    V_GPIO11(1U)
+
+#define S_GPIO10    10
+#define V_GPIO10(x) ((x) << S_GPIO10)
+#define F_GPIO10    V_GPIO10(1U)
+
+#define S_GPIO7    7
+#define V_GPIO7(x) ((x) << S_GPIO7)
+#define F_GPIO7    V_GPIO7(1U)
+
+#define S_GPIO6    6
+#define V_GPIO6(x) ((x) << S_GPIO6)
+#define F_GPIO6    V_GPIO6(1U)
+
+#define S_GPIO5    5
+#define V_GPIO5(x) ((x) << S_GPIO5)
+#define F_GPIO5    V_GPIO5(1U)
+
+#define S_GPIO4    4
+#define V_GPIO4(x) ((x) << S_GPIO4)
+#define F_GPIO4    V_GPIO4(1U)
+
+#define S_GPIO3    3
+#define V_GPIO3(x) ((x) << S_GPIO3)
+#define F_GPIO3    V_GPIO3(1U)
+
+#define S_GPIO2    2
+#define V_GPIO2(x) ((x) << S_GPIO2)
+#define F_GPIO2    V_GPIO2(1U)
+
+#define S_GPIO1    1
+#define V_GPIO1(x) ((x) << S_GPIO1)
+#define F_GPIO1    V_GPIO1(1U)
+
+#define S_GPIO0    0
+#define V_GPIO0(x) ((x) << S_GPIO0)
+#define F_GPIO0    V_GPIO0(1U)
+
+#define A_T3DBG_INT_CAUSE 0xdc
+
+#define A_T3DBG_GPIO_ACT_LOW 0xf0
+
+#define MC7_PMRX_BASE_ADDR 0x100
+
+#define A_MC7_CFG 0x100
+
+#define S_IFEN    13
+#define V_IFEN(x) ((x) << S_IFEN)
+#define F_IFEN    V_IFEN(1U)
+
+#define S_TERM150    11
+#define V_TERM150(x) ((x) << S_TERM150)
+#define F_TERM150    V_TERM150(1U)
+
+#define S_SLOW    10
+#define V_SLOW(x) ((x) << S_SLOW)
+#define F_SLOW    V_SLOW(1U)
+
+#define S_WIDTH    8
+#define M_WIDTH    0x3
+#define V_WIDTH(x) ((x) << S_WIDTH)
+#define G_WIDTH(x) (((x) >> S_WIDTH) & M_WIDTH)
+
+#define S_BKS    6
+#define V_BKS(x) ((x) << S_BKS)
+#define F_BKS    V_BKS(1U)
+
+#define S_ORG    5
+#define V_ORG(x) ((x) << S_ORG)
+#define F_ORG    V_ORG(1U)
+
+#define S_DEN    2
+#define M_DEN    0x7
+#define V_DEN(x) ((x) << S_DEN)
+#define G_DEN(x) (((x) >> S_DEN) & M_DEN)
+
+#define S_RDY    1
+#define V_RDY(x) ((x) << S_RDY)
+#define F_RDY    V_RDY(1U)
+
+#define S_CLKEN    0
+#define V_CLKEN(x) ((x) << S_CLKEN)
+#define F_CLKEN    V_CLKEN(1U)
+
+#define A_MC7_MODE 0x104
+
+#define S_BUSY    31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY    V_BUSY(1U)
+
+#define S_BUSY    31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY    V_BUSY(1U)
+
+#define A_MC7_EXT_MODE1 0x108
+
+#define A_MC7_EXT_MODE2 0x10c
+
+#define A_MC7_EXT_MODE3 0x110
+
+#define A_MC7_PRE 0x114
+
+#define A_MC7_REF 0x118
+
+#define S_PREREFDIV    1
+#define M_PREREFDIV    0x3fff
+#define V_PREREFDIV(x) ((x) << S_PREREFDIV)
+
+#define S_PERREFEN    0
+#define V_PERREFEN(x) ((x) << S_PERREFEN)
+#define F_PERREFEN    V_PERREFEN(1U)
+
+#define A_MC7_DLL 0x11c
+
+#define S_DLLENB    1
+#define V_DLLENB(x) ((x) << S_DLLENB)
+#define F_DLLENB    V_DLLENB(1U)
+
+#define S_DLLRST    0
+#define V_DLLRST(x) ((x) << S_DLLRST)
+#define F_DLLRST    V_DLLRST(1U)
+
+#define A_MC7_PARM 0x120
+
+#define S_ACTTOPREDLY    26
+#define M_ACTTOPREDLY    0xf
+#define V_ACTTOPREDLY(x) ((x) << S_ACTTOPREDLY)
+
+#define S_ACTTORDWRDLY    23
+#define M_ACTTORDWRDLY    0x7
+#define V_ACTTORDWRDLY(x) ((x) << S_ACTTORDWRDLY)
+
+#define S_PRECYC    20
+#define M_PRECYC    0x7
+#define V_PRECYC(x) ((x) << S_PRECYC)
+
+#define S_REFCYC    13
+#define M_REFCYC    0x7f
+#define V_REFCYC(x) ((x) << S_REFCYC)
+
+#define S_BKCYC    8
+#define M_BKCYC    0x1f
+#define V_BKCYC(x) ((x) << S_BKCYC)
+
+#define S_WRTORDDLY    4
+#define M_WRTORDDLY    0xf
+#define V_WRTORDDLY(x) ((x) << S_WRTORDDLY)
+
+#define S_RDTOWRDLY    0
+#define M_RDTOWRDLY    0xf
+#define V_RDTOWRDLY(x) ((x) << S_RDTOWRDLY)
+
+#define A_MC7_CAL 0x128
+
+#define S_BUSY    31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY    V_BUSY(1U)
+
+#define S_BUSY    31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY    V_BUSY(1U)
+
+#define S_CAL_FAULT    30
+#define V_CAL_FAULT(x) ((x) << S_CAL_FAULT)
+#define F_CAL_FAULT    V_CAL_FAULT(1U)
+
+#define S_SGL_CAL_EN    20
+#define V_SGL_CAL_EN(x) ((x) << S_SGL_CAL_EN)
+#define F_SGL_CAL_EN    V_SGL_CAL_EN(1U)
+
+#define A_MC7_ERR_ADDR 0x12c
+
+#define A_MC7_ECC 0x130
+
+#define S_ECCCHKEN    1
+#define V_ECCCHKEN(x) ((x) << S_ECCCHKEN)
+#define F_ECCCHKEN    V_ECCCHKEN(1U)
+
+#define S_ECCGENEN    0
+#define V_ECCGENEN(x) ((x) << S_ECCGENEN)
+#define F_ECCGENEN    V_ECCGENEN(1U)
+
+#define A_MC7_CE_ADDR 0x134
+
+#define A_MC7_CE_DATA0 0x138
+
+#define A_MC7_CE_DATA1 0x13c
+
+#define A_MC7_CE_DATA2 0x140
+
+#define S_DATA    0
+#define M_DATA    0xff
+
+#define G_DATA(x) (((x) >> S_DATA) & M_DATA)
+
+#define A_MC7_UE_ADDR 0x144
+
+#define A_MC7_UE_DATA0 0x148
+
+#define A_MC7_UE_DATA1 0x14c
+
+#define A_MC7_UE_DATA2 0x150
+
+#define A_MC7_BD_ADDR 0x154
+
+#define S_ADDR    3
+
+#define M_ADDR    0x1fffffff
+
+#define A_MC7_BD_DATA0 0x158
+
+#define A_MC7_BD_DATA1 0x15c
+
+#define A_MC7_BD_OP 0x164
+
+#define S_OP    0
+
+#define V_OP(x) ((x) << S_OP)
+#define F_OP    V_OP(1U)
+
+#define F_OP    V_OP(1U)
+#define A_SF_OP 0x6dc
+
+#define A_MC7_BIST_ADDR_BEG 0x168
+
+#define A_MC7_BIST_ADDR_END 0x16c
+
+#define A_MC7_BIST_DATA 0x170
+
+#define A_MC7_BIST_OP 0x174
+
+#define S_CONT    3
+#define V_CONT(x) ((x) << S_CONT)
+#define F_CONT    V_CONT(1U)
+
+#define F_CONT    V_CONT(1U)
+
+#define A_MC7_INT_ENABLE 0x178
+
+#define S_AE    17
+#define V_AE(x) ((x) << S_AE)
+#define F_AE    V_AE(1U)
+
+#define S_PE    2
+#define M_PE    0x7fff
+
+#define V_PE(x) ((x) << S_PE)
+
+#define G_PE(x) (((x) >> S_PE) & M_PE)
+
+#define S_UE    1
+#define V_UE(x) ((x) << S_UE)
+#define F_UE    V_UE(1U)
+
+#define S_CE    0
+#define V_CE(x) ((x) << S_CE)
+#define F_CE    V_CE(1U)
+
+#define A_MC7_INT_CAUSE 0x17c
+
+#define MC7_PMTX_BASE_ADDR 0x180
+
+#define MC7_CM_BASE_ADDR 0x200
+
+#define A_CIM_BOOT_CFG 0x280
+
+#define S_BOOTADDR    2
+#define M_BOOTADDR    0x3fffffff
+#define V_BOOTADDR(x) ((x) << S_BOOTADDR)
+
+#define A_CIM_SDRAM_BASE_ADDR 0x28c
+
+#define A_CIM_SDRAM_ADDR_SIZE 0x290
+
+#define A_CIM_HOST_INT_ENABLE 0x298
+
+#define A_CIM_HOST_INT_CAUSE 0x29c
+
+#define S_BLKWRPLINT    12
+#define V_BLKWRPLINT(x) ((x) << S_BLKWRPLINT)
+#define F_BLKWRPLINT    V_BLKWRPLINT(1U)
+
+#define S_BLKRDPLINT    11
+#define V_BLKRDPLINT(x) ((x) << S_BLKRDPLINT)
+#define F_BLKRDPLINT    V_BLKRDPLINT(1U)
+
+#define S_BLKWRCTLINT    10
+#define V_BLKWRCTLINT(x) ((x) << S_BLKWRCTLINT)
+#define F_BLKWRCTLINT    V_BLKWRCTLINT(1U)
+
+#define S_BLKRDCTLINT    9
+#define V_BLKRDCTLINT(x) ((x) << S_BLKRDCTLINT)
+#define F_BLKRDCTLINT    V_BLKRDCTLINT(1U)
+
+#define S_BLKWRFLASHINT    8
+#define V_BLKWRFLASHINT(x) ((x) << S_BLKWRFLASHINT)
+#define F_BLKWRFLASHINT    V_BLKWRFLASHINT(1U)
+
+#define S_BLKRDFLASHINT    7
+#define V_BLKRDFLASHINT(x) ((x) << S_BLKRDFLASHINT)
+#define F_BLKRDFLASHINT    V_BLKRDFLASHINT(1U)
+
+#define S_SGLWRFLASHINT    6
+#define V_SGLWRFLASHINT(x) ((x) << S_SGLWRFLASHINT)
+#define F_SGLWRFLASHINT    V_SGLWRFLASHINT(1U)
+
+#define S_WRBLKFLASHINT    5
+#define V_WRBLKFLASHINT(x) ((x) << S_WRBLKFLASHINT)
+#define F_WRBLKFLASHINT    V_WRBLKFLASHINT(1U)
+
+#define S_BLKWRBOOTINT    4
+#define V_BLKWRBOOTINT(x) ((x) << S_BLKWRBOOTINT)
+#define F_BLKWRBOOTINT    V_BLKWRBOOTINT(1U)
+
+#define S_FLASHRANGEINT    2
+#define V_FLASHRANGEINT(x) ((x) << S_FLASHRANGEINT)
+#define F_FLASHRANGEINT    V_FLASHRANGEINT(1U)
+
+#define S_SDRAMRANGEINT    1
+#define V_SDRAMRANGEINT(x) ((x) << S_SDRAMRANGEINT)
+#define F_SDRAMRANGEINT    V_SDRAMRANGEINT(1U)
+
+#define S_RSVDSPACEINT    0
+#define V_RSVDSPACEINT(x) ((x) << S_RSVDSPACEINT)
+#define F_RSVDSPACEINT    V_RSVDSPACEINT(1U)
+
+#define A_CIM_HOST_ACC_CTRL 0x2b0
+
+#define S_HOSTBUSY    17
+#define V_HOSTBUSY(x) ((x) << S_HOSTBUSY)
+#define F_HOSTBUSY    V_HOSTBUSY(1U)
+
+#define A_CIM_HOST_ACC_DATA 0x2b4
+
+#define A_TP_IN_CONFIG 0x300
+
+#define S_NICMODE    14
+#define V_NICMODE(x) ((x) << S_NICMODE)
+#define F_NICMODE    V_NICMODE(1U)
+
+#define F_NICMODE    V_NICMODE(1U)
+
+#define S_IPV6ENABLE    15
+#define V_IPV6ENABLE(x) ((x) << S_IPV6ENABLE)
+#define F_IPV6ENABLE    V_IPV6ENABLE(1U)
+
+#define A_TP_OUT_CONFIG 0x304
+
+#define S_VLANEXTRACTIONENABLE    12
+
+#define A_TP_GLOBAL_CONFIG 0x308
+
+#define S_TXPACINGENABLE    24
+#define V_TXPACINGENABLE(x) ((x) << S_TXPACINGENABLE)
+#define F_TXPACINGENABLE    V_TXPACINGENABLE(1U)
+
+#define S_PATHMTU    15
+#define V_PATHMTU(x) ((x) << S_PATHMTU)
+#define F_PATHMTU    V_PATHMTU(1U)
+
+#define S_IPCHECKSUMOFFLOAD    13
+#define V_IPCHECKSUMOFFLOAD(x) ((x) << S_IPCHECKSUMOFFLOAD)
+#define F_IPCHECKSUMOFFLOAD    V_IPCHECKSUMOFFLOAD(1U)
+
+#define S_UDPCHECKSUMOFFLOAD    12
+#define V_UDPCHECKSUMOFFLOAD(x) ((x) << S_UDPCHECKSUMOFFLOAD)
+#define F_UDPCHECKSUMOFFLOAD    V_UDPCHECKSUMOFFLOAD(1U)
+
+#define S_TCPCHECKSUMOFFLOAD    11
+#define V_TCPCHECKSUMOFFLOAD(x) ((x) << S_TCPCHECKSUMOFFLOAD)
+#define F_TCPCHECKSUMOFFLOAD    V_TCPCHECKSUMOFFLOAD(1U)
+
+#define S_IPTTL    0
+#define M_IPTTL    0xff
+#define V_IPTTL(x) ((x) << S_IPTTL)
+
+#define A_TP_CMM_MM_BASE 0x314
+
+#define A_TP_CMM_TIMER_BASE 0x318
+
+#define S_CMTIMERMAXNUM    28
+#define M_CMTIMERMAXNUM    0x3
+#define V_CMTIMERMAXNUM(x) ((x) << S_CMTIMERMAXNUM)
+
+#define A_TP_PMM_SIZE 0x31c
+
+#define A_TP_PMM_TX_BASE 0x320
+
+#define A_TP_PMM_RX_BASE 0x328
+
+#define A_TP_PMM_RX_PAGE_SIZE 0x32c
+
+#define A_TP_PMM_RX_MAX_PAGE 0x330
+
+#define A_TP_PMM_TX_PAGE_SIZE 0x334
+
+#define A_TP_PMM_TX_MAX_PAGE 0x338
+
+#define A_TP_TCP_OPTIONS 0x340
+
+#define S_MTUDEFAULT    16
+#define M_MTUDEFAULT    0xffff
+#define V_MTUDEFAULT(x) ((x) << S_MTUDEFAULT)
+
+#define S_MTUENABLE    10
+#define V_MTUENABLE(x) ((x) << S_MTUENABLE)
+#define F_MTUENABLE    V_MTUENABLE(1U)
+
+#define S_SACKRX    8
+#define V_SACKRX(x) ((x) << S_SACKRX)
+#define F_SACKRX    V_SACKRX(1U)
+
+#define S_SACKMODE    4
+
+#define M_SACKMODE    0x3
+
+#define V_SACKMODE(x) ((x) << S_SACKMODE)
+
+#define S_WINDOWSCALEMODE    2
+#define M_WINDOWSCALEMODE    0x3
+#define V_WINDOWSCALEMODE(x) ((x) << S_WINDOWSCALEMODE)
+
+#define S_TIMESTAMPSMODE    0
+
+#define M_TIMESTAMPSMODE    0x3
+
+#define V_TIMESTAMPSMODE(x) ((x) << S_TIMESTAMPSMODE)
+
+#define A_TP_DACK_CONFIG 0x344
+
+#define S_AUTOSTATE3    30
+#define M_AUTOSTATE3    0x3
+#define V_AUTOSTATE3(x) ((x) << S_AUTOSTATE3)
+
+#define S_AUTOSTATE2    28
+#define M_AUTOSTATE2    0x3
+#define V_AUTOSTATE2(x) ((x) << S_AUTOSTATE2)
+
+#define S_AUTOSTATE1    26
+#define M_AUTOSTATE1    0x3
+#define V_AUTOSTATE1(x) ((x) << S_AUTOSTATE1)
+
+#define S_BYTETHRESHOLD    5
+#define M_BYTETHRESHOLD    0xfffff
+#define V_BYTETHRESHOLD(x) ((x) << S_BYTETHRESHOLD)
+
+#define S_MSSTHRESHOLD    3
+#define M_MSSTHRESHOLD    0x3
+#define V_MSSTHRESHOLD(x) ((x) << S_MSSTHRESHOLD)
+
+#define S_AUTOCAREFUL    2
+#define V_AUTOCAREFUL(x) ((x) << S_AUTOCAREFUL)
+#define F_AUTOCAREFUL    V_AUTOCAREFUL(1U)
+
+#define S_AUTOENABLE    1
+#define V_AUTOENABLE(x) ((x) << S_AUTOENABLE)
+#define F_AUTOENABLE    V_AUTOENABLE(1U)
+
+#define S_DACK_MODE    0
+#define V_DACK_MODE(x) ((x) << S_DACK_MODE)
+#define F_DACK_MODE    V_DACK_MODE(1U)
+
+#define A_TP_PC_CONFIG 0x348
+
+#define S_TXTOSQUEUEMAPMODE    26
+#define V_TXTOSQUEUEMAPMODE(x) ((x) << S_TXTOSQUEUEMAPMODE)
+#define F_TXTOSQUEUEMAPMODE    V_TXTOSQUEUEMAPMODE(1U)
+
+#define S_ENABLEEPCMDAFULL    23
+#define V_ENABLEEPCMDAFULL(x) ((x) << S_ENABLEEPCMDAFULL)
+#define F_ENABLEEPCMDAFULL    V_ENABLEEPCMDAFULL(1U)
+
+#define S_MODULATEUNIONMODE    22
+#define V_MODULATEUNIONMODE(x) ((x) << S_MODULATEUNIONMODE)
+#define F_MODULATEUNIONMODE    V_MODULATEUNIONMODE(1U)
+
+#define S_TXDEFERENABLE    20
+#define V_TXDEFERENABLE(x) ((x) << S_TXDEFERENABLE)
+#define F_TXDEFERENABLE    V_TXDEFERENABLE(1U)
+
+#define S_RXCONGESTIONMODE    19
+#define V_RXCONGESTIONMODE(x) ((x) << S_RXCONGESTIONMODE)
+#define F_RXCONGESTIONMODE    V_RXCONGESTIONMODE(1U)
+
+#define S_HEARBEATDACK    16
+#define V_HEARBEATDACK(x) ((x) << S_HEARBEATDACK)
+#define F_HEARBEATDACK    V_HEARBEATDACK(1U)
+
+#define S_TXCONGESTIONMODE    15
+#define V_TXCONGESTIONMODE(x) ((x) << S_TXCONGESTIONMODE)
+#define F_TXCONGESTIONMODE    V_TXCONGESTIONMODE(1U)
+
+#define S_ENABLEOCSPIFULL    30
+#define V_ENABLEOCSPIFULL(x) ((x) << S_ENABLEOCSPIFULL)
+#define F_ENABLEOCSPIFULL    V_ENABLEOCSPIFULL(1U)
+
+#define S_LOCKTID    28
+#define V_LOCKTID(x) ((x) << S_LOCKTID)
+#define F_LOCKTID    V_LOCKTID(1U)
+
+#define A_TP_PC_CONFIG2 0x34c
+
+#define S_CHDRAFULL    4
+#define V_CHDRAFULL(x) ((x) << S_CHDRAFULL)
+#define F_CHDRAFULL    V_CHDRAFULL(1U)
+
+#define A_TP_TCP_BACKOFF_REG0 0x350
+
+#define A_TP_TCP_BACKOFF_REG1 0x354
+
+#define A_TP_TCP_BACKOFF_REG2 0x358
+
+#define A_TP_TCP_BACKOFF_REG3 0x35c
+
+#define A_TP_PARA_REG2 0x368
+
+#define S_MAXRXDATA    16
+#define M_MAXRXDATA    0xffff
+#define V_MAXRXDATA(x) ((x) << S_MAXRXDATA)
+
+#define S_RXCOALESCESIZE    0
+#define M_RXCOALESCESIZE    0xffff
+#define V_RXCOALESCESIZE(x) ((x) << S_RXCOALESCESIZE)
+
+#define A_TP_PARA_REG3 0x36c
+
+#define S_TXDATAACKIDX    16
+#define M_TXDATAACKIDX    0xf
+
+#define V_TXDATAACKIDX(x) ((x) << S_TXDATAACKIDX)
+
+#define S_TXPACEAUTOSTRICT    10
+#define V_TXPACEAUTOSTRICT(x) ((x) << S_TXPACEAUTOSTRICT)
+#define F_TXPACEAUTOSTRICT    V_TXPACEAUTOSTRICT(1U)
+
+#define S_TXPACEFIXED    9
+#define V_TXPACEFIXED(x) ((x) << S_TXPACEFIXED)
+#define F_TXPACEFIXED    V_TXPACEFIXED(1U)
+
+#define S_TXPACEAUTO    8
+#define V_TXPACEAUTO(x) ((x) << S_TXPACEAUTO)
+#define F_TXPACEAUTO    V_TXPACEAUTO(1U)
+
+#define S_RXCOALESCEENABLE    1
+#define V_RXCOALESCEENABLE(x) ((x) << S_RXCOALESCEENABLE)
+#define F_RXCOALESCEENABLE    V_RXCOALESCEENABLE(1U)
+
+#define S_RXCOALESCEPSHEN    0
+#define V_RXCOALESCEPSHEN(x) ((x) << S_RXCOALESCEPSHEN)
+#define F_RXCOALESCEPSHEN    V_RXCOALESCEPSHEN(1U)
+
+#define A_TP_PARA_REG4 0x370
+
+#define A_TP_PARA_REG6 0x378
+
+#define S_T3A_ENABLEESND    13
+#define V_T3A_ENABLEESND(x) ((x) << S_T3A_ENABLEESND)
+#define F_T3A_ENABLEESND    V_T3A_ENABLEESND(1U)
+
+#define S_ENABLEESND    11
+#define V_ENABLEESND(x) ((x) << S_ENABLEESND)
+#define F_ENABLEESND    V_ENABLEESND(1U)
+
+#define A_TP_PARA_REG7 0x37c
+
+#define S_PMMAXXFERLEN1    16
+#define M_PMMAXXFERLEN1    0xffff
+#define V_PMMAXXFERLEN1(x) ((x) << S_PMMAXXFERLEN1)
+
+#define S_PMMAXXFERLEN0    0
+#define M_PMMAXXFERLEN0    0xffff
+#define V_PMMAXXFERLEN0(x) ((x) << S_PMMAXXFERLEN0)
+
+#define A_TP_TIMER_RESOLUTION 0x390
+
+#define S_TIMERRESOLUTION    16
+#define M_TIMERRESOLUTION    0xff
+#define V_TIMERRESOLUTION(x) ((x) << S_TIMERRESOLUTION)
+
+#define S_TIMESTAMPRESOLUTION    8
+#define M_TIMESTAMPRESOLUTION    0xff
+#define V_TIMESTAMPRESOLUTION(x) ((x) << S_TIMESTAMPRESOLUTION)
+
+#define S_DELAYEDACKRESOLUTION    0
+#define M_DELAYEDACKRESOLUTION    0xff
+#define V_DELAYEDACKRESOLUTION(x) ((x) << S_DELAYEDACKRESOLUTION)
+
+#define A_TP_MSL 0x394
+
+#define A_TP_RXT_MIN 0x398
+
+#define A_TP_RXT_MAX 0x39c
+
+#define A_TP_PERS_MIN 0x3a0
+
+#define A_TP_PERS_MAX 0x3a4
+
+#define A_TP_KEEP_IDLE 0x3a8
+
+#define A_TP_KEEP_INTVL 0x3ac
+
+#define A_TP_INIT_SRTT 0x3b0
+
+#define A_TP_DACK_TIMER 0x3b4
+
+#define A_TP_FINWAIT2_TIMER 0x3b8
+
+#define A_TP_SHIFT_CNT 0x3c0
+
+#define S_SYNSHIFTMAX    24
+
+#define M_SYNSHIFTMAX    0xff
+
+#define V_SYNSHIFTMAX(x) ((x) << S_SYNSHIFTMAX)
+
+#define S_RXTSHIFTMAXR1    20
+
+#define M_RXTSHIFTMAXR1    0xf
+
+#define V_RXTSHIFTMAXR1(x) ((x) << S_RXTSHIFTMAXR1)
+
+#define S_RXTSHIFTMAXR2    16
+
+#define M_RXTSHIFTMAXR2    0xf
+
+#define V_RXTSHIFTMAXR2(x) ((x) << S_RXTSHIFTMAXR2)
+
+#define S_PERSHIFTBACKOFFMAX    12
+#define M_PERSHIFTBACKOFFMAX    0xf
+#define V_PERSHIFTBACKOFFMAX(x) ((x) << S_PERSHIFTBACKOFFMAX)
+
+#define S_PERSHIFTMAX    8
+#define M_PERSHIFTMAX    0xf
+#define V_PERSHIFTMAX(x) ((x) << S_PERSHIFTMAX)
+
+#define S_KEEPALIVEMAX    0
+
+#define M_KEEPALIVEMAX    0xff
+
+#define V_KEEPALIVEMAX(x) ((x) << S_KEEPALIVEMAX)
+
+#define A_TP_MTU_PORT_TABLE 0x3d0
+
+#define A_TP_CCTRL_TABLE 0x3dc
+
+#define A_TP_MTU_TABLE 0x3e4
+
+#define A_TP_RSS_MAP_TABLE 0x3e8
+
+#define A_TP_RSS_LKP_TABLE 0x3ec
+
+#define A_TP_RSS_CONFIG 0x3f0
+
+#define S_TNL4TUPEN    29
+#define V_TNL4TUPEN(x) ((x) << S_TNL4TUPEN)
+#define F_TNL4TUPEN    V_TNL4TUPEN(1U)
+
+#define S_TNL2TUPEN    28
+#define V_TNL2TUPEN(x) ((x) << S_TNL2TUPEN)
+#define F_TNL2TUPEN    V_TNL2TUPEN(1U)
+
+#define S_TNLPRTEN    26
+#define V_TNLPRTEN(x) ((x) << S_TNLPRTEN)
+#define F_TNLPRTEN    V_TNLPRTEN(1U)
+
+#define S_TNLMAPEN    25
+#define V_TNLMAPEN(x) ((x) << S_TNLMAPEN)
+#define F_TNLMAPEN    V_TNLMAPEN(1U)
+
+#define S_TNLLKPEN    24
+#define V_TNLLKPEN(x) ((x) << S_TNLLKPEN)
+#define F_TNLLKPEN    V_TNLLKPEN(1U)
+
+#define S_RRCPLCPUSIZE    4
+#define M_RRCPLCPUSIZE    0x7
+#define V_RRCPLCPUSIZE(x) ((x) << S_RRCPLCPUSIZE)
+
+#define S_RQFEEDBACKENABLE    3
+#define V_RQFEEDBACKENABLE(x) ((x) << S_RQFEEDBACKENABLE)
+#define F_RQFEEDBACKENABLE    V_RQFEEDBACKENABLE(1U)
+
+#define S_DISABLE    0
+
+#define A_TP_TM_PIO_ADDR 0x418
+
+#define A_TP_TM_PIO_DATA 0x41c
+
+#define A_TP_TX_MOD_QUE_TABLE 0x420
+
+#define A_TP_TX_RESOURCE_LIMIT 0x424
+
+#define A_TP_TX_MOD_QUEUE_REQ_MAP 0x428
+
+#define S_TX_MOD_QUEUE_REQ_MAP    0
+#define M_TX_MOD_QUEUE_REQ_MAP    0xff
+#define V_TX_MOD_QUEUE_REQ_MAP(x) ((x) << S_TX_MOD_QUEUE_REQ_MAP)
+
+#define A_TP_TX_MOD_QUEUE_WEIGHT1 0x42c
+
+#define A_TP_TX_MOD_QUEUE_WEIGHT0 0x430
+
+#define A_TP_MOD_CHANNEL_WEIGHT 0x434
+
+#define A_TP_PIO_ADDR 0x440
+
+#define A_TP_PIO_DATA 0x444
+
+#define A_TP_RESET 0x44c
+
+#define S_FLSTINITENABLE    1
+#define V_FLSTINITENABLE(x) ((x) << S_FLSTINITENABLE)
+#define F_FLSTINITENABLE    V_FLSTINITENABLE(1U)
+
+#define S_TPRESET    0
+#define V_TPRESET(x) ((x) << S_TPRESET)
+#define F_TPRESET    V_TPRESET(1U)
+
+#define A_TP_CMM_MM_RX_FLST_BASE 0x460
+
+#define A_TP_CMM_MM_TX_FLST_BASE 0x464
+
+#define A_TP_CMM_MM_PS_FLST_BASE 0x468
+
+#define A_TP_MIB_INDEX 0x450
+
+#define A_TP_MIB_RDATA 0x454
+
+#define A_TP_CMM_MM_MAX_PSTRUCT 0x46c
+
+#define A_TP_INT_ENABLE 0x470
+
+#define A_TP_INT_CAUSE 0x474
+
+#define A_TP_TX_MOD_Q1_Q0_RATE_LIMIT 0x8
+
+#define A_TP_TX_DROP_CFG_CH0 0x12b
+
+#define A_TP_TX_DROP_MODE 0x12f
+
+#define A_TP_EGRESS_CONFIG 0x145
+
+#define S_REWRITEFORCETOSIZE    0
+#define V_REWRITEFORCETOSIZE(x) ((x) << S_REWRITEFORCETOSIZE)
+#define F_REWRITEFORCETOSIZE    V_REWRITEFORCETOSIZE(1U)
+
+#define A_TP_TX_TRC_KEY0 0x20
+
+#define A_TP_RX_TRC_KEY0 0x120
+
+#define A_ULPRX_CTL 0x500
+
+#define S_ROUND_ROBIN    4
+#define V_ROUND_ROBIN(x) ((x) << S_ROUND_ROBIN)
+#define F_ROUND_ROBIN    V_ROUND_ROBIN(1U)
+
+#define A_ULPRX_INT_ENABLE 0x504
+
+#define S_PARERR    0
+#define V_PARERR(x) ((x) << S_PARERR)
+#define F_PARERR    V_PARERR(1U)
+
+#define A_ULPRX_INT_CAUSE 0x508
+
+#define A_ULPRX_ISCSI_LLIMIT 0x50c
+
+#define A_ULPRX_ISCSI_ULIMIT 0x510
+
+#define A_ULPRX_ISCSI_TAGMASK 0x514
+
+#define A_ULPRX_TDDP_LLIMIT 0x51c
+
+#define A_ULPRX_TDDP_ULIMIT 0x520
+
+#define A_ULPRX_STAG_LLIMIT 0x52c
+
+#define A_ULPRX_STAG_ULIMIT 0x530
+
+#define A_ULPRX_RQ_LLIMIT 0x534
+#define A_ULPRX_RQ_LLIMIT 0x534
+
+#define A_ULPRX_RQ_ULIMIT 0x538
+#define A_ULPRX_RQ_ULIMIT 0x538
+
+#define A_ULPRX_PBL_LLIMIT 0x53c
+
+#define A_ULPRX_PBL_ULIMIT 0x540
+#define A_ULPRX_PBL_ULIMIT 0x540
+
+#define A_ULPRX_TDDP_TAGMASK 0x524
+
+#define A_ULPRX_RQ_LLIMIT 0x534
+#define A_ULPRX_RQ_LLIMIT 0x534
+
+#define A_ULPRX_RQ_ULIMIT 0x538
+#define A_ULPRX_RQ_ULIMIT 0x538
+
+#define A_ULPRX_PBL_ULIMIT 0x540
+#define A_ULPRX_PBL_ULIMIT 0x540
+
+#define A_ULPTX_CONFIG 0x580
+
+#define S_CFG_RR_ARB    0
+#define V_CFG_RR_ARB(x) ((x) << S_CFG_RR_ARB)
+#define F_CFG_RR_ARB    V_CFG_RR_ARB(1U)
+
+#define A_ULPTX_INT_ENABLE 0x584
+
+#define S_PBL_BOUND_ERR_CH1    1
+#define V_PBL_BOUND_ERR_CH1(x) ((x) << S_PBL_BOUND_ERR_CH1)
+#define F_PBL_BOUND_ERR_CH1    V_PBL_BOUND_ERR_CH1(1U)
+
+#define S_PBL_BOUND_ERR_CH0    0
+#define V_PBL_BOUND_ERR_CH0(x) ((x) << S_PBL_BOUND_ERR_CH0)
+#define F_PBL_BOUND_ERR_CH0    V_PBL_BOUND_ERR_CH0(1U)
+
+#define A_ULPTX_INT_CAUSE 0x588
+
+#define A_ULPTX_TPT_LLIMIT 0x58c
+
+#define A_ULPTX_TPT_ULIMIT 0x590
+
+#define A_ULPTX_PBL_LLIMIT 0x594
+
+#define A_ULPTX_PBL_ULIMIT 0x598
+
+#define A_ULPTX_DMA_WEIGHT 0x5ac
+
+#define S_D1_WEIGHT    16
+#define M_D1_WEIGHT    0xffff
+#define V_D1_WEIGHT(x) ((x) << S_D1_WEIGHT)
+
+#define S_D0_WEIGHT    0
+#define M_D0_WEIGHT    0xffff
+#define V_D0_WEIGHT(x) ((x) << S_D0_WEIGHT)
+
+#define A_PM1_RX_CFG 0x5c0
+
+#define A_PM1_RX_INT_ENABLE 0x5d8
+
+#define S_ZERO_E_CMD_ERROR    18
+#define V_ZERO_E_CMD_ERROR(x) ((x) << S_ZERO_E_CMD_ERROR)
+#define F_ZERO_E_CMD_ERROR    V_ZERO_E_CMD_ERROR(1U)
+
+#define S_IESPI0_FIFO2X_RX_FRAMING_ERROR    17
+#define V_IESPI0_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_IESPI0_FIFO2X_RX_FRAMING_ERROR)
+#define F_IESPI0_FIFO2X_RX_FRAMING_ERROR    V_IESPI0_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI1_FIFO2X_RX_FRAMING_ERROR    16
+#define V_IESPI1_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_IESPI1_FIFO2X_RX_FRAMING_ERROR)
+#define F_IESPI1_FIFO2X_RX_FRAMING_ERROR    V_IESPI1_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI0_RX_FRAMING_ERROR    15
+#define V_IESPI0_RX_FRAMING_ERROR(x) ((x) << S_IESPI0_RX_FRAMING_ERROR)
+#define F_IESPI0_RX_FRAMING_ERROR    V_IESPI0_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI1_RX_FRAMING_ERROR    14
+#define V_IESPI1_RX_FRAMING_ERROR(x) ((x) << S_IESPI1_RX_FRAMING_ERROR)
+#define F_IESPI1_RX_FRAMING_ERROR    V_IESPI1_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI0_TX_FRAMING_ERROR    13
+#define V_IESPI0_TX_FRAMING_ERROR(x) ((x) << S_IESPI0_TX_FRAMING_ERROR)
+#define F_IESPI0_TX_FRAMING_ERROR    V_IESPI0_TX_FRAMING_ERROR(1U)
+
+#define S_IESPI1_TX_FRAMING_ERROR    12
+#define V_IESPI1_TX_FRAMING_ERROR(x) ((x) << S_IESPI1_TX_FRAMING_ERROR)
+#define F_IESPI1_TX_FRAMING_ERROR    V_IESPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI0_RX_FRAMING_ERROR    11
+#define V_OCSPI0_RX_FRAMING_ERROR(x) ((x) << S_OCSPI0_RX_FRAMING_ERROR)
+#define F_OCSPI0_RX_FRAMING_ERROR    V_OCSPI0_RX_FRAMING_ERROR(1U)
+
+#define S_OCSPI1_RX_FRAMING_ERROR    10
+#define V_OCSPI1_RX_FRAMING_ERROR(x) ((x) << S_OCSPI1_RX_FRAMING_ERROR)
+#define F_OCSPI1_RX_FRAMING_ERROR    V_OCSPI1_RX_FRAMING_ERROR(1U)
+
+#define S_OCSPI0_TX_FRAMING_ERROR    9
+#define V_OCSPI0_TX_FRAMING_ERROR(x) ((x) << S_OCSPI0_TX_FRAMING_ERROR)
+#define F_OCSPI0_TX_FRAMING_ERROR    V_OCSPI0_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI1_TX_FRAMING_ERROR    8
+#define V_OCSPI1_TX_FRAMING_ERROR(x) ((x) << S_OCSPI1_TX_FRAMING_ERROR)
+#define F_OCSPI1_TX_FRAMING_ERROR    V_OCSPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI0_OFIFO2X_TX_FRAMING_ERROR    7
+#define V_OCSPI0_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OCSPI0_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR    V_OCSPI0_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI1_OFIFO2X_TX_FRAMING_ERROR    6
+#define V_OCSPI1_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OCSPI1_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR    V_OCSPI1_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_IESPI_PAR_ERROR    3
+#define M_IESPI_PAR_ERROR    0x7
+
+#define V_IESPI_PAR_ERROR(x) ((x) << S_IESPI_PAR_ERROR)
+
+#define S_OCSPI_PAR_ERROR    0
+#define M_OCSPI_PAR_ERROR    0x7
+
+#define V_OCSPI_PAR_ERROR(x) ((x) << S_OCSPI_PAR_ERROR)
+
+#define A_PM1_RX_INT_CAUSE 0x5dc
+
+#define A_PM1_TX_CFG 0x5e0
+
+#define A_PM1_TX_INT_ENABLE 0x5f8
+
+#define S_ZERO_C_CMD_ERROR    18
+#define V_ZERO_C_CMD_ERROR(x) ((x) << S_ZERO_C_CMD_ERROR)
+#define F_ZERO_C_CMD_ERROR    V_ZERO_C_CMD_ERROR(1U)
+
+#define S_ICSPI0_FIFO2X_RX_FRAMING_ERROR    17
+#define V_ICSPI0_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_ICSPI0_FIFO2X_RX_FRAMING_ERROR)
+#define F_ICSPI0_FIFO2X_RX_FRAMING_ERROR    V_ICSPI0_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI1_FIFO2X_RX_FRAMING_ERROR    16
+#define V_ICSPI1_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_ICSPI1_FIFO2X_RX_FRAMING_ERROR)
+#define F_ICSPI1_FIFO2X_RX_FRAMING_ERROR    V_ICSPI1_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI0_RX_FRAMING_ERROR    15
+#define V_ICSPI0_RX_FRAMING_ERROR(x) ((x) << S_ICSPI0_RX_FRAMING_ERROR)
+#define F_ICSPI0_RX_FRAMING_ERROR    V_ICSPI0_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI1_RX_FRAMING_ERROR    14
+#define V_ICSPI1_RX_FRAMING_ERROR(x) ((x) << S_ICSPI1_RX_FRAMING_ERROR)
+#define F_ICSPI1_RX_FRAMING_ERROR    V_ICSPI1_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI0_TX_FRAMING_ERROR    13
+#define V_ICSPI0_TX_FRAMING_ERROR(x) ((x) << S_ICSPI0_TX_FRAMING_ERROR)
+#define F_ICSPI0_TX_FRAMING_ERROR    V_ICSPI0_TX_FRAMING_ERROR(1U)
+
+#define S_ICSPI1_TX_FRAMING_ERROR    12
+#define V_ICSPI1_TX_FRAMING_ERROR(x) ((x) << S_ICSPI1_TX_FRAMING_ERROR)
+#define F_ICSPI1_TX_FRAMING_ERROR    V_ICSPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI0_RX_FRAMING_ERROR    11
+#define V_OESPI0_RX_FRAMING_ERROR(x) ((x) << S_OESPI0_RX_FRAMING_ERROR)
+#define F_OESPI0_RX_FRAMING_ERROR    V_OESPI0_RX_FRAMING_ERROR(1U)
+
+#define S_OESPI1_RX_FRAMING_ERROR    10
+#define V_OESPI1_RX_FRAMING_ERROR(x) ((x) << S_OESPI1_RX_FRAMING_ERROR)
+#define F_OESPI1_RX_FRAMING_ERROR    V_OESPI1_RX_FRAMING_ERROR(1U)
+
+#define S_OESPI0_TX_FRAMING_ERROR    9
+#define V_OESPI0_TX_FRAMING_ERROR(x) ((x) << S_OESPI0_TX_FRAMING_ERROR)
+#define F_OESPI0_TX_FRAMING_ERROR    V_OESPI0_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI1_TX_FRAMING_ERROR    8
+#define V_OESPI1_TX_FRAMING_ERROR(x) ((x) << S_OESPI1_TX_FRAMING_ERROR)
+#define F_OESPI1_TX_FRAMING_ERROR    V_OESPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI0_OFIFO2X_TX_FRAMING_ERROR    7
+#define V_OESPI0_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OESPI0_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OESPI0_OFIFO2X_TX_FRAMING_ERROR    V_OESPI0_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI1_OFIFO2X_TX_FRAMING_ERROR    6
+#define V_OESPI1_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OESPI1_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OESPI1_OFIFO2X_TX_FRAMING_ERROR    V_OESPI1_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_ICSPI_PAR_ERROR    3
+#define M_ICSPI_PAR_ERROR    0x7
+
+#define V_ICSPI_PAR_ERROR(x) ((x) << S_ICSPI_PAR_ERROR)
+
+#define S_OESPI_PAR_ERROR    0
+#define M_OESPI_PAR_ERROR    0x7
+
+#define V_OESPI_PAR_ERROR(x) ((x) << S_OESPI_PAR_ERROR)
+
+#define A_PM1_TX_INT_CAUSE 0x5fc
+
+#define A_MPS_CFG 0x600
+
+#define S_TPRXPORTEN    4
+#define V_TPRXPORTEN(x) ((x) << S_TPRXPORTEN)
+#define F_TPRXPORTEN    V_TPRXPORTEN(1U)
+
+#define S_TPTXPORT1EN    3
+#define V_TPTXPORT1EN(x) ((x) << S_TPTXPORT1EN)
+#define F_TPTXPORT1EN    V_TPTXPORT1EN(1U)
+
+#define S_TPTXPORT0EN    2
+#define V_TPTXPORT0EN(x) ((x) << S_TPTXPORT0EN)
+#define F_TPTXPORT0EN    V_TPTXPORT0EN(1U)
+
+#define S_PORT1ACTIVE    1
+#define V_PORT1ACTIVE(x) ((x) << S_PORT1ACTIVE)
+#define F_PORT1ACTIVE    V_PORT1ACTIVE(1U)
+
+#define S_PORT0ACTIVE    0
+#define V_PORT0ACTIVE(x) ((x) << S_PORT0ACTIVE)
+#define F_PORT0ACTIVE    V_PORT0ACTIVE(1U)
+
+#define S_ENFORCEPKT    11
+#define V_ENFORCEPKT(x) ((x) << S_ENFORCEPKT)
+#define F_ENFORCEPKT    V_ENFORCEPKT(1U)
+
+#define A_MPS_INT_ENABLE 0x61c
+
+#define S_MCAPARERRENB    6
+#define M_MCAPARERRENB    0x7
+
+#define V_MCAPARERRENB(x) ((x) << S_MCAPARERRENB)
+
+#define S_RXTPPARERRENB    4
+#define M_RXTPPARERRENB    0x3
+
+#define V_RXTPPARERRENB(x) ((x) << S_RXTPPARERRENB)
+
+#define S_TX1TPPARERRENB    2
+#define M_TX1TPPARERRENB    0x3
+
+#define V_TX1TPPARERRENB(x) ((x) << S_TX1TPPARERRENB)
+
+#define S_TX0TPPARERRENB    0
+#define M_TX0TPPARERRENB    0x3
+
+#define V_TX0TPPARERRENB(x) ((x) << S_TX0TPPARERRENB)
+
+#define A_MPS_INT_CAUSE 0x620
+
+#define S_MCAPARERR    6
+#define M_MCAPARERR    0x7
+
+#define V_MCAPARERR(x) ((x) << S_MCAPARERR)
+
+#define S_RXTPPARERR    4
+#define M_RXTPPARERR    0x3
+
+#define V_RXTPPARERR(x) ((x) << S_RXTPPARERR)
+
+#define S_TX1TPPARERR    2
+#define M_TX1TPPARERR    0x3
+
+#define V_TX1TPPARERR(x) ((x) << S_TX1TPPARERR)
+
+#define S_TX0TPPARERR    0
+#define M_TX0TPPARERR    0x3
+
+#define V_TX0TPPARERR(x) ((x) << S_TX0TPPARERR)
+
+#define A_CPL_SWITCH_CNTRL 0x640
+
+#define A_CPL_INTR_ENABLE 0x650
+
+#define S_CIM_OVFL_ERROR    4
+#define V_CIM_OVFL_ERROR(x) ((x) << S_CIM_OVFL_ERROR)
+#define F_CIM_OVFL_ERROR    V_CIM_OVFL_ERROR(1U)
+
+#define S_TP_FRAMING_ERROR    3
+#define V_TP_FRAMING_ERROR(x) ((x) << S_TP_FRAMING_ERROR)
+#define F_TP_FRAMING_ERROR    V_TP_FRAMING_ERROR(1U)
+
+#define S_SGE_FRAMING_ERROR    2
+#define V_SGE_FRAMING_ERROR(x) ((x) << S_SGE_FRAMING_ERROR)
+#define F_SGE_FRAMING_ERROR    V_SGE_FRAMING_ERROR(1U)
+
+#define S_CIM_FRAMING_ERROR    1
+#define V_CIM_FRAMING_ERROR(x) ((x) << S_CIM_FRAMING_ERROR)
+#define F_CIM_FRAMING_ERROR    V_CIM_FRAMING_ERROR(1U)
+
+#define S_ZERO_SWITCH_ERROR    0
+#define V_ZERO_SWITCH_ERROR(x) ((x) << S_ZERO_SWITCH_ERROR)
+#define F_ZERO_SWITCH_ERROR    V_ZERO_SWITCH_ERROR(1U)
+
+#define A_CPL_INTR_CAUSE 0x654
+
+#define A_CPL_MAP_TBL_DATA 0x65c
+
+#define A_SMB_GLOBAL_TIME_CFG 0x660
+
+#define A_I2C_CFG 0x6a0
+
+#define S_I2C_CLKDIV    0
+#define M_I2C_CLKDIV    0xfff
+#define V_I2C_CLKDIV(x) ((x) << S_I2C_CLKDIV)
+
+#define A_MI1_CFG 0x6b0
+
+#define S_CLKDIV    5
+#define M_CLKDIV    0xff
+#define V_CLKDIV(x) ((x) << S_CLKDIV)
+
+#define S_ST    3
+
+#define M_ST    0x3
+
+#define V_ST(x) ((x) << S_ST)
+
+#define G_ST(x) (((x) >> S_ST) & M_ST)
+
+#define S_PREEN    2
+#define V_PREEN(x) ((x) << S_PREEN)
+#define F_PREEN    V_PREEN(1U)
+
+#define S_MDIINV    1
+#define V_MDIINV(x) ((x) << S_MDIINV)
+#define F_MDIINV    V_MDIINV(1U)
+
+#define S_MDIEN    0
+#define V_MDIEN(x) ((x) << S_MDIEN)
+#define F_MDIEN    V_MDIEN(1U)
+
+#define A_MI1_ADDR 0x6b4
+
+#define S_PHYADDR    5
+#define M_PHYADDR    0x1f
+#define V_PHYADDR(x) ((x) << S_PHYADDR)
+
+#define S_REGADDR    0
+#define M_REGADDR    0x1f
+#define V_REGADDR(x) ((x) << S_REGADDR)
+
+#define A_MI1_DATA 0x6b8
+
+#define A_MI1_OP 0x6bc
+
+#define S_MDI_OP    0
+#define M_MDI_OP    0x3
+#define V_MDI_OP(x) ((x) << S_MDI_OP)
+
+#define A_SF_DATA 0x6d8
+
+#define A_SF_OP 0x6dc
+
+#define S_BYTECNT    1
+#define M_BYTECNT    0x3
+#define V_BYTECNT(x) ((x) << S_BYTECNT)
+
+#define A_PL_INT_ENABLE0 0x6e0
+
+#define S_T3DBG    23
+#define V_T3DBG(x) ((x) << S_T3DBG)
+#define F_T3DBG    V_T3DBG(1U)
+
+#define S_XGMAC0_1    20
+#define V_XGMAC0_1(x) ((x) << S_XGMAC0_1)
+#define F_XGMAC0_1    V_XGMAC0_1(1U)
+
+#define S_XGMAC0_0    19
+#define V_XGMAC0_0(x) ((x) << S_XGMAC0_0)
+#define F_XGMAC0_0    V_XGMAC0_0(1U)
+
+#define S_MC5A    18
+#define V_MC5A(x) ((x) << S_MC5A)
+#define F_MC5A    V_MC5A(1U)
+
+#define S_CPL_SWITCH    12
+#define V_CPL_SWITCH(x) ((x) << S_CPL_SWITCH)
+#define F_CPL_SWITCH    V_CPL_SWITCH(1U)
+
+#define S_MPS0    11
+#define V_MPS0(x) ((x) << S_MPS0)
+#define F_MPS0    V_MPS0(1U)
+
+#define S_PM1_TX    10
+#define V_PM1_TX(x) ((x) << S_PM1_TX)
+#define F_PM1_TX    V_PM1_TX(1U)
+
+#define S_PM1_RX    9
+#define V_PM1_RX(x) ((x) << S_PM1_RX)
+#define F_PM1_RX    V_PM1_RX(1U)
+
+#define S_ULP2_TX    8
+#define V_ULP2_TX(x) ((x) << S_ULP2_TX)
+#define F_ULP2_TX    V_ULP2_TX(1U)
+
+#define S_ULP2_RX    7
+#define V_ULP2_RX(x) ((x) << S_ULP2_RX)
+#define F_ULP2_RX    V_ULP2_RX(1U)
+
+#define S_TP1    6
+#define V_TP1(x) ((x) << S_TP1)
+#define F_TP1    V_TP1(1U)
+
+#define S_CIM    5
+#define V_CIM(x) ((x) << S_CIM)
+#define F_CIM    V_CIM(1U)
+
+#define S_MC7_CM    4
+#define V_MC7_CM(x) ((x) << S_MC7_CM)
+#define F_MC7_CM    V_MC7_CM(1U)
+
+#define S_MC7_PMTX    3
+#define V_MC7_PMTX(x) ((x) << S_MC7_PMTX)
+#define F_MC7_PMTX    V_MC7_PMTX(1U)
+
+#define S_MC7_PMRX    2
+#define V_MC7_PMRX(x) ((x) << S_MC7_PMRX)
+#define F_MC7_PMRX    V_MC7_PMRX(1U)
+
+#define S_PCIM0    1
+#define V_PCIM0(x) ((x) << S_PCIM0)
+#define F_PCIM0    V_PCIM0(1U)
+
+#define S_SGE3    0
+#define V_SGE3(x) ((x) << S_SGE3)
+#define F_SGE3    V_SGE3(1U)
+
+#define A_PL_INT_CAUSE0 0x6e4
+
+#define A_PL_RST 0x6f0
+
+#define S_CRSTWRM    1
+#define V_CRSTWRM(x) ((x) << S_CRSTWRM)
+#define F_CRSTWRM    V_CRSTWRM(1U)
+
+#define A_PL_REV 0x6f4
+
+#define A_PL_CLI 0x6f8
+
+#define A_MC5_DB_CONFIG 0x704
+
+#define S_TMTYPEHI    30
+#define V_TMTYPEHI(x) ((x) << S_TMTYPEHI)
+#define F_TMTYPEHI    V_TMTYPEHI(1U)
+
+#define S_TMPARTSIZE    28
+#define M_TMPARTSIZE    0x3
+#define V_TMPARTSIZE(x) ((x) << S_TMPARTSIZE)
+#define G_TMPARTSIZE(x) (((x) >> S_TMPARTSIZE) & M_TMPARTSIZE)
+
+#define S_TMTYPE    26
+#define M_TMTYPE    0x3
+#define V_TMTYPE(x) ((x) << S_TMTYPE)
+#define G_TMTYPE(x) (((x) >> S_TMTYPE) & M_TMTYPE)
+
+#define S_COMPEN    17
+#define V_COMPEN(x) ((x) << S_COMPEN)
+#define F_COMPEN    V_COMPEN(1U)
+
+#define S_PRTYEN    6
+#define V_PRTYEN(x) ((x) << S_PRTYEN)
+#define F_PRTYEN    V_PRTYEN(1U)
+
+#define S_MBUSEN    5
+#define V_MBUSEN(x) ((x) << S_MBUSEN)
+#define F_MBUSEN    V_MBUSEN(1U)
+
+#define S_DBGIEN    4
+#define V_DBGIEN(x) ((x) << S_DBGIEN)
+#define F_DBGIEN    V_DBGIEN(1U)
+
+#define S_TMRDY    2
+#define V_TMRDY(x) ((x) << S_TMRDY)
+#define F_TMRDY    V_TMRDY(1U)
+
+#define S_TMRST    1
+#define V_TMRST(x) ((x) << S_TMRST)
+#define F_TMRST    V_TMRST(1U)
+
+#define S_TMMODE    0
+#define V_TMMODE(x) ((x) << S_TMMODE)
+#define F_TMMODE    V_TMMODE(1U)
+
+#define F_TMMODE    V_TMMODE(1U)
+
+#define A_MC5_DB_ROUTING_TABLE_INDEX 0x70c
+
+#define A_MC5_DB_FILTER_TABLE 0x710
+
+#define A_MC5_DB_SERVER_INDEX 0x714
+
+#define A_MC5_DB_RSP_LATENCY 0x720
+
+#define S_RDLAT    16
+#define M_RDLAT    0x1f
+#define V_RDLAT(x) ((x) << S_RDLAT)
+
+#define S_LRNLAT    8
+#define M_LRNLAT    0x1f
+#define V_LRNLAT(x) ((x) << S_LRNLAT)
+
+#define S_SRCHLAT    0
+#define M_SRCHLAT    0x1f
+#define V_SRCHLAT(x) ((x) << S_SRCHLAT)
+
+#define A_MC5_DB_PART_ID_INDEX 0x72c
+
+#define A_MC5_DB_INT_ENABLE 0x740
+
+#define S_DELACTEMPTY    18
+#define V_DELACTEMPTY(x) ((x) << S_DELACTEMPTY)
+#define F_DELACTEMPTY    V_DELACTEMPTY(1U)
+
+#define S_DISPQPARERR    17
+#define V_DISPQPARERR(x) ((x) << S_DISPQPARERR)
+#define F_DISPQPARERR    V_DISPQPARERR(1U)
+
+#define S_REQQPARERR    16
+#define V_REQQPARERR(x) ((x) << S_REQQPARERR)
+#define F_REQQPARERR    V_REQQPARERR(1U)
+
+#define S_UNKNOWNCMD    15
+#define V_UNKNOWNCMD(x) ((x) << S_UNKNOWNCMD)
+#define F_UNKNOWNCMD    V_UNKNOWNCMD(1U)
+
+#define S_NFASRCHFAIL    8
+#define V_NFASRCHFAIL(x) ((x) << S_NFASRCHFAIL)
+#define F_NFASRCHFAIL    V_NFASRCHFAIL(1U)
+
+#define S_ACTRGNFULL    7
+#define V_ACTRGNFULL(x) ((x) << S_ACTRGNFULL)
+#define F_ACTRGNFULL    V_ACTRGNFULL(1U)
+
+#define S_PARITYERR    6
+#define V_PARITYERR(x) ((x) << S_PARITYERR)
+#define F_PARITYERR    V_PARITYERR(1U)
+
+#define A_MC5_DB_INT_CAUSE 0x744
+
+#define A_MC5_DB_DBGI_CONFIG 0x774
+
+#define A_MC5_DB_DBGI_REQ_CMD 0x778
+
+#define A_MC5_DB_DBGI_REQ_ADDR0 0x77c
+
+#define A_MC5_DB_DBGI_REQ_ADDR1 0x780
+
+#define A_MC5_DB_DBGI_REQ_ADDR2 0x784
+
+#define A_MC5_DB_DBGI_REQ_DATA0 0x788
+
+#define A_MC5_DB_DBGI_REQ_DATA1 0x78c
+
+#define A_MC5_DB_DBGI_REQ_DATA2 0x790
+
+#define A_MC5_DB_DBGI_RSP_STATUS 0x7b0
+
+#define S_DBGIRSPVALID    0
+#define V_DBGIRSPVALID(x) ((x) << S_DBGIRSPVALID)
+#define F_DBGIRSPVALID    V_DBGIRSPVALID(1U)
+
+#define A_MC5_DB_DBGI_RSP_DATA0 0x7b4
+
+#define A_MC5_DB_DBGI_RSP_DATA1 0x7b8
+
+#define A_MC5_DB_DBGI_RSP_DATA2 0x7bc
+
+#define A_MC5_DB_POPEN_DATA_WR_CMD 0x7cc
+
+#define A_MC5_DB_POPEN_MASK_WR_CMD 0x7d0
+
+#define A_MC5_DB_AOPEN_SRCH_CMD 0x7d4
+
+#define A_MC5_DB_AOPEN_LRN_CMD 0x7d8
+
+#define A_MC5_DB_SYN_SRCH_CMD 0x7dc
+
+#define A_MC5_DB_SYN_LRN_CMD 0x7e0
+
+#define A_MC5_DB_ACK_SRCH_CMD 0x7e4
+
+#define A_MC5_DB_ACK_LRN_CMD 0x7e8
+
+#define A_MC5_DB_ILOOKUP_CMD 0x7ec
+
+#define A_MC5_DB_ELOOKUP_CMD 0x7f0
+
+#define A_MC5_DB_DATA_WRITE_CMD 0x7f4
+
+#define A_MC5_DB_DATA_READ_CMD 0x7f8
+
+#define XGMAC0_0_BASE_ADDR 0x800
+
+#define A_XGM_TX_CTRL 0x800
+
+#define S_TXEN    0
+#define V_TXEN(x) ((x) << S_TXEN)
+#define F_TXEN    V_TXEN(1U)
+
+#define A_XGM_TX_CFG 0x804
+
+#define S_TXPAUSEEN    0
+#define V_TXPAUSEEN(x) ((x) << S_TXPAUSEEN)
+#define F_TXPAUSEEN    V_TXPAUSEEN(1U)
+
+#define A_XGM_RX_CTRL 0x80c
+
+#define S_RXEN    0
+#define V_RXEN(x) ((x) << S_RXEN)
+#define F_RXEN    V_RXEN(1U)
+
+#define A_XGM_RX_CFG 0x810
+
+#define S_DISPAUSEFRAMES    9
+#define V_DISPAUSEFRAMES(x) ((x) << S_DISPAUSEFRAMES)
+#define F_DISPAUSEFRAMES    V_DISPAUSEFRAMES(1U)
+
+#define S_EN1536BFRAMES    8
+#define V_EN1536BFRAMES(x) ((x) << S_EN1536BFRAMES)
+#define F_EN1536BFRAMES    V_EN1536BFRAMES(1U)
+
+#define S_ENJUMBO    7
+#define V_ENJUMBO(x) ((x) << S_ENJUMBO)
+#define F_ENJUMBO    V_ENJUMBO(1U)
+
+#define S_RMFCS    6
+#define V_RMFCS(x) ((x) << S_RMFCS)
+#define F_RMFCS    V_RMFCS(1U)
+
+#define S_ENHASHMCAST    2
+#define V_ENHASHMCAST(x) ((x) << S_ENHASHMCAST)
+#define F_ENHASHMCAST    V_ENHASHMCAST(1U)
+
+#define S_COPYALLFRAMES    0
+#define V_COPYALLFRAMES(x) ((x) << S_COPYALLFRAMES)
+#define F_COPYALLFRAMES    V_COPYALLFRAMES(1U)
+
+#define A_XGM_RX_HASH_LOW 0x814
+
+#define A_XGM_RX_HASH_HIGH 0x818
+
+#define A_XGM_RX_EXACT_MATCH_LOW_1 0x81c
+
+#define A_XGM_RX_EXACT_MATCH_HIGH_1 0x820
+
+#define A_XGM_RX_EXACT_MATCH_LOW_2 0x824
+
+#define A_XGM_RX_EXACT_MATCH_LOW_3 0x82c
+
+#define A_XGM_RX_EXACT_MATCH_LOW_4 0x834
+
+#define A_XGM_RX_EXACT_MATCH_LOW_5 0x83c
+
+#define A_XGM_RX_EXACT_MATCH_LOW_6 0x844
+
+#define A_XGM_RX_EXACT_MATCH_LOW_7 0x84c
+
+#define A_XGM_RX_EXACT_MATCH_LOW_8 0x854
+
+#define A_XGM_STAT_CTRL 0x880
+
+#define S_CLRSTATS    2
+#define V_CLRSTATS(x) ((x) << S_CLRSTATS)
+#define F_CLRSTATS    V_CLRSTATS(1U)
+
+#define A_XGM_RXFIFO_CFG 0x884
+
+#define S_RXFIFOPAUSEHWM    17
+#define M_RXFIFOPAUSEHWM    0xfff
+
+#define V_RXFIFOPAUSEHWM(x) ((x) << S_RXFIFOPAUSEHWM)
+
+#define G_RXFIFOPAUSEHWM(x) (((x) >> S_RXFIFOPAUSEHWM) & M_RXFIFOPAUSEHWM)
+
+#define S_RXFIFOPAUSELWM    5
+#define M_RXFIFOPAUSELWM    0xfff
+
+#define V_RXFIFOPAUSELWM(x) ((x) << S_RXFIFOPAUSELWM)
+
+#define G_RXFIFOPAUSELWM(x) (((x) >> S_RXFIFOPAUSELWM) & M_RXFIFOPAUSELWM)
+
+#define S_RXSTRFRWRD    1
+#define V_RXSTRFRWRD(x) ((x) << S_RXSTRFRWRD)
+#define F_RXSTRFRWRD    V_RXSTRFRWRD(1U)
+
+#define S_DISERRFRAMES    0
+#define V_DISERRFRAMES(x) ((x) << S_DISERRFRAMES)
+#define F_DISERRFRAMES    V_DISERRFRAMES(1U)
+
+#define A_XGM_TXFIFO_CFG 0x888
+
+#define S_TXFIFOTHRESH    4
+#define M_TXFIFOTHRESH    0x1ff
+
+#define V_TXFIFOTHRESH(x) ((x) << S_TXFIFOTHRESH)
+
+#define A_XGM_SERDES_CTRL 0x890
+#define A_XGM_SERDES_CTRL0 0x8e0
+
+#define S_SERDESRESET_    24
+#define V_SERDESRESET_(x) ((x) << S_SERDESRESET_)
+#define F_SERDESRESET_    V_SERDESRESET_(1U)
+
+#define S_RXENABLE    4
+#define V_RXENABLE(x) ((x) << S_RXENABLE)
+#define F_RXENABLE    V_RXENABLE(1U)
+
+#define S_TXENABLE    3
+#define V_TXENABLE(x) ((x) << S_TXENABLE)
+#define F_TXENABLE    V_TXENABLE(1U)
+
+#define A_XGM_PAUSE_TIMER 0x890
+
+#define A_XGM_RGMII_IMP 0x89c
+
+#define S_XGM_IMPSETUPDATE    6
+#define V_XGM_IMPSETUPDATE(x) ((x) << S_XGM_IMPSETUPDATE)
+#define F_XGM_IMPSETUPDATE    V_XGM_IMPSETUPDATE(1U)
+
+#define S_RGMIIIMPPD    3
+#define M_RGMIIIMPPD    0x7
+#define V_RGMIIIMPPD(x) ((x) << S_RGMIIIMPPD)
+
+#define S_RGMIIIMPPU    0
+#define M_RGMIIIMPPU    0x7
+#define V_RGMIIIMPPU(x) ((x) << S_RGMIIIMPPU)
+
+#define S_CALRESET    8
+#define V_CALRESET(x) ((x) << S_CALRESET)
+#define F_CALRESET    V_CALRESET(1U)
+
+#define S_CALUPDATE    7
+#define V_CALUPDATE(x) ((x) << S_CALUPDATE)
+#define F_CALUPDATE    V_CALUPDATE(1U)
+
+#define A_XGM_XAUI_IMP 0x8a0
+
+#define S_CALBUSY    31
+#define V_CALBUSY(x) ((x) << S_CALBUSY)
+#define F_CALBUSY    V_CALBUSY(1U)
+
+#define S_XGM_CALFAULT    29
+#define V_XGM_CALFAULT(x) ((x) << S_XGM_CALFAULT)
+#define F_XGM_CALFAULT    V_XGM_CALFAULT(1U)
+
+#define S_CALIMP    24
+#define M_CALIMP    0x1f
+#define V_CALIMP(x) ((x) << S_CALIMP)
+#define G_CALIMP(x) (((x) >> S_CALIMP) & M_CALIMP)
+
+#define S_XAUIIMP    0
+#define M_XAUIIMP    0x7
+#define V_XAUIIMP(x) ((x) << S_XAUIIMP)
+
+#define A_XGM_RX_MAX_PKT_SIZE 0x8a8
+#define A_XGM_RX_MAX_PKT_SIZE_ERR_CNT 0x9a4
+
+#define A_XGM_RESET_CTRL 0x8ac
+
+#define S_XG2G_RESET_    3
+#define V_XG2G_RESET_(x) ((x) << S_XG2G_RESET_)
+#define F_XG2G_RESET_    V_XG2G_RESET_(1U)
+
+#define S_RGMII_RESET_    2
+#define V_RGMII_RESET_(x) ((x) << S_RGMII_RESET_)
+#define F_RGMII_RESET_    V_RGMII_RESET_(1U)
+
+#define S_PCS_RESET_    1
+#define V_PCS_RESET_(x) ((x) << S_PCS_RESET_)
+#define F_PCS_RESET_    V_PCS_RESET_(1U)
+
+#define S_MAC_RESET_    0
+#define V_MAC_RESET_(x) ((x) << S_MAC_RESET_)
+#define F_MAC_RESET_    V_MAC_RESET_(1U)
+
+#define A_XGM_PORT_CFG 0x8b8
+
+#define S_CLKDIVRESET_    3
+#define V_CLKDIVRESET_(x) ((x) << S_CLKDIVRESET_)
+#define F_CLKDIVRESET_    V_CLKDIVRESET_(1U)
+
+#define S_PORTSPEED    1
+#define M_PORTSPEED    0x3
+
+#define V_PORTSPEED(x) ((x) << S_PORTSPEED)
+
+#define S_ENRGMII    0
+#define V_ENRGMII(x) ((x) << S_ENRGMII)
+#define F_ENRGMII    V_ENRGMII(1U)
+
+#define A_XGM_INT_ENABLE 0x8d4
+
+#define S_TXFIFO_PRTY_ERR    17
+#define M_TXFIFO_PRTY_ERR    0x7
+
+#define V_TXFIFO_PRTY_ERR(x) ((x) << S_TXFIFO_PRTY_ERR)
+
+#define S_RXFIFO_PRTY_ERR    14
+#define M_RXFIFO_PRTY_ERR    0x7
+
+#define V_RXFIFO_PRTY_ERR(x) ((x) << S_RXFIFO_PRTY_ERR)
+
+#define S_TXFIFO_UNDERRUN    13
+#define V_TXFIFO_UNDERRUN(x) ((x) << S_TXFIFO_UNDERRUN)
+#define F_TXFIFO_UNDERRUN    V_TXFIFO_UNDERRUN(1U)
+
+#define S_RXFIFO_OVERFLOW    12
+#define V_RXFIFO_OVERFLOW(x) ((x) << S_RXFIFO_OVERFLOW)
+#define F_RXFIFO_OVERFLOW    V_RXFIFO_OVERFLOW(1U)
+
+#define S_SERDES_LOS    4
+#define M_SERDES_LOS    0xf
+
+#define V_SERDES_LOS(x) ((x) << S_SERDES_LOS)
+
+#define S_XAUIPCSCTCERR    3
+#define V_XAUIPCSCTCERR(x) ((x) << S_XAUIPCSCTCERR)
+#define F_XAUIPCSCTCERR    V_XAUIPCSCTCERR(1U)
+
+#define S_XAUIPCSALIGNCHANGE    2
+#define V_XAUIPCSALIGNCHANGE(x) ((x) << S_XAUIPCSALIGNCHANGE)
+#define F_XAUIPCSALIGNCHANGE    V_XAUIPCSALIGNCHANGE(1U)
+
+#define A_XGM_INT_CAUSE 0x8d8
+
+#define A_XGM_XAUI_ACT_CTRL 0x8dc
+
+#define S_TXACTENABLE    1
+#define V_TXACTENABLE(x) ((x) << S_TXACTENABLE)
+#define F_TXACTENABLE    V_TXACTENABLE(1U)
+
+#define A_XGM_SERDES_CTRL0 0x8e0
+
+#define S_RESET3    23
+#define V_RESET3(x) ((x) << S_RESET3)
+#define F_RESET3    V_RESET3(1U)
+
+#define S_RESET2    22
+#define V_RESET2(x) ((x) << S_RESET2)
+#define F_RESET2    V_RESET2(1U)
+
+#define S_RESET1    21
+#define V_RESET1(x) ((x) << S_RESET1)
+#define F_RESET1    V_RESET1(1U)
+
+#define S_RESET0    20
+#define V_RESET0(x) ((x) << S_RESET0)
+#define F_RESET0    V_RESET0(1U)
+
+#define S_PWRDN3    19
+#define V_PWRDN3(x) ((x) << S_PWRDN3)
+#define F_PWRDN3    V_PWRDN3(1U)
+
+#define S_PWRDN2    18
+#define V_PWRDN2(x) ((x) << S_PWRDN2)
+#define F_PWRDN2    V_PWRDN2(1U)
+
+#define S_PWRDN1    17
+#define V_PWRDN1(x) ((x) << S_PWRDN1)
+#define F_PWRDN1    V_PWRDN1(1U)
+
+#define S_PWRDN0    16
+#define V_PWRDN0(x) ((x) << S_PWRDN0)
+#define F_PWRDN0    V_PWRDN0(1U)
+
+#define S_RESETPLL23    15
+#define V_RESETPLL23(x) ((x) << S_RESETPLL23)
+#define F_RESETPLL23    V_RESETPLL23(1U)
+
+#define S_RESETPLL01    14
+#define V_RESETPLL01(x) ((x) << S_RESETPLL01)
+#define F_RESETPLL01    V_RESETPLL01(1U)
+
+#define A_XGM_SERDES_STAT0 0x8f0
+
+#define S_LOWSIG0    0
+#define V_LOWSIG0(x) ((x) << S_LOWSIG0)
+#define F_LOWSIG0    V_LOWSIG0(1U)
+
+#define A_XGM_SERDES_STAT3 0x8fc
+
+#define A_XGM_STAT_TX_BYTE_LOW 0x900
+
+#define A_XGM_STAT_TX_BYTE_HIGH 0x904
+
+#define A_XGM_STAT_TX_FRAME_LOW 0x908
+
+#define A_XGM_STAT_TX_FRAME_HIGH 0x90c
+
+#define A_XGM_STAT_TX_BCAST 0x910
+
+#define A_XGM_STAT_TX_MCAST 0x914
+
+#define A_XGM_STAT_TX_PAUSE 0x918
+
+#define A_XGM_STAT_TX_64B_FRAMES 0x91c
+
+#define A_XGM_STAT_TX_65_127B_FRAMES 0x920
+
+#define A_XGM_STAT_TX_128_255B_FRAMES 0x924
+
+#define A_XGM_STAT_TX_256_511B_FRAMES 0x928
+
+#define A_XGM_STAT_TX_512_1023B_FRAMES 0x92c
+
+#define A_XGM_STAT_TX_1024_1518B_FRAMES 0x930
+
+#define A_XGM_STAT_TX_1519_MAXB_FRAMES 0x934
+
+#define A_XGM_STAT_TX_ERR_FRAMES 0x938
+
+#define A_XGM_STAT_RX_BYTES_LOW 0x93c
+
+#define A_XGM_STAT_RX_BYTES_HIGH 0x940
+
+#define A_XGM_STAT_RX_FRAMES_LOW 0x944
+
+#define A_XGM_STAT_RX_FRAMES_HIGH 0x948
+
+#define A_XGM_STAT_RX_BCAST_FRAMES 0x94c
+
+#define A_XGM_STAT_RX_MCAST_FRAMES 0x950
+
+#define A_XGM_STAT_RX_PAUSE_FRAMES 0x954
+
+#define A_XGM_STAT_RX_64B_FRAMES 0x958
+
+#define A_XGM_STAT_RX_65_127B_FRAMES 0x95c
+
+#define A_XGM_STAT_RX_128_255B_FRAMES 0x960
+
+#define A_XGM_STAT_RX_256_511B_FRAMES 0x964
+
+#define A_XGM_STAT_RX_512_1023B_FRAMES 0x968
+
+#define A_XGM_STAT_RX_1024_1518B_FRAMES 0x96c
+
+#define A_XGM_STAT_RX_1519_MAXB_FRAMES 0x970
+
+#define A_XGM_STAT_RX_SHORT_FRAMES 0x974
+
+#define A_XGM_STAT_RX_OVERSIZE_FRAMES 0x978
+
+#define A_XGM_STAT_RX_JABBER_FRAMES 0x97c
+
+#define A_XGM_STAT_RX_CRC_ERR_FRAMES 0x980
+
+#define A_XGM_STAT_RX_LENGTH_ERR_FRAMES 0x984
+
+#define A_XGM_STAT_RX_SYM_CODE_ERR_FRAMES 0x988
+
+#define A_XGM_SERDES_STATUS0 0x98c
+
+#define A_XGM_SERDES_STATUS1 0x990
+
+#define S_CMULOCK    31
+#define V_CMULOCK(x) ((x) << S_CMULOCK)
+#define F_CMULOCK    V_CMULOCK(1U)
+
+#define A_XGM_RX_MAX_PKT_SIZE_ERR_CNT 0x9a4
+
+#define A_XGM_RX_SPI4_SOP_EOP_CNT 0x9ac
+
+#define XGMAC0_1_BASE_ADDR 0xa00
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
new file mode 100644
index 0000000..3f2cf8a
--- /dev/null
+++ b/drivers/net/cxgb3/sge.c
@@ -0,0 +1,2681 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/dma-mapping.h>
+#include "common.h"
+#include "regs.h"
+#include "sge_defs.h"
+#include "t3_cpl.h"
+#include "firmware_exports.h"
+
+#define USE_GTS 0
+
+#define SGE_RX_SM_BUF_SIZE 1536
+#define SGE_RX_COPY_THRES  256
+
+# define SGE_RX_DROP_THRES 16
+
+/*
+ * Period of the Tx buffer reclaim timer.  This timer does not need to run
+ * frequently as Tx buffers are usually reclaimed by new Tx packets.
+ */
+#define TX_RECLAIM_PERIOD (HZ / 4)
+
+/* WR size in bytes */
+#define WR_LEN (WR_FLITS * 8)
+
+/*
+ * Types of Tx queues in each queue set.  Order here matters, do not change.
+ */
+enum { TXQ_ETH, TXQ_OFLD, TXQ_CTRL };
+
+/* Values for sge_txq.flags */
+enum {
+	TXQ_RUNNING = 1 << 0,	/* fetch engine is running */
+	TXQ_LAST_PKT_DB = 1 << 1,	/* last packet rang the doorbell */
+};
+
+struct tx_desc {
+	u64 flit[TX_DESC_FLITS];
+};
+
+struct rx_desc {
+	__be32 addr_lo;
+	__be32 len_gen;
+	__be32 gen2;
+	__be32 addr_hi;
+};
+
+struct tx_sw_desc {		/* SW state per Tx descriptor */
+	struct sk_buff *skb;
+};
+
+struct rx_sw_desc {		/* SW state per Rx descriptor */
+	struct sk_buff *skb;
+	 DECLARE_PCI_UNMAP_ADDR(dma_addr);
+};
+
+struct rsp_desc {		/* response queue descriptor */
+	struct rss_header rss_hdr;
+	__be32 flags;
+	__be32 len_cq;
+	u8 imm_data[47];
+	u8 intr_gen;
+};
+
+struct unmap_info {		/* packet unmapping info, overlays skb->cb */
+	int sflit;		/* start flit of first SGL entry in Tx descriptor */
+	u16 fragidx;		/* first page fragment in current Tx descriptor */
+	u16 addr_idx;		/* buffer index of first SGL entry in descriptor */
+	u32 len;		/* mapped length of skb main body */
+};
+
+/*
+ * Maps a number of flits to the number of Tx descriptors that can hold them.
+ * The formula is
+ *
+ * desc = 1 + (flits - 2) / (WR_FLITS - 1).
+ *
+ * HW allows up to 4 descriptors to be combined into a WR.
+ */
+static u8 flit_desc_map[] = {
+	0,
+#if SGE_NUM_GENBITS == 1
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+#elif SGE_NUM_GENBITS == 2
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+#else
+# error "SGE_NUM_GENBITS must be 1 or 2"
+#endif
+};
+
+static inline struct sge_qset *fl_to_qset(const struct sge_fl *q, int qidx)
+{
+	return container_of(q, struct sge_qset, fl[qidx]);
+}
+
+static inline struct sge_qset *rspq_to_qset(const struct sge_rspq *q)
+{
+	return container_of(q, struct sge_qset, rspq);
+}
+
+static inline struct sge_qset *txq_to_qset(const struct sge_txq *q, int qidx)
+{
+	return container_of(q, struct sge_qset, txq[qidx]);
+}
+
+/**
+ *	refill_rspq - replenish an SGE response queue
+ *	@adapter: the adapter
+ *	@q: the response queue to replenish
+ *	@credits: how many new responses to make available
+ *
+ *	Replenishes a response queue by making the supplied number of responses
+ *	available to HW.
+ */
+static inline void refill_rspq(struct adapter *adapter,
+			       const struct sge_rspq *q, unsigned int credits)
+{
+	t3_write_reg(adapter, A_SG_RSPQ_CREDIT_RETURN,
+		     V_RSPQ(q->cntxt_id) | V_CREDITS(credits));
+}
+
+/**
+ *	need_skb_unmap - does the platform need unmapping of sk_buffs?
+ *
+ *	Returns true if the platfrom needs sk_buff unmapping.  The compiler
+ *	optimizes away unecessary code if this returns true.
+ */
+static inline int need_skb_unmap(void)
+{
+	/*
+	 * This structure is used to tell if the platfrom needs buffer
+	 * unmapping by checking if DECLARE_PCI_UNMAP_ADDR defines anything.
+	 */
+	struct dummy {
+		DECLARE_PCI_UNMAP_ADDR(addr);
+	};
+
+	return sizeof(struct dummy) != 0;
+}
+
+/**
+ *	unmap_skb - unmap a packet main body and its page fragments
+ *	@skb: the packet
+ *	@q: the Tx queue containing Tx descriptors for the packet
+ *	@cidx: index of Tx descriptor
+ *	@pdev: the PCI device
+ *
+ *	Unmap the main body of an sk_buff and its page fragments, if any.
+ *	Because of the fairly complicated structure of our SGLs and the desire
+ *	to conserve space for metadata, we keep the information necessary to
+ *	unmap an sk_buff partly in the sk_buff itself (in its cb), and partly
+ *	in the Tx descriptors (the physical addresses of the various data
+ *	buffers).  The send functions initialize the state in skb->cb so we
+ *	can unmap the buffers held in the first Tx descriptor here, and we
+ *	have enough information at this point to update the state for the next
+ *	Tx descriptor.
+ */
+static inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q,
+			     unsigned int cidx, struct pci_dev *pdev)
+{
+	const struct sg_ent *sgp;
+	struct unmap_info *ui = (struct unmap_info *)skb->cb;
+	int nfrags, frag_idx, curflit, j = ui->addr_idx;
+
+	sgp = (struct sg_ent *)&q->desc[cidx].flit[ui->sflit];
+
+	if (ui->len) {
+		pci_unmap_single(pdev, be64_to_cpu(sgp->addr[0]), ui->len,
+				 PCI_DMA_TODEVICE);
+		ui->len = 0;	/* so we know for next descriptor for this skb */
+		j = 1;
+	}
+
+	frag_idx = ui->fragidx;
+	curflit = ui->sflit + 1 + j;
+	nfrags = skb_shinfo(skb)->nr_frags;
+
+	while (frag_idx < nfrags && curflit < WR_FLITS) {
+		pci_unmap_page(pdev, be64_to_cpu(sgp->addr[j]),
+			       skb_shinfo(skb)->frags[frag_idx].size,
+			       PCI_DMA_TODEVICE);
+		j ^= 1;
+		if (j == 0) {
+			sgp++;
+			curflit++;
+		}
+		curflit++;
+		frag_idx++;
+	}
+
+	if (frag_idx < nfrags) {	/* SGL continues into next Tx descriptor */
+		ui->fragidx = frag_idx;
+		ui->addr_idx = j;
+		ui->sflit = curflit - WR_FLITS - j;	/* sflit can be -1 */
+	}
+}
+
+/**
+ *	free_tx_desc - reclaims Tx descriptors and their buffers
+ *	@adapter: the adapter
+ *	@q: the Tx queue to reclaim descriptors from
+ *	@n: the number of descriptors to reclaim
+ *
+ *	Reclaims Tx descriptors from an SGE Tx queue and frees the associated
+ *	Tx buffers.  Called with the Tx queue lock held.
+ */
+static void free_tx_desc(struct adapter *adapter, struct sge_txq *q,
+			 unsigned int n)
+{
+	struct tx_sw_desc *d;
+	struct pci_dev *pdev = adapter->pdev;
+	unsigned int cidx = q->cidx;
+
+	d = &q->sdesc[cidx];
+	while (n--) {
+		if (d->skb) {	/* an SGL is present */
+			if (need_skb_unmap())
+				unmap_skb(d->skb, q, cidx, pdev);
+			if (d->skb->priority == cidx)
+				kfree_skb(d->skb);
+		}
+		++d;
+		if (++cidx == q->size) {
+			cidx = 0;
+			d = q->sdesc;
+		}
+	}
+	q->cidx = cidx;
+}
+
+/**
+ *	reclaim_completed_tx - reclaims completed Tx descriptors
+ *	@adapter: the adapter
+ *	@q: the Tx queue to reclaim completed descriptors from
+ *
+ *	Reclaims Tx descriptors that the SGE has indicated it has processed,
+ *	and frees the associated buffers if possible.  Called with the Tx
+ *	queue's lock held.
+ */
+static inline void reclaim_completed_tx(struct adapter *adapter,
+					struct sge_txq *q)
+{
+	unsigned int reclaim = q->processed - q->cleaned;
+
+	if (reclaim) {
+		free_tx_desc(adapter, q, reclaim);
+		q->cleaned += reclaim;
+		q->in_use -= reclaim;
+	}
+}
+
+/**
+ *	should_restart_tx - are there enough resources to restart a Tx queue?
+ *	@q: the Tx queue
+ *
+ *	Checks if there are enough descriptors to restart a suspended Tx queue.
+ */
+static inline int should_restart_tx(const struct sge_txq *q)
+{
+	unsigned int r = q->processed - q->cleaned;
+
+	return q->in_use - r < (q->size >> 1);
+}
+
+/**
+ *	free_rx_bufs - free the Rx buffers on an SGE free list
+ *	@pdev: the PCI device associated with the adapter
+ *	@rxq: the SGE free list to clean up
+ *
+ *	Release the buffers on an SGE free-buffer Rx queue.  HW fetching from
+ *	this queue should be stopped before calling this function.
+ */
+static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q)
+{
+	unsigned int cidx = q->cidx;
+
+	while (q->credits--) {
+		struct rx_sw_desc *d = &q->sdesc[cidx];
+
+		pci_unmap_single(pdev, pci_unmap_addr(d, dma_addr),
+				 q->buf_size, PCI_DMA_FROMDEVICE);
+		kfree_skb(d->skb);
+		d->skb = NULL;
+		if (++cidx == q->size)
+			cidx = 0;
+	}
+}
+
+/**
+ *	add_one_rx_buf - add a packet buffer to a free-buffer list
+ *	@skb: the buffer to add
+ *	@len: the buffer length
+ *	@d: the HW Rx descriptor to write
+ *	@sd: the SW Rx descriptor to write
+ *	@gen: the generation bit value
+ *	@pdev: the PCI device associated with the adapter
+ *
+ *	Add a buffer of the given length to the supplied HW and SW Rx
+ *	descriptors.
+ */
+static inline void add_one_rx_buf(struct sk_buff *skb, unsigned int len,
+				  struct rx_desc *d, struct rx_sw_desc *sd,
+				  unsigned int gen, struct pci_dev *pdev)
+{
+	dma_addr_t mapping;
+
+	sd->skb = skb;
+	mapping = pci_map_single(pdev, skb->data, len, PCI_DMA_FROMDEVICE);
+	pci_unmap_addr_set(sd, dma_addr, mapping);
+
+	d->addr_lo = cpu_to_be32(mapping);
+	d->addr_hi = cpu_to_be32((u64) mapping >> 32);
+	wmb();
+	d->len_gen = cpu_to_be32(V_FLD_GEN1(gen));
+	d->gen2 = cpu_to_be32(V_FLD_GEN2(gen));
+}
+
+/**
+ *	refill_fl - refill an SGE free-buffer list
+ *	@adapter: the adapter
+ *	@q: the free-list to refill
+ *	@n: the number of new buffers to allocate
+ *	@gfp: the gfp flags for allocating new buffers
+ *
+ *	(Re)populate an SGE free-buffer list with up to @n new packet buffers,
+ *	allocated with the supplied gfp flags.  The caller must assure that
+ *	@n does not exceed the queue's capacity.
+ */
+static void refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp)
+{
+	struct rx_sw_desc *sd = &q->sdesc[q->pidx];
+	struct rx_desc *d = &q->desc[q->pidx];
+
+	while (n--) {
+		struct sk_buff *skb = alloc_skb(q->buf_size, gfp);
+
+		if (!skb)
+			break;
+
+		add_one_rx_buf(skb, q->buf_size, d, sd, q->gen, adap->pdev);
+		d++;
+		sd++;
+		if (++q->pidx == q->size) {
+			q->pidx = 0;
+			q->gen ^= 1;
+			sd = q->sdesc;
+			d = q->desc;
+		}
+		q->credits++;
+	}
+
+	t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
+}
+
+static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl)
+{
+	refill_fl(adap, fl, min(16U, fl->size - fl->credits), GFP_ATOMIC);
+}
+
+/**
+ *	recycle_rx_buf - recycle a receive buffer
+ *	@adapter: the adapter
+ *	@q: the SGE free list
+ *	@idx: index of buffer to recycle
+ *
+ *	Recycles the specified buffer on the given free list by adding it at
+ *	the next available slot on the list.
+ */
+static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q,
+			   unsigned int idx)
+{
+	struct rx_desc *from = &q->desc[idx];
+	struct rx_desc *to = &q->desc[q->pidx];
+
+	q->sdesc[q->pidx] = q->sdesc[idx];
+	to->addr_lo = from->addr_lo;	/* already big endian */
+	to->addr_hi = from->addr_hi;	/* likewise */
+	wmb();
+	to->len_gen = cpu_to_be32(V_FLD_GEN1(q->gen));
+	to->gen2 = cpu_to_be32(V_FLD_GEN2(q->gen));
+	q->credits++;
+
+	if (++q->pidx == q->size) {
+		q->pidx = 0;
+		q->gen ^= 1;
+	}
+	t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
+}
+
+/**
+ *	alloc_ring - allocate resources for an SGE descriptor ring
+ *	@pdev: the PCI device
+ *	@nelem: the number of descriptors
+ *	@elem_size: the size of each descriptor
+ *	@sw_size: the size of the SW state associated with each ring element
+ *	@phys: the physical address of the allocated ring
+ *	@metadata: address of the array holding the SW state for the ring
+ *
+ *	Allocates resources for an SGE descriptor ring, such as Tx queues,
+ *	free buffer lists, or response queues.  Each SGE ring requires
+ *	space for its HW descriptors plus, optionally, space for the SW state
+ *	associated with each HW entry (the metadata).  The function returns
+ *	three values: the virtual address for the HW ring (the return value
+ *	of the function), the physical address of the HW ring, and the address
+ *	of the SW ring.
+ */
+static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size,
+			size_t sw_size, dma_addr_t *phys, void *metadata)
+{
+	size_t len = nelem * elem_size;
+	void *s = NULL;
+	void *p = dma_alloc_coherent(&pdev->dev, len, phys, GFP_KERNEL);
+
+	if (!p)
+		return NULL;
+	if (sw_size) {
+		s = kcalloc(nelem, sw_size, GFP_KERNEL);
+
+		if (!s) {
+			dma_free_coherent(&pdev->dev, len, p, *phys);
+			return NULL;
+		}
+	}
+	if (metadata)
+		*(void **)metadata = s;
+	memset(p, 0, len);
+	return p;
+}
+
+/**
+ *	free_qset - free the resources of an SGE queue set
+ *	@adapter: the adapter owning the queue set
+ *	@q: the queue set
+ *
+ *	Release the HW and SW resources associated with an SGE queue set, such
+ *	as HW contexts, packet buffers, and descriptor rings.  Traffic to the
+ *	queue set must be quiesced prior to calling this.
+ */
+void t3_free_qset(struct adapter *adapter, struct sge_qset *q)
+{
+	int i;
+	struct pci_dev *pdev = adapter->pdev;
+
+	if (q->tx_reclaim_timer.function)
+		del_timer_sync(&q->tx_reclaim_timer);
+
+	for (i = 0; i < SGE_RXQ_PER_SET; ++i)
+		if (q->fl[i].desc) {
+			spin_lock(&adapter->sge.reg_lock);
+			t3_sge_disable_fl(adapter, q->fl[i].cntxt_id);
+			spin_unlock(&adapter->sge.reg_lock);
+			free_rx_bufs(pdev, &q->fl[i]);
+			kfree(q->fl[i].sdesc);
+			dma_free_coherent(&pdev->dev,
+					  q->fl[i].size *
+					  sizeof(struct rx_desc), q->fl[i].desc,
+					  q->fl[i].phys_addr);
+		}
+
+	for (i = 0; i < SGE_TXQ_PER_SET; ++i)
+		if (q->txq[i].desc) {
+			spin_lock(&adapter->sge.reg_lock);
+			t3_sge_enable_ecntxt(adapter, q->txq[i].cntxt_id, 0);
+			spin_unlock(&adapter->sge.reg_lock);
+			if (q->txq[i].sdesc) {
+				free_tx_desc(adapter, &q->txq[i],
+					     q->txq[i].in_use);
+				kfree(q->txq[i].sdesc);
+			}
+			dma_free_coherent(&pdev->dev,
+					  q->txq[i].size *
+					  sizeof(struct tx_desc),
+					  q->txq[i].desc, q->txq[i].phys_addr);
+			__skb_queue_purge(&q->txq[i].sendq);
+		}
+
+	if (q->rspq.desc) {
+		spin_lock(&adapter->sge.reg_lock);
+		t3_sge_disable_rspcntxt(adapter, q->rspq.cntxt_id);
+		spin_unlock(&adapter->sge.reg_lock);
+		dma_free_coherent(&pdev->dev,
+				  q->rspq.size * sizeof(struct rsp_desc),
+				  q->rspq.desc, q->rspq.phys_addr);
+	}
+
+	if (q->netdev)
+		q->netdev->atalk_ptr = NULL;
+
+	memset(q, 0, sizeof(*q));
+}
+
+/**
+ *	init_qset_cntxt - initialize an SGE queue set context info
+ *	@qs: the queue set
+ *	@id: the queue set id
+ *
+ *	Initializes the TIDs and context ids for the queues of a queue set.
+ */
+static void init_qset_cntxt(struct sge_qset *qs, unsigned int id)
+{
+	qs->rspq.cntxt_id = id;
+	qs->fl[0].cntxt_id = 2 * id;
+	qs->fl[1].cntxt_id = 2 * id + 1;
+	qs->txq[TXQ_ETH].cntxt_id = FW_TUNNEL_SGEEC_START + id;
+	qs->txq[TXQ_ETH].token = FW_TUNNEL_TID_START + id;
+	qs->txq[TXQ_OFLD].cntxt_id = FW_OFLD_SGEEC_START + id;
+	qs->txq[TXQ_CTRL].cntxt_id = FW_CTRL_SGEEC_START + id;
+	qs->txq[TXQ_CTRL].token = FW_CTRL_TID_START + id;
+}
+
+/**
+ *	sgl_len - calculates the size of an SGL of the given capacity
+ *	@n: the number of SGL entries
+ *
+ *	Calculates the number of flits needed for a scatter/gather list that
+ *	can hold the given number of entries.
+ */
+static inline unsigned int sgl_len(unsigned int n)
+{
+	/* alternatively: 3 * (n / 2) + 2 * (n & 1) */
+	return (3 * n) / 2 + (n & 1);
+}
+
+/**
+ *	flits_to_desc - returns the num of Tx descriptors for the given flits
+ *	@n: the number of flits
+ *
+ *	Calculates the number of Tx descriptors needed for the supplied number
+ *	of flits.
+ */
+static inline unsigned int flits_to_desc(unsigned int n)
+{
+	BUG_ON(n >= ARRAY_SIZE(flit_desc_map));
+	return flit_desc_map[n];
+}
+
+/**
+ *	get_packet - return the next ingress packet buffer from a free list
+ *	@adap: the adapter that received the packet
+ *	@fl: the SGE free list holding the packet
+ *	@len: the packet length including any SGE padding
+ *	@drop_thres: # of remaining buffers before we start dropping packets
+ *
+ *	Get the next packet from a free list and complete setup of the
+ *	sk_buff.  If the packet is small we make a copy and recycle the
+ *	original buffer, otherwise we use the original buffer itself.  If a
+ *	positive drop threshold is supplied packets are dropped and their
+ *	buffers recycled if (a) the number of remaining buffers is under the
+ *	threshold and the packet is too big to copy, or (b) the packet should
+ *	be copied but there is no memory for the copy.
+ */
+static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl,
+				  unsigned int len, unsigned int drop_thres)
+{
+	struct sk_buff *skb = NULL;
+	struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
+
+	prefetch(sd->skb->data);
+
+	if (len <= SGE_RX_COPY_THRES) {
+		skb = alloc_skb(len, GFP_ATOMIC);
+		if (likely(skb != NULL)) {
+			__skb_put(skb, len);
+			pci_dma_sync_single_for_cpu(adap->pdev,
+						    pci_unmap_addr(sd,
+								   dma_addr),
+						    len, PCI_DMA_FROMDEVICE);
+			memcpy(skb->data, sd->skb->data, len);
+			pci_dma_sync_single_for_device(adap->pdev,
+						       pci_unmap_addr(sd,
+								      dma_addr),
+						       len, PCI_DMA_FROMDEVICE);
+		} else if (!drop_thres)
+			goto use_orig_buf;
+	      recycle:
+		recycle_rx_buf(adap, fl, fl->cidx);
+		return skb;
+	}
+
+	if (unlikely(fl->credits < drop_thres))
+		goto recycle;
+
+      use_orig_buf:
+	pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
+			 fl->buf_size, PCI_DMA_FROMDEVICE);
+	skb = sd->skb;
+	skb_put(skb, len);
+	__refill_fl(adap, fl);
+	return skb;
+}
+
+/**
+ *	get_imm_packet - return the next ingress packet buffer from a response
+ *	@resp: the response descriptor containing the packet data
+ *
+ *	Return a packet containing the immediate data of the given response.
+ */
+static inline struct sk_buff *get_imm_packet(const struct rsp_desc *resp)
+{
+	struct sk_buff *skb = alloc_skb(IMMED_PKT_SIZE, GFP_ATOMIC);
+
+	if (skb) {
+		__skb_put(skb, IMMED_PKT_SIZE);
+		memcpy(skb->data, resp->imm_data, IMMED_PKT_SIZE);
+	}
+	return skb;
+}
+
+/**
+ *	calc_tx_descs - calculate the number of Tx descriptors for a packet
+ *	@skb: the packet
+ *
+ * 	Returns the number of Tx descriptors needed for the given Ethernet
+ * 	packet.  Ethernet packets require addition of WR and CPL headers.
+ */
+static inline unsigned int calc_tx_descs(const struct sk_buff *skb)
+{
+	unsigned int flits;
+
+	if (skb->len <= WR_LEN - sizeof(struct cpl_tx_pkt))
+		return 1;
+
+	flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 2;
+	if (skb_shinfo(skb)->gso_size)
+		flits++;
+	return flits_to_desc(flits);
+}
+
+/**
+ *	make_sgl - populate a scatter/gather list for a packet
+ *	@skb: the packet
+ *	@sgp: the SGL to populate
+ *	@start: start address of skb main body data to include in the SGL
+ *	@len: length of skb main body data to include in the SGL
+ *	@pdev: the PCI device
+ *
+ *	Generates a scatter/gather list for the buffers that make up a packet
+ *	and returns the SGL size in 8-byte words.  The caller must size the SGL
+ *	appropriately.
+ */
+static inline unsigned int make_sgl(const struct sk_buff *skb,
+				    struct sg_ent *sgp, unsigned char *start,
+				    unsigned int len, struct pci_dev *pdev)
+{
+	dma_addr_t mapping;
+	unsigned int i, j = 0, nfrags;
+
+	if (len) {
+		mapping = pci_map_single(pdev, start, len, PCI_DMA_TODEVICE);
+		sgp->len[0] = cpu_to_be32(len);
+		sgp->addr[0] = cpu_to_be64(mapping);
+		j = 1;
+	}
+
+	nfrags = skb_shinfo(skb)->nr_frags;
+	for (i = 0; i < nfrags; i++) {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+		mapping = pci_map_page(pdev, frag->page, frag->page_offset,
+				       frag->size, PCI_DMA_TODEVICE);
+		sgp->len[j] = cpu_to_be32(frag->size);
+		sgp->addr[j] = cpu_to_be64(mapping);
+		j ^= 1;
+		if (j == 0)
+			++sgp;
+	}
+	if (j)
+		sgp->len[j] = 0;
+	return ((nfrags + (len != 0)) * 3) / 2 + j;
+}
+
+/**
+ *	check_ring_tx_db - check and potentially ring a Tx queue's doorbell
+ *	@adap: the adapter
+ *	@q: the Tx queue
+ *
+ *	Ring the doorbel if a Tx queue is asleep.  There is a natural race,
+ *	where the HW is going to sleep just after we checked, however,
+ *	then the interrupt handler will detect the outstanding TX packet
+ *	and ring the doorbell for us.
+ *
+ *	When GTS is disabled we unconditionally ring the doorbell.
+ */
+static inline void check_ring_tx_db(struct adapter *adap, struct sge_txq *q)
+{
+#if USE_GTS
+	clear_bit(TXQ_LAST_PKT_DB, &q->flags);
+	if (test_and_set_bit(TXQ_RUNNING, &q->flags) == 0) {
+		set_bit(TXQ_LAST_PKT_DB, &q->flags);
+		t3_write_reg(adap, A_SG_KDOORBELL,
+			     F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+	}
+#else
+	wmb();			/* write descriptors before telling HW */
+	t3_write_reg(adap, A_SG_KDOORBELL,
+		     F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+#endif
+}
+
+static inline void wr_gen2(struct tx_desc *d, unsigned int gen)
+{
+#if SGE_NUM_GENBITS == 2
+	d->flit[TX_DESC_FLITS - 1] = cpu_to_be64(gen);
+#endif
+}
+
+/**
+ *	write_wr_hdr_sgl - write a WR header and, optionally, SGL
+ *	@ndesc: number of Tx descriptors spanned by the SGL
+ *	@skb: the packet corresponding to the WR
+ *	@d: first Tx descriptor to be written
+ *	@pidx: index of above descriptors
+ *	@q: the SGE Tx queue
+ *	@sgl: the SGL
+ *	@flits: number of flits to the start of the SGL in the first descriptor
+ *	@sgl_flits: the SGL size in flits
+ *	@gen: the Tx descriptor generation
+ *	@wr_hi: top 32 bits of WR header based on WR type (big endian)
+ *	@wr_lo: low 32 bits of WR header based on WR type (big endian)
+ *
+ *	Write a work request header and an associated SGL.  If the SGL is
+ *	small enough to fit into one Tx descriptor it has already been written
+ *	and we just need to write the WR header.  Otherwise we distribute the
+ *	SGL across the number of descriptors it spans.
+ */
+static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb,
+			     struct tx_desc *d, unsigned int pidx,
+			     const struct sge_txq *q,
+			     const struct sg_ent *sgl,
+			     unsigned int flits, unsigned int sgl_flits,
+			     unsigned int gen, unsigned int wr_hi,
+			     unsigned int wr_lo)
+{
+	struct work_request_hdr *wrp = (struct work_request_hdr *)d;
+	struct tx_sw_desc *sd = &q->sdesc[pidx];
+
+	sd->skb = skb;
+	if (need_skb_unmap()) {
+		struct unmap_info *ui = (struct unmap_info *)skb->cb;
+
+		ui->fragidx = 0;
+		ui->addr_idx = 0;
+		ui->sflit = flits;
+	}
+
+	if (likely(ndesc == 1)) {
+		skb->priority = pidx;
+		wrp->wr_hi = htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) |
+				   V_WR_SGLSFLT(flits)) | wr_hi;
+		wmb();
+		wrp->wr_lo = htonl(V_WR_LEN(flits + sgl_flits) |
+				   V_WR_GEN(gen)) | wr_lo;
+		wr_gen2(d, gen);
+	} else {
+		unsigned int ogen = gen;
+		const u64 *fp = (const u64 *)sgl;
+		struct work_request_hdr *wp = wrp;
+
+		wrp->wr_hi = htonl(F_WR_SOP | V_WR_DATATYPE(1) |
+				   V_WR_SGLSFLT(flits)) | wr_hi;
+
+		while (sgl_flits) {
+			unsigned int avail = WR_FLITS - flits;
+
+			if (avail > sgl_flits)
+				avail = sgl_flits;
+			memcpy(&d->flit[flits], fp, avail * sizeof(*fp));
+			sgl_flits -= avail;
+			ndesc--;
+			if (!sgl_flits)
+				break;
+
+			fp += avail;
+			d++;
+			sd++;
+			if (++pidx == q->size) {
+				pidx = 0;
+				gen ^= 1;
+				d = q->desc;
+				sd = q->sdesc;
+			}
+
+			sd->skb = skb;
+			wrp = (struct work_request_hdr *)d;
+			wrp->wr_hi = htonl(V_WR_DATATYPE(1) |
+					   V_WR_SGLSFLT(1)) | wr_hi;
+			wrp->wr_lo = htonl(V_WR_LEN(min(WR_FLITS,
+							sgl_flits + 1)) |
+					   V_WR_GEN(gen)) | wr_lo;
+			wr_gen2(d, gen);
+			flits = 1;
+		}
+		skb->priority = pidx;
+		wrp->wr_hi |= htonl(F_WR_EOP);
+		wmb();
+		wp->wr_lo = htonl(V_WR_LEN(WR_FLITS) | V_WR_GEN(ogen)) | wr_lo;
+		wr_gen2((struct tx_desc *)wp, ogen);
+		WARN_ON(ndesc != 0);
+	}
+}
+
+/**
+ *	write_tx_pkt_wr - write a TX_PKT work request
+ *	@adap: the adapter
+ *	@skb: the packet to send
+ *	@pi: the egress interface
+ *	@pidx: index of the first Tx descriptor to write
+ *	@gen: the generation value to use
+ *	@q: the Tx queue
+ *	@ndesc: number of descriptors the packet will occupy
+ *	@compl: the value of the COMPL bit to use
+ *
+ *	Generate a TX_PKT work request to send the supplied packet.
+ */
+static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb,
+			    const struct port_info *pi,
+			    unsigned int pidx, unsigned int gen,
+			    struct sge_txq *q, unsigned int ndesc,
+			    unsigned int compl)
+{
+	unsigned int flits, sgl_flits, cntrl, tso_info;
+	struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1];
+	struct tx_desc *d = &q->desc[pidx];
+	struct cpl_tx_pkt *cpl = (struct cpl_tx_pkt *)d;
+
+	cpl->len = htonl(skb->len | 0x80000000);
+	cntrl = V_TXPKT_INTF(pi->port_id);
+
+	if (vlan_tx_tag_present(skb) && pi->vlan_grp)
+		cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN(vlan_tx_tag_get(skb));
+
+	tso_info = V_LSO_MSS(skb_shinfo(skb)->gso_size);
+	if (tso_info) {
+		int eth_type;
+		struct cpl_tx_pkt_lso *hdr = (struct cpl_tx_pkt_lso *)cpl;
+
+		d->flit[2] = 0;
+		cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT_LSO);
+		hdr->cntrl = htonl(cntrl);
+		eth_type = skb->nh.raw - skb->data == ETH_HLEN ?
+		    CPL_ETH_II : CPL_ETH_II_VLAN;
+		tso_info |= V_LSO_ETH_TYPE(eth_type) |
+		    V_LSO_IPHDR_WORDS(skb->nh.iph->ihl) |
+		    V_LSO_TCPHDR_WORDS(skb->h.th->doff);
+		hdr->lso_info = htonl(tso_info);
+		flits = 3;
+	} else {
+		cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT);
+		cntrl |= F_TXPKT_IPCSUM_DIS;	/* SW calculates IP csum */
+		cntrl |= V_TXPKT_L4CSUM_DIS(skb->ip_summed != CHECKSUM_PARTIAL);
+		cpl->cntrl = htonl(cntrl);
+
+		if (skb->len <= WR_LEN - sizeof(*cpl)) {
+			q->sdesc[pidx].skb = NULL;
+			if (!skb->data_len)
+				memcpy(&d->flit[2], skb->data, skb->len);
+			else
+				skb_copy_bits(skb, 0, &d->flit[2], skb->len);
+
+			flits = (skb->len + 7) / 8 + 2;
+			cpl->wr.wr_hi = htonl(V_WR_BCNTLFLT(skb->len & 7) |
+					      V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT)
+					      | F_WR_SOP | F_WR_EOP | compl);
+			wmb();
+			cpl->wr.wr_lo = htonl(V_WR_LEN(flits) | V_WR_GEN(gen) |
+					      V_WR_TID(q->token));
+			wr_gen2(d, gen);
+			kfree_skb(skb);
+			return;
+		}
+
+		flits = 2;
+	}
+
+	sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
+	sgl_flits = make_sgl(skb, sgp, skb->data, skb_headlen(skb), adap->pdev);
+	if (need_skb_unmap())
+		((struct unmap_info *)skb->cb)->len = skb_headlen(skb);
+
+	write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen,
+			 htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl),
+			 htonl(V_WR_TID(q->token)));
+}
+
+/**
+ *	eth_xmit - add a packet to the Ethernet Tx queue
+ *	@skb: the packet
+ *	@dev: the egress net device
+ *
+ *	Add a packet to an SGE Tx queue.  Runs with softirqs disabled.
+ */
+int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	unsigned int ndesc, pidx, credits, gen, compl;
+	const struct port_info *pi = netdev_priv(dev);
+	struct adapter *adap = dev->priv;
+	struct sge_qset *qs = dev2qset(dev);
+	struct sge_txq *q = &qs->txq[TXQ_ETH];
+
+	/*
+	 * The chip min packet length is 9 octets but play safe and reject
+	 * anything shorter than an Ethernet header.
+	 */
+	if (unlikely(skb->len < ETH_HLEN)) {
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	spin_lock(&q->lock);
+	reclaim_completed_tx(adap, q);
+
+	credits = q->size - q->in_use;
+	ndesc = calc_tx_descs(skb);
+
+	if (unlikely(credits < ndesc)) {
+		if (!netif_queue_stopped(dev)) {
+			netif_stop_queue(dev);
+			set_bit(TXQ_ETH, &qs->txq_stopped);
+			q->stops++;
+			dev_err(&adap->pdev->dev,
+				"%s: Tx ring %u full while queue awake!\n",
+				dev->name, q->cntxt_id & 7);
+		}
+		spin_unlock(&q->lock);
+		return NETDEV_TX_BUSY;
+	}
+
+	q->in_use += ndesc;
+	if (unlikely(credits - ndesc < q->stop_thres)) {
+		q->stops++;
+		netif_stop_queue(dev);
+		set_bit(TXQ_ETH, &qs->txq_stopped);
+#if !USE_GTS
+		if (should_restart_tx(q) &&
+		    test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) {
+			q->restarts++;
+			netif_wake_queue(dev);
+		}
+#endif
+	}
+
+	gen = q->gen;
+	q->unacked += ndesc;
+	compl = (q->unacked & 8) << (S_WR_COMPL - 3);
+	q->unacked &= 7;
+	pidx = q->pidx;
+	q->pidx += ndesc;
+	if (q->pidx >= q->size) {
+		q->pidx -= q->size;
+		q->gen ^= 1;
+	}
+
+	/* update port statistics */
+	if (skb->ip_summed == CHECKSUM_COMPLETE)
+		qs->port_stats[SGE_PSTAT_TX_CSUM]++;
+	if (skb_shinfo(skb)->gso_size)
+		qs->port_stats[SGE_PSTAT_TSO]++;
+	if (vlan_tx_tag_present(skb) && pi->vlan_grp)
+		qs->port_stats[SGE_PSTAT_VLANINS]++;
+
+	dev->trans_start = jiffies;
+	spin_unlock(&q->lock);
+
+	/*
+	 * We do not use Tx completion interrupts to free DMAd Tx packets.
+	 * This is good for performamce but means that we rely on new Tx
+	 * packets arriving to run the destructors of completed packets,
+	 * which open up space in their sockets' send queues.  Sometimes
+	 * we do not get such new packets causing Tx to stall.  A single
+	 * UDP transmitter is a good example of this situation.  We have
+	 * a clean up timer that periodically reclaims completed packets
+	 * but it doesn't run often enough (nor do we want it to) to prevent
+	 * lengthy stalls.  A solution to this problem is to run the
+	 * destructor early, after the packet is queued but before it's DMAd.
+	 * A cons is that we lie to socket memory accounting, but the amount
+	 * of extra memory is reasonable (limited by the number of Tx
+	 * descriptors), the packets do actually get freed quickly by new
+	 * packets almost always, and for protocols like TCP that wait for
+	 * acks to really free up the data the extra memory is even less.
+	 * On the positive side we run the destructors on the sending CPU
+	 * rather than on a potentially different completing CPU, usually a
+	 * good thing.  We also run them without holding our Tx queue lock,
+	 * unlike what reclaim_completed_tx() would otherwise do.
+	 *
+	 * Run the destructor before telling the DMA engine about the packet
+	 * to make sure it doesn't complete and get freed prematurely.
+	 */
+	if (likely(!skb_shared(skb)))
+		skb_orphan(skb);
+
+	write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl);
+	check_ring_tx_db(adap, q);
+	return NETDEV_TX_OK;
+}
+
+/**
+ *	write_imm - write a packet into a Tx descriptor as immediate data
+ *	@d: the Tx descriptor to write
+ *	@skb: the packet
+ *	@len: the length of packet data to write as immediate data
+ *	@gen: the generation bit value to write
+ *
+ *	Writes a packet as immediate data into a Tx descriptor.  The packet
+ *	contains a work request at its beginning.  We must write the packet
+ *	carefully so the SGE doesn't read accidentally before it's written in
+ *	its entirety.
+ */
+static inline void write_imm(struct tx_desc *d, struct sk_buff *skb,
+			     unsigned int len, unsigned int gen)
+{
+	struct work_request_hdr *from = (struct work_request_hdr *)skb->data;
+	struct work_request_hdr *to = (struct work_request_hdr *)d;
+
+	memcpy(&to[1], &from[1], len - sizeof(*from));
+	to->wr_hi = from->wr_hi | htonl(F_WR_SOP | F_WR_EOP |
+					V_WR_BCNTLFLT(len & 7));
+	wmb();
+	to->wr_lo = from->wr_lo | htonl(V_WR_GEN(gen) |
+					V_WR_LEN((len + 7) / 8));
+	wr_gen2(d, gen);
+	kfree_skb(skb);
+}
+
+/**
+ *	check_desc_avail - check descriptor availability on a send queue
+ *	@adap: the adapter
+ *	@q: the send queue
+ *	@skb: the packet needing the descriptors
+ *	@ndesc: the number of Tx descriptors needed
+ *	@qid: the Tx queue number in its queue set (TXQ_OFLD or TXQ_CTRL)
+ *
+ *	Checks if the requested number of Tx descriptors is available on an
+ *	SGE send queue.  If the queue is already suspended or not enough
+ *	descriptors are available the packet is queued for later transmission.
+ *	Must be called with the Tx queue locked.
+ *
+ *	Returns 0 if enough descriptors are available, 1 if there aren't
+ *	enough descriptors and the packet has been queued, and 2 if the caller
+ *	needs to retry because there weren't enough descriptors at the
+ *	beginning of the call but some freed up in the mean time.
+ */
+static inline int check_desc_avail(struct adapter *adap, struct sge_txq *q,
+				   struct sk_buff *skb, unsigned int ndesc,
+				   unsigned int qid)
+{
+	if (unlikely(!skb_queue_empty(&q->sendq))) {
+	      addq_exit:__skb_queue_tail(&q->sendq, skb);
+		return 1;
+	}
+	if (unlikely(q->size - q->in_use < ndesc)) {
+		struct sge_qset *qs = txq_to_qset(q, qid);
+
+		set_bit(qid, &qs->txq_stopped);
+		smp_mb__after_clear_bit();
+
+		if (should_restart_tx(q) &&
+		    test_and_clear_bit(qid, &qs->txq_stopped))
+			return 2;
+
+		q->stops++;
+		goto addq_exit;
+	}
+	return 0;
+}
+
+/**
+ *	reclaim_completed_tx_imm - reclaim completed control-queue Tx descs
+ *	@q: the SGE control Tx queue
+ *
+ *	This is a variant of reclaim_completed_tx() that is used for Tx queues
+ *	that send only immediate data (presently just the control queues) and
+ *	thus do not have any sk_buffs to release.
+ */
+static inline void reclaim_completed_tx_imm(struct sge_txq *q)
+{
+	unsigned int reclaim = q->processed - q->cleaned;
+
+	q->in_use -= reclaim;
+	q->cleaned += reclaim;
+}
+
+static inline int immediate(const struct sk_buff *skb)
+{
+	return skb->len <= WR_LEN && !skb->data_len;
+}
+
+/**
+ *	ctrl_xmit - send a packet through an SGE control Tx queue
+ *	@adap: the adapter
+ *	@q: the control queue
+ *	@skb: the packet
+ *
+ *	Send a packet through an SGE control Tx queue.  Packets sent through
+ *	a control queue must fit entirely as immediate data in a single Tx
+ *	descriptor and have no page fragments.
+ */
+static int ctrl_xmit(struct adapter *adap, struct sge_txq *q,
+		     struct sk_buff *skb)
+{
+	int ret;
+	struct work_request_hdr *wrp = (struct work_request_hdr *)skb->data;
+
+	if (unlikely(!immediate(skb))) {
+		WARN_ON(1);
+		dev_kfree_skb(skb);
+		return NET_XMIT_SUCCESS;
+	}
+
+	wrp->wr_hi |= htonl(F_WR_SOP | F_WR_EOP);
+	wrp->wr_lo = htonl(V_WR_TID(q->token));
+
+	spin_lock(&q->lock);
+      again:reclaim_completed_tx_imm(q);
+
+	ret = check_desc_avail(adap, q, skb, 1, TXQ_CTRL);
+	if (unlikely(ret)) {
+		if (ret == 1) {
+			spin_unlock(&q->lock);
+			return NET_XMIT_CN;
+		}
+		goto again;
+	}
+
+	write_imm(&q->desc[q->pidx], skb, skb->len, q->gen);
+
+	q->in_use++;
+	if (++q->pidx >= q->size) {
+		q->pidx = 0;
+		q->gen ^= 1;
+	}
+	spin_unlock(&q->lock);
+	wmb();
+	t3_write_reg(adap, A_SG_KDOORBELL,
+		     F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+	return NET_XMIT_SUCCESS;
+}
+
+/**
+ *	restart_ctrlq - restart a suspended control queue
+ *	@qs: the queue set cotaining the control queue
+ *
+ *	Resumes transmission on a suspended Tx control queue.
+ */
+static void restart_ctrlq(unsigned long data)
+{
+	struct sk_buff *skb;
+	struct sge_qset *qs = (struct sge_qset *)data;
+	struct sge_txq *q = &qs->txq[TXQ_CTRL];
+	struct adapter *adap = qs->netdev->priv;
+
+	spin_lock(&q->lock);
+      again:reclaim_completed_tx_imm(q);
+
+	while (q->in_use < q->size && (skb = __skb_dequeue(&q->sendq)) != NULL) {
+
+		write_imm(&q->desc[q->pidx], skb, skb->len, q->gen);
+
+		if (++q->pidx >= q->size) {
+			q->pidx = 0;
+			q->gen ^= 1;
+		}
+		q->in_use++;
+	}
+
+	if (!skb_queue_empty(&q->sendq)) {
+		set_bit(TXQ_CTRL, &qs->txq_stopped);
+		smp_mb__after_clear_bit();
+
+		if (should_restart_tx(q) &&
+		    test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped))
+			goto again;
+		q->stops++;
+	}
+
+	spin_unlock(&q->lock);
+	t3_write_reg(adap, A_SG_KDOORBELL,
+		     F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+}
+
+/*
+ * Send a management message through control queue 0
+ */
+int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb)
+{
+	return ctrl_xmit(adap, &adap->sge.qs[0].txq[TXQ_CTRL], skb);
+}
+
+/**
+ *	write_ofld_wr - write an offload work request
+ *	@adap: the adapter
+ *	@skb: the packet to send
+ *	@q: the Tx queue
+ *	@pidx: index of the first Tx descriptor to write
+ *	@gen: the generation value to use
+ *	@ndesc: number of descriptors the packet will occupy
+ *
+ *	Write an offload work request to send the supplied packet.  The packet
+ *	data already carry the work request with most fields populated.
+ */
+static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb,
+			  struct sge_txq *q, unsigned int pidx,
+			  unsigned int gen, unsigned int ndesc)
+{
+	unsigned int sgl_flits, flits;
+	struct work_request_hdr *from;
+	struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1];
+	struct tx_desc *d = &q->desc[pidx];
+
+	if (immediate(skb)) {
+		q->sdesc[pidx].skb = NULL;
+		write_imm(d, skb, skb->len, gen);
+		return;
+	}
+
+	/* Only TX_DATA builds SGLs */
+
+	from = (struct work_request_hdr *)skb->data;
+	memcpy(&d->flit[1], &from[1], skb->h.raw - skb->data - sizeof(*from));
+
+	flits = (skb->h.raw - skb->data) / 8;
+	sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
+	sgl_flits = make_sgl(skb, sgp, skb->h.raw, skb->tail - skb->h.raw,
+			     adap->pdev);
+	if (need_skb_unmap())
+		((struct unmap_info *)skb->cb)->len = skb->tail - skb->h.raw;
+
+	write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits,
+			 gen, from->wr_hi, from->wr_lo);
+}
+
+/**
+ *	calc_tx_descs_ofld - calculate # of Tx descriptors for an offload packet
+ *	@skb: the packet
+ *
+ * 	Returns the number of Tx descriptors needed for the given offload
+ * 	packet.  These packets are already fully constructed.
+ */
+static inline unsigned int calc_tx_descs_ofld(const struct sk_buff *skb)
+{
+	unsigned int flits, cnt = skb_shinfo(skb)->nr_frags;
+
+	if (skb->len <= WR_LEN && cnt == 0)
+		return 1;	/* packet fits as immediate data */
+
+	flits = (skb->h.raw - skb->data) / 8;	/* headers */
+	if (skb->tail != skb->h.raw)
+		cnt++;
+	return flits_to_desc(flits + sgl_len(cnt));
+}
+
+/**
+ *	ofld_xmit - send a packet through an offload queue
+ *	@adap: the adapter
+ *	@q: the Tx offload queue
+ *	@skb: the packet
+ *
+ *	Send an offload packet through an SGE offload queue.
+ */
+static int ofld_xmit(struct adapter *adap, struct sge_txq *q,
+		     struct sk_buff *skb)
+{
+	int ret;
+	unsigned int ndesc = calc_tx_descs_ofld(skb), pidx, gen;
+
+	spin_lock(&q->lock);
+      again:reclaim_completed_tx(adap, q);
+
+	ret = check_desc_avail(adap, q, skb, ndesc, TXQ_OFLD);
+	if (unlikely(ret)) {
+		if (ret == 1) {
+			skb->priority = ndesc;	/* save for restart */
+			spin_unlock(&q->lock);
+			return NET_XMIT_CN;
+		}
+		goto again;
+	}
+
+	gen = q->gen;
+	q->in_use += ndesc;
+	pidx = q->pidx;
+	q->pidx += ndesc;
+	if (q->pidx >= q->size) {
+		q->pidx -= q->size;
+		q->gen ^= 1;
+	}
+	spin_unlock(&q->lock);
+
+	write_ofld_wr(adap, skb, q, pidx, gen, ndesc);
+	check_ring_tx_db(adap, q);
+	return NET_XMIT_SUCCESS;
+}
+
+/**
+ *	restart_offloadq - restart a suspended offload queue
+ *	@qs: the queue set cotaining the offload queue
+ *
+ *	Resumes transmission on a suspended Tx offload queue.
+ */
+static void restart_offloadq(unsigned long data)
+{
+	struct sk_buff *skb;
+	struct sge_qset *qs = (struct sge_qset *)data;
+	struct sge_txq *q = &qs->txq[TXQ_OFLD];
+	struct adapter *adap = qs->netdev->priv;
+
+	spin_lock(&q->lock);
+      again:reclaim_completed_tx(adap, q);
+
+	while ((skb = skb_peek(&q->sendq)) != NULL) {
+		unsigned int gen, pidx;
+		unsigned int ndesc = skb->priority;
+
+		if (unlikely(q->size - q->in_use < ndesc)) {
+			set_bit(TXQ_OFLD, &qs->txq_stopped);
+			smp_mb__after_clear_bit();
+
+			if (should_restart_tx(q) &&
+			    test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped))
+				goto again;
+			q->stops++;
+			break;
+		}
+
+		gen = q->gen;
+		q->in_use += ndesc;
+		pidx = q->pidx;
+		q->pidx += ndesc;
+		if (q->pidx >= q->size) {
+			q->pidx -= q->size;
+			q->gen ^= 1;
+		}
+		__skb_unlink(skb, &q->sendq);
+		spin_unlock(&q->lock);
+
+		write_ofld_wr(adap, skb, q, pidx, gen, ndesc);
+		spin_lock(&q->lock);
+	}
+	spin_unlock(&q->lock);
+
+#if USE_GTS
+	set_bit(TXQ_RUNNING, &q->flags);
+	set_bit(TXQ_LAST_PKT_DB, &q->flags);
+#endif
+	t3_write_reg(adap, A_SG_KDOORBELL,
+		     F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+}
+
+/**
+ *	queue_set - return the queue set a packet should use
+ *	@skb: the packet
+ *
+ *	Maps a packet to the SGE queue set it should use.  The desired queue
+ *	set is carried in bits 1-3 in the packet's priority.
+ */
+static inline int queue_set(const struct sk_buff *skb)
+{
+	return skb->priority >> 1;
+}
+
+/**
+ *	is_ctrl_pkt - return whether an offload packet is a control packet
+ *	@skb: the packet
+ *
+ *	Determines whether an offload packet should use an OFLD or a CTRL
+ *	Tx queue.  This is indicated by bit 0 in the packet's priority.
+ */
+static inline int is_ctrl_pkt(const struct sk_buff *skb)
+{
+	return skb->priority & 1;
+}
+
+/**
+ *	t3_offload_tx - send an offload packet
+ *	@tdev: the offload device to send to
+ *	@skb: the packet
+ *
+ *	Sends an offload packet.  We use the packet priority to select the
+ *	appropriate Tx queue as follows: bit 0 indicates whether the packet
+ *	should be sent as regular or control, bits 1-3 select the queue set.
+ */
+int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
+{
+	struct adapter *adap = tdev2adap(tdev);
+	struct sge_qset *qs = &adap->sge.qs[queue_set(skb)];
+
+	if (unlikely(is_ctrl_pkt(skb)))
+		return ctrl_xmit(adap, &qs->txq[TXQ_CTRL], skb);
+
+	return ofld_xmit(adap, &qs->txq[TXQ_OFLD], skb);
+}
+
+/**
+ *	offload_enqueue - add an offload packet to an SGE offload receive queue
+ *	@q: the SGE response queue
+ *	@skb: the packet
+ *
+ *	Add a new offload packet to an SGE response queue's offload packet
+ *	queue.  If the packet is the first on the queue it schedules the RX
+ *	softirq to process the queue.
+ */
+static inline void offload_enqueue(struct sge_rspq *q, struct sk_buff *skb)
+{
+	skb->next = skb->prev = NULL;
+	if (q->rx_tail)
+		q->rx_tail->next = skb;
+	else {
+		struct sge_qset *qs = rspq_to_qset(q);
+
+		if (__netif_rx_schedule_prep(qs->netdev))
+			__netif_rx_schedule(qs->netdev);
+		q->rx_head = skb;
+	}
+	q->rx_tail = skb;
+}
+
+/**
+ *	deliver_partial_bundle - deliver a (partial) bundle of Rx offload pkts
+ *	@tdev: the offload device that will be receiving the packets
+ *	@q: the SGE response queue that assembled the bundle
+ *	@skbs: the partial bundle
+ *	@n: the number of packets in the bundle
+ *
+ *	Delivers a (partial) bundle of Rx offload packets to an offload device.
+ */
+static inline void deliver_partial_bundle(struct t3cdev *tdev,
+					  struct sge_rspq *q,
+					  struct sk_buff *skbs[], int n)
+{
+	if (n) {
+		q->offload_bundles++;
+		tdev->recv(tdev, skbs, n);
+	}
+}
+
+/**
+ *	ofld_poll - NAPI handler for offload packets in interrupt mode
+ *	@dev: the network device doing the polling
+ *	@budget: polling budget
+ *
+ *	The NAPI handler for offload packets when a response queue is serviced
+ *	by the hard interrupt handler, i.e., when it's operating in non-polling
+ *	mode.  Creates small packet batches and sends them through the offload
+ *	receive handler.  Batches need to be of modest size as we do prefetches
+ *	on the packets in each.
+ */
+static int ofld_poll(struct net_device *dev, int *budget)
+{
+	struct adapter *adapter = dev->priv;
+	struct sge_qset *qs = dev2qset(dev);
+	struct sge_rspq *q = &qs->rspq;
+	int work_done, limit = min(*budget, dev->quota), avail = limit;
+
+	while (avail) {
+		struct sk_buff *head, *tail, *skbs[RX_BUNDLE_SIZE];
+		int ngathered;
+
+		spin_lock_irq(&q->lock);
+		head = q->rx_head;
+		if (!head) {
+			work_done = limit - avail;
+			*budget -= work_done;
+			dev->quota -= work_done;
+			__netif_rx_complete(dev);
+			spin_unlock_irq(&q->lock);
+			return 0;
+		}
+
+		tail = q->rx_tail;
+		q->rx_head = q->rx_tail = NULL;
+		spin_unlock_irq(&q->lock);
+
+		for (ngathered = 0; avail && head; avail--) {
+			prefetch(head->data);
+			skbs[ngathered] = head;
+			head = head->next;
+			skbs[ngathered]->next = NULL;
+			if (++ngathered == RX_BUNDLE_SIZE) {
+				q->offload_bundles++;
+				adapter->tdev.recv(&adapter->tdev, skbs,
+						   ngathered);
+				ngathered = 0;
+			}
+		}
+		if (head) {	/* splice remaining packets back onto Rx queue */
+			spin_lock_irq(&q->lock);
+			tail->next = q->rx_head;
+			if (!q->rx_head)
+				q->rx_tail = tail;
+			q->rx_head = head;
+			spin_unlock_irq(&q->lock);
+		}
+		deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered);
+	}
+	work_done = limit - avail;
+	*budget -= work_done;
+	dev->quota -= work_done;
+	return 1;
+}
+
+/**
+ *	rx_offload - process a received offload packet
+ *	@tdev: the offload device receiving the packet
+ *	@rq: the response queue that received the packet
+ *	@skb: the packet
+ *	@rx_gather: a gather list of packets if we are building a bundle
+ *	@gather_idx: index of the next available slot in the bundle
+ *
+ *	Process an ingress offload pakcet and add it to the offload ingress
+ *	queue. 	Returns the index of the next available slot in the bundle.
+ */
+static inline int rx_offload(struct t3cdev *tdev, struct sge_rspq *rq,
+			     struct sk_buff *skb, struct sk_buff *rx_gather[],
+			     unsigned int gather_idx)
+{
+	rq->offload_pkts++;
+	skb->mac.raw = skb->nh.raw = skb->h.raw = skb->data;
+
+	if (rq->polling) {
+		rx_gather[gather_idx++] = skb;
+		if (gather_idx == RX_BUNDLE_SIZE) {
+			tdev->recv(tdev, rx_gather, RX_BUNDLE_SIZE);
+			gather_idx = 0;
+			rq->offload_bundles++;
+		}
+	} else
+		offload_enqueue(rq, skb);
+
+	return gather_idx;
+}
+
+/**
+ *	restart_tx - check whether to restart suspended Tx queues
+ *	@qs: the queue set to resume
+ *
+ *	Restarts suspended Tx queues of an SGE queue set if they have enough
+ *	free resources to resume operation.
+ */
+static void restart_tx(struct sge_qset *qs)
+{
+	if (test_bit(TXQ_ETH, &qs->txq_stopped) &&
+	    should_restart_tx(&qs->txq[TXQ_ETH]) &&
+	    test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) {
+		qs->txq[TXQ_ETH].restarts++;
+		if (netif_running(qs->netdev))
+			netif_wake_queue(qs->netdev);
+	}
+
+	if (test_bit(TXQ_OFLD, &qs->txq_stopped) &&
+	    should_restart_tx(&qs->txq[TXQ_OFLD]) &&
+	    test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) {
+		qs->txq[TXQ_OFLD].restarts++;
+		tasklet_schedule(&qs->txq[TXQ_OFLD].qresume_tsk);
+	}
+	if (test_bit(TXQ_CTRL, &qs->txq_stopped) &&
+	    should_restart_tx(&qs->txq[TXQ_CTRL]) &&
+	    test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) {
+		qs->txq[TXQ_CTRL].restarts++;
+		tasklet_schedule(&qs->txq[TXQ_CTRL].qresume_tsk);
+	}
+}
+
+/**
+ *	rx_eth - process an ingress ethernet packet
+ *	@adap: the adapter
+ *	@rq: the response queue that received the packet
+ *	@skb: the packet
+ *	@pad: amount of padding at the start of the buffer
+ *
+ *	Process an ingress ethernet pakcet and deliver it to the stack.
+ *	The padding is 2 if the packet was delivered in an Rx buffer and 0
+ *	if it was immediate data in a response.
+ */
+static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
+		   struct sk_buff *skb, int pad)
+{
+	struct cpl_rx_pkt *p = (struct cpl_rx_pkt *)(skb->data + pad);
+	struct port_info *pi;
+
+	rq->eth_pkts++;
+	skb_pull(skb, sizeof(*p) + pad);
+	skb->dev = adap->port[p->iff];
+	skb->dev->last_rx = jiffies;
+	skb->protocol = eth_type_trans(skb, skb->dev);
+	pi = netdev_priv(skb->dev);
+	if (pi->rx_csum_offload && p->csum_valid && p->csum == 0xffff &&
+	    !p->fragment) {
+		rspq_to_qset(rq)->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++;
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+	} else
+		skb->ip_summed = CHECKSUM_NONE;
+
+	if (unlikely(p->vlan_valid)) {
+		struct vlan_group *grp = pi->vlan_grp;
+
+		rspq_to_qset(rq)->port_stats[SGE_PSTAT_VLANEX]++;
+		if (likely(grp))
+			__vlan_hwaccel_rx(skb, grp, ntohs(p->vlan),
+					  rq->polling);
+		else
+			dev_kfree_skb_any(skb);
+	} else if (rq->polling)
+		netif_receive_skb(skb);
+	else
+		netif_rx(skb);
+}
+
+/**
+ *	handle_rsp_cntrl_info - handles control information in a response
+ *	@qs: the queue set corresponding to the response
+ *	@flags: the response control flags
+ *
+ *	Handles the control information of an SGE response, such as GTS
+ *	indications and completion credits for the queue set's Tx queues.
+ *	HW coalesces credits, we don't do any extra SW coalescing.
+ */
+static inline void handle_rsp_cntrl_info(struct sge_qset *qs, u32 flags)
+{
+	unsigned int credits;
+
+#if USE_GTS
+	if (flags & F_RSPD_TXQ0_GTS)
+		clear_bit(TXQ_RUNNING, &qs->txq[TXQ_ETH].flags);
+#endif
+
+	credits = G_RSPD_TXQ0_CR(flags);
+	if (credits)
+		qs->txq[TXQ_ETH].processed += credits;
+
+	credits = G_RSPD_TXQ2_CR(flags);
+	if (credits)
+		qs->txq[TXQ_CTRL].processed += credits;
+
+# if USE_GTS
+	if (flags & F_RSPD_TXQ1_GTS)
+		clear_bit(TXQ_RUNNING, &qs->txq[TXQ_OFLD].flags);
+# endif
+	credits = G_RSPD_TXQ1_CR(flags);
+	if (credits)
+		qs->txq[TXQ_OFLD].processed += credits;
+}
+
+/**
+ *	check_ring_db - check if we need to ring any doorbells
+ *	@adapter: the adapter
+ *	@qs: the queue set whose Tx queues are to be examined
+ *	@sleeping: indicates which Tx queue sent GTS
+ *
+ *	Checks if some of a queue set's Tx queues need to ring their doorbells
+ *	to resume transmission after idling while they still have unprocessed
+ *	descriptors.
+ */
+static void check_ring_db(struct adapter *adap, struct sge_qset *qs,
+			  unsigned int sleeping)
+{
+	if (sleeping & F_RSPD_TXQ0_GTS) {
+		struct sge_txq *txq = &qs->txq[TXQ_ETH];
+
+		if (txq->cleaned + txq->in_use != txq->processed &&
+		    !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) {
+			set_bit(TXQ_RUNNING, &txq->flags);
+			t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX |
+				     V_EGRCNTX(txq->cntxt_id));
+		}
+	}
+
+	if (sleeping & F_RSPD_TXQ1_GTS) {
+		struct sge_txq *txq = &qs->txq[TXQ_OFLD];
+
+		if (txq->cleaned + txq->in_use != txq->processed &&
+		    !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) {
+			set_bit(TXQ_RUNNING, &txq->flags);
+			t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX |
+				     V_EGRCNTX(txq->cntxt_id));
+		}
+	}
+}
+
+/**
+ *	is_new_response - check if a response is newly written
+ *	@r: the response descriptor
+ *	@q: the response queue
+ *
+ *	Returns true if a response descriptor contains a yet unprocessed
+ *	response.
+ */
+static inline int is_new_response(const struct rsp_desc *r,
+				  const struct sge_rspq *q)
+{
+	return (r->intr_gen & F_RSPD_GEN2) == q->gen;
+}
+
+#define RSPD_GTS_MASK  (F_RSPD_TXQ0_GTS | F_RSPD_TXQ1_GTS)
+#define RSPD_CTRL_MASK (RSPD_GTS_MASK | \
+			V_RSPD_TXQ0_CR(M_RSPD_TXQ0_CR) | \
+			V_RSPD_TXQ1_CR(M_RSPD_TXQ1_CR) | \
+			V_RSPD_TXQ2_CR(M_RSPD_TXQ2_CR))
+
+/* How long to delay the next interrupt in case of memory shortage, in 0.1us. */
+#define NOMEM_INTR_DELAY 2500
+
+/**
+ *	process_responses - process responses from an SGE response queue
+ *	@adap: the adapter
+ *	@qs: the queue set to which the response queue belongs
+ *	@budget: how many responses can be processed in this round
+ *
+ *	Process responses from an SGE response queue up to the supplied budget.
+ *	Responses include received packets as well as credits and other events
+ *	for the queues that belong to the response queue's queue set.
+ *	A negative budget is effectively unlimited.
+ *
+ *	Additionally choose the interrupt holdoff time for the next interrupt
+ *	on this queue.  If the system is under memory shortage use a fairly
+ *	long delay to help recovery.
+ */
+static int process_responses(struct adapter *adap, struct sge_qset *qs,
+			     int budget)
+{
+	struct sge_rspq *q = &qs->rspq;
+	struct rsp_desc *r = &q->desc[q->cidx];
+	int budget_left = budget;
+	unsigned int sleeping = 0;
+	struct sk_buff *offload_skbs[RX_BUNDLE_SIZE];
+	int ngathered = 0;
+
+	q->next_holdoff = q->holdoff_tmr;
+
+	while (likely(budget_left && is_new_response(r, q))) {
+		int eth, ethpad = 0;
+		struct sk_buff *skb = NULL;
+		u32 len, flags = ntohl(r->flags);
+		u32 rss_hi = *(const u32 *)r, rss_lo = r->rss_hdr.rss_hash_val;
+
+		eth = r->rss_hdr.opcode == CPL_RX_PKT;
+
+		if (unlikely(flags & F_RSPD_ASYNC_NOTIF)) {
+			skb = alloc_skb(AN_PKT_SIZE, GFP_ATOMIC);
+			if (!skb)
+				goto no_mem;
+
+			memcpy(__skb_put(skb, AN_PKT_SIZE), r, AN_PKT_SIZE);
+			skb->data[0] = CPL_ASYNC_NOTIF;
+			rss_hi = htonl(CPL_ASYNC_NOTIF << 24);
+			q->async_notif++;
+		} else if (flags & F_RSPD_IMM_DATA_VALID) {
+			skb = get_imm_packet(r);
+			if (unlikely(!skb)) {
+			      no_mem:
+				q->next_holdoff = NOMEM_INTR_DELAY;
+				q->nomem++;
+				/* consume one credit since we tried */
+				budget_left--;
+				break;
+			}
+			q->imm_data++;
+		} else if ((len = ntohl(r->len_cq)) != 0) {
+			struct sge_fl *fl;
+
+			fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0];
+			fl->credits--;
+			skb = get_packet(adap, fl, G_RSPD_LEN(len),
+					 eth ? SGE_RX_DROP_THRES : 0);
+			if (!skb)
+				q->rx_drops++;
+			else if (r->rss_hdr.opcode == CPL_TRACE_PKT)
+				__skb_pull(skb, 2);
+			ethpad = 2;
+			if (++fl->cidx == fl->size)
+				fl->cidx = 0;
+		} else
+			q->pure_rsps++;
+
+		if (flags & RSPD_CTRL_MASK) {
+			sleeping |= flags & RSPD_GTS_MASK;
+			handle_rsp_cntrl_info(qs, flags);
+		}
+
+		r++;
+		if (unlikely(++q->cidx == q->size)) {
+			q->cidx = 0;
+			q->gen ^= 1;
+			r = q->desc;
+		}
+		prefetch(r);
+
+		if (++q->credits >= (q->size / 4)) {
+			refill_rspq(adap, q, q->credits);
+			q->credits = 0;
+		}
+
+		if (likely(skb != NULL)) {
+			if (eth)
+				rx_eth(adap, q, skb, ethpad);
+			else {
+				/* Preserve the RSS info in csum & priority */
+				skb->csum = rss_hi;
+				skb->priority = rss_lo;
+				ngathered = rx_offload(&adap->tdev, q, skb,
+						       offload_skbs, ngathered);
+			}
+		}
+
+		--budget_left;
+	}
+
+	deliver_partial_bundle(&adap->tdev, q, offload_skbs, ngathered);
+	if (sleeping)
+		check_ring_db(adap, qs, sleeping);
+
+	smp_mb();		/* commit Tx queue .processed updates */
+	if (unlikely(qs->txq_stopped != 0))
+		restart_tx(qs);
+
+	budget -= budget_left;
+	return budget;
+}
+
+static inline int is_pure_response(const struct rsp_desc *r)
+{
+	u32 n = ntohl(r->flags) & (F_RSPD_ASYNC_NOTIF | F_RSPD_IMM_DATA_VALID);
+
+	return (n | r->len_cq) == 0;
+}
+
+/**
+ *	napi_rx_handler - the NAPI handler for Rx processing
+ *	@dev: the net device
+ *	@budget: how many packets we can process in this round
+ *
+ *	Handler for new data events when using NAPI.
+ */
+static int napi_rx_handler(struct net_device *dev, int *budget)
+{
+	struct adapter *adap = dev->priv;
+	struct sge_qset *qs = dev2qset(dev);
+	int effective_budget = min(*budget, dev->quota);
+
+	int work_done = process_responses(adap, qs, effective_budget);
+	*budget -= work_done;
+	dev->quota -= work_done;
+
+	if (work_done >= effective_budget)
+		return 1;
+
+	netif_rx_complete(dev);
+
+	/*
+	 * Because we don't atomically flush the following write it is
+	 * possible that in very rare cases it can reach the device in a way
+	 * that races with a new response being written plus an error interrupt
+	 * causing the NAPI interrupt handler below to return unhandled status
+	 * to the OS.  To protect against this would require flushing the write
+	 * and doing both the write and the flush with interrupts off.  Way too
+	 * expensive and unjustifiable given the rarity of the race.
+	 *
+	 * The race cannot happen at all with MSI-X.
+	 */
+	t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) |
+		     V_NEWTIMER(qs->rspq.next_holdoff) |
+		     V_NEWINDEX(qs->rspq.cidx));
+	return 0;
+}
+
+/*
+ * Returns true if the device is already scheduled for polling.
+ */
+static inline int napi_is_scheduled(struct net_device *dev)
+{
+	return test_bit(__LINK_STATE_RX_SCHED, &dev->state);
+}
+
+/**
+ *	process_pure_responses - process pure responses from a response queue
+ *	@adap: the adapter
+ *	@qs: the queue set owning the response queue
+ *	@r: the first pure response to process
+ *
+ *	A simpler version of process_responses() that handles only pure (i.e.,
+ *	non data-carrying) responses.  Such respones are too light-weight to
+ *	justify calling a softirq under NAPI, so we handle them specially in
+ *	the interrupt handler.  The function is called with a pointer to a
+ *	response, which the caller must ensure is a valid pure response.
+ *
+ *	Returns 1 if it encounters a valid data-carrying response, 0 otherwise.
+ */
+static int process_pure_responses(struct adapter *adap, struct sge_qset *qs,
+				  struct rsp_desc *r)
+{
+	struct sge_rspq *q = &qs->rspq;
+	unsigned int sleeping = 0;
+
+	do {
+		u32 flags = ntohl(r->flags);
+
+		r++;
+		if (unlikely(++q->cidx == q->size)) {
+			q->cidx = 0;
+			q->gen ^= 1;
+			r = q->desc;
+		}
+		prefetch(r);
+
+		if (flags & RSPD_CTRL_MASK) {
+			sleeping |= flags & RSPD_GTS_MASK;
+			handle_rsp_cntrl_info(qs, flags);
+		}
+
+		q->pure_rsps++;
+		if (++q->credits >= (q->size / 4)) {
+			refill_rspq(adap, q, q->credits);
+			q->credits = 0;
+		}
+	} while (is_new_response(r, q) && is_pure_response(r));
+
+	if (sleeping)
+		check_ring_db(adap, qs, sleeping);
+
+	smp_mb();		/* commit Tx queue .processed updates */
+	if (unlikely(qs->txq_stopped != 0))
+		restart_tx(qs);
+
+	return is_new_response(r, q);
+}
+
+/**
+ *	handle_responses - decide what to do with new responses in NAPI mode
+ *	@adap: the adapter
+ *	@q: the response queue
+ *
+ *	This is used by the NAPI interrupt handlers to decide what to do with
+ *	new SGE responses.  If there are no new responses it returns -1.  If
+ *	there are new responses and they are pure (i.e., non-data carrying)
+ *	it handles them straight in hard interrupt context as they are very
+ *	cheap and don't deliver any packets.  Finally, if there are any data
+ *	signaling responses it schedules the NAPI handler.  Returns 1 if it
+ *	schedules NAPI, 0 if all new responses were pure.
+ *
+ *	The caller must ascertain NAPI is not already running.
+ */
+static inline int handle_responses(struct adapter *adap, struct sge_rspq *q)
+{
+	struct sge_qset *qs = rspq_to_qset(q);
+	struct rsp_desc *r = &q->desc[q->cidx];
+
+	if (!is_new_response(r, q))
+		return -1;
+	if (is_pure_response(r) && process_pure_responses(adap, qs, r) == 0) {
+		t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) |
+			     V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx));
+		return 0;
+	}
+	if (likely(__netif_rx_schedule_prep(qs->netdev)))
+		__netif_rx_schedule(qs->netdev);
+	return 1;
+}
+
+/*
+ * The MSI-X interrupt handler for an SGE response queue for the non-NAPI case
+ * (i.e., response queue serviced in hard interrupt).
+ */
+irqreturn_t t3_sge_intr_msix(int irq, void *cookie)
+{
+	struct sge_qset *qs = cookie;
+	struct adapter *adap = qs->netdev->priv;
+	struct sge_rspq *q = &qs->rspq;
+
+	spin_lock(&q->lock);
+	if (process_responses(adap, qs, -1) == 0)
+		q->unhandled_irqs++;
+	t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) |
+		     V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx));
+	spin_unlock(&q->lock);
+	return IRQ_HANDLED;
+}
+
+/*
+ * The MSI-X interrupt handler for an SGE response queue for the NAPI case
+ * (i.e., response queue serviced by NAPI polling).
+ */
+irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie)
+{
+	struct sge_qset *qs = cookie;
+	struct adapter *adap = qs->netdev->priv;
+	struct sge_rspq *q = &qs->rspq;
+
+	spin_lock(&q->lock);
+	BUG_ON(napi_is_scheduled(qs->netdev));
+
+	if (handle_responses(adap, q) < 0)
+		q->unhandled_irqs++;
+	spin_unlock(&q->lock);
+	return IRQ_HANDLED;
+}
+
+/*
+ * The non-NAPI MSI interrupt handler.  This needs to handle data events from
+ * SGE response queues as well as error and other async events as they all use
+ * the same MSI vector.  We use one SGE response queue per port in this mode
+ * and protect all response queues with queue 0's lock.
+ */
+static irqreturn_t t3_intr_msi(int irq, void *cookie)
+{
+	int new_packets = 0;
+	struct adapter *adap = cookie;
+	struct sge_rspq *q = &adap->sge.qs[0].rspq;
+
+	spin_lock(&q->lock);
+
+	if (process_responses(adap, &adap->sge.qs[0], -1)) {
+		t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) |
+			     V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx));
+		new_packets = 1;
+	}
+
+	if (adap->params.nports == 2 &&
+	    process_responses(adap, &adap->sge.qs[1], -1)) {
+		struct sge_rspq *q1 = &adap->sge.qs[1].rspq;
+
+		t3_write_reg(adap, A_SG_GTS, V_RSPQ(q1->cntxt_id) |
+			     V_NEWTIMER(q1->next_holdoff) |
+			     V_NEWINDEX(q1->cidx));
+		new_packets = 1;
+	}
+
+	if (!new_packets && t3_slow_intr_handler(adap) == 0)
+		q->unhandled_irqs++;
+
+	spin_unlock(&q->lock);
+	return IRQ_HANDLED;
+}
+
+static int rspq_check_napi(struct net_device *dev, struct sge_rspq *q)
+{
+	if (!napi_is_scheduled(dev) && is_new_response(&q->desc[q->cidx], q)) {
+		if (likely(__netif_rx_schedule_prep(dev)))
+			__netif_rx_schedule(dev);
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * The MSI interrupt handler for the NAPI case (i.e., response queues serviced
+ * by NAPI polling).  Handles data events from SGE response queues as well as
+ * error and other async events as they all use the same MSI vector.  We use
+ * one SGE response queue per port in this mode and protect all response
+ * queues with queue 0's lock.
+ */
+irqreturn_t t3_intr_msi_napi(int irq, void *cookie)
+{
+	int new_packets;
+	struct adapter *adap = cookie;
+	struct sge_rspq *q = &adap->sge.qs[0].rspq;
+
+	spin_lock(&q->lock);
+
+	new_packets = rspq_check_napi(adap->sge.qs[0].netdev, q);
+	if (adap->params.nports == 2)
+		new_packets += rspq_check_napi(adap->sge.qs[1].netdev,
+					       &adap->sge.qs[1].rspq);
+	if (!new_packets && t3_slow_intr_handler(adap) == 0)
+		q->unhandled_irqs++;
+
+	spin_unlock(&q->lock);
+	return IRQ_HANDLED;
+}
+
+/*
+ * A helper function that processes responses and issues GTS.
+ */
+static inline int process_responses_gts(struct adapter *adap,
+					struct sge_rspq *rq)
+{
+	int work;
+
+	work = process_responses(adap, rspq_to_qset(rq), -1);
+	t3_write_reg(adap, A_SG_GTS, V_RSPQ(rq->cntxt_id) |
+		     V_NEWTIMER(rq->next_holdoff) | V_NEWINDEX(rq->cidx));
+	return work;
+}
+
+/*
+ * The legacy INTx interrupt handler.  This needs to handle data events from
+ * SGE response queues as well as error and other async events as they all use
+ * the same interrupt pin.  We use one SGE response queue per port in this mode
+ * and protect all response queues with queue 0's lock.
+ */
+static irqreturn_t t3_intr(int irq, void *cookie)
+{
+	int work_done, w0, w1;
+	struct adapter *adap = cookie;
+	struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
+	struct sge_rspq *q1 = &adap->sge.qs[1].rspq;
+
+	spin_lock(&q0->lock);
+
+	w0 = is_new_response(&q0->desc[q0->cidx], q0);
+	w1 = adap->params.nports == 2 &&
+	    is_new_response(&q1->desc[q1->cidx], q1);
+
+	if (likely(w0 | w1)) {
+		t3_write_reg(adap, A_PL_CLI, 0);
+		t3_read_reg(adap, A_PL_CLI);	/* flush */
+
+		if (likely(w0))
+			process_responses_gts(adap, q0);
+
+		if (w1)
+			process_responses_gts(adap, q1);
+
+		work_done = w0 | w1;
+	} else
+		work_done = t3_slow_intr_handler(adap);
+
+	spin_unlock(&q0->lock);
+	return IRQ_RETVAL(work_done != 0);
+}
+
+/*
+ * Interrupt handler for legacy INTx interrupts for T3B-based cards.
+ * Handles data events from SGE response queues as well as error and other
+ * async events as they all use the same interrupt pin.  We use one SGE
+ * response queue per port in this mode and protect all response queues with
+ * queue 0's lock.
+ */
+static irqreturn_t t3b_intr(int irq, void *cookie)
+{
+	u32 map;
+	struct adapter *adap = cookie;
+	struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
+
+	t3_write_reg(adap, A_PL_CLI, 0);
+	map = t3_read_reg(adap, A_SG_DATA_INTR);
+
+	if (unlikely(!map))	/* shared interrupt, most likely */
+		return IRQ_NONE;
+
+	spin_lock(&q0->lock);
+
+	if (unlikely(map & F_ERRINTR))
+		t3_slow_intr_handler(adap);
+
+	if (likely(map & 1))
+		process_responses_gts(adap, q0);
+
+	if (map & 2)
+		process_responses_gts(adap, &adap->sge.qs[1].rspq);
+
+	spin_unlock(&q0->lock);
+	return IRQ_HANDLED;
+}
+
+/*
+ * NAPI interrupt handler for legacy INTx interrupts for T3B-based cards.
+ * Handles data events from SGE response queues as well as error and other
+ * async events as they all use the same interrupt pin.  We use one SGE
+ * response queue per port in this mode and protect all response queues with
+ * queue 0's lock.
+ */
+static irqreturn_t t3b_intr_napi(int irq, void *cookie)
+{
+	u32 map;
+	struct net_device *dev;
+	struct adapter *adap = cookie;
+	struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
+
+	t3_write_reg(adap, A_PL_CLI, 0);
+	map = t3_read_reg(adap, A_SG_DATA_INTR);
+
+	if (unlikely(!map))	/* shared interrupt, most likely */
+		return IRQ_NONE;
+
+	spin_lock(&q0->lock);
+
+	if (unlikely(map & F_ERRINTR))
+		t3_slow_intr_handler(adap);
+
+	if (likely(map & 1)) {
+		dev = adap->sge.qs[0].netdev;
+
+		if (likely(__netif_rx_schedule_prep(dev)))
+			__netif_rx_schedule(dev);
+	}
+	if (map & 2) {
+		dev = adap->sge.qs[1].netdev;
+
+		if (likely(__netif_rx_schedule_prep(dev)))
+			__netif_rx_schedule(dev);
+	}
+
+	spin_unlock(&q0->lock);
+	return IRQ_HANDLED;
+}
+
+/**
+ *	t3_intr_handler - select the top-level interrupt handler
+ *	@adap: the adapter
+ *	@polling: whether using NAPI to service response queues
+ *
+ *	Selects the top-level interrupt handler based on the type of interrupts
+ *	(MSI-X, MSI, or legacy) and whether NAPI will be used to service the
+ *	response queues.
+ */
+intr_handler_t t3_intr_handler(struct adapter *adap, int polling)
+{
+	if (adap->flags & USING_MSIX)
+		return polling ? t3_sge_intr_msix_napi : t3_sge_intr_msix;
+	if (adap->flags & USING_MSI)
+		return polling ? t3_intr_msi_napi : t3_intr_msi;
+	if (adap->params.rev > 0)
+		return polling ? t3b_intr_napi : t3b_intr;
+	return t3_intr;
+}
+
+/**
+ *	t3_sge_err_intr_handler - SGE async event interrupt handler
+ *	@adapter: the adapter
+ *
+ *	Interrupt handler for SGE asynchronous (non-data) events.
+ */
+void t3_sge_err_intr_handler(struct adapter *adapter)
+{
+	unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE);
+
+	if (status & F_RSPQCREDITOVERFOW)
+		CH_ALERT(adapter, "SGE response queue credit overflow\n");
+
+	if (status & F_RSPQDISABLED) {
+		v = t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS);
+
+		CH_ALERT(adapter,
+			 "packet delivered to disabled response queue "
+			 "(0x%x)\n", (v >> S_RSPQ0DISABLED) & 0xff);
+	}
+
+	t3_write_reg(adapter, A_SG_INT_CAUSE, status);
+	if (status & (F_RSPQCREDITOVERFOW | F_RSPQDISABLED))
+		t3_fatal_err(adapter);
+}
+
+/**
+ *	sge_timer_cb - perform periodic maintenance of an SGE qset
+ *	@data: the SGE queue set to maintain
+ *
+ *	Runs periodically from a timer to perform maintenance of an SGE queue
+ *	set.  It performs two tasks:
+ *
+ *	a) Cleans up any completed Tx descriptors that may still be pending.
+ *	Normal descriptor cleanup happens when new packets are added to a Tx
+ *	queue so this timer is relatively infrequent and does any cleanup only
+ *	if the Tx queue has not seen any new packets in a while.  We make a
+ *	best effort attempt to reclaim descriptors, in that we don't wait
+ *	around if we cannot get a queue's lock (which most likely is because
+ *	someone else is queueing new packets and so will also handle the clean
+ *	up).  Since control queues use immediate data exclusively we don't
+ *	bother cleaning them up here.
+ *
+ *	b) Replenishes Rx queues that have run out due to memory shortage.
+ *	Normally new Rx buffers are added when existing ones are consumed but
+ *	when out of memory a queue can become empty.  We try to add only a few
+ *	buffers here, the queue will be replenished fully as these new buffers
+ *	are used up if memory shortage has subsided.
+ */
+static void sge_timer_cb(unsigned long data)
+{
+	spinlock_t *lock;
+	struct sge_qset *qs = (struct sge_qset *)data;
+	struct adapter *adap = qs->netdev->priv;
+
+	if (spin_trylock(&qs->txq[TXQ_ETH].lock)) {
+		reclaim_completed_tx(adap, &qs->txq[TXQ_ETH]);
+		spin_unlock(&qs->txq[TXQ_ETH].lock);
+	}
+	if (spin_trylock(&qs->txq[TXQ_OFLD].lock)) {
+		reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD]);
+		spin_unlock(&qs->txq[TXQ_OFLD].lock);
+	}
+	lock = (adap->flags & USING_MSIX) ? &qs->rspq.lock :
+	    &adap->sge.qs[0].rspq.lock;
+	if (spin_trylock_irq(lock)) {
+		if (!napi_is_scheduled(qs->netdev)) {
+			if (qs->fl[0].credits < qs->fl[0].size)
+				__refill_fl(adap, &qs->fl[0]);
+			if (qs->fl[1].credits < qs->fl[1].size)
+				__refill_fl(adap, &qs->fl[1]);
+		}
+		spin_unlock_irq(lock);
+	}
+	mod_timer(&qs->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD);
+}
+
+/**
+ *	t3_update_qset_coalesce - update coalescing settings for a queue set
+ *	@qs: the SGE queue set
+ *	@p: new queue set parameters
+ *
+ *	Update the coalescing settings for an SGE queue set.  Nothing is done
+ *	if the queue set is not initialized yet.
+ */
+void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p)
+{
+	if (!qs->netdev)
+		return;
+
+	qs->rspq.holdoff_tmr = max(p->coalesce_usecs * 10, 1U);/* can't be 0 */
+	qs->rspq.polling = p->polling;
+	qs->netdev->poll = p->polling ? napi_rx_handler : ofld_poll;
+}
+
+/**
+ *	t3_sge_alloc_qset - initialize an SGE queue set
+ *	@adapter: the adapter
+ *	@id: the queue set id
+ *	@nports: how many Ethernet ports will be using this queue set
+ *	@irq_vec_idx: the IRQ vector index for response queue interrupts
+ *	@p: configuration parameters for this queue set
+ *	@ntxq: number of Tx queues for the queue set
+ *	@netdev: net device associated with this queue set
+ *
+ *	Allocate resources and initialize an SGE queue set.  A queue set
+ *	comprises a response queue, two Rx free-buffer queues, and up to 3
+ *	Tx queues.  The Tx queues are assigned roles in the order Ethernet
+ *	queue, offload queue, and control queue.
+ */
+int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
+		      int irq_vec_idx, const struct qset_params *p,
+		      int ntxq, struct net_device *netdev)
+{
+	int i, ret = -ENOMEM;
+	struct sge_qset *q = &adapter->sge.qs[id];
+
+	init_qset_cntxt(q, id);
+	init_timer(&q->tx_reclaim_timer);
+	q->tx_reclaim_timer.data = (unsigned long)q;
+	q->tx_reclaim_timer.function = sge_timer_cb;
+
+	q->fl[0].desc = alloc_ring(adapter->pdev, p->fl_size,
+				   sizeof(struct rx_desc),
+				   sizeof(struct rx_sw_desc),
+				   &q->fl[0].phys_addr, &q->fl[0].sdesc);
+	if (!q->fl[0].desc)
+		goto err;
+
+	q->fl[1].desc = alloc_ring(adapter->pdev, p->jumbo_size,
+				   sizeof(struct rx_desc),
+				   sizeof(struct rx_sw_desc),
+				   &q->fl[1].phys_addr, &q->fl[1].sdesc);
+	if (!q->fl[1].desc)
+		goto err;
+
+	q->rspq.desc = alloc_ring(adapter->pdev, p->rspq_size,
+				  sizeof(struct rsp_desc), 0,
+				  &q->rspq.phys_addr, NULL);
+	if (!q->rspq.desc)
+		goto err;
+
+	for (i = 0; i < ntxq; ++i) {
+		/*
+		 * The control queue always uses immediate data so does not
+		 * need to keep track of any sk_buffs.
+		 */
+		size_t sz = i == TXQ_CTRL ? 0 : sizeof(struct tx_sw_desc);
+
+		q->txq[i].desc = alloc_ring(adapter->pdev, p->txq_size[i],
+					    sizeof(struct tx_desc), sz,
+					    &q->txq[i].phys_addr,
+					    &q->txq[i].sdesc);
+		if (!q->txq[i].desc)
+			goto err;
+
+		q->txq[i].gen = 1;
+		q->txq[i].size = p->txq_size[i];
+		spin_lock_init(&q->txq[i].lock);
+		skb_queue_head_init(&q->txq[i].sendq);
+	}
+
+	tasklet_init(&q->txq[TXQ_OFLD].qresume_tsk, restart_offloadq,
+		     (unsigned long)q);
+	tasklet_init(&q->txq[TXQ_CTRL].qresume_tsk, restart_ctrlq,
+		     (unsigned long)q);
+
+	q->fl[0].gen = q->fl[1].gen = 1;
+	q->fl[0].size = p->fl_size;
+	q->fl[1].size = p->jumbo_size;
+
+	q->rspq.gen = 1;
+	q->rspq.size = p->rspq_size;
+	spin_lock_init(&q->rspq.lock);
+
+	q->txq[TXQ_ETH].stop_thres = nports *
+	    flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3);
+
+	if (ntxq == 1) {
+		q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + 2 +
+		    sizeof(struct cpl_rx_pkt);
+		q->fl[1].buf_size = MAX_FRAME_SIZE + 2 +
+		    sizeof(struct cpl_rx_pkt);
+	} else {
+		q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE +
+		    sizeof(struct cpl_rx_data);
+		q->fl[1].buf_size = (16 * 1024) -
+		    SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+	}
+
+	spin_lock(&adapter->sge.reg_lock);
+
+	/* FL threshold comparison uses < */
+	ret = t3_sge_init_rspcntxt(adapter, q->rspq.cntxt_id, irq_vec_idx,
+				   q->rspq.phys_addr, q->rspq.size,
+				   q->fl[0].buf_size, 1, 0);
+	if (ret)
+		goto err_unlock;
+
+	for (i = 0; i < SGE_RXQ_PER_SET; ++i) {
+		ret = t3_sge_init_flcntxt(adapter, q->fl[i].cntxt_id, 0,
+					  q->fl[i].phys_addr, q->fl[i].size,
+					  q->fl[i].buf_size, p->cong_thres, 1,
+					  0);
+		if (ret)
+			goto err_unlock;
+	}
+
+	ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_ETH].cntxt_id, USE_GTS,
+				 SGE_CNTXT_ETH, id, q->txq[TXQ_ETH].phys_addr,
+				 q->txq[TXQ_ETH].size, q->txq[TXQ_ETH].token,
+				 1, 0);
+	if (ret)
+		goto err_unlock;
+
+	if (ntxq > 1) {
+		ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_OFLD].cntxt_id,
+					 USE_GTS, SGE_CNTXT_OFLD, id,
+					 q->txq[TXQ_OFLD].phys_addr,
+					 q->txq[TXQ_OFLD].size, 0, 1, 0);
+		if (ret)
+			goto err_unlock;
+	}
+
+	if (ntxq > 2) {
+		ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_CTRL].cntxt_id, 0,
+					 SGE_CNTXT_CTRL, id,
+					 q->txq[TXQ_CTRL].phys_addr,
+					 q->txq[TXQ_CTRL].size,
+					 q->txq[TXQ_CTRL].token, 1, 0);
+		if (ret)
+			goto err_unlock;
+	}
+
+	spin_unlock(&adapter->sge.reg_lock);
+	q->netdev = netdev;
+	t3_update_qset_coalesce(q, p);
+
+	/*
+	 * We use atalk_ptr as a backpointer to a qset.  In case a device is
+	 * associated with multiple queue sets only the first one sets
+	 * atalk_ptr.
+	 */
+	if (netdev->atalk_ptr == NULL)
+		netdev->atalk_ptr = q;
+
+	refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL);
+	refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL);
+	refill_rspq(adapter, &q->rspq, q->rspq.size - 1);
+
+	t3_write_reg(adapter, A_SG_GTS, V_RSPQ(q->rspq.cntxt_id) |
+		     V_NEWTIMER(q->rspq.holdoff_tmr));
+
+	mod_timer(&q->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD);
+	return 0;
+
+      err_unlock:
+	spin_unlock(&adapter->sge.reg_lock);
+      err:
+	t3_free_qset(adapter, q);
+	return ret;
+}
+
+/**
+ *	t3_free_sge_resources - free SGE resources
+ *	@adap: the adapter
+ *
+ *	Frees resources used by the SGE queue sets.
+ */
+void t3_free_sge_resources(struct adapter *adap)
+{
+	int i;
+
+	for (i = 0; i < SGE_QSETS; ++i)
+		t3_free_qset(adap, &adap->sge.qs[i]);
+}
+
+/**
+ *	t3_sge_start - enable SGE
+ *	@adap: the adapter
+ *
+ *	Enables the SGE for DMAs.  This is the last step in starting packet
+ *	transfers.
+ */
+void t3_sge_start(struct adapter *adap)
+{
+	t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, F_GLOBALENABLE);
+}
+
+/**
+ *	t3_sge_stop - disable SGE operation
+ *	@adap: the adapter
+ *
+ *	Disables the DMA engine.  This can be called in emeregencies (e.g.,
+ *	from error interrupts) or from normal process context.  In the latter
+ *	case it also disables any pending queue restart tasklets.  Note that
+ *	if it is called in interrupt context it cannot disable the restart
+ *	tasklets as it cannot wait, however the tasklets will have no effect
+ *	since the doorbells are disabled and the driver will call this again
+ *	later from process context, at which time the tasklets will be stopped
+ *	if they are still running.
+ */
+void t3_sge_stop(struct adapter *adap)
+{
+	t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, 0);
+	if (!in_interrupt()) {
+		int i;
+
+		for (i = 0; i < SGE_QSETS; ++i) {
+			struct sge_qset *qs = &adap->sge.qs[i];
+
+			tasklet_kill(&qs->txq[TXQ_OFLD].qresume_tsk);
+			tasklet_kill(&qs->txq[TXQ_CTRL].qresume_tsk);
+		}
+	}
+}
+
+/**
+ *	t3_sge_init - initialize SGE
+ *	@adap: the adapter
+ *	@p: the SGE parameters
+ *
+ *	Performs SGE initialization needed every time after a chip reset.
+ *	We do not initialize any of the queue sets here, instead the driver
+ *	top-level must request those individually.  We also do not enable DMA
+ *	here, that should be done after the queues have been set up.
+ */
+void t3_sge_init(struct adapter *adap, struct sge_params *p)
+{
+	unsigned int ctrl, ups = ffs(pci_resource_len(adap->pdev, 2) >> 12);
+
+	ctrl = F_DROPPKT | V_PKTSHIFT(2) | F_FLMODE | F_AVOIDCQOVFL |
+	    F_CQCRDTCTRL |
+	    V_HOSTPAGESIZE(PAGE_SHIFT - 11) | F_BIGENDIANINGRESS |
+	    V_USERSPACESIZE(ups ? ups - 1 : 0) | F_ISCSICOALESCING;
+#if SGE_NUM_GENBITS == 1
+	ctrl |= F_EGRGENCTRL;
+#endif
+	if (adap->params.rev > 0) {
+		if (!(adap->flags & (USING_MSIX | USING_MSI)))
+			ctrl |= F_ONEINTMULTQ | F_OPTONEINTMULTQ;
+		ctrl |= F_CQCRDTCTRL | F_AVOIDCQOVFL;
+	}
+	t3_write_reg(adap, A_SG_CONTROL, ctrl);
+	t3_write_reg(adap, A_SG_EGR_RCQ_DRB_THRSH, V_HIRCQDRBTHRSH(512) |
+		     V_LORCQDRBTHRSH(512));
+	t3_write_reg(adap, A_SG_TIMER_TICK, core_ticks_per_usec(adap) / 10);
+	t3_write_reg(adap, A_SG_CMDQ_CREDIT_TH, V_THRESHOLD(32) |
+		     V_TIMEOUT(200 * core_ticks_per_usec(adap)));
+	t3_write_reg(adap, A_SG_HI_DRB_HI_THRSH, 1000);
+	t3_write_reg(adap, A_SG_HI_DRB_LO_THRSH, 256);
+	t3_write_reg(adap, A_SG_LO_DRB_HI_THRSH, 1000);
+	t3_write_reg(adap, A_SG_LO_DRB_LO_THRSH, 256);
+	t3_write_reg(adap, A_SG_OCO_BASE, V_BASE1(0xfff));
+	t3_write_reg(adap, A_SG_DRB_PRI_THRESH, 63 * 1024);
+}
+
+/**
+ *	t3_sge_prep - one-time SGE initialization
+ *	@adap: the associated adapter
+ *	@p: SGE parameters
+ *
+ *	Performs one-time initialization of SGE SW state.  Includes determining
+ *	defaults for the assorted SGE parameters, which admins can change until
+ *	they are used to initialize the SGE.
+ */
+void __devinit t3_sge_prep(struct adapter *adap, struct sge_params *p)
+{
+	int i;
+
+	p->max_pkt_size = (16 * 1024) - sizeof(struct cpl_rx_data) -
+	    SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+	for (i = 0; i < SGE_QSETS; ++i) {
+		struct qset_params *q = p->qset + i;
+
+		q->polling = adap->params.rev > 0;
+		q->coalesce_usecs = 5;
+		q->rspq_size = 1024;
+		q->fl_size = 4096;
+		q->jumbo_size = 512;
+		q->txq_size[TXQ_ETH] = 1024;
+		q->txq_size[TXQ_OFLD] = 1024;
+		q->txq_size[TXQ_CTRL] = 256;
+		q->cong_thres = 0;
+	}
+
+	spin_lock_init(&adap->sge.reg_lock);
+}
+
+/**
+ *	t3_get_desc - dump an SGE descriptor for debugging purposes
+ *	@qs: the queue set
+ *	@qnum: identifies the specific queue (0..2: Tx, 3:response, 4..5: Rx)
+ *	@idx: the descriptor index in the queue
+ *	@data: where to dump the descriptor contents
+ *
+ *	Dumps the contents of a HW descriptor of an SGE queue.  Returns the
+ *	size of the descriptor.
+ */
+int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
+		unsigned char *data)
+{
+	if (qnum >= 6)
+		return -EINVAL;
+
+	if (qnum < 3) {
+		if (!qs->txq[qnum].desc || idx >= qs->txq[qnum].size)
+			return -EINVAL;
+		memcpy(data, &qs->txq[qnum].desc[idx], sizeof(struct tx_desc));
+		return sizeof(struct tx_desc);
+	}
+
+	if (qnum == 3) {
+		if (!qs->rspq.desc || idx >= qs->rspq.size)
+			return -EINVAL;
+		memcpy(data, &qs->rspq.desc[idx], sizeof(struct rsp_desc));
+		return sizeof(struct rsp_desc);
+	}
+
+	qnum -= 4;
+	if (!qs->fl[qnum].desc || idx >= qs->fl[qnum].size)
+		return -EINVAL;
+	memcpy(data, &qs->fl[qnum].desc[idx], sizeof(struct rx_desc));
+	return sizeof(struct rx_desc);
+}
diff --git a/drivers/net/cxgb3/sge_defs.h b/drivers/net/cxgb3/sge_defs.h
new file mode 100644
index 0000000..514869e
--- /dev/null
+++ b/drivers/net/cxgb3/sge_defs.h
@@ -0,0 +1,251 @@
+/*
+ * This file is automatically generated --- any changes will be lost.
+ */
+
+#ifndef _SGE_DEFS_H
+#define _SGE_DEFS_H
+
+#define S_EC_CREDITS    0
+#define M_EC_CREDITS    0x7FFF
+#define V_EC_CREDITS(x) ((x) << S_EC_CREDITS)
+#define G_EC_CREDITS(x) (((x) >> S_EC_CREDITS) & M_EC_CREDITS)
+
+#define S_EC_GTS    15
+#define V_EC_GTS(x) ((x) << S_EC_GTS)
+#define F_EC_GTS    V_EC_GTS(1U)
+
+#define S_EC_INDEX    16
+#define M_EC_INDEX    0xFFFF
+#define V_EC_INDEX(x) ((x) << S_EC_INDEX)
+#define G_EC_INDEX(x) (((x) >> S_EC_INDEX) & M_EC_INDEX)
+
+#define S_EC_SIZE    0
+#define M_EC_SIZE    0xFFFF
+#define V_EC_SIZE(x) ((x) << S_EC_SIZE)
+#define G_EC_SIZE(x) (((x) >> S_EC_SIZE) & M_EC_SIZE)
+
+#define S_EC_BASE_LO    16
+#define M_EC_BASE_LO    0xFFFF
+#define V_EC_BASE_LO(x) ((x) << S_EC_BASE_LO)
+#define G_EC_BASE_LO(x) (((x) >> S_EC_BASE_LO) & M_EC_BASE_LO)
+
+#define S_EC_BASE_HI    0
+#define M_EC_BASE_HI    0xF
+#define V_EC_BASE_HI(x) ((x) << S_EC_BASE_HI)
+#define G_EC_BASE_HI(x) (((x) >> S_EC_BASE_HI) & M_EC_BASE_HI)
+
+#define S_EC_RESPQ    4
+#define M_EC_RESPQ    0x7
+#define V_EC_RESPQ(x) ((x) << S_EC_RESPQ)
+#define G_EC_RESPQ(x) (((x) >> S_EC_RESPQ) & M_EC_RESPQ)
+
+#define S_EC_TYPE    7
+#define M_EC_TYPE    0x7
+#define V_EC_TYPE(x) ((x) << S_EC_TYPE)
+#define G_EC_TYPE(x) (((x) >> S_EC_TYPE) & M_EC_TYPE)
+
+#define S_EC_GEN    10
+#define V_EC_GEN(x) ((x) << S_EC_GEN)
+#define F_EC_GEN    V_EC_GEN(1U)
+
+#define S_EC_UP_TOKEN    11
+#define M_EC_UP_TOKEN    0xFFFFF
+#define V_EC_UP_TOKEN(x) ((x) << S_EC_UP_TOKEN)
+#define G_EC_UP_TOKEN(x) (((x) >> S_EC_UP_TOKEN) & M_EC_UP_TOKEN)
+
+#define S_EC_VALID    31
+#define V_EC_VALID(x) ((x) << S_EC_VALID)
+#define F_EC_VALID    V_EC_VALID(1U)
+
+#define S_RQ_MSI_VEC    20
+#define M_RQ_MSI_VEC    0x3F
+#define V_RQ_MSI_VEC(x) ((x) << S_RQ_MSI_VEC)
+#define G_RQ_MSI_VEC(x) (((x) >> S_RQ_MSI_VEC) & M_RQ_MSI_VEC)
+
+#define S_RQ_INTR_EN    26
+#define V_RQ_INTR_EN(x) ((x) << S_RQ_INTR_EN)
+#define F_RQ_INTR_EN    V_RQ_INTR_EN(1U)
+
+#define S_RQ_GEN    28
+#define V_RQ_GEN(x) ((x) << S_RQ_GEN)
+#define F_RQ_GEN    V_RQ_GEN(1U)
+
+#define S_CQ_INDEX    0
+#define M_CQ_INDEX    0xFFFF
+#define V_CQ_INDEX(x) ((x) << S_CQ_INDEX)
+#define G_CQ_INDEX(x) (((x) >> S_CQ_INDEX) & M_CQ_INDEX)
+
+#define S_CQ_SIZE    16
+#define M_CQ_SIZE    0xFFFF
+#define V_CQ_SIZE(x) ((x) << S_CQ_SIZE)
+#define G_CQ_SIZE(x) (((x) >> S_CQ_SIZE) & M_CQ_SIZE)
+
+#define S_CQ_BASE_HI    0
+#define M_CQ_BASE_HI    0xFFFFF
+#define V_CQ_BASE_HI(x) ((x) << S_CQ_BASE_HI)
+#define G_CQ_BASE_HI(x) (((x) >> S_CQ_BASE_HI) & M_CQ_BASE_HI)
+
+#define S_CQ_RSPQ    20
+#define M_CQ_RSPQ    0x3F
+#define V_CQ_RSPQ(x) ((x) << S_CQ_RSPQ)
+#define G_CQ_RSPQ(x) (((x) >> S_CQ_RSPQ) & M_CQ_RSPQ)
+
+#define S_CQ_ASYNC_NOTIF    26
+#define V_CQ_ASYNC_NOTIF(x) ((x) << S_CQ_ASYNC_NOTIF)
+#define F_CQ_ASYNC_NOTIF    V_CQ_ASYNC_NOTIF(1U)
+
+#define S_CQ_ARMED    27
+#define V_CQ_ARMED(x) ((x) << S_CQ_ARMED)
+#define F_CQ_ARMED    V_CQ_ARMED(1U)
+
+#define S_CQ_ASYNC_NOTIF_SOL    28
+#define V_CQ_ASYNC_NOTIF_SOL(x) ((x) << S_CQ_ASYNC_NOTIF_SOL)
+#define F_CQ_ASYNC_NOTIF_SOL    V_CQ_ASYNC_NOTIF_SOL(1U)
+
+#define S_CQ_GEN    29
+#define V_CQ_GEN(x) ((x) << S_CQ_GEN)
+#define F_CQ_GEN    V_CQ_GEN(1U)
+
+#define S_CQ_OVERFLOW_MODE    31
+#define V_CQ_OVERFLOW_MODE(x) ((x) << S_CQ_OVERFLOW_MODE)
+#define F_CQ_OVERFLOW_MODE    V_CQ_OVERFLOW_MODE(1U)
+
+#define S_CQ_CREDITS    0
+#define M_CQ_CREDITS    0xFFFF
+#define V_CQ_CREDITS(x) ((x) << S_CQ_CREDITS)
+#define G_CQ_CREDITS(x) (((x) >> S_CQ_CREDITS) & M_CQ_CREDITS)
+
+#define S_CQ_CREDIT_THRES    16
+#define M_CQ_CREDIT_THRES    0x1FFF
+#define V_CQ_CREDIT_THRES(x) ((x) << S_CQ_CREDIT_THRES)
+#define G_CQ_CREDIT_THRES(x) (((x) >> S_CQ_CREDIT_THRES) & M_CQ_CREDIT_THRES)
+
+#define S_FL_BASE_HI    0
+#define M_FL_BASE_HI    0xFFFFF
+#define V_FL_BASE_HI(x) ((x) << S_FL_BASE_HI)
+#define G_FL_BASE_HI(x) (((x) >> S_FL_BASE_HI) & M_FL_BASE_HI)
+
+#define S_FL_INDEX_LO    20
+#define M_FL_INDEX_LO    0xFFF
+#define V_FL_INDEX_LO(x) ((x) << S_FL_INDEX_LO)
+#define G_FL_INDEX_LO(x) (((x) >> S_FL_INDEX_LO) & M_FL_INDEX_LO)
+
+#define S_FL_INDEX_HI    0
+#define M_FL_INDEX_HI    0xF
+#define V_FL_INDEX_HI(x) ((x) << S_FL_INDEX_HI)
+#define G_FL_INDEX_HI(x) (((x) >> S_FL_INDEX_HI) & M_FL_INDEX_HI)
+
+#define S_FL_SIZE    4
+#define M_FL_SIZE    0xFFFF
+#define V_FL_SIZE(x) ((x) << S_FL_SIZE)
+#define G_FL_SIZE(x) (((x) >> S_FL_SIZE) & M_FL_SIZE)
+
+#define S_FL_GEN    20
+#define V_FL_GEN(x) ((x) << S_FL_GEN)
+#define F_FL_GEN    V_FL_GEN(1U)
+
+#define S_FL_ENTRY_SIZE_LO    21
+#define M_FL_ENTRY_SIZE_LO    0x7FF
+#define V_FL_ENTRY_SIZE_LO(x) ((x) << S_FL_ENTRY_SIZE_LO)
+#define G_FL_ENTRY_SIZE_LO(x) (((x) >> S_FL_ENTRY_SIZE_LO) & M_FL_ENTRY_SIZE_LO)
+
+#define S_FL_ENTRY_SIZE_HI    0
+#define M_FL_ENTRY_SIZE_HI    0x1FFFFF
+#define V_FL_ENTRY_SIZE_HI(x) ((x) << S_FL_ENTRY_SIZE_HI)
+#define G_FL_ENTRY_SIZE_HI(x) (((x) >> S_FL_ENTRY_SIZE_HI) & M_FL_ENTRY_SIZE_HI)
+
+#define S_FL_CONG_THRES    21
+#define M_FL_CONG_THRES    0x3FF
+#define V_FL_CONG_THRES(x) ((x) << S_FL_CONG_THRES)
+#define G_FL_CONG_THRES(x) (((x) >> S_FL_CONG_THRES) & M_FL_CONG_THRES)
+
+#define S_FL_GTS    31
+#define V_FL_GTS(x) ((x) << S_FL_GTS)
+#define F_FL_GTS    V_FL_GTS(1U)
+
+#define S_FLD_GEN1    31
+#define V_FLD_GEN1(x) ((x) << S_FLD_GEN1)
+#define F_FLD_GEN1    V_FLD_GEN1(1U)
+
+#define S_FLD_GEN2    0
+#define V_FLD_GEN2(x) ((x) << S_FLD_GEN2)
+#define F_FLD_GEN2    V_FLD_GEN2(1U)
+
+#define S_RSPD_TXQ1_CR    0
+#define M_RSPD_TXQ1_CR    0x7F
+#define V_RSPD_TXQ1_CR(x) ((x) << S_RSPD_TXQ1_CR)
+#define G_RSPD_TXQ1_CR(x) (((x) >> S_RSPD_TXQ1_CR) & M_RSPD_TXQ1_CR)
+
+#define S_RSPD_TXQ1_GTS    7
+#define V_RSPD_TXQ1_GTS(x) ((x) << S_RSPD_TXQ1_GTS)
+#define F_RSPD_TXQ1_GTS    V_RSPD_TXQ1_GTS(1U)
+
+#define S_RSPD_TXQ2_CR    8
+#define M_RSPD_TXQ2_CR    0x7F
+#define V_RSPD_TXQ2_CR(x) ((x) << S_RSPD_TXQ2_CR)
+#define G_RSPD_TXQ2_CR(x) (((x) >> S_RSPD_TXQ2_CR) & M_RSPD_TXQ2_CR)
+
+#define S_RSPD_TXQ2_GTS    15
+#define V_RSPD_TXQ2_GTS(x) ((x) << S_RSPD_TXQ2_GTS)
+#define F_RSPD_TXQ2_GTS    V_RSPD_TXQ2_GTS(1U)
+
+#define S_RSPD_TXQ0_CR    16
+#define M_RSPD_TXQ0_CR    0x7F
+#define V_RSPD_TXQ0_CR(x) ((x) << S_RSPD_TXQ0_CR)
+#define G_RSPD_TXQ0_CR(x) (((x) >> S_RSPD_TXQ0_CR) & M_RSPD_TXQ0_CR)
+
+#define S_RSPD_TXQ0_GTS    23
+#define V_RSPD_TXQ0_GTS(x) ((x) << S_RSPD_TXQ0_GTS)
+#define F_RSPD_TXQ0_GTS    V_RSPD_TXQ0_GTS(1U)
+
+#define S_RSPD_EOP    24
+#define V_RSPD_EOP(x) ((x) << S_RSPD_EOP)
+#define F_RSPD_EOP    V_RSPD_EOP(1U)
+
+#define S_RSPD_SOP    25
+#define V_RSPD_SOP(x) ((x) << S_RSPD_SOP)
+#define F_RSPD_SOP    V_RSPD_SOP(1U)
+
+#define S_RSPD_ASYNC_NOTIF    26
+#define V_RSPD_ASYNC_NOTIF(x) ((x) << S_RSPD_ASYNC_NOTIF)
+#define F_RSPD_ASYNC_NOTIF    V_RSPD_ASYNC_NOTIF(1U)
+
+#define S_RSPD_FL0_GTS    27
+#define V_RSPD_FL0_GTS(x) ((x) << S_RSPD_FL0_GTS)
+#define F_RSPD_FL0_GTS    V_RSPD_FL0_GTS(1U)
+
+#define S_RSPD_FL1_GTS    28
+#define V_RSPD_FL1_GTS(x) ((x) << S_RSPD_FL1_GTS)
+#define F_RSPD_FL1_GTS    V_RSPD_FL1_GTS(1U)
+
+#define S_RSPD_IMM_DATA_VALID    29
+#define V_RSPD_IMM_DATA_VALID(x) ((x) << S_RSPD_IMM_DATA_VALID)
+#define F_RSPD_IMM_DATA_VALID    V_RSPD_IMM_DATA_VALID(1U)
+
+#define S_RSPD_OFFLOAD    30
+#define V_RSPD_OFFLOAD(x) ((x) << S_RSPD_OFFLOAD)
+#define F_RSPD_OFFLOAD    V_RSPD_OFFLOAD(1U)
+
+#define S_RSPD_GEN1    31
+#define V_RSPD_GEN1(x) ((x) << S_RSPD_GEN1)
+#define F_RSPD_GEN1    V_RSPD_GEN1(1U)
+
+#define S_RSPD_LEN    0
+#define M_RSPD_LEN    0x7FFFFFFF
+#define V_RSPD_LEN(x) ((x) << S_RSPD_LEN)
+#define G_RSPD_LEN(x) (((x) >> S_RSPD_LEN) & M_RSPD_LEN)
+
+#define S_RSPD_FLQ    31
+#define V_RSPD_FLQ(x) ((x) << S_RSPD_FLQ)
+#define F_RSPD_FLQ    V_RSPD_FLQ(1U)
+
+#define S_RSPD_GEN2    0
+#define V_RSPD_GEN2(x) ((x) << S_RSPD_GEN2)
+#define F_RSPD_GEN2    V_RSPD_GEN2(1U)
+
+#define S_RSPD_INR_VEC    1
+#define M_RSPD_INR_VEC    0x7F
+#define V_RSPD_INR_VEC(x) ((x) << S_RSPD_INR_VEC)
+#define G_RSPD_INR_VEC(x) (((x) >> S_RSPD_INR_VEC) & M_RSPD_INR_VEC)
+
+#endif				/* _SGE_DEFS_H */
diff --git a/drivers/net/cxgb3/t3_cpl.h b/drivers/net/cxgb3/t3_cpl.h
new file mode 100644
index 0000000..b7a1a31
--- /dev/null
+++ b/drivers/net/cxgb3/t3_cpl.h
@@ -0,0 +1,1444 @@
+/*
+ * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef T3_CPL_H
+#define T3_CPL_H
+
+#if !defined(__LITTLE_ENDIAN_BITFIELD) && !defined(__BIG_ENDIAN_BITFIELD)
+# include <asm/byteorder.h>
+#endif
+
+enum CPL_opcode {
+	CPL_PASS_OPEN_REQ = 0x1,
+	CPL_PASS_ACCEPT_RPL = 0x2,
+	CPL_ACT_OPEN_REQ = 0x3,
+	CPL_SET_TCB = 0x4,
+	CPL_SET_TCB_FIELD = 0x5,
+	CPL_GET_TCB = 0x6,
+	CPL_PCMD = 0x7,
+	CPL_CLOSE_CON_REQ = 0x8,
+	CPL_CLOSE_LISTSRV_REQ = 0x9,
+	CPL_ABORT_REQ = 0xA,
+	CPL_ABORT_RPL = 0xB,
+	CPL_TX_DATA = 0xC,
+	CPL_RX_DATA_ACK = 0xD,
+	CPL_TX_PKT = 0xE,
+	CPL_RTE_DELETE_REQ = 0xF,
+	CPL_RTE_WRITE_REQ = 0x10,
+	CPL_RTE_READ_REQ = 0x11,
+	CPL_L2T_WRITE_REQ = 0x12,
+	CPL_L2T_READ_REQ = 0x13,
+	CPL_SMT_WRITE_REQ = 0x14,
+	CPL_SMT_READ_REQ = 0x15,
+	CPL_TX_PKT_LSO = 0x16,
+	CPL_PCMD_READ = 0x17,
+	CPL_BARRIER = 0x18,
+	CPL_TID_RELEASE = 0x1A,
+
+	CPL_CLOSE_LISTSRV_RPL = 0x20,
+	CPL_ERROR = 0x21,
+	CPL_GET_TCB_RPL = 0x22,
+	CPL_L2T_WRITE_RPL = 0x23,
+	CPL_PCMD_READ_RPL = 0x24,
+	CPL_PCMD_RPL = 0x25,
+	CPL_PEER_CLOSE = 0x26,
+	CPL_RTE_DELETE_RPL = 0x27,
+	CPL_RTE_WRITE_RPL = 0x28,
+	CPL_RX_DDP_COMPLETE = 0x29,
+	CPL_RX_PHYS_ADDR = 0x2A,
+	CPL_RX_PKT = 0x2B,
+	CPL_RX_URG_NOTIFY = 0x2C,
+	CPL_SET_TCB_RPL = 0x2D,
+	CPL_SMT_WRITE_RPL = 0x2E,
+	CPL_TX_DATA_ACK = 0x2F,
+
+	CPL_ABORT_REQ_RSS = 0x30,
+	CPL_ABORT_RPL_RSS = 0x31,
+	CPL_CLOSE_CON_RPL = 0x32,
+	CPL_ISCSI_HDR = 0x33,
+	CPL_L2T_READ_RPL = 0x34,
+	CPL_RDMA_CQE = 0x35,
+	CPL_RDMA_CQE_READ_RSP = 0x36,
+	CPL_RDMA_CQE_ERR = 0x37,
+	CPL_RTE_READ_RPL = 0x38,
+	CPL_RX_DATA = 0x39,
+
+	CPL_ACT_OPEN_RPL = 0x40,
+	CPL_PASS_OPEN_RPL = 0x41,
+	CPL_RX_DATA_DDP = 0x42,
+	CPL_SMT_READ_RPL = 0x43,
+
+	CPL_ACT_ESTABLISH = 0x50,
+	CPL_PASS_ESTABLISH = 0x51,
+
+	CPL_PASS_ACCEPT_REQ = 0x70,
+
+	CPL_ASYNC_NOTIF = 0x80,	/* fake opcode for async notifications */
+
+	CPL_TX_DMA_ACK = 0xA0,
+	CPL_RDMA_READ_REQ = 0xA1,
+	CPL_RDMA_TERMINATE = 0xA2,
+	CPL_TRACE_PKT = 0xA3,
+	CPL_RDMA_EC_STATUS = 0xA5,
+
+	NUM_CPL_CMDS		/* must be last and previous entries must be sorted */
+};
+
+enum CPL_error {
+	CPL_ERR_NONE = 0,
+	CPL_ERR_TCAM_PARITY = 1,
+	CPL_ERR_TCAM_FULL = 3,
+	CPL_ERR_CONN_RESET = 20,
+	CPL_ERR_CONN_EXIST = 22,
+	CPL_ERR_ARP_MISS = 23,
+	CPL_ERR_BAD_SYN = 24,
+	CPL_ERR_CONN_TIMEDOUT = 30,
+	CPL_ERR_XMIT_TIMEDOUT = 31,
+	CPL_ERR_PERSIST_TIMEDOUT = 32,
+	CPL_ERR_FINWAIT2_TIMEDOUT = 33,
+	CPL_ERR_KEEPALIVE_TIMEDOUT = 34,
+	CPL_ERR_RTX_NEG_ADVICE = 35,
+	CPL_ERR_PERSIST_NEG_ADVICE = 36,
+	CPL_ERR_ABORT_FAILED = 42,
+	CPL_ERR_GENERAL = 99
+};
+
+enum {
+	CPL_CONN_POLICY_AUTO = 0,
+	CPL_CONN_POLICY_ASK = 1,
+	CPL_CONN_POLICY_DENY = 3
+};
+
+enum {
+	ULP_MODE_NONE = 0,
+	ULP_MODE_ISCSI = 2,
+	ULP_MODE_RDMA = 4,
+	ULP_MODE_TCPDDP = 5
+};
+
+enum {
+	ULP_CRC_HEADER = 1 << 0,
+	ULP_CRC_DATA = 1 << 1
+};
+
+enum {
+	CPL_PASS_OPEN_ACCEPT,
+	CPL_PASS_OPEN_REJECT
+};
+
+enum {
+	CPL_ABORT_SEND_RST = 0,
+	CPL_ABORT_NO_RST,
+	CPL_ABORT_POST_CLOSE_REQ = 2
+};
+
+enum {				/* TX_PKT_LSO ethernet types */
+	CPL_ETH_II,
+	CPL_ETH_II_VLAN,
+	CPL_ETH_802_3,
+	CPL_ETH_802_3_VLAN
+};
+
+enum {				/* TCP congestion control algorithms */
+	CONG_ALG_RENO,
+	CONG_ALG_TAHOE,
+	CONG_ALG_NEWRENO,
+	CONG_ALG_HIGHSPEED
+};
+
+union opcode_tid {
+	__be32 opcode_tid;
+	__u8 opcode;
+};
+
+#define S_OPCODE 24
+#define V_OPCODE(x) ((x) << S_OPCODE)
+#define G_OPCODE(x) (((x) >> S_OPCODE) & 0xFF)
+#define G_TID(x)    ((x) & 0xFFFFFF)
+
+/* tid is assumed to be 24-bits */
+#define MK_OPCODE_TID(opcode, tid) (V_OPCODE(opcode) | (tid))
+
+#define OPCODE_TID(cmd) ((cmd)->ot.opcode_tid)
+
+/* extract the TID from a CPL command */
+#define GET_TID(cmd) (G_TID(ntohl(OPCODE_TID(cmd))))
+
+struct tcp_options {
+	__be16 mss;
+	__u8 wsf;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	 __u8:5;
+	__u8 ecn:1;
+	__u8 sack:1;
+	__u8 tstamp:1;
+#else
+	__u8 tstamp:1;
+	__u8 sack:1;
+	__u8 ecn:1;
+	 __u8:5;
+#endif
+};
+
+struct rss_header {
+	__u8 opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8 cpu_idx:6;
+	__u8 hash_type:2;
+#else
+	__u8 hash_type:2;
+	__u8 cpu_idx:6;
+#endif
+	__be16 cq_idx;
+	__be32 rss_hash_val;
+};
+
+#ifndef CHELSIO_FW
+struct work_request_hdr {
+	__be32 wr_hi;
+	__be32 wr_lo;
+};
+
+/* wr_hi fields */
+#define S_WR_SGE_CREDITS    0
+#define M_WR_SGE_CREDITS    0xFF
+#define V_WR_SGE_CREDITS(x) ((x) << S_WR_SGE_CREDITS)
+#define G_WR_SGE_CREDITS(x) (((x) >> S_WR_SGE_CREDITS) & M_WR_SGE_CREDITS)
+
+#define S_WR_SGLSFLT    8
+#define M_WR_SGLSFLT    0xFF
+#define V_WR_SGLSFLT(x) ((x) << S_WR_SGLSFLT)
+#define G_WR_SGLSFLT(x) (((x) >> S_WR_SGLSFLT) & M_WR_SGLSFLT)
+
+#define S_WR_BCNTLFLT    16
+#define M_WR_BCNTLFLT    0xF
+#define V_WR_BCNTLFLT(x) ((x) << S_WR_BCNTLFLT)
+#define G_WR_BCNTLFLT(x) (((x) >> S_WR_BCNTLFLT) & M_WR_BCNTLFLT)
+
+#define S_WR_DATATYPE    20
+#define V_WR_DATATYPE(x) ((x) << S_WR_DATATYPE)
+#define F_WR_DATATYPE    V_WR_DATATYPE(1U)
+
+#define S_WR_COMPL    21
+#define V_WR_COMPL(x) ((x) << S_WR_COMPL)
+#define F_WR_COMPL    V_WR_COMPL(1U)
+
+#define S_WR_EOP    22
+#define V_WR_EOP(x) ((x) << S_WR_EOP)
+#define F_WR_EOP    V_WR_EOP(1U)
+
+#define S_WR_SOP    23
+#define V_WR_SOP(x) ((x) << S_WR_SOP)
+#define F_WR_SOP    V_WR_SOP(1U)
+
+#define S_WR_OP    24
+#define M_WR_OP    0xFF
+#define V_WR_OP(x) ((x) << S_WR_OP)
+#define G_WR_OP(x) (((x) >> S_WR_OP) & M_WR_OP)
+
+/* wr_lo fields */
+#define S_WR_LEN    0
+#define M_WR_LEN    0xFF
+#define V_WR_LEN(x) ((x) << S_WR_LEN)
+#define G_WR_LEN(x) (((x) >> S_WR_LEN) & M_WR_LEN)
+
+#define S_WR_TID    8
+#define M_WR_TID    0xFFFFF
+#define V_WR_TID(x) ((x) << S_WR_TID)
+#define G_WR_TID(x) (((x) >> S_WR_TID) & M_WR_TID)
+
+#define S_WR_CR_FLUSH    30
+#define V_WR_CR_FLUSH(x) ((x) << S_WR_CR_FLUSH)
+#define F_WR_CR_FLUSH    V_WR_CR_FLUSH(1U)
+
+#define S_WR_GEN    31
+#define V_WR_GEN(x) ((x) << S_WR_GEN)
+#define F_WR_GEN    V_WR_GEN(1U)
+
+# define WR_HDR struct work_request_hdr wr
+# define RSS_HDR
+#else
+# define WR_HDR
+# define RSS_HDR struct rss_header rss_hdr;
+#endif
+
+/* option 0 lower-half fields */
+#define S_CPL_STATUS    0
+#define M_CPL_STATUS    0xFF
+#define V_CPL_STATUS(x) ((x) << S_CPL_STATUS)
+#define G_CPL_STATUS(x) (((x) >> S_CPL_STATUS) & M_CPL_STATUS)
+
+#define S_INJECT_TIMER    6
+#define V_INJECT_TIMER(x) ((x) << S_INJECT_TIMER)
+#define F_INJECT_TIMER    V_INJECT_TIMER(1U)
+
+#define S_NO_OFFLOAD    7
+#define V_NO_OFFLOAD(x) ((x) << S_NO_OFFLOAD)
+#define F_NO_OFFLOAD    V_NO_OFFLOAD(1U)
+
+#define S_ULP_MODE    8
+#define M_ULP_MODE    0xF
+#define V_ULP_MODE(x) ((x) << S_ULP_MODE)
+#define G_ULP_MODE(x) (((x) >> S_ULP_MODE) & M_ULP_MODE)
+
+#define S_RCV_BUFSIZ    12
+#define M_RCV_BUFSIZ    0x3FFF
+#define V_RCV_BUFSIZ(x) ((x) << S_RCV_BUFSIZ)
+#define G_RCV_BUFSIZ(x) (((x) >> S_RCV_BUFSIZ) & M_RCV_BUFSIZ)
+
+#define S_TOS    26
+#define M_TOS    0x3F
+#define V_TOS(x) ((x) << S_TOS)
+#define G_TOS(x) (((x) >> S_TOS) & M_TOS)
+
+/* option 0 upper-half fields */
+#define S_DELACK    0
+#define V_DELACK(x) ((x) << S_DELACK)
+#define F_DELACK    V_DELACK(1U)
+
+#define S_NO_CONG    1
+#define V_NO_CONG(x) ((x) << S_NO_CONG)
+#define F_NO_CONG    V_NO_CONG(1U)
+
+#define S_SRC_MAC_SEL    2
+#define M_SRC_MAC_SEL    0x3
+#define V_SRC_MAC_SEL(x) ((x) << S_SRC_MAC_SEL)
+#define G_SRC_MAC_SEL(x) (((x) >> S_SRC_MAC_SEL) & M_SRC_MAC_SEL)
+
+#define S_L2T_IDX    4
+#define M_L2T_IDX    0x7FF
+#define V_L2T_IDX(x) ((x) << S_L2T_IDX)
+#define G_L2T_IDX(x) (((x) >> S_L2T_IDX) & M_L2T_IDX)
+
+#define S_TX_CHANNEL    15
+#define V_TX_CHANNEL(x) ((x) << S_TX_CHANNEL)
+#define F_TX_CHANNEL    V_TX_CHANNEL(1U)
+
+#define S_TCAM_BYPASS    16
+#define V_TCAM_BYPASS(x) ((x) << S_TCAM_BYPASS)
+#define F_TCAM_BYPASS    V_TCAM_BYPASS(1U)
+
+#define S_NAGLE    17
+#define V_NAGLE(x) ((x) << S_NAGLE)
+#define F_NAGLE    V_NAGLE(1U)
+
+#define S_WND_SCALE    18
+#define M_WND_SCALE    0xF
+#define V_WND_SCALE(x) ((x) << S_WND_SCALE)
+#define G_WND_SCALE(x) (((x) >> S_WND_SCALE) & M_WND_SCALE)
+
+#define S_KEEP_ALIVE    22
+#define V_KEEP_ALIVE(x) ((x) << S_KEEP_ALIVE)
+#define F_KEEP_ALIVE    V_KEEP_ALIVE(1U)
+
+#define S_MAX_RETRANS    23
+#define M_MAX_RETRANS    0xF
+#define V_MAX_RETRANS(x) ((x) << S_MAX_RETRANS)
+#define G_MAX_RETRANS(x) (((x) >> S_MAX_RETRANS) & M_MAX_RETRANS)
+
+#define S_MAX_RETRANS_OVERRIDE    27
+#define V_MAX_RETRANS_OVERRIDE(x) ((x) << S_MAX_RETRANS_OVERRIDE)
+#define F_MAX_RETRANS_OVERRIDE    V_MAX_RETRANS_OVERRIDE(1U)
+
+#define S_MSS_IDX    28
+#define M_MSS_IDX    0xF
+#define V_MSS_IDX(x) ((x) << S_MSS_IDX)
+#define G_MSS_IDX(x) (((x) >> S_MSS_IDX) & M_MSS_IDX)
+
+/* option 1 fields */
+#define S_RSS_ENABLE    0
+#define V_RSS_ENABLE(x) ((x) << S_RSS_ENABLE)
+#define F_RSS_ENABLE    V_RSS_ENABLE(1U)
+
+#define S_RSS_MASK_LEN    1
+#define M_RSS_MASK_LEN    0x7
+#define V_RSS_MASK_LEN(x) ((x) << S_RSS_MASK_LEN)
+#define G_RSS_MASK_LEN(x) (((x) >> S_RSS_MASK_LEN) & M_RSS_MASK_LEN)
+
+#define S_CPU_IDX    4
+#define M_CPU_IDX    0x3F
+#define V_CPU_IDX(x) ((x) << S_CPU_IDX)
+#define G_CPU_IDX(x) (((x) >> S_CPU_IDX) & M_CPU_IDX)
+
+#define S_MAC_MATCH_VALID    18
+#define V_MAC_MATCH_VALID(x) ((x) << S_MAC_MATCH_VALID)
+#define F_MAC_MATCH_VALID    V_MAC_MATCH_VALID(1U)
+
+#define S_CONN_POLICY    19
+#define M_CONN_POLICY    0x3
+#define V_CONN_POLICY(x) ((x) << S_CONN_POLICY)
+#define G_CONN_POLICY(x) (((x) >> S_CONN_POLICY) & M_CONN_POLICY)
+
+#define S_SYN_DEFENSE    21
+#define V_SYN_DEFENSE(x) ((x) << S_SYN_DEFENSE)
+#define F_SYN_DEFENSE    V_SYN_DEFENSE(1U)
+
+#define S_VLAN_PRI    22
+#define M_VLAN_PRI    0x3
+#define V_VLAN_PRI(x) ((x) << S_VLAN_PRI)
+#define G_VLAN_PRI(x) (((x) >> S_VLAN_PRI) & M_VLAN_PRI)
+
+#define S_VLAN_PRI_VALID    24
+#define V_VLAN_PRI_VALID(x) ((x) << S_VLAN_PRI_VALID)
+#define F_VLAN_PRI_VALID    V_VLAN_PRI_VALID(1U)
+
+#define S_PKT_TYPE    25
+#define M_PKT_TYPE    0x3
+#define V_PKT_TYPE(x) ((x) << S_PKT_TYPE)
+#define G_PKT_TYPE(x) (((x) >> S_PKT_TYPE) & M_PKT_TYPE)
+
+#define S_MAC_MATCH    27
+#define M_MAC_MATCH    0x1F
+#define V_MAC_MATCH(x) ((x) << S_MAC_MATCH)
+#define G_MAC_MATCH(x) (((x) >> S_MAC_MATCH) & M_MAC_MATCH)
+
+/* option 2 fields */
+#define S_CPU_INDEX    0
+#define M_CPU_INDEX    0x7F
+#define V_CPU_INDEX(x) ((x) << S_CPU_INDEX)
+#define G_CPU_INDEX(x) (((x) >> S_CPU_INDEX) & M_CPU_INDEX)
+
+#define S_CPU_INDEX_VALID    7
+#define V_CPU_INDEX_VALID(x) ((x) << S_CPU_INDEX_VALID)
+#define F_CPU_INDEX_VALID    V_CPU_INDEX_VALID(1U)
+
+#define S_RX_COALESCE    8
+#define M_RX_COALESCE    0x3
+#define V_RX_COALESCE(x) ((x) << S_RX_COALESCE)
+#define G_RX_COALESCE(x) (((x) >> S_RX_COALESCE) & M_RX_COALESCE)
+
+#define S_RX_COALESCE_VALID    10
+#define V_RX_COALESCE_VALID(x) ((x) << S_RX_COALESCE_VALID)
+#define F_RX_COALESCE_VALID    V_RX_COALESCE_VALID(1U)
+
+#define S_CONG_CONTROL_FLAVOR    11
+#define M_CONG_CONTROL_FLAVOR    0x3
+#define V_CONG_CONTROL_FLAVOR(x) ((x) << S_CONG_CONTROL_FLAVOR)
+#define G_CONG_CONTROL_FLAVOR(x) (((x) >> S_CONG_CONTROL_FLAVOR) & M_CONG_CONTROL_FLAVOR)
+
+#define S_PACING_FLAVOR    13
+#define M_PACING_FLAVOR    0x3
+#define V_PACING_FLAVOR(x) ((x) << S_PACING_FLAVOR)
+#define G_PACING_FLAVOR(x) (((x) >> S_PACING_FLAVOR) & M_PACING_FLAVOR)
+
+#define S_FLAVORS_VALID    15
+#define V_FLAVORS_VALID(x) ((x) << S_FLAVORS_VALID)
+#define F_FLAVORS_VALID    V_FLAVORS_VALID(1U)
+
+#define S_RX_FC_DISABLE    16
+#define V_RX_FC_DISABLE(x) ((x) << S_RX_FC_DISABLE)
+#define F_RX_FC_DISABLE    V_RX_FC_DISABLE(1U)
+
+#define S_RX_FC_VALID    17
+#define V_RX_FC_VALID(x) ((x) << S_RX_FC_VALID)
+#define F_RX_FC_VALID    V_RX_FC_VALID(1U)
+
+struct cpl_pass_open_req {
+	WR_HDR;
+	union opcode_tid ot;
+	__be16 local_port;
+	__be16 peer_port;
+	__be32 local_ip;
+	__be32 peer_ip;
+	__be32 opt0h;
+	__be32 opt0l;
+	__be32 peer_netmask;
+	__be32 opt1;
+};
+
+struct cpl_pass_open_rpl {
+	RSS_HDR union opcode_tid ot;
+	__be16 local_port;
+	__be16 peer_port;
+	__be32 local_ip;
+	__be32 peer_ip;
+	__u8 resvd[7];
+	__u8 status;
+};
+
+struct cpl_pass_establish {
+	RSS_HDR union opcode_tid ot;
+	__be16 local_port;
+	__be16 peer_port;
+	__be32 local_ip;
+	__be32 peer_ip;
+	__be32 tos_tid;
+	__be16 l2t_idx;
+	__be16 tcp_opt;
+	__be32 snd_isn;
+	__be32 rcv_isn;
+};
+
+/* cpl_pass_establish.tos_tid fields */
+#define S_PASS_OPEN_TID    0
+#define M_PASS_OPEN_TID    0xFFFFFF
+#define V_PASS_OPEN_TID(x) ((x) << S_PASS_OPEN_TID)
+#define G_PASS_OPEN_TID(x) (((x) >> S_PASS_OPEN_TID) & M_PASS_OPEN_TID)
+
+#define S_PASS_OPEN_TOS    24
+#define M_PASS_OPEN_TOS    0xFF
+#define V_PASS_OPEN_TOS(x) ((x) << S_PASS_OPEN_TOS)
+#define G_PASS_OPEN_TOS(x) (((x) >> S_PASS_OPEN_TOS) & M_PASS_OPEN_TOS)
+
+/* cpl_pass_establish.l2t_idx fields */
+#define S_L2T_IDX16    5
+#define M_L2T_IDX16    0x7FF
+#define V_L2T_IDX16(x) ((x) << S_L2T_IDX16)
+#define G_L2T_IDX16(x) (((x) >> S_L2T_IDX16) & M_L2T_IDX16)
+
+/* cpl_pass_establish.tcp_opt fields (also applies act_open_establish) */
+#define G_TCPOPT_WSCALE_OK(x)  (((x) >> 5) & 1)
+#define G_TCPOPT_SACK(x)       (((x) >> 6) & 1)
+#define G_TCPOPT_TSTAMP(x)     (((x) >> 7) & 1)
+#define G_TCPOPT_SND_WSCALE(x) (((x) >> 8) & 0xf)
+#define G_TCPOPT_MSS(x)        (((x) >> 12) & 0xf)
+
+struct cpl_pass_accept_req {
+	RSS_HDR union opcode_tid ot;
+	__be16 local_port;
+	__be16 peer_port;
+	__be32 local_ip;
+	__be32 peer_ip;
+	__be32 tos_tid;
+	struct tcp_options tcp_options;
+	__u8 dst_mac[6];
+	__be16 vlan_tag;
+	__u8 src_mac[6];
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	 __u8:3;
+	__u8 addr_idx:3;
+	__u8 port_idx:1;
+	__u8 exact_match:1;
+#else
+	__u8 exact_match:1;
+	__u8 port_idx:1;
+	__u8 addr_idx:3;
+	 __u8:3;
+#endif
+	__u8 rsvd;
+	__be32 rcv_isn;
+	__be32 rsvd2;
+};
+
+struct cpl_pass_accept_rpl {
+	WR_HDR;
+	union opcode_tid ot;
+	__be32 opt2;
+	__be32 rsvd;
+	__be32 peer_ip;
+	__be32 opt0h;
+	__be32 opt0l_status;
+};
+
+struct cpl_act_open_req {
+	WR_HDR;
+	union opcode_tid ot;
+	__be16 local_port;
+	__be16 peer_port;
+	__be32 local_ip;
+	__be32 peer_ip;
+	__be32 opt0h;
+	__be32 opt0l;
+	__be32 params;
+	__be32 opt2;
+};
+
+/* cpl_act_open_req.params fields */
+#define S_AOPEN_VLAN_PRI    9
+#define M_AOPEN_VLAN_PRI    0x3
+#define V_AOPEN_VLAN_PRI(x) ((x) << S_AOPEN_VLAN_PRI)
+#define G_AOPEN_VLAN_PRI(x) (((x) >> S_AOPEN_VLAN_PRI) & M_AOPEN_VLAN_PRI)
+
+#define S_AOPEN_VLAN_PRI_VALID    11
+#define V_AOPEN_VLAN_PRI_VALID(x) ((x) << S_AOPEN_VLAN_PRI_VALID)
+#define F_AOPEN_VLAN_PRI_VALID    V_AOPEN_VLAN_PRI_VALID(1U)
+
+#define S_AOPEN_PKT_TYPE    12
+#define M_AOPEN_PKT_TYPE    0x3
+#define V_AOPEN_PKT_TYPE(x) ((x) << S_AOPEN_PKT_TYPE)
+#define G_AOPEN_PKT_TYPE(x) (((x) >> S_AOPEN_PKT_TYPE) & M_AOPEN_PKT_TYPE)
+
+#define S_AOPEN_MAC_MATCH    14
+#define M_AOPEN_MAC_MATCH    0x1F
+#define V_AOPEN_MAC_MATCH(x) ((x) << S_AOPEN_MAC_MATCH)
+#define G_AOPEN_MAC_MATCH(x) (((x) >> S_AOPEN_MAC_MATCH) & M_AOPEN_MAC_MATCH)
+
+#define S_AOPEN_MAC_MATCH_VALID    19
+#define V_AOPEN_MAC_MATCH_VALID(x) ((x) << S_AOPEN_MAC_MATCH_VALID)
+#define F_AOPEN_MAC_MATCH_VALID    V_AOPEN_MAC_MATCH_VALID(1U)
+
+#define S_AOPEN_IFF_VLAN    20
+#define M_AOPEN_IFF_VLAN    0xFFF
+#define V_AOPEN_IFF_VLAN(x) ((x) << S_AOPEN_IFF_VLAN)
+#define G_AOPEN_IFF_VLAN(x) (((x) >> S_AOPEN_IFF_VLAN) & M_AOPEN_IFF_VLAN)
+
+struct cpl_act_open_rpl {
+	RSS_HDR union opcode_tid ot;
+	__be16 local_port;
+	__be16 peer_port;
+	__be32 local_ip;
+	__be32 peer_ip;
+	__be32 atid;
+	__u8 rsvd[3];
+	__u8 status;
+};
+
+struct cpl_act_establish {
+	RSS_HDR union opcode_tid ot;
+	__be16 local_port;
+	__be16 peer_port;
+	__be32 local_ip;
+	__be32 peer_ip;
+	__be32 tos_tid;
+	__be16 l2t_idx;
+	__be16 tcp_opt;
+	__be32 snd_isn;
+	__be32 rcv_isn;
+};
+
+struct cpl_get_tcb {
+	WR_HDR;
+	union opcode_tid ot;
+	__be16 cpuno;
+	__be16 rsvd;
+};
+
+struct cpl_get_tcb_rpl {
+	RSS_HDR union opcode_tid ot;
+	__u8 rsvd;
+	__u8 status;
+	__be16 len;
+};
+
+struct cpl_set_tcb {
+	WR_HDR;
+	union opcode_tid ot;
+	__u8 reply;
+	__u8 cpu_idx;
+	__be16 len;
+};
+
+/* cpl_set_tcb.reply fields */
+#define S_NO_REPLY    7
+#define V_NO_REPLY(x) ((x) << S_NO_REPLY)
+#define F_NO_REPLY    V_NO_REPLY(1U)
+
+struct cpl_set_tcb_field {
+	WR_HDR;
+	union opcode_tid ot;
+	__u8 reply;
+	__u8 cpu_idx;
+	__be16 word;
+	__be64 mask;
+	__be64 val;
+};
+
+struct cpl_set_tcb_rpl {
+	RSS_HDR union opcode_tid ot;
+	__u8 rsvd[3];
+	__u8 status;
+};
+
+struct cpl_pcmd {
+	WR_HDR;
+	union opcode_tid ot;
+	__u8 rsvd[3];
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8 src:1;
+	__u8 bundle:1;
+	__u8 channel:1;
+	 __u8:5;
+#else
+	 __u8:5;
+	__u8 channel:1;
+	__u8 bundle:1;
+	__u8 src:1;
+#endif
+	__be32 pcmd_parm[2];
+};
+
+struct cpl_pcmd_reply {
+	RSS_HDR union opcode_tid ot;
+	__u8 status;
+	__u8 rsvd;
+	__be16 len;
+};
+
+struct cpl_close_con_req {
+	WR_HDR;
+	union opcode_tid ot;
+	__be32 rsvd;
+};
+
+struct cpl_close_con_rpl {
+	RSS_HDR union opcode_tid ot;
+	__u8 rsvd[3];
+	__u8 status;
+	__be32 snd_nxt;
+	__be32 rcv_nxt;
+};
+
+struct cpl_close_listserv_req {
+	WR_HDR;
+	union opcode_tid ot;
+	__u8 rsvd0;
+	__u8 cpu_idx;
+	__be16 rsvd1;
+};
+
+struct cpl_close_listserv_rpl {
+	RSS_HDR union opcode_tid ot;
+	__u8 rsvd[3];
+	__u8 status;
+};
+
+struct cpl_abort_req_rss {
+	RSS_HDR union opcode_tid ot;
+	__be32 rsvd0;
+	__u8 rsvd1;
+	__u8 status;
+	__u8 rsvd2[6];
+};
+
+struct cpl_abort_req {
+	WR_HDR;
+	union opcode_tid ot;
+	__be32 rsvd0;
+	__u8 rsvd1;
+	__u8 cmd;
+	__u8 rsvd2[6];
+};
+
+struct cpl_abort_rpl_rss {
+	RSS_HDR union opcode_tid ot;
+	__be32 rsvd0;
+	__u8 rsvd1;
+	__u8 status;
+	__u8 rsvd2[6];
+};
+
+struct cpl_abort_rpl {
+	WR_HDR;
+	union opcode_tid ot;
+	__be32 rsvd0;
+	__u8 rsvd1;
+	__u8 cmd;
+	__u8 rsvd2[6];
+};
+
+struct cpl_peer_close {
+	RSS_HDR union opcode_tid ot;
+	__be32 rcv_nxt;
+};
+
+struct tx_data_wr {
+	__be32 wr_hi;
+	__be32 wr_lo;
+	__be32 len;
+	__be32 flags;
+	__be32 sndseq;
+	__be32 param;
+};
+
+/* tx_data_wr.param fields */
+#define S_TX_PORT    0
+#define M_TX_PORT    0x7
+#define V_TX_PORT(x) ((x) << S_TX_PORT)
+#define G_TX_PORT(x) (((x) >> S_TX_PORT) & M_TX_PORT)
+
+#define S_TX_MSS    4
+#define M_TX_MSS    0xF
+#define V_TX_MSS(x) ((x) << S_TX_MSS)
+#define G_TX_MSS(x) (((x) >> S_TX_MSS) & M_TX_MSS)
+
+#define S_TX_QOS    8
+#define M_TX_QOS    0xFF
+#define V_TX_QOS(x) ((x) << S_TX_QOS)
+#define G_TX_QOS(x) (((x) >> S_TX_QOS) & M_TX_QOS)
+
+#define S_TX_SNDBUF 16
+#define M_TX_SNDBUF 0xFFFF
+#define V_TX_SNDBUF(x) ((x) << S_TX_SNDBUF)
+#define G_TX_SNDBUF(x) (((x) >> S_TX_SNDBUF) & M_TX_SNDBUF)
+
+struct cpl_tx_data {
+	union opcode_tid ot;
+	__be32 len;
+	__be32 rsvd;
+	__be16 urg;
+	__be16 flags;
+};
+
+/* cpl_tx_data.flags fields */
+#define S_TX_ULP_SUBMODE    6
+#define M_TX_ULP_SUBMODE    0xF
+#define V_TX_ULP_SUBMODE(x) ((x) << S_TX_ULP_SUBMODE)
+#define G_TX_ULP_SUBMODE(x) (((x) >> S_TX_ULP_SUBMODE) & M_TX_ULP_SUBMODE)
+
+#define S_TX_ULP_MODE    10
+#define M_TX_ULP_MODE    0xF
+#define V_TX_ULP_MODE(x) ((x) << S_TX_ULP_MODE)
+#define G_TX_ULP_MODE(x) (((x) >> S_TX_ULP_MODE) & M_TX_ULP_MODE)
+
+#define S_TX_SHOVE    14
+#define V_TX_SHOVE(x) ((x) << S_TX_SHOVE)
+#define F_TX_SHOVE    V_TX_SHOVE(1U)
+
+#define S_TX_MORE    15
+#define V_TX_MORE(x) ((x) << S_TX_MORE)
+#define F_TX_MORE    V_TX_MORE(1U)
+
+/* additional tx_data_wr.flags fields */
+#define S_TX_CPU_IDX    0
+#define M_TX_CPU_IDX    0x3F
+#define V_TX_CPU_IDX(x) ((x) << S_TX_CPU_IDX)
+#define G_TX_CPU_IDX(x) (((x) >> S_TX_CPU_IDX) & M_TX_CPU_IDX)
+
+#define S_TX_URG    16
+#define V_TX_URG(x) ((x) << S_TX_URG)
+#define F_TX_URG    V_TX_URG(1U)
+
+#define S_TX_CLOSE    17
+#define V_TX_CLOSE(x) ((x) << S_TX_CLOSE)
+#define F_TX_CLOSE    V_TX_CLOSE(1U)
+
+#define S_TX_INIT    18
+#define V_TX_INIT(x) ((x) << S_TX_INIT)
+#define F_TX_INIT    V_TX_INIT(1U)
+
+#define S_TX_IMM_ACK    19
+#define V_TX_IMM_ACK(x) ((x) << S_TX_IMM_ACK)
+#define F_TX_IMM_ACK    V_TX_IMM_ACK(1U)
+
+#define S_TX_IMM_DMA    20
+#define V_TX_IMM_DMA(x) ((x) << S_TX_IMM_DMA)
+#define F_TX_IMM_DMA    V_TX_IMM_DMA(1U)
+
+struct cpl_tx_data_ack {
+	RSS_HDR union opcode_tid ot;
+	__be32 ack_seq;
+};
+
+struct cpl_wr_ack {
+	RSS_HDR union opcode_tid ot;
+	__be16 credits;
+	__be16 rsvd;
+	__be32 snd_nxt;
+	__be32 snd_una;
+};
+
+struct cpl_rdma_ec_status {
+	RSS_HDR union opcode_tid ot;
+	__u8 rsvd[3];
+	__u8 status;
+};
+
+struct mngt_pktsched_wr {
+	__be32 wr_hi;
+	__be32 wr_lo;
+	__u8 mngt_opcode;
+	__u8 rsvd[7];
+	__u8 sched;
+	__u8 idx;
+	__u8 min;
+	__u8 max;
+	__u8 binding;
+	__u8 rsvd1[3];
+};
+
+struct cpl_iscsi_hdr {
+	RSS_HDR union opcode_tid ot;
+	__be16 pdu_len_ddp;
+	__be16 len;
+	__be32 seq;
+	__be16 urg;
+	__u8 rsvd;
+	__u8 status;
+};
+
+/* cpl_iscsi_hdr.pdu_len_ddp fields */
+#define S_ISCSI_PDU_LEN    0
+#define M_ISCSI_PDU_LEN    0x7FFF
+#define V_ISCSI_PDU_LEN(x) ((x) << S_ISCSI_PDU_LEN)
+#define G_ISCSI_PDU_LEN(x) (((x) >> S_ISCSI_PDU_LEN) & M_ISCSI_PDU_LEN)
+
+#define S_ISCSI_DDP    15
+#define V_ISCSI_DDP(x) ((x) << S_ISCSI_DDP)
+#define F_ISCSI_DDP    V_ISCSI_DDP(1U)
+
+struct cpl_rx_data {
+	RSS_HDR union opcode_tid ot;
+	__be16 rsvd;
+	__be16 len;
+	__be32 seq;
+	__be16 urg;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8 dack_mode:2;
+	__u8 psh:1;
+	__u8 heartbeat:1;
+	 __u8:4;
+#else
+	 __u8:4;
+	__u8 heartbeat:1;
+	__u8 psh:1;
+	__u8 dack_mode:2;
+#endif
+	__u8 status;
+};
+
+struct cpl_rx_data_ack {
+	WR_HDR;
+	union opcode_tid ot;
+	__be32 credit_dack;
+};
+
+/* cpl_rx_data_ack.ack_seq fields */
+#define S_RX_CREDITS    0
+#define M_RX_CREDITS    0x7FFFFFF
+#define V_RX_CREDITS(x) ((x) << S_RX_CREDITS)
+#define G_RX_CREDITS(x) (((x) >> S_RX_CREDITS) & M_RX_CREDITS)
+
+#define S_RX_MODULATE    27
+#define V_RX_MODULATE(x) ((x) << S_RX_MODULATE)
+#define F_RX_MODULATE    V_RX_MODULATE(1U)
+
+#define S_RX_FORCE_ACK    28
+#define V_RX_FORCE_ACK(x) ((x) << S_RX_FORCE_ACK)
+#define F_RX_FORCE_ACK    V_RX_FORCE_ACK(1U)
+
+#define S_RX_DACK_MODE    29
+#define M_RX_DACK_MODE    0x3
+#define V_RX_DACK_MODE(x) ((x) << S_RX_DACK_MODE)
+#define G_RX_DACK_MODE(x) (((x) >> S_RX_DACK_MODE) & M_RX_DACK_MODE)
+
+#define S_RX_DACK_CHANGE    31
+#define V_RX_DACK_CHANGE(x) ((x) << S_RX_DACK_CHANGE)
+#define F_RX_DACK_CHANGE    V_RX_DACK_CHANGE(1U)
+
+struct cpl_rx_urg_notify {
+	RSS_HDR union opcode_tid ot;
+	__be32 seq;
+};
+
+struct cpl_rx_ddp_complete {
+	RSS_HDR union opcode_tid ot;
+	__be32 ddp_report;
+};
+
+struct cpl_rx_data_ddp {
+	RSS_HDR union opcode_tid ot;
+	__be16 urg;
+	__be16 len;
+	__be32 seq;
+	union {
+		__be32 nxt_seq;
+		__be32 ddp_report;
+	};
+	__be32 ulp_crc;
+	__be32 ddpvld_status;
+};
+
+/* cpl_rx_data_ddp.ddpvld_status fields */
+#define S_DDP_STATUS    0
+#define M_DDP_STATUS    0xFF
+#define V_DDP_STATUS(x) ((x) << S_DDP_STATUS)
+#define G_DDP_STATUS(x) (((x) >> S_DDP_STATUS) & M_DDP_STATUS)
+
+#define S_DDP_VALID    15
+#define M_DDP_VALID    0x1FFFF
+#define V_DDP_VALID(x) ((x) << S_DDP_VALID)
+#define G_DDP_VALID(x) (((x) >> S_DDP_VALID) & M_DDP_VALID)
+
+#define S_DDP_PPOD_MISMATCH    15
+#define V_DDP_PPOD_MISMATCH(x) ((x) << S_DDP_PPOD_MISMATCH)
+#define F_DDP_PPOD_MISMATCH    V_DDP_PPOD_MISMATCH(1U)
+
+#define S_DDP_PDU    16
+#define V_DDP_PDU(x) ((x) << S_DDP_PDU)
+#define F_DDP_PDU    V_DDP_PDU(1U)
+
+#define S_DDP_LLIMIT_ERR    17
+#define V_DDP_LLIMIT_ERR(x) ((x) << S_DDP_LLIMIT_ERR)
+#define F_DDP_LLIMIT_ERR    V_DDP_LLIMIT_ERR(1U)
+
+#define S_DDP_PPOD_PARITY_ERR    18
+#define V_DDP_PPOD_PARITY_ERR(x) ((x) << S_DDP_PPOD_PARITY_ERR)
+#define F_DDP_PPOD_PARITY_ERR    V_DDP_PPOD_PARITY_ERR(1U)
+
+#define S_DDP_PADDING_ERR    19
+#define V_DDP_PADDING_ERR(x) ((x) << S_DDP_PADDING_ERR)
+#define F_DDP_PADDING_ERR    V_DDP_PADDING_ERR(1U)
+
+#define S_DDP_HDRCRC_ERR    20
+#define V_DDP_HDRCRC_ERR(x) ((x) << S_DDP_HDRCRC_ERR)
+#define F_DDP_HDRCRC_ERR    V_DDP_HDRCRC_ERR(1U)
+
+#define S_DDP_DATACRC_ERR    21
+#define V_DDP_DATACRC_ERR(x) ((x) << S_DDP_DATACRC_ERR)
+#define F_DDP_DATACRC_ERR    V_DDP_DATACRC_ERR(1U)
+
+#define S_DDP_INVALID_TAG    22
+#define V_DDP_INVALID_TAG(x) ((x) << S_DDP_INVALID_TAG)
+#define F_DDP_INVALID_TAG    V_DDP_INVALID_TAG(1U)
+
+#define S_DDP_ULIMIT_ERR    23
+#define V_DDP_ULIMIT_ERR(x) ((x) << S_DDP_ULIMIT_ERR)
+#define F_DDP_ULIMIT_ERR    V_DDP_ULIMIT_ERR(1U)
+
+#define S_DDP_OFFSET_ERR    24
+#define V_DDP_OFFSET_ERR(x) ((x) << S_DDP_OFFSET_ERR)
+#define F_DDP_OFFSET_ERR    V_DDP_OFFSET_ERR(1U)
+
+#define S_DDP_COLOR_ERR    25
+#define V_DDP_COLOR_ERR(x) ((x) << S_DDP_COLOR_ERR)
+#define F_DDP_COLOR_ERR    V_DDP_COLOR_ERR(1U)
+
+#define S_DDP_TID_MISMATCH    26
+#define V_DDP_TID_MISMATCH(x) ((x) << S_DDP_TID_MISMATCH)
+#define F_DDP_TID_MISMATCH    V_DDP_TID_MISMATCH(1U)
+
+#define S_DDP_INVALID_PPOD    27
+#define V_DDP_INVALID_PPOD(x) ((x) << S_DDP_INVALID_PPOD)
+#define F_DDP_INVALID_PPOD    V_DDP_INVALID_PPOD(1U)
+
+#define S_DDP_ULP_MODE    28
+#define M_DDP_ULP_MODE    0xF
+#define V_DDP_ULP_MODE(x) ((x) << S_DDP_ULP_MODE)
+#define G_DDP_ULP_MODE(x) (((x) >> S_DDP_ULP_MODE) & M_DDP_ULP_MODE)
+
+/* cpl_rx_data_ddp.ddp_report fields */
+#define S_DDP_OFFSET    0
+#define M_DDP_OFFSET    0x3FFFFF
+#define V_DDP_OFFSET(x) ((x) << S_DDP_OFFSET)
+#define G_DDP_OFFSET(x) (((x) >> S_DDP_OFFSET) & M_DDP_OFFSET)
+
+#define S_DDP_URG    24
+#define V_DDP_URG(x) ((x) << S_DDP_URG)
+#define F_DDP_URG    V_DDP_URG(1U)
+
+#define S_DDP_PSH    25
+#define V_DDP_PSH(x) ((x) << S_DDP_PSH)
+#define F_DDP_PSH    V_DDP_PSH(1U)
+
+#define S_DDP_BUF_COMPLETE    26
+#define V_DDP_BUF_COMPLETE(x) ((x) << S_DDP_BUF_COMPLETE)
+#define F_DDP_BUF_COMPLETE    V_DDP_BUF_COMPLETE(1U)
+
+#define S_DDP_BUF_TIMED_OUT    27
+#define V_DDP_BUF_TIMED_OUT(x) ((x) << S_DDP_BUF_TIMED_OUT)
+#define F_DDP_BUF_TIMED_OUT    V_DDP_BUF_TIMED_OUT(1U)
+
+#define S_DDP_BUF_IDX    28
+#define V_DDP_BUF_IDX(x) ((x) << S_DDP_BUF_IDX)
+#define F_DDP_BUF_IDX    V_DDP_BUF_IDX(1U)
+
+struct cpl_tx_pkt {
+	WR_HDR;
+	__be32 cntrl;
+	__be32 len;
+};
+
+struct cpl_tx_pkt_lso {
+	WR_HDR;
+	__be32 cntrl;
+	__be32 len;
+
+	__be32 rsvd;
+	__be32 lso_info;
+};
+
+/* cpl_tx_pkt*.cntrl fields */
+#define S_TXPKT_VLAN    0
+#define M_TXPKT_VLAN    0xFFFF
+#define V_TXPKT_VLAN(x) ((x) << S_TXPKT_VLAN)
+#define G_TXPKT_VLAN(x) (((x) >> S_TXPKT_VLAN) & M_TXPKT_VLAN)
+
+#define S_TXPKT_INTF    16
+#define M_TXPKT_INTF    0xF
+#define V_TXPKT_INTF(x) ((x) << S_TXPKT_INTF)
+#define G_TXPKT_INTF(x) (((x) >> S_TXPKT_INTF) & M_TXPKT_INTF)
+
+#define S_TXPKT_IPCSUM_DIS    20
+#define V_TXPKT_IPCSUM_DIS(x) ((x) << S_TXPKT_IPCSUM_DIS)
+#define F_TXPKT_IPCSUM_DIS    V_TXPKT_IPCSUM_DIS(1U)
+
+#define S_TXPKT_L4CSUM_DIS    21
+#define V_TXPKT_L4CSUM_DIS(x) ((x) << S_TXPKT_L4CSUM_DIS)
+#define F_TXPKT_L4CSUM_DIS    V_TXPKT_L4CSUM_DIS(1U)
+
+#define S_TXPKT_VLAN_VLD    22
+#define V_TXPKT_VLAN_VLD(x) ((x) << S_TXPKT_VLAN_VLD)
+#define F_TXPKT_VLAN_VLD    V_TXPKT_VLAN_VLD(1U)
+
+#define S_TXPKT_LOOPBACK    23
+#define V_TXPKT_LOOPBACK(x) ((x) << S_TXPKT_LOOPBACK)
+#define F_TXPKT_LOOPBACK    V_TXPKT_LOOPBACK(1U)
+
+#define S_TXPKT_OPCODE    24
+#define M_TXPKT_OPCODE    0xFF
+#define V_TXPKT_OPCODE(x) ((x) << S_TXPKT_OPCODE)
+#define G_TXPKT_OPCODE(x) (((x) >> S_TXPKT_OPCODE) & M_TXPKT_OPCODE)
+
+/* cpl_tx_pkt_lso.lso_info fields */
+#define S_LSO_MSS    0
+#define M_LSO_MSS    0x3FFF
+#define V_LSO_MSS(x) ((x) << S_LSO_MSS)
+#define G_LSO_MSS(x) (((x) >> S_LSO_MSS) & M_LSO_MSS)
+
+#define S_LSO_ETH_TYPE    14
+#define M_LSO_ETH_TYPE    0x3
+#define V_LSO_ETH_TYPE(x) ((x) << S_LSO_ETH_TYPE)
+#define G_LSO_ETH_TYPE(x) (((x) >> S_LSO_ETH_TYPE) & M_LSO_ETH_TYPE)
+
+#define S_LSO_TCPHDR_WORDS    16
+#define M_LSO_TCPHDR_WORDS    0xF
+#define V_LSO_TCPHDR_WORDS(x) ((x) << S_LSO_TCPHDR_WORDS)
+#define G_LSO_TCPHDR_WORDS(x) (((x) >> S_LSO_TCPHDR_WORDS) & M_LSO_TCPHDR_WORDS)
+
+#define S_LSO_IPHDR_WORDS    20
+#define M_LSO_IPHDR_WORDS    0xF
+#define V_LSO_IPHDR_WORDS(x) ((x) << S_LSO_IPHDR_WORDS)
+#define G_LSO_IPHDR_WORDS(x) (((x) >> S_LSO_IPHDR_WORDS) & M_LSO_IPHDR_WORDS)
+
+#define S_LSO_IPV6    24
+#define V_LSO_IPV6(x) ((x) << S_LSO_IPV6)
+#define F_LSO_IPV6    V_LSO_IPV6(1U)
+
+struct cpl_trace_pkt {
+#ifdef CHELSIO_FW
+	__u8 rss_opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8 err:1;
+	 __u8:7;
+#else
+	 __u8:7;
+	__u8 err:1;
+#endif
+	__u8 rsvd0;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8 qid:4;
+	 __u8:4;
+#else
+	 __u8:4;
+	__u8 qid:4;
+#endif
+	__be32 tstamp;
+#endif				/* CHELSIO_FW */
+
+	__u8 opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8 iff:4;
+	 __u8:4;
+#else
+	 __u8:4;
+	__u8 iff:4;
+#endif
+	__u8 rsvd[4];
+	__be16 len;
+};
+
+struct cpl_rx_pkt {
+	RSS_HDR __u8 opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8 iff:4;
+	__u8 csum_valid:1;
+	__u8 ipmi_pkt:1;
+	__u8 vlan_valid:1;
+	__u8 fragment:1;
+#else
+	__u8 fragment:1;
+	__u8 vlan_valid:1;
+	__u8 ipmi_pkt:1;
+	__u8 csum_valid:1;
+	__u8 iff:4;
+#endif
+	__be16 csum;
+	__be16 vlan;
+	__be16 len;
+};
+
+struct cpl_l2t_write_req {
+	WR_HDR;
+	union opcode_tid ot;
+	__be32 params;
+	__u8 rsvd[2];
+	__u8 dst_mac[6];
+};
+
+/* cpl_l2t_write_req.params fields */
+#define S_L2T_W_IDX    0
+#define M_L2T_W_IDX    0x7FF
+#define V_L2T_W_IDX(x) ((x) << S_L2T_W_IDX)
+#define G_L2T_W_IDX(x) (((x) >> S_L2T_W_IDX) & M_L2T_W_IDX)
+
+#define S_L2T_W_VLAN    11
+#define M_L2T_W_VLAN    0xFFF
+#define V_L2T_W_VLAN(x) ((x) << S_L2T_W_VLAN)
+#define G_L2T_W_VLAN(x) (((x) >> S_L2T_W_VLAN) & M_L2T_W_VLAN)
+
+#define S_L2T_W_IFF    23
+#define M_L2T_W_IFF    0xF
+#define V_L2T_W_IFF(x) ((x) << S_L2T_W_IFF)
+#define G_L2T_W_IFF(x) (((x) >> S_L2T_W_IFF) & M_L2T_W_IFF)
+
+#define S_L2T_W_PRIO    27
+#define M_L2T_W_PRIO    0x7
+#define V_L2T_W_PRIO(x) ((x) << S_L2T_W_PRIO)
+#define G_L2T_W_PRIO(x) (((x) >> S_L2T_W_PRIO) & M_L2T_W_PRIO)
+
+struct cpl_l2t_write_rpl {
+	RSS_HDR union opcode_tid ot;
+	__u8 status;
+	__u8 rsvd[3];
+};
+
+struct cpl_l2t_read_req {
+	WR_HDR;
+	union opcode_tid ot;
+	__be16 rsvd;
+	__be16 l2t_idx;
+};
+
+struct cpl_l2t_read_rpl {
+	RSS_HDR union opcode_tid ot;
+	__be32 params;
+	__u8 rsvd[2];
+	__u8 dst_mac[6];
+};
+
+/* cpl_l2t_read_rpl.params fields */
+#define S_L2T_R_PRIO    0
+#define M_L2T_R_PRIO    0x7
+#define V_L2T_R_PRIO(x) ((x) << S_L2T_R_PRIO)
+#define G_L2T_R_PRIO(x) (((x) >> S_L2T_R_PRIO) & M_L2T_R_PRIO)
+
+#define S_L2T_R_VLAN    8
+#define M_L2T_R_VLAN    0xFFF
+#define V_L2T_R_VLAN(x) ((x) << S_L2T_R_VLAN)
+#define G_L2T_R_VLAN(x) (((x) >> S_L2T_R_VLAN) & M_L2T_R_VLAN)
+
+#define S_L2T_R_IFF    20
+#define M_L2T_R_IFF    0xF
+#define V_L2T_R_IFF(x) ((x) << S_L2T_R_IFF)
+#define G_L2T_R_IFF(x) (((x) >> S_L2T_R_IFF) & M_L2T_R_IFF)
+
+#define S_L2T_STATUS    24
+#define M_L2T_STATUS    0xFF
+#define V_L2T_STATUS(x) ((x) << S_L2T_STATUS)
+#define G_L2T_STATUS(x) (((x) >> S_L2T_STATUS) & M_L2T_STATUS)
+
+struct cpl_smt_write_req {
+	WR_HDR;
+	union opcode_tid ot;
+	__u8 rsvd0;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8 mtu_idx:4;
+	__u8 iff:4;
+#else
+	__u8 iff:4;
+	__u8 mtu_idx:4;
+#endif
+	__be16 rsvd2;
+	__be16 rsvd3;
+	__u8 src_mac1[6];
+	__be16 rsvd4;
+	__u8 src_mac0[6];
+};
+
+struct cpl_smt_write_rpl {
+	RSS_HDR union opcode_tid ot;
+	__u8 status;
+	__u8 rsvd[3];
+};
+
+struct cpl_smt_read_req {
+	WR_HDR;
+	union opcode_tid ot;
+	__u8 rsvd0;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	 __u8:4;
+	__u8 iff:4;
+#else
+	__u8 iff:4;
+	 __u8:4;
+#endif
+	__be16 rsvd2;
+};
+
+struct cpl_smt_read_rpl {
+	RSS_HDR union opcode_tid ot;
+	__u8 status;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8 mtu_idx:4;
+	 __u8:4;
+#else
+	 __u8:4;
+	__u8 mtu_idx:4;
+#endif
+	__be16 rsvd2;
+	__be16 rsvd3;
+	__u8 src_mac1[6];
+	__be16 rsvd4;
+	__u8 src_mac0[6];
+};
+
+struct cpl_rte_delete_req {
+	WR_HDR;
+	union opcode_tid ot;
+	__be32 params;
+};
+
+/* { cpl_rte_delete_req, cpl_rte_read_req }.params fields */
+#define S_RTE_REQ_LUT_IX    8
+#define M_RTE_REQ_LUT_IX    0x7FF
+#define V_RTE_REQ_LUT_IX(x) ((x) << S_RTE_REQ_LUT_IX)
+#define G_RTE_REQ_LUT_IX(x) (((x) >> S_RTE_REQ_LUT_IX) & M_RTE_REQ_LUT_IX)
+
+#define S_RTE_REQ_LUT_BASE    19
+#define M_RTE_REQ_LUT_BASE    0x7FF
+#define V_RTE_REQ_LUT_BASE(x) ((x) << S_RTE_REQ_LUT_BASE)
+#define G_RTE_REQ_LUT_BASE(x) (((x) >> S_RTE_REQ_LUT_BASE) & M_RTE_REQ_LUT_BASE)
+
+#define S_RTE_READ_REQ_SELECT    31
+#define V_RTE_READ_REQ_SELECT(x) ((x) << S_RTE_READ_REQ_SELECT)
+#define F_RTE_READ_REQ_SELECT    V_RTE_READ_REQ_SELECT(1U)
+
+struct cpl_rte_delete_rpl {
+	RSS_HDR union opcode_tid ot;
+	__u8 status;
+	__u8 rsvd[3];
+};
+
+struct cpl_rte_write_req {
+	WR_HDR;
+	union opcode_tid ot;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	 __u8:6;
+	__u8 write_tcam:1;
+	__u8 write_l2t_lut:1;
+#else
+	__u8 write_l2t_lut:1;
+	__u8 write_tcam:1;
+	 __u8:6;
+#endif
+	__u8 rsvd[3];
+	__be32 lut_params;
+	__be16 rsvd2;
+	__be16 l2t_idx;
+	__be32 netmask;
+	__be32 faddr;
+};
+
+/* cpl_rte_write_req.lut_params fields */
+#define S_RTE_WRITE_REQ_LUT_IX    10
+#define M_RTE_WRITE_REQ_LUT_IX    0x7FF
+#define V_RTE_WRITE_REQ_LUT_IX(x) ((x) << S_RTE_WRITE_REQ_LUT_IX)
+#define G_RTE_WRITE_REQ_LUT_IX(x) (((x) >> S_RTE_WRITE_REQ_LUT_IX) & M_RTE_WRITE_REQ_LUT_IX)
+
+#define S_RTE_WRITE_REQ_LUT_BASE    21
+#define M_RTE_WRITE_REQ_LUT_BASE    0x7FF
+#define V_RTE_WRITE_REQ_LUT_BASE(x) ((x) << S_RTE_WRITE_REQ_LUT_BASE)
+#define G_RTE_WRITE_REQ_LUT_BASE(x) (((x) >> S_RTE_WRITE_REQ_LUT_BASE) & M_RTE_WRITE_REQ_LUT_BASE)
+
+struct cpl_rte_write_rpl {
+	RSS_HDR union opcode_tid ot;
+	__u8 status;
+	__u8 rsvd[3];
+};
+
+struct cpl_rte_read_req {
+	WR_HDR;
+	union opcode_tid ot;
+	__be32 params;
+};
+
+struct cpl_rte_read_rpl {
+	RSS_HDR union opcode_tid ot;
+	__u8 status;
+	__u8 rsvd0;
+	__be16 l2t_idx;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	 __u8:7;
+	__u8 select:1;
+#else
+	__u8 select:1;
+	 __u8:7;
+#endif
+	__u8 rsvd2[3];
+	__be32 addr;
+};
+
+struct cpl_tid_release {
+	WR_HDR;
+	union opcode_tid ot;
+	__be32 rsvd;
+};
+
+struct cpl_barrier {
+	WR_HDR;
+	__u8 opcode;
+	__u8 rsvd[7];
+};
+
+struct cpl_rdma_read_req {
+	__u8 opcode;
+	__u8 rsvd[15];
+};
+
+struct cpl_rdma_terminate {
+#ifdef CHELSIO_FW
+	__u8 opcode;
+	__u8 rsvd[2];
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8 rspq:3;
+	 __u8:5;
+#else
+	 __u8:5;
+	__u8 rspq:3;
+#endif
+	__be32 tid_len;
+#endif
+	__be32 msn;
+	__be32 mo;
+	__u8 data[0];
+};
+
+/* cpl_rdma_terminate.tid_len fields */
+#define S_FLIT_CNT    0
+#define M_FLIT_CNT    0xFF
+#define V_FLIT_CNT(x) ((x) << S_FLIT_CNT)
+#define G_FLIT_CNT(x) (((x) >> S_FLIT_CNT) & M_FLIT_CNT)
+
+#define S_TERM_TID    8
+#define M_TERM_TID    0xFFFFF
+#define V_TERM_TID(x) ((x) << S_TERM_TID)
+#define G_TERM_TID(x) (((x) >> S_TERM_TID) & M_TERM_TID)
+#endif				/* T3_CPL_H */
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
new file mode 100644
index 0000000..365a7f5
--- /dev/null
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -0,0 +1,3375 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+#include "sge_defs.h"
+#include "firmware_exports.h"
+
+/**
+ *	t3_wait_op_done_val - wait until an operation is completed
+ *	@adapter: the adapter performing the operation
+ *	@reg: the register to check for completion
+ *	@mask: a single-bit field within @reg that indicates completion
+ *	@polarity: the value of the field when the operation is completed
+ *	@attempts: number of check iterations
+ *	@delay: delay in usecs between iterations
+ *	@valp: where to store the value of the register at completion time
+ *
+ *	Wait until an operation is completed by checking a bit in a register
+ *	up to @attempts times.  If @valp is not NULL the value of the register
+ *	at the time it indicated completion is stored there.  Returns 0 if the
+ *	operation completes and -EAGAIN otherwise.
+ */
+
+int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask,
+			int polarity, int attempts, int delay, u32 *valp)
+{
+	while (1) {
+		u32 val = t3_read_reg(adapter, reg);
+
+		if (!!(val & mask) == polarity) {
+			if (valp)
+				*valp = val;
+			return 0;
+		}
+		if (--attempts == 0)
+ 			return -EAGAIN;
+		if (delay)
+			udelay(delay);
+	}
+}
+
+/**
+ *	t3_write_regs - write a bunch of registers
+ *	@adapter: the adapter to program
+ *	@p: an array of register address/register value pairs
+ *	@n: the number of address/value pairs
+ *	@offset: register address offset
+ *
+ *	Takes an array of register address/register value pairs and writes each
+ *	value to the corresponding register.  Register addresses are adjusted
+ *	by the supplied offset.
+ */
+void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p,
+		   int n, unsigned int offset)
+{
+	while (n--) {
+		t3_write_reg(adapter, p->reg_addr + offset, p->val);
+		p++;
+	}
+}
+
+/**
+ *	t3_set_reg_field - set a register field to a value
+ *	@adapter: the adapter to program
+ *	@addr: the register address
+ *	@mask: specifies the portion of the register to modify
+ *	@val: the new value for the register field
+ *
+ *	Sets a register field specified by the supplied mask to the
+ *	given value.
+ */
+void t3_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask,
+		      u32 val)
+{
+	u32 v = t3_read_reg(adapter, addr) & ~mask;
+
+	t3_write_reg(adapter, addr, v | val);
+	t3_read_reg(adapter, addr);	/* flush */
+}
+
+/**
+ *	t3_read_indirect - read indirectly addressed registers
+ *	@adap: the adapter
+ *	@addr_reg: register holding the indirect address
+ *	@data_reg: register holding the value of the indirect register
+ *	@vals: where the read register values are stored
+ *	@start_idx: index of first indirect register to read
+ *	@nregs: how many indirect registers to read
+ *
+ *	Reads registers that are accessed indirectly through an address/data
+ *	register pair.
+ */
+void t3_read_indirect(struct adapter *adap, unsigned int addr_reg,
+		      unsigned int data_reg, u32 *vals, unsigned int nregs,
+		      unsigned int start_idx)
+{
+	while (nregs--) {
+		t3_write_reg(adap, addr_reg, start_idx);
+		*vals++ = t3_read_reg(adap, data_reg);
+		start_idx++;
+	}
+}
+
+/**
+ *	t3_mc7_bd_read - read from MC7 through backdoor accesses
+ *	@mc7: identifies MC7 to read from
+ *	@start: index of first 64-bit word to read
+ *	@n: number of 64-bit words to read
+ *	@buf: where to store the read result
+ *
+ *	Read n 64-bit words from MC7 starting at word start, using backdoor
+ *	accesses.
+ */
+int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
+		   u64 *buf)
+{
+	static const int shift[] = { 0, 0, 16, 24 };
+	static const int step[] = { 0, 32, 16, 8 };
+
+	unsigned int size64 = mc7->size / 8;	/* # of 64-bit words */
+	struct adapter *adap = mc7->adapter;
+
+	if (start >= size64 || start + n > size64)
+		return -EINVAL;
+
+	start *= (8 << mc7->width);
+	while (n--) {
+		int i;
+		u64 val64 = 0;
+
+		for (i = (1 << mc7->width) - 1; i >= 0; --i) {
+			int attempts = 10;
+			u32 val;
+
+			t3_write_reg(adap, mc7->offset + A_MC7_BD_ADDR, start);
+			t3_write_reg(adap, mc7->offset + A_MC7_BD_OP, 0);
+			val = t3_read_reg(adap, mc7->offset + A_MC7_BD_OP);
+			while ((val & F_BUSY) && attempts--)
+				val = t3_read_reg(adap,
+						  mc7->offset + A_MC7_BD_OP);
+			if (val & F_BUSY)
+				return -EIO;
+
+			val = t3_read_reg(adap, mc7->offset + A_MC7_BD_DATA1);
+			if (mc7->width == 0) {
+				val64 = t3_read_reg(adap,
+						    mc7->offset +
+						    A_MC7_BD_DATA0);
+				val64 |= (u64) val << 32;
+			} else {
+				if (mc7->width > 1)
+					val >>= shift[mc7->width];
+				val64 |= (u64) val << (step[mc7->width] * i);
+			}
+			start += 8;
+		}
+		*buf++ = val64;
+	}
+	return 0;
+}
+
+/*
+ * Initialize MI1.
+ */
+static void mi1_init(struct adapter *adap, const struct adapter_info *ai)
+{
+	u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1;
+	u32 val = F_PREEN | V_MDIINV(ai->mdiinv) | V_MDIEN(ai->mdien) |
+	    V_CLKDIV(clkdiv);
+
+	if (!(ai->caps & SUPPORTED_10000baseT_Full))
+		val |= V_ST(1);
+	t3_write_reg(adap, A_MI1_CFG, val);
+}
+
+#define MDIO_ATTEMPTS 10
+
+/*
+ * MI1 read/write operations for direct-addressed PHYs.
+ */
+static int mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr,
+		    int reg_addr, unsigned int *valp)
+{
+	int ret;
+	u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
+
+	if (mmd_addr)
+		return -EINVAL;
+
+	mutex_lock(&adapter->mdio_lock);
+	t3_write_reg(adapter, A_MI1_ADDR, addr);
+	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2));
+	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+	if (!ret)
+		*valp = t3_read_reg(adapter, A_MI1_DATA);
+	mutex_unlock(&adapter->mdio_lock);
+	return ret;
+}
+
+static int mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr,
+		     int reg_addr, unsigned int val)
+{
+	int ret;
+	u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
+
+	if (mmd_addr)
+		return -EINVAL;
+
+	mutex_lock(&adapter->mdio_lock);
+	t3_write_reg(adapter, A_MI1_ADDR, addr);
+	t3_write_reg(adapter, A_MI1_DATA, val);
+	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
+	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+	mutex_unlock(&adapter->mdio_lock);
+	return ret;
+}
+
+static const struct mdio_ops mi1_mdio_ops = {
+	mi1_read,
+	mi1_write
+};
+
+/*
+ * MI1 read/write operations for indirect-addressed PHYs.
+ */
+static int mi1_ext_read(struct adapter *adapter, int phy_addr, int mmd_addr,
+			int reg_addr, unsigned int *valp)
+{
+	int ret;
+	u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
+
+	mutex_lock(&adapter->mdio_lock);
+	t3_write_reg(adapter, A_MI1_ADDR, addr);
+	t3_write_reg(adapter, A_MI1_DATA, reg_addr);
+	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
+	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+	if (!ret) {
+		t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(3));
+		ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
+				      MDIO_ATTEMPTS, 20);
+		if (!ret)
+			*valp = t3_read_reg(adapter, A_MI1_DATA);
+	}
+	mutex_unlock(&adapter->mdio_lock);
+	return ret;
+}
+
+static int mi1_ext_write(struct adapter *adapter, int phy_addr, int mmd_addr,
+			 int reg_addr, unsigned int val)
+{
+	int ret;
+	u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
+
+	mutex_lock(&adapter->mdio_lock);
+	t3_write_reg(adapter, A_MI1_ADDR, addr);
+	t3_write_reg(adapter, A_MI1_DATA, reg_addr);
+	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
+	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+	if (!ret) {
+		t3_write_reg(adapter, A_MI1_DATA, val);
+		t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
+		ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
+				      MDIO_ATTEMPTS, 20);
+	}
+	mutex_unlock(&adapter->mdio_lock);
+	return ret;
+}
+
+static const struct mdio_ops mi1_mdio_ext_ops = {
+	mi1_ext_read,
+	mi1_ext_write
+};
+
+/**
+ *	t3_mdio_change_bits - modify the value of a PHY register
+ *	@phy: the PHY to operate on
+ *	@mmd: the device address
+ *	@reg: the register address
+ *	@clear: what part of the register value to mask off
+ *	@set: what part of the register value to set
+ *
+ *	Changes the value of a PHY register by applying a mask to its current
+ *	value and ORing the result with a new value.
+ */
+int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear,
+			unsigned int set)
+{
+	int ret;
+	unsigned int val;
+
+	ret = mdio_read(phy, mmd, reg, &val);
+	if (!ret) {
+		val &= ~clear;
+		ret = mdio_write(phy, mmd, reg, val | set);
+	}
+	return ret;
+}
+
+/**
+ *	t3_phy_reset - reset a PHY block
+ *	@phy: the PHY to operate on
+ *	@mmd: the device address of the PHY block to reset
+ *	@wait: how long to wait for the reset to complete in 1ms increments
+ *
+ *	Resets a PHY block and optionally waits for the reset to complete.
+ *	@mmd should be 0 for 10/100/1000 PHYs and the device address to reset
+ *	for 10G PHYs.
+ */
+int t3_phy_reset(struct cphy *phy, int mmd, int wait)
+{
+	int err;
+	unsigned int ctl;
+
+	err = t3_mdio_change_bits(phy, mmd, MII_BMCR, BMCR_PDOWN, BMCR_RESET);
+	if (err || !wait)
+		return err;
+
+	do {
+		err = mdio_read(phy, mmd, MII_BMCR, &ctl);
+		if (err)
+			return err;
+		ctl &= BMCR_RESET;
+		if (ctl)
+			msleep(1);
+	} while (ctl && --wait);
+
+	return ctl ? -1 : 0;
+}
+
+/**
+ *	t3_phy_advertise - set the PHY advertisement registers for autoneg
+ *	@phy: the PHY to operate on
+ *	@advert: bitmap of capabilities the PHY should advertise
+ *
+ *	Sets a 10/100/1000 PHY's advertisement registers to advertise the
+ *	requested capabilities.
+ */
+int t3_phy_advertise(struct cphy *phy, unsigned int advert)
+{
+	int err;
+	unsigned int val = 0;
+
+	err = mdio_read(phy, 0, MII_CTRL1000, &val);
+	if (err)
+		return err;
+
+	val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
+	if (advert & ADVERTISED_1000baseT_Half)
+		val |= ADVERTISE_1000HALF;
+	if (advert & ADVERTISED_1000baseT_Full)
+		val |= ADVERTISE_1000FULL;
+
+	err = mdio_write(phy, 0, MII_CTRL1000, val);
+	if (err)
+		return err;
+
+	val = 1;
+	if (advert & ADVERTISED_10baseT_Half)
+		val |= ADVERTISE_10HALF;
+	if (advert & ADVERTISED_10baseT_Full)
+		val |= ADVERTISE_10FULL;
+	if (advert & ADVERTISED_100baseT_Half)
+		val |= ADVERTISE_100HALF;
+	if (advert & ADVERTISED_100baseT_Full)
+		val |= ADVERTISE_100FULL;
+	if (advert & ADVERTISED_Pause)
+		val |= ADVERTISE_PAUSE_CAP;
+	if (advert & ADVERTISED_Asym_Pause)
+		val |= ADVERTISE_PAUSE_ASYM;
+	return mdio_write(phy, 0, MII_ADVERTISE, val);
+}
+
+/**
+ *	t3_set_phy_speed_duplex - force PHY speed and duplex
+ *	@phy: the PHY to operate on
+ *	@speed: requested PHY speed
+ *	@duplex: requested PHY duplex
+ *
+ *	Force a 10/100/1000 PHY's speed and duplex.  This also disables
+ *	auto-negotiation except for GigE, where auto-negotiation is mandatory.
+ */
+int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex)
+{
+	int err;
+	unsigned int ctl;
+
+	err = mdio_read(phy, 0, MII_BMCR, &ctl);
+	if (err)
+		return err;
+
+	if (speed >= 0) {
+		ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
+		if (speed == SPEED_100)
+			ctl |= BMCR_SPEED100;
+		else if (speed == SPEED_1000)
+			ctl |= BMCR_SPEED1000;
+	}
+	if (duplex >= 0) {
+		ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
+		if (duplex == DUPLEX_FULL)
+			ctl |= BMCR_FULLDPLX;
+	}
+	if (ctl & BMCR_SPEED1000) /* auto-negotiation required for GigE */
+		ctl |= BMCR_ANENABLE;
+	return mdio_write(phy, 0, MII_BMCR, ctl);
+}
+
+static const struct adapter_info t3_adap_info[] = {
+	{2, 0, 0, 0,
+	 F_GPIO2_OEN | F_GPIO4_OEN |
+	 F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5,
+	 SUPPORTED_OFFLOAD,
+	 &mi1_mdio_ops, "Chelsio PE9000"},
+	{2, 0, 0, 0,
+	 F_GPIO2_OEN | F_GPIO4_OEN |
+	 F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5,
+	 SUPPORTED_OFFLOAD,
+	 &mi1_mdio_ops, "Chelsio T302"},
+	{1, 0, 0, 0,
+	 F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN |
+	 F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0,
+	 SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_OFFLOAD,
+	 &mi1_mdio_ext_ops, "Chelsio T310"},
+	{2, 0, 0, 0,
+	 F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN |
+	 F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL |
+	 F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0,
+	 SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_OFFLOAD,
+	 &mi1_mdio_ext_ops, "Chelsio T320"},
+};
+
+/*
+ * Return the adapter_info structure with a given index.  Out-of-range indices
+ * return NULL.
+ */
+const struct adapter_info *t3_get_adapter_info(unsigned int id)
+{
+	return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL;
+}
+
+#define CAPS_1G (SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | \
+		 SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII)
+#define CAPS_10G (SUPPORTED_10000baseT_Full | SUPPORTED_AUI)
+
+static const struct port_type_info port_types[] = {
+	{NULL},
+	{t3_ael1002_phy_prep, CAPS_10G | SUPPORTED_FIBRE,
+	 "10GBASE-XR"},
+	{t3_vsc8211_phy_prep, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ,
+	 "10/100/1000BASE-T"},
+	{NULL, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ,
+	 "10/100/1000BASE-T"},
+	{t3_xaui_direct_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
+	{NULL, CAPS_10G, "10GBASE-KX4"},
+	{t3_qt2045_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
+	{t3_ael1006_phy_prep, CAPS_10G | SUPPORTED_FIBRE,
+	 "10GBASE-SR"},
+	{NULL, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
+};
+
+#undef CAPS_1G
+#undef CAPS_10G
+
+#define VPD_ENTRY(name, len) \
+	u8 name##_kword[2]; u8 name##_len; u8 name##_data[len]
+
+/*
+ * Partial EEPROM Vital Product Data structure.  Includes only the ID and
+ * VPD-R sections.
+ */
+struct t3_vpd {
+	u8 id_tag;
+	u8 id_len[2];
+	u8 id_data[16];
+	u8 vpdr_tag;
+	u8 vpdr_len[2];
+	VPD_ENTRY(pn, 16);	/* part number */
+	VPD_ENTRY(ec, 16);	/* EC level */
+	VPD_ENTRY(sn, 16);	/* serial number */
+	VPD_ENTRY(na, 12);	/* MAC address base */
+	VPD_ENTRY(cclk, 6);	/* core clock */
+	VPD_ENTRY(mclk, 6);	/* mem clock */
+	VPD_ENTRY(uclk, 6);	/* uP clk */
+	VPD_ENTRY(mdc, 6);	/* MDIO clk */
+	VPD_ENTRY(mt, 2);	/* mem timing */
+	VPD_ENTRY(xaui0cfg, 6);	/* XAUI0 config */
+	VPD_ENTRY(xaui1cfg, 6);	/* XAUI1 config */
+	VPD_ENTRY(port0, 2);	/* PHY0 complex */
+	VPD_ENTRY(port1, 2);	/* PHY1 complex */
+	VPD_ENTRY(port2, 2);	/* PHY2 complex */
+	VPD_ENTRY(port3, 2);	/* PHY3 complex */
+	VPD_ENTRY(rv, 1);	/* csum */
+	u32 pad;		/* for multiple-of-4 sizing and alignment */
+};
+
+#define EEPROM_MAX_POLL   4
+#define EEPROM_STAT_ADDR  0x4000
+#define VPD_BASE          0xc00
+
+/**
+ *	t3_seeprom_read - read a VPD EEPROM location
+ *	@adapter: adapter to read
+ *	@addr: EEPROM address
+ *	@data: where to store the read data
+ *
+ *	Read a 32-bit word from a location in VPD EEPROM using the card's PCI
+ *	VPD ROM capability.  A zero is written to the flag bit when the
+ *	addres is written to the control register.  The hardware device will
+ *	set the flag to 1 when 4 bytes have been read into the data register.
+ */
+int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data)
+{
+	u16 val;
+	int attempts = EEPROM_MAX_POLL;
+	unsigned int base = adapter->params.pci.vpd_cap_addr;
+
+	if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
+		return -EINVAL;
+
+	pci_write_config_word(adapter->pdev, base + PCI_VPD_ADDR, addr);
+	do {
+		udelay(10);
+		pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val);
+	} while (!(val & PCI_VPD_ADDR_F) && --attempts);
+
+	if (!(val & PCI_VPD_ADDR_F)) {
+		CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr);
+		return -EIO;
+	}
+	pci_read_config_dword(adapter->pdev, base + PCI_VPD_DATA, data);
+	*data = le32_to_cpu(*data);
+	return 0;
+}
+
+/**
+ *	t3_seeprom_write - write a VPD EEPROM location
+ *	@adapter: adapter to write
+ *	@addr: EEPROM address
+ *	@data: value to write
+ *
+ *	Write a 32-bit word to a location in VPD EEPROM using the card's PCI
+ *	VPD ROM capability.
+ */
+int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data)
+{
+	u16 val;
+	int attempts = EEPROM_MAX_POLL;
+	unsigned int base = adapter->params.pci.vpd_cap_addr;
+
+	if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
+		return -EINVAL;
+
+	pci_write_config_dword(adapter->pdev, base + PCI_VPD_DATA,
+			       cpu_to_le32(data));
+	pci_write_config_word(adapter->pdev,base + PCI_VPD_ADDR,
+			      addr | PCI_VPD_ADDR_F);
+	do {
+		msleep(1);
+		pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val);
+	} while ((val & PCI_VPD_ADDR_F) && --attempts);
+
+	if (val & PCI_VPD_ADDR_F) {
+		CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr);
+		return -EIO;
+	}
+	return 0;
+}
+
+/**
+ *	t3_seeprom_wp - enable/disable EEPROM write protection
+ *	@adapter: the adapter
+ *	@enable: 1 to enable write protection, 0 to disable it
+ *
+ *	Enables or disables write protection on the serial EEPROM.
+ */
+int t3_seeprom_wp(struct adapter *adapter, int enable)
+{
+	return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0);
+}
+
+/*
+ * Convert a character holding a hex digit to a number.
+ */
+static unsigned int hex2int(unsigned char c)
+{
+	return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10;
+}
+
+/**
+ *	get_vpd_params - read VPD parameters from VPD EEPROM
+ *	@adapter: adapter to read
+ *	@p: where to store the parameters
+ *
+ *	Reads card parameters stored in VPD EEPROM.
+ */
+static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
+{
+	int i, addr, ret;
+	struct t3_vpd vpd;
+
+	/*
+	 * Card information is normally at VPD_BASE but some early cards had
+	 * it at 0.
+	 */
+	ret = t3_seeprom_read(adapter, VPD_BASE, (u32 *)&vpd);
+	if (ret)
+		return ret;
+	addr = vpd.id_tag == 0x82 ? VPD_BASE : 0;
+
+	for (i = 0; i < sizeof(vpd); i += 4) {
+		ret = t3_seeprom_read(adapter, addr + i,
+				      (u32 *)((u8 *)&vpd + i));
+		if (ret)
+			return ret;
+	}
+
+	p->cclk = simple_strtoul(vpd.cclk_data, NULL, 10);
+	p->mclk = simple_strtoul(vpd.mclk_data, NULL, 10);
+	p->uclk = simple_strtoul(vpd.uclk_data, NULL, 10);
+	p->mdc = simple_strtoul(vpd.mdc_data, NULL, 10);
+	p->mem_timing = simple_strtoul(vpd.mt_data, NULL, 10);
+
+	/* Old eeproms didn't have port information */
+	if (adapter->params.rev == 0 && !vpd.port0_data[0]) {
+		p->port_type[0] = uses_xaui(adapter) ? 1 : 2;
+		p->port_type[1] = uses_xaui(adapter) ? 6 : 2;
+	} else {
+		p->port_type[0] = hex2int(vpd.port0_data[0]);
+		p->port_type[1] = hex2int(vpd.port1_data[0]);
+		p->xauicfg[0] = simple_strtoul(vpd.xaui0cfg_data, NULL, 16);
+		p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16);
+	}
+
+	for (i = 0; i < 6; i++)
+		p->eth_base[i] = hex2int(vpd.na_data[2 * i]) * 16 +
+				 hex2int(vpd.na_data[2 * i + 1]);
+	return 0;
+}
+
+/* serial flash and firmware constants */
+enum {
+	SF_ATTEMPTS = 5,	/* max retries for SF1 operations */
+	SF_SEC_SIZE = 64 * 1024,	/* serial flash sector size */
+	SF_SIZE = SF_SEC_SIZE * 8,	/* serial flash size */
+
+	/* flash command opcodes */
+	SF_PROG_PAGE = 2,	/* program page */
+	SF_WR_DISABLE = 4,	/* disable writes */
+	SF_RD_STATUS = 5,	/* read status register */
+	SF_WR_ENABLE = 6,	/* enable writes */
+	SF_RD_DATA_FAST = 0xb,	/* read flash */
+	SF_ERASE_SECTOR = 0xd8,	/* erase sector */
+
+	FW_FLASH_BOOT_ADDR = 0x70000,	/* start address of FW in flash */
+	FW_VERS_ADDR = 0x77ffc	/* flash address holding FW version */
+};
+
+/**
+ *	sf1_read - read data from the serial flash
+ *	@adapter: the adapter
+ *	@byte_cnt: number of bytes to read
+ *	@cont: whether another operation will be chained
+ *	@valp: where to store the read data
+ *
+ *	Reads up to 4 bytes of data from the serial flash.  The location of
+ *	the read needs to be specified prior to calling this by issuing the
+ *	appropriate commands to the serial flash.
+ */
+static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont,
+		    u32 *valp)
+{
+	int ret;
+
+	if (!byte_cnt || byte_cnt > 4)
+		return -EINVAL;
+	if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
+		return -EBUSY;
+	t3_write_reg(adapter, A_SF_OP, V_CONT(cont) | V_BYTECNT(byte_cnt - 1));
+	ret = t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
+	if (!ret)
+		*valp = t3_read_reg(adapter, A_SF_DATA);
+	return ret;
+}
+
+/**
+ *	sf1_write - write data to the serial flash
+ *	@adapter: the adapter
+ *	@byte_cnt: number of bytes to write
+ *	@cont: whether another operation will be chained
+ *	@val: value to write
+ *
+ *	Writes up to 4 bytes of data to the serial flash.  The location of
+ *	the write needs to be specified prior to calling this by issuing the
+ *	appropriate commands to the serial flash.
+ */
+static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont,
+		     u32 val)
+{
+	if (!byte_cnt || byte_cnt > 4)
+		return -EINVAL;
+	if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
+		return -EBUSY;
+	t3_write_reg(adapter, A_SF_DATA, val);
+	t3_write_reg(adapter, A_SF_OP,
+		     V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1));
+	return t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
+}
+
+/**
+ *	flash_wait_op - wait for a flash operation to complete
+ *	@adapter: the adapter
+ *	@attempts: max number of polls of the status register
+ *	@delay: delay between polls in ms
+ *
+ *	Wait for a flash operation to complete by polling the status register.
+ */
+static int flash_wait_op(struct adapter *adapter, int attempts, int delay)
+{
+	int ret;
+	u32 status;
+
+	while (1) {
+		if ((ret = sf1_write(adapter, 1, 1, SF_RD_STATUS)) != 0 ||
+		    (ret = sf1_read(adapter, 1, 0, &status)) != 0)
+			return ret;
+		if (!(status & 1))
+			return 0;
+		if (--attempts == 0)
+			return -EAGAIN;
+		if (delay)
+			msleep(delay);
+	}
+}
+
+/**
+ *	t3_read_flash - read words from serial flash
+ *	@adapter: the adapter
+ *	@addr: the start address for the read
+ *	@nwords: how many 32-bit words to read
+ *	@data: where to store the read data
+ *	@byte_oriented: whether to store data as bytes or as words
+ *
+ *	Read the specified number of 32-bit words from the serial flash.
+ *	If @byte_oriented is set the read data is stored as a byte array
+ *	(i.e., big-endian), otherwise as 32-bit words in the platform's
+ *	natural endianess.
+ */
+int t3_read_flash(struct adapter *adapter, unsigned int addr,
+		  unsigned int nwords, u32 *data, int byte_oriented)
+{
+	int ret;
+
+	if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3))
+		return -EINVAL;
+
+	addr = swab32(addr) | SF_RD_DATA_FAST;
+
+	if ((ret = sf1_write(adapter, 4, 1, addr)) != 0 ||
+	    (ret = sf1_read(adapter, 1, 1, data)) != 0)
+		return ret;
+
+	for (; nwords; nwords--, data++) {
+		ret = sf1_read(adapter, 4, nwords > 1, data);
+		if (ret)
+			return ret;
+		if (byte_oriented)
+			*data = htonl(*data);
+	}
+	return 0;
+}
+
+/**
+ *	t3_write_flash - write up to a page of data to the serial flash
+ *	@adapter: the adapter
+ *	@addr: the start address to write
+ *	@n: length of data to write
+ *	@data: the data to write
+ *
+ *	Writes up to a page of data (256 bytes) to the serial flash starting
+ *	at the given address.
+ */
+static int t3_write_flash(struct adapter *adapter, unsigned int addr,
+			  unsigned int n, const u8 *data)
+{
+	int ret;
+	u32 buf[64];
+	unsigned int i, c, left, val, offset = addr & 0xff;
+
+	if (addr + n > SF_SIZE || offset + n > 256)
+		return -EINVAL;
+
+	val = swab32(addr) | SF_PROG_PAGE;
+
+	if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
+	    (ret = sf1_write(adapter, 4, 1, val)) != 0)
+		return ret;
+
+	for (left = n; left; left -= c) {
+		c = min(left, 4U);
+		for (val = 0, i = 0; i < c; ++i)
+			val = (val << 8) + *data++;
+
+		ret = sf1_write(adapter, c, c != left, val);
+		if (ret)
+			return ret;
+	}
+	if ((ret = flash_wait_op(adapter, 5, 1)) != 0)
+		return ret;
+
+	/* Read the page to verify the write succeeded */
+	ret = t3_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1);
+	if (ret)
+		return ret;
+
+	if (memcmp(data - n, (u8 *) buf + offset, n))
+		return -EIO;
+	return 0;
+}
+
+enum fw_version_type {
+	FW_VERSION_N3,
+	FW_VERSION_T3
+};
+
+/**
+ *	t3_get_fw_version - read the firmware version
+ *	@adapter: the adapter
+ *	@vers: where to place the version
+ *
+ *	Reads the FW version from flash.
+ */
+int t3_get_fw_version(struct adapter *adapter, u32 *vers)
+{
+	return t3_read_flash(adapter, FW_VERS_ADDR, 1, vers, 0);
+}
+
+/**
+ *	t3_check_fw_version - check if the FW is compatible with this driver
+ *	@adapter: the adapter
+ *
+ *	Checks if an adapter's FW is compatible with the driver.  Returns 0
+ *	if the versions are compatible, a negative error otherwise.
+ */
+int t3_check_fw_version(struct adapter *adapter)
+{
+	int ret;
+	u32 vers;
+	unsigned int type, major, minor;
+
+	ret = t3_get_fw_version(adapter, &vers);
+	if (ret)
+		return ret;
+
+	type = G_FW_VERSION_TYPE(vers);
+	major = G_FW_VERSION_MAJOR(vers);
+	minor = G_FW_VERSION_MINOR(vers);
+
+	if (type == FW_VERSION_T3 && major == 3 && minor == 1)
+		return 0;
+
+	CH_ERR(adapter, "found wrong FW version(%u.%u), "
+	       "driver needs version 3.1\n", major, minor);
+	return -EINVAL;
+}
+
+/**
+ *	t3_flash_erase_sectors - erase a range of flash sectors
+ *	@adapter: the adapter
+ *	@start: the first sector to erase
+ *	@end: the last sector to erase
+ *
+ *	Erases the sectors in the given range.
+ */
+static int t3_flash_erase_sectors(struct adapter *adapter, int start, int end)
+{
+	while (start <= end) {
+		int ret;
+
+		if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
+		    (ret = sf1_write(adapter, 4, 0,
+				     SF_ERASE_SECTOR | (start << 8))) != 0 ||
+		    (ret = flash_wait_op(adapter, 5, 500)) != 0)
+			return ret;
+		start++;
+	}
+	return 0;
+}
+
+/*
+ *	t3_load_fw - download firmware
+ *	@adapter: the adapter
+ *	@fw_data: the firrware image to write
+ *	@size: image size
+ *
+ *	Write the supplied firmware image to the card's serial flash.
+ *	The FW image has the following sections: @size - 8 bytes of code and
+ *	data, followed by 4 bytes of FW version, followed by the 32-bit
+ *	1's complement checksum of the whole image.
+ */
+int t3_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size)
+{
+	u32 csum;
+	unsigned int i;
+	const u32 *p = (const u32 *)fw_data;
+	int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16;
+
+	if (size & 3)
+		return -EINVAL;
+	if (size > FW_VERS_ADDR + 8 - FW_FLASH_BOOT_ADDR)
+		return -EFBIG;
+
+	for (csum = 0, i = 0; i < size / sizeof(csum); i++)
+		csum += ntohl(p[i]);
+	if (csum != 0xffffffff) {
+		CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
+		       csum);
+		return -EINVAL;
+	}
+
+	ret = t3_flash_erase_sectors(adapter, fw_sector, fw_sector);
+	if (ret)
+		goto out;
+
+	size -= 8;		/* trim off version and checksum */
+	for (addr = FW_FLASH_BOOT_ADDR; size;) {
+		unsigned int chunk_size = min(size, 256U);
+
+		ret = t3_write_flash(adapter, addr, chunk_size, fw_data);
+		if (ret)
+			goto out;
+
+		addr += chunk_size;
+		fw_data += chunk_size;
+		size -= chunk_size;
+	}
+
+	ret = t3_write_flash(adapter, FW_VERS_ADDR, 4, fw_data);
+out:
+	if (ret)
+		CH_ERR(adapter, "firmware download failed, error %d\n", ret);
+	return ret;
+}
+
+#define CIM_CTL_BASE 0x2000
+
+/**
+ *      t3_cim_ctl_blk_read - read a block from CIM control region
+ *
+ *      @adap: the adapter
+ *      @addr: the start address within the CIM control region
+ *      @n: number of words to read
+ *      @valp: where to store the result
+ *
+ *      Reads a block of 4-byte words from the CIM control region.
+ */
+int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr,
+			unsigned int n, unsigned int *valp)
+{
+	int ret = 0;
+
+	if (t3_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY)
+		return -EBUSY;
+
+	for ( ; !ret && n--; addr += 4) {
+		t3_write_reg(adap, A_CIM_HOST_ACC_CTRL, CIM_CTL_BASE + addr);
+		ret = t3_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY,
+				      0, 5, 2);
+		if (!ret)
+			*valp++ = t3_read_reg(adap, A_CIM_HOST_ACC_DATA);
+	}
+	return ret;
+}
+
+
+/**
+ *	t3_link_changed - handle interface link changes
+ *	@adapter: the adapter
+ *	@port_id: the port index that changed link state
+ *
+ *	Called when a port's link settings change to propagate the new values
+ *	to the associated PHY and MAC.  After performing the common tasks it
+ *	invokes an OS-specific handler.
+ */
+void t3_link_changed(struct adapter *adapter, int port_id)
+{
+	int link_ok, speed, duplex, fc;
+	struct port_info *pi = adap2pinfo(adapter, port_id);
+	struct cphy *phy = &pi->phy;
+	struct cmac *mac = &pi->mac;
+	struct link_config *lc = &pi->link_config;
+
+	phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
+
+	if (link_ok != lc->link_ok && adapter->params.rev > 0 &&
+	    uses_xaui(adapter)) {
+		if (link_ok)
+			t3b_pcs_reset(mac);
+		t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset,
+			     link_ok ? F_TXACTENABLE | F_RXEN : 0);
+	}
+	lc->link_ok = link_ok;
+	lc->speed = speed < 0 ? SPEED_INVALID : speed;
+	lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
+	if (lc->requested_fc & PAUSE_AUTONEG)
+		fc &= lc->requested_fc;
+	else
+		fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+
+	if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) {
+		/* Set MAC speed, duplex, and flow control to match PHY. */
+		t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc);
+		lc->fc = fc;
+	}
+
+	t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc);
+}
+
+/**
+ *	t3_link_start - apply link configuration to MAC/PHY
+ *	@phy: the PHY to setup
+ *	@mac: the MAC to setup
+ *	@lc: the requested link configuration
+ *
+ *	Set up a port's MAC and PHY according to a desired link configuration.
+ *	- If the PHY can auto-negotiate first decide what to advertise, then
+ *	  enable/disable auto-negotiation as desired, and reset.
+ *	- If the PHY does not auto-negotiate just reset it.
+ *	- If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
+ *	  otherwise do it later based on the outcome of auto-negotiation.
+ */
+int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
+{
+	unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+
+	lc->link_ok = 0;
+	if (lc->supported & SUPPORTED_Autoneg) {
+		lc->advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause);
+		if (fc) {
+			lc->advertising |= ADVERTISED_Asym_Pause;
+			if (fc & PAUSE_RX)
+				lc->advertising |= ADVERTISED_Pause;
+		}
+		phy->ops->advertise(phy, lc->advertising);
+
+		if (lc->autoneg == AUTONEG_DISABLE) {
+			lc->speed = lc->requested_speed;
+			lc->duplex = lc->requested_duplex;
+			lc->fc = (unsigned char)fc;
+			t3_mac_set_speed_duplex_fc(mac, lc->speed, lc->duplex,
+						   fc);
+			/* Also disables autoneg */
+			phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);
+			phy->ops->reset(phy, 0);
+		} else
+			phy->ops->autoneg_enable(phy);
+	} else {
+		t3_mac_set_speed_duplex_fc(mac, -1, -1, fc);
+		lc->fc = (unsigned char)fc;
+		phy->ops->reset(phy, 0);
+	}
+	return 0;
+}
+
+/**
+ *	t3_set_vlan_accel - control HW VLAN extraction
+ *	@adapter: the adapter
+ *	@ports: bitmap of adapter ports to operate on
+ *	@on: enable (1) or disable (0) HW VLAN extraction
+ *
+ *	Enables or disables HW extraction of VLAN tags for the given port.
+ */
+void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on)
+{
+	t3_set_reg_field(adapter, A_TP_OUT_CONFIG,
+			 ports << S_VLANEXTRACTIONENABLE,
+			 on ? (ports << S_VLANEXTRACTIONENABLE) : 0);
+}
+
+struct intr_info {
+	unsigned int mask;	/* bits to check in interrupt status */
+	const char *msg;	/* message to print or NULL */
+	short stat_idx;		/* stat counter to increment or -1 */
+	unsigned short fatal:1;	/* whether the condition reported is fatal */
+};
+
+/**
+ *	t3_handle_intr_status - table driven interrupt handler
+ *	@adapter: the adapter that generated the interrupt
+ *	@reg: the interrupt status register to process
+ *	@mask: a mask to apply to the interrupt status
+ *	@acts: table of interrupt actions
+ *	@stats: statistics counters tracking interrupt occurences
+ *
+ *	A table driven interrupt handler that applies a set of masks to an
+ *	interrupt status word and performs the corresponding actions if the
+ *	interrupts described by the mask have occured.  The actions include
+ *	optionally printing a warning or alert message, and optionally
+ *	incrementing a stat counter.  The table is terminated by an entry
+ *	specifying mask 0.  Returns the number of fatal interrupt conditions.
+ */
+static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg,
+				 unsigned int mask,
+				 const struct intr_info *acts,
+				 unsigned long *stats)
+{
+	int fatal = 0;
+	unsigned int status = t3_read_reg(adapter, reg) & mask;
+
+	for (; acts->mask; ++acts) {
+		if (!(status & acts->mask))
+			continue;
+		if (acts->fatal) {
+			fatal++;
+			CH_ALERT(adapter, "%s (0x%x)\n",
+				 acts->msg, status & acts->mask);
+		} else if (acts->msg)
+			CH_WARN(adapter, "%s (0x%x)\n",
+				acts->msg, status & acts->mask);
+		if (acts->stat_idx >= 0)
+			stats[acts->stat_idx]++;
+	}
+	if (status)		/* clear processed interrupts */
+		t3_write_reg(adapter, reg, status);
+	return fatal;
+}
+
+#define SGE_INTR_MASK (F_RSPQDISABLED)
+#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \
+		       F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \
+		       F_NFASRCHFAIL)
+#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE))
+#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
+		       V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \
+		       F_TXFIFO_UNDERRUN | F_RXFIFO_OVERFLOW)
+#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \
+			F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \
+			F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \
+			F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \
+			V_WFPARERR(M_WFPARERR) | V_RFPARERR(M_RFPARERR) | \
+			V_CFPARERR(M_CFPARERR) /* | V_MSIXPARERR(M_MSIXPARERR) */)
+#define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\
+			F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \
+			/* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \
+			V_BISTERR(M_BISTERR) | F_PEXERR)
+#define ULPRX_INTR_MASK F_PARERR
+#define ULPTX_INTR_MASK 0
+#define CPLSW_INTR_MASK (F_TP_FRAMING_ERROR | \
+			 F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \
+			 F_ZERO_SWITCH_ERROR)
+#define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \
+		       F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \
+		       F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \
+	 	       F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT)
+#define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \
+			V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \
+			V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR))
+#define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \
+			V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR) | \
+			V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR))
+#define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \
+		       V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \
+		       V_RXTPPARERRENB(M_RXTPPARERRENB) | \
+		       V_MCAPARERRENB(M_MCAPARERRENB))
+#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \
+		      F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \
+		      F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \
+		      F_MPS0 | F_CPL_SWITCH)
+
+/*
+ * Interrupt handler for the PCIX1 module.
+ */
+static void pci_intr_handler(struct adapter *adapter)
+{
+	static const struct intr_info pcix1_intr_info[] = {
+		{F_MSTDETPARERR, "PCI master detected parity error", -1, 1},
+		{F_SIGTARABT, "PCI signaled target abort", -1, 1},
+		{F_RCVTARABT, "PCI received target abort", -1, 1},
+		{F_RCVMSTABT, "PCI received master abort", -1, 1},
+		{F_SIGSYSERR, "PCI signaled system error", -1, 1},
+		{F_DETPARERR, "PCI detected parity error", -1, 1},
+		{F_SPLCMPDIS, "PCI split completion discarded", -1, 1},
+		{F_UNXSPLCMP, "PCI unexpected split completion error", -1, 1},
+		{F_RCVSPLCMPERR, "PCI received split completion error", -1,
+		 1},
+		{F_DETCORECCERR, "PCI correctable ECC error",
+		 STAT_PCI_CORR_ECC, 0},
+		{F_DETUNCECCERR, "PCI uncorrectable ECC error", -1, 1},
+		{F_PIOPARERR, "PCI PIO FIFO parity error", -1, 1},
+		{V_WFPARERR(M_WFPARERR), "PCI write FIFO parity error", -1,
+		 1},
+		{V_RFPARERR(M_RFPARERR), "PCI read FIFO parity error", -1,
+		 1},
+		{V_CFPARERR(M_CFPARERR), "PCI command FIFO parity error", -1,
+		 1},
+		{V_MSIXPARERR(M_MSIXPARERR), "PCI MSI-X table/PBA parity "
+		 "error", -1, 1},
+		{0}
+	};
+
+	if (t3_handle_intr_status(adapter, A_PCIX_INT_CAUSE, PCIX_INTR_MASK,
+				  pcix1_intr_info, adapter->irq_stats))
+		t3_fatal_err(adapter);
+}
+
+/*
+ * Interrupt handler for the PCIE module.
+ */
+static void pcie_intr_handler(struct adapter *adapter)
+{
+	static const struct intr_info pcie_intr_info[] = {
+		{F_PEXERR, "PCI PEX error", -1, 1},
+		{F_UNXSPLCPLERRR,
+		 "PCI unexpected split completion DMA read error", -1, 1},
+		{F_UNXSPLCPLERRC,
+		 "PCI unexpected split completion DMA command error", -1, 1},
+		{F_PCIE_PIOPARERR, "PCI PIO FIFO parity error", -1, 1},
+		{F_PCIE_WFPARERR, "PCI write FIFO parity error", -1, 1},
+		{F_PCIE_RFPARERR, "PCI read FIFO parity error", -1, 1},
+		{F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1},
+		{V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR),
+		 "PCI MSI-X table/PBA parity error", -1, 1},
+		{V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1},
+		{0}
+	};
+
+	if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK,
+				  pcie_intr_info, adapter->irq_stats))
+		t3_fatal_err(adapter);
+}
+
+/*
+ * TP interrupt handler.
+ */
+static void tp_intr_handler(struct adapter *adapter)
+{
+	static const struct intr_info tp_intr_info[] = {
+		{0xffffff, "TP parity error", -1, 1},
+		{0x1000000, "TP out of Rx pages", -1, 1},
+		{0x2000000, "TP out of Tx pages", -1, 1},
+		{0}
+	};
+
+	if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff,
+				  tp_intr_info, NULL))
+		t3_fatal_err(adapter);
+}
+
+/*
+ * CIM interrupt handler.
+ */
+static void cim_intr_handler(struct adapter *adapter)
+{
+	static const struct intr_info cim_intr_info[] = {
+		{F_RSVDSPACEINT, "CIM reserved space write", -1, 1},
+		{F_SDRAMRANGEINT, "CIM SDRAM address out of range", -1, 1},
+		{F_FLASHRANGEINT, "CIM flash address out of range", -1, 1},
+		{F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1},
+		{F_WRBLKFLASHINT, "CIM write to cached flash space", -1, 1},
+		{F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1},
+		{F_BLKRDFLASHINT, "CIM block read from flash space", -1, 1},
+		{F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1},
+		{F_BLKRDCTLINT, "CIM block read from CTL space", -1, 1},
+		{F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1},
+		{F_BLKRDPLINT, "CIM block read from PL space", -1, 1},
+		{F_BLKWRPLINT, "CIM block write to PL space", -1, 1},
+		{0}
+	};
+
+	if (t3_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, 0xffffffff,
+				  cim_intr_info, NULL))
+		t3_fatal_err(adapter);
+}
+
+/*
+ * ULP RX interrupt handler.
+ */
+static void ulprx_intr_handler(struct adapter *adapter)
+{
+	static const struct intr_info ulprx_intr_info[] = {
+		{F_PARERR, "ULP RX parity error", -1, 1},
+		{0}
+	};
+
+	if (t3_handle_intr_status(adapter, A_ULPRX_INT_CAUSE, 0xffffffff,
+				  ulprx_intr_info, NULL))
+		t3_fatal_err(adapter);
+}
+
+/*
+ * ULP TX interrupt handler.
+ */
+static void ulptx_intr_handler(struct adapter *adapter)
+{
+	static const struct intr_info ulptx_intr_info[] = {
+		{F_PBL_BOUND_ERR_CH0, "ULP TX channel 0 PBL out of bounds",
+		 STAT_ULP_CH0_PBL_OOB, 0},
+		{F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds",
+		 STAT_ULP_CH1_PBL_OOB, 0},
+		{0}
+	};
+
+	if (t3_handle_intr_status(adapter, A_ULPTX_INT_CAUSE, 0xffffffff,
+				  ulptx_intr_info, adapter->irq_stats))
+		t3_fatal_err(adapter);
+}
+
+#define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \
+	F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \
+	F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \
+	F_ICSPI1_TX_FRAMING_ERROR)
+#define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \
+	F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \
+	F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \
+	F_OESPI1_OFIFO2X_TX_FRAMING_ERROR)
+
+/*
+ * PM TX interrupt handler.
+ */
+static void pmtx_intr_handler(struct adapter *adapter)
+{
+	static const struct intr_info pmtx_intr_info[] = {
+		{F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1},
+		{ICSPI_FRM_ERR, "PMTX ispi framing error", -1, 1},
+		{OESPI_FRM_ERR, "PMTX ospi framing error", -1, 1},
+		{V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR),
+		 "PMTX ispi parity error", -1, 1},
+		{V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR),
+		 "PMTX ospi parity error", -1, 1},
+		{0}
+	};
+
+	if (t3_handle_intr_status(adapter, A_PM1_TX_INT_CAUSE, 0xffffffff,
+				  pmtx_intr_info, NULL))
+		t3_fatal_err(adapter);
+}
+
+#define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \
+	F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \
+	F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \
+	F_IESPI1_TX_FRAMING_ERROR)
+#define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \
+	F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \
+	F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \
+	F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR)
+
+/*
+ * PM RX interrupt handler.
+ */
+static void pmrx_intr_handler(struct adapter *adapter)
+{
+	static const struct intr_info pmrx_intr_info[] = {
+		{F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1},
+		{IESPI_FRM_ERR, "PMRX ispi framing error", -1, 1},
+		{OCSPI_FRM_ERR, "PMRX ospi framing error", -1, 1},
+		{V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR),
+		 "PMRX ispi parity error", -1, 1},
+		{V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR),
+		 "PMRX ospi parity error", -1, 1},
+		{0}
+	};
+
+	if (t3_handle_intr_status(adapter, A_PM1_RX_INT_CAUSE, 0xffffffff,
+				  pmrx_intr_info, NULL))
+		t3_fatal_err(adapter);
+}
+
+/*
+ * CPL switch interrupt handler.
+ */
+static void cplsw_intr_handler(struct adapter *adapter)
+{
+	static const struct intr_info cplsw_intr_info[] = {
+/*		{ F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1 }, */
+		{F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1},
+		{F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1},
+		{F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1},
+		{F_ZERO_SWITCH_ERROR, "CPL switch no-switch error", -1, 1},
+		{0}
+	};
+
+	if (t3_handle_intr_status(adapter, A_CPL_INTR_CAUSE, 0xffffffff,
+				  cplsw_intr_info, NULL))
+		t3_fatal_err(adapter);
+}
+
+/*
+ * MPS interrupt handler.
+ */
+static void mps_intr_handler(struct adapter *adapter)
+{
+	static const struct intr_info mps_intr_info[] = {
+		{0x1ff, "MPS parity error", -1, 1},
+		{0}
+	};
+
+	if (t3_handle_intr_status(adapter, A_MPS_INT_CAUSE, 0xffffffff,
+				  mps_intr_info, NULL))
+		t3_fatal_err(adapter);
+}
+
+#define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE)
+
+/*
+ * MC7 interrupt handler.
+ */
+static void mc7_intr_handler(struct mc7 *mc7)
+{
+	struct adapter *adapter = mc7->adapter;
+	u32 cause = t3_read_reg(adapter, mc7->offset + A_MC7_INT_CAUSE);
+
+	if (cause & F_CE) {
+		mc7->stats.corr_err++;
+		CH_WARN(adapter, "%s MC7 correctable error at addr 0x%x, "
+			"data 0x%x 0x%x 0x%x\n", mc7->name,
+			t3_read_reg(adapter, mc7->offset + A_MC7_CE_ADDR),
+			t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA0),
+			t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA1),
+			t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA2));
+	}
+
+	if (cause & F_UE) {
+		mc7->stats.uncorr_err++;
+		CH_ALERT(adapter, "%s MC7 uncorrectable error at addr 0x%x, "
+			 "data 0x%x 0x%x 0x%x\n", mc7->name,
+			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_ADDR),
+			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA0),
+			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA1),
+			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA2));
+	}
+
+	if (G_PE(cause)) {
+		mc7->stats.parity_err++;
+		CH_ALERT(adapter, "%s MC7 parity error 0x%x\n",
+			 mc7->name, G_PE(cause));
+	}
+
+	if (cause & F_AE) {
+		u32 addr = 0;
+
+		if (adapter->params.rev > 0)
+			addr = t3_read_reg(adapter,
+					   mc7->offset + A_MC7_ERR_ADDR);
+		mc7->stats.addr_err++;
+		CH_ALERT(adapter, "%s MC7 address error: 0x%x\n",
+			 mc7->name, addr);
+	}
+
+	if (cause & MC7_INTR_FATAL)
+		t3_fatal_err(adapter);
+
+	t3_write_reg(adapter, mc7->offset + A_MC7_INT_CAUSE, cause);
+}
+
+#define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
+			V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR))
+/*
+ * XGMAC interrupt handler.
+ */
+static int mac_intr_handler(struct adapter *adap, unsigned int idx)
+{
+	struct cmac *mac = &adap2pinfo(adap, idx)->mac;
+	u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset);
+
+	if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) {
+		mac->stats.tx_fifo_parity_err++;
+		CH_ALERT(adap, "port%d: MAC TX FIFO parity error\n", idx);
+	}
+	if (cause & V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) {
+		mac->stats.rx_fifo_parity_err++;
+		CH_ALERT(adap, "port%d: MAC RX FIFO parity error\n", idx);
+	}
+	if (cause & F_TXFIFO_UNDERRUN)
+		mac->stats.tx_fifo_urun++;
+	if (cause & F_RXFIFO_OVERFLOW)
+		mac->stats.rx_fifo_ovfl++;
+	if (cause & V_SERDES_LOS(M_SERDES_LOS))
+		mac->stats.serdes_signal_loss++;
+	if (cause & F_XAUIPCSCTCERR)
+		mac->stats.xaui_pcs_ctc_err++;
+	if (cause & F_XAUIPCSALIGNCHANGE)
+		mac->stats.xaui_pcs_align_change++;
+
+	t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause);
+	if (cause & XGM_INTR_FATAL)
+		t3_fatal_err(adap);
+	return cause != 0;
+}
+
+/*
+ * Interrupt handler for PHY events.
+ */
+int t3_phy_intr_handler(struct adapter *adapter)
+{
+	static const int intr_gpio_bits[] = { 8, 0x20 };
+
+	u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE);
+
+	for_each_port(adapter, i) {
+		if (cause & intr_gpio_bits[i]) {
+			struct cphy *phy = &adap2pinfo(adapter, i)->phy;
+			int phy_cause = phy->ops->intr_handler(phy);
+
+			if (phy_cause & cphy_cause_link_change)
+				t3_link_changed(adapter, i);
+			if (phy_cause & cphy_cause_fifo_error)
+				phy->fifo_errors++;
+		}
+	}
+
+	t3_write_reg(adapter, A_T3DBG_INT_CAUSE, cause);
+	return 0;
+}
+
+/*
+ * T3 slow path (non-data) interrupt handler.
+ */
+int t3_slow_intr_handler(struct adapter *adapter)
+{
+	u32 cause = t3_read_reg(adapter, A_PL_INT_CAUSE0);
+
+	cause &= adapter->slow_intr_mask;
+	if (!cause)
+		return 0;
+	if (cause & F_PCIM0) {
+		if (is_pcie(adapter))
+			pcie_intr_handler(adapter);
+		else
+			pci_intr_handler(adapter);
+	}
+	if (cause & F_SGE3)
+		t3_sge_err_intr_handler(adapter);
+	if (cause & F_MC7_PMRX)
+		mc7_intr_handler(&adapter->pmrx);
+	if (cause & F_MC7_PMTX)
+		mc7_intr_handler(&adapter->pmtx);
+	if (cause & F_MC7_CM)
+		mc7_intr_handler(&adapter->cm);
+	if (cause & F_CIM)
+		cim_intr_handler(adapter);
+	if (cause & F_TP1)
+		tp_intr_handler(adapter);
+	if (cause & F_ULP2_RX)
+		ulprx_intr_handler(adapter);
+	if (cause & F_ULP2_TX)
+		ulptx_intr_handler(adapter);
+	if (cause & F_PM1_RX)
+		pmrx_intr_handler(adapter);
+	if (cause & F_PM1_TX)
+		pmtx_intr_handler(adapter);
+	if (cause & F_CPL_SWITCH)
+		cplsw_intr_handler(adapter);
+	if (cause & F_MPS0)
+		mps_intr_handler(adapter);
+	if (cause & F_MC5A)
+		t3_mc5_intr_handler(&adapter->mc5);
+	if (cause & F_XGMAC0_0)
+		mac_intr_handler(adapter, 0);
+	if (cause & F_XGMAC0_1)
+		mac_intr_handler(adapter, 1);
+	if (cause & F_T3DBG)
+		t3_os_ext_intr_handler(adapter);
+
+	/* Clear the interrupts just processed. */
+	t3_write_reg(adapter, A_PL_INT_CAUSE0, cause);
+	t3_read_reg(adapter, A_PL_INT_CAUSE0);	/* flush */
+	return 1;
+}
+
+/**
+ *	t3_intr_enable - enable interrupts
+ *	@adapter: the adapter whose interrupts should be enabled
+ *
+ *	Enable interrupts by setting the interrupt enable registers of the
+ *	various HW modules and then enabling the top-level interrupt
+ *	concentrator.
+ */
+void t3_intr_enable(struct adapter *adapter)
+{
+	static const struct addr_val_pair intr_en_avp[] = {
+		{A_SG_INT_ENABLE, SGE_INTR_MASK},
+		{A_MC7_INT_ENABLE, MC7_INTR_MASK},
+		{A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
+		 MC7_INTR_MASK},
+		{A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
+		 MC7_INTR_MASK},
+		{A_MC5_DB_INT_ENABLE, MC5_INTR_MASK},
+		{A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK},
+		{A_TP_INT_ENABLE, 0x3bfffff},
+		{A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK},
+		{A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK},
+		{A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK},
+		{A_MPS_INT_ENABLE, MPS_INTR_MASK},
+	};
+
+	adapter->slow_intr_mask = PL_INTR_MASK;
+
+	t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0);
+
+	if (adapter->params.rev > 0) {
+		t3_write_reg(adapter, A_CPL_INTR_ENABLE,
+			     CPLSW_INTR_MASK | F_CIM_OVFL_ERROR);
+		t3_write_reg(adapter, A_ULPTX_INT_ENABLE,
+			     ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 |
+			     F_PBL_BOUND_ERR_CH1);
+	} else {
+		t3_write_reg(adapter, A_CPL_INTR_ENABLE, CPLSW_INTR_MASK);
+		t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK);
+	}
+
+	t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW,
+		     adapter_info(adapter)->gpio_intr);
+	t3_write_reg(adapter, A_T3DBG_INT_ENABLE,
+		     adapter_info(adapter)->gpio_intr);
+	if (is_pcie(adapter))
+		t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK);
+	else
+		t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK);
+	t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask);
+	t3_read_reg(adapter, A_PL_INT_ENABLE0);	/* flush */
+}
+
+/**
+ *	t3_intr_disable - disable a card's interrupts
+ *	@adapter: the adapter whose interrupts should be disabled
+ *
+ *	Disable interrupts.  We only disable the top-level interrupt
+ *	concentrator and the SGE data interrupts.
+ */
+void t3_intr_disable(struct adapter *adapter)
+{
+	t3_write_reg(adapter, A_PL_INT_ENABLE0, 0);
+	t3_read_reg(adapter, A_PL_INT_ENABLE0);	/* flush */
+	adapter->slow_intr_mask = 0;
+}
+
+/**
+ *	t3_intr_clear - clear all interrupts
+ *	@adapter: the adapter whose interrupts should be cleared
+ *
+ *	Clears all interrupts.
+ */
+void t3_intr_clear(struct adapter *adapter)
+{
+	static const unsigned int cause_reg_addr[] = {
+		A_SG_INT_CAUSE,
+		A_SG_RSPQ_FL_STATUS,
+		A_PCIX_INT_CAUSE,
+		A_MC7_INT_CAUSE,
+		A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
+		A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
+		A_CIM_HOST_INT_CAUSE,
+		A_TP_INT_CAUSE,
+		A_MC5_DB_INT_CAUSE,
+		A_ULPRX_INT_CAUSE,
+		A_ULPTX_INT_CAUSE,
+		A_CPL_INTR_CAUSE,
+		A_PM1_TX_INT_CAUSE,
+		A_PM1_RX_INT_CAUSE,
+		A_MPS_INT_CAUSE,
+		A_T3DBG_INT_CAUSE,
+	};
+	unsigned int i;
+
+	/* Clear PHY and MAC interrupts for each port. */
+	for_each_port(adapter, i)
+	    t3_port_intr_clear(adapter, i);
+
+	for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i)
+		t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff);
+
+	t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff);
+	t3_read_reg(adapter, A_PL_INT_CAUSE0);	/* flush */
+}
+
+/**
+ *	t3_port_intr_enable - enable port-specific interrupts
+ *	@adapter: associated adapter
+ *	@idx: index of port whose interrupts should be enabled
+ *
+ *	Enable port-specific (i.e., MAC and PHY) interrupts for the given
+ *	adapter port.
+ */
+void t3_port_intr_enable(struct adapter *adapter, int idx)
+{
+	struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
+
+	t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), XGM_INTR_MASK);
+	t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */
+	phy->ops->intr_enable(phy);
+}
+
+/**
+ *	t3_port_intr_disable - disable port-specific interrupts
+ *	@adapter: associated adapter
+ *	@idx: index of port whose interrupts should be disabled
+ *
+ *	Disable port-specific (i.e., MAC and PHY) interrupts for the given
+ *	adapter port.
+ */
+void t3_port_intr_disable(struct adapter *adapter, int idx)
+{
+	struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
+
+	t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), 0);
+	t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */
+	phy->ops->intr_disable(phy);
+}
+
+/**
+ *	t3_port_intr_clear - clear port-specific interrupts
+ *	@adapter: associated adapter
+ *	@idx: index of port whose interrupts to clear
+ *
+ *	Clear port-specific (i.e., MAC and PHY) interrupts for the given
+ *	adapter port.
+ */
+void t3_port_intr_clear(struct adapter *adapter, int idx)
+{
+	struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
+
+	t3_write_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx), 0xffffffff);
+	t3_read_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx)); /* flush */
+	phy->ops->intr_clear(phy);
+}
+
+/**
+ * 	t3_sge_write_context - write an SGE context
+ * 	@adapter: the adapter
+ * 	@id: the context id
+ * 	@type: the context type
+ *
+ * 	Program an SGE context with the values already loaded in the
+ * 	CONTEXT_DATA? registers.
+ */
+static int t3_sge_write_context(struct adapter *adapter, unsigned int id,
+				unsigned int type)
+{
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff);
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff);
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0xffffffff);
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff);
+	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+		     V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id));
+	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+			       0, 5, 1);
+}
+
+/**
+ *	t3_sge_init_ecntxt - initialize an SGE egress context
+ *	@adapter: the adapter to configure
+ *	@id: the context id
+ *	@gts_enable: whether to enable GTS for the context
+ *	@type: the egress context type
+ *	@respq: associated response queue
+ *	@base_addr: base address of queue
+ *	@size: number of queue entries
+ *	@token: uP token
+ *	@gen: initial generation value for the context
+ *	@cidx: consumer pointer
+ *
+ *	Initialize an SGE egress context and make it ready for use.  If the
+ *	platform allows concurrent context operations, the caller is
+ *	responsible for appropriate locking.
+ */
+int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable,
+		       enum sge_context_type type, int respq, u64 base_addr,
+		       unsigned int size, unsigned int token, int gen,
+		       unsigned int cidx)
+{
+	unsigned int credits = type == SGE_CNTXT_OFLD ? 0 : FW_WR_NUM;
+
+	if (base_addr & 0xfff)	/* must be 4K aligned */
+		return -EINVAL;
+	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+		return -EBUSY;
+
+	base_addr >>= 12;
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_EC_INDEX(cidx) |
+		     V_EC_CREDITS(credits) | V_EC_GTS(gts_enable));
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA1, V_EC_SIZE(size) |
+		     V_EC_BASE_LO(base_addr & 0xffff));
+	base_addr >>= 16;
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA2, base_addr);
+	base_addr >>= 32;
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
+		     V_EC_BASE_HI(base_addr & 0xf) | V_EC_RESPQ(respq) |
+		     V_EC_TYPE(type) | V_EC_GEN(gen) | V_EC_UP_TOKEN(token) |
+		     F_EC_VALID);
+	return t3_sge_write_context(adapter, id, F_EGRESS);
+}
+
+/**
+ *	t3_sge_init_flcntxt - initialize an SGE free-buffer list context
+ *	@adapter: the adapter to configure
+ *	@id: the context id
+ *	@gts_enable: whether to enable GTS for the context
+ *	@base_addr: base address of queue
+ *	@size: number of queue entries
+ *	@bsize: size of each buffer for this queue
+ *	@cong_thres: threshold to signal congestion to upstream producers
+ *	@gen: initial generation value for the context
+ *	@cidx: consumer pointer
+ *
+ *	Initialize an SGE free list context and make it ready for use.  The
+ *	caller is responsible for ensuring only one context operation occurs
+ *	at a time.
+ */
+int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id,
+			int gts_enable, u64 base_addr, unsigned int size,
+			unsigned int bsize, unsigned int cong_thres, int gen,
+			unsigned int cidx)
+{
+	if (base_addr & 0xfff)	/* must be 4K aligned */
+		return -EINVAL;
+	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+		return -EBUSY;
+
+	base_addr >>= 12;
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, base_addr);
+	base_addr >>= 32;
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA1,
+		     V_FL_BASE_HI((u32) base_addr) |
+		     V_FL_INDEX_LO(cidx & M_FL_INDEX_LO));
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_FL_SIZE(size) |
+		     V_FL_GEN(gen) | V_FL_INDEX_HI(cidx >> 12) |
+		     V_FL_ENTRY_SIZE_LO(bsize & M_FL_ENTRY_SIZE_LO));
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
+		     V_FL_ENTRY_SIZE_HI(bsize >> (32 - S_FL_ENTRY_SIZE_LO)) |
+		     V_FL_CONG_THRES(cong_thres) | V_FL_GTS(gts_enable));
+	return t3_sge_write_context(adapter, id, F_FREELIST);
+}
+
+/**
+ *	t3_sge_init_rspcntxt - initialize an SGE response queue context
+ *	@adapter: the adapter to configure
+ *	@id: the context id
+ *	@irq_vec_idx: MSI-X interrupt vector index, 0 if no MSI-X, -1 if no IRQ
+ *	@base_addr: base address of queue
+ *	@size: number of queue entries
+ *	@fl_thres: threshold for selecting the normal or jumbo free list
+ *	@gen: initial generation value for the context
+ *	@cidx: consumer pointer
+ *
+ *	Initialize an SGE response queue context and make it ready for use.
+ *	The caller is responsible for ensuring only one context operation
+ *	occurs at a time.
+ */
+int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id,
+			 int irq_vec_idx, u64 base_addr, unsigned int size,
+			 unsigned int fl_thres, int gen, unsigned int cidx)
+{
+	unsigned int intr = 0;
+
+	if (base_addr & 0xfff)	/* must be 4K aligned */
+		return -EINVAL;
+	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+		return -EBUSY;
+
+	base_addr >>= 12;
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size) |
+		     V_CQ_INDEX(cidx));
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr);
+	base_addr >>= 32;
+	if (irq_vec_idx >= 0)
+		intr = V_RQ_MSI_VEC(irq_vec_idx) | F_RQ_INTR_EN;
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
+		     V_CQ_BASE_HI((u32) base_addr) | intr | V_RQ_GEN(gen));
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, fl_thres);
+	return t3_sge_write_context(adapter, id, F_RESPONSEQ);
+}
+
+/**
+ *	t3_sge_init_cqcntxt - initialize an SGE completion queue context
+ *	@adapter: the adapter to configure
+ *	@id: the context id
+ *	@base_addr: base address of queue
+ *	@size: number of queue entries
+ *	@rspq: response queue for async notifications
+ *	@ovfl_mode: CQ overflow mode
+ *	@credits: completion queue credits
+ *	@credit_thres: the credit threshold
+ *
+ *	Initialize an SGE completion queue context and make it ready for use.
+ *	The caller is responsible for ensuring only one context operation
+ *	occurs at a time.
+ */
+int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr,
+			unsigned int size, int rspq, int ovfl_mode,
+			unsigned int credits, unsigned int credit_thres)
+{
+	if (base_addr & 0xfff)	/* must be 4K aligned */
+		return -EINVAL;
+	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+		return -EBUSY;
+
+	base_addr >>= 12;
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size));
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr);
+	base_addr >>= 32;
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
+		     V_CQ_BASE_HI((u32) base_addr) | V_CQ_RSPQ(rspq) |
+		     V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode));
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) |
+		     V_CQ_CREDIT_THRES(credit_thres));
+	return t3_sge_write_context(adapter, id, F_CQ);
+}
+
+/**
+ *	t3_sge_enable_ecntxt - enable/disable an SGE egress context
+ *	@adapter: the adapter
+ *	@id: the egress context id
+ *	@enable: enable (1) or disable (0) the context
+ *
+ *	Enable or disable an SGE egress context.  The caller is responsible for
+ *	ensuring only one context operation occurs at a time.
+ */
+int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable)
+{
+	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+		return -EBUSY;
+
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, F_EC_VALID);
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_EC_VALID(enable));
+	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+		     V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id));
+	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+			       0, 5, 1);
+}
+
+/**
+ *	t3_sge_disable_fl - disable an SGE free-buffer list
+ *	@adapter: the adapter
+ *	@id: the free list context id
+ *
+ *	Disable an SGE free-buffer list.  The caller is responsible for
+ *	ensuring only one context operation occurs at a time.
+ */
+int t3_sge_disable_fl(struct adapter *adapter, unsigned int id)
+{
+	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+		return -EBUSY;
+
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, V_FL_SIZE(M_FL_SIZE));
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 0);
+	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+		     V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id));
+	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+			       0, 5, 1);
+}
+
+/**
+ *	t3_sge_disable_rspcntxt - disable an SGE response queue
+ *	@adapter: the adapter
+ *	@id: the response queue context id
+ *
+ *	Disable an SGE response queue.  The caller is responsible for
+ *	ensuring only one context operation occurs at a time.
+ */
+int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id)
+{
+	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+		return -EBUSY;
+
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
+	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+		     V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id));
+	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+			       0, 5, 1);
+}
+
+/**
+ *	t3_sge_disable_cqcntxt - disable an SGE completion queue
+ *	@adapter: the adapter
+ *	@id: the completion queue context id
+ *
+ *	Disable an SGE completion queue.  The caller is responsible for
+ *	ensuring only one context operation occurs at a time.
+ */
+int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id)
+{
+	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+		return -EBUSY;
+
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
+	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
+	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+		     V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id));
+	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+			       0, 5, 1);
+}
+
+/**
+ *	t3_sge_cqcntxt_op - perform an operation on a completion queue context
+ *	@adapter: the adapter
+ *	@id: the context id
+ *	@op: the operation to perform
+ *
+ *	Perform the selected operation on an SGE completion queue context.
+ *	The caller is responsible for ensuring only one context operation
+ *	occurs at a time.
+ */
+int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
+		      unsigned int credits)
+{
+	u32 val;
+
+	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+		return -EBUSY;
+
+	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, credits << 16);
+	t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) |
+		     V_CONTEXT(id) | F_CQ);
+	if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+				0, 5, 1, &val))
+		return -EIO;
+
+	if (op >= 2 && op < 7) {
+		if (adapter->params.rev > 0)
+			return G_CQ_INDEX(val);
+
+		t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+			     V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id));
+		if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD,
+				    F_CONTEXT_CMD_BUSY, 0, 5, 1))
+			return -EIO;
+		return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0));
+	}
+	return 0;
+}
+
+/**
+ * 	t3_sge_read_context - read an SGE context
+ * 	@type: the context type
+ * 	@adapter: the adapter
+ * 	@id: the context id
+ * 	@data: holds the retrieved context
+ *
+ * 	Read an SGE egress context.  The caller is responsible for ensuring
+ * 	only one context operation occurs at a time.
+ */
+static int t3_sge_read_context(unsigned int type, struct adapter *adapter,
+			       unsigned int id, u32 data[4])
+{
+	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+		return -EBUSY;
+
+	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+		     V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id));
+	if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0,
+			    5, 1))
+		return -EIO;
+	data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0);
+	data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1);
+	data[2] = t3_read_reg(adapter, A_SG_CONTEXT_DATA2);
+	data[3] = t3_read_reg(adapter, A_SG_CONTEXT_DATA3);
+	return 0;
+}
+
+/**
+ * 	t3_sge_read_ecntxt - read an SGE egress context
+ * 	@adapter: the adapter
+ * 	@id: the context id
+ * 	@data: holds the retrieved context
+ *
+ * 	Read an SGE egress context.  The caller is responsible for ensuring
+ * 	only one context operation occurs at a time.
+ */
+int t3_sge_read_ecntxt(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+	if (id >= 65536)
+		return -EINVAL;
+	return t3_sge_read_context(F_EGRESS, adapter, id, data);
+}
+
+/**
+ * 	t3_sge_read_cq - read an SGE CQ context
+ * 	@adapter: the adapter
+ * 	@id: the context id
+ * 	@data: holds the retrieved context
+ *
+ * 	Read an SGE CQ context.  The caller is responsible for ensuring
+ * 	only one context operation occurs at a time.
+ */
+int t3_sge_read_cq(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+	if (id >= 65536)
+		return -EINVAL;
+	return t3_sge_read_context(F_CQ, adapter, id, data);
+}
+
+/**
+ * 	t3_sge_read_fl - read an SGE free-list context
+ * 	@adapter: the adapter
+ * 	@id: the context id
+ * 	@data: holds the retrieved context
+ *
+ * 	Read an SGE free-list context.  The caller is responsible for ensuring
+ * 	only one context operation occurs at a time.
+ */
+int t3_sge_read_fl(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+	if (id >= SGE_QSETS * 2)
+		return -EINVAL;
+	return t3_sge_read_context(F_FREELIST, adapter, id, data);
+}
+
+/**
+ * 	t3_sge_read_rspq - read an SGE response queue context
+ * 	@adapter: the adapter
+ * 	@id: the context id
+ * 	@data: holds the retrieved context
+ *
+ * 	Read an SGE response queue context.  The caller is responsible for
+ * 	ensuring only one context operation occurs at a time.
+ */
+int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+	if (id >= SGE_QSETS)
+		return -EINVAL;
+	return t3_sge_read_context(F_RESPONSEQ, adapter, id, data);
+}
+
+/**
+ *	t3_config_rss - configure Rx packet steering
+ *	@adapter: the adapter
+ *	@rss_config: RSS settings (written to TP_RSS_CONFIG)
+ *	@cpus: values for the CPU lookup table (0xff terminated)
+ *	@rspq: values for the response queue lookup table (0xffff terminated)
+ *
+ *	Programs the receive packet steering logic.  @cpus and @rspq provide
+ *	the values for the CPU and response queue lookup tables.  If they
+ *	provide fewer values than the size of the tables the supplied values
+ *	are used repeatedly until the tables are fully populated.
+ */
+void t3_config_rss(struct adapter *adapter, unsigned int rss_config,
+		   const u8 * cpus, const u16 *rspq)
+{
+	int i, j, cpu_idx = 0, q_idx = 0;
+
+	if (cpus)
+		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+			u32 val = i << 16;
+
+			for (j = 0; j < 2; ++j) {
+				val |= (cpus[cpu_idx++] & 0x3f) << (8 * j);
+				if (cpus[cpu_idx] == 0xff)
+					cpu_idx = 0;
+			}
+			t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, val);
+		}
+
+	if (rspq)
+		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+			t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
+				     (i << 16) | rspq[q_idx++]);
+			if (rspq[q_idx] == 0xffff)
+				q_idx = 0;
+		}
+
+	t3_write_reg(adapter, A_TP_RSS_CONFIG, rss_config);
+}
+
+/**
+ *	t3_read_rss - read the contents of the RSS tables
+ *	@adapter: the adapter
+ *	@lkup: holds the contents of the RSS lookup table
+ *	@map: holds the contents of the RSS map table
+ *
+ *	Reads the contents of the receive packet steering tables.
+ */
+int t3_read_rss(struct adapter *adapter, u8 * lkup, u16 *map)
+{
+	int i;
+	u32 val;
+
+	if (lkup)
+		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+			t3_write_reg(adapter, A_TP_RSS_LKP_TABLE,
+				     0xffff0000 | i);
+			val = t3_read_reg(adapter, A_TP_RSS_LKP_TABLE);
+			if (!(val & 0x80000000))
+				return -EAGAIN;
+			*lkup++ = val;
+			*lkup++ = (val >> 8);
+		}
+
+	if (map)
+		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+			t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
+				     0xffff0000 | i);
+			val = t3_read_reg(adapter, A_TP_RSS_MAP_TABLE);
+			if (!(val & 0x80000000))
+				return -EAGAIN;
+			*map++ = val;
+		}
+	return 0;
+}
+
+/**
+ *	t3_tp_set_offload_mode - put TP in NIC/offload mode
+ *	@adap: the adapter
+ *	@enable: 1 to select offload mode, 0 for regular NIC
+ *
+ *	Switches TP to NIC/offload mode.
+ */
+void t3_tp_set_offload_mode(struct adapter *adap, int enable)
+{
+	if (is_offload(adap) || !enable)
+		t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE,
+				 V_NICMODE(!enable));
+}
+
+/**
+ *	pm_num_pages - calculate the number of pages of the payload memory
+ *	@mem_size: the size of the payload memory
+ *	@pg_size: the size of each payload memory page
+ *
+ *	Calculate the number of pages, each of the given size, that fit in a
+ *	memory of the specified size, respecting the HW requirement that the
+ *	number of pages must be a multiple of 24.
+ */
+static inline unsigned int pm_num_pages(unsigned int mem_size,
+					unsigned int pg_size)
+{
+	unsigned int n = mem_size / pg_size;
+
+	return n - n % 24;
+}
+
+#define mem_region(adap, start, size, reg) \
+	t3_write_reg((adap), A_ ## reg, (start)); \
+	start += size
+
+/*
+ *	partition_mem - partition memory and configure TP memory settings
+ *	@adap: the adapter
+ *	@p: the TP parameters
+ *
+ *	Partitions context and payload memory and configures TP's memory
+ *	registers.
+ */
+static void partition_mem(struct adapter *adap, const struct tp_params *p)
+{
+	unsigned int m, pstructs, tids = t3_mc5_size(&adap->mc5);
+	unsigned int timers = 0, timers_shift = 22;
+
+	if (adap->params.rev > 0) {
+		if (tids <= 16 * 1024) {
+			timers = 1;
+			timers_shift = 16;
+		} else if (tids <= 64 * 1024) {
+			timers = 2;
+			timers_shift = 18;
+		} else if (tids <= 256 * 1024) {
+			timers = 3;
+			timers_shift = 20;
+		}
+	}
+
+	t3_write_reg(adap, A_TP_PMM_SIZE,
+		     p->chan_rx_size | (p->chan_tx_size >> 16));
+
+	t3_write_reg(adap, A_TP_PMM_TX_BASE, 0);
+	t3_write_reg(adap, A_TP_PMM_TX_PAGE_SIZE, p->tx_pg_size);
+	t3_write_reg(adap, A_TP_PMM_TX_MAX_PAGE, p->tx_num_pgs);
+	t3_set_reg_field(adap, A_TP_PARA_REG3, V_TXDATAACKIDX(M_TXDATAACKIDX),
+			 V_TXDATAACKIDX(fls(p->tx_pg_size) - 12));
+
+	t3_write_reg(adap, A_TP_PMM_RX_BASE, 0);
+	t3_write_reg(adap, A_TP_PMM_RX_PAGE_SIZE, p->rx_pg_size);
+	t3_write_reg(adap, A_TP_PMM_RX_MAX_PAGE, p->rx_num_pgs);
+
+	pstructs = p->rx_num_pgs + p->tx_num_pgs;
+	/* Add a bit of headroom and make multiple of 24 */
+	pstructs += 48;
+	pstructs -= pstructs % 24;
+	t3_write_reg(adap, A_TP_CMM_MM_MAX_PSTRUCT, pstructs);
+
+	m = tids * TCB_SIZE;
+	mem_region(adap, m, (64 << 10) * 64, SG_EGR_CNTX_BADDR);
+	mem_region(adap, m, (64 << 10) * 64, SG_CQ_CONTEXT_BADDR);
+	t3_write_reg(adap, A_TP_CMM_TIMER_BASE, V_CMTIMERMAXNUM(timers) | m);
+	m += ((p->ntimer_qs - 1) << timers_shift) + (1 << 22);
+	mem_region(adap, m, pstructs * 64, TP_CMM_MM_BASE);
+	mem_region(adap, m, 64 * (pstructs / 24), TP_CMM_MM_PS_FLST_BASE);
+	mem_region(adap, m, 64 * (p->rx_num_pgs / 24), TP_CMM_MM_RX_FLST_BASE);
+	mem_region(adap, m, 64 * (p->tx_num_pgs / 24), TP_CMM_MM_TX_FLST_BASE);
+
+	m = (m + 4095) & ~0xfff;
+	t3_write_reg(adap, A_CIM_SDRAM_BASE_ADDR, m);
+	t3_write_reg(adap, A_CIM_SDRAM_ADDR_SIZE, p->cm_size - m);
+
+	tids = (p->cm_size - m - (3 << 20)) / 3072 - 32;
+	m = t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers -
+	    adap->params.mc5.nfilters - adap->params.mc5.nroutes;
+	if (tids < m)
+		adap->params.mc5.nservers += m - tids;
+}
+
+static inline void tp_wr_indirect(struct adapter *adap, unsigned int addr,
+				  u32 val)
+{
+	t3_write_reg(adap, A_TP_PIO_ADDR, addr);
+	t3_write_reg(adap, A_TP_PIO_DATA, val);
+}
+
+static void tp_config(struct adapter *adap, const struct tp_params *p)
+{
+	t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU |
+		     F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD |
+		     F_TCPCHECKSUMOFFLOAD | V_IPTTL(64));
+	t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) |
+		     F_MTUENABLE | V_WINDOWSCALEMODE(1) |
+		     V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1));
+	t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) |
+		     V_AUTOSTATE2(1) | V_AUTOSTATE1(0) |
+		     V_BYTETHRESHOLD(16384) | V_MSSTHRESHOLD(2) |
+		     F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1));
+	t3_set_reg_field(adap, A_TP_IN_CONFIG, F_IPV6ENABLE | F_NICMODE,
+			 F_IPV6ENABLE | F_NICMODE);
+	t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814);
+	t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105);
+	t3_set_reg_field(adap, A_TP_PARA_REG6,
+			 adap->params.rev > 0 ? F_ENABLEESND : F_T3A_ENABLEESND,
+			 0);
+
+	t3_set_reg_field(adap, A_TP_PC_CONFIG,
+			 F_ENABLEEPCMDAFULL | F_ENABLEOCSPIFULL,
+			 F_TXDEFERENABLE | F_HEARBEATDACK | F_TXCONGESTIONMODE |
+			 F_RXCONGESTIONMODE);
+	t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, 0);
+
+	if (adap->params.rev > 0) {
+		tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE);
+		t3_set_reg_field(adap, A_TP_PARA_REG3, F_TXPACEAUTO,
+				 F_TXPACEAUTO);
+		t3_set_reg_field(adap, A_TP_PC_CONFIG, F_LOCKTID, F_LOCKTID);
+		t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEAUTOSTRICT);
+	} else
+		t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED);
+
+	t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0x12121212);
+	t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0x12121212);
+	t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0x1212);
+}
+
+/* Desired TP timer resolution in usec */
+#define TP_TMR_RES 50
+
+/* TCP timer values in ms */
+#define TP_DACK_TIMER 50
+#define TP_RTO_MIN    250
+
+/**
+ *	tp_set_timers - set TP timing parameters
+ *	@adap: the adapter to set
+ *	@core_clk: the core clock frequency in Hz
+ *
+ *	Set TP's timing parameters, such as the various timer resolutions and
+ *	the TCP timer values.
+ */
+static void tp_set_timers(struct adapter *adap, unsigned int core_clk)
+{
+	unsigned int tre = fls(core_clk / (1000000 / TP_TMR_RES)) - 1;
+	unsigned int dack_re = fls(core_clk / 5000) - 1;	/* 200us */
+	unsigned int tstamp_re = fls(core_clk / 1000);	/* 1ms, at least */
+	unsigned int tps = core_clk >> tre;
+
+	t3_write_reg(adap, A_TP_TIMER_RESOLUTION, V_TIMERRESOLUTION(tre) |
+		     V_DELAYEDACKRESOLUTION(dack_re) |
+		     V_TIMESTAMPRESOLUTION(tstamp_re));
+	t3_write_reg(adap, A_TP_DACK_TIMER,
+		     (core_clk >> dack_re) / (1000 / TP_DACK_TIMER));
+	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG0, 0x3020100);
+	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG1, 0x7060504);
+	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG2, 0xb0a0908);
+	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG3, 0xf0e0d0c);
+	t3_write_reg(adap, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) |
+		     V_RXTSHIFTMAXR1(4) | V_RXTSHIFTMAXR2(15) |
+		     V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) |
+		     V_KEEPALIVEMAX(9));
+
+#define SECONDS * tps
+
+	t3_write_reg(adap, A_TP_MSL, adap->params.rev > 0 ? 0 : 2 SECONDS);
+	t3_write_reg(adap, A_TP_RXT_MIN, tps / (1000 / TP_RTO_MIN));
+	t3_write_reg(adap, A_TP_RXT_MAX, 64 SECONDS);
+	t3_write_reg(adap, A_TP_PERS_MIN, 5 SECONDS);
+	t3_write_reg(adap, A_TP_PERS_MAX, 64 SECONDS);
+	t3_write_reg(adap, A_TP_KEEP_IDLE, 7200 SECONDS);
+	t3_write_reg(adap, A_TP_KEEP_INTVL, 75 SECONDS);
+	t3_write_reg(adap, A_TP_INIT_SRTT, 3 SECONDS);
+	t3_write_reg(adap, A_TP_FINWAIT2_TIMER, 600 SECONDS);
+
+#undef SECONDS
+}
+
+/**
+ *	t3_tp_set_coalescing_size - set receive coalescing size
+ *	@adap: the adapter
+ *	@size: the receive coalescing size
+ *	@psh: whether a set PSH bit should deliver coalesced data
+ *
+ *	Set the receive coalescing size and PSH bit handling.
+ */
+int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh)
+{
+	u32 val;
+
+	if (size > MAX_RX_COALESCING_LEN)
+		return -EINVAL;
+
+	val = t3_read_reg(adap, A_TP_PARA_REG3);
+	val &= ~(F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN);
+
+	if (size) {
+		val |= F_RXCOALESCEENABLE;
+		if (psh)
+			val |= F_RXCOALESCEPSHEN;
+		t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) |
+			     V_MAXRXDATA(MAX_RX_COALESCING_LEN));
+	}
+	t3_write_reg(adap, A_TP_PARA_REG3, val);
+	return 0;
+}
+
+/**
+ *	t3_tp_set_max_rxsize - set the max receive size
+ *	@adap: the adapter
+ *	@size: the max receive size
+ *
+ *	Set TP's max receive size.  This is the limit that applies when
+ *	receive coalescing is disabled.
+ */
+void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size)
+{
+	t3_write_reg(adap, A_TP_PARA_REG7,
+		     V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size));
+}
+
+static void __devinit init_mtus(unsigned short mtus[])
+{
+	/*
+	 * See draft-mathis-plpmtud-00.txt for the values.  The min is 88 so
+	 * it can accomodate max size TCP/IP headers when SACK and timestamps
+	 * are enabled and still have at least 8 bytes of payload.
+	 */
+	mtus[0] = 88;
+	mtus[1] = 256;
+	mtus[2] = 512;
+	mtus[3] = 576;
+	mtus[4] = 808;
+	mtus[5] = 1024;
+	mtus[6] = 1280;
+	mtus[7] = 1492;
+	mtus[8] = 1500;
+	mtus[9] = 2002;
+	mtus[10] = 2048;
+	mtus[11] = 4096;
+	mtus[12] = 4352;
+	mtus[13] = 8192;
+	mtus[14] = 9000;
+	mtus[15] = 9600;
+}
+
+/*
+ * Initial congestion control parameters.
+ */
+static void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b)
+{
+	a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1;
+	a[9] = 2;
+	a[10] = 3;
+	a[11] = 4;
+	a[12] = 5;
+	a[13] = 6;
+	a[14] = 7;
+	a[15] = 8;
+	a[16] = 9;
+	a[17] = 10;
+	a[18] = 14;
+	a[19] = 17;
+	a[20] = 21;
+	a[21] = 25;
+	a[22] = 30;
+	a[23] = 35;
+	a[24] = 45;
+	a[25] = 60;
+	a[26] = 80;
+	a[27] = 100;
+	a[28] = 200;
+	a[29] = 300;
+	a[30] = 400;
+	a[31] = 500;
+
+	b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0;
+	b[9] = b[10] = 1;
+	b[11] = b[12] = 2;
+	b[13] = b[14] = b[15] = b[16] = 3;
+	b[17] = b[18] = b[19] = b[20] = b[21] = 4;
+	b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5;
+	b[28] = b[29] = 6;
+	b[30] = b[31] = 7;
+}
+
+/* The minimum additive increment value for the congestion control table */
+#define CC_MIN_INCR 2U
+
+/**
+ *	t3_load_mtus - write the MTU and congestion control HW tables
+ *	@adap: the adapter
+ *	@mtus: the unrestricted values for the MTU table
+ *	@alphs: the values for the congestion control alpha parameter
+ *	@beta: the values for the congestion control beta parameter
+ *	@mtu_cap: the maximum permitted effective MTU
+ *
+ *	Write the MTU table with the supplied MTUs capping each at &mtu_cap.
+ *	Update the high-speed congestion control table with the supplied alpha,
+ * 	beta, and MTUs.
+ */
+void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS],
+		  unsigned short alpha[NCCTRL_WIN],
+		  unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap)
+{
+	static const unsigned int avg_pkts[NCCTRL_WIN] = {
+		2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640,
+		896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480,
+		28672, 40960, 57344, 81920, 114688, 163840, 229376
+	};
+
+	unsigned int i, w;
+
+	for (i = 0; i < NMTUS; ++i) {
+		unsigned int mtu = min(mtus[i], mtu_cap);
+		unsigned int log2 = fls(mtu);
+
+		if (!(mtu & ((1 << log2) >> 2)))	/* round */
+			log2--;
+		t3_write_reg(adap, A_TP_MTU_TABLE,
+			     (i << 24) | (log2 << 16) | mtu);
+
+		for (w = 0; w < NCCTRL_WIN; ++w) {
+			unsigned int inc;
+
+			inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w],
+				  CC_MIN_INCR);
+
+			t3_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) |
+				     (w << 16) | (beta[w] << 13) | inc);
+		}
+	}
+}
+
+/**
+ *	t3_read_hw_mtus - returns the values in the HW MTU table
+ *	@adap: the adapter
+ *	@mtus: where to store the HW MTU values
+ *
+ *	Reads the HW MTU table.
+ */
+void t3_read_hw_mtus(struct adapter *adap, unsigned short mtus[NMTUS])
+{
+	int i;
+
+	for (i = 0; i < NMTUS; ++i) {
+		unsigned int val;
+
+		t3_write_reg(adap, A_TP_MTU_TABLE, 0xff000000 | i);
+		val = t3_read_reg(adap, A_TP_MTU_TABLE);
+		mtus[i] = val & 0x3fff;
+	}
+}
+
+/**
+ *	t3_get_cong_cntl_tab - reads the congestion control table
+ *	@adap: the adapter
+ *	@incr: where to store the alpha values
+ *
+ *	Reads the additive increments programmed into the HW congestion
+ *	control table.
+ */
+void t3_get_cong_cntl_tab(struct adapter *adap,
+			  unsigned short incr[NMTUS][NCCTRL_WIN])
+{
+	unsigned int mtu, w;
+
+	for (mtu = 0; mtu < NMTUS; ++mtu)
+		for (w = 0; w < NCCTRL_WIN; ++w) {
+			t3_write_reg(adap, A_TP_CCTRL_TABLE,
+				     0xffff0000 | (mtu << 5) | w);
+			incr[mtu][w] = t3_read_reg(adap, A_TP_CCTRL_TABLE) &
+				       0x1fff;
+		}
+}
+
+/**
+ *	t3_tp_get_mib_stats - read TP's MIB counters
+ *	@adap: the adapter
+ *	@tps: holds the returned counter values
+ *
+ *	Returns the values of TP's MIB counters.
+ */
+void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps)
+{
+	t3_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_RDATA, (u32 *) tps,
+			 sizeof(*tps) / sizeof(u32), 0);
+}
+
+#define ulp_region(adap, name, start, len) \
+	t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \
+	t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \
+		     (start) + (len) - 1); \
+	start += len
+
+#define ulptx_region(adap, name, start, len) \
+	t3_write_reg((adap), A_ULPTX_ ## name ## _LLIMIT, (start)); \
+	t3_write_reg((adap), A_ULPTX_ ## name ## _ULIMIT, \
+		     (start) + (len) - 1)
+
+static void ulp_config(struct adapter *adap, const struct tp_params *p)
+{
+	unsigned int m = p->chan_rx_size;
+
+	ulp_region(adap, ISCSI, m, p->chan_rx_size / 8);
+	ulp_region(adap, TDDP, m, p->chan_rx_size / 8);
+	ulptx_region(adap, TPT, m, p->chan_rx_size / 4);
+	ulp_region(adap, STAG, m, p->chan_rx_size / 4);
+	ulp_region(adap, RQ, m, p->chan_rx_size / 4);
+	ulptx_region(adap, PBL, m, p->chan_rx_size / 4);
+	ulp_region(adap, PBL, m, p->chan_rx_size / 4);
+	t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff);
+}
+
+void t3_config_trace_filter(struct adapter *adapter,
+			    const struct trace_params *tp, int filter_index,
+			    int invert, int enable)
+{
+	u32 addr, key[4], mask[4];
+
+	key[0] = tp->sport | (tp->sip << 16);
+	key[1] = (tp->sip >> 16) | (tp->dport << 16);
+	key[2] = tp->dip;
+	key[3] = tp->proto | (tp->vlan << 8) | (tp->intf << 20);
+
+	mask[0] = tp->sport_mask | (tp->sip_mask << 16);
+	mask[1] = (tp->sip_mask >> 16) | (tp->dport_mask << 16);
+	mask[2] = tp->dip_mask;
+	mask[3] = tp->proto_mask | (tp->vlan_mask << 8) | (tp->intf_mask << 20);
+
+	if (invert)
+		key[3] |= (1 << 29);
+	if (enable)
+		key[3] |= (1 << 28);
+
+	addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0;
+	tp_wr_indirect(adapter, addr++, key[0]);
+	tp_wr_indirect(adapter, addr++, mask[0]);
+	tp_wr_indirect(adapter, addr++, key[1]);
+	tp_wr_indirect(adapter, addr++, mask[1]);
+	tp_wr_indirect(adapter, addr++, key[2]);
+	tp_wr_indirect(adapter, addr++, mask[2]);
+	tp_wr_indirect(adapter, addr++, key[3]);
+	tp_wr_indirect(adapter, addr, mask[3]);
+	t3_read_reg(adapter, A_TP_PIO_DATA);
+}
+
+/**
+ *	t3_config_sched - configure a HW traffic scheduler
+ *	@adap: the adapter
+ *	@kbps: target rate in Kbps
+ *	@sched: the scheduler index
+ *
+ *	Configure a HW scheduler for the target rate
+ */
+int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched)
+{
+	unsigned int v, tps, cpt, bpt, delta, mindelta = ~0;
+	unsigned int clk = adap->params.vpd.cclk * 1000;
+	unsigned int selected_cpt = 0, selected_bpt = 0;
+
+	if (kbps > 0) {
+		kbps *= 125;	/* -> bytes */
+		for (cpt = 1; cpt <= 255; cpt++) {
+			tps = clk / cpt;
+			bpt = (kbps + tps / 2) / tps;
+			if (bpt > 0 && bpt <= 255) {
+				v = bpt * tps;
+				delta = v >= kbps ? v - kbps : kbps - v;
+				if (delta <= mindelta) {
+					mindelta = delta;
+					selected_cpt = cpt;
+					selected_bpt = bpt;
+				}
+			} else if (selected_cpt)
+				break;
+		}
+		if (!selected_cpt)
+			return -EINVAL;
+	}
+	t3_write_reg(adap, A_TP_TM_PIO_ADDR,
+		     A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2);
+	v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
+	if (sched & 1)
+		v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24);
+	else
+		v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8);
+	t3_write_reg(adap, A_TP_TM_PIO_DATA, v);
+	return 0;
+}
+
+static int tp_init(struct adapter *adap, const struct tp_params *p)
+{
+	int busy = 0;
+
+	tp_config(adap, p);
+	t3_set_vlan_accel(adap, 3, 0);
+
+	if (is_offload(adap)) {
+		tp_set_timers(adap, adap->params.vpd.cclk * 1000);
+		t3_write_reg(adap, A_TP_RESET, F_FLSTINITENABLE);
+		busy = t3_wait_op_done(adap, A_TP_RESET, F_FLSTINITENABLE,
+				       0, 1000, 5);
+		if (busy)
+			CH_ERR(adap, "TP initialization timed out\n");
+	}
+
+	if (!busy)
+		t3_write_reg(adap, A_TP_RESET, F_TPRESET);
+	return busy;
+}
+
+int t3_mps_set_active_ports(struct adapter *adap, unsigned int port_mask)
+{
+	if (port_mask & ~((1 << adap->params.nports) - 1))
+		return -EINVAL;
+	t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE,
+			 port_mask << S_PORT0ACTIVE);
+	return 0;
+}
+
+/*
+ * Perform the bits of HW initialization that are dependent on the number
+ * of available ports.
+ */
+static void init_hw_for_avail_ports(struct adapter *adap, int nports)
+{
+	int i;
+
+	if (nports == 1) {
+		t3_set_reg_field(adap, A_ULPRX_CTL, F_ROUND_ROBIN, 0);
+		t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0);
+		t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_TPTXPORT0EN |
+			     F_PORT0ACTIVE | F_ENFORCEPKT);
+		t3_write_reg(adap, A_PM1_TX_CFG, 0xc000c000);
+	} else {
+		t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN);
+		t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB);
+		t3_write_reg(adap, A_ULPTX_DMA_WEIGHT,
+			     V_D1_WEIGHT(16) | V_D0_WEIGHT(16));
+		t3_write_reg(adap, A_MPS_CFG, F_TPTXPORT0EN | F_TPTXPORT1EN |
+			     F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE |
+			     F_ENFORCEPKT);
+		t3_write_reg(adap, A_PM1_TX_CFG, 0x80008000);
+		t3_set_reg_field(adap, A_TP_PC_CONFIG, 0, F_TXTOSQUEUEMAPMODE);
+		t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP,
+			     V_TX_MOD_QUEUE_REQ_MAP(0xaa));
+		for (i = 0; i < 16; i++)
+			t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE,
+				     (i << 16) | 0x1010);
+	}
+}
+
+static int calibrate_xgm(struct adapter *adapter)
+{
+	if (uses_xaui(adapter)) {
+		unsigned int v, i;
+
+		for (i = 0; i < 5; ++i) {
+			t3_write_reg(adapter, A_XGM_XAUI_IMP, 0);
+			t3_read_reg(adapter, A_XGM_XAUI_IMP);
+			msleep(1);
+			v = t3_read_reg(adapter, A_XGM_XAUI_IMP);
+			if (!(v & (F_XGM_CALFAULT | F_CALBUSY))) {
+				t3_write_reg(adapter, A_XGM_XAUI_IMP,
+					     V_XAUIIMP(G_CALIMP(v) >> 2));
+				return 0;
+			}
+		}
+		CH_ERR(adapter, "MAC calibration failed\n");
+		return -1;
+	} else {
+		t3_write_reg(adapter, A_XGM_RGMII_IMP,
+			     V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
+		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
+				 F_XGM_IMPSETUPDATE);
+	}
+	return 0;
+}
+
+static void calibrate_xgm_t3b(struct adapter *adapter)
+{
+	if (!uses_xaui(adapter)) {
+		t3_write_reg(adapter, A_XGM_RGMII_IMP, F_CALRESET |
+			     F_CALUPDATE | V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
+		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALRESET, 0);
+		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0,
+				 F_XGM_IMPSETUPDATE);
+		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
+				 0);
+		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALUPDATE, 0);
+		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, F_CALUPDATE);
+	}
+}
+
+struct mc7_timing_params {
+	unsigned char ActToPreDly;
+	unsigned char ActToRdWrDly;
+	unsigned char PreCyc;
+	unsigned char RefCyc[5];
+	unsigned char BkCyc;
+	unsigned char WrToRdDly;
+	unsigned char RdToWrDly;
+};
+
+/*
+ * Write a value to a register and check that the write completed.  These
+ * writes normally complete in a cycle or two, so one read should suffice.
+ * The very first read exists to flush the posted write to the device.
+ */
+static int wrreg_wait(struct adapter *adapter, unsigned int addr, u32 val)
+{
+	t3_write_reg(adapter, addr, val);
+	t3_read_reg(adapter, addr);	/* flush */
+	if (!(t3_read_reg(adapter, addr) & F_BUSY))
+		return 0;
+	CH_ERR(adapter, "write to MC7 register 0x%x timed out\n", addr);
+	return -EIO;
+}
+
+static int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type)
+{
+	static const unsigned int mc7_mode[] = {
+		0x632, 0x642, 0x652, 0x432, 0x442
+	};
+	static const struct mc7_timing_params mc7_timings[] = {
+		{12, 3, 4, {20, 28, 34, 52, 0}, 15, 6, 4},
+		{12, 4, 5, {20, 28, 34, 52, 0}, 16, 7, 4},
+		{12, 5, 6, {20, 28, 34, 52, 0}, 17, 8, 4},
+		{9, 3, 4, {15, 21, 26, 39, 0}, 12, 6, 4},
+		{9, 4, 5, {15, 21, 26, 39, 0}, 13, 7, 4}
+	};
+
+	u32 val;
+	unsigned int width, density, slow, attempts;
+	struct adapter *adapter = mc7->adapter;
+	const struct mc7_timing_params *p = &mc7_timings[mem_type];
+
+	val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
+	slow = val & F_SLOW;
+	width = G_WIDTH(val);
+	density = G_DEN(val);
+
+	t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN);
+	val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);	/* flush */
+	msleep(1);
+
+	if (!slow) {
+		t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN);
+		t3_read_reg(adapter, mc7->offset + A_MC7_CAL);
+		msleep(1);
+		if (t3_read_reg(adapter, mc7->offset + A_MC7_CAL) &
+		    (F_BUSY | F_SGL_CAL_EN | F_CAL_FAULT)) {
+			CH_ERR(adapter, "%s MC7 calibration timed out\n",
+			       mc7->name);
+			goto out_fail;
+		}
+	}
+
+	t3_write_reg(adapter, mc7->offset + A_MC7_PARM,
+		     V_ACTTOPREDLY(p->ActToPreDly) |
+		     V_ACTTORDWRDLY(p->ActToRdWrDly) | V_PRECYC(p->PreCyc) |
+		     V_REFCYC(p->RefCyc[density]) | V_BKCYC(p->BkCyc) |
+		     V_WRTORDDLY(p->WrToRdDly) | V_RDTOWRDLY(p->RdToWrDly));
+
+	t3_write_reg(adapter, mc7->offset + A_MC7_CFG,
+		     val | F_CLKEN | F_TERM150);
+	t3_read_reg(adapter, mc7->offset + A_MC7_CFG);	/* flush */
+
+	if (!slow)
+		t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLENB,
+				 F_DLLENB);
+	udelay(1);
+
+	val = slow ? 3 : 6;
+	if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
+	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE2, 0) ||
+	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE3, 0) ||
+	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
+		goto out_fail;
+
+	if (!slow) {
+		t3_write_reg(adapter, mc7->offset + A_MC7_MODE, 0x100);
+		t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLRST, 0);
+		udelay(5);
+	}
+
+	if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
+	    wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
+	    wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
+	    wrreg_wait(adapter, mc7->offset + A_MC7_MODE,
+		       mc7_mode[mem_type]) ||
+	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val | 0x380) ||
+	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
+		goto out_fail;
+
+	/* clock value is in KHz */
+	mc7_clock = mc7_clock * 7812 + mc7_clock / 2;	/* ns */
+	mc7_clock /= 1000000;	/* KHz->MHz, ns->us */
+
+	t3_write_reg(adapter, mc7->offset + A_MC7_REF,
+		     F_PERREFEN | V_PREREFDIV(mc7_clock));
+	t3_read_reg(adapter, mc7->offset + A_MC7_REF);	/* flush */
+
+	t3_write_reg(adapter, mc7->offset + A_MC7_ECC, F_ECCGENEN | F_ECCCHKEN);
+	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_DATA, 0);
+	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_BEG, 0);
+	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_END,
+		     (mc7->size << width) - 1);
+	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_OP, V_OP(1));
+	t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP);	/* flush */
+
+	attempts = 50;
+	do {
+		msleep(250);
+		val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP);
+	} while ((val & F_BUSY) && --attempts);
+	if (val & F_BUSY) {
+		CH_ERR(adapter, "%s MC7 BIST timed out\n", mc7->name);
+		goto out_fail;
+	}
+
+	/* Enable normal memory accesses. */
+	t3_set_reg_field(adapter, mc7->offset + A_MC7_CFG, 0, F_RDY);
+	return 0;
+
+out_fail:
+	return -1;
+}
+
+static void config_pcie(struct adapter *adap)
+{
+	static const u16 ack_lat[4][6] = {
+		{237, 416, 559, 1071, 2095, 4143},
+		{128, 217, 289, 545, 1057, 2081},
+		{73, 118, 154, 282, 538, 1050},
+		{67, 107, 86, 150, 278, 534}
+	};
+	static const u16 rpl_tmr[4][6] = {
+		{711, 1248, 1677, 3213, 6285, 12429},
+		{384, 651, 867, 1635, 3171, 6243},
+		{219, 354, 462, 846, 1614, 3150},
+		{201, 321, 258, 450, 834, 1602}
+	};
+
+	u16 val;
+	unsigned int log2_width, pldsize;
+	unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt;
+
+	pci_read_config_word(adap->pdev,
+			     adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL,
+			     &val);
+	pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
+	pci_read_config_word(adap->pdev,
+			     adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL,
+			     &val);
+
+	fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0));
+	fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx :
+	    G_NUMFSTTRNSEQRX(t3_read_reg(adap, A_PCIE_MODE));
+	log2_width = fls(adap->params.pci.width) - 1;
+	acklat = ack_lat[log2_width][pldsize];
+	if (val & 1)		/* check LOsEnable */
+		acklat += fst_trn_tx * 4;
+	rpllmt = rpl_tmr[log2_width][pldsize] + fst_trn_rx * 4;
+
+	if (adap->params.rev == 0)
+		t3_set_reg_field(adap, A_PCIE_PEX_CTRL1,
+				 V_T3A_ACKLAT(M_T3A_ACKLAT),
+				 V_T3A_ACKLAT(acklat));
+	else
+		t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, V_ACKLAT(M_ACKLAT),
+				 V_ACKLAT(acklat));
+
+	t3_set_reg_field(adap, A_PCIE_PEX_CTRL0, V_REPLAYLMT(M_REPLAYLMT),
+			 V_REPLAYLMT(rpllmt));
+
+	t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff);
+	t3_set_reg_field(adap, A_PCIE_CFG, F_PCIE_CLIDECEN, F_PCIE_CLIDECEN);
+}
+
+/*
+ * Initialize and configure T3 HW modules.  This performs the
+ * initialization steps that need to be done once after a card is reset.
+ * MAC and PHY initialization is handled separarely whenever a port is enabled.
+ *
+ * fw_params are passed to FW and their value is platform dependent.  Only the
+ * top 8 bits are available for use, the rest must be 0.
+ */
+int t3_init_hw(struct adapter *adapter, u32 fw_params)
+{
+	int err = -EIO, attempts = 100;
+	const struct vpd_params *vpd = &adapter->params.vpd;
+
+	if (adapter->params.rev > 0)
+		calibrate_xgm_t3b(adapter);
+	else if (calibrate_xgm(adapter))
+		goto out_err;
+
+	if (vpd->mclk) {
+		partition_mem(adapter, &adapter->params.tp);
+
+		if (mc7_init(&adapter->pmrx, vpd->mclk, vpd->mem_timing) ||
+		    mc7_init(&adapter->pmtx, vpd->mclk, vpd->mem_timing) ||
+		    mc7_init(&adapter->cm, vpd->mclk, vpd->mem_timing) ||
+		    t3_mc5_init(&adapter->mc5, adapter->params.mc5.nservers,
+				adapter->params.mc5.nfilters,
+				adapter->params.mc5.nroutes))
+			goto out_err;
+	}
+
+	if (tp_init(adapter, &adapter->params.tp))
+		goto out_err;
+
+	t3_tp_set_coalescing_size(adapter,
+				  min(adapter->params.sge.max_pkt_size,
+				      MAX_RX_COALESCING_LEN), 1);
+	t3_tp_set_max_rxsize(adapter,
+			     min(adapter->params.sge.max_pkt_size, 16384U));
+	ulp_config(adapter, &adapter->params.tp);
+
+	if (is_pcie(adapter))
+		config_pcie(adapter);
+	else
+		t3_set_reg_field(adapter, A_PCIX_CFG, 0, F_CLIDECEN);
+
+	t3_write_reg(adapter, A_PM1_RX_CFG, 0xf000f000);
+	init_hw_for_avail_ports(adapter, adapter->params.nports);
+	t3_sge_init(adapter, &adapter->params.sge);
+
+	t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params);
+	t3_write_reg(adapter, A_CIM_BOOT_CFG,
+		     V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2));
+	t3_read_reg(adapter, A_CIM_BOOT_CFG);	/* flush */
+
+	do {			/* wait for uP to initialize */
+		msleep(20);
+	} while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts);
+	if (!attempts)
+		goto out_err;
+
+	err = 0;
+out_err:
+	return err;
+}
+
+/**
+ *	get_pci_mode - determine a card's PCI mode
+ *	@adapter: the adapter
+ *	@p: where to store the PCI settings
+ *
+ *	Determines a card's PCI mode and associated parameters, such as speed
+ *	and width.
+ */
+static void __devinit get_pci_mode(struct adapter *adapter,
+				   struct pci_params *p)
+{
+	static unsigned short speed_map[] = { 33, 66, 100, 133 };
+	u32 pci_mode, pcie_cap;
+
+	pcie_cap = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+	if (pcie_cap) {
+		u16 val;
+
+		p->variant = PCI_VARIANT_PCIE;
+		p->pcie_cap_addr = pcie_cap;
+		pci_read_config_word(adapter->pdev, pcie_cap + PCI_EXP_LNKSTA,
+					&val);
+		p->width = (val >> 4) & 0x3f;
+		return;
+	}
+
+	pci_mode = t3_read_reg(adapter, A_PCIX_MODE);
+	p->speed = speed_map[G_PCLKRANGE(pci_mode)];
+	p->width = (pci_mode & F_64BIT) ? 64 : 32;
+	pci_mode = G_PCIXINITPAT(pci_mode);
+	if (pci_mode == 0)
+		p->variant = PCI_VARIANT_PCI;
+	else if (pci_mode < 4)
+		p->variant = PCI_VARIANT_PCIX_MODE1_PARITY;
+	else if (pci_mode < 8)
+		p->variant = PCI_VARIANT_PCIX_MODE1_ECC;
+	else
+		p->variant = PCI_VARIANT_PCIX_266_MODE2;
+}
+
+/**
+ *	init_link_config - initialize a link's SW state
+ *	@lc: structure holding the link state
+ *	@ai: information about the current card
+ *
+ *	Initializes the SW state maintained for each link, including the link's
+ *	capabilities and default speed/duplex/flow-control/autonegotiation
+ *	settings.
+ */
+static void __devinit init_link_config(struct link_config *lc,
+				       unsigned int caps)
+{
+	lc->supported = caps;
+	lc->requested_speed = lc->speed = SPEED_INVALID;
+	lc->requested_duplex = lc->duplex = DUPLEX_INVALID;
+	lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
+	if (lc->supported & SUPPORTED_Autoneg) {
+		lc->advertising = lc->supported;
+		lc->autoneg = AUTONEG_ENABLE;
+		lc->requested_fc |= PAUSE_AUTONEG;
+	} else {
+		lc->advertising = 0;
+		lc->autoneg = AUTONEG_DISABLE;
+	}
+}
+
+/**
+ *	mc7_calc_size - calculate MC7 memory size
+ *	@cfg: the MC7 configuration
+ *
+ *	Calculates the size of an MC7 memory in bytes from the value of its
+ *	configuration register.
+ */
+static unsigned int __devinit mc7_calc_size(u32 cfg)
+{
+	unsigned int width = G_WIDTH(cfg);
+	unsigned int banks = !!(cfg & F_BKS) + 1;
+	unsigned int org = !!(cfg & F_ORG) + 1;
+	unsigned int density = G_DEN(cfg);
+	unsigned int MBs = ((256 << density) * banks) / (org << width);
+
+	return MBs << 20;
+}
+
+static void __devinit mc7_prep(struct adapter *adapter, struct mc7 *mc7,
+			       unsigned int base_addr, const char *name)
+{
+	u32 cfg;
+
+	mc7->adapter = adapter;
+	mc7->name = name;
+	mc7->offset = base_addr - MC7_PMRX_BASE_ADDR;
+	cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
+	mc7->size = mc7_calc_size(cfg);
+	mc7->width = G_WIDTH(cfg);
+}
+
+void mac_prep(struct cmac *mac, struct adapter *adapter, int index)
+{
+	mac->adapter = adapter;
+	mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index;
+	mac->nucast = 1;
+
+	if (adapter->params.rev == 0 && uses_xaui(adapter)) {
+		t3_write_reg(adapter, A_XGM_SERDES_CTRL + mac->offset,
+			     is_10G(adapter) ? 0x2901c04 : 0x2301c04);
+		t3_set_reg_field(adapter, A_XGM_PORT_CFG + mac->offset,
+				 F_ENRGMII, 0);
+	}
+}
+
+void early_hw_init(struct adapter *adapter, const struct adapter_info *ai)
+{
+	u32 val = V_PORTSPEED(is_10G(adapter) ? 3 : 2);
+
+	mi1_init(adapter, ai);
+	t3_write_reg(adapter, A_I2C_CFG,	/* set for 80KHz */
+		     V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1));
+	t3_write_reg(adapter, A_T3DBG_GPIO_EN,
+		     ai->gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL);
+
+	if (adapter->params.rev == 0 || !uses_xaui(adapter))
+		val |= F_ENRGMII;
+
+	/* Enable MAC clocks so we can access the registers */
+	t3_write_reg(adapter, A_XGM_PORT_CFG, val);
+	t3_read_reg(adapter, A_XGM_PORT_CFG);
+
+	val |= F_CLKDIVRESET_;
+	t3_write_reg(adapter, A_XGM_PORT_CFG, val);
+	t3_read_reg(adapter, A_XGM_PORT_CFG);
+	t3_write_reg(adapter, XGM_REG(A_XGM_PORT_CFG, 1), val);
+	t3_read_reg(adapter, A_XGM_PORT_CFG);
+}
+
+/*
+ * Reset the adapter.  PCIe cards lose their config space during reset, PCI-X
+ * ones don't.
+ */
+int t3_reset_adapter(struct adapter *adapter)
+{
+	int i;
+	uint16_t devid = 0;
+
+	if (is_pcie(adapter))
+		pci_save_state(adapter->pdev);
+	t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE);
+
+	/*
+	 * Delay. Give Some time to device to reset fully.
+	 * XXX The delay time should be modified.
+	 */
+	for (i = 0; i < 10; i++) {
+		msleep(50);
+		pci_read_config_word(adapter->pdev, 0x00, &devid);
+		if (devid == 0x1425)
+			break;
+	}
+
+	if (devid != 0x1425)
+		return -1;
+
+	if (is_pcie(adapter))
+		pci_restore_state(adapter->pdev);
+	return 0;
+}
+
+/*
+ * Initialize adapter SW state for the various HW modules, set initial values
+ * for some adapter tunables, take PHYs out of reset, and initialize the MDIO
+ * interface.
+ */
+int __devinit t3_prep_adapter(struct adapter *adapter,
+			      const struct adapter_info *ai, int reset)
+{
+	int ret;
+	unsigned int i, j = 0;
+
+	get_pci_mode(adapter, &adapter->params.pci);
+
+	adapter->params.info = ai;
+	adapter->params.nports = ai->nports;
+	adapter->params.rev = t3_read_reg(adapter, A_PL_REV);
+	adapter->params.linkpoll_period = 0;
+	adapter->params.stats_update_period = is_10G(adapter) ?
+	    MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10);
+	adapter->params.pci.vpd_cap_addr =
+	    pci_find_capability(adapter->pdev, PCI_CAP_ID_VPD);
+	ret = get_vpd_params(adapter, &adapter->params.vpd);
+	if (ret < 0)
+		return ret;
+
+	if (reset && t3_reset_adapter(adapter))
+		return -1;
+
+	t3_sge_prep(adapter, &adapter->params.sge);
+
+	if (adapter->params.vpd.mclk) {
+		struct tp_params *p = &adapter->params.tp;
+
+		mc7_prep(adapter, &adapter->pmrx, MC7_PMRX_BASE_ADDR, "PMRX");
+		mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX");
+		mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM");
+
+		p->nchan = ai->nports;
+		p->pmrx_size = t3_mc7_size(&adapter->pmrx);
+		p->pmtx_size = t3_mc7_size(&adapter->pmtx);
+		p->cm_size = t3_mc7_size(&adapter->cm);
+		p->chan_rx_size = p->pmrx_size / 2;	/* only 1 Rx channel */
+		p->chan_tx_size = p->pmtx_size / p->nchan;
+		p->rx_pg_size = 64 * 1024;
+		p->tx_pg_size = is_10G(adapter) ? 64 * 1024 : 16 * 1024;
+		p->rx_num_pgs = pm_num_pages(p->chan_rx_size, p->rx_pg_size);
+		p->tx_num_pgs = pm_num_pages(p->chan_tx_size, p->tx_pg_size);
+		p->ntimer_qs = p->cm_size >= (128 << 20) ||
+		    adapter->params.rev > 0 ? 12 : 6;
+
+		adapter->params.mc5.nservers = DEFAULT_NSERVERS;
+		adapter->params.mc5.nfilters = adapter->params.rev > 0 ?
+		    DEFAULT_NFILTERS : 0;
+		adapter->params.mc5.nroutes = 0;
+		t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT);
+
+		init_mtus(adapter->params.mtus);
+		init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
+	}
+
+	early_hw_init(adapter, ai);
+
+	for_each_port(adapter, i) {
+		u8 hw_addr[6];
+		struct port_info *p = adap2pinfo(adapter, i);
+
+		while (!adapter->params.vpd.port_type[j])
+			++j;
+
+		p->port_type = &port_types[adapter->params.vpd.port_type[j]];
+		p->port_type->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
+				       ai->mdio_ops);
+		mac_prep(&p->mac, adapter, j);
+		++j;
+
+		/*
+		 * The VPD EEPROM stores the base Ethernet address for the
+		 * card.  A port's address is derived from the base by adding
+		 * the port's index to the base's low octet.
+		 */
+		memcpy(hw_addr, adapter->params.vpd.eth_base, 5);
+		hw_addr[5] = adapter->params.vpd.eth_base[5] + i;
+
+		memcpy(adapter->port[i]->dev_addr, hw_addr,
+		       ETH_ALEN);
+		memcpy(adapter->port[i]->perm_addr, hw_addr,
+		       ETH_ALEN);
+		init_link_config(&p->link_config, p->port_type->caps);
+		p->phy.ops->power_down(&p->phy, 1);
+		if (!(p->port_type->caps & SUPPORTED_IRQ))
+			adapter->params.linkpoll_period = 10;
+	}
+
+	return 0;
+}
+
+void t3_led_ready(struct adapter *adapter)
+{
+	t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
+			 F_GPIO0_OUT_VAL);
+}
diff --git a/drivers/net/cxgb3/t3cdev.h b/drivers/net/cxgb3/t3cdev.h
new file mode 100644
index 0000000..9af3bcd
--- /dev/null
+++ b/drivers/net/cxgb3/t3cdev.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2006-2007 Chelsio Communications.  All rights reserved.
+ * Copyright (C) 2006-2007 Open Grid Computing, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _T3CDEV_H_
+#define _T3CDEV_H_
+
+#include <linux/list.h>
+#include <asm/atomic.h>
+#include <asm/semaphore.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <net/neighbour.h>
+
+#define T3CNAMSIZ 16
+
+/* Get the t3cdev associated with a net_device */
+#define T3CDEV(netdev) (struct t3cdev *)(netdev->priv)
+
+struct cxgb3_client;
+
+enum t3ctype {
+	T3A = 0,
+	T3B
+};
+
+struct t3cdev {
+	char name[T3CNAMSIZ];	/* T3C device name */
+	enum t3ctype type;
+	struct list_head ofld_dev_list;	/* for list linking */
+	struct net_device *lldev;	/* LL dev associated with T3C messages */
+	struct proc_dir_entry *proc_dir;	/* root of proc dir for this T3C */
+	int (*send)(struct t3cdev *dev, struct sk_buff *skb);
+	int (*recv)(struct t3cdev *dev, struct sk_buff **skb, int n);
+	int (*ctl)(struct t3cdev *dev, unsigned int req, void *data);
+	void (*neigh_update)(struct t3cdev *dev, struct neighbour *neigh);
+	void *priv;		/* driver private data */
+	void *l2opt;		/* optional layer 2 data */
+	void *l3opt;		/* optional layer 3 data */
+	void *l4opt;		/* optional layer 4 data */
+	void *ulp;		/* ulp stuff */
+};
+
+#endif				/* _T3CDEV_H_ */
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
new file mode 100644
index 0000000..2b67dd5
--- /dev/null
+++ b/drivers/net/cxgb3/version.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $Date: 2006/10/31 18:57:51 $ $RCSfile: version.h,v $ $Revision: 1.3 $ */
+#ifndef __CHELSIO_VERSION_H
+#define __CHELSIO_VERSION_H
+#define DRV_DESC "Chelsio T3 Network Driver"
+#define DRV_NAME "cxgb3"
+/* Driver version */
+#define DRV_VERSION "1.0"
+#endif				/* __CHELSIO_VERSION_H */
diff --git a/drivers/net/cxgb3/vsc8211.c b/drivers/net/cxgb3/vsc8211.c
new file mode 100644
index 0000000..eee4285
--- /dev/null
+++ b/drivers/net/cxgb3/vsc8211.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+
+/* VSC8211 PHY specific registers. */
+enum {
+	VSC8211_INTR_ENABLE = 25,
+	VSC8211_INTR_STATUS = 26,
+	VSC8211_AUX_CTRL_STAT = 28,
+};
+
+enum {
+	VSC_INTR_RX_ERR = 1 << 0,
+	VSC_INTR_MS_ERR = 1 << 1,	/* master/slave resolution error */
+	VSC_INTR_CABLE = 1 << 2,	/* cable impairment */
+	VSC_INTR_FALSE_CARR = 1 << 3,	/* false carrier */
+	VSC_INTR_MEDIA_CHG = 1 << 4,	/* AMS media change */
+	VSC_INTR_RX_FIFO = 1 << 5,	/* Rx FIFO over/underflow */
+	VSC_INTR_TX_FIFO = 1 << 6,	/* Tx FIFO over/underflow */
+	VSC_INTR_DESCRAMBL = 1 << 7,	/* descrambler lock-lost */
+	VSC_INTR_SYMBOL_ERR = 1 << 8,	/* symbol error */
+	VSC_INTR_NEG_DONE = 1 << 10,	/* autoneg done */
+	VSC_INTR_NEG_ERR = 1 << 11,	/* autoneg error */
+	VSC_INTR_LINK_CHG = 1 << 13,	/* link change */
+	VSC_INTR_ENABLE = 1 << 15,	/* interrupt enable */
+};
+
+#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
+	 		   VSC_INTR_NEG_DONE)
+#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
+		   VSC_INTR_ENABLE)
+
+/* PHY specific auxiliary control & status register fields */
+#define S_ACSR_ACTIPHY_TMR    0
+#define M_ACSR_ACTIPHY_TMR    0x3
+#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR)
+
+#define S_ACSR_SPEED    3
+#define M_ACSR_SPEED    0x3
+#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED)
+
+#define S_ACSR_DUPLEX 5
+#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
+
+#define S_ACSR_ACTIPHY 6
+#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
+
+/*
+ * Reset the PHY.  This PHY completes reset immediately so we never wait.
+ */
+static int vsc8211_reset(struct cphy *cphy, int wait)
+{
+	return t3_phy_reset(cphy, 0, 0);
+}
+
+static int vsc8211_intr_enable(struct cphy *cphy)
+{
+	return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, INTR_MASK);
+}
+
+static int vsc8211_intr_disable(struct cphy *cphy)
+{
+	return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, 0);
+}
+
+static int vsc8211_intr_clear(struct cphy *cphy)
+{
+	u32 val;
+
+	/* Clear PHY interrupts by reading the register. */
+	return mdio_read(cphy, 0, VSC8211_INTR_STATUS, &val);
+}
+
+static int vsc8211_autoneg_enable(struct cphy *cphy)
+{
+	return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
+				   BMCR_ANENABLE | BMCR_ANRESTART);
+}
+
+static int vsc8211_autoneg_restart(struct cphy *cphy)
+{
+	return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
+				   BMCR_ANRESTART);
+}
+
+static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok,
+				   int *speed, int *duplex, int *fc)
+{
+	unsigned int bmcr, status, lpa, adv;
+	int err, sp = -1, dplx = -1, pause = 0;
+
+	err = mdio_read(cphy, 0, MII_BMCR, &bmcr);
+	if (!err)
+		err = mdio_read(cphy, 0, MII_BMSR, &status);
+	if (err)
+		return err;
+
+	if (link_ok) {
+		/*
+		 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
+		 * once more to get the current link state.
+		 */
+		if (!(status & BMSR_LSTATUS))
+			err = mdio_read(cphy, 0, MII_BMSR, &status);
+		if (err)
+			return err;
+		*link_ok = (status & BMSR_LSTATUS) != 0;
+	}
+	if (!(bmcr & BMCR_ANENABLE)) {
+		dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+		if (bmcr & BMCR_SPEED1000)
+			sp = SPEED_1000;
+		else if (bmcr & BMCR_SPEED100)
+			sp = SPEED_100;
+		else
+			sp = SPEED_10;
+	} else if (status & BMSR_ANEGCOMPLETE) {
+		err = mdio_read(cphy, 0, VSC8211_AUX_CTRL_STAT, &status);
+		if (err)
+			return err;
+
+		dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
+		sp = G_ACSR_SPEED(status);
+		if (sp == 0)
+			sp = SPEED_10;
+		else if (sp == 1)
+			sp = SPEED_100;
+		else
+			sp = SPEED_1000;
+
+		if (fc && dplx == DUPLEX_FULL) {
+			err = mdio_read(cphy, 0, MII_LPA, &lpa);
+			if (!err)
+				err = mdio_read(cphy, 0, MII_ADVERTISE, &adv);
+			if (err)
+				return err;
+
+			if (lpa & adv & ADVERTISE_PAUSE_CAP)
+				pause = PAUSE_RX | PAUSE_TX;
+			else if ((lpa & ADVERTISE_PAUSE_CAP) &&
+				 (lpa & ADVERTISE_PAUSE_ASYM) &&
+				 (adv & ADVERTISE_PAUSE_ASYM))
+				pause = PAUSE_TX;
+			else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
+				 (adv & ADVERTISE_PAUSE_CAP))
+				pause = PAUSE_RX;
+		}
+	}
+	if (speed)
+		*speed = sp;
+	if (duplex)
+		*duplex = dplx;
+	if (fc)
+		*fc = pause;
+	return 0;
+}
+
+static int vsc8211_power_down(struct cphy *cphy, int enable)
+{
+	return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
+				   enable ? BMCR_PDOWN : 0);
+}
+
+static int vsc8211_intr_handler(struct cphy *cphy)
+{
+	unsigned int cause;
+	int err, cphy_cause = 0;
+
+	err = mdio_read(cphy, 0, VSC8211_INTR_STATUS, &cause);
+	if (err)
+		return err;
+
+	cause &= INTR_MASK;
+	if (cause & CFG_CHG_INTR_MASK)
+		cphy_cause |= cphy_cause_link_change;
+	if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO))
+		cphy_cause |= cphy_cause_fifo_error;
+	return cphy_cause;
+}
+
+static struct cphy_ops vsc8211_ops = {
+	.reset = vsc8211_reset,
+	.intr_enable = vsc8211_intr_enable,
+	.intr_disable = vsc8211_intr_disable,
+	.intr_clear = vsc8211_intr_clear,
+	.intr_handler = vsc8211_intr_handler,
+	.autoneg_enable = vsc8211_autoneg_enable,
+	.autoneg_restart = vsc8211_autoneg_restart,
+	.advertise = t3_phy_advertise,
+	.set_speed_duplex = t3_set_phy_speed_duplex,
+	.get_link_status = vsc8211_get_link_status,
+	.power_down = vsc8211_power_down,
+};
+
+void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
+			 int phy_addr, const struct mdio_ops *mdio_ops)
+{
+	cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops);
+}
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
new file mode 100644
index 0000000..907a272
--- /dev/null
+++ b/drivers/net/cxgb3/xgmac.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+
+/*
+ * # of exact address filters.  The first one is used for the station address,
+ * the rest are available for multicast addresses.
+ */
+#define EXACT_ADDR_FILTERS 8
+
+static inline int macidx(const struct cmac *mac)
+{
+	return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);
+}
+
+static void xaui_serdes_reset(struct cmac *mac)
+{
+	static const unsigned int clear[] = {
+		F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1,
+		F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3
+	};
+
+	int i;
+	struct adapter *adap = mac->adapter;
+	u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset;
+
+	t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] |
+		     F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 |
+		     F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 |
+		     F_RESETPLL23 | F_RESETPLL01);
+	t3_read_reg(adap, ctrl);
+	udelay(15);
+
+	for (i = 0; i < ARRAY_SIZE(clear); i++) {
+		t3_set_reg_field(adap, ctrl, clear[i], 0);
+		udelay(15);
+	}
+}
+
+void t3b_pcs_reset(struct cmac *mac)
+{
+	t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
+			 F_PCS_RESET_, 0);
+	udelay(20);
+	t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0,
+			 F_PCS_RESET_);
+}
+
+int t3_mac_reset(struct cmac *mac)
+{
+	static const struct addr_val_pair mac_reset_avp[] = {
+		{A_XGM_TX_CTRL, 0},
+		{A_XGM_RX_CTRL, 0},
+		{A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES |
+		 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST},
+		{A_XGM_RX_HASH_LOW, 0},
+		{A_XGM_RX_HASH_HIGH, 0},
+		{A_XGM_RX_EXACT_MATCH_LOW_1, 0},
+		{A_XGM_RX_EXACT_MATCH_LOW_2, 0},
+		{A_XGM_RX_EXACT_MATCH_LOW_3, 0},
+		{A_XGM_RX_EXACT_MATCH_LOW_4, 0},
+		{A_XGM_RX_EXACT_MATCH_LOW_5, 0},
+		{A_XGM_RX_EXACT_MATCH_LOW_6, 0},
+		{A_XGM_RX_EXACT_MATCH_LOW_7, 0},
+		{A_XGM_RX_EXACT_MATCH_LOW_8, 0},
+		{A_XGM_STAT_CTRL, F_CLRSTATS}
+	};
+	u32 val;
+	struct adapter *adap = mac->adapter;
+	unsigned int oft = mac->offset;
+
+	t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
+	t3_read_reg(adap, A_XGM_RESET_CTRL + oft);	/* flush */
+
+	t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft);
+	t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,
+			 F_RXSTRFRWRD | F_DISERRFRAMES,
+			 uses_xaui(adap) ? 0 : F_RXSTRFRWRD);
+
+	if (uses_xaui(adap)) {
+		if (adap->params.rev == 0) {
+			t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
+					 F_RXENABLE | F_TXENABLE);
+			if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft,
+					    F_CMULOCK, 1, 5, 2)) {
+				CH_ERR(adap,
+				       "MAC %d XAUI SERDES CMU lock failed\n",
+				       macidx(mac));
+				return -1;
+			}
+			t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
+					 F_SERDESRESET_);
+		} else
+			xaui_serdes_reset(mac);
+	}
+
+	if (adap->params.rev > 0)
+		t3_write_reg(adap, A_XGM_PAUSE_TIMER + oft, 0xf000);
+
+	val = F_MAC_RESET_;
+	if (is_10G(adap))
+		val |= F_PCS_RESET_;
+	else if (uses_xaui(adap))
+		val |= F_PCS_RESET_ | F_XG2G_RESET_;
+	else
+		val |= F_RGMII_RESET_ | F_XG2G_RESET_;
+	t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
+	t3_read_reg(adap, A_XGM_RESET_CTRL + oft);	/* flush */
+	if ((val & F_PCS_RESET_) && adap->params.rev) {
+		msleep(1);
+		t3b_pcs_reset(mac);
+	}
+
+	memset(&mac->stats, 0, sizeof(mac->stats));
+	return 0;
+}
+
+/*
+ * Set the exact match register 'idx' to recognize the given Ethernet address.
+ */
+static void set_addr_filter(struct cmac *mac, int idx, const u8 * addr)
+{
+	u32 addr_lo, addr_hi;
+	unsigned int oft = mac->offset + idx * 8;
+
+	addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
+	addr_hi = (addr[5] << 8) | addr[4];
+
+	t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo);
+	t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);
+}
+
+/* Set one of the station's unicast MAC addresses. */
+int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6])
+{
+	if (idx >= mac->nucast)
+		return -EINVAL;
+	set_addr_filter(mac, idx, addr);
+	return 0;
+}
+
+/*
+ * Specify the number of exact address filters that should be reserved for
+ * unicast addresses.  Caller should reload the unicast and multicast addresses
+ * after calling this.
+ */
+int t3_mac_set_num_ucast(struct cmac *mac, int n)
+{
+	if (n > EXACT_ADDR_FILTERS)
+		return -EINVAL;
+	mac->nucast = n;
+	return 0;
+}
+
+/* Calculate the RX hash filter index of an Ethernet address */
+static int hash_hw_addr(const u8 * addr)
+{
+	int hash = 0, octet, bit, i = 0, c;
+
+	for (octet = 0; octet < 6; ++octet)
+		for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) {
+			hash ^= (c & 1) << i;
+			if (++i == 6)
+				i = 0;
+		}
+	return hash;
+}
+
+int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
+{
+	u32 val, hash_lo, hash_hi;
+	struct adapter *adap = mac->adapter;
+	unsigned int oft = mac->offset;
+
+	val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES;
+	if (rm->dev->flags & IFF_PROMISC)
+		val |= F_COPYALLFRAMES;
+	t3_write_reg(adap, A_XGM_RX_CFG + oft, val);
+
+	if (rm->dev->flags & IFF_ALLMULTI)
+		hash_lo = hash_hi = 0xffffffff;
+	else {
+		u8 *addr;
+		int exact_addr_idx = mac->nucast;
+
+		hash_lo = hash_hi = 0;
+		while ((addr = t3_get_next_mcaddr(rm)))
+			if (exact_addr_idx < EXACT_ADDR_FILTERS)
+				set_addr_filter(mac, exact_addr_idx++, addr);
+			else {
+				int hash = hash_hw_addr(addr);
+
+				if (hash < 32)
+					hash_lo |= (1 << hash);
+				else
+					hash_hi |= (1 << (hash - 32));
+			}
+	}
+
+	t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo);
+	t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi);
+	return 0;
+}
+
+int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
+{
+	int hwm, lwm;
+	unsigned int thres, v;
+	struct adapter *adap = mac->adapter;
+
+	/*
+	 * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't.  The HW max
+	 * packet size register includes header, but not FCS.
+	 */
+	mtu += 14;
+	if (mtu > MAX_FRAME_SIZE - 4)
+		return -EINVAL;
+	t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);
+
+	/*
+	 * Adjust the PAUSE frame watermarks.  We always set the LWM, and the
+	 * HWM only if flow-control is enabled.
+	 */
+	hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, MAC_RXFIFO_SIZE / 2U);
+	hwm = min(hwm, 3 * MAC_RXFIFO_SIZE / 4 + 1024);
+	lwm = hwm - 1024;
+	v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
+	v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
+	v |= V_RXFIFOPAUSELWM(lwm / 8);
+	if (G_RXFIFOPAUSEHWM(v))
+		v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
+		    V_RXFIFOPAUSEHWM(hwm / 8);
+	t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
+
+	/* Adjust the TX FIFO threshold based on the MTU */
+	thres = (adap->params.vpd.cclk * 1000) / 15625;
+	thres = (thres * mtu) / 1000;
+	if (is_10G(adap))
+		thres /= 10;
+	thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
+	thres = max(thres, 8U);	/* need at least 8 */
+	t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
+			 V_TXFIFOTHRESH(M_TXFIFOTHRESH), V_TXFIFOTHRESH(thres));
+	return 0;
+}
+
+int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
+{
+	u32 val;
+	struct adapter *adap = mac->adapter;
+	unsigned int oft = mac->offset;
+
+	if (duplex >= 0 && duplex != DUPLEX_FULL)
+		return -EINVAL;
+	if (speed >= 0) {
+		if (speed == SPEED_10)
+			val = V_PORTSPEED(0);
+		else if (speed == SPEED_100)
+			val = V_PORTSPEED(1);
+		else if (speed == SPEED_1000)
+			val = V_PORTSPEED(2);
+		else if (speed == SPEED_10000)
+			val = V_PORTSPEED(3);
+		else
+			return -EINVAL;
+
+		t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
+				 V_PORTSPEED(M_PORTSPEED), val);
+	}
+
+	val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
+	val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
+	if (fc & PAUSE_TX)
+		val |= V_RXFIFOPAUSEHWM(G_RXFIFOPAUSELWM(val) + 128);	/* +1KB */
+	t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
+
+	t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
+			 (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
+	return 0;
+}
+
+int t3_mac_enable(struct cmac *mac, int which)
+{
+	int idx = macidx(mac);
+	struct adapter *adap = mac->adapter;
+	unsigned int oft = mac->offset;
+
+	if (which & MAC_DIRECTION_TX) {
+		t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
+		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
+		t3_write_reg(adap, A_TP_PIO_DATA, 0xbf000001);
+		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
+		t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
+	}
+	if (which & MAC_DIRECTION_RX)
+		t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
+	return 0;
+}
+
+int t3_mac_disable(struct cmac *mac, int which)
+{
+	int idx = macidx(mac);
+	struct adapter *adap = mac->adapter;
+
+	if (which & MAC_DIRECTION_TX) {
+		t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
+		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
+		t3_write_reg(adap, A_TP_PIO_DATA, 0xc000001f);
+		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
+		t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 0);
+	}
+	if (which & MAC_DIRECTION_RX)
+		t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
+	return 0;
+}
+
+/*
+ * This function is called periodically to accumulate the current values of the
+ * RMON counters into the port statistics.  Since the packet counters are only
+ * 32 bits they can overflow in ~286 secs at 10G, so the function should be
+ * called more frequently than that.  The byte counters are 45-bit wide, they
+ * would overflow in ~7.8 hours.
+ */
+const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
+{
+#define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
+#define RMON_UPDATE(mac, name, reg) \
+	(mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
+#define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
+	(mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
+			     ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
+
+	u32 v, lo;
+
+	RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);
+	RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);
+	RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);
+	RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);
+	RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);
+	RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);
+	RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);
+	RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);
+	RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);
+
+	RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
+	mac->stats.rx_too_long += RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
+
+	RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES);
+	RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES);
+	RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES);
+	RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES);
+	RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES);
+	RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);
+	RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES);
+
+	RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);
+	RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);
+	RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);
+	RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);
+	RMON_UPDATE(mac, tx_pause, TX_PAUSE);
+	/* This counts error frames in general (bad FCS, underrun, etc). */
+	RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);
+
+	RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES);
+	RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES);
+	RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES);
+	RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES);
+	RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES);
+	RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);
+	RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES);
+
+	/* The next stat isn't clear-on-read. */
+	t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);
+	v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);
+	lo = (u32) mac->stats.rx_cong_drops;
+	mac->stats.rx_cong_drops += (u64) (v - lo);
+
+	return &mac->stats;
+}
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index 4ae0fed..9f7e1db 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -5,7 +5,7 @@
  *
  *      adopted from sunlance.c by Richard van den Berg
  *
- *      Copyright (C) 2002, 2003, 2005  Maciej W. Rozycki
+ *      Copyright (C) 2002, 2003, 2005, 2006  Maciej W. Rozycki
  *
  *      additional sources:
  *      - PMAD-AA TURBOchannel Ethernet Module Functional Specification,
@@ -44,6 +44,8 @@
  *      v0.010: Fixes for the PMAD mapping of the LANCE buffer and for the
  *              PMAX requirement to only use halfword accesses to the
  *              buffer. macro
+ *
+ *      v0.011: Converted the PMAD to the driver model. macro
  */
 
 #include <linux/crc32.h>
@@ -58,6 +60,7 @@
 #include <linux/spinlock.h>
 #include <linux/stddef.h>
 #include <linux/string.h>
+#include <linux/tc.h>
 #include <linux/types.h>
 
 #include <asm/addrspace.h>
@@ -69,15 +72,16 @@
 #include <asm/dec/kn01.h>
 #include <asm/dec/machtype.h>
 #include <asm/dec/system.h>
-#include <asm/dec/tc.h>
 
 static char version[] __devinitdata =
-"declance.c: v0.010 by Linux MIPS DECstation task force\n";
+"declance.c: v0.011 by Linux MIPS DECstation task force\n";
 
 MODULE_AUTHOR("Linux MIPS DECstation task force");
 MODULE_DESCRIPTION("DEC LANCE (DECstation onboard, PMAD-xx) driver");
 MODULE_LICENSE("GPL");
 
+#define __unused __attribute__ ((unused))
+
 /*
  * card types
  */
@@ -246,7 +250,6 @@
 struct lance_private {
 	struct net_device *next;
 	int type;
-	int slot;
 	int dma_irq;
 	volatile struct lance_regs *ll;
 
@@ -288,6 +291,7 @@
 
 int dec_lance_debug = 2;
 
+static struct tc_driver dec_lance_tc_driver;
 static struct net_device *root_lance_dev;
 
 static inline void writereg(volatile unsigned short *regptr, short value)
@@ -1023,7 +1027,7 @@
 	lance_set_multicast(dev);
 }
 
-static int __init dec_lance_init(const int type, const int slot)
+static int __init dec_lance_probe(struct device *bdev, const int type)
 {
 	static unsigned version_printed;
 	static const char fmt[] = "declance%d";
@@ -1031,6 +1035,7 @@
 	struct net_device *dev;
 	struct lance_private *lp;
 	volatile struct lance_regs *ll;
+	resource_size_t start = 0, len = 0;
 	int i, ret;
 	unsigned long esar_base;
 	unsigned char *esar;
@@ -1038,14 +1043,18 @@
 	if (dec_lance_debug && version_printed++ == 0)
 		printk(version);
 
-	i = 0;
-	dev = root_lance_dev;
-	while (dev) {
-		i++;
-		lp = (struct lance_private *)dev->priv;
-		dev = lp->next;
+	if (bdev)
+		snprintf(name, sizeof(name), "%s", bdev->bus_id);
+	else {
+		i = 0;
+		dev = root_lance_dev;
+		while (dev) {
+			i++;
+			lp = (struct lance_private *)dev->priv;
+			dev = lp->next;
+		}
+		snprintf(name, sizeof(name), fmt, i);
 	}
-	snprintf(name, sizeof(name), fmt, i);
 
 	dev = alloc_etherdev(sizeof(struct lance_private));
 	if (!dev) {
@@ -1063,7 +1072,6 @@
 	spin_lock_init(&lp->lock);
 
 	lp->type = type;
-	lp->slot = slot;
 	switch (type) {
 	case ASIC_LANCE:
 		dev->base_addr = CKSEG1ADDR(dec_kn_slot_base + IOASIC_LANCE);
@@ -1110,12 +1118,22 @@
 		break;
 #ifdef CONFIG_TC
 	case PMAD_LANCE:
-		claim_tc_card(slot);
+		dev_set_drvdata(bdev, dev);
 
-		dev->mem_start = CKSEG1ADDR(get_tc_base_addr(slot));
+		start = to_tc_dev(bdev)->resource.start;
+		len = to_tc_dev(bdev)->resource.end - start + 1;
+		if (!request_mem_region(start, len, bdev->bus_id)) {
+			printk(KERN_ERR
+			       "%s: Unable to reserve MMIO resource\n",
+			       bdev->bus_id);
+			ret = -EBUSY;
+			goto err_out_dev;
+		}
+
+		dev->mem_start = CKSEG1ADDR(start);
 		dev->mem_end = dev->mem_start + 0x100000;
 		dev->base_addr = dev->mem_start + 0x100000;
-		dev->irq = get_tc_irq_nr(slot);
+		dev->irq = to_tc_dev(bdev)->interrupt;
 		esar_base = dev->mem_start + 0x1c0002;
 		lp->dma_irq = -1;
 
@@ -1174,7 +1192,7 @@
 		printk(KERN_ERR "%s: declance_init called with unknown type\n",
 			name);
 		ret = -ENODEV;
-		goto err_out_free_dev;
+		goto err_out_dev;
 	}
 
 	ll = (struct lance_regs *) dev->base_addr;
@@ -1188,7 +1206,7 @@
 			"%s: Ethernet station address prom not found!\n",
 			name);
 		ret = -ENODEV;
-		goto err_out_free_dev;
+		goto err_out_resource;
 	}
 	/* Check the prom contents */
 	for (i = 0; i < 8; i++) {
@@ -1198,7 +1216,7 @@
 			printk(KERN_ERR "%s: Something is wrong with the "
 				"ethernet station address prom!\n", name);
 			ret = -ENODEV;
-			goto err_out_free_dev;
+			goto err_out_resource;
 		}
 	}
 
@@ -1255,48 +1273,51 @@
 	if (ret) {
 		printk(KERN_ERR
 			"%s: Unable to register netdev, aborting.\n", name);
-		goto err_out_free_dev;
+		goto err_out_resource;
 	}
 
-	lp->next = root_lance_dev;
-	root_lance_dev = dev;
+	if (!bdev) {
+		lp->next = root_lance_dev;
+		root_lance_dev = dev;
+	}
 
 	printk("%s: registered as %s.\n", name, dev->name);
 	return 0;
 
-err_out_free_dev:
+err_out_resource:
+	if (bdev)
+		release_mem_region(start, len);
+
+err_out_dev:
 	free_netdev(dev);
 
 err_out:
 	return ret;
 }
 
+static void __exit dec_lance_remove(struct device *bdev)
+{
+	struct net_device *dev = dev_get_drvdata(bdev);
+	resource_size_t start, len;
+
+	unregister_netdev(dev);
+	start = to_tc_dev(bdev)->resource.start;
+	len = to_tc_dev(bdev)->resource.end - start + 1;
+	release_mem_region(start, len);
+	free_netdev(dev);
+}
 
 /* Find all the lance cards on the system and initialize them */
-static int __init dec_lance_probe(void)
+static int __init dec_lance_platform_probe(void)
 {
 	int count = 0;
 
-	/* Scan slots for PMAD-AA cards first. */
-#ifdef CONFIG_TC
-	if (TURBOCHANNEL) {
-		int slot;
-
-		while ((slot = search_tc_card("PMAD-AA")) >= 0) {
-			if (dec_lance_init(PMAD_LANCE, slot) < 0)
-				break;
-			count++;
-		}
-	}
-#endif
-
-	/* Then handle onboard devices. */
 	if (dec_interrupt[DEC_IRQ_LANCE] >= 0) {
 		if (dec_interrupt[DEC_IRQ_LANCE_MERR] >= 0) {
-			if (dec_lance_init(ASIC_LANCE, -1) >= 0)
+			if (dec_lance_probe(NULL, ASIC_LANCE) >= 0)
 				count++;
 		} else if (!TURBOCHANNEL) {
-			if (dec_lance_init(PMAX_LANCE, -1) >= 0)
+			if (dec_lance_probe(NULL, PMAX_LANCE) >= 0)
 				count++;
 		}
 	}
@@ -1304,21 +1325,70 @@
 	return (count > 0) ? 0 : -ENODEV;
 }
 
-static void __exit dec_lance_cleanup(void)
+static void __exit dec_lance_platform_remove(void)
 {
 	while (root_lance_dev) {
 		struct net_device *dev = root_lance_dev;
 		struct lance_private *lp = netdev_priv(dev);
 
 		unregister_netdev(dev);
-#ifdef CONFIG_TC
-		if (lp->slot >= 0)
-			release_tc_card(lp->slot);
-#endif
 		root_lance_dev = lp->next;
 		free_netdev(dev);
 	}
 }
 
-module_init(dec_lance_probe);
-module_exit(dec_lance_cleanup);
+#ifdef CONFIG_TC
+static int __init dec_lance_tc_probe(struct device *dev);
+static int __exit dec_lance_tc_remove(struct device *dev);
+
+static const struct tc_device_id dec_lance_tc_table[] = {
+	{ "DEC     ", "PMAD-AA " },
+	{ }
+};
+MODULE_DEVICE_TABLE(tc, dec_lance_tc_table);
+
+static struct tc_driver dec_lance_tc_driver = {
+	.id_table	= dec_lance_tc_table,
+	.driver		= {
+		.name	= "declance",
+		.bus	= &tc_bus_type,
+		.probe	= dec_lance_tc_probe,
+		.remove	= __exit_p(dec_lance_tc_remove),
+	},
+};
+
+static int __init dec_lance_tc_probe(struct device *dev)
+{
+        int status = dec_lance_probe(dev, PMAD_LANCE);
+        if (!status)
+                get_device(dev);
+        return status;
+}
+
+static int __exit dec_lance_tc_remove(struct device *dev)
+{
+        put_device(dev);
+        dec_lance_remove(dev);
+        return 0;
+}
+#endif
+
+static int __init dec_lance_init(void)
+{
+	int status;
+
+	status = tc_register_driver(&dec_lance_tc_driver);
+	if (!status)
+		dec_lance_platform_probe();
+	return status;
+}
+
+static void __exit dec_lance_exit(void)
+{
+	dec_lance_platform_remove();
+	tc_unregister_driver(&dec_lance_tc_driver);
+}
+
+
+module_init(dec_lance_init);
+module_exit(dec_lance_exit);
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index dc3ab3b..07d2731 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -10,10 +10,12 @@
  *
  * Abstract:
  *   A Linux device driver supporting the Digital Equipment Corporation
- *   FDDI EISA and PCI controller families.  Supported adapters include:
+ *   FDDI TURBOchannel, EISA and PCI controller families.  Supported
+ *   adapters include:
  *
- *		DEC FDDIcontroller/EISA (DEFEA)
- *		DEC FDDIcontroller/PCI  (DEFPA)
+ *		DEC FDDIcontroller/TURBOchannel (DEFTA)
+ *		DEC FDDIcontroller/EISA         (DEFEA)
+ *		DEC FDDIcontroller/PCI          (DEFPA)
  *
  * The original author:
  *   LVS	Lawrence V. Stefani <lstefani@yahoo.com>
@@ -193,24 +195,27 @@
  *		14 Aug 2004	macro		Fix device names reported.
  *		14 Jun 2005	macro		Use irqreturn_t.
  *		23 Oct 2006	macro		Big-endian host support.
+ *		14 Dec 2006	macro		TURBOchannel support.
  */
 
 /* Include files */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/fddidevice.h>
-#include <linux/skbuff.h>
 #include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/eisa.h>
+#include <linux/errno.h>
+#include <linux/fddidevice.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/tc.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -219,8 +224,8 @@
 
 /* Version information string should be updated prior to each new release!  */
 #define DRV_NAME "defxx"
-#define DRV_VERSION "v1.09"
-#define DRV_RELDATE "2006/10/23"
+#define DRV_VERSION "v1.10"
+#define DRV_RELDATE "2006/12/14"
 
 static char version[] __devinitdata =
 	DRV_NAME ": " DRV_VERSION " " DRV_RELDATE
@@ -235,12 +240,41 @@
  */
 #define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128)
 
+#define __unused __attribute__ ((unused))
+
+#ifdef CONFIG_PCI
+#define DFX_BUS_PCI(dev) (dev->bus == &pci_bus_type)
+#else
+#define DFX_BUS_PCI(dev) 0
+#endif
+
+#ifdef CONFIG_EISA
+#define DFX_BUS_EISA(dev) (dev->bus == &eisa_bus_type)
+#else
+#define DFX_BUS_EISA(dev) 0
+#endif
+
+#ifdef CONFIG_TC
+#define DFX_BUS_TC(dev) (dev->bus == &tc_bus_type)
+#else
+#define DFX_BUS_TC(dev) 0
+#endif
+
+#ifdef CONFIG_DEFXX_MMIO
+#define DFX_MMIO 1
+#else
+#define DFX_MMIO 0
+#endif
+
 /* Define module-wide (static) routines */
 
 static void		dfx_bus_init(struct net_device *dev);
+static void		dfx_bus_uninit(struct net_device *dev);
 static void		dfx_bus_config_check(DFX_board_t *bp);
 
-static int		dfx_driver_init(struct net_device *dev, const char *print_name);
+static int		dfx_driver_init(struct net_device *dev,
+					const char *print_name,
+					resource_size_t bar_start);
 static int		dfx_adap_init(DFX_board_t *bp, int get_buffers);
 
 static int		dfx_open(struct net_device *dev);
@@ -273,13 +307,13 @@
 
 /* Define module-wide (static) variables */
 
-static struct net_device *root_dfx_eisa_dev;
+static struct pci_driver dfx_pci_driver;
+static struct eisa_driver dfx_eisa_driver;
+static struct tc_driver dfx_tc_driver;
 
 
 /*
  * =======================
- * = dfx_port_write_byte =
- * = dfx_port_read_byte	 =
  * = dfx_port_write_long =
  * = dfx_port_read_long  =
  * =======================
@@ -291,12 +325,11 @@
  *   None
  *
  * Arguments:
- *   bp     - pointer to board information
- *   offset - register offset from base I/O address
- *   data   - for dfx_port_write_byte and dfx_port_write_long, this
- *			  is a value to write.
- *			  for dfx_port_read_byte and dfx_port_read_byte, this
- *			  is a pointer to store the read value.
+ *   bp		- pointer to board information
+ *   offset	- register offset from base I/O address
+ *   data	- for dfx_port_write_long, this is a value to write;
+ *		  for dfx_port_read_long, this is a pointer to store
+ *		  the read value
  *
  * Functional Description:
  *   These routines perform the correct operation to read or write
@@ -310,7 +343,7 @@
  *   registers using the register offsets defined in DEFXX.H.
  *
  *   PCI port block base addresses are assigned by the PCI BIOS or system
- *	 firmware.  There is one 128 byte port block which can be accessed.  It
+ *   firmware.  There is one 128 byte port block which can be accessed.  It
  *   allows for I/O mapping of both PDQ and PFI registers using the register
  *   offsets defined in DEFXX.H.
  *
@@ -318,7 +351,7 @@
  *   None
  *
  * Assumptions:
- *   bp->base_addr is a valid base I/O address for this adapter.
+ *   bp->base is a valid base I/O address for this adapter.
  *   offset is a valid register offset for this adapter.
  *
  * Side Effects:
@@ -329,69 +362,135 @@
  *   advantage of strict data type checking.
  */
 
-static inline void dfx_port_write_byte(
-	DFX_board_t	*bp,
-	int			offset,
-	u8			data
-	)
+static inline void dfx_writel(DFX_board_t *bp, int offset, u32 data)
+{
+	writel(data, bp->base.mem + offset);
+	mb();
+}
 
-	{
-	u16 port = bp->base_addr + offset;
+static inline void dfx_outl(DFX_board_t *bp, int offset, u32 data)
+{
+	outl(data, bp->base.port + offset);
+}
 
-	outb(data, port);
-	}
+static void dfx_port_write_long(DFX_board_t *bp, int offset, u32 data)
+{
+	struct device __unused *bdev = bp->bus_dev;
+	int dfx_bus_tc = DFX_BUS_TC(bdev);
+	int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
 
-static inline void dfx_port_read_byte(
-	DFX_board_t	*bp,
-	int			offset,
-	u8			*data
-	)
+	if (dfx_use_mmio)
+		dfx_writel(bp, offset, data);
+	else
+		dfx_outl(bp, offset, data);
+}
 
-	{
-	u16 port = bp->base_addr + offset;
 
-	*data = inb(port);
-	}
+static inline void dfx_readl(DFX_board_t *bp, int offset, u32 *data)
+{
+	mb();
+	*data = readl(bp->base.mem + offset);
+}
 
-static inline void dfx_port_write_long(
-	DFX_board_t	*bp,
-	int			offset,
-	u32			data
-	)
+static inline void dfx_inl(DFX_board_t *bp, int offset, u32 *data)
+{
+	*data = inl(bp->base.port + offset);
+}
 
-	{
-	u16 port = bp->base_addr + offset;
+static void dfx_port_read_long(DFX_board_t *bp, int offset, u32 *data)
+{
+	struct device __unused *bdev = bp->bus_dev;
+	int dfx_bus_tc = DFX_BUS_TC(bdev);
+	int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
 
-	outl(data, port);
-	}
-
-static inline void dfx_port_read_long(
-	DFX_board_t	*bp,
-	int			offset,
-	u32			*data
-	)
-
-	{
-	u16 port = bp->base_addr + offset;
-
-	*data = inl(port);
-	}
+	if (dfx_use_mmio)
+		dfx_readl(bp, offset, data);
+	else
+		dfx_inl(bp, offset, data);
+}
 
 
 /*
- * =============
- * = dfx_init_one_pci_or_eisa =
- * =============
+ * ================
+ * = dfx_get_bars =
+ * ================
  *
  * Overview:
- *   Initializes a supported FDDI EISA or PCI controller
+ *   Retrieves the address range used to access control and status
+ *   registers.
+ *
+ * Returns:
+ *   None
+ *
+ * Arguments:
+ *   bdev	- pointer to device information
+ *   bar_start	- pointer to store the start address
+ *   bar_len	- pointer to store the length of the area
+ *
+ * Assumptions:
+ *   I am sure there are some.
+ *
+ * Side Effects:
+ *   None
+ */
+static void dfx_get_bars(struct device *bdev,
+			 resource_size_t *bar_start, resource_size_t *bar_len)
+{
+	int dfx_bus_pci = DFX_BUS_PCI(bdev);
+	int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+	int dfx_bus_tc = DFX_BUS_TC(bdev);
+	int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
+
+	if (dfx_bus_pci) {
+		int num = dfx_use_mmio ? 0 : 1;
+
+		*bar_start = pci_resource_start(to_pci_dev(bdev), num);
+		*bar_len = pci_resource_len(to_pci_dev(bdev), num);
+	}
+	if (dfx_bus_eisa) {
+		unsigned long base_addr = to_eisa_device(bdev)->base_addr;
+		resource_size_t bar;
+
+		if (dfx_use_mmio) {
+			bar = inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_2);
+			bar <<= 8;
+			bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_1);
+			bar <<= 8;
+			bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_0);
+			bar <<= 16;
+			*bar_start = bar;
+			bar = inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_2);
+			bar <<= 8;
+			bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_1);
+			bar <<= 8;
+			bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_0);
+			bar <<= 16;
+			*bar_len = (bar | PI_MEM_ADD_MASK_M) + 1;
+		} else {
+			*bar_start = base_addr;
+			*bar_len = PI_ESIC_K_CSR_IO_LEN;
+		}
+	}
+	if (dfx_bus_tc) {
+		*bar_start = to_tc_dev(bdev)->resource.start +
+			     PI_TC_K_CSR_OFFSET;
+		*bar_len = PI_TC_K_CSR_LEN;
+	}
+}
+
+/*
+ * ================
+ * = dfx_register =
+ * ================
+ *
+ * Overview:
+ *   Initializes a supported FDDI controller
  *
  * Returns:
  *   Condition code
  *
  * Arguments:
- *   pdev - pointer to pci device information (NULL for EISA)
- *   ioaddr - pointer to port (NULL for PCI)
+ *   bdev - pointer to device information
  *
  * Functional Description:
  *
@@ -407,56 +506,74 @@
  *   initialized and the board resources are read and stored in
  *   the device structure.
  */
-static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr)
+static int __devinit dfx_register(struct device *bdev)
 {
 	static int version_disp;
-	char *print_name = DRV_NAME;
+	int dfx_bus_pci = DFX_BUS_PCI(bdev);
+	int dfx_bus_tc = DFX_BUS_TC(bdev);
+	int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
+	char *print_name = bdev->bus_id;
 	struct net_device *dev;
 	DFX_board_t	  *bp;			/* board pointer */
+	resource_size_t bar_start = 0;		/* pointer to port */
+	resource_size_t bar_len = 0;		/* resource length */
 	int alloc_size;				/* total buffer size used */
-	int err;
+	struct resource *region;
+	int err = 0;
 
 	if (!version_disp) {	/* display version info if adapter is found */
 		version_disp = 1;	/* set display flag to TRUE so that */
 		printk(version);	/* we only display this string ONCE */
 	}
 
-	if (pdev != NULL)
-		print_name = pci_name(pdev);
-
 	dev = alloc_fddidev(sizeof(*bp));
 	if (!dev) {
-		printk(KERN_ERR "%s: unable to allocate fddidev, aborting\n",
+		printk(KERN_ERR "%s: Unable to allocate fddidev, aborting\n",
 		       print_name);
 		return -ENOMEM;
 	}
 
 	/* Enable PCI device. */
-	if (pdev != NULL) {
-		err = pci_enable_device (pdev);
-		if (err) goto err_out;
-		ioaddr = pci_resource_start (pdev, 1);
-	}
-
-	SET_MODULE_OWNER(dev);
-	if (pdev != NULL)
-		SET_NETDEV_DEV(dev, &pdev->dev);
-
-	bp = dev->priv;
-
-	if (!request_region(ioaddr,
-			    pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN,
-			    print_name)) {
-		printk(KERN_ERR "%s: Cannot reserve I/O resource "
-		       "0x%x @ 0x%lx, aborting\n", print_name,
-		       pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, ioaddr);
-		err = -EBUSY;
+	if (dfx_bus_pci && pci_enable_device(to_pci_dev(bdev))) {
+		printk(KERN_ERR "%s: Cannot enable PCI device, aborting\n",
+		       print_name);
 		goto err_out;
 	}
 
-	/* Initialize new device structure */
+	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, bdev);
 
-	dev->base_addr			= ioaddr; /* save port (I/O) base address */
+	bp = netdev_priv(dev);
+	bp->bus_dev = bdev;
+	dev_set_drvdata(bdev, dev);
+
+	dfx_get_bars(bdev, &bar_start, &bar_len);
+
+	if (dfx_use_mmio)
+		region = request_mem_region(bar_start, bar_len, print_name);
+	else
+		region = request_region(bar_start, bar_len, print_name);
+	if (!region) {
+		printk(KERN_ERR "%s: Cannot reserve I/O resource "
+		       "0x%lx @ 0x%lx, aborting\n",
+		       print_name, (long)bar_len, (long)bar_start);
+		err = -EBUSY;
+		goto err_out_disable;
+	}
+
+	/* Set up I/O base address. */
+	if (dfx_use_mmio) {
+		bp->base.mem = ioremap_nocache(bar_start, bar_len);
+		if (!bp->base.mem) {
+			printk(KERN_ERR "%s: Cannot map MMIO\n", print_name);
+			goto err_out_region;
+		}
+	} else {
+		bp->base.port = bar_start;
+		dev->base_addr = bar_start;
+	}
+
+	/* Initialize new device structure */
 
 	dev->get_stats			= dfx_ctl_get_stats;
 	dev->open			= dfx_open;
@@ -465,22 +582,12 @@
 	dev->set_multicast_list		= dfx_ctl_set_multicast_list;
 	dev->set_mac_address		= dfx_ctl_set_mac_address;
 
-	if (pdev == NULL) {
-		/* EISA board */
-		bp->bus_type = DFX_BUS_TYPE_EISA;
-		bp->next = root_dfx_eisa_dev;
-		root_dfx_eisa_dev = dev;
-	} else {
-		/* PCI board */
-		bp->bus_type = DFX_BUS_TYPE_PCI;
-		bp->pci_dev = pdev;
-		pci_set_drvdata (pdev, dev);
-		pci_set_master (pdev);
-	}
+	if (dfx_bus_pci)
+		pci_set_master(to_pci_dev(bdev));
 
-	if (dfx_driver_init(dev, print_name) != DFX_K_SUCCESS) {
+	if (dfx_driver_init(dev, print_name, bar_start) != DFX_K_SUCCESS) {
 		err = -ENODEV;
-		goto err_out_region;
+		goto err_out_unmap;
 	}
 
 	err = register_netdev(dev);
@@ -499,44 +606,28 @@
 		     sizeof(PI_CONSUMER_BLOCK) +
 		     (PI_ALIGN_K_DESC_BLK - 1);
 	if (bp->kmalloced)
-		pci_free_consistent(pdev, alloc_size,
-				    bp->kmalloced, bp->kmalloced_dma);
+		dma_free_coherent(bdev, alloc_size,
+				  bp->kmalloced, bp->kmalloced_dma);
+
+err_out_unmap:
+	if (dfx_use_mmio)
+		iounmap(bp->base.mem);
+
 err_out_region:
-	release_region(ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN);
+	if (dfx_use_mmio)
+		release_mem_region(bar_start, bar_len);
+	else
+		release_region(bar_start, bar_len);
+
+err_out_disable:
+	if (dfx_bus_pci)
+		pci_disable_device(to_pci_dev(bdev));
+
 err_out:
 	free_netdev(dev);
 	return err;
 }
 
-static int __devinit dfx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-	return dfx_init_one_pci_or_eisa(pdev, 0);
-}
-
-static int __init dfx_eisa_init(void)
-{
-	int rc = -ENODEV;
-	int i;			/* used in for loops */
-	u16 port;		/* temporary I/O (port) address */
-	u32 slot_id;		/* EISA hardware (slot) ID read from adapter */
-
-	DBG_printk("In dfx_eisa_init...\n");
-
-	/* Scan for FDDI EISA controllers */
-
-	for (i=0; i < DFX_MAX_EISA_SLOTS; i++)		/* only scan for up to 16 EISA slots */
-	{
-		port = (i << 12) + PI_ESIC_K_SLOT_ID;	/* port = I/O address for reading slot ID */
-		slot_id = inl(port);					/* read EISA HW (slot) ID */
-		if ((slot_id & 0xF0FFFFFF) == DEFEA_PRODUCT_ID)
-		{
-			port = (i << 12);					/* recalc base addr */
-
-			if (dfx_init_one_pci_or_eisa(NULL, port) == 0) rc = 0;
-		}
-	}
-	return rc;
-}
 
 /*
  * ================
@@ -544,7 +635,7 @@
  * ================
  *
  * Overview:
- *   Initializes EISA and PCI controller bus-specific logic.
+ *   Initializes the bus-specific controller logic.
  *
  * Returns:
  *   None
@@ -560,7 +651,7 @@
  *   None
  *
  * Assumptions:
- *   dev->base_addr has already been set with the proper
+ *   bp->base has already been set with the proper
  *	 base I/O address for this device.
  *
  * Side Effects:
@@ -571,87 +662,103 @@
 
 static void __devinit dfx_bus_init(struct net_device *dev)
 {
-	DFX_board_t *bp = dev->priv;
-	u8			val;	/* used for I/O read/writes */
+	DFX_board_t *bp = netdev_priv(dev);
+	struct device *bdev = bp->bus_dev;
+	int dfx_bus_pci = DFX_BUS_PCI(bdev);
+	int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+	int dfx_bus_tc = DFX_BUS_TC(bdev);
+	int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
+	u8 val;
 
 	DBG_printk("In dfx_bus_init...\n");
 
-	/*
-	 * Initialize base I/O address field in bp structure
-	 *
-	 * Note: bp->base_addr is the same as dev->base_addr.
-	 *		 It's useful because often we'll need to read
-	 *		 or write registers where we already have the
-	 *		 bp pointer instead of the dev pointer.  Having
-	 *		 the base address in the bp structure will
-	 *		 save a pointer dereference.
-	 *
-	 *		 IMPORTANT!! This field must be defined before
-	 *		 any of the dfx_port_* inline functions are
-	 *		 called.
-	 */
-
-	bp->base_addr = dev->base_addr;
-
-	/* And a pointer back to the net_device struct */
+	/* Initialize a pointer back to the net_device struct */
 	bp->dev = dev;
 
 	/* Initialize adapter based on bus type */
 
-	if (bp->bus_type == DFX_BUS_TYPE_EISA)
-		{
-		/* Get the interrupt level from the ESIC chip */
+	if (dfx_bus_tc)
+		dev->irq = to_tc_dev(bdev)->interrupt;
+	if (dfx_bus_eisa) {
+		unsigned long base_addr = to_eisa_device(bdev)->base_addr;
 
-		dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val);
-		switch ((val & PI_CONFIG_STAT_0_M_IRQ) >> PI_CONFIG_STAT_0_V_IRQ)
-			{
-			case PI_CONFIG_STAT_0_IRQ_K_9:
-				dev->irq = 9;
-				break;
+		/* Get the interrupt level from the ESIC chip.  */
+		val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
+		val &= PI_CONFIG_STAT_0_M_IRQ;
+		val >>= PI_CONFIG_STAT_0_V_IRQ;
 
-			case PI_CONFIG_STAT_0_IRQ_K_10:
-				dev->irq = 10;
-				break;
+		switch (val) {
+		case PI_CONFIG_STAT_0_IRQ_K_9:
+			dev->irq = 9;
+			break;
 
-			case PI_CONFIG_STAT_0_IRQ_K_11:
-				dev->irq = 11;
-				break;
+		case PI_CONFIG_STAT_0_IRQ_K_10:
+			dev->irq = 10;
+			break;
 
-			case PI_CONFIG_STAT_0_IRQ_K_15:
-				dev->irq = 15;
-				break;
-			}
+		case PI_CONFIG_STAT_0_IRQ_K_11:
+			dev->irq = 11;
+			break;
 
-		/* Enable access to I/O on the board by writing 0x03 to Function Control Register */
-
-		dfx_port_write_byte(bp, PI_ESIC_K_FUNCTION_CNTRL, PI_ESIC_K_FUNCTION_CNTRL_IO_ENB);
-
-		/* Set the I/O decode range of the board */
-
-		val = ((dev->base_addr >> 12) << PI_IO_CMP_V_SLOT);
-		dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_0_1, val);
-		dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_1_1, val);
-
-		/* Enable access to rest of module (including PDQ and packet memory) */
-
-		dfx_port_write_byte(bp, PI_ESIC_K_SLOT_CNTRL, PI_SLOT_CNTRL_M_ENB);
+		case PI_CONFIG_STAT_0_IRQ_K_15:
+			dev->irq = 15;
+			break;
+		}
 
 		/*
-		 * Map PDQ registers into I/O space.  This is done by clearing a bit
-		 * in Burst Holdoff register.
+		 * Enable memory decoding (MEMCS0) and/or port decoding
+		 * (IOCS1/IOCS0) as appropriate in Function Control
+		 * Register.  One of the port chip selects seems to be
+		 * used for the Burst Holdoff register, but this bit of
+		 * documentation is missing and as yet it has not been
+		 * determined which of the two.  This is also the reason
+		 * the size of the decoded port range is twice as large
+		 * as one required by the PDQ.
 		 */
 
-		dfx_port_read_byte(bp, PI_ESIC_K_BURST_HOLDOFF, &val);
-		dfx_port_write_byte(bp, PI_ESIC_K_BURST_HOLDOFF, (val & ~PI_BURST_HOLDOFF_M_MEM_MAP));
+		/* Set the decode range of the board.  */
+		val = ((bp->base.port >> 12) << PI_IO_CMP_V_SLOT);
+		outb(base_addr + PI_ESIC_K_IO_ADD_CMP_0_1, val);
+		outb(base_addr + PI_ESIC_K_IO_ADD_CMP_0_0, 0);
+		outb(base_addr + PI_ESIC_K_IO_ADD_CMP_1_1, val);
+		outb(base_addr + PI_ESIC_K_IO_ADD_CMP_1_0, 0);
+		val = PI_ESIC_K_CSR_IO_LEN - 1;
+		outb(base_addr + PI_ESIC_K_IO_ADD_MASK_0_1, (val >> 8) & 0xff);
+		outb(base_addr + PI_ESIC_K_IO_ADD_MASK_0_0, val & 0xff);
+		outb(base_addr + PI_ESIC_K_IO_ADD_MASK_1_1, (val >> 8) & 0xff);
+		outb(base_addr + PI_ESIC_K_IO_ADD_MASK_1_0, val & 0xff);
+
+		/* Enable the decoders.  */
+		val = PI_FUNCTION_CNTRL_M_IOCS1 | PI_FUNCTION_CNTRL_M_IOCS0;
+		if (dfx_use_mmio)
+			val |= PI_FUNCTION_CNTRL_M_MEMCS0;
+		outb(base_addr + PI_ESIC_K_FUNCTION_CNTRL, val);
+
+		/*
+		 * Enable access to the rest of the module
+		 * (including PDQ and packet memory).
+		 */
+		val = PI_SLOT_CNTRL_M_ENB;
+		outb(base_addr + PI_ESIC_K_SLOT_CNTRL, val);
+
+		/*
+		 * Map PDQ registers into memory or port space.  This is
+		 * done with a bit in the Burst Holdoff register.
+		 */
+		val = inb(base_addr + PI_DEFEA_K_BURST_HOLDOFF);
+		if (dfx_use_mmio)
+			val |= PI_BURST_HOLDOFF_V_MEM_MAP;
+		else
+			val &= ~PI_BURST_HOLDOFF_V_MEM_MAP;
+		outb(base_addr + PI_DEFEA_K_BURST_HOLDOFF, val);
 
 		/* Enable interrupts at EISA bus interface chip (ESIC) */
-
-		dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val);
-		dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, (val | PI_CONFIG_STAT_0_M_INT_ENB));
-		}
-	else
-		{
-		struct pci_dev *pdev = bp->pci_dev;
+		val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
+		val |= PI_CONFIG_STAT_0_M_INT_ENB;
+		outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, val);
+	}
+	if (dfx_bus_pci) {
+		struct pci_dev *pdev = to_pci_dev(bdev);
 
 		/* Get the interrupt level from the PCI Configuration Table */
 
@@ -660,17 +767,70 @@
 		/* Check Latency Timer and set if less than minimal */
 
 		pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &val);
-		if (val < PFI_K_LAT_TIMER_MIN)	/* if less than min, override with default */
-			{
+		if (val < PFI_K_LAT_TIMER_MIN) {
 			val = PFI_K_LAT_TIMER_DEF;
 			pci_write_config_byte(pdev, PCI_LATENCY_TIMER, val);
-			}
+		}
 
 		/* Enable interrupts at PCI bus interface chip (PFI) */
-
-		dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, (PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB));
-		}
+		val = PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB;
+		dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, val);
 	}
+}
+
+/*
+ * ==================
+ * = dfx_bus_uninit =
+ * ==================
+ *
+ * Overview:
+ *   Uninitializes the bus-specific controller logic.
+ *
+ * Returns:
+ *   None
+ *
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   Perform bus-specific logic uninitialization.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   bp->base has already been set with the proper
+ *	 base I/O address for this device.
+ *
+ * Side Effects:
+ *   Interrupts are disabled at the adapter bus-specific logic.
+ */
+
+static void __devinit dfx_bus_uninit(struct net_device *dev)
+{
+	DFX_board_t *bp = netdev_priv(dev);
+	struct device *bdev = bp->bus_dev;
+	int dfx_bus_pci = DFX_BUS_PCI(bdev);
+	int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+	u8 val;
+
+	DBG_printk("In dfx_bus_uninit...\n");
+
+	/* Uninitialize adapter based on bus type */
+
+	if (dfx_bus_eisa) {
+		unsigned long base_addr = to_eisa_device(bdev)->base_addr;
+
+		/* Disable interrupts at EISA bus interface chip (ESIC) */
+		val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
+		val &= ~PI_CONFIG_STAT_0_M_INT_ENB;
+		outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, val);
+	}
+	if (dfx_bus_pci) {
+		/* Disable interrupts at PCI bus interface chip (PFI) */
+		dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, 0);
+	}
+}
 
 
 /*
@@ -705,18 +865,16 @@
 
 static void __devinit dfx_bus_config_check(DFX_board_t *bp)
 {
+	struct device __unused *bdev = bp->bus_dev;
+	int dfx_bus_eisa = DFX_BUS_EISA(bdev);
 	int	status;				/* return code from adapter port control call */
-	u32	slot_id;			/* EISA-bus hardware id (DEC3001, DEC3002,...) */
 	u32	host_data;			/* LW data returned from port control call */
 
 	DBG_printk("In dfx_bus_config_check...\n");
 
 	/* Configuration check only valid for EISA adapter */
 
-	if (bp->bus_type == DFX_BUS_TYPE_EISA)
-		{
-		dfx_port_read_long(bp, PI_ESIC_K_SLOT_ID, &slot_id);
-
+	if (dfx_bus_eisa) {
 		/*
 		 * First check if revision 2 EISA controller.  Rev. 1 cards used
 		 * PDQ revision B, so no workaround needed in this case.  Rev. 3
@@ -724,14 +882,11 @@
 		 * case, either.  Only Rev. 2 cards used either Rev. D or E
 		 * chips, so we must verify the chip revision on Rev. 2 cards.
 		 */
-
-		if (slot_id == DEFEA_PROD_ID_2)
-			{
+		if (to_eisa_device(bdev)->id.driver_data == DEFEA_PROD_ID_2) {
 			/*
-			 * Revision 2 FDDI EISA controller found, so let's check PDQ
-			 * revision of adapter.
+			 * Revision 2 FDDI EISA controller found,
+			 * so let's check PDQ revision of adapter.
 			 */
-
 			status = dfx_hw_port_ctrl_req(bp,
 											PI_PCTRL_M_SUB_CMD,
 											PI_SUB_CMD_K_PDQ_REV_GET,
@@ -805,13 +960,20 @@
  */
 
 static int __devinit dfx_driver_init(struct net_device *dev,
-				     const char *print_name)
+				     const char *print_name,
+				     resource_size_t bar_start)
 {
-	DFX_board_t *bp = dev->priv;
-	int			alloc_size;			/* total buffer size needed */
-	char		*top_v, *curr_v;	/* virtual addrs into memory block */
-	dma_addr_t		top_p, curr_p;		/* physical addrs into memory block */
-	u32			data;				/* host data register value */
+	DFX_board_t *bp = netdev_priv(dev);
+	struct device *bdev = bp->bus_dev;
+	int dfx_bus_pci = DFX_BUS_PCI(bdev);
+	int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+	int dfx_bus_tc = DFX_BUS_TC(bdev);
+	int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
+	int alloc_size;			/* total buffer size needed */
+	char *top_v, *curr_v;		/* virtual addrs into memory block */
+	dma_addr_t top_p, curr_p;	/* physical addrs into memory block */
+	u32 data, le32;			/* host data register value */
+	char *board_name = NULL;
 
 	DBG_printk("In dfx_driver_init...\n");
 
@@ -860,8 +1022,8 @@
 		       print_name);
 		return(DFX_K_FAILURE);
 	}
-	data = cpu_to_le32(data);
-	memcpy(&bp->factory_mac_addr[0], &data, sizeof(u32));
+	le32 = cpu_to_le32(data);
+	memcpy(&bp->factory_mac_addr[0], &le32, sizeof(u32));
 
 	if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_MLA, PI_PDATA_A_MLA_K_HI, 0,
 				 &data) != DFX_K_SUCCESS) {
@@ -869,8 +1031,8 @@
 		       print_name);
 		return(DFX_K_FAILURE);
 	}
-	data = cpu_to_le32(data);
-	memcpy(&bp->factory_mac_addr[4], &data, sizeof(u16));
+	le32 = cpu_to_le32(data);
+	memcpy(&bp->factory_mac_addr[4], &le32, sizeof(u16));
 
 	/*
 	 * Set current address to factory address
@@ -880,20 +1042,18 @@
 	 */
 
 	memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN);
-	if (bp->bus_type == DFX_BUS_TYPE_EISA)
-		printk("%s: DEFEA at I/O addr = 0x%lX, IRQ = %d, "
-		       "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
-		       print_name, dev->base_addr, dev->irq,
-		       dev->dev_addr[0], dev->dev_addr[1],
-		       dev->dev_addr[2], dev->dev_addr[3],
-		       dev->dev_addr[4], dev->dev_addr[5]);
-	else
-		printk("%s: DEFPA at I/O addr = 0x%lX, IRQ = %d, "
-		       "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
-		       print_name, dev->base_addr, dev->irq,
-		       dev->dev_addr[0], dev->dev_addr[1],
-		       dev->dev_addr[2], dev->dev_addr[3],
-		       dev->dev_addr[4], dev->dev_addr[5]);
+	if (dfx_bus_tc)
+		board_name = "DEFTA";
+	if (dfx_bus_eisa)
+		board_name = "DEFEA";
+	if (dfx_bus_pci)
+		board_name = "DEFPA";
+	pr_info("%s: %s at %saddr = 0x%llx, IRQ = %d, "
+		"Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
+		print_name, board_name, dfx_use_mmio ? "" : "I/O ",
+		(long long)bar_start, dev->irq,
+		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
 
 	/*
 	 * Get memory for descriptor block, consumer block, and other buffers
@@ -908,8 +1068,9 @@
 #endif
 					sizeof(PI_CONSUMER_BLOCK) +
 					(PI_ALIGN_K_DESC_BLK - 1);
-	bp->kmalloced = top_v = pci_alloc_consistent(bp->pci_dev, alloc_size,
-						     &bp->kmalloced_dma);
+	bp->kmalloced = top_v = dma_alloc_coherent(bp->bus_dev, alloc_size,
+						   &bp->kmalloced_dma,
+						   GFP_ATOMIC);
 	if (top_v == NULL) {
 		printk("%s: Could not allocate memory for host buffers "
 		       "and structures!\n", print_name);
@@ -1219,14 +1380,15 @@
 
 static int dfx_open(struct net_device *dev)
 {
+	DFX_board_t *bp = netdev_priv(dev);
 	int ret;
-	DFX_board_t	*bp = dev->priv;
 
 	DBG_printk("In dfx_open...\n");
 
 	/* Register IRQ - support shared interrupts by passing device ptr */
 
-	ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name, dev);
+	ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name,
+			  dev);
 	if (ret) {
 		printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq);
 		return ret;
@@ -1309,7 +1471,7 @@
 
 static int dfx_close(struct net_device *dev)
 {
-	DFX_board_t	*bp = dev->priv;
+	DFX_board_t *bp = netdev_priv(dev);
 
 	DBG_printk("In dfx_close...\n");
 
@@ -1645,7 +1807,7 @@
 
 static void dfx_int_common(struct net_device *dev)
 {
-	DFX_board_t 	*bp = dev->priv;
+	DFX_board_t *bp = netdev_priv(dev);
 	PI_UINT32	port_status;		/* Port Status register */
 
 	/* Process xmt interrupts - frequent case, so always call this routine */
@@ -1715,18 +1877,16 @@
 
 static irqreturn_t dfx_interrupt(int irq, void *dev_id)
 {
-	struct net_device	*dev = dev_id;
-	DFX_board_t		*bp;	/* private board structure pointer */
-
-	/* Get board pointer only if device structure is valid */
-
-	bp = dev->priv;
-
-	/* See if we're already servicing an interrupt */
+	struct net_device *dev = dev_id;
+	DFX_board_t *bp = netdev_priv(dev);
+	struct device *bdev = bp->bus_dev;
+	int dfx_bus_pci = DFX_BUS_PCI(bdev);
+	int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+	int dfx_bus_tc = DFX_BUS_TC(bdev);
 
 	/* Service adapter interrupts */
 
-	if (bp->bus_type == DFX_BUS_TYPE_PCI) {
+	if (dfx_bus_pci) {
 		u32 status;
 
 		dfx_port_read_long(bp, PFI_K_REG_STATUS, &status);
@@ -1750,10 +1910,12 @@
 				     PFI_MODE_M_DMA_ENB));
 
 		spin_unlock(&bp->lock);
-	} else {
+	}
+	if (dfx_bus_eisa) {
+		unsigned long base_addr = to_eisa_device(bdev)->base_addr;
 		u8 status;
 
-		dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &status);
+		status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
 		if (!(status & PI_CONFIG_STAT_0_M_PEND))
 			return IRQ_NONE;
 
@@ -1761,15 +1923,35 @@
 
 		/* Disable interrupts at the ESIC */
 		status &= ~PI_CONFIG_STAT_0_M_INT_ENB;
-		dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, status);
+		outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, status);
 
 		/* Call interrupt service routine for this adapter */
 		dfx_int_common(dev);
 
 		/* Reenable interrupts at the ESIC */
-		dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &status);
+		status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
 		status |= PI_CONFIG_STAT_0_M_INT_ENB;
-		dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, status);
+		outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, status);
+
+		spin_unlock(&bp->lock);
+	}
+	if (dfx_bus_tc) {
+		u32 status;
+
+		dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &status);
+		if (!(status & (PI_PSTATUS_M_RCV_DATA_PENDING |
+				PI_PSTATUS_M_XMT_DATA_PENDING |
+				PI_PSTATUS_M_SMT_HOST_PENDING |
+				PI_PSTATUS_M_UNSOL_PENDING |
+				PI_PSTATUS_M_CMD_RSP_PENDING |
+				PI_PSTATUS_M_CMD_REQ_PENDING |
+				PI_PSTATUS_M_TYPE_0_PENDING)))
+			return IRQ_NONE;
+
+		spin_lock(&bp->lock);
+
+		/* Call interrupt service routine for this adapter */
+		dfx_int_common(dev);
 
 		spin_unlock(&bp->lock);
 	}
@@ -1823,7 +2005,7 @@
 
 static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev)
 	{
-	DFX_board_t	*bp = dev->priv;
+	DFX_board_t *bp = netdev_priv(dev);
 
 	/* Fill the bp->stats structure with driver-maintained counters */
 
@@ -2009,8 +2191,8 @@
  */
 
 static void dfx_ctl_set_multicast_list(struct net_device *dev)
-	{
-	DFX_board_t			*bp = dev->priv;
+{
+	DFX_board_t *bp = netdev_priv(dev);
 	int					i;			/* used as index in for loop */
 	struct dev_mc_list	*dmi;		/* ptr to multicast addr entry */
 
@@ -2124,8 +2306,8 @@
 
 static int dfx_ctl_set_mac_address(struct net_device *dev, void *addr)
 	{
-	DFX_board_t		*bp = dev->priv;
 	struct sockaddr	*p_sockaddr = (struct sockaddr *)addr;
+	DFX_board_t *bp = netdev_priv(dev);
 
 	/* Copy unicast address to driver-maintained structs and update count */
 
@@ -2764,9 +2946,9 @@
 
 			my_skb_align(newskb, 128);
 			bp->descr_block_virt->rcv_data[i + j].long_1 =
-				(u32)pci_map_single(bp->pci_dev, newskb->data,
+				(u32)dma_map_single(bp->bus_dev, newskb->data,
 						    NEW_SKB_SIZE,
-						    PCI_DMA_FROMDEVICE);
+						    DMA_FROM_DEVICE);
 			/*
 			 * p_rcv_buff_va is only used inside the
 			 * kernel so we put the skb pointer here.
@@ -2880,17 +3062,17 @@
 
 						my_skb_align(newskb, 128);
 						skb = (struct sk_buff *)bp->p_rcv_buff_va[entry];
-						pci_unmap_single(bp->pci_dev,
+						dma_unmap_single(bp->bus_dev,
 							bp->descr_block_virt->rcv_data[entry].long_1,
 							NEW_SKB_SIZE,
-							PCI_DMA_FROMDEVICE);
+							DMA_FROM_DEVICE);
 						skb_reserve(skb, RCV_BUFF_K_PADDING);
 						bp->p_rcv_buff_va[entry] = (char *)newskb;
 						bp->descr_block_virt->rcv_data[entry].long_1 =
-							(u32)pci_map_single(bp->pci_dev,
+							(u32)dma_map_single(bp->bus_dev,
 								newskb->data,
 								NEW_SKB_SIZE,
-								PCI_DMA_FROMDEVICE);
+								DMA_FROM_DEVICE);
 					} else
 						skb = NULL;
 				} else
@@ -3010,7 +3192,7 @@
 	)
 
 	{
-	DFX_board_t		*bp = dev->priv;
+	DFX_board_t		*bp = netdev_priv(dev);
 	u8			prod;				/* local transmit producer index */
 	PI_XMT_DESCR		*p_xmt_descr;		/* ptr to transmit descriptor block entry */
 	XMT_DRIVER_DESCR	*p_xmt_drv_descr;	/* ptr to transmit driver descriptor */
@@ -3116,8 +3298,8 @@
 	 */
 
 	p_xmt_descr->long_0	= (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len) << PI_XMT_DESCR_V_SEG_LEN));
-	p_xmt_descr->long_1 = (u32)pci_map_single(bp->pci_dev, skb->data,
-						  skb->len, PCI_DMA_TODEVICE);
+	p_xmt_descr->long_1 = (u32)dma_map_single(bp->bus_dev, skb->data,
+						  skb->len, DMA_TO_DEVICE);
 
 	/*
 	 * Verify that descriptor is actually available
@@ -3220,10 +3402,10 @@
 
 		/* Return skb to operating system */
 		comp = bp->rcv_xmt_reg.index.xmt_comp;
-		pci_unmap_single(bp->pci_dev,
+		dma_unmap_single(bp->bus_dev,
 				 bp->descr_block_virt->xmt_data[comp].long_1,
 				 p_xmt_drv_descr->p_skb->len,
-				 PCI_DMA_TODEVICE);
+				 DMA_TO_DEVICE);
 		dev_kfree_skb_irq(p_xmt_drv_descr->p_skb);
 
 		/*
@@ -3344,10 +3526,10 @@
 
 		/* Return skb to operating system */
 		comp = bp->rcv_xmt_reg.index.xmt_comp;
-		pci_unmap_single(bp->pci_dev,
+		dma_unmap_single(bp->bus_dev,
 				 bp->descr_block_virt->xmt_data[comp].long_1,
 				 p_xmt_drv_descr->p_skb->len,
-				 PCI_DMA_TODEVICE);
+				 DMA_TO_DEVICE);
 		dev_kfree_skb(p_xmt_drv_descr->p_skb);
 
 		/* Increment transmit error counter */
@@ -3375,13 +3557,44 @@
 	bp->cons_block_virt->xmt_rcv_data = prod_cons;
 	}
 
-static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct net_device *dev)
+/*
+ * ==================
+ * = dfx_unregister =
+ * ==================
+ *
+ * Overview:
+ *   Shuts down an FDDI controller
+ *
+ * Returns:
+ *   Condition code
+ *
+ * Arguments:
+ *   bdev - pointer to device information
+ *
+ * Functional Description:
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   It compiles so it should work :-( (PCI cards do :-)
+ *
+ * Side Effects:
+ *   Device structures for FDDI adapters (fddi0, fddi1, etc) are
+ *   freed.
+ */
+static void __devexit dfx_unregister(struct device *bdev)
 {
-	DFX_board_t	*bp = dev->priv;
+	struct net_device *dev = dev_get_drvdata(bdev);
+	DFX_board_t *bp = netdev_priv(dev);
+	int dfx_bus_pci = DFX_BUS_PCI(bdev);
+	int dfx_bus_tc = DFX_BUS_TC(bdev);
+	int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
+	resource_size_t bar_start = 0;		/* pointer to port */
+	resource_size_t bar_len = 0;		/* resource length */
 	int		alloc_size;		/* total buffer size used */
 
 	unregister_netdev(dev);
-	release_region(dev->base_addr,  pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN );
 
 	alloc_size = sizeof(PI_DESCR_BLOCK) +
 		     PI_CMD_REQ_K_SIZE_MAX + PI_CMD_RSP_K_SIZE_MAX +
@@ -3391,78 +3604,141 @@
 		     sizeof(PI_CONSUMER_BLOCK) +
 		     (PI_ALIGN_K_DESC_BLK - 1);
 	if (bp->kmalloced)
-		pci_free_consistent(pdev, alloc_size, bp->kmalloced,
-				    bp->kmalloced_dma);
+		dma_free_coherent(bdev, alloc_size,
+				  bp->kmalloced, bp->kmalloced_dma);
+
+	dfx_bus_uninit(dev);
+
+	dfx_get_bars(bdev, &bar_start, &bar_len);
+	if (dfx_use_mmio) {
+		iounmap(bp->base.mem);
+		release_mem_region(bar_start, bar_len);
+	} else
+		release_region(bar_start, bar_len);
+
+	if (dfx_bus_pci)
+		pci_disable_device(to_pci_dev(bdev));
+
 	free_netdev(dev);
 }
 
-static void __devexit dfx_remove_one (struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
 
-	dfx_remove_one_pci_or_eisa(pdev, dev);
-	pci_set_drvdata(pdev, NULL);
-}
+static int __devinit __unused dfx_dev_register(struct device *);
+static int __devexit __unused dfx_dev_unregister(struct device *);
 
-static struct pci_device_id dfx_pci_tbl[] = {
-	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, PCI_ANY_ID, PCI_ANY_ID, },
-	{ 0, }
+#ifdef CONFIG_PCI
+static int __devinit dfx_pci_register(struct pci_dev *,
+				      const struct pci_device_id *);
+static void __devexit dfx_pci_unregister(struct pci_dev *);
+
+static struct pci_device_id dfx_pci_table[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI) },
+	{ }
 };
-MODULE_DEVICE_TABLE(pci, dfx_pci_tbl);
+MODULE_DEVICE_TABLE(pci, dfx_pci_table);
 
-static struct pci_driver dfx_driver = {
+static struct pci_driver dfx_pci_driver = {
 	.name		= "defxx",
-	.probe		= dfx_init_one,
-	.remove		= __devexit_p(dfx_remove_one),
-	.id_table	= dfx_pci_tbl,
+	.id_table	= dfx_pci_table,
+	.probe		= dfx_pci_register,
+	.remove		= __devexit_p(dfx_pci_unregister),
 };
 
-static int dfx_have_pci;
-static int dfx_have_eisa;
-
-
-static void __exit dfx_eisa_cleanup(void)
+static __devinit int dfx_pci_register(struct pci_dev *pdev,
+				      const struct pci_device_id *ent)
 {
-	struct net_device *dev = root_dfx_eisa_dev;
-
-	while (dev)
-	{
-		struct net_device *tmp;
-		DFX_board_t *bp;
-
-		bp = (DFX_board_t*)dev->priv;
-		tmp = bp->next;
-		dfx_remove_one_pci_or_eisa(NULL, dev);
-		dev = tmp;
-	}
+	return dfx_register(&pdev->dev);
 }
 
-static int __init dfx_init(void)
+static void __devexit dfx_pci_unregister(struct pci_dev *pdev)
 {
-	int rc_pci, rc_eisa;
+	dfx_unregister(&pdev->dev);
+}
+#endif /* CONFIG_PCI */
 
-	rc_pci = pci_register_driver(&dfx_driver);
-	if (rc_pci >= 0) dfx_have_pci = 1;
+#ifdef CONFIG_EISA
+static struct eisa_device_id dfx_eisa_table[] = {
+        { "DEC3001", DEFEA_PROD_ID_1 },
+        { "DEC3002", DEFEA_PROD_ID_2 },
+        { "DEC3003", DEFEA_PROD_ID_3 },
+        { "DEC3004", DEFEA_PROD_ID_4 },
+        { }
+};
+MODULE_DEVICE_TABLE(eisa, dfx_eisa_table);
 
-	rc_eisa = dfx_eisa_init();
-	if (rc_eisa >= 0) dfx_have_eisa = 1;
+static struct eisa_driver dfx_eisa_driver = {
+	.id_table	= dfx_eisa_table,
+	.driver		= {
+		.name	= "defxx",
+		.bus	= &eisa_bus_type,
+		.probe	= dfx_dev_register,
+		.remove	= __devexit_p(dfx_dev_unregister),
+	},
+};
+#endif /* CONFIG_EISA */
 
-	return ((rc_eisa < 0) ? 0 : rc_eisa)  + ((rc_pci < 0) ? 0 : rc_pci);
+#ifdef CONFIG_TC
+static struct tc_device_id const dfx_tc_table[] = {
+	{ "DEC     ", "PMAF-FA " },
+	{ "DEC     ", "PMAF-FD " },
+	{ "DEC     ", "PMAF-FS " },
+	{ "DEC     ", "PMAF-FU " },
+	{ }
+};
+MODULE_DEVICE_TABLE(tc, dfx_tc_table);
+
+static struct tc_driver dfx_tc_driver = {
+	.id_table	= dfx_tc_table,
+	.driver		= {
+		.name	= "defxx",
+		.bus	= &tc_bus_type,
+		.probe	= dfx_dev_register,
+		.remove	= __devexit_p(dfx_dev_unregister),
+	},
+};
+#endif /* CONFIG_TC */
+
+static int __devinit __unused dfx_dev_register(struct device *dev)
+{
+	int status;
+
+	status = dfx_register(dev);
+	if (!status)
+		get_device(dev);
+	return status;
 }
 
-static void __exit dfx_cleanup(void)
+static int __devexit __unused dfx_dev_unregister(struct device *dev)
 {
-	if (dfx_have_pci)
-		pci_unregister_driver(&dfx_driver);
-	if (dfx_have_eisa)
-		dfx_eisa_cleanup();
+	put_device(dev);
+	dfx_unregister(dev);
+	return 0;
+}
 
+
+static int __devinit dfx_init(void)
+{
+	int status;
+
+	status = pci_register_driver(&dfx_pci_driver);
+	if (!status)
+		status = eisa_driver_register(&dfx_eisa_driver);
+	if (!status)
+		status = tc_register_driver(&dfx_tc_driver);
+	return status;
+}
+
+static void __devexit dfx_cleanup(void)
+{
+	tc_unregister_driver(&dfx_tc_driver);
+	eisa_driver_unregister(&dfx_eisa_driver);
+	pci_unregister_driver(&dfx_pci_driver);
 }
 
 module_init(dfx_init);
 module_exit(dfx_cleanup);
 MODULE_AUTHOR("Lawrence V. Stefani");
-MODULE_DESCRIPTION("DEC FDDIcontroller EISA/PCI (DEFEA/DEFPA) driver "
+MODULE_DESCRIPTION("DEC FDDIcontroller TC/EISA/PCI (DEFTA/DEFEA/DEFPA) driver "
 		   DRV_VERSION " " DRV_RELDATE);
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/net/defxx.h b/drivers/net/defxx.h
index 2ce8f97..19a6f64 100644
--- a/drivers/net/defxx.h
+++ b/drivers/net/defxx.h
@@ -26,6 +26,7 @@
  *		12-Sep-96	LVS		Removed packet request header pointers.
  *		04 Aug 2003	macro		Converted to the DMA API.
  *		23 Oct 2006	macro		Big-endian host support.
+ *		14 Dec 2006	macro		TURBOchannel support.
  */
 
 #ifndef _DEFXX_H_
@@ -1471,9 +1472,17 @@
 
 #endif /* __BIG_ENDIAN */
 
+/* Define TC PDQ CSR offset and length */
+
+#define PI_TC_K_CSR_OFFSET		0x100000
+#define PI_TC_K_CSR_LEN			0x40		/* 64 bytes */
+
 /* Define EISA controller register offsets */
 
-#define PI_ESIC_K_BURST_HOLDOFF		0x040
+#define PI_ESIC_K_CSR_IO_LEN		0x80		/* 128 bytes */
+
+#define PI_DEFEA_K_BURST_HOLDOFF	0x040
+
 #define PI_ESIC_K_SLOT_ID            	0xC80
 #define PI_ESIC_K_SLOT_CNTRL		0xC84
 #define PI_ESIC_K_MEM_ADD_CMP_0     	0xC85
@@ -1488,14 +1497,14 @@
 #define PI_ESIC_K_MEM_ADD_LO_CMP_0  	0xC8E
 #define PI_ESIC_K_MEM_ADD_LO_CMP_1  	0xC8F
 #define PI_ESIC_K_MEM_ADD_LO_CMP_2  	0xC90
-#define PI_ESIC_K_IO_CMP_0_0		0xC91
-#define PI_ESIC_K_IO_CMP_0_1		0xC92
-#define PI_ESIC_K_IO_CMP_1_0		0xC93
-#define PI_ESIC_K_IO_CMP_1_1		0xC94
-#define PI_ESIC_K_IO_CMP_2_0		0xC95
-#define PI_ESIC_K_IO_CMP_2_1		0xC96
-#define PI_ESIC_K_IO_CMP_3_0		0xC97
-#define PI_ESIC_K_IO_CMP_3_1		0xC98
+#define PI_ESIC_K_IO_ADD_CMP_0_0	0xC91
+#define PI_ESIC_K_IO_ADD_CMP_0_1	0xC92
+#define PI_ESIC_K_IO_ADD_CMP_1_0	0xC93
+#define PI_ESIC_K_IO_ADD_CMP_1_1	0xC94
+#define PI_ESIC_K_IO_ADD_CMP_2_0	0xC95
+#define PI_ESIC_K_IO_ADD_CMP_2_1	0xC96
+#define PI_ESIC_K_IO_ADD_CMP_3_0	0xC97
+#define PI_ESIC_K_IO_ADD_CMP_3_1	0xC98
 #define PI_ESIC_K_IO_ADD_MASK_0_0    	0xC99
 #define PI_ESIC_K_IO_ADD_MASK_0_1    	0xC9A
 #define PI_ESIC_K_IO_ADD_MASK_1_0    	0xC9B
@@ -1518,11 +1527,16 @@
 #define PI_ESIC_K_INPUT_PORT         	0xCAC
 #define PI_ESIC_K_OUTPUT_PORT        	0xCAD
 #define PI_ESIC_K_FUNCTION_CNTRL	0xCAE
-#define PI_ESIC_K_CSR_IO_LEN		PI_ESIC_K_FUNCTION_CNTRL+1	/* always last reg + 1 */
 
-/* Define the value all drivers must write to the function control register. */
+/* Define the bits in the function control register. */
 
-#define PI_ESIC_K_FUNCTION_CNTRL_IO_ENB	0x03
+#define PI_FUNCTION_CNTRL_M_IOCS0	0x01
+#define PI_FUNCTION_CNTRL_M_IOCS1	0x02
+#define PI_FUNCTION_CNTRL_M_IOCS2	0x04
+#define PI_FUNCTION_CNTRL_M_IOCS3	0x08
+#define PI_FUNCTION_CNTRL_M_MEMCS0	0x10
+#define PI_FUNCTION_CNTRL_M_MEMCS1	0x20
+#define PI_FUNCTION_CNTRL_M_DMA		0x80
 
 /* Define the bits in the slot control register. */
 
@@ -1540,6 +1554,10 @@
 #define PI_BURST_HOLDOFF_V_RESERVED	1
 #define PI_BURST_HOLDOFF_V_MEM_MAP	0
 
+/* Define the implicit mask of the Memory Address Mask Register.  */
+
+#define PI_MEM_ADD_MASK_M		0x3ff
+
 /*
  * Define the fields in the IO Compare registers.
  * The driver must initialize the slot field with the slot ID shifted by the
@@ -1577,6 +1595,7 @@
 #define DEFEA_PROD_ID_1		0x0130A310		/* DEC product 300, rev 1	*/
 #define DEFEA_PROD_ID_2		0x0230A310		/* DEC product 300, rev 2	*/
 #define DEFEA_PROD_ID_3		0x0330A310		/* DEC product 300, rev 3	*/
+#define DEFEA_PROD_ID_4		0x0430A310		/* DEC product 300, rev 4	*/
 
 /**********************************************/
 /* Digital PFI Specification v1.0 Definitions */
@@ -1633,12 +1652,6 @@
 #define PFI_STATUS_V_FIFO_EMPTY		 1
 #define PFI_STATUS_V_DMA_IN_PROGRESS 0
 
-#define DFX_MAX_EISA_SLOTS		16			/* maximum number of EISA slots to scan */
-#define DFX_MAX_NUM_BOARDS		8			/* maximum number of adapters supported */
-
-#define DFX_BUS_TYPE_PCI		0			/* type code for DEC FDDIcontroller/PCI */
-#define DFX_BUS_TYPE_EISA		1			/* type code for DEC FDDIcontroller/EISA */
-
 #define DFX_FC_PRH2_PRH1_PRH0		0x54003820	/* Packet Request Header bytes + FC */
 #define DFX_PRH0_BYTE			0x20		/* Packet Request Header byte 0 */
 #define DFX_PRH1_BYTE			0x38		/* Packet Request Header byte 1 */
@@ -1756,10 +1769,11 @@
 	/* Store device, bus-specific, and parameter information for this adapter */
 
 	struct net_device		*dev;						/* pointer to device structure */
-	struct net_device		*next;
-	u32				bus_type;					/* bus type (0 == PCI, 1 == EISA) */
-	u16				base_addr;					/* base I/O address (same as dev->base_addr) */
-	struct pci_dev *		pci_dev;
+	union {
+		void __iomem *mem;
+		int port;
+	} base;										/* base address */
+	struct device			*bus_dev;
 	u32				full_duplex_enb;				/* FDDI Full Duplex enable (1 == on, 2 == off) */
 	u32				req_ttrt;					/* requested TTRT value (in 80ns units) */
 	u32				burst_size;					/* adapter burst size (enumerated) */
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index f091042..689f158 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -59,17 +59,13 @@
 #include <linux/capability.h>
 #include <linux/in.h>
 #include <linux/ip.h>
-#ifdef NETIF_F_TSO6
 #include <linux/ipv6.h>
-#endif
 #include <linux/tcp.h>
 #include <linux/udp.h>
 #include <net/pkt_sched.h>
 #include <linux/list.h>
 #include <linux/reboot.h>
-#ifdef NETIF_F_TSO
 #include <net/checksum.h>
-#endif
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
@@ -257,7 +253,6 @@
 	spinlock_t tx_queue_lock;
 #endif
 	atomic_t irq_sem;
-	unsigned int detect_link;
 	unsigned int total_tx_bytes;
 	unsigned int total_tx_packets;
 	unsigned int total_rx_bytes;
@@ -348,9 +343,7 @@
 	boolean_t have_msi;
 #endif
 	/* to not mess up cache alignment, always add to the bottom */
-#ifdef NETIF_F_TSO
 	boolean_t tso_force;
-#endif
 	boolean_t smart_power_down;	/* phy smart power down */
 	boolean_t quad_port_a;
 	unsigned long flags;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index fb96c87..44ebc72 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -338,7 +338,6 @@
 	return 0;
 }
 
-#ifdef NETIF_F_TSO
 static int
 e1000_set_tso(struct net_device *netdev, uint32_t data)
 {
@@ -352,18 +351,15 @@
 	else
 		netdev->features &= ~NETIF_F_TSO;
 
-#ifdef NETIF_F_TSO6
 	if (data)
 		netdev->features |= NETIF_F_TSO6;
 	else
 		netdev->features &= ~NETIF_F_TSO6;
-#endif
 
 	DPRINTK(PROBE, INFO, "TSO is %s\n", data ? "Enabled" : "Disabled");
 	adapter->tso_force = TRUE;
 	return 0;
 }
-#endif /* NETIF_F_TSO */
 
 static uint32_t
 e1000_get_msglevel(struct net_device *netdev)
@@ -1971,10 +1967,8 @@
 	.set_tx_csum            = e1000_set_tx_csum,
 	.get_sg                 = ethtool_op_get_sg,
 	.set_sg                 = ethtool_op_set_sg,
-#ifdef NETIF_F_TSO
 	.get_tso                = ethtool_op_get_tso,
 	.set_tso                = e1000_set_tso,
-#endif
 	.self_test_count        = e1000_diag_test_count,
 	.self_test              = e1000_diag_test,
 	.get_strings            = e1000_get_strings,
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index c6259c7..619c892 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -36,7 +36,7 @@
 #else
 #define DRIVERNAPI "-NAPI"
 #endif
-#define DRV_VERSION "7.3.15-k2"DRIVERNAPI
+#define DRV_VERSION "7.3.20-k2"DRIVERNAPI
 char e1000_driver_version[] = DRV_VERSION;
 static char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
 
@@ -990,16 +990,12 @@
 			netdev->features &= ~NETIF_F_HW_VLAN_FILTER;
 	}
 
-#ifdef NETIF_F_TSO
 	if ((adapter->hw.mac_type >= e1000_82544) &&
 	   (adapter->hw.mac_type != e1000_82547))
 		netdev->features |= NETIF_F_TSO;
 
-#ifdef NETIF_F_TSO6
 	if (adapter->hw.mac_type > e1000_82547_rev_2)
 		netdev->features |= NETIF_F_TSO6;
-#endif
-#endif
 	if (pci_using_dac)
 		netdev->features |= NETIF_F_HIGHDMA;
 
@@ -2583,15 +2579,22 @@
 
 	if (link) {
 		if (!netif_carrier_ok(netdev)) {
+			uint32_t ctrl;
 			boolean_t txb2b = 1;
 			e1000_get_speed_and_duplex(&adapter->hw,
 			                           &adapter->link_speed,
 			                           &adapter->link_duplex);
 
-			DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s\n",
-			       adapter->link_speed,
-			       adapter->link_duplex == FULL_DUPLEX ?
-			       "Full Duplex" : "Half Duplex");
+			ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+			DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s, "
+			        "Flow Control: %s\n",
+			        adapter->link_speed,
+			        adapter->link_duplex == FULL_DUPLEX ?
+			        "Full Duplex" : "Half Duplex",
+			        ((ctrl & E1000_CTRL_TFCE) && (ctrl &
+			        E1000_CTRL_RFCE)) ? "RX/TX" : ((ctrl &
+			        E1000_CTRL_RFCE) ? "RX" : ((ctrl &
+			        E1000_CTRL_TFCE) ? "TX" : "None" )));
 
 			/* tweak tx_queue_len according to speed/duplex
 			 * and adjust the timeout factor */
@@ -2619,7 +2622,6 @@
 				E1000_WRITE_REG(&adapter->hw, TARC0, tarc0);
 			}
 
-#ifdef NETIF_F_TSO
 			/* disable TSO for pcie and 10/100 speeds, to avoid
 			 * some hardware issues */
 			if (!adapter->tso_force &&
@@ -2630,22 +2632,17 @@
 					DPRINTK(PROBE,INFO,
 				        "10/100 speed: disabling TSO\n");
 					netdev->features &= ~NETIF_F_TSO;
-#ifdef NETIF_F_TSO6
 					netdev->features &= ~NETIF_F_TSO6;
-#endif
 					break;
 				case SPEED_1000:
 					netdev->features |= NETIF_F_TSO;
-#ifdef NETIF_F_TSO6
 					netdev->features |= NETIF_F_TSO6;
-#endif
 					break;
 				default:
 					/* oops */
 					break;
 				}
 			}
-#endif
 
 			/* enable transmits in the hardware, need to do this
 			 * after setting TARC0 */
@@ -2875,7 +2872,6 @@
 e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
           struct sk_buff *skb)
 {
-#ifdef NETIF_F_TSO
 	struct e1000_context_desc *context_desc;
 	struct e1000_buffer *buffer_info;
 	unsigned int i;
@@ -2904,7 +2900,6 @@
 						   0);
 			cmd_length = E1000_TXD_CMD_IP;
 			ipcse = skb->h.raw - skb->data - 1;
-#ifdef NETIF_F_TSO6
 		} else if (skb->protocol == htons(ETH_P_IPV6)) {
 			skb->nh.ipv6h->payload_len = 0;
 			skb->h.th->check =
@@ -2914,7 +2909,6 @@
 						 IPPROTO_TCP,
 						 0);
 			ipcse = 0;
-#endif
 		}
 		ipcss = skb->nh.raw - skb->data;
 		ipcso = (void *)&(skb->nh.iph->check) - (void *)skb->data;
@@ -2947,8 +2941,6 @@
 
 		return TRUE;
 	}
-#endif
-
 	return FALSE;
 }
 
@@ -2968,8 +2960,9 @@
 		buffer_info = &tx_ring->buffer_info[i];
 		context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
 
+		context_desc->lower_setup.ip_config = 0;
 		context_desc->upper_setup.tcp_fields.tucss = css;
-		context_desc->upper_setup.tcp_fields.tucso = css + skb->csum_offset;
+		context_desc->upper_setup.tcp_fields.tucso = css + skb->csum;
 		context_desc->upper_setup.tcp_fields.tucse = 0;
 		context_desc->tcp_seg_setup.data = 0;
 		context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
@@ -3005,7 +2998,6 @@
 	while (len) {
 		buffer_info = &tx_ring->buffer_info[i];
 		size = min(len, max_per_txd);
-#ifdef NETIF_F_TSO
 		/* Workaround for Controller erratum --
 		 * descriptor for non-tso packet in a linear SKB that follows a
 		 * tso gets written back prematurely before the data is fully
@@ -3020,7 +3012,6 @@
 		 * in TSO mode.  Append 4-byte sentinel desc */
 		if (unlikely(mss && !nr_frags && size == len && size > 8))
 			size -= 4;
-#endif
 		/* work-around for errata 10 and it applies
 		 * to all controllers in PCI-X mode
 		 * The fix is to make sure that the first descriptor of a
@@ -3062,12 +3053,10 @@
 		while (len) {
 			buffer_info = &tx_ring->buffer_info[i];
 			size = min(len, max_per_txd);
-#ifdef NETIF_F_TSO
 			/* Workaround for premature desc write-backs
 			 * in TSO mode.  Append 4-byte sentinel desc */
 			if (unlikely(mss && f == (nr_frags-1) && size == len && size > 8))
 				size -= 4;
-#endif
 			/* Workaround for potential 82544 hang in PCI-X.
 			 * Avoid terminating buffers within evenly-aligned
 			 * dwords. */
@@ -3292,7 +3281,6 @@
 	if (adapter->hw.mac_type >= e1000_82571)
 		max_per_txd = 8192;
 
-#ifdef NETIF_F_TSO
 	mss = skb_shinfo(skb)->gso_size;
 	/* The controller does a simple calculation to
 	 * make sure there is enough room in the FIFO before
@@ -3346,16 +3334,10 @@
 	if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL))
 		count++;
 	count++;
-#else
-	if (skb->ip_summed == CHECKSUM_PARTIAL)
-		count++;
-#endif
 
-#ifdef NETIF_F_TSO
 	/* Controller Erratum workaround */
 	if (!skb->data_len && tx_ring->last_tx_tso && !skb_is_gso(skb))
 		count++;
-#endif
 
 	count += TXD_USE_COUNT(len, max_txd_pwr);
 
@@ -3602,7 +3584,7 @@
 	 */
 	if (adapter->link_speed == 0)
 		return;
-	if (pdev->error_state && pdev->error_state != pci_channel_io_normal)
+	if (pci_channel_offline(pdev))
 		return;
 
 	spin_lock_irqsave(&adapter->stats_lock, flags);
@@ -3765,8 +3747,8 @@
  * @data: pointer to a network interface device structure
  **/
 
-static
-irqreturn_t e1000_intr_msi(int irq, void *data)
+static irqreturn_t
+e1000_intr_msi(int irq, void *data)
 {
 	struct net_device *netdev = data;
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -3774,49 +3756,27 @@
 #ifndef CONFIG_E1000_NAPI
 	int i;
 #endif
+	uint32_t icr = E1000_READ_REG(hw, ICR);
 
-	/* this code avoids the read of ICR but has to get 1000 interrupts
-	 * at every link change event before it will notice the change */
-	if (++adapter->detect_link >= 1000) {
-		uint32_t icr = E1000_READ_REG(hw, ICR);
 #ifdef CONFIG_E1000_NAPI
-		/* read ICR disables interrupts using IAM, so keep up with our
-		 * enable/disable accounting */
-		atomic_inc(&adapter->irq_sem);
+	/* read ICR disables interrupts using IAM, so keep up with our
+	 * enable/disable accounting */
+	atomic_inc(&adapter->irq_sem);
 #endif
-		adapter->detect_link = 0;
-		if ((icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) &&
-		    (icr & E1000_ICR_INT_ASSERTED)) {
-			hw->get_link_status = 1;
-			/* 80003ES2LAN workaround--
-			* For packet buffer work-around on link down event;
-			* disable receives here in the ISR and
-			* reset adapter in watchdog
-			*/
-			if (netif_carrier_ok(netdev) &&
-			    (adapter->hw.mac_type == e1000_80003es2lan)) {
-				/* disable receives */
-				uint32_t rctl = E1000_READ_REG(hw, RCTL);
-				E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
-			}
-			/* guard against interrupt when we're going down */
-			if (!test_bit(__E1000_DOWN, &adapter->flags))
-				mod_timer(&adapter->watchdog_timer,
-				          jiffies + 1);
+	if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+		hw->get_link_status = 1;
+		/* 80003ES2LAN workaround-- For packet buffer work-around on
+		 * link down event; disable receives here in the ISR and reset
+		 * adapter in watchdog */
+		if (netif_carrier_ok(netdev) &&
+		    (adapter->hw.mac_type == e1000_80003es2lan)) {
+			/* disable receives */
+			uint32_t rctl = E1000_READ_REG(hw, RCTL);
+			E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
 		}
-	} else {
-		E1000_WRITE_REG(hw, ICR, (0xffffffff & ~(E1000_ICR_RXSEQ |
-		                                         E1000_ICR_LSC)));
-		/* bummer we have to flush here, but things break otherwise as
-		 * some event appears to be lost or delayed and throughput
-		 * drops.  In almost all tests this flush is un-necessary */
-		E1000_WRITE_FLUSH(hw);
-#ifdef CONFIG_E1000_NAPI
-		/* Interrupt Auto-Mask (IAM)...upon writing ICR, interrupts are
-		 * masked.  No need for the IMC write, but it does mean we
-		 * should account for it ASAP. */
-		atomic_inc(&adapter->irq_sem);
-#endif
+		/* guard against interrupt when we're going down */
+		if (!test_bit(__E1000_DOWN, &adapter->flags))
+			mod_timer(&adapter->watchdog_timer, jiffies + 1);
 	}
 
 #ifdef CONFIG_E1000_NAPI
@@ -3836,7 +3796,7 @@
 
 	for (i = 0; i < E1000_MAX_INTR; i++)
 		if (unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) &
-		   !e1000_clean_tx_irq(adapter, adapter->tx_ring)))
+		   e1000_clean_tx_irq(adapter, adapter->tx_ring)))
 			break;
 
 	if (likely(adapter->itr_setting & 3))
@@ -3939,7 +3899,7 @@
 
 	for (i = 0; i < E1000_MAX_INTR; i++)
 		if (unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) &
-		   !e1000_clean_tx_irq(adapter, adapter->tx_ring)))
+		   e1000_clean_tx_irq(adapter, adapter->tx_ring)))
 			break;
 
 	if (likely(adapter->itr_setting & 3))
@@ -3989,7 +3949,7 @@
 	poll_dev->quota -= work_done;
 
 	/* If no Tx and not enough Rx work done, exit the polling mode */
-	if ((!tx_cleaned && (work_done == 0)) ||
+	if ((tx_cleaned && (work_done < work_to_do)) ||
 	   !netif_running(poll_dev)) {
 quit_polling:
 		if (likely(adapter->itr_setting & 3))
@@ -4019,7 +3979,7 @@
 #ifdef CONFIG_E1000_NAPI
 	unsigned int count = 0;
 #endif
-	boolean_t cleaned = FALSE;
+	boolean_t cleaned = TRUE;
 	unsigned int total_tx_bytes=0, total_tx_packets=0;
 
 	i = tx_ring->next_to_clean;
@@ -4034,10 +3994,13 @@
 
 			if (cleaned) {
 				struct sk_buff *skb = buffer_info->skb;
-				unsigned int segs = skb_shinfo(skb)->gso_segs;
+				unsigned int segs, bytecount;
+				segs = skb_shinfo(skb)->gso_segs ?: 1;
+				/* multiply data chunks by size of headers */
+				bytecount = ((segs - 1) * skb_headlen(skb)) +
+				            skb->len;
 				total_tx_packets += segs;
-				total_tx_packets++;
-				total_tx_bytes += skb->len;
+				total_tx_bytes += bytecount;
 			}
 			e1000_unmap_and_free_tx_resource(adapter, buffer_info);
 			tx_desc->upper.data = 0;
@@ -4050,7 +4013,10 @@
 #ifdef CONFIG_E1000_NAPI
 #define E1000_TX_WEIGHT 64
 		/* weight of a sort for tx, to avoid endless transmit cleanup */
-		if (count++ == E1000_TX_WEIGHT) break;
+		if (count++ == E1000_TX_WEIGHT) {
+			cleaned = FALSE;
+			break;
+		}
 #endif
 	}
 
diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h
index 18afc0c..10af742 100644
--- a/drivers/net/e1000/e1000_osdep.h
+++ b/drivers/net/e1000/e1000_osdep.h
@@ -48,8 +48,6 @@
     TRUE = 1
 } boolean_t;
 
-#define MSGOUT(S, A, B)	printk(KERN_DEBUG S "\n", A, B)
-
 #ifdef DBG
 #define DEBUGOUT(S)		printk(KERN_DEBUG S "\n")
 #define DEBUGOUT1(S, A...)	printk(KERN_DEBUG S "\n", A)
@@ -58,7 +56,7 @@
 #define DEBUGOUT1(S, A...)
 #endif
 
-#define DEBUGFUNC(F) DEBUGOUT(F)
+#define DEBUGFUNC(F) DEBUGOUT(F "\n")
 #define DEBUGOUT2 DEBUGOUT1
 #define DEBUGOUT3 DEBUGOUT2
 #define DEBUGOUT7 DEBUGOUT3
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index cf2a279..f8862e2 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -760,22 +760,13 @@
 	case SPEED_1000:
 		DPRINTK(PROBE, INFO, "1000 Mbps Speed specified without "
 			"Duplex\n");
-		DPRINTK(PROBE, INFO,
-			"Using Autonegotiation at 1000 Mbps "
-			"Full Duplex only\n");
-		adapter->hw.autoneg = adapter->fc_autoneg = 1;
-		adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
-		break;
+		goto full_duplex_only;
 	case SPEED_1000 + HALF_DUPLEX:
 		DPRINTK(PROBE, INFO,
 			"Half Duplex is not supported at 1000 Mbps\n");
-		DPRINTK(PROBE, INFO,
-			"Using Autonegotiation at 1000 Mbps "
-			"Full Duplex only\n");
-		adapter->hw.autoneg = adapter->fc_autoneg = 1;
-		adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
-		break;
+		/* fall through */
 	case SPEED_1000 + FULL_DUPLEX:
+full_duplex_only:
 		DPRINTK(PROBE, INFO,
 		       "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
 		adapter->hw.autoneg = adapter->fc_autoneg = 1;
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index c62d9c6..b2b0a96 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -355,8 +355,7 @@
 
 	mem_on(ioaddr, shared_mem, (ring_offset>>8));
 
-	/* Packet is always in one chunk -- we can copy + cksum. */
-	eth_io_copy_and_sum(skb, ei_status.mem + (ring_offset & 0xff), count, 0);
+	memcpy_fromio(skb->data, ei_status.mem + (ring_offset & 0xff), count);
 
 	mem_off(ioaddr);
 }
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 272e1ec..42295d6 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -39,7 +39,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME	"ehea"
-#define DRV_VERSION	"EHEA_0045"
+#define DRV_VERSION	"EHEA_0046"
 
 #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
 	| NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 9de2d38..1ef3846 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -76,7 +76,7 @@
 	int x;
 	unsigned char *deb = adr;
 	for (x = 0; x < len; x += 16) {
-		printk(DRV_NAME "%s adr=%p ofs=%04x %016lx %016lx\n", msg,
+		printk(DRV_NAME " %s adr=%p ofs=%04x %016lx %016lx\n", msg,
 			  deb, x, *((u64*)&deb[0]), *((u64*)&deb[8]));
 		deb += 16;
 	}
@@ -555,6 +555,7 @@
 {
 	struct ehea_port *port = param;
 	struct ehea_eqe *eqe;
+	struct ehea_qp *qp;
 	u32 qp_token;
 
 	eqe = ehea_poll_eq(port->qp_eq);
@@ -563,9 +564,14 @@
 		qp_token = EHEA_BMASK_GET(EHEA_EQE_QP_TOKEN, eqe->entry);
 		ehea_error("QP aff_err: entry=0x%lx, token=0x%x",
 			   eqe->entry, qp_token);
+
+		qp = port->port_res[qp_token].qp;
+		ehea_error_data(port->adapter, qp->fw_handle);
 		eqe = ehea_poll_eq(port->qp_eq);
 	}
 
+	queue_work(port->adapter->ehea_wq, &port->reset_task);
+
 	return IRQ_HANDLED;
 }
 
diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c
index 37716e0..bc3c005 100644
--- a/drivers/net/ehea/ehea_phyp.c
+++ b/drivers/net/ehea/ehea_phyp.c
@@ -612,3 +612,13 @@
 				       event_mask,		/* R6 */
 				       0, 0, 0, 0);		/* R7-R12 */
 }
+
+u64 ehea_h_error_data(const u64 adapter_handle, const u64 ressource_handle,
+		      void *rblock)
+{
+	return ehea_plpar_hcall_norets(H_ERROR_DATA,
+				       adapter_handle,          /* R4 */
+				       ressource_handle,        /* R5 */
+				       virt_to_abs(rblock),     /* R6 */
+				       0, 0, 0, 0);             /* R7-R12 */
+}
diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h
index 919f94b..90acddb 100644
--- a/drivers/net/ehea/ehea_phyp.h
+++ b/drivers/net/ehea/ehea_phyp.h
@@ -454,4 +454,7 @@
 u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle,
 			const u64 event_mask);
 
+u64 ehea_h_error_data(const u64 adapter_handle, const u64 ressource_handle,
+		      void *rblock);
+
 #endif	/* __EHEA_PHYP_H__ */
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index f143e13..96ff3b6 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -486,6 +486,7 @@
 	if (!qp)
 		return 0;
 
+	ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle);
 	hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle);
 	if (hret != H_SUCCESS) {
 		ehea_error("destroy_qp failed");
@@ -581,4 +582,45 @@
 	return ret;
 }
 
+void print_error_data(u64 *data)
+{
+	int length;
+	u64 type = EHEA_BMASK_GET(ERROR_DATA_TYPE, data[2]);
+	u64 resource = data[1];
 
+	length = EHEA_BMASK_GET(ERROR_DATA_LENGTH, data[0]);
+
+	if (length > EHEA_PAGESIZE)
+		length = EHEA_PAGESIZE;
+
+	if (type == 0x8) /* Queue Pair */
+		ehea_error("QP (resource=%lX) state: AER=0x%lX, AERR=0x%lX, "
+			   "port=%lX", resource, data[6], data[12], data[22]);
+
+	ehea_dump(data, length, "error data");
+}
+
+void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle)
+{
+	unsigned long ret;
+	u64 *rblock;
+
+	rblock = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!rblock) {
+		ehea_error("Cannot allocate rblock memory.");
+		return;
+	}
+
+	ret = ehea_h_error_data(adapter->handle,
+				res_handle,
+				rblock);
+
+	if (ret == H_R_STATE)
+		ehea_error("No error data is available: %lX.", res_handle);
+	else if (ret == H_SUCCESS)
+		print_error_data(rblock);
+	else
+		ehea_error("Error data could not be fetched: %lX", res_handle);
+
+	kfree(rblock);
+}
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
index 7efdc96..1ff6098 100644
--- a/drivers/net/ehea/ehea_qmr.h
+++ b/drivers/net/ehea/ehea_qmr.h
@@ -180,6 +180,9 @@
 	u64 entry;
 };
 
+#define ERROR_DATA_LENGTH  EHEA_BMASK_IBM(52,63)
+#define ERROR_DATA_TYPE    EHEA_BMASK_IBM(0,7)
+
 static inline void *hw_qeit_calc(struct hw_queue *queue, u64 q_offset)
 {
 	struct ehea_page *current_page;
@@ -355,4 +358,6 @@
 
 int ehea_reg_mr_adapter(struct ehea_adapter *adapter);
 
+void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle);
+
 #endif	/* __EHEA_QMR_H__ */
diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c
index 2d2ea94..822e5bf 100644
--- a/drivers/net/es3210.c
+++ b/drivers/net/es3210.c
@@ -375,7 +375,7 @@
 		memcpy_fromio(skb->data + semi_count, ei_status.mem, count);
 	} else {
 		/* Packet is in one chunk. */
-		eth_io_copy_and_sum(skb, xfer_start, count, 0);
+		memcpy_fromio(skb->data, xfer_start, count);
 	}
 }
 
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 93f2b7a..a363148 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -111,6 +111,7 @@
  *	0.57: 14 May 2006: Mac address set in probe/remove and order corrections.
  *	0.58: 30 Oct 2006: Added support for sideband management unit.
  *	0.59: 30 Oct 2006: Added support for recoverable error.
+ *	0.60: 20 Jan 2007: Code optimizations for rings, rx & tx data paths, and stats.
  *
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
@@ -127,7 +128,7 @@
 #else
 #define DRIVERNAPI
 #endif
-#define FORCEDETH_VERSION		"0.59"
+#define FORCEDETH_VERSION		"0.60"
 #define DRV_NAME			"forcedeth"
 
 #include <linux/module.h>
@@ -173,9 +174,10 @@
 #define DEV_HAS_MSI_X           0x0080  /* device supports MSI-X */
 #define DEV_HAS_POWER_CNTRL     0x0100  /* device supports power savings */
 #define DEV_HAS_PAUSEFRAME_TX   0x0200  /* device supports tx pause frames */
-#define DEV_HAS_STATISTICS      0x0400  /* device supports hw statistics */
-#define DEV_HAS_TEST_EXTENDED   0x0800  /* device supports extended diagnostic test */
-#define DEV_HAS_MGMT_UNIT       0x1000  /* device supports management unit */
+#define DEV_HAS_STATISTICS_V1   0x0400  /* device supports hw statistics version 1 */
+#define DEV_HAS_STATISTICS_V2   0x0800  /* device supports hw statistics version 2 */
+#define DEV_HAS_TEST_EXTENDED   0x1000  /* device supports extended diagnostic test */
+#define DEV_HAS_MGMT_UNIT       0x2000  /* device supports management unit */
 
 enum {
 	NvRegIrqStatus = 0x000,
@@ -210,7 +212,7 @@
  * NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms
  */
 	NvRegPollingInterval = 0x00c,
-#define NVREG_POLL_DEFAULT_THROUGHPUT	970
+#define NVREG_POLL_DEFAULT_THROUGHPUT	970 /* backup tx cleanup if loop max reached */
 #define NVREG_POLL_DEFAULT_CPU	13
 	NvRegMSIMap0 = 0x020,
 	NvRegMSIMap1 = 0x024,
@@ -304,8 +306,8 @@
 #define NVREG_TXRXCTL_RESET	0x0010
 #define NVREG_TXRXCTL_RXCHECK	0x0400
 #define NVREG_TXRXCTL_DESC_1	0
-#define NVREG_TXRXCTL_DESC_2	0x02100
-#define NVREG_TXRXCTL_DESC_3	0x02200
+#define NVREG_TXRXCTL_DESC_2	0x002100
+#define NVREG_TXRXCTL_DESC_3	0xc02200
 #define NVREG_TXRXCTL_VLANSTRIP 0x00040
 #define NVREG_TXRXCTL_VLANINS	0x00080
 	NvRegTxRingPhysAddrHigh = 0x148,
@@ -487,7 +489,8 @@
 
 /* Miscelaneous hardware related defines: */
 #define NV_PCI_REGSZ_VER1      	0x270
-#define NV_PCI_REGSZ_VER2      	0x604
+#define NV_PCI_REGSZ_VER2      	0x2d4
+#define NV_PCI_REGSZ_VER3      	0x604
 
 /* various timeout delays: all in usec */
 #define NV_TXRX_RESET_DELAY	4
@@ -518,12 +521,6 @@
 #define TX_RING_MIN		64
 #define RING_MAX_DESC_VER_1	1024
 #define RING_MAX_DESC_VER_2_3	16384
-/*
- * Difference between the get and put pointers for the tx ring.
- * This is used to throttle the amount of data outstanding in the
- * tx ring.
- */
-#define TX_LIMIT_DIFFERENCE	1
 
 /* rx/tx mac addr + type + vlan + align + slack*/
 #define NV_RX_HEADERS		(64)
@@ -611,9 +608,6 @@
 	{ "tx_carrier_errors" },
 	{ "tx_excess_deferral" },
 	{ "tx_retry_error" },
-	{ "tx_deferral" },
-	{ "tx_packets" },
-	{ "tx_pause" },
 	{ "rx_frame_error" },
 	{ "rx_extra_byte" },
 	{ "rx_late_collision" },
@@ -626,11 +620,17 @@
 	{ "rx_unicast" },
 	{ "rx_multicast" },
 	{ "rx_broadcast" },
-	{ "rx_bytes" },
-	{ "rx_pause" },
-	{ "rx_drop_frame" },
 	{ "rx_packets" },
-	{ "rx_errors_total" }
+	{ "rx_errors_total" },
+	{ "tx_errors_total" },
+
+	/* version 2 stats */
+	{ "tx_deferral" },
+	{ "tx_packets" },
+	{ "rx_bytes" },
+	{ "tx_pause" },
+	{ "rx_pause" },
+	{ "rx_drop_frame" }
 };
 
 struct nv_ethtool_stats {
@@ -643,9 +643,6 @@
 	u64 tx_carrier_errors;
 	u64 tx_excess_deferral;
 	u64 tx_retry_error;
-	u64 tx_deferral;
-	u64 tx_packets;
-	u64 tx_pause;
 	u64 rx_frame_error;
 	u64 rx_extra_byte;
 	u64 rx_late_collision;
@@ -658,13 +655,22 @@
 	u64 rx_unicast;
 	u64 rx_multicast;
 	u64 rx_broadcast;
-	u64 rx_bytes;
-	u64 rx_pause;
-	u64 rx_drop_frame;
 	u64 rx_packets;
 	u64 rx_errors_total;
+	u64 tx_errors_total;
+
+	/* version 2 stats */
+	u64 tx_deferral;
+	u64 tx_packets;
+	u64 rx_bytes;
+	u64 tx_pause;
+	u64 rx_pause;
+	u64 rx_drop_frame;
 };
 
+#define NV_DEV_STATISTICS_V2_COUNT (sizeof(struct nv_ethtool_stats)/sizeof(u64))
+#define NV_DEV_STATISTICS_V1_COUNT (NV_DEV_STATISTICS_V2_COUNT - 6)
+
 /* diagnostics */
 #define NV_TEST_COUNT_BASE 3
 #define NV_TEST_COUNT_EXTENDED 4
@@ -691,6 +697,12 @@
 	{ 0,0 }
 };
 
+struct nv_skb_map {
+	struct sk_buff *skb;
+	dma_addr_t dma;
+	unsigned int dma_len;
+};
+
 /*
  * SMP locking:
  * All hardware access under dev->priv->lock, except the performance
@@ -741,10 +753,12 @@
 	/* rx specific fields.
 	 * Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
 	 */
+	union ring_type get_rx, put_rx, first_rx, last_rx;
+	struct nv_skb_map *get_rx_ctx, *put_rx_ctx;
+	struct nv_skb_map *first_rx_ctx, *last_rx_ctx;
+	struct nv_skb_map *rx_skb;
+
 	union ring_type rx_ring;
-	unsigned int cur_rx, refill_rx;
-	struct sk_buff **rx_skbuff;
-	dma_addr_t *rx_dma;
 	unsigned int rx_buf_sz;
 	unsigned int pkt_limit;
 	struct timer_list oom_kick;
@@ -761,15 +775,15 @@
 	/*
 	 * tx specific fields.
 	 */
+	union ring_type get_tx, put_tx, first_tx, last_tx;
+	struct nv_skb_map *get_tx_ctx, *put_tx_ctx;
+	struct nv_skb_map *first_tx_ctx, *last_tx_ctx;
+	struct nv_skb_map *tx_skb;
+
 	union ring_type tx_ring;
-	unsigned int next_tx, nic_tx;
-	struct sk_buff **tx_skbuff;
-	dma_addr_t *tx_dma;
-	unsigned int *tx_dma_len;
 	u32 tx_flags;
 	int tx_ring_size;
-	int tx_limit_start;
-	int tx_limit_stop;
+	int tx_stop;
 
 	/* vlan fields */
 	struct vlan_group *vlangrp;
@@ -921,16 +935,10 @@
 			pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (np->rx_ring_size + np->tx_ring_size),
 					    np->rx_ring.ex, np->ring_addr);
 	}
-	if (np->rx_skbuff)
-		kfree(np->rx_skbuff);
-	if (np->rx_dma)
-		kfree(np->rx_dma);
-	if (np->tx_skbuff)
-		kfree(np->tx_skbuff);
-	if (np->tx_dma)
-		kfree(np->tx_dma);
-	if (np->tx_dma_len)
-		kfree(np->tx_dma_len);
+	if (np->rx_skb)
+		kfree(np->rx_skb);
+	if (np->tx_skb)
+		kfree(np->tx_skb);
 }
 
 static int using_multi_irqs(struct net_device *dev)
@@ -1279,6 +1287,61 @@
 	pci_push(base);
 }
 
+static void nv_get_hw_stats(struct net_device *dev)
+{
+	struct fe_priv *np = netdev_priv(dev);
+	u8 __iomem *base = get_hwbase(dev);
+
+	np->estats.tx_bytes += readl(base + NvRegTxCnt);
+	np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt);
+	np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt);
+	np->estats.tx_many_rexmt += readl(base + NvRegTxManyReXmt);
+	np->estats.tx_late_collision += readl(base + NvRegTxLateCol);
+	np->estats.tx_fifo_errors += readl(base + NvRegTxUnderflow);
+	np->estats.tx_carrier_errors += readl(base + NvRegTxLossCarrier);
+	np->estats.tx_excess_deferral += readl(base + NvRegTxExcessDef);
+	np->estats.tx_retry_error += readl(base + NvRegTxRetryErr);
+	np->estats.rx_frame_error += readl(base + NvRegRxFrameErr);
+	np->estats.rx_extra_byte += readl(base + NvRegRxExtraByte);
+	np->estats.rx_late_collision += readl(base + NvRegRxLateCol);
+	np->estats.rx_runt += readl(base + NvRegRxRunt);
+	np->estats.rx_frame_too_long += readl(base + NvRegRxFrameTooLong);
+	np->estats.rx_over_errors += readl(base + NvRegRxOverflow);
+	np->estats.rx_crc_errors += readl(base + NvRegRxFCSErr);
+	np->estats.rx_frame_align_error += readl(base + NvRegRxFrameAlignErr);
+	np->estats.rx_length_error += readl(base + NvRegRxLenErr);
+	np->estats.rx_unicast += readl(base + NvRegRxUnicast);
+	np->estats.rx_multicast += readl(base + NvRegRxMulticast);
+	np->estats.rx_broadcast += readl(base + NvRegRxBroadcast);
+	np->estats.rx_packets =
+		np->estats.rx_unicast +
+		np->estats.rx_multicast +
+		np->estats.rx_broadcast;
+	np->estats.rx_errors_total =
+		np->estats.rx_crc_errors +
+		np->estats.rx_over_errors +
+		np->estats.rx_frame_error +
+		(np->estats.rx_frame_align_error - np->estats.rx_extra_byte) +
+		np->estats.rx_late_collision +
+		np->estats.rx_runt +
+		np->estats.rx_frame_too_long;
+	np->estats.tx_errors_total =
+		np->estats.tx_late_collision +
+		np->estats.tx_fifo_errors +
+		np->estats.tx_carrier_errors +
+		np->estats.tx_excess_deferral +
+		np->estats.tx_retry_error;
+
+	if (np->driver_data & DEV_HAS_STATISTICS_V2) {
+		np->estats.tx_deferral += readl(base + NvRegTxDef);
+		np->estats.tx_packets += readl(base + NvRegTxFrame);
+		np->estats.rx_bytes += readl(base + NvRegRxCnt);
+		np->estats.tx_pause += readl(base + NvRegTxPause);
+		np->estats.rx_pause += readl(base + NvRegRxPause);
+		np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame);
+	}
+}
+
 /*
  * nv_get_stats: dev->get_stats function
  * Get latest stats value from the nic.
@@ -1289,10 +1352,19 @@
 {
 	struct fe_priv *np = netdev_priv(dev);
 
-	/* It seems that the nic always generates interrupts and doesn't
-	 * accumulate errors internally. Thus the current values in np->stats
-	 * are already up to date.
-	 */
+	/* If the nic supports hw counters then retrieve latest values */
+	if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2)) {
+		nv_get_hw_stats(dev);
+
+		/* copy to net_device stats */
+		np->stats.tx_bytes = np->estats.tx_bytes;
+		np->stats.tx_fifo_errors = np->estats.tx_fifo_errors;
+		np->stats.tx_carrier_errors = np->estats.tx_carrier_errors;
+		np->stats.rx_crc_errors = np->estats.rx_crc_errors;
+		np->stats.rx_over_errors = np->estats.rx_over_errors;
+		np->stats.rx_errors = np->estats.rx_errors_total;
+		np->stats.tx_errors = np->estats.tx_errors_total;
+	}
 	return &np->stats;
 }
 
@@ -1304,43 +1376,63 @@
 static int nv_alloc_rx(struct net_device *dev)
 {
 	struct fe_priv *np = netdev_priv(dev);
-	unsigned int refill_rx = np->refill_rx;
-	int nr;
+	struct ring_desc* less_rx;
 
-	while (np->cur_rx != refill_rx) {
-		struct sk_buff *skb;
+	less_rx = np->get_rx.orig;
+	if (less_rx-- == np->first_rx.orig)
+		less_rx = np->last_rx.orig;
 
-		nr = refill_rx % np->rx_ring_size;
-		if (np->rx_skbuff[nr] == NULL) {
-
-			skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
-			if (!skb)
-				break;
-
+	while (np->put_rx.orig != less_rx) {
+		struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
+		if (skb) {
 			skb->dev = dev;
-			np->rx_skbuff[nr] = skb;
-		} else {
-			skb = np->rx_skbuff[nr];
-		}
-		np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data,
-					skb->end-skb->data, PCI_DMA_FROMDEVICE);
-		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-			np->rx_ring.orig[nr].buf = cpu_to_le32(np->rx_dma[nr]);
+			np->put_rx_ctx->skb = skb;
+			np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data,
+							     skb->end-skb->data, PCI_DMA_FROMDEVICE);
+			np->put_rx_ctx->dma_len = skb->end-skb->data;
+			np->put_rx.orig->buf = cpu_to_le32(np->put_rx_ctx->dma);
 			wmb();
-			np->rx_ring.orig[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
+			np->put_rx.orig->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
+			if (unlikely(np->put_rx.orig++ == np->last_rx.orig))
+				np->put_rx.orig = np->first_rx.orig;
+			if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
+				np->put_rx_ctx = np->first_rx_ctx;
 		} else {
-			np->rx_ring.ex[nr].bufhigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
-			np->rx_ring.ex[nr].buflow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
-			wmb();
-			np->rx_ring.ex[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
+			return 1;
 		}
-		dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n",
-					dev->name, refill_rx);
-		refill_rx++;
 	}
-	np->refill_rx = refill_rx;
-	if (np->cur_rx - refill_rx == np->rx_ring_size)
-		return 1;
+	return 0;
+}
+
+static int nv_alloc_rx_optimized(struct net_device *dev)
+{
+	struct fe_priv *np = netdev_priv(dev);
+	struct ring_desc_ex* less_rx;
+
+	less_rx = np->get_rx.ex;
+	if (less_rx-- == np->first_rx.ex)
+		less_rx = np->last_rx.ex;
+
+	while (np->put_rx.ex != less_rx) {
+		struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
+		if (skb) {
+			skb->dev = dev;
+			np->put_rx_ctx->skb = skb;
+			np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data,
+							     skb->end-skb->data, PCI_DMA_FROMDEVICE);
+			np->put_rx_ctx->dma_len = skb->end-skb->data;
+			np->put_rx.ex->bufhigh = cpu_to_le64(np->put_rx_ctx->dma) >> 32;
+			np->put_rx.ex->buflow = cpu_to_le64(np->put_rx_ctx->dma) & 0x0FFFFFFFF;
+			wmb();
+			np->put_rx.ex->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
+			if (unlikely(np->put_rx.ex++ == np->last_rx.ex))
+				np->put_rx.ex = np->first_rx.ex;
+			if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
+				np->put_rx_ctx = np->first_rx_ctx;
+		} else {
+			return 1;
+		}
+	}
 	return 0;
 }
 
@@ -1358,6 +1450,7 @@
 {
 	struct net_device *dev = (struct net_device *) data;
 	struct fe_priv *np = netdev_priv(dev);
+	int retcode;
 
 	if (!using_multi_irqs(dev)) {
 		if (np->msi_flags & NV_MSI_X_ENABLED)
@@ -1367,7 +1460,11 @@
 	} else {
 		disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
 	}
-	if (nv_alloc_rx(dev)) {
+	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+		retcode = nv_alloc_rx(dev);
+	else
+		retcode = nv_alloc_rx_optimized(dev);
+	if (retcode) {
 		spin_lock_irq(&np->lock);
 		if (!np->in_shutdown)
 			mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
@@ -1388,56 +1485,81 @@
 {
 	struct fe_priv *np = netdev_priv(dev);
 	int i;
+	np->get_rx = np->put_rx = np->first_rx = np->rx_ring;
+	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+		np->last_rx.orig = &np->rx_ring.orig[np->rx_ring_size-1];
+	else
+		np->last_rx.ex = &np->rx_ring.ex[np->rx_ring_size-1];
+	np->get_rx_ctx = np->put_rx_ctx = np->first_rx_ctx = np->rx_skb;
+	np->last_rx_ctx = &np->rx_skb[np->rx_ring_size-1];
 
-	np->cur_rx = np->rx_ring_size;
-	np->refill_rx = 0;
-	for (i = 0; i < np->rx_ring_size; i++)
-		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+	for (i = 0; i < np->rx_ring_size; i++) {
+		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
 			np->rx_ring.orig[i].flaglen = 0;
-	        else
+			np->rx_ring.orig[i].buf = 0;
+		} else {
 			np->rx_ring.ex[i].flaglen = 0;
+			np->rx_ring.ex[i].txvlan = 0;
+			np->rx_ring.ex[i].bufhigh = 0;
+			np->rx_ring.ex[i].buflow = 0;
+		}
+		np->rx_skb[i].skb = NULL;
+		np->rx_skb[i].dma = 0;
+	}
 }
 
 static void nv_init_tx(struct net_device *dev)
 {
 	struct fe_priv *np = netdev_priv(dev);
 	int i;
+	np->get_tx = np->put_tx = np->first_tx = np->tx_ring;
+	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+		np->last_tx.orig = &np->tx_ring.orig[np->tx_ring_size-1];
+	else
+		np->last_tx.ex = &np->tx_ring.ex[np->tx_ring_size-1];
+	np->get_tx_ctx = np->put_tx_ctx = np->first_tx_ctx = np->tx_skb;
+	np->last_tx_ctx = &np->tx_skb[np->tx_ring_size-1];
 
-	np->next_tx = np->nic_tx = 0;
 	for (i = 0; i < np->tx_ring_size; i++) {
-		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
 			np->tx_ring.orig[i].flaglen = 0;
-	        else
+			np->tx_ring.orig[i].buf = 0;
+		} else {
 			np->tx_ring.ex[i].flaglen = 0;
-		np->tx_skbuff[i] = NULL;
-		np->tx_dma[i] = 0;
+			np->tx_ring.ex[i].txvlan = 0;
+			np->tx_ring.ex[i].bufhigh = 0;
+			np->tx_ring.ex[i].buflow = 0;
+		}
+		np->tx_skb[i].skb = NULL;
+		np->tx_skb[i].dma = 0;
 	}
 }
 
 static int nv_init_ring(struct net_device *dev)
 {
+	struct fe_priv *np = netdev_priv(dev);
+
 	nv_init_tx(dev);
 	nv_init_rx(dev);
-	return nv_alloc_rx(dev);
+	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+		return nv_alloc_rx(dev);
+	else
+		return nv_alloc_rx_optimized(dev);
 }
 
-static int nv_release_txskb(struct net_device *dev, unsigned int skbnr)
+static int nv_release_txskb(struct net_device *dev, struct nv_skb_map* tx_skb)
 {
 	struct fe_priv *np = netdev_priv(dev);
 
-	dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d\n",
-		dev->name, skbnr);
-
-	if (np->tx_dma[skbnr]) {
-		pci_unmap_page(np->pci_dev, np->tx_dma[skbnr],
-			       np->tx_dma_len[skbnr],
+	if (tx_skb->dma) {
+		pci_unmap_page(np->pci_dev, tx_skb->dma,
+			       tx_skb->dma_len,
 			       PCI_DMA_TODEVICE);
-		np->tx_dma[skbnr] = 0;
+		tx_skb->dma = 0;
 	}
-
-	if (np->tx_skbuff[skbnr]) {
-		dev_kfree_skb_any(np->tx_skbuff[skbnr]);
-		np->tx_skbuff[skbnr] = NULL;
+	if (tx_skb->skb) {
+		dev_kfree_skb_any(tx_skb->skb);
+		tx_skb->skb = NULL;
 		return 1;
 	} else {
 		return 0;
@@ -1450,11 +1572,16 @@
 	unsigned int i;
 
 	for (i = 0; i < np->tx_ring_size; i++) {
-		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
 			np->tx_ring.orig[i].flaglen = 0;
-		else
+			np->tx_ring.orig[i].buf = 0;
+		} else {
 			np->tx_ring.ex[i].flaglen = 0;
-		if (nv_release_txskb(dev, i))
+			np->tx_ring.ex[i].txvlan = 0;
+			np->tx_ring.ex[i].bufhigh = 0;
+			np->tx_ring.ex[i].buflow = 0;
+		}
+		if (nv_release_txskb(dev, &np->tx_skb[i]))
 			np->stats.tx_dropped++;
 	}
 }
@@ -1463,18 +1590,24 @@
 {
 	struct fe_priv *np = netdev_priv(dev);
 	int i;
+
 	for (i = 0; i < np->rx_ring_size; i++) {
-		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
 			np->rx_ring.orig[i].flaglen = 0;
-		else
+			np->rx_ring.orig[i].buf = 0;
+		} else {
 			np->rx_ring.ex[i].flaglen = 0;
+			np->rx_ring.ex[i].txvlan = 0;
+			np->rx_ring.ex[i].bufhigh = 0;
+			np->rx_ring.ex[i].buflow = 0;
+		}
 		wmb();
-		if (np->rx_skbuff[i]) {
-			pci_unmap_single(np->pci_dev, np->rx_dma[i],
-						np->rx_skbuff[i]->end-np->rx_skbuff[i]->data,
+		if (np->rx_skb[i].skb) {
+			pci_unmap_single(np->pci_dev, np->rx_skb[i].dma,
+						np->rx_skb[i].skb->end-np->rx_skb[i].skb->data,
 						PCI_DMA_FROMDEVICE);
-			dev_kfree_skb(np->rx_skbuff[i]);
-			np->rx_skbuff[i] = NULL;
+			dev_kfree_skb(np->rx_skb[i].skb);
+			np->rx_skb[i].skb = NULL;
 		}
 	}
 }
@@ -1485,6 +1618,11 @@
 	nv_drain_rx(dev);
 }
 
+static inline u32 nv_get_empty_tx_slots(struct fe_priv *np)
+{
+	return (u32)(np->tx_ring_size - ((np->tx_ring_size + (np->put_tx_ctx - np->get_tx_ctx)) % np->tx_ring_size));
+}
+
 /*
  * nv_start_xmit: dev->hard_start_xmit function
  * Called with netif_tx_lock held.
@@ -1495,14 +1633,16 @@
 	u32 tx_flags = 0;
 	u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
 	unsigned int fragments = skb_shinfo(skb)->nr_frags;
-	unsigned int nr = (np->next_tx - 1) % np->tx_ring_size;
-	unsigned int start_nr = np->next_tx % np->tx_ring_size;
 	unsigned int i;
 	u32 offset = 0;
 	u32 bcnt;
 	u32 size = skb->len-skb->data_len;
 	u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
-	u32 tx_flags_vlan = 0;
+	u32 empty_slots;
+	struct ring_desc* put_tx;
+	struct ring_desc* start_tx;
+	struct ring_desc* prev_tx;
+	struct nv_skb_map* prev_tx_ctx;
 
 	/* add fragments to entries count */
 	for (i = 0; i < fragments; i++) {
@@ -1510,34 +1650,35 @@
 			   ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
 	}
 
-	spin_lock_irq(&np->lock);
-
-	if ((np->next_tx - np->nic_tx + entries - 1) > np->tx_limit_stop) {
-		spin_unlock_irq(&np->lock);
+	empty_slots = nv_get_empty_tx_slots(np);
+	if (unlikely(empty_slots <= entries)) {
+		spin_lock_irq(&np->lock);
 		netif_stop_queue(dev);
+		np->tx_stop = 1;
+		spin_unlock_irq(&np->lock);
 		return NETDEV_TX_BUSY;
 	}
 
+	start_tx = put_tx = np->put_tx.orig;
+
 	/* setup the header buffer */
 	do {
+		prev_tx = put_tx;
+		prev_tx_ctx = np->put_tx_ctx;
 		bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
-		nr = (nr + 1) % np->tx_ring_size;
-
-		np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
+		np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
 						PCI_DMA_TODEVICE);
-		np->tx_dma_len[nr] = bcnt;
+		np->put_tx_ctx->dma_len = bcnt;
+		put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma);
+		put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
 
-		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-			np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
-			np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
-		} else {
-			np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
-			np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
-			np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
-		}
 		tx_flags = np->tx_flags;
 		offset += bcnt;
 		size -= bcnt;
+		if (unlikely(put_tx++ == np->last_tx.orig))
+			put_tx = np->first_tx.orig;
+		if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+			np->put_tx_ctx = np->first_tx_ctx;
 	} while (size);
 
 	/* setup the fragments */
@@ -1547,58 +1688,46 @@
 		offset = 0;
 
 		do {
+			prev_tx = put_tx;
+			prev_tx_ctx = np->put_tx_ctx;
 			bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
-			nr = (nr + 1) % np->tx_ring_size;
+			np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
+							   PCI_DMA_TODEVICE);
+			np->put_tx_ctx->dma_len = bcnt;
+			put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma);
+			put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
 
-			np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
-						      PCI_DMA_TODEVICE);
-			np->tx_dma_len[nr] = bcnt;
-
-			if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-				np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
-				np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
-			} else {
-				np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
-				np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
-				np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
-			}
 			offset += bcnt;
 			size -= bcnt;
+			if (unlikely(put_tx++ == np->last_tx.orig))
+				put_tx = np->first_tx.orig;
+			if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+				np->put_tx_ctx = np->first_tx_ctx;
 		} while (size);
 	}
 
 	/* set last fragment flag  */
-	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-		np->tx_ring.orig[nr].flaglen |= cpu_to_le32(tx_flags_extra);
-	} else {
-		np->tx_ring.ex[nr].flaglen |= cpu_to_le32(tx_flags_extra);
-	}
+	prev_tx->flaglen |= cpu_to_le32(tx_flags_extra);
 
-	np->tx_skbuff[nr] = skb;
+	/* save skb in this slot's context area */
+	prev_tx_ctx->skb = skb;
 
-#ifdef NETIF_F_TSO
 	if (skb_is_gso(skb))
 		tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
 	else
-#endif
-	tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
+		tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
 			 NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0;
 
-	/* vlan tag */
-	if (np->vlangrp && vlan_tx_tag_present(skb)) {
-		tx_flags_vlan = NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb);
-	}
+	spin_lock_irq(&np->lock);
 
 	/* set tx flags */
-	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-		np->tx_ring.orig[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
-	} else {
-		np->tx_ring.ex[start_nr].txvlan = cpu_to_le32(tx_flags_vlan);
-		np->tx_ring.ex[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
-	}
+	start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
+	np->put_tx.orig = put_tx;
 
-	dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n",
-		dev->name, np->next_tx, entries, tx_flags_extra);
+	spin_unlock_irq(&np->lock);
+
+	dprintk(KERN_DEBUG "%s: nv_start_xmit: entries %d queued for transmission. tx_flags_extra: %x\n",
+		dev->name, entries, tx_flags_extra);
 	{
 		int j;
 		for (j=0; j<64; j++) {
@@ -1609,12 +1738,136 @@
 		dprintk("\n");
 	}
 
-	np->next_tx += entries;
+	dev->trans_start = jiffies;
+	writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
+	return NETDEV_TX_OK;
+}
+
+static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev)
+{
+	struct fe_priv *np = netdev_priv(dev);
+	u32 tx_flags = 0;
+	u32 tx_flags_extra;
+	unsigned int fragments = skb_shinfo(skb)->nr_frags;
+	unsigned int i;
+	u32 offset = 0;
+	u32 bcnt;
+	u32 size = skb->len-skb->data_len;
+	u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+	u32 empty_slots;
+	struct ring_desc_ex* put_tx;
+	struct ring_desc_ex* start_tx;
+	struct ring_desc_ex* prev_tx;
+	struct nv_skb_map* prev_tx_ctx;
+
+	/* add fragments to entries count */
+	for (i = 0; i < fragments; i++) {
+		entries += (skb_shinfo(skb)->frags[i].size >> NV_TX2_TSO_MAX_SHIFT) +
+			   ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+	}
+
+	empty_slots = nv_get_empty_tx_slots(np);
+	if (unlikely(empty_slots <= entries)) {
+		spin_lock_irq(&np->lock);
+		netif_stop_queue(dev);
+		np->tx_stop = 1;
+		spin_unlock_irq(&np->lock);
+		return NETDEV_TX_BUSY;
+	}
+
+	start_tx = put_tx = np->put_tx.ex;
+
+	/* setup the header buffer */
+	do {
+		prev_tx = put_tx;
+		prev_tx_ctx = np->put_tx_ctx;
+		bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+		np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
+						PCI_DMA_TODEVICE);
+		np->put_tx_ctx->dma_len = bcnt;
+		put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32;
+		put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF;
+		put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
+
+		tx_flags = NV_TX2_VALID;
+		offset += bcnt;
+		size -= bcnt;
+		if (unlikely(put_tx++ == np->last_tx.ex))
+			put_tx = np->first_tx.ex;
+		if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+			np->put_tx_ctx = np->first_tx_ctx;
+	} while (size);
+
+	/* setup the fragments */
+	for (i = 0; i < fragments; i++) {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+		u32 size = frag->size;
+		offset = 0;
+
+		do {
+			prev_tx = put_tx;
+			prev_tx_ctx = np->put_tx_ctx;
+			bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+			np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
+							   PCI_DMA_TODEVICE);
+			np->put_tx_ctx->dma_len = bcnt;
+			put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32;
+			put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF;
+			put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
+
+			offset += bcnt;
+			size -= bcnt;
+			if (unlikely(put_tx++ == np->last_tx.ex))
+				put_tx = np->first_tx.ex;
+			if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+				np->put_tx_ctx = np->first_tx_ctx;
+		} while (size);
+	}
+
+	/* set last fragment flag  */
+	prev_tx->flaglen |= cpu_to_le32(NV_TX2_LASTPACKET);
+
+	/* save skb in this slot's context area */
+	prev_tx_ctx->skb = skb;
+
+	if (skb_is_gso(skb))
+		tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
+	else
+		tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
+			 NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0;
+
+	/* vlan tag */
+	if (likely(!np->vlangrp)) {
+		start_tx->txvlan = 0;
+	} else {
+		if (vlan_tx_tag_present(skb))
+			start_tx->txvlan = cpu_to_le32(NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb));
+		else
+			start_tx->txvlan = 0;
+	}
+
+	spin_lock_irq(&np->lock);
+
+	/* set tx flags */
+	start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
+	np->put_tx.ex = put_tx;
+
+	spin_unlock_irq(&np->lock);
+
+	dprintk(KERN_DEBUG "%s: nv_start_xmit_optimized: entries %d queued for transmission. tx_flags_extra: %x\n",
+		dev->name, entries, tx_flags_extra);
+	{
+		int j;
+		for (j=0; j<64; j++) {
+			if ((j%16) == 0)
+				dprintk("\n%03x:", j);
+			dprintk(" %02x", ((unsigned char*)skb->data)[j]);
+		}
+		dprintk("\n");
+	}
 
 	dev->trans_start = jiffies;
-	spin_unlock_irq(&np->lock);
 	writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
-	pci_push(get_hwbase(dev));
 	return NETDEV_TX_OK;
 }
 
@@ -1627,26 +1880,22 @@
 {
 	struct fe_priv *np = netdev_priv(dev);
 	u32 flags;
-	unsigned int i;
-	struct sk_buff *skb;
+	struct ring_desc* orig_get_tx = np->get_tx.orig;
 
-	while (np->nic_tx != np->next_tx) {
-		i = np->nic_tx % np->tx_ring_size;
+	while ((np->get_tx.orig != np->put_tx.orig) &&
+	       !((flags = le32_to_cpu(np->get_tx.orig->flaglen)) & NV_TX_VALID)) {
 
-		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
-			flags = le32_to_cpu(np->tx_ring.orig[i].flaglen);
-		else
-			flags = le32_to_cpu(np->tx_ring.ex[i].flaglen);
+		dprintk(KERN_DEBUG "%s: nv_tx_done: flags 0x%x.\n",
+					dev->name, flags);
 
-		dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, flags 0x%x.\n",
-					dev->name, np->nic_tx, flags);
-		if (flags & NV_TX_VALID)
-			break;
+		pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma,
+			       np->get_tx_ctx->dma_len,
+			       PCI_DMA_TODEVICE);
+		np->get_tx_ctx->dma = 0;
+
 		if (np->desc_ver == DESC_VER_1) {
 			if (flags & NV_TX_LASTPACKET) {
-				skb = np->tx_skbuff[i];
-				if (flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
-					     NV_TX_UNDERFLOW|NV_TX_ERROR)) {
+				if (flags & NV_TX_ERROR) {
 					if (flags & NV_TX_UNDERFLOW)
 						np->stats.tx_fifo_errors++;
 					if (flags & NV_TX_CARRIERLOST)
@@ -1654,14 +1903,14 @@
 					np->stats.tx_errors++;
 				} else {
 					np->stats.tx_packets++;
-					np->stats.tx_bytes += skb->len;
+					np->stats.tx_bytes += np->get_tx_ctx->skb->len;
 				}
+				dev_kfree_skb_any(np->get_tx_ctx->skb);
+				np->get_tx_ctx->skb = NULL;
 			}
 		} else {
 			if (flags & NV_TX2_LASTPACKET) {
-				skb = np->tx_skbuff[i];
-				if (flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
-					     NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
+				if (flags & NV_TX2_ERROR) {
 					if (flags & NV_TX2_UNDERFLOW)
 						np->stats.tx_fifo_errors++;
 					if (flags & NV_TX2_CARRIERLOST)
@@ -1669,15 +1918,56 @@
 					np->stats.tx_errors++;
 				} else {
 					np->stats.tx_packets++;
-					np->stats.tx_bytes += skb->len;
+					np->stats.tx_bytes += np->get_tx_ctx->skb->len;
 				}
+				dev_kfree_skb_any(np->get_tx_ctx->skb);
+				np->get_tx_ctx->skb = NULL;
 			}
 		}
-		nv_release_txskb(dev, i);
-		np->nic_tx++;
+		if (unlikely(np->get_tx.orig++ == np->last_tx.orig))
+			np->get_tx.orig = np->first_tx.orig;
+		if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx))
+			np->get_tx_ctx = np->first_tx_ctx;
 	}
-	if (np->next_tx - np->nic_tx < np->tx_limit_start)
+	if (unlikely((np->tx_stop == 1) && (np->get_tx.orig != orig_get_tx))) {
+		np->tx_stop = 0;
 		netif_wake_queue(dev);
+	}
+}
+
+static void nv_tx_done_optimized(struct net_device *dev, int limit)
+{
+	struct fe_priv *np = netdev_priv(dev);
+	u32 flags;
+	struct ring_desc_ex* orig_get_tx = np->get_tx.ex;
+
+	while ((np->get_tx.ex != np->put_tx.ex) &&
+	       !((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX_VALID) &&
+	       (limit-- > 0)) {
+
+		dprintk(KERN_DEBUG "%s: nv_tx_done_optimized: flags 0x%x.\n",
+					dev->name, flags);
+
+		pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma,
+			       np->get_tx_ctx->dma_len,
+			       PCI_DMA_TODEVICE);
+		np->get_tx_ctx->dma = 0;
+
+		if (flags & NV_TX2_LASTPACKET) {
+			if (!(flags & NV_TX2_ERROR))
+				np->stats.tx_packets++;
+			dev_kfree_skb_any(np->get_tx_ctx->skb);
+			np->get_tx_ctx->skb = NULL;
+		}
+		if (unlikely(np->get_tx.ex++ == np->last_tx.ex))
+			np->get_tx.ex = np->first_tx.ex;
+		if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx))
+			np->get_tx_ctx = np->first_tx_ctx;
+	}
+	if (unlikely((np->tx_stop == 1) && (np->get_tx.ex != orig_get_tx))) {
+		np->tx_stop = 0;
+		netif_wake_queue(dev);
+	}
 }
 
 /*
@@ -1700,9 +1990,8 @@
 	{
 		int i;
 
-		printk(KERN_INFO "%s: Ring at %lx: next %d nic %d\n",
-				dev->name, (unsigned long)np->ring_addr,
-				np->next_tx, np->nic_tx);
+		printk(KERN_INFO "%s: Ring at %lx\n",
+		       dev->name, (unsigned long)np->ring_addr);
 		printk(KERN_INFO "%s: Dumping tx registers\n", dev->name);
 		for (i=0;i<=np->register_size;i+= 32) {
 			printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
@@ -1750,13 +2039,16 @@
 	nv_stop_tx(dev);
 
 	/* 2) check that the packets were not sent already: */
-	nv_tx_done(dev);
+	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+		nv_tx_done(dev);
+	else
+		nv_tx_done_optimized(dev, np->tx_ring_size);
 
 	/* 3) if there are dead entries: clear everything */
-	if (np->next_tx != np->nic_tx) {
+	if (np->get_tx_ctx != np->put_tx_ctx) {
 		printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name);
 		nv_drain_tx(dev);
-		np->next_tx = np->nic_tx = 0;
+		nv_init_tx(dev);
 		setup_hw_rings(dev, NV_SETUP_TX_RING);
 		netif_wake_queue(dev);
 	}
@@ -1823,40 +2115,27 @@
 {
 	struct fe_priv *np = netdev_priv(dev);
 	u32 flags;
-	u32 vlanflags = 0;
-	int count;
+	u32 rx_processed_cnt = 0;
+	struct sk_buff *skb;
+	int len;
 
- 	for (count = 0; count < limit; ++count) {
-		struct sk_buff *skb;
-		int len;
-		int i;
-		if (np->cur_rx - np->refill_rx >= np->rx_ring_size)
-			break;	/* we scanned the whole ring - do not continue */
+	while((np->get_rx.orig != np->put_rx.orig) &&
+	      !((flags = le32_to_cpu(np->get_rx.orig->flaglen)) & NV_RX_AVAIL) &&
+		(rx_processed_cnt++ < limit)) {
 
-		i = np->cur_rx % np->rx_ring_size;
-		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-			flags = le32_to_cpu(np->rx_ring.orig[i].flaglen);
-			len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver);
-		} else {
-			flags = le32_to_cpu(np->rx_ring.ex[i].flaglen);
-			len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver);
-			vlanflags = le32_to_cpu(np->rx_ring.ex[i].buflow);
-		}
-
-		dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, flags 0x%x.\n",
-					dev->name, np->cur_rx, flags);
-
-		if (flags & NV_RX_AVAIL)
-			break;	/* still owned by hardware, */
+		dprintk(KERN_DEBUG "%s: nv_rx_process: flags 0x%x.\n",
+					dev->name, flags);
 
 		/*
 		 * the packet is for us - immediately tear down the pci mapping.
 		 * TODO: check if a prefetch of the first cacheline improves
 		 * the performance.
 		 */
-		pci_unmap_single(np->pci_dev, np->rx_dma[i],
-				np->rx_skbuff[i]->end-np->rx_skbuff[i]->data,
+		pci_unmap_single(np->pci_dev, np->get_rx_ctx->dma,
+				np->get_rx_ctx->dma_len,
 				PCI_DMA_FROMDEVICE);
+		skb = np->get_rx_ctx->skb;
+		np->get_rx_ctx->skb = NULL;
 
 		{
 			int j;
@@ -1864,123 +2143,228 @@
 			for (j=0; j<64; j++) {
 				if ((j%16) == 0)
 					dprintk("\n%03x:", j);
-				dprintk(" %02x", ((unsigned char*)np->rx_skbuff[i]->data)[j]);
+				dprintk(" %02x", ((unsigned char*)skb->data)[j]);
 			}
 			dprintk("\n");
 		}
 		/* look at what we actually got: */
 		if (np->desc_ver == DESC_VER_1) {
-			if (!(flags & NV_RX_DESCRIPTORVALID))
-				goto next_pkt;
-
-			if (flags & NV_RX_ERROR) {
-				if (flags & NV_RX_MISSEDFRAME) {
-					np->stats.rx_missed_errors++;
-					np->stats.rx_errors++;
-					goto next_pkt;
-				}
-				if (flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
-					np->stats.rx_errors++;
-					goto next_pkt;
-				}
-				if (flags & NV_RX_CRCERR) {
-					np->stats.rx_crc_errors++;
-					np->stats.rx_errors++;
-					goto next_pkt;
-				}
-				if (flags & NV_RX_OVERFLOW) {
-					np->stats.rx_over_errors++;
-					np->stats.rx_errors++;
-					goto next_pkt;
-				}
-				if (flags & NV_RX_ERROR4) {
-					len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
-					if (len < 0) {
+			if (likely(flags & NV_RX_DESCRIPTORVALID)) {
+				len = flags & LEN_MASK_V1;
+				if (unlikely(flags & NV_RX_ERROR)) {
+					if (flags & NV_RX_ERROR4) {
+						len = nv_getlen(dev, skb->data, len);
+						if (len < 0) {
+							np->stats.rx_errors++;
+							dev_kfree_skb(skb);
+							goto next_pkt;
+						}
+					}
+					/* framing errors are soft errors */
+					else if (flags & NV_RX_FRAMINGERR) {
+						if (flags & NV_RX_SUBSTRACT1) {
+							len--;
+						}
+					}
+					/* the rest are hard errors */
+					else {
+						if (flags & NV_RX_MISSEDFRAME)
+							np->stats.rx_missed_errors++;
+						if (flags & NV_RX_CRCERR)
+							np->stats.rx_crc_errors++;
+						if (flags & NV_RX_OVERFLOW)
+							np->stats.rx_over_errors++;
 						np->stats.rx_errors++;
+						dev_kfree_skb(skb);
 						goto next_pkt;
 					}
 				}
-				/* framing errors are soft errors. */
-				if (flags & NV_RX_FRAMINGERR) {
-					if (flags & NV_RX_SUBSTRACT1) {
-						len--;
-					}
-				}
+			} else {
+				dev_kfree_skb(skb);
+				goto next_pkt;
 			}
 		} else {
-			if (!(flags & NV_RX2_DESCRIPTORVALID))
-				goto next_pkt;
-
-			if (flags & NV_RX2_ERROR) {
-				if (flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
-					np->stats.rx_errors++;
-					goto next_pkt;
-				}
-				if (flags & NV_RX2_CRCERR) {
-					np->stats.rx_crc_errors++;
-					np->stats.rx_errors++;
-					goto next_pkt;
-				}
-				if (flags & NV_RX2_OVERFLOW) {
-					np->stats.rx_over_errors++;
-					np->stats.rx_errors++;
-					goto next_pkt;
-				}
-				if (flags & NV_RX2_ERROR4) {
-					len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
-					if (len < 0) {
+			if (likely(flags & NV_RX2_DESCRIPTORVALID)) {
+				len = flags & LEN_MASK_V2;
+				if (unlikely(flags & NV_RX2_ERROR)) {
+					if (flags & NV_RX2_ERROR4) {
+						len = nv_getlen(dev, skb->data, len);
+						if (len < 0) {
+							np->stats.rx_errors++;
+							dev_kfree_skb(skb);
+							goto next_pkt;
+						}
+					}
+					/* framing errors are soft errors */
+					else if (flags & NV_RX2_FRAMINGERR) {
+						if (flags & NV_RX2_SUBSTRACT1) {
+							len--;
+						}
+					}
+					/* the rest are hard errors */
+					else {
+						if (flags & NV_RX2_CRCERR)
+							np->stats.rx_crc_errors++;
+						if (flags & NV_RX2_OVERFLOW)
+							np->stats.rx_over_errors++;
 						np->stats.rx_errors++;
+						dev_kfree_skb(skb);
 						goto next_pkt;
 					}
 				}
-				/* framing errors are soft errors */
-				if (flags & NV_RX2_FRAMINGERR) {
-					if (flags & NV_RX2_SUBSTRACT1) {
-						len--;
+				if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ {
+					skb->ip_summed = CHECKSUM_UNNECESSARY;
+				} else {
+					if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 ||
+					    (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) {
+						skb->ip_summed = CHECKSUM_UNNECESSARY;
 					}
 				}
-			}
-			if (np->rx_csum) {
-				flags &= NV_RX2_CHECKSUMMASK;
-				if (flags == NV_RX2_CHECKSUMOK1 ||
-				    flags == NV_RX2_CHECKSUMOK2 ||
-				    flags == NV_RX2_CHECKSUMOK3) {
-					dprintk(KERN_DEBUG "%s: hw checksum hit!.\n", dev->name);
-					np->rx_skbuff[i]->ip_summed = CHECKSUM_UNNECESSARY;
-				} else {
-					dprintk(KERN_DEBUG "%s: hwchecksum miss!.\n", dev->name);
-				}
+			} else {
+				dev_kfree_skb(skb);
+				goto next_pkt;
 			}
 		}
 		/* got a valid packet - forward it to the network core */
-		skb = np->rx_skbuff[i];
-		np->rx_skbuff[i] = NULL;
-
 		skb_put(skb, len);
 		skb->protocol = eth_type_trans(skb, dev);
-		dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n",
-					dev->name, np->cur_rx, len, skb->protocol);
+		dprintk(KERN_DEBUG "%s: nv_rx_process: %d bytes, proto %d accepted.\n",
+					dev->name, len, skb->protocol);
 #ifdef CONFIG_FORCEDETH_NAPI
-		if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
-			vlan_hwaccel_receive_skb(skb, np->vlangrp,
-						 vlanflags & NV_RX3_VLAN_TAG_MASK);
-		else
-			netif_receive_skb(skb);
+		netif_receive_skb(skb);
 #else
-		if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
-			vlan_hwaccel_rx(skb, np->vlangrp,
-					vlanflags & NV_RX3_VLAN_TAG_MASK);
-		else
-			netif_rx(skb);
+		netif_rx(skb);
 #endif
 		dev->last_rx = jiffies;
 		np->stats.rx_packets++;
 		np->stats.rx_bytes += len;
 next_pkt:
-		np->cur_rx++;
+		if (unlikely(np->get_rx.orig++ == np->last_rx.orig))
+			np->get_rx.orig = np->first_rx.orig;
+		if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx))
+			np->get_rx_ctx = np->first_rx_ctx;
 	}
 
-	return count;
+	return rx_processed_cnt;
+}
+
+static int nv_rx_process_optimized(struct net_device *dev, int limit)
+{
+	struct fe_priv *np = netdev_priv(dev);
+	u32 flags;
+	u32 vlanflags = 0;
+	u32 rx_processed_cnt = 0;
+	struct sk_buff *skb;
+	int len;
+
+	while((np->get_rx.ex != np->put_rx.ex) &&
+	      !((flags = le32_to_cpu(np->get_rx.ex->flaglen)) & NV_RX2_AVAIL) &&
+	      (rx_processed_cnt++ < limit)) {
+
+		dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: flags 0x%x.\n",
+					dev->name, flags);
+
+		/*
+		 * the packet is for us - immediately tear down the pci mapping.
+		 * TODO: check if a prefetch of the first cacheline improves
+		 * the performance.
+		 */
+		pci_unmap_single(np->pci_dev, np->get_rx_ctx->dma,
+				np->get_rx_ctx->dma_len,
+				PCI_DMA_FROMDEVICE);
+		skb = np->get_rx_ctx->skb;
+		np->get_rx_ctx->skb = NULL;
+
+		{
+			int j;
+			dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",flags);
+			for (j=0; j<64; j++) {
+				if ((j%16) == 0)
+					dprintk("\n%03x:", j);
+				dprintk(" %02x", ((unsigned char*)skb->data)[j]);
+			}
+			dprintk("\n");
+		}
+		/* look at what we actually got: */
+		if (likely(flags & NV_RX2_DESCRIPTORVALID)) {
+			len = flags & LEN_MASK_V2;
+			if (unlikely(flags & NV_RX2_ERROR)) {
+				if (flags & NV_RX2_ERROR4) {
+					len = nv_getlen(dev, skb->data, len);
+					if (len < 0) {
+						dev_kfree_skb(skb);
+						goto next_pkt;
+					}
+				}
+				/* framing errors are soft errors */
+				else if (flags & NV_RX2_FRAMINGERR) {
+					if (flags & NV_RX2_SUBSTRACT1) {
+						len--;
+					}
+				}
+				/* the rest are hard errors */
+				else {
+					dev_kfree_skb(skb);
+					goto next_pkt;
+				}
+			}
+
+			if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ {
+				skb->ip_summed = CHECKSUM_UNNECESSARY;
+			} else {
+				if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 ||
+				    (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) {
+					skb->ip_summed = CHECKSUM_UNNECESSARY;
+				}
+			}
+
+			/* got a valid packet - forward it to the network core */
+			skb_put(skb, len);
+			skb->protocol = eth_type_trans(skb, dev);
+			prefetch(skb->data);
+
+			dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: %d bytes, proto %d accepted.\n",
+				dev->name, len, skb->protocol);
+
+			if (likely(!np->vlangrp)) {
+#ifdef CONFIG_FORCEDETH_NAPI
+				netif_receive_skb(skb);
+#else
+				netif_rx(skb);
+#endif
+			} else {
+				vlanflags = le32_to_cpu(np->get_rx.ex->buflow);
+				if (vlanflags & NV_RX3_VLAN_TAG_PRESENT) {
+#ifdef CONFIG_FORCEDETH_NAPI
+					vlan_hwaccel_receive_skb(skb, np->vlangrp,
+								 vlanflags & NV_RX3_VLAN_TAG_MASK);
+#else
+					vlan_hwaccel_rx(skb, np->vlangrp,
+							vlanflags & NV_RX3_VLAN_TAG_MASK);
+#endif
+				} else {
+#ifdef CONFIG_FORCEDETH_NAPI
+					netif_receive_skb(skb);
+#else
+					netif_rx(skb);
+#endif
+				}
+			}
+
+			dev->last_rx = jiffies;
+			np->stats.rx_packets++;
+			np->stats.rx_bytes += len;
+		} else {
+			dev_kfree_skb(skb);
+		}
+next_pkt:
+		if (unlikely(np->get_rx.ex++ == np->last_rx.ex))
+			np->get_rx.ex = np->first_rx.ex;
+		if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx))
+			np->get_rx_ctx = np->first_rx_ctx;
+	}
+
+	return rx_processed_cnt;
 }
 
 static void set_bufsize(struct net_device *dev)
@@ -2456,7 +2840,6 @@
 			events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
 			writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus);
 		}
-		pci_push(base);
 		dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
 		if (!(events & np->irqmask))
 			break;
@@ -2465,22 +2848,46 @@
 		nv_tx_done(dev);
 		spin_unlock(&np->lock);
 
-		if (events & NVREG_IRQ_LINK) {
+#ifdef CONFIG_FORCEDETH_NAPI
+		if (events & NVREG_IRQ_RX_ALL) {
+			netif_rx_schedule(dev);
+
+			/* Disable furthur receive irq's */
+			spin_lock(&np->lock);
+			np->irqmask &= ~NVREG_IRQ_RX_ALL;
+
+			if (np->msi_flags & NV_MSI_X_ENABLED)
+				writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
+			else
+				writel(np->irqmask, base + NvRegIrqMask);
+			spin_unlock(&np->lock);
+		}
+#else
+		if (nv_rx_process(dev, dev->weight)) {
+			if (unlikely(nv_alloc_rx(dev))) {
+				spin_lock(&np->lock);
+				if (!np->in_shutdown)
+					mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+				spin_unlock(&np->lock);
+			}
+		}
+#endif
+		if (unlikely(events & NVREG_IRQ_LINK)) {
 			spin_lock(&np->lock);
 			nv_link_irq(dev);
 			spin_unlock(&np->lock);
 		}
-		if (np->need_linktimer && time_after(jiffies, np->link_timeout)) {
+		if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
 			spin_lock(&np->lock);
 			nv_linkchange(dev);
 			spin_unlock(&np->lock);
 			np->link_timeout = jiffies + LINK_TIMEOUT;
 		}
-		if (events & (NVREG_IRQ_TX_ERR)) {
+		if (unlikely(events & (NVREG_IRQ_TX_ERR))) {
 			dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
 						dev->name, events);
 		}
-		if (events & (NVREG_IRQ_UNKNOWN)) {
+		if (unlikely(events & (NVREG_IRQ_UNKNOWN))) {
 			printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
 						dev->name, events);
 		}
@@ -2501,30 +2908,7 @@
 			spin_unlock(&np->lock);
 			break;
 		}
-#ifdef CONFIG_FORCEDETH_NAPI
-		if (events & NVREG_IRQ_RX_ALL) {
-			netif_rx_schedule(dev);
-
-			/* Disable furthur receive irq's */
-			spin_lock(&np->lock);
-			np->irqmask &= ~NVREG_IRQ_RX_ALL;
-
-			if (np->msi_flags & NV_MSI_X_ENABLED)
-				writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
-			else
-				writel(np->irqmask, base + NvRegIrqMask);
-			spin_unlock(&np->lock);
-		}
-#else
-		nv_rx_process(dev, dev->weight);
-		if (nv_alloc_rx(dev)) {
-			spin_lock(&np->lock);
-			if (!np->in_shutdown)
-				mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
-			spin_unlock(&np->lock);
-		}
-#endif
-		if (i > max_interrupt_work) {
+		if (unlikely(i > max_interrupt_work)) {
 			spin_lock(&np->lock);
 			/* disable interrupts on the nic */
 			if (!(np->msi_flags & NV_MSI_X_ENABLED))
@@ -2548,6 +2932,124 @@
 	return IRQ_RETVAL(i);
 }
 
+#define TX_WORK_PER_LOOP  64
+#define RX_WORK_PER_LOOP  64
+/**
+ * All _optimized functions are used to help increase performance
+ * (reduce CPU and increase throughput). They use descripter version 3,
+ * compiler directives, and reduce memory accesses.
+ */
+static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
+{
+	struct net_device *dev = (struct net_device *) data;
+	struct fe_priv *np = netdev_priv(dev);
+	u8 __iomem *base = get_hwbase(dev);
+	u32 events;
+	int i;
+
+	dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized\n", dev->name);
+
+	for (i=0; ; i++) {
+		if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
+			events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
+			writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
+		} else {
+			events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
+			writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus);
+		}
+		dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
+		if (!(events & np->irqmask))
+			break;
+
+		spin_lock(&np->lock);
+		nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
+		spin_unlock(&np->lock);
+
+#ifdef CONFIG_FORCEDETH_NAPI
+		if (events & NVREG_IRQ_RX_ALL) {
+			netif_rx_schedule(dev);
+
+			/* Disable furthur receive irq's */
+			spin_lock(&np->lock);
+			np->irqmask &= ~NVREG_IRQ_RX_ALL;
+
+			if (np->msi_flags & NV_MSI_X_ENABLED)
+				writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
+			else
+				writel(np->irqmask, base + NvRegIrqMask);
+			spin_unlock(&np->lock);
+		}
+#else
+		if (nv_rx_process_optimized(dev, dev->weight)) {
+			if (unlikely(nv_alloc_rx_optimized(dev))) {
+				spin_lock(&np->lock);
+				if (!np->in_shutdown)
+					mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+				spin_unlock(&np->lock);
+			}
+		}
+#endif
+		if (unlikely(events & NVREG_IRQ_LINK)) {
+			spin_lock(&np->lock);
+			nv_link_irq(dev);
+			spin_unlock(&np->lock);
+		}
+		if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
+			spin_lock(&np->lock);
+			nv_linkchange(dev);
+			spin_unlock(&np->lock);
+			np->link_timeout = jiffies + LINK_TIMEOUT;
+		}
+		if (unlikely(events & (NVREG_IRQ_TX_ERR))) {
+			dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
+						dev->name, events);
+		}
+		if (unlikely(events & (NVREG_IRQ_UNKNOWN))) {
+			printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
+						dev->name, events);
+		}
+		if (unlikely(events & NVREG_IRQ_RECOVER_ERROR)) {
+			spin_lock(&np->lock);
+			/* disable interrupts on the nic */
+			if (!(np->msi_flags & NV_MSI_X_ENABLED))
+				writel(0, base + NvRegIrqMask);
+			else
+				writel(np->irqmask, base + NvRegIrqMask);
+			pci_push(base);
+
+			if (!np->in_shutdown) {
+				np->nic_poll_irq = np->irqmask;
+				np->recover_error = 1;
+				mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+			}
+			spin_unlock(&np->lock);
+			break;
+		}
+
+		if (unlikely(i > max_interrupt_work)) {
+			spin_lock(&np->lock);
+			/* disable interrupts on the nic */
+			if (!(np->msi_flags & NV_MSI_X_ENABLED))
+				writel(0, base + NvRegIrqMask);
+			else
+				writel(np->irqmask, base + NvRegIrqMask);
+			pci_push(base);
+
+			if (!np->in_shutdown) {
+				np->nic_poll_irq = np->irqmask;
+				mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+			}
+			printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
+			spin_unlock(&np->lock);
+			break;
+		}
+
+	}
+	dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized completed\n", dev->name);
+
+	return IRQ_RETVAL(i);
+}
+
 static irqreturn_t nv_nic_irq_tx(int foo, void *data)
 {
 	struct net_device *dev = (struct net_device *) data;
@@ -2562,20 +3064,19 @@
 	for (i=0; ; i++) {
 		events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_TX_ALL;
 		writel(NVREG_IRQ_TX_ALL, base + NvRegMSIXIrqStatus);
-		pci_push(base);
 		dprintk(KERN_DEBUG "%s: tx irq: %08x\n", dev->name, events);
 		if (!(events & np->irqmask))
 			break;
 
 		spin_lock_irqsave(&np->lock, flags);
-		nv_tx_done(dev);
+		nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
 		spin_unlock_irqrestore(&np->lock, flags);
 
-		if (events & (NVREG_IRQ_TX_ERR)) {
+		if (unlikely(events & (NVREG_IRQ_TX_ERR))) {
 			dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
 						dev->name, events);
 		}
-		if (i > max_interrupt_work) {
+		if (unlikely(i > max_interrupt_work)) {
 			spin_lock_irqsave(&np->lock, flags);
 			/* disable interrupts on the nic */
 			writel(NVREG_IRQ_TX_ALL, base + NvRegIrqMask);
@@ -2604,7 +3105,10 @@
 	u8 __iomem *base = get_hwbase(dev);
 	unsigned long flags;
 
-	pkts = nv_rx_process(dev, limit);
+	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+		pkts = nv_rx_process(dev, limit);
+	else
+		pkts = nv_rx_process_optimized(dev, limit);
 
 	if (nv_alloc_rx(dev)) {
 		spin_lock_irqsave(&np->lock, flags);
@@ -2670,20 +3174,20 @@
 	for (i=0; ; i++) {
 		events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL;
 		writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus);
-		pci_push(base);
 		dprintk(KERN_DEBUG "%s: rx irq: %08x\n", dev->name, events);
 		if (!(events & np->irqmask))
 			break;
 
-		nv_rx_process(dev, dev->weight);
-		if (nv_alloc_rx(dev)) {
-			spin_lock_irqsave(&np->lock, flags);
-			if (!np->in_shutdown)
-				mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
-			spin_unlock_irqrestore(&np->lock, flags);
+		if (nv_rx_process_optimized(dev, dev->weight)) {
+			if (unlikely(nv_alloc_rx_optimized(dev))) {
+				spin_lock_irqsave(&np->lock, flags);
+				if (!np->in_shutdown)
+					mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+				spin_unlock_irqrestore(&np->lock, flags);
+			}
 		}
 
-		if (i > max_interrupt_work) {
+		if (unlikely(i > max_interrupt_work)) {
 			spin_lock_irqsave(&np->lock, flags);
 			/* disable interrupts on the nic */
 			writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
@@ -2718,11 +3222,15 @@
 	for (i=0; ; i++) {
 		events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_OTHER;
 		writel(NVREG_IRQ_OTHER, base + NvRegMSIXIrqStatus);
-		pci_push(base);
 		dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
 		if (!(events & np->irqmask))
 			break;
 
+		/* check tx in case we reached max loop limit in tx isr */
+		spin_lock_irqsave(&np->lock, flags);
+		nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
+		spin_unlock_irqrestore(&np->lock, flags);
+
 		if (events & NVREG_IRQ_LINK) {
 			spin_lock_irqsave(&np->lock, flags);
 			nv_link_irq(dev);
@@ -2752,7 +3260,7 @@
 			printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
 						dev->name, events);
 		}
-		if (i > max_interrupt_work) {
+		if (unlikely(i > max_interrupt_work)) {
 			spin_lock_irqsave(&np->lock, flags);
 			/* disable interrupts on the nic */
 			writel(NVREG_IRQ_OTHER, base + NvRegIrqMask);
@@ -2835,6 +3343,16 @@
 	u8 __iomem *base = get_hwbase(dev);
 	int ret = 1;
 	int i;
+	irqreturn_t (*handler)(int foo, void *data);
+
+	if (intr_test) {
+		handler = nv_nic_irq_test;
+	} else {
+		if (np->desc_ver == DESC_VER_3)
+			handler = nv_nic_irq_optimized;
+		else
+			handler = nv_nic_irq;
+	}
 
 	if (np->msi_flags & NV_MSI_X_CAPABLE) {
 		for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) {
@@ -2872,10 +3390,7 @@
 				set_msix_vector_map(dev, NV_MSI_X_VECTOR_OTHER, NVREG_IRQ_OTHER);
 			} else {
 				/* Request irq for all interrupts */
-				if ((!intr_test &&
-				     request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
-				    (intr_test &&
-				     request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) {
+				if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, handler, IRQF_SHARED, dev->name, dev) != 0) {
 					printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
 					pci_disable_msix(np->pci_dev);
 					np->msi_flags &= ~NV_MSI_X_ENABLED;
@@ -2891,8 +3406,7 @@
 	if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) {
 		if ((ret = pci_enable_msi(np->pci_dev)) == 0) {
 			np->msi_flags |= NV_MSI_ENABLED;
-			if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
-			    (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) {
+			if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) {
 				printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
 				pci_disable_msi(np->pci_dev);
 				np->msi_flags &= ~NV_MSI_ENABLED;
@@ -2907,8 +3421,7 @@
 		}
 	}
 	if (ret != 0) {
-		if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
-		    (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0))
+		if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0)
 			goto out_err;
 
 	}
@@ -3051,47 +3564,8 @@
 {
 	struct net_device *dev = (struct net_device *) data;
 	struct fe_priv *np = netdev_priv(dev);
-	u8 __iomem *base = get_hwbase(dev);
 
-	np->estats.tx_bytes += readl(base + NvRegTxCnt);
-	np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt);
-	np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt);
-	np->estats.tx_many_rexmt += readl(base + NvRegTxManyReXmt);
-	np->estats.tx_late_collision += readl(base + NvRegTxLateCol);
-	np->estats.tx_fifo_errors += readl(base + NvRegTxUnderflow);
-	np->estats.tx_carrier_errors += readl(base + NvRegTxLossCarrier);
-	np->estats.tx_excess_deferral += readl(base + NvRegTxExcessDef);
-	np->estats.tx_retry_error += readl(base + NvRegTxRetryErr);
-	np->estats.tx_deferral += readl(base + NvRegTxDef);
-	np->estats.tx_packets += readl(base + NvRegTxFrame);
-	np->estats.tx_pause += readl(base + NvRegTxPause);
-	np->estats.rx_frame_error += readl(base + NvRegRxFrameErr);
-	np->estats.rx_extra_byte += readl(base + NvRegRxExtraByte);
-	np->estats.rx_late_collision += readl(base + NvRegRxLateCol);
-	np->estats.rx_runt += readl(base + NvRegRxRunt);
-	np->estats.rx_frame_too_long += readl(base + NvRegRxFrameTooLong);
-	np->estats.rx_over_errors += readl(base + NvRegRxOverflow);
-	np->estats.rx_crc_errors += readl(base + NvRegRxFCSErr);
-	np->estats.rx_frame_align_error += readl(base + NvRegRxFrameAlignErr);
-	np->estats.rx_length_error += readl(base + NvRegRxLenErr);
-	np->estats.rx_unicast += readl(base + NvRegRxUnicast);
-	np->estats.rx_multicast += readl(base + NvRegRxMulticast);
-	np->estats.rx_broadcast += readl(base + NvRegRxBroadcast);
-	np->estats.rx_bytes += readl(base + NvRegRxCnt);
-	np->estats.rx_pause += readl(base + NvRegRxPause);
-	np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame);
-	np->estats.rx_packets =
-		np->estats.rx_unicast +
-		np->estats.rx_multicast +
-		np->estats.rx_broadcast;
-	np->estats.rx_errors_total =
-		np->estats.rx_crc_errors +
-		np->estats.rx_over_errors +
-		np->estats.rx_frame_error +
-		(np->estats.rx_frame_align_error - np->estats.rx_extra_byte) +
-		np->estats.rx_late_collision +
-		np->estats.rx_runt +
-		np->estats.rx_frame_too_long;
+	nv_get_hw_stats(dev);
 
 	if (!np->in_shutdown)
 		mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL);
@@ -3465,7 +3939,7 @@
 {
 	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
-	u8 *rxtx_ring, *rx_skbuff, *tx_skbuff, *rx_dma, *tx_dma, *tx_dma_len;
+	u8 *rxtx_ring, *rx_skbuff, *tx_skbuff;
 	dma_addr_t ring_addr;
 
 	if (ring->rx_pending < RX_RING_MIN ||
@@ -3491,12 +3965,9 @@
 					    sizeof(struct ring_desc_ex) * (ring->rx_pending + ring->tx_pending),
 					    &ring_addr);
 	}
-	rx_skbuff = kmalloc(sizeof(struct sk_buff*) * ring->rx_pending, GFP_KERNEL);
-	rx_dma = kmalloc(sizeof(dma_addr_t) * ring->rx_pending, GFP_KERNEL);
-	tx_skbuff = kmalloc(sizeof(struct sk_buff*) * ring->tx_pending, GFP_KERNEL);
-	tx_dma = kmalloc(sizeof(dma_addr_t) * ring->tx_pending, GFP_KERNEL);
-	tx_dma_len = kmalloc(sizeof(unsigned int) * ring->tx_pending, GFP_KERNEL);
-	if (!rxtx_ring || !rx_skbuff || !rx_dma || !tx_skbuff || !tx_dma || !tx_dma_len) {
+	rx_skbuff = kmalloc(sizeof(struct nv_skb_map) * ring->rx_pending, GFP_KERNEL);
+	tx_skbuff = kmalloc(sizeof(struct nv_skb_map) * ring->tx_pending, GFP_KERNEL);
+	if (!rxtx_ring || !rx_skbuff || !tx_skbuff) {
 		/* fall back to old rings */
 		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
 			if (rxtx_ring)
@@ -3509,14 +3980,8 @@
 		}
 		if (rx_skbuff)
 			kfree(rx_skbuff);
-		if (rx_dma)
-			kfree(rx_dma);
 		if (tx_skbuff)
 			kfree(tx_skbuff);
-		if (tx_dma)
-			kfree(tx_dma);
-		if (tx_dma_len)
-			kfree(tx_dma_len);
 		goto exit;
 	}
 
@@ -3538,8 +4003,6 @@
 	/* set new values */
 	np->rx_ring_size = ring->rx_pending;
 	np->tx_ring_size = ring->tx_pending;
-	np->tx_limit_stop = ring->tx_pending - TX_LIMIT_DIFFERENCE;
-	np->tx_limit_start = ring->tx_pending - TX_LIMIT_DIFFERENCE - 1;
 	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
 		np->rx_ring.orig = (struct ring_desc*)rxtx_ring;
 		np->tx_ring.orig = &np->rx_ring.orig[np->rx_ring_size];
@@ -3547,18 +4010,12 @@
 		np->rx_ring.ex = (struct ring_desc_ex*)rxtx_ring;
 		np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
 	}
-	np->rx_skbuff = (struct sk_buff**)rx_skbuff;
-	np->rx_dma = (dma_addr_t*)rx_dma;
-	np->tx_skbuff = (struct sk_buff**)tx_skbuff;
-	np->tx_dma = (dma_addr_t*)tx_dma;
-	np->tx_dma_len = (unsigned int*)tx_dma_len;
+	np->rx_skb = (struct nv_skb_map*)rx_skbuff;
+	np->tx_skb = (struct nv_skb_map*)tx_skbuff;
 	np->ring_addr = ring_addr;
 
-	memset(np->rx_skbuff, 0, sizeof(struct sk_buff*) * np->rx_ring_size);
-	memset(np->rx_dma, 0, sizeof(dma_addr_t) * np->rx_ring_size);
-	memset(np->tx_skbuff, 0, sizeof(struct sk_buff*) * np->tx_ring_size);
-	memset(np->tx_dma, 0, sizeof(dma_addr_t) * np->tx_ring_size);
-	memset(np->tx_dma_len, 0, sizeof(unsigned int) * np->tx_ring_size);
+	memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size);
+	memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size);
 
 	if (netif_running(dev)) {
 		/* reinit driver view of the queues */
@@ -3727,8 +4184,10 @@
 {
 	struct fe_priv *np = netdev_priv(dev);
 
-	if (np->driver_data & DEV_HAS_STATISTICS)
-		return sizeof(struct nv_ethtool_stats)/sizeof(u64);
+	if (np->driver_data & DEV_HAS_STATISTICS_V1)
+		return NV_DEV_STATISTICS_V1_COUNT;
+	else if (np->driver_data & DEV_HAS_STATISTICS_V2)
+		return NV_DEV_STATISTICS_V2_COUNT;
 	else
 		return 0;
 }
@@ -3955,7 +4414,7 @@
 			dprintk(KERN_DEBUG "%s: loopback len mismatch %d vs %d\n",
 				dev->name, len, pkt_len);
 		} else {
-			rx_skb = np->rx_skbuff[0];
+			rx_skb = np->rx_skb[0].skb;
 			for (i = 0; i < pkt_len; i++) {
 				if (rx_skb->data[i] != (u8)(i & 0xff)) {
 					ret = 0;
@@ -4315,7 +4774,7 @@
 		mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
 
 	/* start statistics timer */
-	if (np->driver_data & DEV_HAS_STATISTICS)
+	if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2))
 		mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL);
 
 	spin_unlock_irq(&np->lock);
@@ -4412,7 +4871,9 @@
 	if (err < 0)
 		goto out_disable;
 
-	if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS))
+	if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V2))
+		np->register_size = NV_PCI_REGSZ_VER3;
+	else if (id->driver_data & DEV_HAS_STATISTICS_V1)
 		np->register_size = NV_PCI_REGSZ_VER2;
 	else
 		np->register_size = NV_PCI_REGSZ_VER1;
@@ -4475,10 +4936,8 @@
 		np->rx_csum = 1;
 		np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
 		dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
-#ifdef NETIF_F_TSO
 		dev->features |= NETIF_F_TSO;
-#endif
- 	}
+	}
 
 	np->vlanctl_bits = 0;
 	if (id->driver_data & DEV_HAS_VLAN) {
@@ -4512,8 +4971,6 @@
 
 	np->rx_ring_size = RX_RING_DEFAULT;
 	np->tx_ring_size = TX_RING_DEFAULT;
-	np->tx_limit_stop = np->tx_ring_size - TX_LIMIT_DIFFERENCE;
-	np->tx_limit_start = np->tx_ring_size - TX_LIMIT_DIFFERENCE - 1;
 
 	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
 		np->rx_ring.orig = pci_alloc_consistent(pci_dev,
@@ -4530,22 +4987,19 @@
 			goto out_unmap;
 		np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
 	}
-	np->rx_skbuff = kmalloc(sizeof(struct sk_buff*) * np->rx_ring_size, GFP_KERNEL);
-	np->rx_dma = kmalloc(sizeof(dma_addr_t) * np->rx_ring_size, GFP_KERNEL);
-	np->tx_skbuff = kmalloc(sizeof(struct sk_buff*) * np->tx_ring_size, GFP_KERNEL);
-	np->tx_dma = kmalloc(sizeof(dma_addr_t) * np->tx_ring_size, GFP_KERNEL);
-	np->tx_dma_len = kmalloc(sizeof(unsigned int) * np->tx_ring_size, GFP_KERNEL);
-	if (!np->rx_skbuff || !np->rx_dma || !np->tx_skbuff || !np->tx_dma || !np->tx_dma_len)
+	np->rx_skb = kmalloc(sizeof(struct nv_skb_map) * np->rx_ring_size, GFP_KERNEL);
+	np->tx_skb = kmalloc(sizeof(struct nv_skb_map) * np->tx_ring_size, GFP_KERNEL);
+	if (!np->rx_skb || !np->tx_skb)
 		goto out_freering;
-	memset(np->rx_skbuff, 0, sizeof(struct sk_buff*) * np->rx_ring_size);
-	memset(np->rx_dma, 0, sizeof(dma_addr_t) * np->rx_ring_size);
-	memset(np->tx_skbuff, 0, sizeof(struct sk_buff*) * np->tx_ring_size);
-	memset(np->tx_dma, 0, sizeof(dma_addr_t) * np->tx_ring_size);
-	memset(np->tx_dma_len, 0, sizeof(unsigned int) * np->tx_ring_size);
+	memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size);
+	memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size);
 
 	dev->open = nv_open;
 	dev->stop = nv_close;
-	dev->hard_start_xmit = nv_start_xmit;
+	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+		dev->hard_start_xmit = nv_start_xmit;
+	else
+		dev->hard_start_xmit = nv_start_xmit_optimized;
 	dev->get_stats = nv_get_stats;
 	dev->change_mtu = nv_change_mtu;
 	dev->set_mac_address = nv_set_mac_address;
@@ -4553,7 +5007,7 @@
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = nv_poll_controller;
 #endif
-	dev->weight = 64;
+	dev->weight = RX_WORK_PER_LOOP;
 #ifdef CONFIG_FORCEDETH_NAPI
 	dev->poll = nv_napi_poll;
 #endif
@@ -4868,83 +5322,83 @@
 	},
 	{	/* CK804 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
 	},
 	{	/* CK804 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
 	},
 	{	/* MCP04 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
 	},
 	{	/* MCP04 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
 	},
 	{	/* MCP51 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
 	},
 	{	/* MCP51 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
 	},
 	{	/* MCP55 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
 	},
 	{	/* MCP55 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
 	},
 	{	/* MCP61 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
 	},
 	{	/* MCP61 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_17),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
 	},
 	{	/* MCP61 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_18),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
 	},
 	{	/* MCP61 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
 	},
 	{	/* MCP65 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
 	},
 	{	/* MCP65 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
 	},
 	{	/* MCP65 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
 	},
 	{	/* MCP65 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
 	},
 	{	/* MCP67 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
 	},
 	{	/* MCP67 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
 	},
 	{	/* MCP67 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
 	},
 	{	/* MCP67 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
 	},
 	{0,},
 };
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index 92590d8..569be22 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -9,6 +9,7 @@
 #include <linux/dma-mapping.h>
 
 #include <linux/fs_enet_pd.h>
+#include <asm/fs_pd.h>
 
 #ifdef CONFIG_CPM1
 #include <asm/commproc.h>
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 6d71bea..0d6943d 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -42,8 +42,6 @@
 
 #include "gianfar.h"
 
-#define is_power_of_2(x)        ((x) != 0 && (((x) & ((x) - 1)) == 0))
-
 extern void gfar_start(struct net_device *dev);
 extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
 
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 844c136..7dc5185 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -3034,7 +3034,7 @@
 		goto out2;
 #endif
 #ifdef CONFIG_PCI
-	err = pci_module_init(&hp100_pci_driver);
+	err = pci_register_driver(&hp100_pci_driver);
 	if (err && err != -ENODEV)
 		goto out3;
 #endif
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 2194b56..0e9ba3c 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -1102,7 +1102,7 @@
 	}
 
 	kobject_init(&port->kobject);
-	port->kobject.parent = &dev->class_dev.kobj;
+	port->kobject.parent = &dev->dev.kobj;
 	port->kobject.ktype  = &veth_port_ktype;
 	kobject_set_name(&port->kobject, "veth_port");
 	if (0 != kobject_add(&port->kobject))
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
index f4aba43..cf30a10 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -61,9 +61,7 @@
 #include <net/pkt_sched.h>
 #include <linux/list.h>
 #include <linux/reboot.h>
-#ifdef NETIF_F_TSO
 #include <net/checksum.h>
-#endif
 
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index 82c044d..d6628bd 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -82,10 +82,8 @@
 	{"tx_restart_queue", IXGB_STAT(restart_queue) },
 	{"rx_long_length_errors", IXGB_STAT(stats.roc)},
 	{"rx_short_length_errors", IXGB_STAT(stats.ruc)},
-#ifdef NETIF_F_TSO
 	{"tx_tcp_seg_good", IXGB_STAT(stats.tsctc)},
 	{"tx_tcp_seg_failed", IXGB_STAT(stats.tsctfc)},
-#endif
 	{"rx_flow_control_xon", IXGB_STAT(stats.xonrxc)},
 	{"rx_flow_control_xoff", IXGB_STAT(stats.xoffrxc)},
 	{"tx_flow_control_xon", IXGB_STAT(stats.xontxc)},
@@ -240,7 +238,6 @@
 	return 0;
 }
 
-#ifdef NETIF_F_TSO
 static int
 ixgb_set_tso(struct net_device *netdev, uint32_t data)
 {
@@ -250,7 +247,6 @@
 		netdev->features &= ~NETIF_F_TSO;
 	return 0;
 } 
-#endif /* NETIF_F_TSO */
 
 static uint32_t
 ixgb_get_msglevel(struct net_device *netdev)
@@ -722,10 +718,8 @@
 	.set_sg	= ethtool_op_set_sg,
 	.get_msglevel = ixgb_get_msglevel,
 	.set_msglevel = ixgb_set_msglevel,
-#ifdef NETIF_F_TSO
 	.get_tso = ethtool_op_get_tso,
 	.set_tso = ixgb_set_tso,
-#endif
 	.get_strings = ixgb_get_strings,
 	.phys_id = ixgb_phys_id,
 	.get_stats_count = ixgb_get_stats_count,
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index a083a91..0c36828 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -456,9 +456,7 @@
 			   NETIF_F_HW_VLAN_TX |
 			   NETIF_F_HW_VLAN_RX |
 			   NETIF_F_HW_VLAN_FILTER;
-#ifdef NETIF_F_TSO
 	netdev->features |= NETIF_F_TSO;
-#endif
 #ifdef NETIF_F_LLTX
 	netdev->features |= NETIF_F_LLTX;
 #endif
@@ -1176,7 +1174,6 @@
 static int
 ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb)
 {
-#ifdef NETIF_F_TSO
 	struct ixgb_context_desc *context_desc;
 	unsigned int i;
 	uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
@@ -1233,7 +1230,6 @@
 
 		return 1;
 	}
-#endif
 
 	return 0;
 }
@@ -1609,7 +1605,7 @@
 	struct pci_dev *pdev = adapter->pdev;
 
 	/* Prevent stats update while adapter is being reset */
-	if (pdev->error_state && pdev->error_state != pci_channel_io_normal)
+	if (pci_channel_offline(pdev))
 		return;
 
 	if((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) ||
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 25b559b5..e67361e 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -27,8 +27,6 @@
 
 #include "macb.h"
 
-#define to_net_dev(class) container_of(class, struct net_device, class_dev)
-
 #define RX_BUFFER_SIZE		128
 #define RX_RING_SIZE		512
 #define RX_RING_BYTES		(sizeof(struct dma_desc) * RX_RING_SIZE)
@@ -945,10 +943,10 @@
 	return ret;
 }
 
-static ssize_t macb_mii_show(const struct class_device *cd, char *buf,
+static ssize_t macb_mii_show(const struct device *_dev, char *buf,
 			unsigned long addr)
 {
-	struct net_device *dev = to_net_dev(cd);
+	struct net_device *dev = to_net_dev(_dev);
 	struct macb *bp = netdev_priv(dev);
 	ssize_t ret = -EINVAL;
 
@@ -962,11 +960,13 @@
 }
 
 #define MII_ENTRY(name, addr)					\
-static ssize_t show_##name(struct class_device *cd, char *buf)	\
+static ssize_t show_##name(struct device *_dev,			\
+			   struct device_attribute *attr,	\
+			   char *buf)				\
 {								\
-	return macb_mii_show(cd, buf, addr);			\
+	return macb_mii_show(_dev, buf, addr);			\
 }								\
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
 
 MII_ENTRY(bmcr, MII_BMCR);
 MII_ENTRY(bmsr, MII_BMSR);
@@ -977,13 +977,13 @@
 MII_ENTRY(expansion, MII_EXPANSION);
 
 static struct attribute *macb_mii_attrs[] = {
-	&class_device_attr_bmcr.attr,
-	&class_device_attr_bmsr.attr,
-	&class_device_attr_physid1.attr,
-	&class_device_attr_physid2.attr,
-	&class_device_attr_advertise.attr,
-	&class_device_attr_lpa.attr,
-	&class_device_attr_expansion.attr,
+	&dev_attr_bmcr.attr,
+	&dev_attr_bmsr.attr,
+	&dev_attr_physid1.attr,
+	&dev_attr_physid2.attr,
+	&dev_attr_advertise.attr,
+	&dev_attr_lpa.attr,
+	&dev_attr_expansion.attr,
 	NULL,
 };
 
@@ -994,17 +994,17 @@
 
 static void macb_unregister_sysfs(struct net_device *net)
 {
-	struct class_device *class_dev = &net->class_dev;
+	struct device *_dev = &net->dev;
 
-	sysfs_remove_group(&class_dev->kobj, &macb_mii_group);
+	sysfs_remove_group(&_dev->kobj, &macb_mii_group);
 }
 
 static int macb_register_sysfs(struct net_device *net)
 {
-	struct class_device *class_dev = &net->class_dev;
+	struct device *_dev = &net->dev;
 	int ret;
 
-	ret = sysfs_create_group(&class_dev->kobj, &macb_mii_group);
+	ret = sysfs_create_group(&_dev->kobj, &macb_mii_group);
 	if (ret)
 		printk(KERN_WARNING
 		       "%s: sysfs mii attribute registration failed: %d\n",
@@ -1046,6 +1046,14 @@
 
 	spin_lock_init(&bp->lock);
 
+#if defined(CONFIG_ARCH_AT91)
+	bp->pclk = clk_get(&pdev->dev, "macb_clk");
+	if (IS_ERR(bp->pclk)) {
+		dev_err(&pdev->dev, "failed to get macb_clk\n");
+		goto err_out_free_dev;
+	}
+	clk_enable(bp->pclk);
+#else
 	bp->pclk = clk_get(&pdev->dev, "pclk");
 	if (IS_ERR(bp->pclk)) {
 		dev_err(&pdev->dev, "failed to get pclk\n");
@@ -1059,6 +1067,7 @@
 
 	clk_enable(bp->pclk);
 	clk_enable(bp->hclk);
+#endif
 
 	bp->regs = ioremap(regs->start, regs->end - regs->start + 1);
 	if (!bp->regs) {
@@ -1119,9 +1128,17 @@
 
 	pdata = pdev->dev.platform_data;
 	if (pdata && pdata->is_rmii)
+#if defined(CONFIG_ARCH_AT91)
+		macb_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN)) );
+#else
 		macb_writel(bp, USRIO, 0);
+#endif
 	else
+#if defined(CONFIG_ARCH_AT91)
+		macb_writel(bp, USRIO, MACB_BIT(CLKEN));
+#else
 		macb_writel(bp, USRIO, MACB_BIT(MII));
+#endif
 
 	bp->tx_pending = DEF_TX_RING_PENDING;
 
@@ -1148,9 +1165,11 @@
 err_out_iounmap:
 	iounmap(bp->regs);
 err_out_disable_clocks:
+#ifndef CONFIG_ARCH_AT91
 	clk_disable(bp->hclk);
-	clk_disable(bp->pclk);
 	clk_put(bp->hclk);
+#endif
+	clk_disable(bp->pclk);
 err_out_put_pclk:
 	clk_put(bp->pclk);
 err_out_free_dev:
@@ -1173,9 +1192,11 @@
 		unregister_netdev(dev);
 		free_irq(dev->irq, dev);
 		iounmap(bp->regs);
+#ifndef CONFIG_ARCH_AT91
 		clk_disable(bp->hclk);
-		clk_disable(bp->pclk);
 		clk_put(bp->hclk);
+#endif
+		clk_disable(bp->pclk);
 		clk_put(bp->pclk);
 		free_netdev(dev);
 		platform_set_drvdata(pdev, NULL);
diff --git a/drivers/net/macb.h b/drivers/net/macb.h
index 27bf0ae..b3bb218 100644
--- a/drivers/net/macb.h
+++ b/drivers/net/macb.h
@@ -200,7 +200,7 @@
 #define MACB_SOF_OFFSET				30
 #define MACB_SOF_SIZE				2
 
-/* Bitfields in USRIO */
+/* Bitfields in USRIO (AVR32) */
 #define MACB_MII_OFFSET				0
 #define MACB_MII_SIZE				1
 #define MACB_EAM_OFFSET				1
@@ -210,6 +210,12 @@
 #define MACB_TX_PAUSE_ZERO_OFFSET		3
 #define MACB_TX_PAUSE_ZERO_SIZE			1
 
+/* Bitfields in USRIO (AT91) */
+#define MACB_RMII_OFFSET			0
+#define MACB_RMII_SIZE				1
+#define MACB_CLKEN_OFFSET			1
+#define MACB_CLKEN_SIZE				1
+
 /* Bitfields in WOL */
 #define MACB_IP_OFFSET				0
 #define MACB_IP_SIZE				16
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 2907cfb..9ec24f0 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/crc32.h>
 #include <linux/spinlock.h>
+#include <linux/bitrev.h>
 #include <asm/prom.h>
 #include <asm/dbdma.h>
 #include <asm/io.h>
@@ -74,7 +75,6 @@
 #define PRIV_BYTES	(sizeof(struct mace_data) \
 	+ (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd))
 
-static int bitrev(int);
 static int mace_open(struct net_device *dev);
 static int mace_close(struct net_device *dev);
 static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
@@ -96,18 +96,6 @@
  */
 static unsigned char *dummy_buf;
 
-/* Bit-reverse one byte of an ethernet hardware address. */
-static inline int
-bitrev(int b)
-{
-    int d = 0, i;
-
-    for (i = 0; i < 8; ++i, b >>= 1)
-	d = (d << 1) | (b & 1);
-    return d;
-}
-
-
 static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_id *match)
 {
 	struct device_node *mace = macio_get_of_node(mdev);
@@ -173,7 +161,7 @@
 
 	rev = addr[0] == 0 && addr[1] == 0xA0;
 	for (j = 0; j < 6; ++j) {
-		dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
+		dev->dev_addr[j] = rev ? bitrev8(addr[j]): addr[j];
 	}
 	mp->chipid = (in_8(&mp->mace->chipid_hi) << 8) |
 			in_8(&mp->mace->chipid_lo);
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 464e4a6..5d541e8 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -22,6 +22,7 @@
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/crc32.h>
+#include <linux/bitrev.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
@@ -81,19 +82,6 @@
 static irqreturn_t mace_dma_intr(int irq, void *dev_id);
 static void mace_tx_timeout(struct net_device *dev);
 
-/* Bit-reverse one byte of an ethernet hardware address. */
-
-static int bitrev(int b)
-{
-	int d = 0, i;
-
-	for (i = 0; i < 8; ++i, b >>= 1) {
-		d = (d << 1) | (b & 1);
-	}
-
-	return d;
-}
-
 /*
  * Load a receive DMA channel with a base address and ring length
  */
@@ -219,12 +207,12 @@
 	addr = (void *)MACE_PROM;
 
 	for (j = 0; j < 6; ++j) {
-		u8 v=bitrev(addr[j<<4]);
+		u8 v = bitrev8(addr[j<<4]);
 		checksum ^= v;
 		dev->dev_addr[j] = v;
 	}
 	for (; j < 8; ++j) {
-		checksum ^= bitrev(addr[j<<4]);
+		checksum ^= bitrev8(addr[j<<4]);
 	}
 
 	if (checksum != 0xFF) {
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
index 393d995..8ca57a0 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -49,6 +49,7 @@
 #include <linux/skbuff.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/bitrev.h>
 
 #include <asm/bootinfo.h>
 #include <asm/system.h>
@@ -121,16 +122,12 @@
  * For reversing the PROM address
  */
 
-static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14,
-				    1, 9, 5, 13, 3, 11, 7, 15};
-
 static inline void bit_reverse_addr(unsigned char addr[6])
 {
 	int i;
 
 	for(i = 0; i < 6; i++)
-		addr[i] = ((nibbletab[addr[i] & 0xf] << 4) |
-			   nibbletab[(addr[i] >> 4) &0xf]);
+		addr[i] = bitrev8(addr[i]);
 }
 
 int __init macsonic_init(struct net_device* dev)
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index b3bf864..d98e53e 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -2780,7 +2780,6 @@
 	.get_link               = mv643xx_eth_get_link,
 	.get_sg			= ethtool_op_get_sg,
 	.set_sg			= ethtool_op_set_sg,
-	.get_strings            = mv643xx_get_strings,
 	.get_stats_count        = mv643xx_get_stats_count,
 	.get_ethtool_stats      = mv643xx_get_ethtool_stats,
 	.get_strings            = mv643xx_get_strings,
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 61cbd4a..030924f 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -1412,10 +1412,8 @@
 	.set_tx_csum = ethtool_op_set_tx_hw_csum,
 	.get_sg = ethtool_op_get_sg,
 	.set_sg = ethtool_op_set_sg,
-#ifdef NETIF_F_TSO
 	.get_tso = ethtool_op_get_tso,
 	.set_tso = ethtool_op_set_tso,
-#endif
 	.get_strings = myri10ge_get_strings,
 	.get_stats_count = myri10ge_get_stats_count,
 	.get_ethtool_stats = myri10ge_get_ethtool_stats,
@@ -1975,13 +1973,11 @@
 	mss = 0;
 	max_segments = MXGEFW_MAX_SEND_DESC;
 
-#ifdef NETIF_F_TSO
 	if (skb->len > (dev->mtu + ETH_HLEN)) {
 		mss = skb_shinfo(skb)->gso_size;
 		if (mss != 0)
 			max_segments = MYRI10GE_MAX_SEND_DESC_TSO;
 	}
-#endif				/*NETIF_F_TSO */
 
 	if ((unlikely(avail < max_segments))) {
 		/* we are out of transmit resources */
@@ -2013,7 +2009,6 @@
 
 	cum_len = 0;
 
-#ifdef NETIF_F_TSO
 	if (mss) {		/* TSO */
 		/* this removes any CKSUM flag from before */
 		flags = (MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST);
@@ -2029,7 +2024,6 @@
 		 * the checksum by parsing the header. */
 		pseudo_hdr_offset = mss;
 	} else
-#endif				/*NETIF_F_TSO */
 		/* Mark small packets, and pad out tiny packets */
 	if (skb->len <= MXGEFW_SEND_SMALL_SIZE) {
 		flags |= MXGEFW_FLAGS_SMALL;
@@ -2097,7 +2091,6 @@
 				seglen = len;
 			flags_next = flags & ~MXGEFW_FLAGS_FIRST;
 			cum_len_next = cum_len + seglen;
-#ifdef NETIF_F_TSO
 			if (mss) {	/* TSO */
 				(req - rdma_count)->rdma_count = rdma_count + 1;
 
@@ -2124,7 +2117,6 @@
 					    (small * MXGEFW_FLAGS_SMALL);
 				}
 			}
-#endif				/* NETIF_F_TSO */
 			req->addr_high = high_swapped;
 			req->addr_low = htonl(low);
 			req->pseudo_hdr_offset = htons(pseudo_hdr_offset);
@@ -2161,14 +2153,12 @@
 	}
 
 	(req - rdma_count)->rdma_count = rdma_count;
-#ifdef NETIF_F_TSO
 	if (mss)
 		do {
 			req--;
 			req->flags |= MXGEFW_FLAGS_TSO_LAST;
 		} while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP |
 					 MXGEFW_FLAGS_FIRST)));
-#endif
 	idx = ((count - 1) + tx->req) & tx->mask;
 	tx->info[idx].last = 1;
 	if (tx->wc_fifo == NULL)
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index e8598b8..e021a30 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -63,11 +63,14 @@
 
 #include "netxen_nic_hw.h"
 
-#define NETXEN_NIC_BUILD_NO     "2"
 #define _NETXEN_NIC_LINUX_MAJOR 3
 #define _NETXEN_NIC_LINUX_MINOR 3
 #define _NETXEN_NIC_LINUX_SUBVERSION 3
-#define NETXEN_NIC_LINUX_VERSIONID  "3.3.3" "-" NETXEN_NIC_BUILD_NO
+#define NETXEN_NIC_LINUX_VERSIONID  "3.3.3"
+
+#define NUM_FLASH_SECTORS (64)
+#define FLASH_SECTOR_SIZE (64 * 1024)
+#define FLASH_TOTAL_SIZE  (NUM_FLASH_SECTORS * FLASH_SECTOR_SIZE)
 
 #define RCV_DESC_RINGSIZE	\
 	(sizeof(struct rcv_desc) * adapter->max_rx_desc_count)
@@ -85,6 +88,7 @@
 #define NETXEN_RCV_PRODUCER_OFFSET	0
 #define NETXEN_RCV_PEG_DB_ID		2
 #define NETXEN_HOST_DUMMY_DMA_SIZE 1024
+#define FLASH_SUCCESS 0
 
 #define ADDR_IN_WINDOW1(off)	\
 	((off > NETXEN_CRB_PCIX_HOST2) && (off < NETXEN_CRB_MAX)) ? 1 : 0
@@ -1028,6 +1032,16 @@
 void netxen_load_firmware(struct netxen_adapter *adapter);
 int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose);
 int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp);
+int netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr, 
+				u8 *bytes, size_t size);
+int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr, 
+				u8 *bytes, size_t size);
+int netxen_flash_unlock(struct netxen_adapter *adapter);
+int netxen_backup_crbinit(struct netxen_adapter *adapter);
+int netxen_flash_erase_secondary(struct netxen_adapter *adapter);
+int netxen_flash_erase_primary(struct netxen_adapter *adapter);
+void netxen_halt_pegs(struct netxen_adapter *adapter);
+
 int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data);
 int netxen_rom_se(struct netxen_adapter *adapter, int addr);
 int netxen_do_rom_se(struct netxen_adapter *adapter, int addr);
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index c381d77..6252e9a 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -32,6 +32,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/delay.h>
 #include <asm/uaccess.h>
 #include <linux/pci.h>
 #include <asm/io.h>
@@ -94,17 +95,7 @@
 
 static int netxen_nic_get_eeprom_len(struct net_device *dev)
 {
-	struct netxen_port *port = netdev_priv(dev);
-	struct netxen_adapter *adapter = port->adapter;
-	int n;
-
-	if ((netxen_rom_fast_read(adapter, 0, &n) == 0)
-	    && (n & NETXEN_ROM_ROUNDUP)) {
-		n &= ~NETXEN_ROM_ROUNDUP;
-		if (n < NETXEN_MAX_EEPROM_LEN)
-			return n;
-	}
-	return 0;
+	return FLASH_TOTAL_SIZE;
 }
 
 static void
@@ -411,7 +402,7 @@
 	wol->wolopts = 0;
 }
 
-static u32 netxen_nic_get_link(struct net_device *dev)
+static u32 netxen_nic_test_link(struct net_device *dev)
 {
 	struct netxen_port *port = netdev_priv(dev);
 	struct netxen_adapter *adapter = port->adapter;
@@ -440,18 +431,93 @@
 	struct netxen_port *port = netdev_priv(dev);
 	struct netxen_adapter *adapter = port->adapter;
 	int offset;
+	int ret;
 
 	if (eeprom->len == 0)
 		return -EINVAL;
 
 	eeprom->magic = (port->pdev)->vendor | ((port->pdev)->device << 16);
-	for (offset = 0; offset < eeprom->len; offset++)
-		if (netxen_rom_fast_read
-		    (adapter, (8 * offset) + 8, (int *)eeprom->data) == -1)
-			return -EIO;
+	offset = eeprom->offset;
+
+	ret = netxen_rom_fast_read_words(adapter, offset, bytes, 
+						eeprom->len);
+	if (ret < 0)
+		return ret;
+
 	return 0;
 }
 
+static int
+netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+			u8 * bytes)
+{
+	struct netxen_port *port = netdev_priv(dev);
+	struct netxen_adapter *adapter = port->adapter;
+	int offset = eeprom->offset;
+	static int flash_start;
+	static int ready_to_flash;
+	int ret;
+
+	if (flash_start == 0) {
+		netxen_halt_pegs(adapter);
+		ret = netxen_flash_unlock(adapter);
+		if (ret < 0) {
+			printk(KERN_ERR "%s: Flash unlock failed.\n",
+				netxen_nic_driver_name);
+			return ret;
+		}
+		printk(KERN_INFO "%s: flash unlocked. \n", 
+			netxen_nic_driver_name);
+		ret = netxen_flash_erase_secondary(adapter);
+		if (ret != FLASH_SUCCESS) {
+			printk(KERN_ERR "%s: Flash erase failed.\n", 
+				netxen_nic_driver_name);
+			return ret;
+		}
+		printk(KERN_INFO "%s: secondary flash erased successfully.\n", 
+			netxen_nic_driver_name);
+		flash_start = 1;
+		return 0;
+	}
+
+	if (offset == BOOTLD_START) {
+		ret = netxen_flash_erase_primary(adapter);
+		if (ret != FLASH_SUCCESS) {
+			printk(KERN_ERR "%s: Flash erase failed.\n", 
+				netxen_nic_driver_name);
+			return ret;
+		}
+
+		ret = netxen_rom_se(adapter, USER_START);
+		if (ret != FLASH_SUCCESS)
+			return ret;
+		ret = netxen_rom_se(adapter, FIXED_START);
+		if (ret != FLASH_SUCCESS)
+			return ret;
+
+		printk(KERN_INFO "%s: primary flash erased successfully\n", 
+			netxen_nic_driver_name);
+
+		ret = netxen_backup_crbinit(adapter);
+		if (ret != FLASH_SUCCESS) {
+			printk(KERN_ERR "%s: CRBinit backup failed.\n", 
+				netxen_nic_driver_name);
+			return ret;
+		}
+		printk(KERN_INFO "%s: CRBinit backup done.\n", 
+			netxen_nic_driver_name);
+		ready_to_flash = 1;
+	}
+
+	if (!ready_to_flash) {
+		printk(KERN_ERR "%s: Invalid write sequence, returning...\n",
+			netxen_nic_driver_name);
+		return -EINVAL;
+	}
+
+	return netxen_rom_fast_write_words(adapter, offset, bytes, eeprom->len);
+}
+
 static void
 netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
 {
@@ -647,7 +713,7 @@
 {
 	if (eth_test->flags == ETH_TEST_FL_OFFLINE) {	/* offline tests */
 		/* link test */
-		if (!(data[4] = (u64) netxen_nic_get_link(dev)))
+		if (!(data[4] = (u64) netxen_nic_test_link(dev)))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
 		if (netif_running(dev))
@@ -662,7 +728,7 @@
 			dev->open(dev);
 	} else {		/* online tests */
 		/* link test */
-		if (!(data[4] = (u64) netxen_nic_get_link(dev)))
+		if (!(data[4] = (u64) netxen_nic_test_link(dev)))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
 		/* other tests pass by default */
@@ -718,9 +784,10 @@
 	.get_regs_len = netxen_nic_get_regs_len,
 	.get_regs = netxen_nic_get_regs,
 	.get_wol = netxen_nic_get_wol,
-	.get_link = netxen_nic_get_link,
+	.get_link = ethtool_op_get_link,
 	.get_eeprom_len = netxen_nic_get_eeprom_len,
 	.get_eeprom = netxen_nic_get_eeprom,
+	.set_eeprom = netxen_nic_set_eeprom,
 	.get_ringparam = netxen_nic_get_ringparam,
 	.get_pauseparam = netxen_nic_get_pauseparam,
 	.set_pauseparam = netxen_nic_set_pauseparam,
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index f263232..7195af3 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -420,6 +420,7 @@
 	for (i = 0; i < size / sizeof(u32); i++) {
 		if (netxen_rom_fast_read(adapter, addr, ptr32) == -1)
 			return -1;
+		*ptr32 = cpu_to_le32(*ptr32);
 		ptr32++;
 		addr += sizeof(u32);
 	}
@@ -428,6 +429,7 @@
 
 		if (netxen_rom_fast_read(adapter, addr, &local) == -1)
 			return -1;
+		local = cpu_to_le32(local);
 		memcpy(ptr32, &local, (char *)buf + size - (char *)ptr32);
 	}
 
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 973af96..2f32436 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -110,6 +110,7 @@
 	crb_addr_transform(CAM);
 	crb_addr_transform(C2C1);
 	crb_addr_transform(C2C0);
+	crb_addr_transform(SMB);
 }
 
 int netxen_init_firmware(struct netxen_adapter *adapter)
@@ -276,6 +277,7 @@
 
 static long rom_max_timeout = 10000;
 static long rom_lock_timeout = 1000000;
+static long rom_write_timeout = 700;
 
 static inline int rom_lock(struct netxen_adapter *adapter)
 {
@@ -404,7 +406,7 @@
 {
 	netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr);
 	netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3);
-	udelay(100);		/* prevent bursting on CRB */
+	udelay(70);		/* prevent bursting on CRB */
 	netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
 	netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0xb);
 	if (netxen_wait_rom_done(adapter)) {
@@ -413,13 +415,46 @@
 	}
 	/* reset abyte_cnt and dummy_byte_cnt */
 	netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0);
-	udelay(100);		/* prevent bursting on CRB */
+	udelay(70);		/* prevent bursting on CRB */
 	netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
 
 	*valp = netxen_nic_reg_read(adapter, NETXEN_ROMUSB_ROM_RDATA);
 	return 0;
 }
 
+static inline int 
+do_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
+			u8 *bytes, size_t size)
+{
+	int addridx;
+	int ret = 0;
+
+	for (addridx = addr; addridx < (addr + size); addridx += 4) {
+		ret = do_rom_fast_read(adapter, addridx, (int *)bytes);
+		if (ret != 0)
+			break;
+		bytes += 4;
+	}
+
+	return ret;
+}
+
+int
+netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr, 
+				u8 *bytes, size_t size)
+{
+	int ret;
+
+	ret = rom_lock(adapter);
+	if (ret < 0)
+		return ret;
+
+	ret = do_rom_fast_read_words(adapter, addr, bytes, size);
+
+	netxen_rom_unlock(adapter);
+	return ret;
+}
+
 int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
 {
 	int ret;
@@ -443,6 +478,152 @@
 	netxen_rom_unlock(adapter);
 	return ret;
 }
+
+static inline int do_rom_fast_write_words(struct netxen_adapter *adapter, 
+						int addr, u8 *bytes, size_t size)
+{
+	int addridx = addr;
+	int ret = 0;
+
+	while (addridx < (addr + size)) {
+		int last_attempt = 0;
+		int timeout = 0;
+		int data;
+
+		data = *(u32*)bytes;
+
+		ret = do_rom_fast_write(adapter, addridx, data);
+		if (ret < 0)
+			return ret;
+			
+		while(1) {
+			int data1;
+
+			do_rom_fast_read(adapter, addridx, &data1);
+			if (data1 == data)
+				break;
+
+			if (timeout++ >= rom_write_timeout) {
+				if (last_attempt++ < 4) {
+					ret = do_rom_fast_write(adapter, 
+								addridx, data);
+					if (ret < 0)
+						return ret;
+				}
+				else {
+					printk(KERN_INFO "Data write did not "
+					   "succeed at address 0x%x\n", addridx);
+					break;
+				}
+			}
+		}
+
+		bytes += 4;
+		addridx += 4;
+	}
+
+	return ret;
+}
+
+int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr, 
+					u8 *bytes, size_t size)
+{
+	int ret = 0;
+
+	ret = rom_lock(adapter);
+	if (ret < 0)
+		return ret;
+
+	ret = do_rom_fast_write_words(adapter, addr, bytes, size);
+	netxen_rom_unlock(adapter);
+
+	return ret;
+}
+
+int netxen_rom_wrsr(struct netxen_adapter *adapter, int data)
+{
+	int ret;
+
+	ret = netxen_rom_wren(adapter);
+	if (ret < 0)
+		return ret;
+
+	netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_ROM_WDATA, data);
+	netxen_crb_writelit_adapter(adapter, 
+					NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0x1);
+
+	ret = netxen_wait_rom_done(adapter);
+	if (ret < 0)
+		return ret;
+
+	return netxen_rom_wip_poll(adapter);
+}
+
+int netxen_rom_rdsr(struct netxen_adapter *adapter)
+{
+	int ret;
+
+	ret = rom_lock(adapter);
+	if (ret < 0)
+		return ret;
+
+	ret = netxen_do_rom_rdsr(adapter);
+	netxen_rom_unlock(adapter);
+	return ret;
+}
+
+int netxen_backup_crbinit(struct netxen_adapter *adapter)
+{
+	int ret = FLASH_SUCCESS;
+	int val;
+	char *buffer = kmalloc(FLASH_SECTOR_SIZE, GFP_KERNEL);
+
+	if (!buffer)
+		return -ENOMEM;	
+	/* unlock sector 63 */
+	val = netxen_rom_rdsr(adapter);
+	val = val & 0xe3;
+	ret = netxen_rom_wrsr(adapter, val);
+	if (ret != FLASH_SUCCESS)
+		goto out_kfree;
+
+	ret = netxen_rom_wip_poll(adapter);
+	if (ret != FLASH_SUCCESS)
+		goto out_kfree;
+
+	/* copy  sector 0 to sector 63 */
+	ret = netxen_rom_fast_read_words(adapter, CRBINIT_START, 
+						buffer, FLASH_SECTOR_SIZE);
+	if (ret != FLASH_SUCCESS)
+		goto out_kfree;
+
+	ret = netxen_rom_fast_write_words(adapter, FIXED_START, 
+						buffer, FLASH_SECTOR_SIZE);
+	if (ret != FLASH_SUCCESS)
+		goto out_kfree;
+
+	/* lock sector 63 */
+	val = netxen_rom_rdsr(adapter);
+	if (!(val & 0x8)) {
+		val |= (0x1 << 2);
+		/* lock sector 63 */
+		if (netxen_rom_wrsr(adapter, val) == 0) {
+			ret = netxen_rom_wip_poll(adapter);
+			if (ret != FLASH_SUCCESS)
+				goto out_kfree;
+
+			/* lock SR writes */
+			ret = netxen_rom_wip_poll(adapter);
+			if (ret != FLASH_SUCCESS)
+				goto out_kfree;
+		}
+	}
+
+out_kfree:
+	kfree(buffer);
+	return ret;
+}
+
 int netxen_do_rom_se(struct netxen_adapter *adapter, int addr)
 {
 	netxen_rom_wren(adapter);
@@ -457,6 +638,27 @@
 	return netxen_rom_wip_poll(adapter);
 }
 
+void check_erased_flash(struct netxen_adapter *adapter, int addr)
+{
+	int i;
+	int val;
+	int count = 0, erased_errors = 0;
+	int range;
+
+	range = (addr == USER_START) ? FIXED_START : addr + FLASH_SECTOR_SIZE;
+	
+	for (i = addr; i < range; i += 4) {
+		netxen_rom_fast_read(adapter, i, &val);
+		if (val != 0xffffffff)
+			erased_errors++;
+		count++;
+	}
+
+	if (erased_errors)
+		printk(KERN_INFO "0x%x out of 0x%x words fail to be erased "
+			"for sector address: %x\n", erased_errors, count, addr);
+}
+
 int netxen_rom_se(struct netxen_adapter *adapter, int addr)
 {
 	int ret = 0;
@@ -465,6 +667,76 @@
 	}
 	ret = netxen_do_rom_se(adapter, addr);
 	netxen_rom_unlock(adapter);
+	msleep(30);
+	check_erased_flash(adapter, addr);
+
+	return ret;
+}
+
+int
+netxen_flash_erase_sections(struct netxen_adapter *adapter, int start, int end)
+{
+	int ret = FLASH_SUCCESS;
+	int i;
+
+	for (i = start; i < end; i++) {
+		ret = netxen_rom_se(adapter, i * FLASH_SECTOR_SIZE);
+		if (ret)
+			break;
+		ret = netxen_rom_wip_poll(adapter);
+		if (ret < 0)
+			return ret;
+	}
+
+	return ret;
+}
+
+int
+netxen_flash_erase_secondary(struct netxen_adapter *adapter)
+{
+	int ret = FLASH_SUCCESS;
+	int start, end;
+
+	start = SECONDARY_START / FLASH_SECTOR_SIZE;
+	end   = USER_START / FLASH_SECTOR_SIZE;
+	ret = netxen_flash_erase_sections(adapter, start, end);
+
+	return ret;
+}
+
+int
+netxen_flash_erase_primary(struct netxen_adapter *adapter)
+{
+	int ret = FLASH_SUCCESS;
+	int start, end;
+
+	start = PRIMARY_START / FLASH_SECTOR_SIZE;
+	end   = SECONDARY_START / FLASH_SECTOR_SIZE;
+	ret = netxen_flash_erase_sections(adapter, start, end);
+
+	return ret;
+}
+
+void netxen_halt_pegs(struct netxen_adapter *adapter)
+{
+	 netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_0 + 0x3c, 1);
+	 netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_1 + 0x3c, 1);
+	 netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_2 + 0x3c, 1);
+	 netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_3 + 0x3c, 1);
+}
+
+int netxen_flash_unlock(struct netxen_adapter *adapter)
+{
+	int ret = 0;
+
+	ret = netxen_rom_wrsr(adapter, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = netxen_rom_wren(adapter);
+	if (ret < 0)
+		return ret;
+
 	return ret;
 }
 
@@ -543,9 +815,13 @@
 		}
 		for (i = 0; i < n; i++) {
 
-			off =
-			    netxen_decode_crb_addr((unsigned long)buf[i].addr) +
-			    NETXEN_PCI_CRBSPACE;
+			off = netxen_decode_crb_addr((unsigned long)buf[i].addr);
+			if (off == NETXEN_ADDR_ERROR) {
+				printk(KERN_ERR"CRB init value out of range %lx\n",
+					buf[i].addr);
+				continue;
+			}
+			off += NETXEN_PCI_CRBSPACE;
 			/* skipping cold reboot MAGIC */
 			if (off == NETXEN_CAM_RAM(0x1fc))
 				continue;
@@ -662,6 +938,7 @@
 	int loops = 0;
 
 	if (!pegtune_val) {
+		val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
 		while (val != PHAN_INITIALIZE_COMPLETE && loops < 200000) {
 			udelay(100);
 			schedule();
@@ -977,7 +1254,7 @@
 	 * the netdev which is associated with that device.
 	 */
 
-	consumer = *(adapter->cmd_consumer);
+	consumer = le32_to_cpu(*(adapter->cmd_consumer));
 	if (last_consumer == consumer) {	/* Ring is empty    */
 		DPRINTK(INFO, "last_consumer %d == consumer %d\n",
 			last_consumer, consumer);
@@ -1071,7 +1348,7 @@
 	if (adapter->last_cmd_consumer == consumer &&
 	    (((adapter->cmd_producer + 1) %
 	      adapter->max_tx_desc_count) == adapter->last_cmd_consumer)) {
-		consumer = *(adapter->cmd_consumer);
+		consumer = le32_to_cpu(*(adapter->cmd_consumer));
 	}
 	done = (adapter->last_cmd_consumer == consumer);
 
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 69c1b9d..c2da7ec 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -434,12 +434,13 @@
 		adapter->port_count++;
 		adapter->port[i] = port;
 	}
-
+#ifndef CONFIG_PPC64
 	writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
 	netxen_pinit_from_rom(adapter, 0);
 	udelay(500);
 	netxen_load_firmware(adapter);
 	netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
+#endif
 	/*
 	 * delay a while to ensure that the Pegs are up & running.
 	 * Otherwise, we might see some flaky behaviour.
diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c
index 40d7003..d5d9507 100644
--- a/drivers/net/netxen/netxen_nic_niu.c
+++ b/drivers/net/netxen/netxen_nic_niu.c
@@ -458,7 +458,7 @@
 
 int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port)
 {
-	long reg = 0, ret = 0;
+	u32 reg = 0, ret = 0;
 
 	if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) {
 		netxen_crb_writelit_adapter(adapter,
diff --git a/drivers/net/oaknet.c b/drivers/net/oaknet.c
deleted file mode 100644
index 702e3e9..0000000
--- a/drivers/net/oaknet.c
+++ /dev/null
@@ -1,666 +0,0 @@
-/*
- *
- *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: oaknet.c
- *
- *    Description:
- *      Driver for the National Semiconductor DP83902AV Ethernet controller
- *      on-board the IBM PowerPC "Oak" evaluation board. Adapted from the
- *      various other 8390 drivers written by Donald Becker and Paul Gortmaker.
- *
- *      Additional inspiration from the "tcd8390.c" driver from TiVo, Inc.
- *      and "enetLib.c" from IBM.
- *
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/jiffies.h>
-
-#include <asm/board.h>
-#include <asm/io.h>
-
-#include "8390.h"
-
-
-/* Preprocessor Defines */
-
-#if !defined(TRUE) || TRUE != 1
-#define	TRUE	1
-#endif
-
-#if !defined(FALSE) || FALSE != 0
-#define	FALSE	0
-#endif
-
-#define	OAKNET_START_PG		0x20	/* First page of TX buffer */
-#define	OAKNET_STOP_PG		0x40	/* Last pagge +1 of RX ring */
-
-#define	OAKNET_WAIT		(2 * HZ / 100)	/* 20 ms */
-
-/* Experimenting with some fixes for a broken driver... */
-
-#define	OAKNET_DISINT
-#define	OAKNET_HEADCHECK
-#define	OAKNET_RWFIX
-
-
-/* Global Variables */
-
-static const char *name = "National DP83902AV";
-
-static struct net_device *oaknet_devs;
-
-
-/* Function Prototypes */
-
-static int	 oaknet_open(struct net_device *dev);
-static int	 oaknet_close(struct net_device *dev);
-
-static void	 oaknet_reset_8390(struct net_device *dev);
-static void	 oaknet_get_8390_hdr(struct net_device *dev,
-				     struct e8390_pkt_hdr *hdr, int ring_page);
-static void	 oaknet_block_input(struct net_device *dev, int count,
-				    struct sk_buff *skb, int ring_offset);
-static void	 oaknet_block_output(struct net_device *dev, int count,
-				     const unsigned char *buf, int start_page);
-
-static void	 oaknet_dma_error(struct net_device *dev, const char *name);
-
-
-/*
- * int oaknet_init()
- *
- * Description:
- *   This routine performs all the necessary platform-specific initiali-
- *   zation and set-up for the IBM "Oak" evaluation board's National
- *   Semiconductor DP83902AV "ST-NIC" Ethernet controller.
- *
- * Input(s):
- *   N/A
- *
- * Output(s):
- *   N/A
- *
- * Returns:
- *   0 if OK, otherwise system error number on error.
- *
- */
-static int __init oaknet_init(void)
-{
-	register int i;
-	int reg0, regd;
-	int ret = -ENOMEM;
-	struct net_device *dev;
-#if 0
-	unsigned long ioaddr = OAKNET_IO_BASE;
-#else
-	unsigned long ioaddr = ioremap(OAKNET_IO_BASE, OAKNET_IO_SIZE);
-#endif
-	bd_t *bip = (bd_t *)__res;
-
-	if (!ioaddr)
-		return -ENOMEM;
-
-	dev = alloc_ei_netdev();
-	if (!dev)
-		goto out_unmap;
-
-	ret = -EBUSY;
-	if (!request_region(OAKNET_IO_BASE, OAKNET_IO_SIZE, name))
-		goto out_dev;
-
-	/* Quick register check to see if the device is really there. */
-
-	ret = -ENODEV;
-	if ((reg0 = ei_ibp(ioaddr)) == 0xFF)
-		goto out_region;
-
-	/*
-	 * That worked. Now a more thorough check, using the multicast
-	 * address registers, that the device is definitely out there
-	 * and semi-functional.
-	 */
-
-	ei_obp(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ioaddr + E8390_CMD);
-	regd = ei_ibp(ioaddr + 0x0D);
-	ei_obp(0xFF, ioaddr + 0x0D);
-	ei_obp(E8390_NODMA + E8390_PAGE0, ioaddr + E8390_CMD);
-	ei_ibp(ioaddr + EN0_COUNTER0);
-
-	/* It's no good. Fix things back up and leave. */
-
-	ret = -ENODEV;
-	if (ei_ibp(ioaddr + EN0_COUNTER0) != 0) {
-		ei_obp(reg0, ioaddr);
-		ei_obp(regd, ioaddr + 0x0D);
-		goto out_region;
-	}
-
-	SET_MODULE_OWNER(dev);
-
-	/*
-	 * This controller is on an embedded board, so the base address
-	 * and interrupt assignments are pre-assigned and unchageable.
-	 */
-
-	dev->base_addr = ioaddr;
-	dev->irq = OAKNET_INT;
-
-	/*
-	 * Disable all chip interrupts for now and ACK all pending
-	 * interrupts.
-	 */
-
-	ei_obp(0x0, ioaddr + EN0_IMR);
-	ei_obp(0xFF, ioaddr + EN0_ISR);
-
-	/* Attempt to get the interrupt line */
-
-	ret = -EAGAIN;
-	if (request_irq(dev->irq, ei_interrupt, 0, name, dev)) {
-		printk("%s: unable to request interrupt %d.\n",
-		       name, dev->irq);
-		goto out_region;
-	}
-
-	/* Tell the world about what and where we've found. */
-
-	printk("%s: %s at", dev->name, name);
-	for (i = 0; i < ETHER_ADDR_LEN; ++i) {
-		dev->dev_addr[i] = bip->bi_enetaddr[i];
-		printk("%c%.2x", (i ? ':' : ' '), dev->dev_addr[i]);
-	}
-	printk(", found at %#lx, using IRQ %d.\n", dev->base_addr, dev->irq);
-
-	/* Set up some required driver fields and then we're done. */
-
-	ei_status.name		= name;
-	ei_status.word16	= FALSE;
-	ei_status.tx_start_page	= OAKNET_START_PG;
-	ei_status.rx_start_page = OAKNET_START_PG + TX_PAGES;
-	ei_status.stop_page	= OAKNET_STOP_PG;
-
-	ei_status.reset_8390	= &oaknet_reset_8390;
-	ei_status.block_input	= &oaknet_block_input;
-	ei_status.block_output	= &oaknet_block_output;
-	ei_status.get_8390_hdr	= &oaknet_get_8390_hdr;
-
-	dev->open = oaknet_open;
-	dev->stop = oaknet_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = ei_poll;
-#endif
-
-	NS8390_init(dev, FALSE);
-	ret = register_netdev(dev);
-	if (ret)
-		goto out_irq;
-
-	oaknet_devs = dev;
-	return 0;
-
-out_irq;
-	free_irq(dev->irq, dev);
-out_region:
-	release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE);
-out_dev:
-	free_netdev(dev);
-out_unmap:
-	iounmap(ioaddr);
-	return ret;
-}
-
-/*
- * static int oaknet_open()
- *
- * Description:
- *   This routine is a modest wrapper around ei_open, the 8390-generic,
- *   driver open routine. This just increments the module usage count
- *   and passes along the status from ei_open.
- *
- * Input(s):
- *  *dev - Pointer to the device structure for this driver.
- *
- * Output(s):
- *  *dev - Pointer to the device structure for this driver, potentially
- *         modified by ei_open.
- *
- * Returns:
- *   0 if OK, otherwise < 0 on error.
- *
- */
-static int
-oaknet_open(struct net_device *dev)
-{
-	int status = ei_open(dev);
-	return (status);
-}
-
-/*
- * static int oaknet_close()
- *
- * Description:
- *   This routine is a modest wrapper around ei_close, the 8390-generic,
- *   driver close routine. This just decrements the module usage count
- *   and passes along the status from ei_close.
- *
- * Input(s):
- *  *dev - Pointer to the device structure for this driver.
- *
- * Output(s):
- *  *dev - Pointer to the device structure for this driver, potentially
- *         modified by ei_close.
- *
- * Returns:
- *   0 if OK, otherwise < 0 on error.
- *
- */
-static int
-oaknet_close(struct net_device *dev)
-{
-	int status = ei_close(dev);
-	return (status);
-}
-
-/*
- * static void oaknet_reset_8390()
- *
- * Description:
- *   This routine resets the DP83902 chip.
- *
- * Input(s):
- *  *dev - Pointer to the device structure for this driver.
- *
- * Output(s):
- *   N/A
- *
- * Returns:
- *   N/A
- *
- */
-static void
-oaknet_reset_8390(struct net_device *dev)
-{
-	int base = E8390_BASE;
-
-	/*
-	 * We have no provision of reseting the controller as is done
-	 * in other drivers, such as "ne.c". However, the following
-	 * seems to work well enough in the TiVo driver.
-	 */
-
-	printk("Resetting %s...\n", dev->name);
-	ei_obp(E8390_STOP | E8390_NODMA | E8390_PAGE0, base + E8390_CMD);
-	ei_status.txing = 0;
-	ei_status.dmaing = 0;
-}
-
-/*
- * static void oaknet_get_8390_hdr()
- *
- * Description:
- *   This routine grabs the 8390-specific header. It's similar to the
- *   block input routine, but we don't need to be concerned with ring wrap
- *   as the header will be at the start of a page, so we optimize accordingly.
- *
- * Input(s):
- *  *dev       - Pointer to the device structure for this driver.
- *  *hdr       - Pointer to storage for the 8390-specific packet header.
- *   ring_page - ?
- *
- * Output(s):
- *  *hdr       - Pointer to the 8390-specific packet header for the just-
- *               received frame.
- *
- * Returns:
- *   N/A
- *
- */
-static void
-oaknet_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-		    int ring_page)
-{
-	int base = dev->base_addr;
-
-	/*
-	 * This should NOT happen. If it does, it is the LAST thing you'll
-	 * see.
-	 */
-
-	if (ei_status.dmaing) {
-		oaknet_dma_error(dev, "oaknet_get_8390_hdr");
-		return;
-	}
-
-	ei_status.dmaing |= 0x01;
-	outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, base + OAKNET_CMD);
-	outb_p(sizeof(struct e8390_pkt_hdr), base + EN0_RCNTLO);
-	outb_p(0, base + EN0_RCNTHI);
-	outb_p(0, base + EN0_RSARLO);		/* On page boundary */
-	outb_p(ring_page, base + EN0_RSARHI);
-	outb_p(E8390_RREAD + E8390_START, base + OAKNET_CMD);
-
-	if (ei_status.word16)
-		insw(base + OAKNET_DATA, hdr,
-		     sizeof(struct e8390_pkt_hdr) >> 1);
-	else
-		insb(base + OAKNET_DATA, hdr,
-		     sizeof(struct e8390_pkt_hdr));
-
-	/* Byte-swap the packet byte count */
-
-	hdr->count = le16_to_cpu(hdr->count);
-
-	outb_p(ENISR_RDC, base + EN0_ISR);	/* ACK Remote DMA interrupt */
-	ei_status.dmaing &= ~0x01;
-}
-
-/*
- * XXX - Document me.
- */
-static void
-oaknet_block_input(struct net_device *dev, int count, struct sk_buff *skb,
-		   int ring_offset)
-{
-	int base = OAKNET_BASE;
-	char *buf = skb->data;
-
-	/*
-	 * This should NOT happen. If it does, it is the LAST thing you'll
-	 * see.
-	 */
-
-	if (ei_status.dmaing) {
-		oaknet_dma_error(dev, "oaknet_block_input");
-		return;
-	}
-
-#ifdef OAKNET_DISINT
-	save_flags(flags);
-	cli();
-#endif
-
-	ei_status.dmaing |= 0x01;
-	ei_obp(E8390_NODMA + E8390_PAGE0 + E8390_START, base + E8390_CMD);
-	ei_obp(count & 0xff, base + EN0_RCNTLO);
-	ei_obp(count >> 8, base + EN0_RCNTHI);
-	ei_obp(ring_offset & 0xff, base + EN0_RSARLO);
-	ei_obp(ring_offset >> 8, base + EN0_RSARHI);
-	ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD);
-	if (ei_status.word16) {
-		ei_isw(base + E8390_DATA, buf, count >> 1);
-		if (count & 0x01) {
-			buf[count - 1] = ei_ib(base + E8390_DATA);
-#ifdef OAKNET_HEADCHECK
-			bytes++;
-#endif
-		}
-	} else {
-		ei_isb(base + E8390_DATA, buf, count);
-	}
-#ifdef OAKNET_HEADCHECK
-	/*
-	 * This was for the ALPHA version only, but enough people have
-	 * been encountering problems so it is still here.  If you see
-	 * this message you either 1) have a slightly incompatible clone
-	 * or 2) have noise/speed problems with your bus.
-	 */
-
-	/* DMA termination address check... */
-	{
-		int addr, tries = 20;
-		do {
-			/* DON'T check for 'ei_ibp(EN0_ISR) & ENISR_RDC' here
-			   -- it's broken for Rx on some cards! */
-			int high = ei_ibp(base + EN0_RSARHI);
-			int low = ei_ibp(base + EN0_RSARLO);
-			addr = (high << 8) + low;
-			if (((ring_offset + bytes) & 0xff) == low)
-				break;
-		} while (--tries > 0);
-	 	if (tries <= 0)
-			printk("%s: RX transfer address mismatch,"
-			       "%#4.4x (expected) vs. %#4.4x (actual).\n",
-			       dev->name, ring_offset + bytes, addr);
-	}
-#endif
-	ei_obp(ENISR_RDC, base + EN0_ISR);	/* ACK Remote DMA interrupt */
-	ei_status.dmaing &= ~0x01;
-
-#ifdef OAKNET_DISINT
-	restore_flags(flags);
-#endif
-}
-
-/*
- * static void oaknet_block_output()
- *
- * Description:
- *   This routine...
- *
- * Input(s):
- *  *dev        - Pointer to the device structure for this driver.
- *   count      - Number of bytes to be transferred.
- *  *buf        -
- *   start_page -
- *
- * Output(s):
- *   N/A
- *
- * Returns:
- *   N/A
- *
- */
-static void
-oaknet_block_output(struct net_device *dev, int count,
-		    const unsigned char *buf, int start_page)
-{
-	int base = E8390_BASE;
-#if 0
-	int bug;
-#endif
-	unsigned long start;
-#ifdef OAKNET_DISINT
-	unsigned long flags;
-#endif
-#ifdef OAKNET_HEADCHECK
-	int retries = 0;
-#endif
-
-	/* Round the count up for word writes. */
-
-	if (ei_status.word16 && (count & 0x1))
-		count++;
-
-	/*
-	 * This should NOT happen. If it does, it is the LAST thing you'll
-	 * see.
-	 */
-
-	if (ei_status.dmaing) {
-		oaknet_dma_error(dev, "oaknet_block_output");
-		return;
-	}
-
-#ifdef OAKNET_DISINT
-	save_flags(flags);
-	cli();
-#endif
-
-	ei_status.dmaing |= 0x01;
-
-	/* Make sure we are in page 0. */
-
-	ei_obp(E8390_PAGE0 + E8390_START + E8390_NODMA, base + E8390_CMD);
-
-#ifdef OAKNET_HEADCHECK
-retry:
-#endif
-
-#if 0
-	/*
-	 * The 83902 documentation states that the processor needs to
-	 * do a "dummy read" before doing the remote write to work
-	 * around a chip bug they don't feel like fixing.
-	 */
-
-	bug = 0;
-	while (1) {
-		unsigned int rdhi;
-		unsigned int rdlo;
-
-		/* Now the normal output. */
-		ei_obp(ENISR_RDC, base + EN0_ISR);
-		ei_obp(count & 0xff, base + EN0_RCNTLO);
-		ei_obp(count >> 8,   base + EN0_RCNTHI);
-		ei_obp(0x00, base + EN0_RSARLO);
-		ei_obp(start_page, base + EN0_RSARHI);
-
-		if (bug++)
-			break;
-
-		/* Perform the dummy read */
-		rdhi = ei_ibp(base + EN0_CRDAHI);
-		rdlo = ei_ibp(base + EN0_CRDALO);
-		ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD);
-
-		while (1) {
-			unsigned int nrdhi;
-			unsigned int nrdlo;
-			nrdhi = ei_ibp(base + EN0_CRDAHI);
-			nrdlo = ei_ibp(base + EN0_CRDALO);
-			if ((rdhi != nrdhi) || (rdlo != nrdlo))
-				break;
-		}
-	}
-#else
-#ifdef OAKNET_RWFIX
-	/*
-	 * Handle the read-before-write bug the same way as the
-	 * Crynwr packet driver -- the Nat'l Semi. method doesn't work.
-	 * Actually this doesn't always work either, but if you have
-	 * problems with your 83902 this is better than nothing!
-	 */
-
-	ei_obp(0x42, base + EN0_RCNTLO);
-	ei_obp(0x00, base + EN0_RCNTHI);
-	ei_obp(0x42, base + EN0_RSARLO);
-	ei_obp(0x00, base + EN0_RSARHI);
-	ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD);
-	/* Make certain that the dummy read has occurred. */
-	udelay(6);
-#endif
-
-	ei_obp(ENISR_RDC, base + EN0_ISR);
-
-	/* Now the normal output. */
-	ei_obp(count & 0xff, base + EN0_RCNTLO);
-	ei_obp(count >> 8,   base + EN0_RCNTHI);
-	ei_obp(0x00, base + EN0_RSARLO);
-	ei_obp(start_page, base + EN0_RSARHI);
-#endif /* 0/1 */
-
-	ei_obp(E8390_RWRITE + E8390_START, base + E8390_CMD);
-	if (ei_status.word16) {
-		ei_osw(E8390_BASE + E8390_DATA, buf, count >> 1);
-	} else {
-		ei_osb(E8390_BASE + E8390_DATA, buf, count);
-	}
-
-#ifdef OAKNET_DISINT
-	restore_flags(flags);
-#endif
-
-	start = jiffies;
-
-#ifdef OAKNET_HEADCHECK
-	/*
-	 * This was for the ALPHA version only, but enough people have
-	 * been encountering problems so it is still here.
-	 */
-
-	{
-		/* DMA termination address check... */
-		int addr, tries = 20;
-		do {
-			int high = ei_ibp(base + EN0_RSARHI);
-			int low = ei_ibp(base + EN0_RSARLO);
-			addr = (high << 8) + low;
-			if ((start_page << 8) + count == addr)
-				break;
-		} while (--tries > 0);
-
-		if (tries <= 0) {
-			printk("%s: Tx packet transfer address mismatch,"
-			       "%#4.4x (expected) vs. %#4.4x (actual).\n",
-			       dev->name, (start_page << 8) + count, addr);
-			if (retries++ == 0)
-				goto retry;
-		}
-	}
-#endif
-
-	while ((ei_ibp(base + EN0_ISR) & ENISR_RDC) == 0) {
-		if (time_after(jiffies, start + OAKNET_WAIT)) {
-			printk("%s: timeout waiting for Tx RDC.\n", dev->name);
-			oaknet_reset_8390(dev);
-			NS8390_init(dev, TRUE);
-			break;
-		}
-	}
-
-	ei_obp(ENISR_RDC, base + EN0_ISR);	/* Ack intr. */
-	ei_status.dmaing &= ~0x01;
-}
-
-/*
- * static void oaknet_dma_error()
- *
- * Description:
- *   This routine prints out a last-ditch informative message to the console
- *   indicating that a DMA error occurred. If you see this, it's the last
- *   thing you'll see.
- *
- * Input(s):
- *  *dev  - Pointer to the device structure for this driver.
- *  *name - Informative text (e.g. function name) indicating where the
- *          DMA error occurred.
- *
- * Output(s):
- *   N/A
- *
- * Returns:
- *   N/A
- *
- */
-static void
-oaknet_dma_error(struct net_device *dev, const char *name)
-{
-	printk(KERN_EMERG "%s: DMAing conflict in %s."
-	       "[DMAstat:%d][irqlock:%d][intr:%ld]\n",
-	       dev->name, name, ei_status.dmaing, ei_status.irqlock,
-	       dev->interrupt);
-}
-
-/*
- * Oak Ethernet module unload interface.
- */
-static void __exit oaknet_cleanup_module (void)
-{
-	/* Convert to loop once driver supports multiple devices. */
-	unregister_netdev(oaknet_dev);
-	free_irq(oaknet_devs->irq, oaknet_devs);
-	release_region(oaknet_devs->base_addr, OAKNET_IO_SIZE);
-	iounmap(ioaddr);
-	free_netdev(oaknet_devs);
-}
-
-module_init(oaknet_init);
-module_exit(oaknet_cleanup_module);
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
new file mode 100644
index 0000000..d670ac7
--- /dev/null
+++ b/drivers/net/pasemi_mac.c
@@ -0,0 +1,1019 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Driver for the PA Semi PWRficient onchip 1G/10G Ethernet MACs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <asm/dma-mapping.h>
+#include <linux/in.h>
+#include <linux/skbuff.h>
+
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <net/checksum.h>
+
+#include "pasemi_mac.h"
+
+
+/* TODO list
+ *
+ * - Get rid of pci_{read,write}_config(), map registers with ioremap
+ *   for performance
+ * - PHY support
+ * - Multicast support
+ * - Large MTU support
+ * - Other performance improvements
+ */
+
+
+/* Must be a power of two */
+#define RX_RING_SIZE 512
+#define TX_RING_SIZE 512
+
+#define TX_DESC(mac, num)	((mac)->tx->desc[(num) & (TX_RING_SIZE-1)])
+#define TX_DESC_INFO(mac, num)	((mac)->tx->desc_info[(num) & (TX_RING_SIZE-1)])
+#define RX_DESC(mac, num)	((mac)->rx->desc[(num) & (RX_RING_SIZE-1)])
+#define RX_DESC_INFO(mac, num)	((mac)->rx->desc_info[(num) & (RX_RING_SIZE-1)])
+#define RX_BUFF(mac, num)	((mac)->rx->buffers[(num) & (RX_RING_SIZE-1)])
+
+#define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
+
+/* XXXOJN these should come out of the device tree some day */
+#define PAS_DMA_CAP_BASE   0xe00d0040
+#define PAS_DMA_CAP_SIZE   0x100
+#define PAS_DMA_COM_BASE   0xe00d0100
+#define PAS_DMA_COM_SIZE   0x100
+
+static struct pasdma_status *dma_status;
+
+static int pasemi_get_mac_addr(struct pasemi_mac *mac)
+{
+	struct pci_dev *pdev = mac->pdev;
+	struct device_node *dn = pci_device_to_OF_node(pdev);
+	const u8 *maddr;
+	u8 addr[6];
+
+	if (!dn) {
+		dev_dbg(&pdev->dev,
+			  "No device node for mac, not configuring\n");
+		return -ENOENT;
+	}
+
+	maddr = get_property(dn, "mac-address", NULL);
+	if (maddr == NULL) {
+		dev_warn(&pdev->dev,
+			 "no mac address in device tree, not configuring\n");
+		return -ENOENT;
+	}
+
+	if (sscanf(maddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &addr[0],
+		   &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) != 6) {
+		dev_warn(&pdev->dev,
+			 "can't parse mac address, not configuring\n");
+		return -EINVAL;
+	}
+
+	memcpy(mac->mac_addr, addr, sizeof(addr));
+	return 0;
+}
+
+static int pasemi_mac_setup_rx_resources(struct net_device *dev)
+{
+	struct pasemi_mac_rxring *ring;
+	struct pasemi_mac *mac = netdev_priv(dev);
+	int chan_id = mac->dma_rxch;
+
+	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+
+	if (!ring)
+		goto out_ring;
+
+	spin_lock_init(&ring->lock);
+
+	ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
+				  RX_RING_SIZE, GFP_KERNEL);
+
+	if (!ring->desc_info)
+		goto out_desc_info;
+
+	/* Allocate descriptors */
+	ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev,
+					RX_RING_SIZE *
+					sizeof(struct pas_dma_xct_descr),
+					&ring->dma, GFP_KERNEL);
+
+	if (!ring->desc)
+		goto out_desc;
+
+	memset(ring->desc, 0, RX_RING_SIZE * sizeof(struct pas_dma_xct_descr));
+
+	ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev,
+					   RX_RING_SIZE * sizeof(u64),
+					   &ring->buf_dma, GFP_KERNEL);
+	if (!ring->buffers)
+		goto out_buffers;
+
+	memset(ring->buffers, 0, RX_RING_SIZE * sizeof(u64));
+
+	pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEL(chan_id),
+			       PAS_DMA_RXCHAN_BASEL_BRBL(ring->dma));
+
+	pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEU(chan_id),
+			       PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) |
+			       PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 2));
+
+	pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_CFG(chan_id),
+			       PAS_DMA_RXCHAN_CFG_HBU(1));
+
+	pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEL(mac->dma_if),
+			       PAS_DMA_RXINT_BASEL_BRBL(__pa(ring->buffers)));
+
+	pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEU(mac->dma_if),
+			       PAS_DMA_RXINT_BASEU_BRBH(__pa(ring->buffers) >> 32) |
+			       PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3));
+
+	ring->next_to_fill = 0;
+	ring->next_to_clean = 0;
+
+	snprintf(ring->irq_name, sizeof(ring->irq_name),
+		 "%s rx", dev->name);
+	mac->rx = ring;
+
+	return 0;
+
+out_buffers:
+	dma_free_coherent(&mac->dma_pdev->dev,
+			  RX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
+			  mac->rx->desc, mac->rx->dma);
+out_desc:
+	kfree(ring->desc_info);
+out_desc_info:
+	kfree(ring);
+out_ring:
+	return -ENOMEM;
+}
+
+
+static int pasemi_mac_setup_tx_resources(struct net_device *dev)
+{
+	struct pasemi_mac *mac = netdev_priv(dev);
+	u32 val;
+	int chan_id = mac->dma_txch;
+	struct pasemi_mac_txring *ring;
+
+	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+	if (!ring)
+		goto out_ring;
+
+	spin_lock_init(&ring->lock);
+
+	ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
+				  TX_RING_SIZE, GFP_KERNEL);
+	if (!ring->desc_info)
+		goto out_desc_info;
+
+	/* Allocate descriptors */
+	ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev,
+					TX_RING_SIZE *
+					sizeof(struct pas_dma_xct_descr),
+					&ring->dma, GFP_KERNEL);
+	if (!ring->desc)
+		goto out_desc;
+
+	memset(ring->desc, 0, TX_RING_SIZE * sizeof(struct pas_dma_xct_descr));
+
+	pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEL(chan_id),
+			       PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma));
+	val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32);
+	val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2);
+
+	pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEU(chan_id), val);
+
+	pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_CFG(chan_id),
+			       PAS_DMA_TXCHAN_CFG_TY_IFACE |
+			       PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) |
+			       PAS_DMA_TXCHAN_CFG_UP |
+			       PAS_DMA_TXCHAN_CFG_WT(2));
+
+	ring->next_to_use = 0;
+	ring->next_to_clean = 0;
+
+	snprintf(ring->irq_name, sizeof(ring->irq_name),
+		 "%s tx", dev->name);
+	mac->tx = ring;
+
+	return 0;
+
+out_desc:
+	kfree(ring->desc_info);
+out_desc_info:
+	kfree(ring);
+out_ring:
+	return -ENOMEM;
+}
+
+static void pasemi_mac_free_tx_resources(struct net_device *dev)
+{
+	struct pasemi_mac *mac = netdev_priv(dev);
+	unsigned int i;
+	struct pasemi_mac_buffer *info;
+	struct pas_dma_xct_descr *dp;
+
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		info = &TX_DESC_INFO(mac, i);
+		dp = &TX_DESC(mac, i);
+		if (info->dma) {
+			if (info->skb) {
+				pci_unmap_single(mac->dma_pdev,
+						 info->dma,
+						 info->skb->len,
+						 PCI_DMA_TODEVICE);
+				dev_kfree_skb_any(info->skb);
+			}
+			info->dma = 0;
+			info->skb = NULL;
+			dp->mactx = 0;
+			dp->ptr = 0;
+		}
+	}
+
+	dma_free_coherent(&mac->dma_pdev->dev,
+			  TX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
+			  mac->tx->desc, mac->tx->dma);
+
+	kfree(mac->tx->desc_info);
+	kfree(mac->tx);
+	mac->tx = NULL;
+}
+
+static void pasemi_mac_free_rx_resources(struct net_device *dev)
+{
+	struct pasemi_mac *mac = netdev_priv(dev);
+	unsigned int i;
+	struct pasemi_mac_buffer *info;
+	struct pas_dma_xct_descr *dp;
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		info = &RX_DESC_INFO(mac, i);
+		dp = &RX_DESC(mac, i);
+		if (info->dma) {
+			if (info->skb) {
+				pci_unmap_single(mac->dma_pdev,
+						 info->dma,
+						 info->skb->len,
+						 PCI_DMA_FROMDEVICE);
+				dev_kfree_skb_any(info->skb);
+			}
+			info->dma = 0;
+			info->skb = NULL;
+			dp->macrx = 0;
+			dp->ptr = 0;
+		}
+	}
+
+	dma_free_coherent(&mac->dma_pdev->dev,
+			  RX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
+			  mac->rx->desc, mac->rx->dma);
+
+	dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64),
+			  mac->rx->buffers, mac->rx->buf_dma);
+
+	kfree(mac->rx->desc_info);
+	kfree(mac->rx);
+	mac->rx = NULL;
+}
+
+static void pasemi_mac_replenish_rx_ring(struct net_device *dev)
+{
+	struct pasemi_mac *mac = netdev_priv(dev);
+	unsigned int i;
+	int start = mac->rx->next_to_fill;
+	unsigned int count;
+
+	count = (mac->rx->next_to_clean + RX_RING_SIZE -
+		 mac->rx->next_to_fill) & (RX_RING_SIZE - 1);
+
+	/* Check to see if we're doing first-time setup */
+	if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0))
+		count = RX_RING_SIZE;
+
+	if (count <= 0)
+		return;
+
+	for (i = start; i < start + count; i++) {
+		struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i);
+		u64 *buff = &RX_BUFF(mac, i);
+		struct sk_buff *skb;
+		dma_addr_t dma;
+
+		skb = dev_alloc_skb(BUF_SIZE);
+
+		if (!skb) {
+			count = i - start;
+			break;
+		}
+
+		skb->dev = dev;
+
+		dma = pci_map_single(mac->dma_pdev, skb->data, skb->len,
+				     PCI_DMA_FROMDEVICE);
+
+		if (dma_mapping_error(dma)) {
+			dev_kfree_skb_irq(info->skb);
+			count = i - start;
+			break;
+		}
+
+		info->skb = skb;
+		info->dma = dma;
+		*buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma);
+	}
+
+	wmb();
+
+	pci_write_config_dword(mac->dma_pdev,
+			       PAS_DMA_RXCHAN_INCR(mac->dma_rxch),
+			       count);
+	pci_write_config_dword(mac->dma_pdev,
+			       PAS_DMA_RXINT_INCR(mac->dma_if),
+			       count);
+
+	mac->rx->next_to_fill += count;
+}
+
+static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
+{
+	unsigned int i;
+	int start, count;
+
+	spin_lock(&mac->rx->lock);
+
+	start = mac->rx->next_to_clean;
+	count = 0;
+
+	for (i = start; i < (start + RX_RING_SIZE) && count < limit; i++) {
+		struct pas_dma_xct_descr *dp;
+		struct pasemi_mac_buffer *info;
+		struct sk_buff *skb;
+		unsigned int j, len;
+		dma_addr_t dma;
+
+		rmb();
+
+		dp = &RX_DESC(mac, i);
+
+		if (!(dp->macrx & XCT_MACRX_O))
+			break;
+
+		count++;
+
+		info = NULL;
+
+		/* We have to scan for our skb since there's no way
+		 * to back-map them from the descriptor, and if we
+		 * have several receive channels then they might not
+		 * show up in the same order as they were put on the
+		 * interface ring.
+		 */
+
+		dma = (dp->ptr & XCT_PTR_ADDR_M);
+		for (j = start; j < (start + RX_RING_SIZE); j++) {
+			info = &RX_DESC_INFO(mac, j);
+			if (info->dma == dma)
+				break;
+		}
+
+		BUG_ON(!info);
+		BUG_ON(info->dma != dma);
+
+		pci_unmap_single(mac->dma_pdev, info->dma, info->skb->len,
+				 PCI_DMA_FROMDEVICE);
+
+		skb = info->skb;
+
+		len = (dp->macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
+
+		skb_put(skb, len);
+
+		skb->protocol = eth_type_trans(skb, mac->netdev);
+
+		if ((dp->macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) {
+			skb->ip_summed = CHECKSUM_COMPLETE;
+			skb->csum = (dp->macrx & XCT_MACRX_CSUM_M) >>
+					   XCT_MACRX_CSUM_S;
+		} else
+			skb->ip_summed = CHECKSUM_NONE;
+
+		mac->stats.rx_bytes += len;
+		mac->stats.rx_packets++;
+
+		netif_receive_skb(skb);
+
+		info->dma = 0;
+		info->skb = NULL;
+		dp->ptr = 0;
+		dp->macrx = 0;
+	}
+
+	mac->rx->next_to_clean += count;
+	pasemi_mac_replenish_rx_ring(mac->netdev);
+
+	spin_unlock(&mac->rx->lock);
+
+	return count;
+}
+
+static int pasemi_mac_clean_tx(struct pasemi_mac *mac)
+{
+	int i;
+	struct pasemi_mac_buffer *info;
+	struct pas_dma_xct_descr *dp;
+	int start, count;
+	int flags;
+
+	spin_lock_irqsave(&mac->tx->lock, flags);
+
+	start = mac->tx->next_to_clean;
+	count = 0;
+
+	for (i = start; i < mac->tx->next_to_use; i++) {
+		dp = &TX_DESC(mac, i);
+		if (!dp || (dp->mactx & XCT_MACTX_O))
+			break;
+
+		count++;
+
+		info = &TX_DESC_INFO(mac, i);
+
+		pci_unmap_single(mac->dma_pdev, info->dma,
+				 info->skb->len, PCI_DMA_TODEVICE);
+		dev_kfree_skb_irq(info->skb);
+
+		info->skb = NULL;
+		info->dma = 0;
+		dp->mactx = 0;
+		dp->ptr = 0;
+	}
+	mac->tx->next_to_clean += count;
+	spin_unlock_irqrestore(&mac->tx->lock, flags);
+
+	return count;
+}
+
+
+static irqreturn_t pasemi_mac_rx_intr(int irq, void *data)
+{
+	struct net_device *dev = data;
+	struct pasemi_mac *mac = netdev_priv(dev);
+	unsigned int reg;
+
+	if (!(*mac->rx_status & PAS_STATUS_INT))
+		return IRQ_NONE;
+
+	netif_rx_schedule(dev);
+	pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
+			       PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0));
+
+	reg = PAS_IOB_DMA_RXCH_RESET_PINTC | PAS_IOB_DMA_RXCH_RESET_SINTC |
+	      PAS_IOB_DMA_RXCH_RESET_DINTC;
+	if (*mac->rx_status & PAS_STATUS_TIMER)
+		reg |= PAS_IOB_DMA_RXCH_RESET_TINTC;
+
+	pci_write_config_dword(mac->iob_pdev,
+			       PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg);
+
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t pasemi_mac_tx_intr(int irq, void *data)
+{
+	struct net_device *dev = data;
+	struct pasemi_mac *mac = netdev_priv(dev);
+	unsigned int reg;
+	int was_full;
+
+	was_full = mac->tx->next_to_clean - mac->tx->next_to_use == TX_RING_SIZE;
+
+	if (!(*mac->tx_status & PAS_STATUS_INT))
+		return IRQ_NONE;
+
+	pasemi_mac_clean_tx(mac);
+
+	reg = PAS_IOB_DMA_TXCH_RESET_PINTC | PAS_IOB_DMA_TXCH_RESET_SINTC;
+	if (*mac->tx_status & PAS_STATUS_TIMER)
+		reg |= PAS_IOB_DMA_TXCH_RESET_TINTC;
+
+	pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch),
+			       reg);
+
+	if (was_full)
+		netif_wake_queue(dev);
+
+	return IRQ_HANDLED;
+}
+
+static int pasemi_mac_open(struct net_device *dev)
+{
+	struct pasemi_mac *mac = netdev_priv(dev);
+	unsigned int flags;
+	int ret;
+
+	/* enable rx section */
+	pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_RXCMD,
+			       PAS_DMA_COM_RXCMD_EN);
+
+	/* enable tx section */
+	pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_TXCMD,
+			       PAS_DMA_COM_TXCMD_EN);
+
+	flags = PAS_MAC_CFG_TXP_FCE | PAS_MAC_CFG_TXP_FPC(3) |
+		PAS_MAC_CFG_TXP_SL(3) | PAS_MAC_CFG_TXP_COB(0xf) |
+		PAS_MAC_CFG_TXP_TIFT(8) | PAS_MAC_CFG_TXP_TIFG(12);
+
+	pci_write_config_dword(mac->pdev, PAS_MAC_CFG_TXP, flags);
+
+	flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE |
+		PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE;
+
+	flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G;
+
+	pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch),
+			       PAS_IOB_DMA_RXCH_CFG_CNTTH(30));
+
+	pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
+			       PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000));
+
+	pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags);
+
+	ret = pasemi_mac_setup_rx_resources(dev);
+	if (ret)
+		goto out_rx_resources;
+
+	ret = pasemi_mac_setup_tx_resources(dev);
+	if (ret)
+		goto out_tx_resources;
+
+	pci_write_config_dword(mac->pdev, PAS_MAC_IPC_CHNL,
+			       PAS_MAC_IPC_CHNL_DCHNO(mac->dma_rxch) |
+			       PAS_MAC_IPC_CHNL_BCH(mac->dma_rxch));
+
+	/* enable rx if */
+	pci_write_config_dword(mac->dma_pdev,
+			       PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+			       PAS_DMA_RXINT_RCMDSTA_EN);
+
+	/* enable rx channel */
+	pci_write_config_dword(mac->dma_pdev,
+			       PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
+			       PAS_DMA_RXCHAN_CCMDSTA_EN |
+			       PAS_DMA_RXCHAN_CCMDSTA_DU);
+
+	/* enable tx channel */
+	pci_write_config_dword(mac->dma_pdev,
+			       PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
+			       PAS_DMA_TXCHAN_TCMDSTA_EN);
+
+	pasemi_mac_replenish_rx_ring(dev);
+
+	netif_start_queue(dev);
+	netif_poll_enable(dev);
+
+	ret = request_irq(mac->dma_pdev->irq + mac->dma_txch,
+			  &pasemi_mac_tx_intr, IRQF_DISABLED,
+			  mac->tx->irq_name, dev);
+	if (ret) {
+		dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
+		       mac->dma_pdev->irq + mac->dma_txch, ret);
+		goto out_tx_int;
+	}
+
+	ret = request_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch,
+			  &pasemi_mac_rx_intr, IRQF_DISABLED,
+			  mac->rx->irq_name, dev);
+	if (ret) {
+		dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
+		       mac->dma_pdev->irq + 20 + mac->dma_rxch, ret);
+		goto out_rx_int;
+	}
+
+	return 0;
+
+out_rx_int:
+	free_irq(mac->dma_pdev->irq + mac->dma_txch, dev);
+out_tx_int:
+	netif_poll_disable(dev);
+	netif_stop_queue(dev);
+	pasemi_mac_free_tx_resources(dev);
+out_tx_resources:
+	pasemi_mac_free_rx_resources(dev);
+out_rx_resources:
+
+	return ret;
+}
+
+#define MAX_RETRIES 5000
+
+static int pasemi_mac_close(struct net_device *dev)
+{
+	struct pasemi_mac *mac = netdev_priv(dev);
+	unsigned int stat;
+	int retries;
+
+	netif_stop_queue(dev);
+
+	/* Clean out any pending buffers */
+	pasemi_mac_clean_tx(mac);
+	pasemi_mac_clean_rx(mac, RX_RING_SIZE);
+
+	/* Disable interface */
+	pci_write_config_dword(mac->dma_pdev,
+			       PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
+			       PAS_DMA_TXCHAN_TCMDSTA_ST);
+	pci_write_config_dword(mac->dma_pdev,
+		      PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+		      PAS_DMA_RXINT_RCMDSTA_ST);
+	pci_write_config_dword(mac->dma_pdev,
+		      PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
+		      PAS_DMA_RXCHAN_CCMDSTA_ST);
+
+	for (retries = 0; retries < MAX_RETRIES; retries++) {
+		pci_read_config_dword(mac->dma_pdev,
+				      PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
+				      &stat);
+		if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)
+			break;
+		cond_resched();
+	}
+
+	if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) {
+		dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n");
+	}
+
+	for (retries = 0; retries < MAX_RETRIES; retries++) {
+		pci_read_config_dword(mac->dma_pdev,
+				      PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
+				      &stat);
+		if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)
+			break;
+		cond_resched();
+	}
+
+	if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)) {
+		dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n");
+	}
+
+	for (retries = 0; retries < MAX_RETRIES; retries++) {
+		pci_read_config_dword(mac->dma_pdev,
+				      PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+				      &stat);
+		if (stat & PAS_DMA_RXINT_RCMDSTA_ACT)
+			break;
+		cond_resched();
+	}
+
+	if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT)) {
+		dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n");
+	}
+
+	/* Then, disable the channel. This must be done separately from
+	 * stopping, since you can't disable when active.
+	 */
+
+	pci_write_config_dword(mac->dma_pdev,
+			       PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0);
+	pci_write_config_dword(mac->dma_pdev,
+			       PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0);
+	pci_write_config_dword(mac->dma_pdev,
+			       PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
+
+	free_irq(mac->dma_pdev->irq + mac->dma_txch, dev);
+	free_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch, dev);
+
+	/* Free resources */
+	pasemi_mac_free_rx_resources(dev);
+	pasemi_mac_free_tx_resources(dev);
+
+	return 0;
+}
+
+static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct pasemi_mac *mac = netdev_priv(dev);
+	struct pasemi_mac_txring *txring;
+	struct pasemi_mac_buffer *info;
+	struct pas_dma_xct_descr *dp;
+	u64 dflags;
+	dma_addr_t map;
+	int flags;
+
+	dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_SS | XCT_MACTX_CRC_PAD;
+
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		switch (skb->nh.iph->protocol) {
+		case IPPROTO_TCP:
+			dflags |= XCT_MACTX_CSUM_TCP;
+			dflags |= XCT_MACTX_IPH((skb->h.raw - skb->nh.raw) >> 2);
+			dflags |= XCT_MACTX_IPO(skb->nh.raw - skb->data);
+			break;
+		case IPPROTO_UDP:
+			dflags |= XCT_MACTX_CSUM_UDP;
+			dflags |= XCT_MACTX_IPH((skb->h.raw - skb->nh.raw) >> 2);
+			dflags |= XCT_MACTX_IPO(skb->nh.raw - skb->data);
+			break;
+		}
+	}
+
+	map = pci_map_single(mac->dma_pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+
+	if (dma_mapping_error(map))
+		return NETDEV_TX_BUSY;
+
+	txring = mac->tx;
+
+	spin_lock_irqsave(&txring->lock, flags);
+
+	if (txring->next_to_clean - txring->next_to_use == TX_RING_SIZE) {
+		spin_unlock_irqrestore(&txring->lock, flags);
+		pasemi_mac_clean_tx(mac);
+		spin_lock_irqsave(&txring->lock, flags);
+
+		if (txring->next_to_clean - txring->next_to_use ==
+		    TX_RING_SIZE) {
+			/* Still no room -- stop the queue and wait for tx
+			 * intr when there's room.
+			 */
+			netif_stop_queue(dev);
+			goto out_err;
+		}
+	}
+
+
+	dp = &TX_DESC(mac, txring->next_to_use);
+	info = &TX_DESC_INFO(mac, txring->next_to_use);
+
+	dp->mactx = dflags | XCT_MACTX_LLEN(skb->len);
+	dp->ptr   = XCT_PTR_LEN(skb->len) | XCT_PTR_ADDR(map);
+	info->dma = map;
+	info->skb = skb;
+
+	txring->next_to_use++;
+	mac->stats.tx_packets++;
+	mac->stats.tx_bytes += skb->len;
+
+	spin_unlock_irqrestore(&txring->lock, flags);
+
+	pci_write_config_dword(mac->dma_pdev,
+			       PAS_DMA_TXCHAN_INCR(mac->dma_txch), 1);
+
+	return NETDEV_TX_OK;
+
+out_err:
+	spin_unlock_irqrestore(&txring->lock, flags);
+	pci_unmap_single(mac->dma_pdev, map, skb->len, PCI_DMA_TODEVICE);
+	return NETDEV_TX_BUSY;
+}
+
+static struct net_device_stats *pasemi_mac_get_stats(struct net_device *dev)
+{
+	struct pasemi_mac *mac = netdev_priv(dev);
+
+	return &mac->stats;
+}
+
+static void pasemi_mac_set_rx_mode(struct net_device *dev)
+{
+	struct pasemi_mac *mac = netdev_priv(dev);
+	unsigned int flags;
+
+	pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags);
+
+	/* Set promiscuous */
+	if (dev->flags & IFF_PROMISC)
+		flags |= PAS_MAC_CFG_PCFG_PR;
+	else
+		flags &= ~PAS_MAC_CFG_PCFG_PR;
+
+	pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags);
+}
+
+
+static int pasemi_mac_poll(struct net_device *dev, int *budget)
+{
+	int pkts, limit = min(*budget, dev->quota);
+	struct pasemi_mac *mac = netdev_priv(dev);
+
+	pkts = pasemi_mac_clean_rx(mac, limit);
+
+	if (pkts < limit) {
+		/* all done, no more packets present */
+		netif_rx_complete(dev);
+
+		/* re-enable receive interrupts */
+		pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
+				       PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000));
+		return 0;
+	} else {
+		/* used up our quantum, so reschedule */
+		dev->quota -= pkts;
+		*budget -= pkts;
+		return 1;
+	}
+}
+
+static int __devinit
+pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int index = 0;
+	struct net_device *dev;
+	struct pasemi_mac *mac;
+	int err;
+
+	err = pci_enable_device(pdev);
+	if (err)
+		return err;
+
+	dev = alloc_etherdev(sizeof(struct pasemi_mac));
+	if (dev == NULL) {
+		dev_err(&pdev->dev,
+			"pasemi_mac: Could not allocate ethernet device.\n");
+		err = -ENOMEM;
+		goto out_disable_device;
+	}
+
+	SET_MODULE_OWNER(dev);
+	pci_set_drvdata(pdev, dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
+	mac = netdev_priv(dev);
+
+	mac->pdev = pdev;
+	mac->netdev = dev;
+	mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
+
+	if (!mac->dma_pdev) {
+		dev_err(&pdev->dev, "Can't find DMA Controller\n");
+		err = -ENODEV;
+		goto out_free_netdev;
+	}
+
+	mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
+
+	if (!mac->iob_pdev) {
+		dev_err(&pdev->dev, "Can't find I/O Bridge\n");
+		err = -ENODEV;
+		goto out_put_dma_pdev;
+	}
+
+	/* These should come out of the device tree eventually */
+	mac->dma_txch = index;
+	mac->dma_rxch = index;
+
+	/* We probe GMAC before XAUI, but the DMA interfaces are
+	 * in XAUI, GMAC order.
+	 */
+	if (index < 4)
+		mac->dma_if = index + 2;
+	else
+		mac->dma_if = index - 4;
+	index++;
+
+	switch (pdev->device) {
+	case 0xa005:
+		mac->type = MAC_TYPE_GMAC;
+		break;
+	case 0xa006:
+		mac->type = MAC_TYPE_XAUI;
+		break;
+	default:
+		err = -ENODEV;
+		goto out;
+	}
+
+	/* get mac addr from device tree */
+	if (pasemi_get_mac_addr(mac) || !is_valid_ether_addr(mac->mac_addr)) {
+		err = -ENODEV;
+		goto out;
+	}
+	memcpy(dev->dev_addr, mac->mac_addr, sizeof(mac->mac_addr));
+
+	dev->open = pasemi_mac_open;
+	dev->stop = pasemi_mac_close;
+	dev->hard_start_xmit = pasemi_mac_start_tx;
+	dev->get_stats = pasemi_mac_get_stats;
+	dev->set_multicast_list = pasemi_mac_set_rx_mode;
+	dev->weight = 64;
+	dev->poll = pasemi_mac_poll;
+	dev->features = NETIF_F_HW_CSUM;
+
+	/* The dma status structure is located in the I/O bridge, and
+	 * is cache coherent.
+	 */
+	if (!dma_status)
+		/* XXXOJN This should come from the device tree */
+		dma_status = __ioremap(0xfd800000, 0x1000, 0);
+
+	mac->rx_status = &dma_status->rx_sta[mac->dma_rxch];
+	mac->tx_status = &dma_status->tx_sta[mac->dma_txch];
+
+	err = register_netdev(dev);
+
+	if (err) {
+		dev_err(&mac->pdev->dev, "register_netdev failed with error %d\n",
+			err);
+		goto out;
+	} else
+		printk(KERN_INFO "%s: PA Semi %s: intf %d, txch %d, rxch %d, "
+		       "hw addr %02x:%02x:%02x:%02x:%02x:%02x\n",
+		       dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI",
+		       mac->dma_if, mac->dma_txch, mac->dma_rxch,
+		       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+		       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+
+	return err;
+
+out:
+	pci_dev_put(mac->iob_pdev);
+out_put_dma_pdev:
+	pci_dev_put(mac->dma_pdev);
+out_free_netdev:
+	free_netdev(dev);
+out_disable_device:
+	pci_disable_device(pdev);
+	return err;
+
+}
+
+static void __devexit pasemi_mac_remove(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct pasemi_mac *mac;
+
+	if (!netdev)
+		return;
+
+	mac = netdev_priv(netdev);
+
+	unregister_netdev(netdev);
+
+	pci_disable_device(pdev);
+	pci_dev_put(mac->dma_pdev);
+	pci_dev_put(mac->iob_pdev);
+
+	pci_set_drvdata(pdev, NULL);
+	free_netdev(netdev);
+}
+
+static struct pci_device_id pasemi_mac_pci_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa005) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa006) },
+};
+
+MODULE_DEVICE_TABLE(pci, pasemi_mac_pci_tbl);
+
+static struct pci_driver pasemi_mac_driver = {
+	.name		= "pasemi_mac",
+	.id_table	= pasemi_mac_pci_tbl,
+	.probe		= pasemi_mac_probe,
+	.remove		= __devexit_p(pasemi_mac_remove),
+};
+
+static void __exit pasemi_mac_cleanup_module(void)
+{
+	pci_unregister_driver(&pasemi_mac_driver);
+	__iounmap(dma_status);
+	dma_status = NULL;
+}
+
+int pasemi_mac_init_module(void)
+{
+	return pci_register_driver(&pasemi_mac_driver);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
+MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver");
+
+module_init(pasemi_mac_init_module);
+module_exit(pasemi_mac_cleanup_module);
diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h
new file mode 100644
index 0000000..c3e37e4
--- /dev/null
+++ b/drivers/net/pasemi_mac.h
@@ -0,0 +1,460 @@
+/*
+ * Copyright (C) 2006 PA Semi, Inc
+ *
+ * Driver for the PA6T-1682M onchip 1G/10G Ethernet MACs, soft state and
+ * hardware register layouts.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef PASEMI_MAC_H
+#define PASEMI_MAC_H
+
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+
+struct pasemi_mac_txring {
+	spinlock_t	 lock;
+	struct pas_dma_xct_descr	*desc;
+	dma_addr_t	 dma;
+	unsigned int	 size;
+	unsigned int	 next_to_use;
+	unsigned int	 next_to_clean;
+	struct pasemi_mac_buffer *desc_info;
+	char		 irq_name[10];  /* "eth%d tx" */
+};
+
+struct pasemi_mac_rxring {
+	spinlock_t	 lock;
+	struct pas_dma_xct_descr	*desc;	/* RX channel descriptor ring */
+	dma_addr_t	 dma;
+	u64		*buffers;	/* RX interface buffer ring */
+	dma_addr_t	 buf_dma;
+	unsigned int	 size;
+	unsigned int	 next_to_fill;
+	unsigned int	 next_to_clean;
+	struct pasemi_mac_buffer *desc_info;
+	char		 irq_name[10];  /* "eth%d rx" */
+};
+
+struct pasemi_mac {
+	struct net_device *netdev;
+	struct pci_dev *pdev;
+	struct pci_dev *dma_pdev;
+	struct pci_dev *iob_pdev;
+	struct net_device_stats stats;
+
+	/* Pointer to the cacheable per-channel status registers */
+	u64	*rx_status;
+	u64	*tx_status;
+
+	u8		type;
+#define MAC_TYPE_GMAC	1
+#define MAC_TYPE_XAUI	2
+	u32	dma_txch;
+	u32	dma_if;
+	u32	dma_rxch;
+
+	u8		mac_addr[6];
+
+	struct timer_list	rxtimer;
+
+	struct pasemi_mac_txring *tx;
+	struct pasemi_mac_rxring *rx;
+};
+
+/* Software status descriptor (desc_info) */
+struct pasemi_mac_buffer {
+	struct sk_buff *skb;
+	dma_addr_t	dma;
+};
+
+
+/* status register layout in IOB region, at 0xfb800000 */
+struct pasdma_status {
+	u64 rx_sta[64];
+	u64 tx_sta[20];
+};
+
+/* descriptor structure */
+struct pas_dma_xct_descr {
+	union {
+		u64	mactx;
+		u64	macrx;
+	};
+	union {
+		u64	ptr;
+		u64	rxb;
+	};
+};
+
+/* MAC CFG register offsets */
+
+enum {
+	PAS_MAC_CFG_PCFG = 0x80,
+	PAS_MAC_CFG_TXP = 0x98,
+	PAS_MAC_IPC_CHNL = 0x208,
+};
+
+/* MAC CFG register fields */
+#define PAS_MAC_CFG_PCFG_PE		0x80000000
+#define PAS_MAC_CFG_PCFG_CE		0x40000000
+#define PAS_MAC_CFG_PCFG_BU		0x20000000
+#define PAS_MAC_CFG_PCFG_TT		0x10000000
+#define PAS_MAC_CFG_PCFG_TSR_M		0x0c000000
+#define PAS_MAC_CFG_PCFG_TSR_10M	0x00000000
+#define PAS_MAC_CFG_PCFG_TSR_100M	0x04000000
+#define PAS_MAC_CFG_PCFG_TSR_1G		0x08000000
+#define PAS_MAC_CFG_PCFG_TSR_10G	0x0c000000
+#define PAS_MAC_CFG_PCFG_T24		0x02000000
+#define PAS_MAC_CFG_PCFG_PR		0x01000000
+#define PAS_MAC_CFG_PCFG_CRO_M		0x00ff0000
+#define PAS_MAC_CFG_PCFG_CRO_S	16
+#define PAS_MAC_CFG_PCFG_IPO_M		0x0000ff00
+#define PAS_MAC_CFG_PCFG_IPO_S	8
+#define PAS_MAC_CFG_PCFG_S1		0x00000080
+#define PAS_MAC_CFG_PCFG_IO_M		0x00000060
+#define PAS_MAC_CFG_PCFG_IO_MAC		0x00000000
+#define PAS_MAC_CFG_PCFG_IO_OFF		0x00000020
+#define PAS_MAC_CFG_PCFG_IO_IND_ETH	0x00000040
+#define PAS_MAC_CFG_PCFG_IO_IND_IP	0x00000060
+#define PAS_MAC_CFG_PCFG_LP		0x00000010
+#define PAS_MAC_CFG_PCFG_TS		0x00000008
+#define PAS_MAC_CFG_PCFG_HD		0x00000004
+#define PAS_MAC_CFG_PCFG_SPD_M		0x00000003
+#define PAS_MAC_CFG_PCFG_SPD_10M	0x00000000
+#define PAS_MAC_CFG_PCFG_SPD_100M	0x00000001
+#define PAS_MAC_CFG_PCFG_SPD_1G		0x00000002
+#define PAS_MAC_CFG_PCFG_SPD_10G	0x00000003
+#define PAS_MAC_CFG_TXP_FCF		0x01000000
+#define PAS_MAC_CFG_TXP_FCE		0x00800000
+#define PAS_MAC_CFG_TXP_FC		0x00400000
+#define PAS_MAC_CFG_TXP_FPC_M		0x00300000
+#define PAS_MAC_CFG_TXP_FPC_S		20
+#define PAS_MAC_CFG_TXP_FPC(x)		(((x) << PAS_MAC_CFG_TXP_FPC_S) & \
+					 PAS_MAC_CFG_TXP_FPC_M)
+#define PAS_MAC_CFG_TXP_RT		0x00080000
+#define PAS_MAC_CFG_TXP_BL		0x00040000
+#define PAS_MAC_CFG_TXP_SL_M		0x00030000
+#define PAS_MAC_CFG_TXP_SL_S		16
+#define PAS_MAC_CFG_TXP_SL(x)		(((x) << PAS_MAC_CFG_TXP_SL_S) & \
+					 PAS_MAC_CFG_TXP_SL_M)
+#define PAS_MAC_CFG_TXP_COB_M		0x0000f000
+#define PAS_MAC_CFG_TXP_COB_S		12
+#define PAS_MAC_CFG_TXP_COB(x)		(((x) << PAS_MAC_CFG_TXP_COB_S) & \
+					 PAS_MAC_CFG_TXP_COB_M)
+#define PAS_MAC_CFG_TXP_TIFT_M		0x00000f00
+#define PAS_MAC_CFG_TXP_TIFT_S		8
+#define PAS_MAC_CFG_TXP_TIFT(x)		(((x) << PAS_MAC_CFG_TXP_TIFT_S) & \
+					 PAS_MAC_CFG_TXP_TIFT_M)
+#define PAS_MAC_CFG_TXP_TIFG_M		0x000000ff
+#define PAS_MAC_CFG_TXP_TIFG_S		0
+#define PAS_MAC_CFG_TXP_TIFG(x)		(((x) << PAS_MAC_CFG_TXP_TIFG_S) & \
+					 PAS_MAC_CFG_TXP_TIFG_M)
+
+#define PAS_MAC_IPC_CHNL_DCHNO_M	0x003f0000
+#define PAS_MAC_IPC_CHNL_DCHNO_S	16
+#define PAS_MAC_IPC_CHNL_DCHNO(x)	(((x) << PAS_MAC_IPC_CHNL_DCHNO_S) & \
+					 PAS_MAC_IPC_CHNL_DCHNO_M)
+#define PAS_MAC_IPC_CHNL_BCH_M		0x0000003f
+#define PAS_MAC_IPC_CHNL_BCH_S		0
+#define PAS_MAC_IPC_CHNL_BCH(x)		(((x) << PAS_MAC_IPC_CHNL_BCH_S) & \
+					 PAS_MAC_IPC_CHNL_BCH_M)
+
+/* All these registers live in the PCI configuration space for the DMA PCI
+ * device. Use the normal PCI config access functions for them.
+ */
+enum {
+	PAS_DMA_COM_TXCMD = 0x100,	/* Transmit Command Register  */
+	PAS_DMA_COM_TXSTA = 0x104,	/* Transmit Status Register   */
+	PAS_DMA_COM_RXCMD = 0x108,	/* Receive Command Register   */
+	PAS_DMA_COM_RXSTA = 0x10c,	/* Receive Status Register    */
+};
+#define PAS_DMA_COM_TXCMD_EN	0x00000001 /* enable */
+#define PAS_DMA_COM_TXSTA_ACT	0x00000001 /* active */
+#define PAS_DMA_COM_RXCMD_EN	0x00000001 /* enable */
+#define PAS_DMA_COM_RXSTA_ACT	0x00000001 /* active */
+
+
+/* Per-interface and per-channel registers */
+#define _PAS_DMA_RXINT_STRIDE		0x20
+#define PAS_DMA_RXINT_RCMDSTA(i)	(0x200+(i)*_PAS_DMA_RXINT_STRIDE)
+#define    PAS_DMA_RXINT_RCMDSTA_EN	0x00000001
+#define    PAS_DMA_RXINT_RCMDSTA_ST	0x00000002
+#define    PAS_DMA_RXINT_RCMDSTA_OO	0x00000100
+#define    PAS_DMA_RXINT_RCMDSTA_BP	0x00000200
+#define    PAS_DMA_RXINT_RCMDSTA_DR	0x00000400
+#define    PAS_DMA_RXINT_RCMDSTA_BT	0x00000800
+#define    PAS_DMA_RXINT_RCMDSTA_TB	0x00001000
+#define    PAS_DMA_RXINT_RCMDSTA_ACT	0x00010000
+#define    PAS_DMA_RXINT_RCMDSTA_DROPS_M	0xfffe0000
+#define    PAS_DMA_RXINT_RCMDSTA_DROPS_S	17
+#define PAS_DMA_RXINT_INCR(i)		(0x210+(i)*_PAS_DMA_RXINT_STRIDE)
+#define    PAS_DMA_RXINT_INCR_INCR_M	0x0000ffff
+#define    PAS_DMA_RXINT_INCR_INCR_S	0
+#define    PAS_DMA_RXINT_INCR_INCR(x)	((x) & 0x0000ffff)
+#define PAS_DMA_RXINT_BASEL(i)		(0x218+(i)*_PAS_DMA_RXINT_STRIDE)
+#define    PAS_DMA_RXINT_BASEL_BRBL(x)	((x) & ~0x3f)
+#define PAS_DMA_RXINT_BASEU(i)		(0x21c+(i)*_PAS_DMA_RXINT_STRIDE)
+#define    PAS_DMA_RXINT_BASEU_BRBH(x)	((x) & 0xfff)
+#define    PAS_DMA_RXINT_BASEU_SIZ_M	0x3fff0000	/* # of cache lines worth of buffer ring */
+#define    PAS_DMA_RXINT_BASEU_SIZ_S	16		/* 0 = 16K */
+#define    PAS_DMA_RXINT_BASEU_SIZ(x)	(((x) << PAS_DMA_RXINT_BASEU_SIZ_S) & \
+					 PAS_DMA_RXINT_BASEU_SIZ_M)
+
+
+#define _PAS_DMA_TXCHAN_STRIDE	0x20    /* Size per channel		*/
+#define _PAS_DMA_TXCHAN_TCMDSTA	0x300	/* Command / Status		*/
+#define _PAS_DMA_TXCHAN_CFG	0x304	/* Configuration		*/
+#define _PAS_DMA_TXCHAN_DSCRBU	0x308	/* Descriptor BU Allocation	*/
+#define _PAS_DMA_TXCHAN_INCR	0x310	/* Descriptor increment		*/
+#define _PAS_DMA_TXCHAN_CNT	0x314	/* Descriptor count/offset	*/
+#define _PAS_DMA_TXCHAN_BASEL	0x318	/* Descriptor ring base (low)	*/
+#define _PAS_DMA_TXCHAN_BASEU	0x31c	/*			(high)	*/
+#define PAS_DMA_TXCHAN_TCMDSTA(c) (0x300+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define    PAS_DMA_TXCHAN_TCMDSTA_EN	0x00000001	/* Enabled */
+#define    PAS_DMA_TXCHAN_TCMDSTA_ST	0x00000002	/* Stop interface */
+#define    PAS_DMA_TXCHAN_TCMDSTA_ACT	0x00010000	/* Active */
+#define PAS_DMA_TXCHAN_CFG(c)     (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define    PAS_DMA_TXCHAN_CFG_TY_IFACE	0x00000000	/* Type = interface */
+#define    PAS_DMA_TXCHAN_CFG_TATTR_M	0x0000003c
+#define    PAS_DMA_TXCHAN_CFG_TATTR_S	2
+#define    PAS_DMA_TXCHAN_CFG_TATTR(x)	(((x) << PAS_DMA_TXCHAN_CFG_TATTR_S) & \
+					 PAS_DMA_TXCHAN_CFG_TATTR_M)
+#define    PAS_DMA_TXCHAN_CFG_WT_M	0x000001c0
+#define    PAS_DMA_TXCHAN_CFG_WT_S	6
+#define    PAS_DMA_TXCHAN_CFG_WT(x)	(((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \
+					 PAS_DMA_TXCHAN_CFG_WT_M)
+#define    PAS_DMA_TXCHAN_CFG_CF	0x00001000	/* Clean first line */
+#define    PAS_DMA_TXCHAN_CFG_CL	0x00002000	/* Clean last line */
+#define    PAS_DMA_TXCHAN_CFG_UP	0x00004000	/* update tx descr when sent */
+#define PAS_DMA_TXCHAN_INCR(c)    (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define PAS_DMA_TXCHAN_BASEL(c)   (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define    PAS_DMA_TXCHAN_BASEL_BRBL_M	0xffffffc0
+#define    PAS_DMA_TXCHAN_BASEL_BRBL_S	0
+#define    PAS_DMA_TXCHAN_BASEL_BRBL(x)	(((x) << PAS_DMA_TXCHAN_BASEL_BRBL_S) & \
+					 PAS_DMA_TXCHAN_BASEL_BRBL_M)
+#define PAS_DMA_TXCHAN_BASEU(c)   (0x31c+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define    PAS_DMA_TXCHAN_BASEU_BRBH_M	0x00000fff
+#define    PAS_DMA_TXCHAN_BASEU_BRBH_S	0
+#define    PAS_DMA_TXCHAN_BASEU_BRBH(x)	(((x) << PAS_DMA_TXCHAN_BASEU_BRBH_S) & \
+					 PAS_DMA_TXCHAN_BASEU_BRBH_M)
+/* # of cache lines worth of buffer ring */
+#define    PAS_DMA_TXCHAN_BASEU_SIZ_M	0x3fff0000
+#define    PAS_DMA_TXCHAN_BASEU_SIZ_S	16		/* 0 = 16K */
+#define    PAS_DMA_TXCHAN_BASEU_SIZ(x)	(((x) << PAS_DMA_TXCHAN_BASEU_SIZ_S) & \
+					 PAS_DMA_TXCHAN_BASEU_SIZ_M)
+
+#define _PAS_DMA_RXCHAN_STRIDE	0x20    /* Size per channel		*/
+#define _PAS_DMA_RXCHAN_CCMDSTA	0x800	/* Command / Status		*/
+#define _PAS_DMA_RXCHAN_CFG	0x804	/* Configuration		*/
+#define _PAS_DMA_RXCHAN_INCR	0x810	/* Descriptor increment		*/
+#define _PAS_DMA_RXCHAN_CNT	0x814	/* Descriptor count/offset	*/
+#define _PAS_DMA_RXCHAN_BASEL	0x818	/* Descriptor ring base (low)	*/
+#define _PAS_DMA_RXCHAN_BASEU	0x81c	/*			(high)	*/
+#define PAS_DMA_RXCHAN_CCMDSTA(c) (0x800+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define    PAS_DMA_RXCHAN_CCMDSTA_EN	0x00000001	/* Enabled */
+#define    PAS_DMA_RXCHAN_CCMDSTA_ST	0x00000002	/* Stop interface */
+#define    PAS_DMA_RXCHAN_CCMDSTA_ACT	0x00010000	/* Active */
+#define    PAS_DMA_RXCHAN_CCMDSTA_DU	0x00020000
+#define PAS_DMA_RXCHAN_CFG(c)     (0x804+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define    PAS_DMA_RXCHAN_CFG_HBU_M	0x00000380
+#define    PAS_DMA_RXCHAN_CFG_HBU_S	7
+#define    PAS_DMA_RXCHAN_CFG_HBU(x)	(((x) << PAS_DMA_RXCHAN_CFG_HBU_S) & \
+					 PAS_DMA_RXCHAN_CFG_HBU_M)
+#define PAS_DMA_RXCHAN_INCR(c)    (0x810+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_BASEL(c)   (0x818+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define    PAS_DMA_RXCHAN_BASEL_BRBL_M	0xffffffc0
+#define    PAS_DMA_RXCHAN_BASEL_BRBL_S	0
+#define    PAS_DMA_RXCHAN_BASEL_BRBL(x)	(((x) << PAS_DMA_RXCHAN_BASEL_BRBL_S) & \
+					 PAS_DMA_RXCHAN_BASEL_BRBL_M)
+#define PAS_DMA_RXCHAN_BASEU(c)   (0x81c+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define    PAS_DMA_RXCHAN_BASEU_BRBH_M	0x00000fff
+#define    PAS_DMA_RXCHAN_BASEU_BRBH_S	0
+#define    PAS_DMA_RXCHAN_BASEU_BRBH(x)	(((x) << PAS_DMA_RXCHAN_BASEU_BRBH_S) & \
+					 PAS_DMA_RXCHAN_BASEU_BRBH_M)
+/* # of cache lines worth of buffer ring */
+#define    PAS_DMA_RXCHAN_BASEU_SIZ_M	0x3fff0000
+#define    PAS_DMA_RXCHAN_BASEU_SIZ_S	16		/* 0 = 16K */
+#define    PAS_DMA_RXCHAN_BASEU_SIZ(x)	(((x) << PAS_DMA_RXCHAN_BASEU_SIZ_S) & \
+					 PAS_DMA_RXCHAN_BASEU_SIZ_M)
+
+#define    PAS_STATUS_PCNT_M		0x000000000000ffffull
+#define    PAS_STATUS_PCNT_S		0
+#define    PAS_STATUS_DCNT_M		0x00000000ffff0000ull
+#define    PAS_STATUS_DCNT_S		16
+#define    PAS_STATUS_BPCNT_M		0x0000ffff00000000ull
+#define    PAS_STATUS_BPCNT_S		32
+#define    PAS_STATUS_TIMER		0x1000000000000000ull
+#define    PAS_STATUS_ERROR		0x2000000000000000ull
+#define    PAS_STATUS_SOFT		0x4000000000000000ull
+#define    PAS_STATUS_INT		0x8000000000000000ull
+
+#define PAS_IOB_DMA_RXCH_CFG(i)		(0x1100 + (i)*4)
+#define    PAS_IOB_DMA_RXCH_CFG_CNTTH_M		0x00000fff
+#define    PAS_IOB_DMA_RXCH_CFG_CNTTH_S		0
+#define    PAS_IOB_DMA_RXCH_CFG_CNTTH(x)	(((x) << PAS_IOB_DMA_RXCH_CFG_CNTTH_S) & \
+						 PAS_IOB_DMA_RXCH_CFG_CNTTH_M)
+#define PAS_IOB_DMA_TXCH_CFG(i)		(0x1200 + (i)*4)
+#define    PAS_IOB_DMA_TXCH_CFG_CNTTH_M		0x00000fff
+#define    PAS_IOB_DMA_TXCH_CFG_CNTTH_S		0
+#define    PAS_IOB_DMA_TXCH_CFG_CNTTH(x)	(((x) << PAS_IOB_DMA_TXCH_CFG_CNTTH_S) & \
+						 PAS_IOB_DMA_TXCH_CFG_CNTTH_M)
+#define PAS_IOB_DMA_RXCH_STAT(i)	(0x1300 + (i)*4)
+#define    PAS_IOB_DMA_RXCH_STAT_INTGEN	0x00001000
+#define    PAS_IOB_DMA_RXCH_STAT_CNTDEL_M	0x00000fff
+#define    PAS_IOB_DMA_RXCH_STAT_CNTDEL_S	0
+#define    PAS_IOB_DMA_RXCH_STAT_CNTDEL(x)	(((x) << PAS_IOB_DMA_RXCH_STAT_CNTDEL_S) &\
+						 PAS_IOB_DMA_RXCH_STAT_CNTDEL_M)
+#define PAS_IOB_DMA_TXCH_STAT(i)	(0x1400 + (i)*4)
+#define    PAS_IOB_DMA_TXCH_STAT_INTGEN	0x00001000
+#define    PAS_IOB_DMA_TXCH_STAT_CNTDEL_M	0x00000fff
+#define    PAS_IOB_DMA_TXCH_STAT_CNTDEL_S	0
+#define    PAS_IOB_DMA_TXCH_STAT_CNTDEL(x)	(((x) << PAS_IOB_DMA_TXCH_STAT_CNTDEL_S) &\
+						 PAS_IOB_DMA_TXCH_STAT_CNTDEL_M)
+#define PAS_IOB_DMA_RXCH_RESET(i)	(0x1500 + (i)*4)
+#define    PAS_IOB_DMA_RXCH_RESET_PCNT_M	0xffff0000
+#define    PAS_IOB_DMA_RXCH_RESET_PCNT_S	0
+#define    PAS_IOB_DMA_RXCH_RESET_PCNT(x)	(((x) << PAS_IOB_DMA_RXCH_RESET_PCNT_S) & \
+						 PAS_IOB_DMA_RXCH_RESET_PCNT_M)
+#define    PAS_IOB_DMA_RXCH_RESET_PCNTRST	0x00000020
+#define    PAS_IOB_DMA_RXCH_RESET_DCNTRST	0x00000010
+#define    PAS_IOB_DMA_RXCH_RESET_TINTC		0x00000008
+#define    PAS_IOB_DMA_RXCH_RESET_DINTC		0x00000004
+#define    PAS_IOB_DMA_RXCH_RESET_SINTC		0x00000002
+#define    PAS_IOB_DMA_RXCH_RESET_PINTC		0x00000001
+#define PAS_IOB_DMA_TXCH_RESET(i)	(0x1600 + (i)*4)
+#define    PAS_IOB_DMA_TXCH_RESET_PCNT_M	0xffff0000
+#define    PAS_IOB_DMA_TXCH_RESET_PCNT_S	0
+#define    PAS_IOB_DMA_TXCH_RESET_PCNT(x)	(((x) << PAS_IOB_DMA_TXCH_RESET_PCNT_S) & \
+						 PAS_IOB_DMA_TXCH_RESET_PCNT_M)
+#define    PAS_IOB_DMA_TXCH_RESET_PCNTRST	0x00000020
+#define    PAS_IOB_DMA_TXCH_RESET_DCNTRST	0x00000010
+#define    PAS_IOB_DMA_TXCH_RESET_TINTC		0x00000008
+#define    PAS_IOB_DMA_TXCH_RESET_DINTC		0x00000004
+#define    PAS_IOB_DMA_TXCH_RESET_SINTC		0x00000002
+#define    PAS_IOB_DMA_TXCH_RESET_PINTC		0x00000001
+
+#define PAS_IOB_DMA_COM_TIMEOUTCFG		0x1700
+#define    PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M	0x00ffffff
+#define    PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S	0
+#define    PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(x)	(((x) << PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S) & \
+						 PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M)
+
+/* Transmit descriptor fields */
+#define	XCT_MACTX_T		0x8000000000000000ull
+#define	XCT_MACTX_ST		0x4000000000000000ull
+#define XCT_MACTX_NORES		0x0000000000000000ull
+#define XCT_MACTX_8BRES		0x1000000000000000ull
+#define XCT_MACTX_24BRES	0x2000000000000000ull
+#define XCT_MACTX_40BRES	0x3000000000000000ull
+#define XCT_MACTX_I		0x0800000000000000ull
+#define XCT_MACTX_O		0x0400000000000000ull
+#define XCT_MACTX_E		0x0200000000000000ull
+#define XCT_MACTX_VLAN_M	0x0180000000000000ull
+#define XCT_MACTX_VLAN_NOP	0x0000000000000000ull
+#define XCT_MACTX_VLAN_REMOVE	0x0080000000000000ull
+#define XCT_MACTX_VLAN_INSERT   0x0100000000000000ull
+#define XCT_MACTX_VLAN_REPLACE  0x0180000000000000ull
+#define XCT_MACTX_CRC_M		0x0060000000000000ull
+#define XCT_MACTX_CRC_NOP	0x0000000000000000ull
+#define XCT_MACTX_CRC_INSERT	0x0020000000000000ull
+#define XCT_MACTX_CRC_PAD	0x0040000000000000ull
+#define XCT_MACTX_CRC_REPLACE	0x0060000000000000ull
+#define XCT_MACTX_SS		0x0010000000000000ull
+#define XCT_MACTX_LLEN_M	0x00007fff00000000ull
+#define XCT_MACTX_LLEN_S	32ull
+#define XCT_MACTX_LLEN(x)	((((long)(x)) << XCT_MACTX_LLEN_S) & \
+				 XCT_MACTX_LLEN_M)
+#define XCT_MACTX_IPH_M		0x00000000f8000000ull
+#define XCT_MACTX_IPH_S		27ull
+#define XCT_MACTX_IPH(x)	((((long)(x)) << XCT_MACTX_IPH_S) & \
+				 XCT_MACTX_IPH_M)
+#define XCT_MACTX_IPO_M		0x0000000007c00000ull
+#define XCT_MACTX_IPO_S		22ull
+#define XCT_MACTX_IPO(x)	((((long)(x)) << XCT_MACTX_IPO_S) & \
+				 XCT_MACTX_IPO_M)
+#define XCT_MACTX_CSUM_M	0x0000000000000060ull
+#define XCT_MACTX_CSUM_NOP	0x0000000000000000ull
+#define XCT_MACTX_CSUM_TCP	0x0000000000000040ull
+#define XCT_MACTX_CSUM_UDP	0x0000000000000060ull
+#define XCT_MACTX_V6		0x0000000000000010ull
+#define XCT_MACTX_C		0x0000000000000004ull
+#define XCT_MACTX_AL2		0x0000000000000002ull
+
+/* Receive descriptor fields */
+#define	XCT_MACRX_T		0x8000000000000000ull
+#define	XCT_MACRX_ST		0x4000000000000000ull
+#define XCT_MACRX_NORES		0x0000000000000000ull
+#define XCT_MACRX_8BRES		0x1000000000000000ull
+#define XCT_MACRX_24BRES	0x2000000000000000ull
+#define XCT_MACRX_40BRES	0x3000000000000000ull
+#define XCT_MACRX_O		0x0400000000000000ull
+#define XCT_MACRX_E		0x0200000000000000ull
+#define XCT_MACRX_FF		0x0100000000000000ull
+#define XCT_MACRX_PF		0x0080000000000000ull
+#define XCT_MACRX_OB		0x0040000000000000ull
+#define XCT_MACRX_OD		0x0020000000000000ull
+#define XCT_MACRX_FS		0x0010000000000000ull
+#define XCT_MACRX_NB_M		0x000fc00000000000ull
+#define XCT_MACRX_NB_S		46ULL
+#define XCT_MACRX_NB(x)		((((long)(x)) << XCT_MACRX_NB_S) & \
+				 XCT_MACRX_NB_M)
+#define XCT_MACRX_LLEN_M	0x00003fff00000000ull
+#define XCT_MACRX_LLEN_S	32ULL
+#define XCT_MACRX_LLEN(x)	((((long)(x)) << XCT_MACRX_LLEN_S) & \
+				 XCT_MACRX_LLEN_M)
+#define XCT_MACRX_CRC		0x0000000080000000ull
+#define XCT_MACRX_LEN_M		0x0000000060000000ull
+#define XCT_MACRX_LEN_TOOSHORT	0x0000000020000000ull
+#define XCT_MACRX_LEN_BELOWMIN	0x0000000040000000ull
+#define XCT_MACRX_LEN_TRUNC	0x0000000060000000ull
+#define XCT_MACRX_CAST_M	0x0000000018000000ull
+#define XCT_MACRX_CAST_UNI	0x0000000000000000ull
+#define XCT_MACRX_CAST_MULTI	0x0000000008000000ull
+#define XCT_MACRX_CAST_BROAD	0x0000000010000000ull
+#define XCT_MACRX_CAST_PAUSE	0x0000000018000000ull
+#define XCT_MACRX_VLC_M		0x0000000006000000ull
+#define XCT_MACRX_FM		0x0000000001000000ull
+#define XCT_MACRX_HTY_M		0x0000000000c00000ull
+#define XCT_MACRX_HTY_IPV4_OK	0x0000000000000000ull
+#define XCT_MACRX_HTY_IPV6 	0x0000000000400000ull
+#define XCT_MACRX_HTY_IPV4_BAD	0x0000000000800000ull
+#define XCT_MACRX_HTY_NONIP	0x0000000000c00000ull
+#define XCT_MACRX_IPP_M		0x00000000003f0000ull
+#define XCT_MACRX_IPP_S		16
+#define XCT_MACRX_CSUM_M	0x000000000000ffffull
+#define XCT_MACRX_CSUM_S	0
+
+#define XCT_PTR_T		0x8000000000000000ull
+#define XCT_PTR_LEN_M		0x7ffff00000000000ull
+#define XCT_PTR_LEN_S		44
+#define XCT_PTR_LEN(x)		((((long)(x)) << XCT_PTR_LEN_S) & \
+				 XCT_PTR_LEN_M)
+#define XCT_PTR_ADDR_M		0x00000fffffffffffull
+#define XCT_PTR_ADDR_S		0
+#define XCT_PTR_ADDR(x)		((((long)(x)) << XCT_PTR_ADDR_S) & \
+				 XCT_PTR_ADDR_M)
+
+/* Receive interface buffer fields */
+#define XCT_RXB_LEN_M		0x0ffff00000000000ull
+#define XCT_RXB_LEN_S		44
+#define XCT_RXB_LEN(x)		((((long)(x)) << XCT_PTR_LEN_S) & XCT_PTR_LEN_M)
+#define XCT_RXB_ADDR_M		0x00000fffffffffffull
+#define XCT_RXB_ADDR_S		0
+#define XCT_RXB_ADDR(x)		((((long)(x)) << XCT_PTR_ADDR_S) & XCT_PTR_ADDR_M)
+
+
+#endif /* PASEMI_MAC_H */
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
old mode 100644
new mode 100755
index 8844c20..2429b27
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -22,6 +22,7 @@
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/ip.h>
+#include <linux/in.h>
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/netdevice.h>
@@ -63,6 +64,7 @@
 
 static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = {
 	{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3022_DEVICE_ID)},
+	{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3032_DEVICE_ID)},
 	/* required last entry */
 	{0,}
 };
@@ -1475,6 +1477,10 @@
 			 2) << 7))
 		return -1;
 
+	if (qdev->device_id == QL3032_DEVICE_ID)
+		ql_write_page0_reg(qdev, 
+			&port_regs->macMIIMgmtControlReg, 0x0f00000);
+
 	/* Divide 125MHz clock by 28 to meet PHY timing requirements */
 	reg = MAC_MII_CONTROL_CLK_SEL_DIV28;
 
@@ -1706,18 +1712,42 @@
 				   struct ob_mac_iocb_rsp *mac_rsp)
 {
 	struct ql_tx_buf_cb *tx_cb;
+	int i;
 
 	tx_cb = &qdev->tx_buf[mac_rsp->transaction_id];
 	pci_unmap_single(qdev->pdev,
-			 pci_unmap_addr(tx_cb, mapaddr),
-			 pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE);
-	dev_kfree_skb_irq(tx_cb->skb);
+			 pci_unmap_addr(&tx_cb->map[0], mapaddr),
+			 pci_unmap_len(&tx_cb->map[0], maplen),
+			 PCI_DMA_TODEVICE);
+	tx_cb->seg_count--;
+	if (tx_cb->seg_count) {
+		for (i = 1; i < tx_cb->seg_count; i++) {
+			pci_unmap_page(qdev->pdev,
+				       pci_unmap_addr(&tx_cb->map[i],
+						      mapaddr),
+				       pci_unmap_len(&tx_cb->map[i], maplen),
+				       PCI_DMA_TODEVICE);
+		}
+	}
 	qdev->stats.tx_packets++;
 	qdev->stats.tx_bytes += tx_cb->skb->len;
+	dev_kfree_skb_irq(tx_cb->skb);
 	tx_cb->skb = NULL;
 	atomic_inc(&qdev->tx_count);
 }
 
+/*
+ * The difference between 3022 and 3032 for inbound completions:
+ * 3022 uses two buffers per completion.  The first buffer contains 
+ * (some) header info, the second the remainder of the headers plus 
+ * the data.  For this chip we reserve some space at the top of the 
+ * receive buffer so that the header info in buffer one can be 
+ * prepended to the buffer two.  Buffer two is the sent up while 
+ * buffer one is returned to the hardware to be reused.
+ * 3032 receives all of it's data and headers in one buffer for a 
+ * simpler process.  3032 also supports checksum verification as
+ * can be seen in ql_process_macip_rx_intr().
+ */
 static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
 				   struct ib_mac_iocb_rsp *ib_mac_rsp_ptr)
 {
@@ -1740,14 +1770,17 @@
 	qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
 	qdev->small_buf_release_cnt++;
 
-	/* start of first buffer */
-	lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
-	lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
-	qdev->lrg_buf_release_cnt++;
-	if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
-		qdev->lrg_buf_index = 0;
-	curr_ial_ptr++;		/* 64-bit pointers require two incs. */
-	curr_ial_ptr++;
+	if (qdev->device_id == QL3022_DEVICE_ID) {
+		/* start of first buffer (3022 only) */
+		lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+		lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
+		qdev->lrg_buf_release_cnt++;
+		if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) {
+			qdev->lrg_buf_index = 0;
+		}
+		curr_ial_ptr++;	/* 64-bit pointers require two incs. */
+		curr_ial_ptr++;
+	}
 
 	/* start of second buffer */
 	lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
@@ -1778,7 +1811,8 @@
 	qdev->ndev->last_rx = jiffies;
 	lrg_buf_cb2->skb = NULL;
 
-	ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
+	if (qdev->device_id == QL3022_DEVICE_ID)
+		ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
 	ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2);
 }
 
@@ -1790,7 +1824,7 @@
 	struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL;
 	struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL;
 	u32 *curr_ial_ptr;
-	struct sk_buff *skb1, *skb2;
+	struct sk_buff *skb1 = NULL, *skb2;
 	struct net_device *ndev = qdev->ndev;
 	u16 length = le16_to_cpu(ib_ip_rsp_ptr->length);
 	u16 size = 0;
@@ -1806,16 +1840,20 @@
 	qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
 	qdev->small_buf_release_cnt++;
 
-	/* start of first buffer */
-	lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
-	lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
-
-	qdev->lrg_buf_release_cnt++;
-	if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
-		qdev->lrg_buf_index = 0;
-	skb1 = lrg_buf_cb1->skb;
-	curr_ial_ptr++;		/* 64-bit pointers require two incs. */
-	curr_ial_ptr++;
+	if (qdev->device_id == QL3022_DEVICE_ID) {
+		/* start of first buffer on 3022 */
+		lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+		lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
+		qdev->lrg_buf_release_cnt++;
+		if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
+			qdev->lrg_buf_index = 0;
+		skb1 = lrg_buf_cb1->skb;
+		curr_ial_ptr++;	/* 64-bit pointers require two incs. */
+		curr_ial_ptr++;
+		size = ETH_HLEN;
+		if (*((u16 *) skb1->data) != 0xFFFF)
+			size += VLAN_ETH_HLEN - ETH_HLEN;
+	}
 
 	/* start of second buffer */
 	lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
@@ -1825,18 +1863,6 @@
 	if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
 		qdev->lrg_buf_index = 0;
 
-	qdev->stats.rx_packets++;
-	qdev->stats.rx_bytes += length;
-
-	/*
-	 * Copy the ethhdr from first buffer to second. This
-	 * is necessary for IP completions.
-	 */
-	if (*((u16 *) skb1->data) != 0xFFFF)
-		size = VLAN_ETH_HLEN;
-	else
-		size = ETH_HLEN;
-
 	skb_put(skb2, length);	/* Just the second buffer length here. */
 	pci_unmap_single(qdev->pdev,
 			 pci_unmap_addr(lrg_buf_cb2, mapaddr),
@@ -1844,16 +1870,40 @@
 			 PCI_DMA_FROMDEVICE);
 	prefetch(skb2->data);
 
-	memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size);
-	skb2->dev = qdev->ndev;
 	skb2->ip_summed = CHECKSUM_NONE;
+	if (qdev->device_id == QL3022_DEVICE_ID) {
+		/*
+		 * Copy the ethhdr from first buffer to second. This
+		 * is necessary for 3022 IP completions.
+		 */
+		memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size);
+	} else {
+		u16 checksum = le16_to_cpu(ib_ip_rsp_ptr->checksum);
+		if (checksum & 
+			(IB_IP_IOCB_RSP_3032_ICE | 
+			 IB_IP_IOCB_RSP_3032_CE | 
+			 IB_IP_IOCB_RSP_3032_NUC)) {
+			printk(KERN_ERR
+			       "%s: Bad checksum for this %s packet, checksum = %x.\n",
+			       __func__,
+			       ((checksum & 
+				IB_IP_IOCB_RSP_3032_TCP) ? "TCP" :
+				"UDP"),checksum);
+		} else if (checksum & IB_IP_IOCB_RSP_3032_TCP) {
+			skb2->ip_summed = CHECKSUM_UNNECESSARY;
+		} 
+	}
+	skb2->dev = qdev->ndev;
 	skb2->protocol = eth_type_trans(skb2, qdev->ndev);
 
 	netif_receive_skb(skb2);
+	qdev->stats.rx_packets++;
+	qdev->stats.rx_bytes += length;
 	ndev->last_rx = jiffies;
 	lrg_buf_cb2->skb = NULL;
 
-	ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
+	if (qdev->device_id == QL3022_DEVICE_ID)
+		ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
 	ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2);
 }
 
@@ -1880,12 +1930,14 @@
 			break;
 
 		case OPCODE_IB_MAC_IOCB:
+		case OPCODE_IB_3032_MAC_IOCB:
 			ql_process_mac_rx_intr(qdev, (struct ib_mac_iocb_rsp *)
 					       net_rsp);
 			(*rx_cleaned)++;
 			break;
 
 		case OPCODE_IB_IP_IOCB:
+		case OPCODE_IB_3032_IP_IOCB:
 			ql_process_macip_rx_intr(qdev, (struct ib_ip_iocb_rsp *)
 						 net_rsp);
 			(*rx_cleaned)++;
@@ -2032,13 +2084,96 @@
 	return IRQ_RETVAL(handled);
 }
 
+/*
+ * Get the total number of segments needed for the 
+ * given number of fragments.  This is necessary because
+ * outbound address lists (OAL) will be used when more than
+ * two frags are given.  Each address list has 5 addr/len 
+ * pairs.  The 5th pair in each AOL is used to  point to
+ * the next AOL if more frags are coming.  
+ * That is why the frags:segment count  ratio is not linear.
+ */
+static int ql_get_seg_count(unsigned short frags)
+{
+	switch(frags) {
+	case 0:	return 1;	/* just the skb->data seg */
+	case 1:	return 2;	/* skb->data + 1 frag */
+	case 2:	return 3;	/* skb->data + 2 frags */
+	case 3:	return 5;	/* skb->data + 1 frag + 1 AOL containting 2 frags */
+	case 4:	return 6;
+	case 5:	return 7;
+	case 6:	return 8;
+	case 7:	return 10;
+	case 8:	return 11;
+	case 9:	return 12;
+	case 10: return 13;
+	case 11: return 15;
+	case 12: return 16;
+	case 13: return 17;
+	case 14: return 18;
+	case 15: return 20;
+	case 16: return 21;
+	case 17: return 22;
+	case 18: return 23;
+	}
+	return -1;
+}
+
+static void ql_hw_csum_setup(struct sk_buff *skb,
+			     struct ob_mac_iocb_req *mac_iocb_ptr)
+{
+	struct ethhdr *eth;
+	struct iphdr *ip = NULL;
+	u8 offset = ETH_HLEN;
+
+	eth = (struct ethhdr *)(skb->data);
+
+	if (eth->h_proto == __constant_htons(ETH_P_IP)) {
+		ip = (struct iphdr *)&skb->data[ETH_HLEN];
+	} else if (eth->h_proto == htons(ETH_P_8021Q) &&
+		   ((struct vlan_ethhdr *)skb->data)->
+		   h_vlan_encapsulated_proto == __constant_htons(ETH_P_IP)) {
+		ip = (struct iphdr *)&skb->data[VLAN_ETH_HLEN];
+		offset = VLAN_ETH_HLEN;
+	}
+
+	if (ip) {
+		if (ip->protocol == IPPROTO_TCP) {
+			mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_TC;
+			mac_iocb_ptr->ip_hdr_off = offset;
+			mac_iocb_ptr->ip_hdr_len = ip->ihl;
+		} else if (ip->protocol == IPPROTO_UDP) {
+			mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_UC;
+			mac_iocb_ptr->ip_hdr_off = offset;
+			mac_iocb_ptr->ip_hdr_len = ip->ihl;
+		}
+	}
+}
+
+/*
+ * The difference between 3022 and 3032 sends:
+ * 3022 only supports a simple single segment transmission.
+ * 3032 supports checksumming and scatter/gather lists (fragments).
+ * The 3032 supports sglists by using the 3 addr/len pairs (ALP) 
+ * in the IOCB plus a chain of outbound address lists (OAL) that 
+ * each contain 5 ALPs.  The last ALP of the IOCB (3rd) or OAL (5th) 
+ * will used to point to an OAL when more ALP entries are required.  
+ * The IOCB is always the top of the chain followed by one or more 
+ * OALs (when necessary).
+ */
 static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
 {
 	struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
 	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
 	struct ql_tx_buf_cb *tx_cb;
+	u32 tot_len = skb->len;
+	struct oal *oal;
+	struct oal_entry *oal_entry;
+	int len;
 	struct ob_mac_iocb_req *mac_iocb_ptr;
 	u64 map;
+	int seg_cnt, seg = 0;
+	int frag_cnt = (int)skb_shinfo(skb)->nr_frags;
 
 	if (unlikely(atomic_read(&qdev->tx_count) < 2)) {
 		if (!netif_queue_stopped(ndev))
@@ -2046,21 +2181,79 @@
 		return NETDEV_TX_BUSY;
 	}
 	tx_cb = &qdev->tx_buf[qdev->req_producer_index] ;
+	seg_cnt = tx_cb->seg_count = ql_get_seg_count((skb_shinfo(skb)->nr_frags));
+	if(seg_cnt == -1) {
+		printk(KERN_ERR PFX"%s: invalid segment count!\n",__func__);
+		return NETDEV_TX_OK;
+
+	}
 	mac_iocb_ptr = tx_cb->queue_entry;
 	memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req));
 	mac_iocb_ptr->opcode = qdev->mac_ob_opcode;
 	mac_iocb_ptr->flags |= qdev->mb_bit_mask;
 	mac_iocb_ptr->transaction_id = qdev->req_producer_index;
-	mac_iocb_ptr->data_len = cpu_to_le16((u16) skb->len);
+	mac_iocb_ptr->data_len = cpu_to_le16((u16) tot_len);
 	tx_cb->skb = skb;
-	map = pci_map_single(qdev->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
-	mac_iocb_ptr->buf_addr0_low = cpu_to_le32(LS_64BITS(map));
-	mac_iocb_ptr->buf_addr0_high = cpu_to_le32(MS_64BITS(map));
-	mac_iocb_ptr->buf_0_len = cpu_to_le32(skb->len | OB_MAC_IOCB_REQ_E);
-	pci_unmap_addr_set(tx_cb, mapaddr, map);
-	pci_unmap_len_set(tx_cb, maplen, skb->len);
-	atomic_dec(&qdev->tx_count);
+	if (skb->ip_summed == CHECKSUM_PARTIAL)
+		ql_hw_csum_setup(skb, mac_iocb_ptr);
+	len = skb_headlen(skb);
+	map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE);
+	oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low;
+	oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
+	oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
+	oal_entry->len = cpu_to_le32(len);
+	pci_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
+	pci_unmap_len_set(&tx_cb->map[seg], maplen, len);
+	seg++;
 
+	if (!skb_shinfo(skb)->nr_frags) {
+		/* Terminate the last segment. */
+		oal_entry->len =
+		    cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY);
+	} else {
+		int i;
+		oal = tx_cb->oal;
+		for (i=0; i<frag_cnt; i++,seg++) {
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+			oal_entry++;
+			if ((seg == 2 && seg_cnt > 3) ||	/* Check for continuation */
+			    (seg == 7 && seg_cnt > 8) ||	/* requirements. It's strange */
+			    (seg == 12 && seg_cnt > 13) ||	/* but necessary. */
+			    (seg == 17 && seg_cnt > 18)) {
+				/* Continuation entry points to outbound address list. */
+				map = pci_map_single(qdev->pdev, oal,
+						     sizeof(struct oal),
+						     PCI_DMA_TODEVICE);
+				oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
+				oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
+				oal_entry->len =
+				    cpu_to_le32(sizeof(struct oal) |
+						OAL_CONT_ENTRY);
+				pci_unmap_addr_set(&tx_cb->map[seg], mapaddr,
+						   map);
+				pci_unmap_len_set(&tx_cb->map[seg], maplen,
+						  len);
+				oal_entry = (struct oal_entry *)oal;
+				oal++;
+				seg++;
+			}
+
+			map =
+			    pci_map_page(qdev->pdev, frag->page,
+					 frag->page_offset, frag->size,
+					 PCI_DMA_TODEVICE);
+			oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
+			oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
+			oal_entry->len = cpu_to_le32(frag->size);
+			pci_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
+			pci_unmap_len_set(&tx_cb->map[seg], maplen,
+					  frag->size);
+		}
+		/* Terminate the last segment. */
+		oal_entry->len =
+		    cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY);
+	}
+	wmb();
 	qdev->req_producer_index++;
 	if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES)
 		qdev->req_producer_index = 0;
@@ -2074,8 +2267,10 @@
 		printk(KERN_DEBUG PFX "%s: tx queued, slot %d, len %d\n",
 		       ndev->name, qdev->req_producer_index, skb->len);
 
+	atomic_dec(&qdev->tx_count);
 	return NETDEV_TX_OK;
 }
+
 static int ql_alloc_net_req_rsp_queues(struct ql3_adapter *qdev)
 {
 	qdev->req_q_size =
@@ -2359,7 +2554,22 @@
 	return 0;
 }
 
-static void ql_create_send_free_list(struct ql3_adapter *qdev)
+static void ql_free_send_free_list(struct ql3_adapter *qdev)
+{
+	struct ql_tx_buf_cb *tx_cb;
+	int i;
+
+	tx_cb = &qdev->tx_buf[0];
+	for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+		if (tx_cb->oal) {
+			kfree(tx_cb->oal);
+			tx_cb->oal = NULL;
+		}
+		tx_cb++;
+	}
+}
+
+static int ql_create_send_free_list(struct ql3_adapter *qdev)
 {
 	struct ql_tx_buf_cb *tx_cb;
 	int i;
@@ -2368,11 +2578,16 @@
 
 	/* Create free list of transmit buffers */
 	for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+
 		tx_cb = &qdev->tx_buf[i];
 		tx_cb->skb = NULL;
 		tx_cb->queue_entry = req_q_curr;
 		req_q_curr++;
+		tx_cb->oal = kmalloc(512, GFP_KERNEL);
+		if (tx_cb->oal == NULL)
+			return -1;
 	}
+	return 0;
 }
 
 static int ql_alloc_mem_resources(struct ql3_adapter *qdev)
@@ -2447,12 +2662,14 @@
 
 	/* Initialize the large buffer queue. */
 	ql_init_large_buffers(qdev);
-	ql_create_send_free_list(qdev);
+	if (ql_create_send_free_list(qdev))
+		goto err_free_list;
 
 	qdev->rsp_current = qdev->rsp_q_virt_addr;
 
 	return 0;
-
+err_free_list:
+	ql_free_send_free_list(qdev);
 err_small_buffers:
 	ql_free_buffer_queues(qdev);
 err_buffer_queues:
@@ -2468,6 +2685,7 @@
 
 static void ql_free_mem_resources(struct ql3_adapter *qdev)
 {
+	ql_free_send_free_list(qdev);
 	ql_free_large_buffers(qdev);
 	ql_free_small_buffers(qdev);
 	ql_free_buffer_queues(qdev);
@@ -2766,11 +2984,20 @@
 	}
 
 	/* Enable Ethernet Function */
-	value =
-	    (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI |
-	     PORT_CONTROL_HH);
-	ql_write_page0_reg(qdev, &port_regs->portControl,
-			   ((value << 16) | value));
+	if (qdev->device_id == QL3032_DEVICE_ID) {
+		value =
+		    (QL3032_PORT_CONTROL_EF | QL3032_PORT_CONTROL_KIE |
+		     QL3032_PORT_CONTROL_EIv6 | QL3032_PORT_CONTROL_EIv4);
+		ql_write_page0_reg(qdev, &port_regs->functionControl,
+				   ((value << 16) | value));
+	} else {
+		value =
+		    (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI |
+		     PORT_CONTROL_HH);
+		ql_write_page0_reg(qdev, &port_regs->portControl,
+				   ((value << 16) | value));
+	}
+
 
 out:
 	return status;
@@ -2917,8 +3144,10 @@
 	struct pci_dev *pdev = qdev->pdev;
 
 	printk(KERN_INFO PFX
-	       "\n%s Adapter %d RevisionID %d found on PCI slot %d.\n",
-	       DRV_NAME, qdev->index, qdev->chip_rev_id, qdev->pci_slot);
+	       "\n%s Adapter %d RevisionID %d found %s on PCI slot %d.\n",
+	       DRV_NAME, qdev->index, qdev->chip_rev_id,
+	       (qdev->device_id == QL3032_DEVICE_ID) ? "QLA3032" : "QLA3022",
+	       qdev->pci_slot);
 	printk(KERN_INFO PFX
 	       "%s Interface.\n",
 	       test_bit(QL_LINK_OPTICAL,&qdev->flags) ? "OPTICAL" : "COPPER");
@@ -3212,15 +3441,22 @@
 		 * Loop through the active list and return the skb.
 		 */
 		for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+			int j;
 			tx_cb = &qdev->tx_buf[i];
 			if (tx_cb->skb) {
-
 				printk(KERN_DEBUG PFX
 				       "%s: Freeing lost SKB.\n",
 				       qdev->ndev->name);
 				pci_unmap_single(qdev->pdev,
-					pci_unmap_addr(tx_cb, mapaddr),
-					pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE);
+					 pci_unmap_addr(&tx_cb->map[0], mapaddr),
+					 pci_unmap_len(&tx_cb->map[0], maplen),
+					 PCI_DMA_TODEVICE);
+				for(j=1;j<tx_cb->seg_count;j++) {
+					pci_unmap_page(qdev->pdev,
+					       pci_unmap_addr(&tx_cb->map[j],mapaddr),
+					       pci_unmap_len(&tx_cb->map[j],maplen),
+					       PCI_DMA_TODEVICE);
+				}
 				dev_kfree_skb(tx_cb->skb);
 				tx_cb->skb = NULL;
 			}
@@ -3379,21 +3615,24 @@
 	SET_MODULE_OWNER(ndev);
 	SET_NETDEV_DEV(ndev, &pdev->dev);
 
-	if (pci_using_dac)
-		ndev->features |= NETIF_F_HIGHDMA;
-
 	pci_set_drvdata(pdev, ndev);
 
 	qdev = netdev_priv(ndev);
 	qdev->index = cards_found;
 	qdev->ndev = ndev;
 	qdev->pdev = pdev;
+	qdev->device_id = pci_entry->device;
 	qdev->port_link_state = LS_DOWN;
 	if (msi)
 		qdev->msi = 1;
 
 	qdev->msg_enable = netif_msg_init(debug, default_msg);
 
+	if (pci_using_dac)
+		ndev->features |= NETIF_F_HIGHDMA;
+	if (qdev->device_id == QL3032_DEVICE_ID)
+		ndev->features |= (NETIF_F_HW_CSUM | NETIF_F_SG);
+
 	qdev->mem_map_registers =
 	    ioremap_nocache(pci_resource_start(pdev, 1),
 			    pci_resource_len(qdev->pdev, 1));
diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h
old mode 100644
new mode 100755
index ea94de7..b2d76ea
--- a/drivers/net/qla3xxx.h
+++ b/drivers/net/qla3xxx.h
@@ -21,7 +21,9 @@
 
 #define OPCODE_UPDATE_NCB_IOCB      0xF0
 #define OPCODE_IB_MAC_IOCB          0xF9
+#define OPCODE_IB_3032_MAC_IOCB     0x09
 #define OPCODE_IB_IP_IOCB           0xFA
+#define OPCODE_IB_3032_IP_IOCB      0x0A
 #define OPCODE_IB_TCP_IOCB          0xFB
 #define OPCODE_DUMP_PROTO_IOCB      0xFE
 #define OPCODE_BUFFER_ALERT_IOCB    0xFB
@@ -37,18 +39,23 @@
 struct ob_mac_iocb_req {
 	u8 opcode;
 	u8 flags;
-#define OB_MAC_IOCB_REQ_MA  0xC0
-#define OB_MAC_IOCB_REQ_F   0x20
-#define OB_MAC_IOCB_REQ_X   0x10
+#define OB_MAC_IOCB_REQ_MA  0xe0
+#define OB_MAC_IOCB_REQ_F   0x10
+#define OB_MAC_IOCB_REQ_X   0x08
 #define OB_MAC_IOCB_REQ_D   0x02
 #define OB_MAC_IOCB_REQ_I   0x01
-	__le16 reserved0;
+	u8 flags1;
+#define OB_3032MAC_IOCB_REQ_IC	0x04
+#define OB_3032MAC_IOCB_REQ_TC	0x02
+#define OB_3032MAC_IOCB_REQ_UC	0x01
+	u8 reserved0;
 
 	__le32 transaction_id;
 	__le16 data_len;
-	__le16 reserved1;
+	u8 ip_hdr_off;
+	u8 ip_hdr_len;
+	__le32 reserved1;
 	__le32 reserved2;
-	__le32 reserved3;
 	__le32 buf_addr0_low;
 	__le32 buf_addr0_high;
 	__le32 buf_0_len;
@@ -58,8 +65,8 @@
 	__le32 buf_addr2_low;
 	__le32 buf_addr2_high;
 	__le32 buf_2_len;
+	__le32 reserved3;
 	__le32 reserved4;
-	__le32 reserved5;
 };
 /*
  * The following constants define control bits for buffer
@@ -74,6 +81,7 @@
 	u8 opcode;
 	u8 flags;
 #define OB_MAC_IOCB_RSP_P   0x08
+#define OB_MAC_IOCB_RSP_L   0x04
 #define OB_MAC_IOCB_RSP_S   0x02
 #define OB_MAC_IOCB_RSP_I   0x01
 
@@ -85,6 +93,7 @@
 
 struct ib_mac_iocb_rsp {
 	u8 opcode;
+#define IB_MAC_IOCB_RSP_V   0x80
 	u8 flags;
 #define IB_MAC_IOCB_RSP_S   0x80
 #define IB_MAC_IOCB_RSP_H1  0x40
@@ -138,6 +147,7 @@
 struct ob_ip_iocb_rsp {
 	u8 opcode;
 	u8 flags;
+#define OB_MAC_IOCB_RSP_H       0x10
 #define OB_MAC_IOCB_RSP_E       0x08
 #define OB_MAC_IOCB_RSP_L       0x04
 #define OB_MAC_IOCB_RSP_S       0x02
@@ -220,6 +230,10 @@
 
 struct ib_ip_iocb_rsp {
 	u8 opcode;
+#define IB_IP_IOCB_RSP_3032_V   0x80
+#define IB_IP_IOCB_RSP_3032_O   0x40
+#define IB_IP_IOCB_RSP_3032_I   0x20
+#define IB_IP_IOCB_RSP_3032_R   0x10
 	u8 flags;
 #define IB_IP_IOCB_RSP_S        0x80
 #define IB_IP_IOCB_RSP_H1       0x40
@@ -230,6 +244,12 @@
 
 	__le16 length;
 	__le16 checksum;
+#define IB_IP_IOCB_RSP_3032_ICE		0x01
+#define IB_IP_IOCB_RSP_3032_CE		0x02
+#define IB_IP_IOCB_RSP_3032_NUC		0x04
+#define IB_IP_IOCB_RSP_3032_UDP		0x08
+#define IB_IP_IOCB_RSP_3032_TCP		0x10
+#define IB_IP_IOCB_RSP_3032_IPE		0x20
 	__le16 reserved;
 #define IB_IP_IOCB_RSP_R        0x01
 	__le32 ial_low;
@@ -524,6 +544,21 @@
 	IP_ADDR_INDEX_REG_FUNC_2_SEC = 0x0005,
 	IP_ADDR_INDEX_REG_FUNC_3_PRI = 0x0006,
 	IP_ADDR_INDEX_REG_FUNC_3_SEC = 0x0007,
+	IP_ADDR_INDEX_REG_6 = 0x0008,
+	IP_ADDR_INDEX_REG_OFFSET_MASK = 0x0030,
+	IP_ADDR_INDEX_REG_E = 0x0040, 
+};
+enum {
+	QL3032_PORT_CONTROL_DS = 0x0001,
+	QL3032_PORT_CONTROL_HH = 0x0002,
+	QL3032_PORT_CONTROL_EIv6 = 0x0004,
+	QL3032_PORT_CONTROL_EIv4 = 0x0008,
+	QL3032_PORT_CONTROL_ET = 0x0010,
+	QL3032_PORT_CONTROL_EF = 0x0020,
+	QL3032_PORT_CONTROL_DRM = 0x0040,
+	QL3032_PORT_CONTROL_RLB = 0x0080,
+	QL3032_PORT_CONTROL_RCB = 0x0100,
+	QL3032_PORT_CONTROL_KIE = 0x0200,
 };
 
 enum {
@@ -657,7 +692,8 @@
 	u32 internalRamWDataReg;
 	u32 reclaimedBufferAddrRegLow;
 	u32 reclaimedBufferAddrRegHigh;
-	u32 reserved[2];
+	u32 tcpConfiguration;
+	u32 functionControl;
 	u32 fpgaRevID;
 	u32 localRamAddr;
 	u32 localRamDataAutoIncr;
@@ -963,6 +999,7 @@
 
 #define QL3XXX_VENDOR_ID    0x1077
 #define QL3022_DEVICE_ID    0x3022
+#define QL3032_DEVICE_ID    0x3032
 
 /* MTU & Frame Size stuff */
 #define NORMAL_MTU_SIZE 		ETH_DATA_LEN
@@ -1038,11 +1075,41 @@
 	int index;
 };
 
+/*
+ * Original IOCB has 3 sg entries:
+ * first points to skb-data area
+ * second points to first frag
+ * third points to next oal.
+ * OAL has 5 entries:
+ * 1 thru 4 point to frags
+ * fifth points to next oal.
+ */ 
+#define MAX_OAL_CNT ((MAX_SKB_FRAGS-1)/4 + 1)
+
+struct oal_entry {
+	u32 dma_lo;
+	u32 dma_hi;
+	u32 len;
+#define OAL_LAST_ENTRY   0x80000000	/* Last valid buffer in list. */
+#define OAL_CONT_ENTRY   0x40000000	/* points to an OAL. (continuation) */
+	u32 reserved;
+};
+
+struct oal {
+	struct oal_entry oal_entry[5];
+};
+
+struct map_list {
+	 DECLARE_PCI_UNMAP_ADDR(mapaddr);
+	 DECLARE_PCI_UNMAP_LEN(maplen);
+};
+
 struct ql_tx_buf_cb {
 	struct sk_buff *skb;
 	struct ob_mac_iocb_req *queue_entry ;
-	 DECLARE_PCI_UNMAP_ADDR(mapaddr);
-	 DECLARE_PCI_UNMAP_LEN(maplen);
+	int seg_count;
+	struct oal *oal;
+	struct map_list map[MAX_SKB_FRAGS+1]; 
 };
 
 /* definitions for type field */
@@ -1189,6 +1256,7 @@
 	struct delayed_work reset_work;
 	struct delayed_work tx_timeout_work;
 	u32 max_frame_size;
+	u32 device_id;
 };
 
 #endif				/* _QLA3XXX_H_ */
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 577babd..5598d86 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -2016,7 +2016,7 @@
 	if (!skb)
 		goto err_out;
 
-	skb_reserve(skb, (align - 1) & (u32)skb->data);
+	skb_reserve(skb, (align - 1) & (unsigned long)skb->data);
 	*sk_buff = skb;
 
 	mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
@@ -2487,7 +2487,7 @@
 
 		skb = dev_alloc_skb(pkt_size + align);
 		if (skb) {
-			skb_reserve(skb, (align - 1) & (u32)skb->data);
+			skb_reserve(skb, (align - 1) & (unsigned long)skb->data);
 			eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0);
 			*sk_buff = skb;
 			rtl8169_mark_to_asic(desc, rx_buf_sz);
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index a914fef..0e345cb 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -15,7 +15,7 @@
 
 #define TBD 0
 
-typedef struct _XENA_dev_config {
+struct XENA_dev_config {
 /* Convention: mHAL_XXX is mask, vHAL_XXX is value */
 
 /* General Control-Status Registers */
@@ -300,6 +300,7 @@
 	u64 gpio_control;
 #define GPIO_CTRL_GPIO_0		BIT(8)
 	u64 misc_control;
+#define FAULT_BEHAVIOUR			BIT(0)
 #define EXT_REQ_EN			BIT(1)
 #define MISC_LINK_STABILITY_PRD(val)   vBIT(val,29,3)
 
@@ -851,9 +852,9 @@
 #define SPI_CONTROL_DONE		BIT(6)
 	u64 spi_data;
 #define SPI_DATA_WRITE(data,len)	vBIT(data,0,len)
-} XENA_dev_config_t;
+};
 
-#define XENA_REG_SPACE	sizeof(XENA_dev_config_t)
+#define XENA_REG_SPACE	sizeof(struct XENA_dev_config)
 #define	XENA_EEPROM_SPACE (0x01 << 11)
 
 #endif				/* _REGS_H */
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 1dd66b8..8646b64 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -77,7 +77,7 @@
 #include "s2io.h"
 #include "s2io-regs.h"
 
-#define DRV_VERSION "2.0.15.2"
+#define DRV_VERSION "2.0.16.1"
 
 /* S2io Driver name & version. */
 static char s2io_driver_name[] = "Neterion";
@@ -86,7 +86,7 @@
 static int rxd_size[4] = {32,48,48,64};
 static int rxd_count[4] = {127,85,85,63};
 
-static inline int RXD_IS_UP2DT(RxD_t *rxdp)
+static inline int RXD_IS_UP2DT(struct RxD_t *rxdp)
 {
 	int ret;
 
@@ -111,9 +111,9 @@
 #define TASKLET_IN_USE test_and_set_bit(0, (&sp->tasklet_status))
 #define PANIC	1
 #define LOW	2
-static inline int rx_buffer_level(nic_t * sp, int rxb_size, int ring)
+static inline int rx_buffer_level(struct s2io_nic * sp, int rxb_size, int ring)
 {
-	mac_info_t *mac_control;
+	struct mac_info *mac_control;
 
 	mac_control = &sp->mac_control;
 	if (rxb_size <= rxd_count[sp->rxd_mode])
@@ -286,7 +286,7 @@
 static void s2io_vlan_rx_register(struct net_device *dev,
 					struct vlan_group *grp)
 {
-	nic_t *nic = dev->priv;
+	struct s2io_nic *nic = dev->priv;
 	unsigned long flags;
 
 	spin_lock_irqsave(&nic->tx_lock, flags);
@@ -297,7 +297,7 @@
 /* Unregister the vlan */
 static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
 {
-	nic_t *nic = dev->priv;
+	struct s2io_nic *nic = dev->priv;
 	unsigned long flags;
 
 	spin_lock_irqsave(&nic->tx_lock, flags);
@@ -401,9 +401,10 @@
  * aggregation happens until we hit max IP pkt size(64K)
  */
 S2IO_PARM_INT(lro_max_pkts, 0xFFFF);
-#ifndef CONFIG_S2IO_NAPI
 S2IO_PARM_INT(indicate_max_pkts, 0);
-#endif
+
+S2IO_PARM_INT(napi, 1);
+S2IO_PARM_INT(ufo, 0);
 
 static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
     {DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN};
@@ -457,14 +458,14 @@
 	u32 size;
 	void *tmp_v_addr, *tmp_v_addr_next;
 	dma_addr_t tmp_p_addr, tmp_p_addr_next;
-	RxD_block_t *pre_rxd_blk = NULL;
-	int i, j, blk_cnt, rx_sz, tx_sz;
+	struct RxD_block *pre_rxd_blk = NULL;
+	int i, j, blk_cnt;
 	int lst_size, lst_per_page;
 	struct net_device *dev = nic->dev;
 	unsigned long tmp;
-	buffAdd_t *ba;
+	struct buffAdd *ba;
 
-	mac_info_t *mac_control;
+	struct mac_info *mac_control;
 	struct config_param *config;
 
 	mac_control = &nic->mac_control;
@@ -482,13 +483,12 @@
 		return -EINVAL;
 	}
 
-	lst_size = (sizeof(TxD_t) * config->max_txds);
-	tx_sz = lst_size * size;
+	lst_size = (sizeof(struct TxD) * config->max_txds);
 	lst_per_page = PAGE_SIZE / lst_size;
 
 	for (i = 0; i < config->tx_fifo_num; i++) {
 		int fifo_len = config->tx_cfg[i].fifo_len;
-		int list_holder_size = fifo_len * sizeof(list_info_hold_t);
+		int list_holder_size = fifo_len * sizeof(struct list_info_hold);
 		mac_control->fifos[i].list_info = kmalloc(list_holder_size,
 							  GFP_KERNEL);
 		if (!mac_control->fifos[i].list_info) {
@@ -579,10 +579,9 @@
 			mac_control->rings[i].block_count;
 	}
 	if (nic->rxd_mode == RXD_MODE_1)
-		size = (size * (sizeof(RxD1_t)));
+		size = (size * (sizeof(struct RxD1)));
 	else
-		size = (size * (sizeof(RxD3_t)));
-	rx_sz = size;
+		size = (size * (sizeof(struct RxD3)));
 
 	for (i = 0; i < config->rx_ring_num; i++) {
 		mac_control->rings[i].rx_curr_get_info.block_index = 0;
@@ -600,7 +599,7 @@
 				(rxd_count[nic->rxd_mode] + 1);
 		/*  Allocating all the Rx blocks */
 		for (j = 0; j < blk_cnt; j++) {
-			rx_block_info_t *rx_blocks;
+			struct rx_block_info *rx_blocks;
 			int l;
 
 			rx_blocks = &mac_control->rings[i].rx_blocks[j];
@@ -620,9 +619,11 @@
 			memset(tmp_v_addr, 0, size);
 			rx_blocks->block_virt_addr = tmp_v_addr;
 			rx_blocks->block_dma_addr = tmp_p_addr;
-			rx_blocks->rxds = kmalloc(sizeof(rxd_info_t)*
+			rx_blocks->rxds = kmalloc(sizeof(struct rxd_info)*
 						  rxd_count[nic->rxd_mode],
 						  GFP_KERNEL);
+			if (!rx_blocks->rxds)
+				return -ENOMEM;
 			for (l=0; l<rxd_count[nic->rxd_mode];l++) {
 				rx_blocks->rxds[l].virt_addr =
 					rx_blocks->block_virt_addr +
@@ -645,7 +646,7 @@
 				mac_control->rings[i].rx_blocks[(j + 1) %
 					      blk_cnt].block_dma_addr;
 
-			pre_rxd_blk = (RxD_block_t *) tmp_v_addr;
+			pre_rxd_blk = (struct RxD_block *) tmp_v_addr;
 			pre_rxd_blk->reserved_2_pNext_RxD_block =
 			    (unsigned long) tmp_v_addr_next;
 			pre_rxd_blk->pNext_RxD_Blk_physical =
@@ -661,14 +662,14 @@
 			blk_cnt = config->rx_cfg[i].num_rxd /
 			   (rxd_count[nic->rxd_mode]+ 1);
 			mac_control->rings[i].ba =
-				kmalloc((sizeof(buffAdd_t *) * blk_cnt),
+				kmalloc((sizeof(struct buffAdd *) * blk_cnt),
 				     GFP_KERNEL);
 			if (!mac_control->rings[i].ba)
 				return -ENOMEM;
 			for (j = 0; j < blk_cnt; j++) {
 				int k = 0;
 				mac_control->rings[i].ba[j] =
-					kmalloc((sizeof(buffAdd_t) *
+					kmalloc((sizeof(struct buffAdd) *
 						(rxd_count[nic->rxd_mode] + 1)),
 						GFP_KERNEL);
 				if (!mac_control->rings[i].ba[j])
@@ -700,7 +701,7 @@
 	}
 
 	/* Allocation and initialization of Statistics block */
-	size = sizeof(StatInfo_t);
+	size = sizeof(struct stat_block);
 	mac_control->stats_mem = pci_alloc_consistent
 	    (nic->pdev, size, &mac_control->stats_mem_phy);
 
@@ -715,7 +716,7 @@
 	mac_control->stats_mem_sz = size;
 
 	tmp_v_addr = mac_control->stats_mem;
-	mac_control->stats_info = (StatInfo_t *) tmp_v_addr;
+	mac_control->stats_info = (struct stat_block *) tmp_v_addr;
 	memset(tmp_v_addr, 0, size);
 	DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name,
 		  (unsigned long long) tmp_p_addr);
@@ -735,7 +736,7 @@
 	int i, j, blk_cnt, size;
 	void *tmp_v_addr;
 	dma_addr_t tmp_p_addr;
-	mac_info_t *mac_control;
+	struct mac_info *mac_control;
 	struct config_param *config;
 	int lst_size, lst_per_page;
 	struct net_device *dev = nic->dev;
@@ -746,7 +747,7 @@
 	mac_control = &nic->mac_control;
 	config = &nic->config;
 
-	lst_size = (sizeof(TxD_t) * config->max_txds);
+	lst_size = (sizeof(struct TxD) * config->max_txds);
 	lst_per_page = PAGE_SIZE / lst_size;
 
 	for (i = 0; i < config->tx_fifo_num; i++) {
@@ -809,7 +810,7 @@
 				if (!mac_control->rings[i].ba[j])
 					continue;
 				while (k != rxd_count[nic->rxd_mode]) {
-					buffAdd_t *ba =
+					struct buffAdd *ba =
 						&mac_control->rings[i].ba[j][k];
 					kfree(ba->ba_0_org);
 					kfree(ba->ba_1_org);
@@ -835,9 +836,9 @@
  * s2io_verify_pci_mode -
  */
 
-static int s2io_verify_pci_mode(nic_t *nic)
+static int s2io_verify_pci_mode(struct s2io_nic *nic)
 {
-	XENA_dev_config_t __iomem *bar0 = nic->bar0;
+	struct XENA_dev_config __iomem *bar0 = nic->bar0;
 	register u64 val64 = 0;
 	int     mode;
 
@@ -868,9 +869,9 @@
 /**
  * s2io_print_pci_mode -
  */
-static int s2io_print_pci_mode(nic_t *nic)
+static int s2io_print_pci_mode(struct s2io_nic *nic)
 {
-	XENA_dev_config_t __iomem *bar0 = nic->bar0;
+	struct XENA_dev_config __iomem *bar0 = nic->bar0;
 	register u64 val64 = 0;
 	int	mode;
 	struct config_param *config = &nic->config;
@@ -938,13 +939,13 @@
 
 static int init_nic(struct s2io_nic *nic)
 {
-	XENA_dev_config_t __iomem *bar0 = nic->bar0;
+	struct XENA_dev_config __iomem *bar0 = nic->bar0;
 	struct net_device *dev = nic->dev;
 	register u64 val64 = 0;
 	void __iomem *add;
 	u32 time;
 	int i, j;
-	mac_info_t *mac_control;
+	struct mac_info *mac_control;
 	struct config_param *config;
 	int dtx_cnt = 0;
 	unsigned long long mem_share;
@@ -1414,7 +1415,7 @@
 
 	val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
 	    TTI_DATA2_MEM_TX_UFC_B(0x20) |
-	    TTI_DATA2_MEM_TX_UFC_C(0x70) | TTI_DATA2_MEM_TX_UFC_D(0x80);
+	    TTI_DATA2_MEM_TX_UFC_C(0x40) | TTI_DATA2_MEM_TX_UFC_D(0x80);
 	writeq(val64, &bar0->tti_data2_mem);
 
 	val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
@@ -1610,7 +1611,8 @@
 	 * that does not start on an ADB to reduce disconnects.
 	 */
 	if (nic->device_type == XFRAME_II_DEVICE) {
-		val64 = EXT_REQ_EN | MISC_LINK_STABILITY_PRD(3);
+		val64 = FAULT_BEHAVIOUR | EXT_REQ_EN |
+			MISC_LINK_STABILITY_PRD(3);
 		writeq(val64, &bar0->misc_control);
 		val64 = readq(&bar0->pic_control2);
 		val64 &= ~(BIT(13)|BIT(14)|BIT(15));
@@ -1626,7 +1628,7 @@
 #define LINK_UP_DOWN_INTERRUPT		1
 #define MAC_RMAC_ERR_TIMER		2
 
-static int s2io_link_fault_indication(nic_t *nic)
+static int s2io_link_fault_indication(struct s2io_nic *nic)
 {
 	if (nic->intr_type != INTA)
 		return MAC_RMAC_ERR_TIMER;
@@ -1649,14 +1651,14 @@
 
 static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
 {
-	XENA_dev_config_t __iomem *bar0 = nic->bar0;
+	struct XENA_dev_config __iomem *bar0 = nic->bar0;
 	register u64 val64 = 0, temp64 = 0;
 
 	/*  Top level interrupt classification */
 	/*  PIC Interrupts */
 	if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) {
 		/*  Enable PIC Intrs in the general intr mask register */
-		val64 = TXPIC_INT_M | PIC_RX_INT_M;
+		val64 = TXPIC_INT_M;
 		if (flag == ENABLE_INTRS) {
 			temp64 = readq(&bar0->general_int_mask);
 			temp64 &= ~((u64) val64);
@@ -1694,70 +1696,6 @@
 		}
 	}
 
-	/*  DMA Interrupts */
-	/*  Enabling/Disabling Tx DMA interrupts */
-	if (mask & TX_DMA_INTR) {
-		/* Enable TxDMA Intrs in the general intr mask register */
-		val64 = TXDMA_INT_M;
-		if (flag == ENABLE_INTRS) {
-			temp64 = readq(&bar0->general_int_mask);
-			temp64 &= ~((u64) val64);
-			writeq(temp64, &bar0->general_int_mask);
-			/*
-			 * Keep all interrupts other than PFC interrupt
-			 * and PCC interrupt disabled in DMA level.
-			 */
-			val64 = DISABLE_ALL_INTRS & ~(TXDMA_PFC_INT_M |
-						      TXDMA_PCC_INT_M);
-			writeq(val64, &bar0->txdma_int_mask);
-			/*
-			 * Enable only the MISC error 1 interrupt in PFC block
-			 */
-			val64 = DISABLE_ALL_INTRS & (~PFC_MISC_ERR_1);
-			writeq(val64, &bar0->pfc_err_mask);
-			/*
-			 * Enable only the FB_ECC error interrupt in PCC block
-			 */
-			val64 = DISABLE_ALL_INTRS & (~PCC_FB_ECC_ERR);
-			writeq(val64, &bar0->pcc_err_mask);
-		} else if (flag == DISABLE_INTRS) {
-			/*
-			 * Disable TxDMA Intrs in the general intr mask
-			 * register
-			 */
-			writeq(DISABLE_ALL_INTRS, &bar0->txdma_int_mask);
-			writeq(DISABLE_ALL_INTRS, &bar0->pfc_err_mask);
-			temp64 = readq(&bar0->general_int_mask);
-			val64 |= temp64;
-			writeq(val64, &bar0->general_int_mask);
-		}
-	}
-
-	/*  Enabling/Disabling Rx DMA interrupts */
-	if (mask & RX_DMA_INTR) {
-		/*  Enable RxDMA Intrs in the general intr mask register */
-		val64 = RXDMA_INT_M;
-		if (flag == ENABLE_INTRS) {
-			temp64 = readq(&bar0->general_int_mask);
-			temp64 &= ~((u64) val64);
-			writeq(temp64, &bar0->general_int_mask);
-			/*
-			 * All RxDMA block interrupts are disabled for now
-			 * TODO
-			 */
-			writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
-		} else if (flag == DISABLE_INTRS) {
-			/*
-			 * Disable RxDMA Intrs in the general intr mask
-			 * register
-			 */
-			writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
-			temp64 = readq(&bar0->general_int_mask);
-			val64 |= temp64;
-			writeq(val64, &bar0->general_int_mask);
-		}
-	}
-
 	/*  MAC Interrupts */
 	/*  Enabling/Disabling MAC interrupts */
 	if (mask & (TX_MAC_INTR | RX_MAC_INTR)) {
@@ -1784,53 +1722,6 @@
 		}
 	}
 
-	/*  XGXS Interrupts */
-	if (mask & (TX_XGXS_INTR | RX_XGXS_INTR)) {
-		val64 = TXXGXS_INT_M | RXXGXS_INT_M;
-		if (flag == ENABLE_INTRS) {
-			temp64 = readq(&bar0->general_int_mask);
-			temp64 &= ~((u64) val64);
-			writeq(temp64, &bar0->general_int_mask);
-			/*
-			 * All XGXS block error interrupts are disabled for now
-			 * TODO
-			 */
-			writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
-		} else if (flag == DISABLE_INTRS) {
-			/*
-			 * Disable MC Intrs in the general intr mask register
-			 */
-			writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
-			temp64 = readq(&bar0->general_int_mask);
-			val64 |= temp64;
-			writeq(val64, &bar0->general_int_mask);
-		}
-	}
-
-	/*  Memory Controller(MC) interrupts */
-	if (mask & MC_INTR) {
-		val64 = MC_INT_M;
-		if (flag == ENABLE_INTRS) {
-			temp64 = readq(&bar0->general_int_mask);
-			temp64 &= ~((u64) val64);
-			writeq(temp64, &bar0->general_int_mask);
-			/*
-			 * Enable all MC Intrs.
-			 */
-			writeq(0x0, &bar0->mc_int_mask);
-			writeq(0x0, &bar0->mc_err_mask);
-		} else if (flag == DISABLE_INTRS) {
-			/*
-			 * Disable MC Intrs in the general intr mask register
-			 */
-			writeq(DISABLE_ALL_INTRS, &bar0->mc_int_mask);
-			temp64 = readq(&bar0->general_int_mask);
-			val64 |= temp64;
-			writeq(val64, &bar0->general_int_mask);
-		}
-	}
-
-
 	/*  Tx traffic interrupts */
 	if (mask & TX_TRAFFIC_INTR) {
 		val64 = TXTRAFFIC_INT_M;
@@ -1877,41 +1768,36 @@
 	}
 }
 
-static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc)
+/**
+ *  verify_pcc_quiescent- Checks for PCC quiescent state
+ *  Return: 1 If PCC is quiescence
+ *          0 If PCC is not quiescence
+ */
+static int verify_pcc_quiescent(struct s2io_nic *sp, int flag)
 {
-	int ret = 0;
+	int ret = 0, herc;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
+	u64 val64 = readq(&bar0->adapter_status);
+	
+	herc = (sp->device_type == XFRAME_II_DEVICE);
 
 	if (flag == FALSE) {
-		if ((!herc && (rev_id >= 4)) || herc) {
-			if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) &&
-			    ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
-			     ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
+		if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) {
+			if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE))
 				ret = 1;
-			}
-		}else {
-			if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
-			    ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
-			     ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
+		} else {
+			if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
 				ret = 1;
-			}
 		}
 	} else {
-		if ((!herc && (rev_id >= 4)) || herc) {
+		if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) {
 			if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) ==
-			     ADAPTER_STATUS_RMAC_PCC_IDLE) &&
-			    (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
-			     ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
-			      ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
+			     ADAPTER_STATUS_RMAC_PCC_IDLE))
 				ret = 1;
-			}
 		} else {
 			if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) ==
-			     ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
-			    (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
-			     ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
-			      ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
+			     ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
 				ret = 1;
-			}
 		}
 	}
 
@@ -1919,9 +1805,6 @@
 }
 /**
  *  verify_xena_quiescence - Checks whether the H/W is ready
- *  @val64 :  Value read from adapter status register.
- *  @flag : indicates if the adapter enable bit was ever written once
- *  before.
  *  Description: Returns whether the H/W is ready to go or not. Depending
  *  on whether adapter enable bit was written or not the comparison
  *  differs and the calling function passes the input argument flag to
@@ -1930,24 +1813,63 @@
  *          0 If Xena is not quiescence
  */
 
-static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag)
+static int verify_xena_quiescence(struct s2io_nic *sp)
 {
-	int ret = 0, herc;
-	u64 tmp64 = ~((u64) val64);
-	int rev_id = get_xena_rev_id(sp->pdev);
+	int  mode;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
+	u64 val64 = readq(&bar0->adapter_status);
+	mode = s2io_verify_pci_mode(sp);
 
-	herc = (sp->device_type == XFRAME_II_DEVICE);
-	if (!
-	    (tmp64 &
-	     (ADAPTER_STATUS_TDMA_READY | ADAPTER_STATUS_RDMA_READY |
-	      ADAPTER_STATUS_PFC_READY | ADAPTER_STATUS_TMAC_BUF_EMPTY |
-	      ADAPTER_STATUS_PIC_QUIESCENT | ADAPTER_STATUS_MC_DRAM_READY |
-	      ADAPTER_STATUS_MC_QUEUES_READY | ADAPTER_STATUS_M_PLL_LOCK |
-	      ADAPTER_STATUS_P_PLL_LOCK))) {
-		ret = check_prc_pcc_state(val64, flag, rev_id, herc);
+	if (!(val64 & ADAPTER_STATUS_TDMA_READY)) {
+		DBG_PRINT(ERR_DBG, "%s", "TDMA is not ready!");
+		return 0;
+	}
+	if (!(val64 & ADAPTER_STATUS_RDMA_READY)) {
+	DBG_PRINT(ERR_DBG, "%s", "RDMA is not ready!");
+		return 0;
+	}
+	if (!(val64 & ADAPTER_STATUS_PFC_READY)) {
+		DBG_PRINT(ERR_DBG, "%s", "PFC is not ready!");
+		return 0;
+	}
+	if (!(val64 & ADAPTER_STATUS_TMAC_BUF_EMPTY)) {
+		DBG_PRINT(ERR_DBG, "%s", "TMAC BUF is not empty!");
+		return 0;
+	}
+	if (!(val64 & ADAPTER_STATUS_PIC_QUIESCENT)) {
+		DBG_PRINT(ERR_DBG, "%s", "PIC is not QUIESCENT!");
+		return 0;
+	}
+	if (!(val64 & ADAPTER_STATUS_MC_DRAM_READY)) {
+		DBG_PRINT(ERR_DBG, "%s", "MC_DRAM is not ready!");
+		return 0;
+	}
+	if (!(val64 & ADAPTER_STATUS_MC_QUEUES_READY)) {
+		DBG_PRINT(ERR_DBG, "%s", "MC_QUEUES is not ready!");
+		return 0;
+	}
+	if (!(val64 & ADAPTER_STATUS_M_PLL_LOCK)) {
+		DBG_PRINT(ERR_DBG, "%s", "M_PLL is not locked!");
+		return 0;
 	}
 
-	return ret;
+	/*
+	 * In PCI 33 mode, the P_PLL is not used, and therefore,
+	 * the the P_PLL_LOCK bit in the adapter_status register will
+	 * not be asserted.
+	 */
+	if (!(val64 & ADAPTER_STATUS_P_PLL_LOCK) &&
+		sp->device_type == XFRAME_II_DEVICE && mode !=
+		PCI_MODE_PCI_33) {
+		DBG_PRINT(ERR_DBG, "%s", "P_PLL is not locked!");
+		return 0;
+	}
+	if (!((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
+			ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
+		DBG_PRINT(ERR_DBG, "%s", "RC_PRC is not QUIESCENT!");
+		return 0;
+	}
+	return 1;
 }
 
 /**
@@ -1958,9 +1880,9 @@
  *
  */
 
-static void fix_mac_address(nic_t * sp)
+static void fix_mac_address(struct s2io_nic * sp)
 {
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	u64 val64;
 	int i = 0;
 
@@ -1986,11 +1908,11 @@
 
 static int start_nic(struct s2io_nic *nic)
 {
-	XENA_dev_config_t __iomem *bar0 = nic->bar0;
+	struct XENA_dev_config __iomem *bar0 = nic->bar0;
 	struct net_device *dev = nic->dev;
 	register u64 val64 = 0;
 	u16 subid, i;
-	mac_info_t *mac_control;
+	struct mac_info *mac_control;
 	struct config_param *config;
 
 	mac_control = &nic->mac_control;
@@ -2052,7 +1974,7 @@
 	 * it.
 	 */
 	val64 = readq(&bar0->adapter_status);
-	if (!verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
+	if (!verify_xena_quiescence(nic)) {
 		DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name);
 		DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n",
 			  (unsigned long long) val64);
@@ -2095,11 +2017,12 @@
 /**
  * s2io_txdl_getskb - Get the skb from txdl, unmap and return skb
  */
-static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, int get_off)
+static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \
+					TxD *txdlp, int get_off)
 {
-	nic_t *nic = fifo_data->nic;
+	struct s2io_nic *nic = fifo_data->nic;
 	struct sk_buff *skb;
-	TxD_t *txds;
+	struct TxD *txds;
 	u16 j, frg_cnt;
 
 	txds = txdlp;
@@ -2113,7 +2036,7 @@
 	skb = (struct sk_buff *) ((unsigned long)
 			txds->Host_Control);
 	if (!skb) {
-		memset(txdlp, 0, (sizeof(TxD_t) * fifo_data->max_txds));
+		memset(txdlp, 0, (sizeof(struct TxD) * fifo_data->max_txds));
 		return NULL;
 	}
 	pci_unmap_single(nic->pdev, (dma_addr_t)
@@ -2132,7 +2055,7 @@
 				       frag->size, PCI_DMA_TODEVICE);
 		}
 	}
-	memset(txdlp,0, (sizeof(TxD_t) * fifo_data->max_txds));
+	memset(txdlp,0, (sizeof(struct TxD) * fifo_data->max_txds));
 	return(skb);
 }
 
@@ -2148,9 +2071,9 @@
 {
 	struct net_device *dev = nic->dev;
 	struct sk_buff *skb;
-	TxD_t *txdp;
+	struct TxD *txdp;
 	int i, j;
-	mac_info_t *mac_control;
+	struct mac_info *mac_control;
 	struct config_param *config;
 	int cnt = 0;
 
@@ -2159,7 +2082,7 @@
 
 	for (i = 0; i < config->tx_fifo_num; i++) {
 		for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
-			txdp = (TxD_t *) mac_control->fifos[i].list_info[j].
+			txdp = (struct TxD *) mac_control->fifos[i].list_info[j].
 			    list_virt_addr;
 			skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
 			if (skb) {
@@ -2187,10 +2110,10 @@
 
 static void stop_nic(struct s2io_nic *nic)
 {
-	XENA_dev_config_t __iomem *bar0 = nic->bar0;
+	struct XENA_dev_config __iomem *bar0 = nic->bar0;
 	register u64 val64 = 0;
 	u16 interruptible;
-	mac_info_t *mac_control;
+	struct mac_info *mac_control;
 	struct config_param *config;
 
 	mac_control = &nic->mac_control;
@@ -2208,14 +2131,15 @@
 	writeq(val64, &bar0->adapter_control);
 }
 
-static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb)
+static int fill_rxd_3buf(struct s2io_nic *nic, struct RxD_t *rxdp, struct \
+				sk_buff *skb)
 {
 	struct net_device *dev = nic->dev;
 	struct sk_buff *frag_list;
 	void *tmp;
 
 	/* Buffer-1 receives L3/L4 headers */
-	((RxD3_t*)rxdp)->Buffer1_ptr = pci_map_single
+	((struct RxD3*)rxdp)->Buffer1_ptr = pci_map_single
 			(nic->pdev, skb->data, l3l4hdr_size + 4,
 			PCI_DMA_FROMDEVICE);
 
@@ -2226,13 +2150,14 @@
 		return -ENOMEM ;
 	}
 	frag_list = skb_shinfo(skb)->frag_list;
+	skb->truesize += frag_list->truesize;
 	frag_list->next = NULL;
 	tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1);
 	frag_list->data = tmp;
 	frag_list->tail = tmp;
 
 	/* Buffer-2 receives L4 data payload */
-	((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
+	((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
 				frag_list->data, dev->mtu,
 				PCI_DMA_FROMDEVICE);
 	rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
@@ -2266,18 +2191,16 @@
 {
 	struct net_device *dev = nic->dev;
 	struct sk_buff *skb;
-	RxD_t *rxdp;
+	struct RxD_t *rxdp;
 	int off, off1, size, block_no, block_no1;
 	u32 alloc_tab = 0;
 	u32 alloc_cnt;
-	mac_info_t *mac_control;
+	struct mac_info *mac_control;
 	struct config_param *config;
 	u64 tmp;
-	buffAdd_t *ba;
-#ifndef CONFIG_S2IO_NAPI
+	struct buffAdd *ba;
 	unsigned long flags;
-#endif
-	RxD_t *first_rxdp = NULL;
+	struct RxD_t *first_rxdp = NULL;
 
 	mac_control = &nic->mac_control;
 	config = &nic->config;
@@ -2320,12 +2243,15 @@
 			DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
 				  dev->name, rxdp);
 		}
-#ifndef CONFIG_S2IO_NAPI
-		spin_lock_irqsave(&nic->put_lock, flags);
-		mac_control->rings[ring_no].put_pos =
-		    (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
-		spin_unlock_irqrestore(&nic->put_lock, flags);
-#endif
+		if(!napi) {
+			spin_lock_irqsave(&nic->put_lock, flags);
+			mac_control->rings[ring_no].put_pos =
+			(block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
+			spin_unlock_irqrestore(&nic->put_lock, flags);
+		} else {
+			mac_control->rings[ring_no].put_pos =
+			(block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
+		}
 		if ((rxdp->Control_1 & RXD_OWN_XENA) &&
 			((nic->rxd_mode >= RXD_MODE_3A) &&
 				(rxdp->Control_2 & BIT(0)))) {
@@ -2356,9 +2282,9 @@
 		}
 		if (nic->rxd_mode == RXD_MODE_1) {
 			/* 1 buffer mode - normal operation mode */
-			memset(rxdp, 0, sizeof(RxD1_t));
+			memset(rxdp, 0, sizeof(struct RxD1));
 			skb_reserve(skb, NET_IP_ALIGN);
-			((RxD1_t*)rxdp)->Buffer0_ptr = pci_map_single
+			((struct RxD1*)rxdp)->Buffer0_ptr = pci_map_single
 			    (nic->pdev, skb->data, size - NET_IP_ALIGN,
 				PCI_DMA_FROMDEVICE);
 			rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
@@ -2375,7 +2301,7 @@
 			 * payload
 			 */
 
-			memset(rxdp, 0, sizeof(RxD3_t));
+			memset(rxdp, 0, sizeof(struct RxD3));
 			ba = &mac_control->rings[ring_no].ba[block_no][off];
 			skb_reserve(skb, BUF0_LEN);
 			tmp = (u64)(unsigned long) skb->data;
@@ -2384,13 +2310,13 @@
 			skb->data = (void *) (unsigned long)tmp;
 			skb->tail = (void *) (unsigned long)tmp;
 
-			if (!(((RxD3_t*)rxdp)->Buffer0_ptr))
-				((RxD3_t*)rxdp)->Buffer0_ptr =
+			if (!(((struct RxD3*)rxdp)->Buffer0_ptr))
+				((struct RxD3*)rxdp)->Buffer0_ptr =
 				   pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
 					   PCI_DMA_FROMDEVICE);
 			else
 				pci_dma_sync_single_for_device(nic->pdev,
-				    (dma_addr_t) ((RxD3_t*)rxdp)->Buffer0_ptr,
+				    (dma_addr_t) ((struct RxD3*)rxdp)->Buffer0_ptr,
 				    BUF0_LEN, PCI_DMA_FROMDEVICE);
 			rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
 			if (nic->rxd_mode == RXD_MODE_3B) {
@@ -2400,13 +2326,13 @@
 				 * Buffer2 will have L3/L4 header plus
 				 * L4 payload
 				 */
-				((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single
+				((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single
 				(nic->pdev, skb->data, dev->mtu + 4,
 						PCI_DMA_FROMDEVICE);
 
 				/* Buffer-1 will be dummy buffer. Not used */
-				if (!(((RxD3_t*)rxdp)->Buffer1_ptr)) {
-					((RxD3_t*)rxdp)->Buffer1_ptr =
+				if (!(((struct RxD3*)rxdp)->Buffer1_ptr)) {
+					((struct RxD3*)rxdp)->Buffer1_ptr =
 						pci_map_single(nic->pdev,
 						ba->ba_1, BUF1_LEN,
 						PCI_DMA_FROMDEVICE);
@@ -2466,9 +2392,9 @@
 	struct net_device *dev = sp->dev;
 	int j;
 	struct sk_buff *skb;
-	RxD_t *rxdp;
-	mac_info_t *mac_control;
-	buffAdd_t *ba;
+	struct RxD_t *rxdp;
+	struct mac_info *mac_control;
+	struct buffAdd *ba;
 
 	mac_control = &sp->mac_control;
 	for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) {
@@ -2481,41 +2407,41 @@
 		}
 		if (sp->rxd_mode == RXD_MODE_1) {
 			pci_unmap_single(sp->pdev, (dma_addr_t)
-				 ((RxD1_t*)rxdp)->Buffer0_ptr,
+				 ((struct RxD1*)rxdp)->Buffer0_ptr,
 				 dev->mtu +
 				 HEADER_ETHERNET_II_802_3_SIZE
 				 + HEADER_802_2_SIZE +
 				 HEADER_SNAP_SIZE,
 				 PCI_DMA_FROMDEVICE);
-			memset(rxdp, 0, sizeof(RxD1_t));
+			memset(rxdp, 0, sizeof(struct RxD1));
 		} else if(sp->rxd_mode == RXD_MODE_3B) {
 			ba = &mac_control->rings[ring_no].
 				ba[blk][j];
 			pci_unmap_single(sp->pdev, (dma_addr_t)
-				 ((RxD3_t*)rxdp)->Buffer0_ptr,
+				 ((struct RxD3*)rxdp)->Buffer0_ptr,
 				 BUF0_LEN,
 				 PCI_DMA_FROMDEVICE);
 			pci_unmap_single(sp->pdev, (dma_addr_t)
-				 ((RxD3_t*)rxdp)->Buffer1_ptr,
+				 ((struct RxD3*)rxdp)->Buffer1_ptr,
 				 BUF1_LEN,
 				 PCI_DMA_FROMDEVICE);
 			pci_unmap_single(sp->pdev, (dma_addr_t)
-				 ((RxD3_t*)rxdp)->Buffer2_ptr,
+				 ((struct RxD3*)rxdp)->Buffer2_ptr,
 				 dev->mtu + 4,
 				 PCI_DMA_FROMDEVICE);
-			memset(rxdp, 0, sizeof(RxD3_t));
+			memset(rxdp, 0, sizeof(struct RxD3));
 		} else {
 			pci_unmap_single(sp->pdev, (dma_addr_t)
-				((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
+				((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN,
 				PCI_DMA_FROMDEVICE);
 			pci_unmap_single(sp->pdev, (dma_addr_t)
-				((RxD3_t*)rxdp)->Buffer1_ptr,
+				((struct RxD3*)rxdp)->Buffer1_ptr,
 				l3l4hdr_size + 4,
 				PCI_DMA_FROMDEVICE);
 			pci_unmap_single(sp->pdev, (dma_addr_t)
-				((RxD3_t*)rxdp)->Buffer2_ptr, dev->mtu,
+				((struct RxD3*)rxdp)->Buffer2_ptr, dev->mtu,
 				PCI_DMA_FROMDEVICE);
-			memset(rxdp, 0, sizeof(RxD3_t));
+			memset(rxdp, 0, sizeof(struct RxD3));
 		}
 		dev_kfree_skb(skb);
 		atomic_dec(&sp->rx_bufs_left[ring_no]);
@@ -2535,7 +2461,7 @@
 {
 	struct net_device *dev = sp->dev;
 	int i, blk = 0, buf_cnt = 0;
-	mac_info_t *mac_control;
+	struct mac_info *mac_control;
 	struct config_param *config;
 
 	mac_control = &sp->mac_control;
@@ -2568,15 +2494,13 @@
  * 0 on success and 1 if there are No Rx packets to be processed.
  */
 
-#if defined(CONFIG_S2IO_NAPI)
 static int s2io_poll(struct net_device *dev, int *budget)
 {
-	nic_t *nic = dev->priv;
+	struct s2io_nic *nic = dev->priv;
 	int pkt_cnt = 0, org_pkts_to_process;
-	mac_info_t *mac_control;
+	struct mac_info *mac_control;
 	struct config_param *config;
-	XENA_dev_config_t __iomem *bar0 = nic->bar0;
-	u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
+	struct XENA_dev_config __iomem *bar0 = nic->bar0;
 	int i;
 
 	atomic_inc(&nic->isr_cnt);
@@ -2588,8 +2512,8 @@
 		nic->pkts_to_process = dev->quota;
 	org_pkts_to_process = nic->pkts_to_process;
 
-	writeq(val64, &bar0->rx_traffic_int);
-	val64 = readl(&bar0->rx_traffic_int);
+	writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+	readl(&bar0->rx_traffic_int);
 
 	for (i = 0; i < config->rx_ring_num; i++) {
 		rx_intr_handler(&mac_control->rings[i]);
@@ -2615,7 +2539,7 @@
 	}
 	/* Re enable the Rx interrupts. */
 	writeq(0x0, &bar0->rx_traffic_mask);
-	val64 = readl(&bar0->rx_traffic_mask);
+	readl(&bar0->rx_traffic_mask);
 	atomic_dec(&nic->isr_cnt);
 	return 0;
 
@@ -2633,7 +2557,6 @@
 	atomic_dec(&nic->isr_cnt);
 	return 1;
 }
-#endif
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /**
@@ -2647,10 +2570,10 @@
  */
 static void s2io_netpoll(struct net_device *dev)
 {
-	nic_t *nic = dev->priv;
-	mac_info_t *mac_control;
+	struct s2io_nic *nic = dev->priv;
+	struct mac_info *mac_control;
 	struct config_param *config;
-	XENA_dev_config_t __iomem *bar0 = nic->bar0;
+	struct XENA_dev_config __iomem *bar0 = nic->bar0;
 	u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
 	int i;
 
@@ -2699,17 +2622,15 @@
  *  Return Value:
  *  NONE.
  */
-static void rx_intr_handler(ring_info_t *ring_data)
+static void rx_intr_handler(struct ring_info *ring_data)
 {
-	nic_t *nic = ring_data->nic;
+	struct s2io_nic *nic = ring_data->nic;
 	struct net_device *dev = (struct net_device *) nic->dev;
 	int get_block, put_block, put_offset;
-	rx_curr_get_info_t get_info, put_info;
-	RxD_t *rxdp;
+	struct rx_curr_get_info get_info, put_info;
+	struct RxD_t *rxdp;
 	struct sk_buff *skb;
-#ifndef CONFIG_S2IO_NAPI
 	int pkt_cnt = 0;
-#endif
 	int i;
 
 	spin_lock(&nic->rx_lock);
@@ -2722,19 +2643,21 @@
 
 	get_info = ring_data->rx_curr_get_info;
 	get_block = get_info.block_index;
-	put_info = ring_data->rx_curr_put_info;
+	memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info));
 	put_block = put_info.block_index;
 	rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr;
-#ifndef CONFIG_S2IO_NAPI
-	spin_lock(&nic->put_lock);
-	put_offset = ring_data->put_pos;
-	spin_unlock(&nic->put_lock);
-#else
-	put_offset = (put_block * (rxd_count[nic->rxd_mode] + 1)) +
-		put_info.offset;
-#endif
+	if (!napi) {
+		spin_lock(&nic->put_lock);
+		put_offset = ring_data->put_pos;
+		spin_unlock(&nic->put_lock);
+	} else
+		put_offset = ring_data->put_pos;
+
 	while (RXD_IS_UP2DT(rxdp)) {
-		/* If your are next to put index then it's FIFO full condition */
+		/*
+		 * If your are next to put index then it's
+		 * FIFO full condition
+		 */
 		if ((get_block == put_block) &&
 		    (get_info.offset + 1) == put_info.offset) {
 			DBG_PRINT(INTR_DBG, "%s: Ring Full\n",dev->name);
@@ -2750,7 +2673,7 @@
 		}
 		if (nic->rxd_mode == RXD_MODE_1) {
 			pci_unmap_single(nic->pdev, (dma_addr_t)
-				 ((RxD1_t*)rxdp)->Buffer0_ptr,
+				 ((struct RxD1*)rxdp)->Buffer0_ptr,
 				 dev->mtu +
 				 HEADER_ETHERNET_II_802_3_SIZE +
 				 HEADER_802_2_SIZE +
@@ -2758,22 +2681,22 @@
 				 PCI_DMA_FROMDEVICE);
 		} else if (nic->rxd_mode == RXD_MODE_3B) {
 			pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
-				 ((RxD3_t*)rxdp)->Buffer0_ptr,
+				 ((struct RxD3*)rxdp)->Buffer0_ptr,
 				 BUF0_LEN, PCI_DMA_FROMDEVICE);
 			pci_unmap_single(nic->pdev, (dma_addr_t)
-				 ((RxD3_t*)rxdp)->Buffer2_ptr,
+				 ((struct RxD3*)rxdp)->Buffer2_ptr,
 				 dev->mtu + 4,
 				 PCI_DMA_FROMDEVICE);
 		} else {
 			pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
-					 ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
+					 ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN,
 					 PCI_DMA_FROMDEVICE);
 			pci_unmap_single(nic->pdev, (dma_addr_t)
-					 ((RxD3_t*)rxdp)->Buffer1_ptr,
+					 ((struct RxD3*)rxdp)->Buffer1_ptr,
 					 l3l4hdr_size + 4,
 					 PCI_DMA_FROMDEVICE);
 			pci_unmap_single(nic->pdev, (dma_addr_t)
-					 ((RxD3_t*)rxdp)->Buffer2_ptr,
+					 ((struct RxD3*)rxdp)->Buffer2_ptr,
 					 dev->mtu, PCI_DMA_FROMDEVICE);
 		}
 		prefetch(skb->data);
@@ -2792,20 +2715,17 @@
 			rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
 		}
 
-#ifdef CONFIG_S2IO_NAPI
 		nic->pkts_to_process -= 1;
-		if (!nic->pkts_to_process)
+		if ((napi) && (!nic->pkts_to_process))
 			break;
-#else
 		pkt_cnt++;
 		if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
 			break;
-#endif
 	}
 	if (nic->lro) {
 		/* Clear all LRO sessions before exiting */
 		for (i=0; i<MAX_LRO_SESSIONS; i++) {
-			lro_t *lro = &nic->lro0_n[i];
+			struct lro *lro = &nic->lro0_n[i];
 			if (lro->in_use) {
 				update_L3L4_header(nic, lro);
 				queue_rx_frame(lro->parent);
@@ -2829,17 +2749,17 @@
  *  NONE
  */
 
-static void tx_intr_handler(fifo_info_t *fifo_data)
+static void tx_intr_handler(struct fifo_info *fifo_data)
 {
-	nic_t *nic = fifo_data->nic;
+	struct s2io_nic *nic = fifo_data->nic;
 	struct net_device *dev = (struct net_device *) nic->dev;
-	tx_curr_get_info_t get_info, put_info;
+	struct tx_curr_get_info get_info, put_info;
 	struct sk_buff *skb;
-	TxD_t *txdlp;
+	struct TxD *txdlp;
 
 	get_info = fifo_data->tx_curr_get_info;
-	put_info = fifo_data->tx_curr_put_info;
-	txdlp = (TxD_t *) fifo_data->list_info[get_info.offset].
+	memcpy(&put_info, &fifo_data->tx_curr_put_info, sizeof(put_info));
+	txdlp = (struct TxD *) fifo_data->list_info[get_info.offset].
 	    list_virt_addr;
 	while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) &&
 	       (get_info.offset != put_info.offset) &&
@@ -2854,11 +2774,10 @@
 			}
 			if ((err >> 48) == 0xA) {
 				DBG_PRINT(TX_DBG, "TxD returned due \
-to loss of link\n");
+						to loss of link\n");
 			}
 			else {
-				DBG_PRINT(ERR_DBG, "***TxD error \
-%llx\n", err);
+				DBG_PRINT(ERR_DBG, "***TxD error %llx\n", err);
 			}
 		}
 
@@ -2877,7 +2796,7 @@
 		get_info.offset++;
 		if (get_info.offset == get_info.fifo_len + 1)
 			get_info.offset = 0;
-		txdlp = (TxD_t *) fifo_data->list_info
+		txdlp = (struct TxD *) fifo_data->list_info
 		    [get_info.offset].list_virt_addr;
 		fifo_data->tx_curr_get_info.offset =
 		    get_info.offset;
@@ -2902,8 +2821,8 @@
 static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev)
 {
 	u64 val64 = 0x0;
-	nic_t *sp = dev->priv;
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct s2io_nic *sp = dev->priv;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 
 	//address transaction
 	val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
@@ -2951,8 +2870,8 @@
 {
 	u64 val64 = 0x0;
 	u64 rval64 = 0x0;
-	nic_t *sp = dev->priv;
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct s2io_nic *sp = dev->priv;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 
 	/* address transaction */
 	val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
@@ -3055,8 +2974,8 @@
 	u64 val64 = 0x0;
 	u64 addr  = 0x0;
 
-	nic_t *sp = dev->priv;
-	StatInfo_t *stat_info = sp->mac_control.stats_info;
+	struct s2io_nic *sp = dev->priv;
+	struct stat_block *stat_info = sp->mac_control.stats_info;
 
 	/* Check the communication with the MDIO slave */
 	addr = 0x0000;
@@ -3154,10 +3073,12 @@
 static void alarm_intr_handler(struct s2io_nic *nic)
 {
 	struct net_device *dev = (struct net_device *) nic->dev;
-	XENA_dev_config_t __iomem *bar0 = nic->bar0;
+	struct XENA_dev_config __iomem *bar0 = nic->bar0;
 	register u64 val64 = 0, err_reg = 0;
 	u64 cnt;
 	int i;
+	if (atomic_read(&nic->card_state) == CARD_DOWN)
+		return;
 	nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
 	/* Handling the XPAK counters update */
 	if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
@@ -3297,6 +3218,25 @@
 	}
 	return ret;
 }
+/*
+ * check_pci_device_id - Checks if the device id is supported
+ * @id : device id
+ * Description: Function to check if the pci device id is supported by driver.
+ * Return value: Actual device id if supported else PCI_ANY_ID
+ */
+static u16 check_pci_device_id(u16 id)
+{
+	switch (id) {
+	case PCI_DEVICE_ID_HERC_WIN:
+	case PCI_DEVICE_ID_HERC_UNI:
+		return XFRAME_II_DEVICE;
+	case PCI_DEVICE_ID_S2IO_UNI:
+	case PCI_DEVICE_ID_S2IO_WIN:
+		return XFRAME_I_DEVICE;
+	default:
+		return PCI_ANY_ID;
+	}
+}
 
 /**
  *  s2io_reset - Resets the card.
@@ -3308,42 +3248,57 @@
  *  void.
  */
 
-static void s2io_reset(nic_t * sp)
+static void s2io_reset(struct s2io_nic * sp)
 {
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	u64 val64;
 	u16 subid, pci_cmd;
+	int i;
+	u16 val16;
+	DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n",
+			__FUNCTION__, sp->dev->name);
 
 	/* Back up  the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
 	pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
 
+	if (sp->device_type == XFRAME_II_DEVICE) {
+		int ret;
+		ret = pci_set_power_state(sp->pdev, 3);
+		if (!ret)
+			ret = pci_set_power_state(sp->pdev, 0);
+		else {
+			DBG_PRINT(ERR_DBG,"%s PME based SW_Reset failed!\n",
+					__FUNCTION__);
+			goto old_way;
+		}
+		msleep(20);
+		goto new_way;
+	}
+old_way:
 	val64 = SW_RESET_ALL;
 	writeq(val64, &bar0->sw_reset);
-
-	/*
-	 * At this stage, if the PCI write is indeed completed, the
-	 * card is reset and so is the PCI Config space of the device.
-	 * So a read cannot be issued at this stage on any of the
-	 * registers to ensure the write into "sw_reset" register
-	 * has gone through.
-	 * Question: Is there any system call that will explicitly force
-	 * all the write commands still pending on the bus to be pushed
-	 * through?
-	 * As of now I'am just giving a 250ms delay and hoping that the
-	 * PCI write to sw_reset register is done by this time.
-	 */
-	msleep(250);
+new_way:
 	if (strstr(sp->product_name, "CX4")) {
 		msleep(750);
 	}
-
-	/* Restore the PCI state saved during initialization. */
-	pci_restore_state(sp->pdev);
-	pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
-				     pci_cmd);
-	s2io_init_pci(sp);
-
 	msleep(250);
+	for (i = 0; i < S2IO_MAX_PCI_CONFIG_SPACE_REINIT; i++) {
+
+		/* Restore the PCI state saved during initialization. */
+		pci_restore_state(sp->pdev);
+		pci_read_config_word(sp->pdev, 0x2, &val16);
+		if (check_pci_device_id(val16) != (u16)PCI_ANY_ID)
+			break;
+		msleep(200);
+	}
+
+	if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) {
+		DBG_PRINT(ERR_DBG,"%s SW_Reset failed!\n", __FUNCTION__);
+	}
+
+	pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, pci_cmd);
+
+	s2io_init_pci(sp);
 
 	/* Set swapper to enable I/O register access */
 	s2io_set_swapper(sp);
@@ -3399,10 +3354,10 @@
  *  SUCCESS on success and FAILURE on failure.
  */
 
-static int s2io_set_swapper(nic_t * sp)
+static int s2io_set_swapper(struct s2io_nic * sp)
 {
 	struct net_device *dev = sp->dev;
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	u64 val64, valt, valr;
 
 	/*
@@ -3527,9 +3482,9 @@
 	return SUCCESS;
 }
 
-static int wait_for_msix_trans(nic_t *nic, int i)
+static int wait_for_msix_trans(struct s2io_nic *nic, int i)
 {
-	XENA_dev_config_t __iomem *bar0 = nic->bar0;
+	struct XENA_dev_config __iomem *bar0 = nic->bar0;
 	u64 val64;
 	int ret = 0, cnt = 0;
 
@@ -3548,9 +3503,9 @@
 	return ret;
 }
 
-static void restore_xmsi_data(nic_t *nic)
+static void restore_xmsi_data(struct s2io_nic *nic)
 {
-	XENA_dev_config_t __iomem *bar0 = nic->bar0;
+	struct XENA_dev_config __iomem *bar0 = nic->bar0;
 	u64 val64;
 	int i;
 
@@ -3566,9 +3521,9 @@
 	}
 }
 
-static void store_xmsi_data(nic_t *nic)
+static void store_xmsi_data(struct s2io_nic *nic)
 {
-	XENA_dev_config_t __iomem *bar0 = nic->bar0;
+	struct XENA_dev_config __iomem *bar0 = nic->bar0;
 	u64 val64, addr, data;
 	int i;
 
@@ -3589,9 +3544,9 @@
 	}
 }
 
-int s2io_enable_msi(nic_t *nic)
+int s2io_enable_msi(struct s2io_nic *nic)
 {
-	XENA_dev_config_t __iomem *bar0 = nic->bar0;
+	struct XENA_dev_config __iomem *bar0 = nic->bar0;
 	u16 msi_ctrl, msg_val;
 	struct config_param *config = &nic->config;
 	struct net_device *dev = nic->dev;
@@ -3639,9 +3594,9 @@
 	return 0;
 }
 
-static int s2io_enable_msi_x(nic_t *nic)
+static int s2io_enable_msi_x(struct s2io_nic *nic)
 {
-	XENA_dev_config_t __iomem *bar0 = nic->bar0;
+	struct XENA_dev_config __iomem *bar0 = nic->bar0;
 	u64 tx_mat, rx_mat;
 	u16 msi_control; /* Temp variable */
 	int ret, i, j, msix_indx = 1;
@@ -3749,7 +3704,7 @@
 
 static int s2io_open(struct net_device *dev)
 {
-	nic_t *sp = dev->priv;
+	struct s2io_nic *sp = dev->priv;
 	int err = 0;
 
 	/*
@@ -3802,7 +3757,7 @@
 
 static int s2io_close(struct net_device *dev)
 {
-	nic_t *sp = dev->priv;
+	struct s2io_nic *sp = dev->priv;
 
 	flush_scheduled_work();
 	netif_stop_queue(dev);
@@ -3828,15 +3783,15 @@
 
 static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	nic_t *sp = dev->priv;
+	struct s2io_nic *sp = dev->priv;
 	u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
 	register u64 val64;
-	TxD_t *txdp;
-	TxFIFO_element_t __iomem *tx_fifo;
+	struct TxD *txdp;
+	struct TxFIFO_element __iomem *tx_fifo;
 	unsigned long flags;
 	u16 vlan_tag = 0;
 	int vlan_priority = 0;
-	mac_info_t *mac_control;
+	struct mac_info *mac_control;
 	struct config_param *config;
 	int offload_type;
 
@@ -3864,7 +3819,7 @@
 
 	put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset;
 	get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset;
-	txdp = (TxD_t *) mac_control->fifos[queue].list_info[put_off].
+	txdp = (struct TxD *) mac_control->fifos[queue].list_info[put_off].
 		list_virt_addr;
 
 	queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
@@ -3887,12 +3842,10 @@
 	}
 
 	offload_type = s2io_offload_type(skb);
-#ifdef NETIF_F_TSO
 	if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
 		txdp->Control_1 |= TXD_TCP_LSO_EN;
 		txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb));
 	}
-#endif
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
 		txdp->Control_2 |=
 		    (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
@@ -3993,13 +3946,13 @@
 static void
 s2io_alarm_handle(unsigned long data)
 {
-	nic_t *sp = (nic_t *)data;
+	struct s2io_nic *sp = (struct s2io_nic *)data;
 
 	alarm_intr_handler(sp);
 	mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
 }
 
-static int s2io_chk_rx_buffers(nic_t *sp, int rng_n)
+static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
 {
 	int rxb_size, level;
 
@@ -4031,9 +3984,9 @@
 static irqreturn_t s2io_msi_handle(int irq, void *dev_id)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
-	nic_t *sp = dev->priv;
+	struct s2io_nic *sp = dev->priv;
 	int i;
-	mac_info_t *mac_control;
+	struct mac_info *mac_control;
 	struct config_param *config;
 
 	atomic_inc(&sp->isr_cnt);
@@ -4063,8 +4016,8 @@
 
 static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
 {
-	ring_info_t *ring = (ring_info_t *)dev_id;
-	nic_t *sp = ring->nic;
+	struct ring_info *ring = (struct ring_info *)dev_id;
+	struct s2io_nic *sp = ring->nic;
 
 	atomic_inc(&sp->isr_cnt);
 
@@ -4077,17 +4030,17 @@
 
 static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id)
 {
-	fifo_info_t *fifo = (fifo_info_t *)dev_id;
-	nic_t *sp = fifo->nic;
+	struct fifo_info *fifo = (struct fifo_info *)dev_id;
+	struct s2io_nic *sp = fifo->nic;
 
 	atomic_inc(&sp->isr_cnt);
 	tx_intr_handler(fifo);
 	atomic_dec(&sp->isr_cnt);
 	return IRQ_HANDLED;
 }
-static void s2io_txpic_intr_handle(nic_t *sp)
+static void s2io_txpic_intr_handle(struct s2io_nic *sp)
 {
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	u64 val64;
 
 	val64 = readq(&bar0->pic_int_status);
@@ -4109,39 +4062,33 @@
 		}
 		else if (val64 & GPIO_INT_REG_LINK_UP) {
 			val64 = readq(&bar0->adapter_status);
-			if (verify_xena_quiescence(sp, val64,
-						   sp->device_enabled_once)) {
 				/* Enable Adapter */
-				val64 = readq(&bar0->adapter_control);
-				val64 |= ADAPTER_CNTL_EN;
-				writeq(val64, &bar0->adapter_control);
-				val64 |= ADAPTER_LED_ON;
-				writeq(val64, &bar0->adapter_control);
-				if (!sp->device_enabled_once)
-					sp->device_enabled_once = 1;
+			val64 = readq(&bar0->adapter_control);
+			val64 |= ADAPTER_CNTL_EN;
+			writeq(val64, &bar0->adapter_control);
+			val64 |= ADAPTER_LED_ON;
+			writeq(val64, &bar0->adapter_control);
+			if (!sp->device_enabled_once)
+				sp->device_enabled_once = 1;
 
-				s2io_link(sp, LINK_UP);
-				/*
-				 * unmask link down interrupt and mask link-up
-				 * intr
-				 */
-				val64 = readq(&bar0->gpio_int_mask);
-				val64 &= ~GPIO_INT_MASK_LINK_DOWN;
-				val64 |= GPIO_INT_MASK_LINK_UP;
-				writeq(val64, &bar0->gpio_int_mask);
+			s2io_link(sp, LINK_UP);
+			/*
+			 * unmask link down interrupt and mask link-up
+			 * intr
+			 */
+			val64 = readq(&bar0->gpio_int_mask);
+			val64 &= ~GPIO_INT_MASK_LINK_DOWN;
+			val64 |= GPIO_INT_MASK_LINK_UP;
+			writeq(val64, &bar0->gpio_int_mask);
 
-			}
 		}else if (val64 & GPIO_INT_REG_LINK_DOWN) {
 			val64 = readq(&bar0->adapter_status);
-			if (verify_xena_quiescence(sp, val64,
-						   sp->device_enabled_once)) {
-				s2io_link(sp, LINK_DOWN);
-				/* Link is down so unmaks link up interrupt */
-				val64 = readq(&bar0->gpio_int_mask);
-				val64 &= ~GPIO_INT_MASK_LINK_UP;
-				val64 |= GPIO_INT_MASK_LINK_DOWN;
-				writeq(val64, &bar0->gpio_int_mask);
-			}
+			s2io_link(sp, LINK_DOWN);
+			/* Link is down so unmaks link up interrupt */
+			val64 = readq(&bar0->gpio_int_mask);
+			val64 &= ~GPIO_INT_MASK_LINK_UP;
+			val64 |= GPIO_INT_MASK_LINK_DOWN;
+			writeq(val64, &bar0->gpio_int_mask);
 		}
 	}
 	val64 = readq(&bar0->gpio_int_mask);
@@ -4163,11 +4110,11 @@
 static irqreturn_t s2io_isr(int irq, void *dev_id)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
-	nic_t *sp = dev->priv;
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct s2io_nic *sp = dev->priv;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	int i;
-	u64 reason = 0, val64, org_mask;
-	mac_info_t *mac_control;
+	u64 reason = 0;
+	struct mac_info *mac_control;
 	struct config_param *config;
 
 	atomic_inc(&sp->isr_cnt);
@@ -4185,43 +4132,48 @@
 	reason = readq(&bar0->general_int_status);
 
 	if (!reason) {
-		/* The interrupt was not raised by Xena. */
+		/* The interrupt was not raised by us. */
+		atomic_dec(&sp->isr_cnt);
+		return IRQ_NONE;
+	}
+	else if (unlikely(reason == S2IO_MINUS_ONE) ) {
+		/* Disable device and get out */
 		atomic_dec(&sp->isr_cnt);
 		return IRQ_NONE;
 	}
 
-	val64 = 0xFFFFFFFFFFFFFFFFULL;
-	/* Store current mask before masking all interrupts */
-	org_mask = readq(&bar0->general_int_mask);
-	writeq(val64, &bar0->general_int_mask);
+	if (napi) {
+		if (reason & GEN_INTR_RXTRAFFIC) {
+			if ( likely ( netif_rx_schedule_prep(dev)) ) {
+				__netif_rx_schedule(dev);
+				writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask);
+			}
+			else
+				writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+		}
+	} else {
+		/*
+		 * Rx handler is called by default, without checking for the
+		 * cause of interrupt.
+		 * rx_traffic_int reg is an R1 register, writing all 1's
+		 * will ensure that the actual interrupt causing bit get's
+		 * cleared and hence a read can be avoided.
+		 */
+		if (reason & GEN_INTR_RXTRAFFIC)
+			writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
 
-#ifdef CONFIG_S2IO_NAPI
-	if (reason & GEN_INTR_RXTRAFFIC) {
-		if (netif_rx_schedule_prep(dev)) {
-			writeq(val64, &bar0->rx_traffic_mask);
-			__netif_rx_schedule(dev);
+		for (i = 0; i < config->rx_ring_num; i++) {
+			rx_intr_handler(&mac_control->rings[i]);
 		}
 	}
-#else
-	/*
-	 * Rx handler is called by default, without checking for the
-	 * cause of interrupt.
-	 * rx_traffic_int reg is an R1 register, writing all 1's
-	 * will ensure that the actual interrupt causing bit get's
-	 * cleared and hence a read can be avoided.
-	 */
-	writeq(val64, &bar0->rx_traffic_int);
-	for (i = 0; i < config->rx_ring_num; i++) {
-		rx_intr_handler(&mac_control->rings[i]);
-	}
-#endif
 
 	/*
 	 * tx_traffic_int reg is an R1 register, writing all 1's
 	 * will ensure that the actual interrupt causing bit get's
 	 * cleared and hence a read can be avoided.
 	 */
-	writeq(val64, &bar0->tx_traffic_int);
+	if (reason & GEN_INTR_TXTRAFFIC)
+		writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
 
 	for (i = 0; i < config->tx_fifo_num; i++)
 		tx_intr_handler(&mac_control->fifos[i]);
@@ -4233,11 +4185,14 @@
 	 * reallocate the buffers from the interrupt handler itself,
 	 * else schedule a tasklet to reallocate the buffers.
 	 */
-#ifndef CONFIG_S2IO_NAPI
-	for (i = 0; i < config->rx_ring_num; i++)
-		s2io_chk_rx_buffers(sp, i);
-#endif
-	writeq(org_mask, &bar0->general_int_mask);
+	if (!napi) {
+		for (i = 0; i < config->rx_ring_num; i++)
+			s2io_chk_rx_buffers(sp, i);
+	}
+
+	writeq(0, &bar0->general_int_mask);
+	readl(&bar0->general_int_status);
+
 	atomic_dec(&sp->isr_cnt);
 	return IRQ_HANDLED;
 }
@@ -4245,9 +4200,9 @@
 /**
  * s2io_updt_stats -
  */
-static void s2io_updt_stats(nic_t *sp)
+static void s2io_updt_stats(struct s2io_nic *sp)
 {
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	u64 val64;
 	int cnt = 0;
 
@@ -4266,7 +4221,7 @@
 				break; /* Updt failed */
 		} while(1);
 	} else {
-		memset(sp->mac_control.stats_info, 0, sizeof(StatInfo_t));
+		memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block));
 	}
 }
 
@@ -4282,8 +4237,8 @@
 
 static struct net_device_stats *s2io_get_stats(struct net_device *dev)
 {
-	nic_t *sp = dev->priv;
-	mac_info_t *mac_control;
+	struct s2io_nic *sp = dev->priv;
+	struct mac_info *mac_control;
 	struct config_param *config;
 
 
@@ -4324,8 +4279,8 @@
 {
 	int i, j, prev_cnt;
 	struct dev_mc_list *mclist;
-	nic_t *sp = dev->priv;
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct s2io_nic *sp = dev->priv;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
 	    0xfeffffffffffULL;
 	u64 dis_addr = 0xffffffffffffULL, mac_addr = 0;
@@ -4478,8 +4433,8 @@
 
 static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
 {
-	nic_t *sp = dev->priv;
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct s2io_nic *sp = dev->priv;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	register u64 val64, mac_addr = 0;
 	int i;
 
@@ -4525,7 +4480,7 @@
 static int s2io_ethtool_sset(struct net_device *dev,
 			     struct ethtool_cmd *info)
 {
-	nic_t *sp = dev->priv;
+	struct s2io_nic *sp = dev->priv;
 	if ((info->autoneg == AUTONEG_ENABLE) ||
 	    (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL))
 		return -EINVAL;
@@ -4551,7 +4506,7 @@
 
 static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
 {
-	nic_t *sp = dev->priv;
+	struct s2io_nic *sp = dev->priv;
 	info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
 	info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
 	info->port = PORT_FIBRE;
@@ -4584,7 +4539,7 @@
 static void s2io_ethtool_gdrvinfo(struct net_device *dev,
 				  struct ethtool_drvinfo *info)
 {
-	nic_t *sp = dev->priv;
+	struct s2io_nic *sp = dev->priv;
 
 	strncpy(info->driver, s2io_driver_name, sizeof(info->driver));
 	strncpy(info->version, s2io_driver_version, sizeof(info->version));
@@ -4616,7 +4571,7 @@
 	int i;
 	u64 reg;
 	u8 *reg_space = (u8 *) space;
-	nic_t *sp = dev->priv;
+	struct s2io_nic *sp = dev->priv;
 
 	regs->len = XENA_REG_SPACE;
 	regs->version = sp->pdev->subsystem_device;
@@ -4638,8 +4593,8 @@
 */
 static void s2io_phy_id(unsigned long data)
 {
-	nic_t *sp = (nic_t *) data;
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct s2io_nic *sp = (struct s2io_nic *) data;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	u64 val64 = 0;
 	u16 subid;
 
@@ -4676,8 +4631,8 @@
 static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
 {
 	u64 val64 = 0, last_gpio_ctrl_val;
-	nic_t *sp = dev->priv;
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct s2io_nic *sp = dev->priv;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	u16 subid;
 
 	subid = sp->pdev->subsystem_device;
@@ -4725,8 +4680,8 @@
 				       struct ethtool_pauseparam *ep)
 {
 	u64 val64;
-	nic_t *sp = dev->priv;
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct s2io_nic *sp = dev->priv;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 
 	val64 = readq(&bar0->rmac_pause_cfg);
 	if (val64 & RMAC_PAUSE_GEN_ENABLE)
@@ -4752,8 +4707,8 @@
 			       struct ethtool_pauseparam *ep)
 {
 	u64 val64;
-	nic_t *sp = dev->priv;
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct s2io_nic *sp = dev->priv;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 
 	val64 = readq(&bar0->rmac_pause_cfg);
 	if (ep->tx_pause)
@@ -4785,12 +4740,12 @@
  */
 
 #define S2IO_DEV_ID		5
-static int read_eeprom(nic_t * sp, int off, u64 * data)
+static int read_eeprom(struct s2io_nic * sp, int off, u64 * data)
 {
 	int ret = -1;
 	u32 exit_cnt = 0;
 	u64 val64;
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 
 	if (sp->device_type == XFRAME_I_DEVICE) {
 		val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
@@ -4850,11 +4805,11 @@
  *  0 on success, -1 on failure.
  */
 
-static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
+static int write_eeprom(struct s2io_nic * sp, int off, u64 data, int cnt)
 {
 	int exit_cnt = 0, ret = -1;
 	u64 val64;
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 
 	if (sp->device_type == XFRAME_I_DEVICE) {
 		val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
@@ -4899,7 +4854,7 @@
 	}
 	return ret;
 }
-static void s2io_vpd_read(nic_t *nic)
+static void s2io_vpd_read(struct s2io_nic *nic)
 {
 	u8 *vpd_data;
 	u8 data;
@@ -4914,6 +4869,7 @@
 		strcpy(nic->product_name, "Xframe I 10GbE network adapter");
 		vpd_addr = 0x50;
 	}
+	strcpy(nic->serial_num, "NOT AVAILABLE");
 
 	vpd_data = kmalloc(256, GFP_KERNEL);
 	if (!vpd_data)
@@ -4937,7 +4893,22 @@
 		pci_read_config_dword(nic->pdev,  (vpd_addr + 4),
 				      (u32 *)&vpd_data[i]);
 	}
-	if ((!fail) && (vpd_data[1] < VPD_PRODUCT_NAME_LEN)) {
+
+	if(!fail) {
+		/* read serial number of adapter */
+		for (cnt = 0; cnt < 256; cnt++) {
+		if ((vpd_data[cnt] == 'S') &&
+			(vpd_data[cnt+1] == 'N') &&
+			(vpd_data[cnt+2] < VPD_STRING_LEN)) {
+				memset(nic->serial_num, 0, VPD_STRING_LEN);
+				memcpy(nic->serial_num, &vpd_data[cnt + 3],
+					vpd_data[cnt+2]);
+				break;
+			}
+		}
+	}
+
+	if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) {
 		memset(nic->product_name, 0, vpd_data[1]);
 		memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
 	}
@@ -4962,7 +4933,7 @@
 {
 	u32 i, valid;
 	u64 data;
-	nic_t *sp = dev->priv;
+	struct s2io_nic *sp = dev->priv;
 
 	eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16);
 
@@ -5000,7 +4971,7 @@
 {
 	int len = eeprom->len, cnt = 0;
 	u64 valid = 0, data;
-	nic_t *sp = dev->priv;
+	struct s2io_nic *sp = dev->priv;
 
 	if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) {
 		DBG_PRINT(ERR_DBG,
@@ -5044,9 +5015,9 @@
  * 0 on success.
  */
 
-static int s2io_register_test(nic_t * sp, uint64_t * data)
+static int s2io_register_test(struct s2io_nic * sp, uint64_t * data)
 {
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	u64 val64 = 0, exp_val;
 	int fail = 0;
 
@@ -5111,7 +5082,7 @@
  * 0 on success.
  */
 
-static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
+static int s2io_eeprom_test(struct s2io_nic * sp, uint64_t * data)
 {
 	int fail = 0;
 	u64 ret_data, org_4F0, org_7F0;
@@ -5213,7 +5184,7 @@
  * 0 on success and -1 on failure.
  */
 
-static int s2io_bist_test(nic_t * sp, uint64_t * data)
+static int s2io_bist_test(struct s2io_nic * sp, uint64_t * data)
 {
 	u8 bist = 0;
 	int cnt = 0, ret = -1;
@@ -5249,9 +5220,9 @@
  * 0 on success.
  */
 
-static int s2io_link_test(nic_t * sp, uint64_t * data)
+static int s2io_link_test(struct s2io_nic * sp, uint64_t * data)
 {
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	u64 val64;
 
 	val64 = readq(&bar0->adapter_status);
@@ -5276,9 +5247,9 @@
  *  0 on success.
  */
 
-static int s2io_rldram_test(nic_t * sp, uint64_t * data)
+static int s2io_rldram_test(struct s2io_nic * sp, uint64_t * data)
 {
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	u64 val64;
 	int cnt, iteration = 0, test_fail = 0;
 
@@ -5380,7 +5351,7 @@
 			      struct ethtool_test *ethtest,
 			      uint64_t * data)
 {
-	nic_t *sp = dev->priv;
+	struct s2io_nic *sp = dev->priv;
 	int orig_state = netif_running(sp->dev);
 
 	if (ethtest->flags == ETH_TEST_FL_OFFLINE) {
@@ -5436,8 +5407,8 @@
 				   u64 * tmp_stats)
 {
 	int i = 0;
-	nic_t *sp = dev->priv;
-	StatInfo_t *stat_info = sp->mac_control.stats_info;
+	struct s2io_nic *sp = dev->priv;
+	struct stat_block *stat_info = sp->mac_control.stats_info;
 
 	s2io_updt_stats(sp);
 	tmp_stats[i++] =
@@ -5664,14 +5635,14 @@
 
 static u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
 {
-	nic_t *sp = dev->priv;
+	struct s2io_nic *sp = dev->priv;
 
 	return (sp->rx_csum);
 }
 
 static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
 {
-	nic_t *sp = dev->priv;
+	struct s2io_nic *sp = dev->priv;
 
 	if (data)
 		sp->rx_csum = 1;
@@ -5750,10 +5721,8 @@
 	.set_tx_csum = s2io_ethtool_op_set_tx_csum,
 	.get_sg = ethtool_op_get_sg,
 	.set_sg = ethtool_op_set_sg,
-#ifdef NETIF_F_TSO
 	.get_tso = s2io_ethtool_op_get_tso,
 	.set_tso = s2io_ethtool_op_set_tso,
-#endif
 	.get_ufo = ethtool_op_get_ufo,
 	.set_ufo = ethtool_op_set_ufo,
 	.self_test_count = s2io_ethtool_self_test_count,
@@ -5794,7 +5763,7 @@
 
 static int s2io_change_mtu(struct net_device *dev, int new_mtu)
 {
-	nic_t *sp = dev->priv;
+	struct s2io_nic *sp = dev->priv;
 
 	if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
 		DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n",
@@ -5813,7 +5782,7 @@
 		if (netif_queue_stopped(dev))
 			netif_wake_queue(dev);
 	} else { /* Device is down */
-		XENA_dev_config_t __iomem *bar0 = sp->bar0;
+		struct XENA_dev_config __iomem *bar0 = sp->bar0;
 		u64 val64 = new_mtu;
 
 		writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
@@ -5838,9 +5807,9 @@
 static void s2io_tasklet(unsigned long dev_addr)
 {
 	struct net_device *dev = (struct net_device *) dev_addr;
-	nic_t *sp = dev->priv;
+	struct s2io_nic *sp = dev->priv;
 	int i, ret;
-	mac_info_t *mac_control;
+	struct mac_info *mac_control;
 	struct config_param *config;
 
 	mac_control = &sp->mac_control;
@@ -5873,9 +5842,9 @@
 
 static void s2io_set_link(struct work_struct *work)
 {
-	nic_t *nic = container_of(work, nic_t, set_link_task);
+	struct s2io_nic *nic = container_of(work, struct s2io_nic, set_link_task);
 	struct net_device *dev = nic->dev;
-	XENA_dev_config_t __iomem *bar0 = nic->bar0;
+	struct XENA_dev_config __iomem *bar0 = nic->bar0;
 	register u64 val64;
 	u16 subid;
 
@@ -5894,57 +5863,53 @@
 	}
 
 	val64 = readq(&bar0->adapter_status);
-	if (verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
-		if (LINK_IS_UP(val64)) {
-			val64 = readq(&bar0->adapter_control);
-			val64 |= ADAPTER_CNTL_EN;
-			writeq(val64, &bar0->adapter_control);
-			if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
-							     subid)) {
-				val64 = readq(&bar0->gpio_control);
-				val64 |= GPIO_CTRL_GPIO_0;
-				writeq(val64, &bar0->gpio_control);
-				val64 = readq(&bar0->gpio_control);
-			} else {
-				val64 |= ADAPTER_LED_ON;
+	if (LINK_IS_UP(val64)) {
+		if (!(readq(&bar0->adapter_control) & ADAPTER_CNTL_EN)) {
+			if (verify_xena_quiescence(nic)) {
+				val64 = readq(&bar0->adapter_control);
+				val64 |= ADAPTER_CNTL_EN;
 				writeq(val64, &bar0->adapter_control);
-			}
-			if (s2io_link_fault_indication(nic) ==
-						MAC_RMAC_ERR_TIMER) {
-				val64 = readq(&bar0->adapter_status);
-				if (!LINK_IS_UP(val64)) {
-					DBG_PRINT(ERR_DBG, "%s:", dev->name);
-					DBG_PRINT(ERR_DBG, " Link down");
-					DBG_PRINT(ERR_DBG, "after ");
-					DBG_PRINT(ERR_DBG, "enabling ");
-					DBG_PRINT(ERR_DBG, "device \n");
+				if (CARDS_WITH_FAULTY_LINK_INDICATORS(
+					nic->device_type, subid)) {
+					val64 = readq(&bar0->gpio_control);
+					val64 |= GPIO_CTRL_GPIO_0;
+					writeq(val64, &bar0->gpio_control);
+					val64 = readq(&bar0->gpio_control);
+				} else {
+					val64 |= ADAPTER_LED_ON;
+					writeq(val64, &bar0->adapter_control);
 				}
-			}
-			if (nic->device_enabled_once == FALSE) {
 				nic->device_enabled_once = TRUE;
+			} else {
+				DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
+				DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
+				netif_stop_queue(dev);
 			}
-			s2io_link(nic, LINK_UP);
-		} else {
-			if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
-							      subid)) {
-				val64 = readq(&bar0->gpio_control);
-				val64 &= ~GPIO_CTRL_GPIO_0;
-				writeq(val64, &bar0->gpio_control);
-				val64 = readq(&bar0->gpio_control);
-			}
-			s2io_link(nic, LINK_DOWN);
 		}
-	} else {		/* NIC is not Quiescent. */
-		DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
-		DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
-		netif_stop_queue(dev);
+		val64 = readq(&bar0->adapter_status);
+		if (!LINK_IS_UP(val64)) {
+			DBG_PRINT(ERR_DBG, "%s:", dev->name);
+			DBG_PRINT(ERR_DBG, " Link down after enabling ");
+			DBG_PRINT(ERR_DBG, "device \n");
+		} else
+			s2io_link(nic, LINK_UP);
+	} else {
+		if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
+						      subid)) {
+			val64 = readq(&bar0->gpio_control);
+			val64 &= ~GPIO_CTRL_GPIO_0;
+			writeq(val64, &bar0->gpio_control);
+			val64 = readq(&bar0->gpio_control);
+		}
+		s2io_link(nic, LINK_DOWN);
 	}
 	clear_bit(0, &(nic->link_state));
 }
 
-static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
-			   struct sk_buff **skb, u64 *temp0, u64 *temp1,
-			   u64 *temp2, int size)
+static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
+				struct buffAdd *ba,
+				struct sk_buff **skb, u64 *temp0, u64 *temp1,
+				u64 *temp2, int size)
 {
 	struct net_device *dev = sp->dev;
 	struct sk_buff *frag_list;
@@ -5958,7 +5923,7 @@
 			 * using same mapped address for the Rxd
 			 * buffer pointer
 			 */
-			((RxD1_t*)rxdp)->Buffer0_ptr = *temp0;
+			((struct RxD1*)rxdp)->Buffer0_ptr = *temp0;
 		} else {
 			*skb = dev_alloc_skb(size);
 			if (!(*skb)) {
@@ -5970,7 +5935,7 @@
 			 * such it will be used for next rxd whose
 			 * Host Control is NULL
 			 */
-			((RxD1_t*)rxdp)->Buffer0_ptr = *temp0 =
+			((struct RxD1*)rxdp)->Buffer0_ptr = *temp0 =
 				pci_map_single( sp->pdev, (*skb)->data,
 					size - NET_IP_ALIGN,
 					PCI_DMA_FROMDEVICE);
@@ -5979,36 +5944,36 @@
 	} else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) {
 		/* Two buffer Mode */
 		if (*skb) {
-			((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
-			((RxD3_t*)rxdp)->Buffer0_ptr = *temp0;
-			((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
+			((struct RxD3*)rxdp)->Buffer2_ptr = *temp2;
+			((struct RxD3*)rxdp)->Buffer0_ptr = *temp0;
+			((struct RxD3*)rxdp)->Buffer1_ptr = *temp1;
 		} else {
 			*skb = dev_alloc_skb(size);
 			if (!(*skb)) {
 				DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
-					  dev->name);
+					dev->name);
 				return -ENOMEM;
 			}
-			((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
+			((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
 				pci_map_single(sp->pdev, (*skb)->data,
 					       dev->mtu + 4,
 					       PCI_DMA_FROMDEVICE);
-			((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
+			((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
 				pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN,
 						PCI_DMA_FROMDEVICE);
 			rxdp->Host_Control = (unsigned long) (*skb);
 
 			/* Buffer-1 will be dummy buffer not used */
-			((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 =
+			((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 =
 				pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN,
 					       PCI_DMA_FROMDEVICE);
 		}
 	} else if ((rxdp->Host_Control == 0)) {
 		/* Three buffer mode */
 		if (*skb) {
-			((RxD3_t*)rxdp)->Buffer0_ptr = *temp0;
-			((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
-			((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
+			((struct RxD3*)rxdp)->Buffer0_ptr = *temp0;
+			((struct RxD3*)rxdp)->Buffer1_ptr = *temp1;
+			((struct RxD3*)rxdp)->Buffer2_ptr = *temp2;
 		} else {
 			*skb = dev_alloc_skb(size);
 			if (!(*skb)) {
@@ -6016,11 +5981,11 @@
 					  dev->name);
 				return -ENOMEM;
 			}
-			((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
+			((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
 				pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN,
 					       PCI_DMA_FROMDEVICE);
 			/* Buffer-1 receives L3/L4 headers */
-			((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 =
+			((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 =
 				pci_map_single( sp->pdev, (*skb)->data,
 						l3l4hdr_size + 4,
 						PCI_DMA_FROMDEVICE);
@@ -6040,14 +6005,15 @@
 			/*
 			 * Buffer-2 receives L4 data payload
 			 */
-			((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
+			((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
 				pci_map_single( sp->pdev, frag_list->data,
 						dev->mtu, PCI_DMA_FROMDEVICE);
 		}
 	}
 	return 0;
 }
-static void set_rxd_buffer_size(nic_t *sp, RxD_t *rxdp, int size)
+static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp,
+				int size)
 {
 	struct net_device *dev = sp->dev;
 	if (sp->rxd_mode == RXD_MODE_1) {
@@ -6063,15 +6029,15 @@
 	}
 }
 
-static  int rxd_owner_bit_reset(nic_t *sp)
+static  int rxd_owner_bit_reset(struct s2io_nic *sp)
 {
 	int i, j, k, blk_cnt = 0, size;
-	mac_info_t * mac_control = &sp->mac_control;
+	struct mac_info * mac_control = &sp->mac_control;
 	struct config_param *config = &sp->config;
 	struct net_device *dev = sp->dev;
-	RxD_t *rxdp = NULL;
+	struct RxD_t *rxdp = NULL;
 	struct sk_buff *skb = NULL;
-	buffAdd_t *ba = NULL;
+	struct buffAdd *ba = NULL;
 	u64 temp0_64 = 0, temp1_64 = 0, temp2_64 = 0;
 
 	/* Calculate the size based on ring mode */
@@ -6110,7 +6076,7 @@
 
 }
 
-static int s2io_add_isr(nic_t * sp)
+static int s2io_add_isr(struct s2io_nic * sp)
 {
 	int ret = 0;
 	struct net_device *dev = sp->dev;
@@ -6125,7 +6091,7 @@
 		sp->intr_type = INTA;
 	}
 
-	/* Store the values of the MSIX table in the nic_t structure */
+	/* Store the values of the MSIX table in the struct s2io_nic structure */
 	store_xmsi_data(sp);
 
 	/* After proper initialization of H/W, register ISR */
@@ -6180,7 +6146,7 @@
 	}
 	return 0;
 }
-static void s2io_rem_isr(nic_t * sp)
+static void s2io_rem_isr(struct s2io_nic * sp)
 {
 	int cnt = 0;
 	struct net_device *dev = sp->dev;
@@ -6222,10 +6188,10 @@
 	} while(cnt < 5);
 }
 
-static void s2io_card_down(nic_t * sp)
+static void s2io_card_down(struct s2io_nic * sp)
 {
 	int cnt = 0;
-	XENA_dev_config_t __iomem *bar0 = sp->bar0;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	unsigned long flags;
 	register u64 val64 = 0;
 
@@ -6256,7 +6222,8 @@
 		rxd_owner_bit_reset(sp);
 
 		val64 = readq(&bar0->adapter_status);
-		if (verify_xena_quiescence(sp, val64, sp->device_enabled_once)) {
+		if (verify_xena_quiescence(sp)) {
+			if(verify_pcc_quiescent(sp, sp->device_enabled_once))
 			break;
 		}
 
@@ -6285,10 +6252,10 @@
 	clear_bit(0, &(sp->link_state));
 }
 
-static int s2io_card_up(nic_t * sp)
+static int s2io_card_up(struct s2io_nic * sp)
 {
 	int i, ret = 0;
-	mac_info_t *mac_control;
+	struct mac_info *mac_control;
 	struct config_param *config;
 	struct net_device *dev = (struct net_device *) sp->dev;
 	u16 interruptible;
@@ -6319,6 +6286,13 @@
 		DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
 			  atomic_read(&sp->rx_bufs_left[i]));
 	}
+	/* Maintain the state prior to the open */
+	if (sp->promisc_flg)
+		sp->promisc_flg = 0;
+	if (sp->m_cast_flg) {
+		sp->m_cast_flg = 0;
+		sp->all_multi_pos= 0;
+	}
 
 	/* Setting its receive mode */
 	s2io_set_multicast(dev);
@@ -6380,7 +6354,7 @@
 
 static void s2io_restart_nic(struct work_struct *work)
 {
-	nic_t *sp = container_of(work, nic_t, rst_timer_task);
+	struct s2io_nic *sp = container_of(work, struct s2io_nic, rst_timer_task);
 	struct net_device *dev = sp->dev;
 
 	s2io_card_down(sp);
@@ -6409,7 +6383,7 @@
 
 static void s2io_tx_watchdog(struct net_device *dev)
 {
-	nic_t *sp = dev->priv;
+	struct s2io_nic *sp = dev->priv;
 
 	if (netif_carrier_ok(dev)) {
 		schedule_work(&sp->rst_timer_task);
@@ -6434,16 +6408,16 @@
  *   Return value:
  *   SUCCESS on success and -1 on failure.
  */
-static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
+static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
 {
-	nic_t *sp = ring_data->nic;
+	struct s2io_nic *sp = ring_data->nic;
 	struct net_device *dev = (struct net_device *) sp->dev;
 	struct sk_buff *skb = (struct sk_buff *)
 		((unsigned long) rxdp->Host_Control);
 	int ring_no = ring_data->ring_no;
 	u16 l3_csum, l4_csum;
 	unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
-	lro_t *lro;
+	struct lro *lro;
 
 	skb->dev = dev;
 
@@ -6488,7 +6462,7 @@
 		int buf2_len = RXD_GET_BUFFER2_SIZE_3(rxdp->Control_2);
 		unsigned char *buff = skb_push(skb, buf0_len);
 
-		buffAdd_t *ba = &ring_data->ba[get_block][get_off];
+		struct buffAdd *ba = &ring_data->ba[get_block][get_off];
 		sp->stats.rx_bytes += buf0_len + buf2_len;
 		memcpy(buff, ba->ba_0, buf0_len);
 
@@ -6498,7 +6472,6 @@
 			skb_put(skb, buf1_len);
 			skb->len += buf2_len;
 			skb->data_len += buf2_len;
-			skb->truesize += buf2_len;
 			skb_put(skb_shinfo(skb)->frag_list, buf2_len);
 			sp->stats.rx_bytes += buf1_len;
 
@@ -6582,23 +6555,20 @@
 
 	if (!sp->lro) {
 		skb->protocol = eth_type_trans(skb, dev);
-#ifdef CONFIG_S2IO_NAPI
 		if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
 			/* Queueing the vlan frame to the upper layer */
-			vlan_hwaccel_receive_skb(skb, sp->vlgrp,
-				RXD_GET_VLAN_TAG(rxdp->Control_2));
+			if (napi)
+				vlan_hwaccel_receive_skb(skb, sp->vlgrp,
+					RXD_GET_VLAN_TAG(rxdp->Control_2));
+			else
+				vlan_hwaccel_rx(skb, sp->vlgrp,
+					RXD_GET_VLAN_TAG(rxdp->Control_2));
 		} else {
-			netif_receive_skb(skb);
+			if (napi)
+				netif_receive_skb(skb);
+			else
+				netif_rx(skb);
 		}
-#else
-		if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
-			/* Queueing the vlan frame to the upper layer */
-			vlan_hwaccel_rx(skb, sp->vlgrp,
-				RXD_GET_VLAN_TAG(rxdp->Control_2));
-		} else {
-			netif_rx(skb);
-		}
-#endif
 	} else {
 send_up:
 		queue_rx_frame(skb);
@@ -6622,7 +6592,7 @@
  *  void.
  */
 
-static void s2io_link(nic_t * sp, int link)
+static void s2io_link(struct s2io_nic * sp, int link)
 {
 	struct net_device *dev = (struct net_device *) sp->dev;
 
@@ -6666,7 +6636,7 @@
  *  void
  */
 
-static void s2io_init_pci(nic_t * sp)
+static void s2io_init_pci(struct s2io_nic * sp)
 {
 	u16 pci_cmd = 0, pcix_cmd = 0;
 
@@ -6699,13 +6669,9 @@
 		DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n");
 		rx_ring_num = 8;
 	}
-#ifdef CONFIG_S2IO_NAPI
-	if (*dev_intr_type != INTA) {
-		DBG_PRINT(ERR_DBG, "s2io: NAPI cannot be enabled when "
-			  "MSI/MSI-X is enabled. Defaulting to INTA\n");
-		*dev_intr_type = INTA;
-	}
-#endif
+	if (*dev_intr_type != INTA)
+		napi = 0;
+
 #ifndef CONFIG_PCI_MSI
 	if (*dev_intr_type != INTA) {
 		DBG_PRINT(ERR_DBG, "s2io: This kernel does not support"
@@ -6726,6 +6692,8 @@
 					"Defaulting to INTA\n");
 		*dev_intr_type = INTA;
 	}
+	if ( (rx_ring_num > 1) && (*dev_intr_type != INTA) )
+		napi = 0;
 	if (rx_ring_mode > 3) {
 		DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n");
 		DBG_PRINT(ERR_DBG, "s2io: Defaulting to 3-buffer mode\n");
@@ -6751,15 +6719,15 @@
 static int __devinit
 s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
 {
-	nic_t *sp;
+	struct s2io_nic *sp;
 	struct net_device *dev;
 	int i, j, ret;
 	int dma_flag = FALSE;
 	u32 mac_up, mac_down;
 	u64 val64 = 0, tmp64 = 0;
-	XENA_dev_config_t __iomem *bar0 = NULL;
+	struct XENA_dev_config __iomem *bar0 = NULL;
 	u16 subid;
-	mac_info_t *mac_control;
+	struct mac_info *mac_control;
 	struct config_param *config;
 	int mode;
 	u8 dev_intr_type = intr_type;
@@ -6814,7 +6782,7 @@
 		}
 	}
 
-	dev = alloc_etherdev(sizeof(nic_t));
+	dev = alloc_etherdev(sizeof(struct s2io_nic));
 	if (dev == NULL) {
 		DBG_PRINT(ERR_DBG, "Device allocation failed\n");
 		pci_disable_device(pdev);
@@ -6829,7 +6797,7 @@
 
 	/*  Private member variable initialized to s2io NIC structure */
 	sp = dev->priv;
-	memset(sp, 0, sizeof(nic_t));
+	memset(sp, 0, sizeof(struct s2io_nic));
 	sp->dev = dev;
 	sp->pdev = pdev;
 	sp->high_dma_flag = dma_flag;
@@ -6925,7 +6893,7 @@
 	sp->bar0 = ioremap(pci_resource_start(pdev, 0),
 				     pci_resource_len(pdev, 0));
 	if (!sp->bar0) {
-		DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem1\n",
+		DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem1\n",
 			  dev->name);
 		ret = -ENOMEM;
 		goto bar0_remap_failed;
@@ -6934,7 +6902,7 @@
 	sp->bar1 = ioremap(pci_resource_start(pdev, 2),
 				     pci_resource_len(pdev, 2));
 	if (!sp->bar1) {
-		DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem2\n",
+		DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem2\n",
 			  dev->name);
 		ret = -ENOMEM;
 		goto bar1_remap_failed;
@@ -6945,7 +6913,7 @@
 
 	/* Initializing the BAR1 address as the start of the FIFO pointer. */
 	for (j = 0; j < MAX_TX_FIFOS; j++) {
-		mac_control->tx_FIFO_start[j] = (TxFIFO_element_t __iomem *)
+		mac_control->tx_FIFO_start[j] = (struct TxFIFO_element __iomem *)
 		    (sp->bar1 + (j * 0x00020000));
 	}
 
@@ -6966,10 +6934,8 @@
 	 * will use eth_mac_addr() for  dev->set_mac_address
 	 * mac address will be set every time dev->open() is called
 	 */
-#if defined(CONFIG_S2IO_NAPI)
 	dev->poll = s2io_poll;
 	dev->weight = 32;
-#endif
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = s2io_netpoll;
@@ -6978,13 +6944,9 @@
 	dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
 	if (sp->high_dma_flag == TRUE)
 		dev->features |= NETIF_F_HIGHDMA;
-#ifdef NETIF_F_TSO
 	dev->features |= NETIF_F_TSO;
-#endif
-#ifdef NETIF_F_TSO6
 	dev->features |= NETIF_F_TSO6;
-#endif
-	if (sp->device_type & XFRAME_II_DEVICE) {
+	if ((sp->device_type & XFRAME_II_DEVICE) && (ufo))  {
 		dev->features |= NETIF_F_UFO;
 		dev->features |= NETIF_F_HW_CSUM;
 	}
@@ -7065,9 +7027,9 @@
 
 	/* Initialize spinlocks */
 	spin_lock_init(&sp->tx_lock);
-#ifndef CONFIG_S2IO_NAPI
-	spin_lock_init(&sp->put_lock);
-#endif
+
+	if (!napi)
+		spin_lock_init(&sp->put_lock);
 	spin_lock_init(&sp->rx_lock);
 
 	/*
@@ -7098,13 +7060,14 @@
 	DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
 		  s2io_driver_version);
 	DBG_PRINT(ERR_DBG, "%s: MAC ADDR: "
-			  "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
+			  "%02x:%02x:%02x:%02x:%02x:%02x", dev->name,
 			  sp->def_mac_addr[0].mac_addr[0],
 			  sp->def_mac_addr[0].mac_addr[1],
 			  sp->def_mac_addr[0].mac_addr[2],
 			  sp->def_mac_addr[0].mac_addr[3],
 			  sp->def_mac_addr[0].mac_addr[4],
 			  sp->def_mac_addr[0].mac_addr[5]);
+	DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num);
 	if (sp->device_type & XFRAME_II_DEVICE) {
 		mode = s2io_print_pci_mode(sp);
 		if (mode < 0) {
@@ -7128,9 +7091,9 @@
 						dev->name);
 		    break;
 	}
-#ifdef CONFIG_S2IO_NAPI
-	DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
-#endif
+
+	if (napi)
+		DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
 	switch(sp->intr_type) {
 		case INTA:
 		    DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
@@ -7145,7 +7108,9 @@
 	if (sp->lro)
 		DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
 			  dev->name);
-
+	if (ufo)
+		DBG_PRINT(ERR_DBG, "%s: UDP Fragmentation Offload(UFO)"
+					" enabled\n", dev->name);
 	/* Initialize device name */
 	sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name);
 
@@ -7202,7 +7167,7 @@
 {
 	struct net_device *dev =
 	    (struct net_device *) pci_get_drvdata(pdev);
-	nic_t *sp;
+	struct s2io_nic *sp;
 
 	if (dev == NULL) {
 		DBG_PRINT(ERR_DBG, "Driver Data is NULL!!\n");
@@ -7215,7 +7180,6 @@
 	free_shared_mem(sp);
 	iounmap(sp->bar0);
 	iounmap(sp->bar1);
-	pci_disable_device(pdev);
 	if (sp->intr_type != MSI_X)
 		pci_release_regions(pdev);
 	else {
@@ -7226,6 +7190,7 @@
 	}
 	pci_set_drvdata(pdev, NULL);
 	free_netdev(dev);
+	pci_disable_device(pdev);
 }
 
 /**
@@ -7244,7 +7209,7 @@
  * Description: This function is the cleanup routine for the driver. It unregist * ers the driver.
  */
 
-static void s2io_closer(void)
+static __exit void s2io_closer(void)
 {
 	pci_unregister_driver(&s2io_driver);
 	DBG_PRINT(INIT_DBG, "cleanup done\n");
@@ -7254,7 +7219,7 @@
 module_exit(s2io_closer);
 
 static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
-		struct tcphdr **tcp, RxD_t *rxdp)
+		struct tcphdr **tcp, struct RxD_t *rxdp)
 {
 	int ip_off;
 	u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len;
@@ -7288,7 +7253,7 @@
 	return 0;
 }
 
-static int check_for_socket_match(lro_t *lro, struct iphdr *ip,
+static int check_for_socket_match(struct lro *lro, struct iphdr *ip,
 				  struct tcphdr *tcp)
 {
 	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
@@ -7303,7 +7268,7 @@
 	return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2));
 }
 
-static void initiate_new_session(lro_t *lro, u8 *l2h,
+static void initiate_new_session(struct lro *lro, u8 *l2h,
 		     struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len)
 {
 	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
@@ -7329,12 +7294,12 @@
 	lro->in_use = 1;
 }
 
-static void update_L3L4_header(nic_t *sp, lro_t *lro)
+static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro)
 {
 	struct iphdr *ip = lro->iph;
 	struct tcphdr *tcp = lro->tcph;
-	u16 nchk;
-	StatInfo_t *statinfo = sp->mac_control.stats_info;
+	__sum16 nchk;
+	struct stat_block *statinfo = sp->mac_control.stats_info;
 	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
 
 	/* Update L3 header */
@@ -7360,7 +7325,7 @@
 	statinfo->sw_stat.num_aggregations++;
 }
 
-static void aggregate_new_rx(lro_t *lro, struct iphdr *ip,
+static void aggregate_new_rx(struct lro *lro, struct iphdr *ip,
 		struct tcphdr *tcp, u32 l4_pyld)
 {
 	DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
@@ -7382,7 +7347,7 @@
 	}
 }
 
-static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
+static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip,
 				    struct tcphdr *tcp, u32 tcp_pyld_len)
 {
 	u8 *ptr;
@@ -7440,8 +7405,8 @@
 }
 
 static int
-s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
-		      RxD_t *rxdp, nic_t *sp)
+s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
+		      struct RxD_t *rxdp, struct s2io_nic *sp)
 {
 	struct iphdr *ip;
 	struct tcphdr *tcph;
@@ -7458,7 +7423,7 @@
 	tcph = (struct tcphdr *)*tcp;
 	*tcp_len = get_l4_pyld_length(ip, tcph);
 	for (i=0; i<MAX_LRO_SESSIONS; i++) {
-		lro_t *l_lro = &sp->lro0_n[i];
+		struct lro *l_lro = &sp->lro0_n[i];
 		if (l_lro->in_use) {
 			if (check_for_socket_match(l_lro, ip, tcph))
 				continue;
@@ -7496,7 +7461,7 @@
 		}
 
 		for (i=0; i<MAX_LRO_SESSIONS; i++) {
-			lro_t *l_lro = &sp->lro0_n[i];
+			struct lro *l_lro = &sp->lro0_n[i];
 			if (!(l_lro->in_use)) {
 				*lro = l_lro;
 				ret = 3; /* Begin anew */
@@ -7535,9 +7500,9 @@
 	return ret;
 }
 
-static void clear_lro_session(lro_t *lro)
+static void clear_lro_session(struct lro *lro)
 {
-	static u16 lro_struct_size = sizeof(lro_t);
+	static u16 lro_struct_size = sizeof(struct lro);
 
 	memset(lro, 0, lro_struct_size);
 }
@@ -7547,14 +7512,14 @@
 	struct net_device *dev = skb->dev;
 
 	skb->protocol = eth_type_trans(skb, dev);
-#ifdef CONFIG_S2IO_NAPI
-	netif_receive_skb(skb);
-#else
-	netif_rx(skb);
-#endif
+	if (napi)
+		netif_receive_skb(skb);
+	else
+		netif_rx(skb);
 }
 
-static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb,
+static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
+			   struct sk_buff *skb,
 			   u32 tcp_len)
 {
 	struct sk_buff *first = lro->parent;
@@ -7566,6 +7531,7 @@
 		lro->last_frag->next = skb;
 	else
 		skb_shinfo(first)->frag_list = skb;
+	first->truesize += skb->truesize;
 	lro->last_frag = skb;
 	sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
 	return;
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 3b0bafd..0de0c65 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -30,6 +30,8 @@
 #undef SUCCESS
 #define SUCCESS 0
 #define FAILURE -1
+#define S2IO_MINUS_ONE 0xFFFFFFFFFFFFFFFFULL
+#define S2IO_MAX_PCI_CONFIG_SPACE_REINIT 100
 
 #define CHECKBIT(value, nbit) (value & (1 << nbit))
 
@@ -37,7 +39,7 @@
 #define MAX_FLICKER_TIME	60000 /* 60 Secs */
 
 /* Maximum outstanding splits to be configured into xena. */
-typedef enum xena_max_outstanding_splits {
+enum {
 	XENA_ONE_SPLIT_TRANSACTION = 0,
 	XENA_TWO_SPLIT_TRANSACTION = 1,
 	XENA_THREE_SPLIT_TRANSACTION = 2,
@@ -46,7 +48,7 @@
 	XENA_TWELVE_SPLIT_TRANSACTION = 5,
 	XENA_SIXTEEN_SPLIT_TRANSACTION = 6,
 	XENA_THIRTYTWO_SPLIT_TRANSACTION = 7
-} xena_max_outstanding_splits;
+};
 #define XENA_MAX_OUTSTANDING_SPLITS(n) (n << 4)
 
 /*  OS concerned variables and constants */
@@ -77,7 +79,7 @@
 #define S2IO_JUMBO_SIZE 9600
 
 /* Driver statistics maintained by driver */
-typedef struct {
+struct swStat {
 	unsigned long long single_ecc_errs;
 	unsigned long long double_ecc_errs;
 	unsigned long long parity_err_cnt;
@@ -92,10 +94,10 @@
 	unsigned long long flush_max_pkts;
 	unsigned long long sum_avg_pkts_aggregated;
 	unsigned long long num_aggregations;
-} swStat_t;
+};
 
 /* Xpak releated alarm and warnings */
-typedef struct {
+struct xpakStat {
 	u64 alarm_transceiver_temp_high;
 	u64 alarm_transceiver_temp_low;
 	u64 alarm_laser_bias_current_high;
@@ -110,11 +112,11 @@
 	u64 warn_laser_output_power_low;
 	u64 xpak_regs_stat;
 	u32 xpak_timer_count;
-} xpakStat_t;
+};
 
 
 /* The statistics block of Xena */
-typedef struct stat_block {
+struct stat_block {
 /* Tx MAC statistics counters. */
 	__le32 tmac_data_octets;
 	__le32 tmac_frms;
@@ -290,9 +292,9 @@
 	__le32 reserved_14;
 	__le32 link_fault_cnt;
 	u8  buffer[20];
-	swStat_t sw_stat;
-	xpakStat_t xpak_stat;
-} StatInfo_t;
+	struct swStat sw_stat;
+	struct xpakStat xpak_stat;
+};
 
 /*
  * Structures representing different init time configuration
@@ -315,7 +317,7 @@
 };
 
 /* Maintains Per FIFO related information. */
-typedef struct tx_fifo_config {
+struct tx_fifo_config {
 #define	MAX_AVAILABLE_TXDS	8192
 	u32 fifo_len;		/* specifies len of FIFO upto 8192, ie no of TxDLs */
 /* Priority definition */
@@ -332,11 +334,11 @@
 	u8 f_no_snoop;
 #define NO_SNOOP_TXD                0x01
 #define NO_SNOOP_TXD_BUFFER          0x02
-} tx_fifo_config_t;
+};
 
 
 /* Maintains per Ring related information */
-typedef struct rx_ring_config {
+struct rx_ring_config {
 	u32 num_rxd;		/*No of RxDs per Rx Ring */
 #define RX_RING_PRI_0               0	/* highest */
 #define RX_RING_PRI_1               1
@@ -357,7 +359,7 @@
 	u8 f_no_snoop;
 #define NO_SNOOP_RXD                0x01
 #define NO_SNOOP_RXD_BUFFER         0x02
-} rx_ring_config_t;
+};
 
 /* This structure provides contains values of the tunable parameters
  * of the H/W
@@ -367,7 +369,7 @@
 	u32 tx_fifo_num;	/*Number of Tx FIFOs */
 
 	u8 fifo_mapping[MAX_TX_FIFOS];
-	tx_fifo_config_t tx_cfg[MAX_TX_FIFOS];	/*Per-Tx FIFO config */
+	struct tx_fifo_config tx_cfg[MAX_TX_FIFOS];	/*Per-Tx FIFO config */
 	u32 max_txds;		/*Max no. of Tx buffer descriptor per TxDL */
 	u64 tx_intr_type;
 	/* Specifies if Tx Intr is UTILZ or PER_LIST type. */
@@ -376,7 +378,7 @@
 	u32 rx_ring_num;	/*Number of receive rings */
 #define MAX_RX_BLOCKS_PER_RING  150
 
-	rx_ring_config_t rx_cfg[MAX_RX_RINGS];	/*Per-Rx Ring config */
+	struct rx_ring_config rx_cfg[MAX_RX_RINGS];	/*Per-Rx Ring config */
 	u8 bimodal;		/*Flag for setting bimodal interrupts*/
 
 #define HEADER_ETHERNET_II_802_3_SIZE 14
@@ -395,14 +397,14 @@
 };
 
 /* Structure representing MAC Addrs */
-typedef struct mac_addr {
+struct mac_addr {
 	u8 mac_addr[ETH_ALEN];
-} macaddr_t;
+};
 
 /* Structure that represent every FIFO element in the BAR1
  * Address location.
  */
-typedef struct _TxFIFO_element {
+struct TxFIFO_element {
 	u64 TxDL_Pointer;
 
 	u64 List_Control;
@@ -413,10 +415,10 @@
 #define TX_FIFO_SPECIAL_FUNC           BIT(23)
 #define TX_FIFO_DS_NO_SNOOP            BIT(31)
 #define TX_FIFO_BUFF_NO_SNOOP          BIT(30)
-} TxFIFO_element_t;
+};
 
 /* Tx descriptor structure */
-typedef struct _TxD {
+struct TxD {
 	u64 Control_1;
 /* bit mask */
 #define TXD_LIST_OWN_XENA       BIT(7)
@@ -447,16 +449,16 @@
 
 	u64 Buffer_Pointer;
 	u64 Host_Control;	/* reserved for host */
-} TxD_t;
+};
 
 /* Structure to hold the phy and virt addr of every TxDL. */
-typedef struct list_info_hold {
+struct list_info_hold {
 	dma_addr_t list_phy_addr;
 	void *list_virt_addr;
-} list_info_hold_t;
+};
 
 /* Rx descriptor structure for 1 buffer mode */
-typedef struct _RxD_t {
+struct RxD_t {
 	u64 Host_Control;	/* reserved for host */
 	u64 Control_1;
 #define RXD_OWN_XENA            BIT(7)
@@ -481,21 +483,21 @@
 #define SET_NUM_TAG(val)       vBIT(val,16,32)
 
 
-} RxD_t;
+};
 /* Rx descriptor structure for 1 buffer mode */
-typedef struct _RxD1_t {
-	struct _RxD_t h;
+struct RxD1 {
+	struct RxD_t h;
 
 #define MASK_BUFFER0_SIZE_1       vBIT(0x3FFF,2,14)
 #define SET_BUFFER0_SIZE_1(val)   vBIT(val,2,14)
 #define RXD_GET_BUFFER0_SIZE_1(_Control_2) \
 	(u16)((_Control_2 & MASK_BUFFER0_SIZE_1) >> 48)
 	u64 Buffer0_ptr;
-} RxD1_t;
+};
 /* Rx descriptor structure for 3 or 2 buffer mode */
 
-typedef struct _RxD3_t {
-	struct _RxD_t h;
+struct RxD3 {
+	struct RxD_t h;
 
 #define MASK_BUFFER0_SIZE_3       vBIT(0xFF,2,14)
 #define MASK_BUFFER1_SIZE_3       vBIT(0xFFFF,16,16)
@@ -515,15 +517,15 @@
 	u64 Buffer0_ptr;
 	u64 Buffer1_ptr;
 	u64 Buffer2_ptr;
-} RxD3_t;
+};
 
 
 /* Structure that represents the Rx descriptor block which contains
  * 128 Rx descriptors.
  */
-typedef struct _RxD_block {
+struct RxD_block {
 #define MAX_RXDS_PER_BLOCK_1            127
-	RxD1_t rxd[MAX_RXDS_PER_BLOCK_1];
+	struct RxD1 rxd[MAX_RXDS_PER_BLOCK_1];
 
 	u64 reserved_0;
 #define END_OF_BLOCK    0xFEFFFFFFFFFFFFFFULL
@@ -533,22 +535,22 @@
 	u64 pNext_RxD_Blk_physical;	/* Buff0_ptr.In a 32 bit arch
 					 * the upper 32 bits should
 					 * be 0 */
-} RxD_block_t;
+};
 
 #define SIZE_OF_BLOCK	4096
 
-#define RXD_MODE_1	0
-#define RXD_MODE_3A	1
-#define RXD_MODE_3B	2
+#define RXD_MODE_1	0 /* One Buffer mode */
+#define RXD_MODE_3A	1 /* Three Buffer mode */
+#define RXD_MODE_3B	2 /* Two Buffer mode */
 
 /* Structure to hold virtual addresses of Buf0 and Buf1 in
  * 2buf mode. */
-typedef struct bufAdd {
+struct buffAdd {
 	void *ba_0_org;
 	void *ba_1_org;
 	void *ba_0;
 	void *ba_1;
-} buffAdd_t;
+};
 
 /* Structure which stores all the MAC control parameters */
 
@@ -556,43 +558,46 @@
  * from which the Rx Interrupt processor can start picking
  * up the RxDs for processing.
  */
-typedef struct _rx_curr_get_info_t {
+struct rx_curr_get_info {
 	u32 block_index;
 	u32 offset;
 	u32 ring_len;
-} rx_curr_get_info_t;
+};
 
-typedef rx_curr_get_info_t rx_curr_put_info_t;
+struct rx_curr_put_info {
+	u32 block_index;
+	u32 offset;
+	u32 ring_len;
+};
 
 /* This structure stores the offset of the TxDl in the FIFO
  * from which the Tx Interrupt processor can start picking
  * up the TxDLs for send complete interrupt processing.
  */
-typedef struct {
+struct tx_curr_get_info {
 	u32 offset;
 	u32 fifo_len;
-} tx_curr_get_info_t;
+};
 
-typedef tx_curr_get_info_t tx_curr_put_info_t;
+struct tx_curr_put_info {
+	u32 offset;
+	u32 fifo_len;
+};
 
-
-typedef struct rxd_info {
+struct rxd_info {
 	void *virt_addr;
 	dma_addr_t dma_addr;
-}rxd_info_t;
+};
 
 /* Structure that holds the Phy and virt addresses of the Blocks */
-typedef struct rx_block_info {
+struct rx_block_info {
 	void *block_virt_addr;
 	dma_addr_t block_dma_addr;
-	rxd_info_t *rxds;
-} rx_block_info_t;
-
-/* pre declaration of the nic structure */
-typedef struct s2io_nic nic_t;
+	struct rxd_info *rxds;
+};
 
 /* Ring specific structure */
-typedef struct ring_info {
+struct ring_info {
 	/* The ring number */
 	int ring_no;
 
@@ -600,7 +605,7 @@
 	 *  Place holders for the virtual and physical addresses of
 	 *  all the Rx Blocks
 	 */
-	rx_block_info_t rx_blocks[MAX_RX_BLOCKS_PER_RING];
+	struct rx_block_info rx_blocks[MAX_RX_BLOCKS_PER_RING];
 	int block_count;
 	int pkt_cnt;
 
@@ -608,26 +613,24 @@
 	 * Put pointer info which indictes which RxD has to be replenished
 	 * with a new buffer.
 	 */
-	rx_curr_put_info_t rx_curr_put_info;
+	struct rx_curr_put_info rx_curr_put_info;
 
 	/*
 	 * Get pointer info which indictes which is the last RxD that was
 	 * processed by the driver.
 	 */
-	rx_curr_get_info_t rx_curr_get_info;
+	struct rx_curr_get_info rx_curr_get_info;
 
-#ifndef CONFIG_S2IO_NAPI
 	/* Index to the absolute position of the put pointer of Rx ring */
 	int put_pos;
-#endif
 
 	/* Buffer Address store. */
-	buffAdd_t **ba;
-	nic_t *nic;
-} ring_info_t;
+	struct buffAdd **ba;
+	struct s2io_nic *nic;
+};
 
 /* Fifo specific structure */
-typedef struct fifo_info {
+struct fifo_info {
 	/* FIFO number */
 	int fifo_no;
 
@@ -635,40 +638,40 @@
 	int max_txds;
 
 	/* Place holder of all the TX List's Phy and Virt addresses. */
-	list_info_hold_t *list_info;
+	struct list_info_hold *list_info;
 
 	/*
 	 * Current offset within the tx FIFO where driver would write
 	 * new Tx frame
 	 */
-	tx_curr_put_info_t tx_curr_put_info;
+	struct tx_curr_put_info tx_curr_put_info;
 
 	/*
 	 * Current offset within tx FIFO from where the driver would start freeing
 	 * the buffers
 	 */
-	tx_curr_get_info_t tx_curr_get_info;
+	struct tx_curr_get_info tx_curr_get_info;
 
-	nic_t *nic;
-}fifo_info_t;
+	struct s2io_nic *nic;
+};
 
 /* Information related to the Tx and Rx FIFOs and Rings of Xena
  * is maintained in this structure.
  */
-typedef struct mac_info {
+struct mac_info {
 /* tx side stuff */
 	/* logical pointer of start of each Tx FIFO */
-	TxFIFO_element_t __iomem *tx_FIFO_start[MAX_TX_FIFOS];
+	struct TxFIFO_element __iomem *tx_FIFO_start[MAX_TX_FIFOS];
 
 	/* Fifo specific structure */
-	fifo_info_t fifos[MAX_TX_FIFOS];
+	struct fifo_info fifos[MAX_TX_FIFOS];
 
 	/* Save virtual address of TxD page with zero DMA addr(if any) */
 	void *zerodma_virt_addr;
 
 /* rx side stuff */
 	/* Ring specific structure */
-	ring_info_t rings[MAX_RX_RINGS];
+	struct ring_info rings[MAX_RX_RINGS];
 
 	u16 rmac_pause_time;
 	u16 mc_pause_threshold_q0q3;
@@ -677,14 +680,14 @@
 	void *stats_mem;	/* orignal pointer to allocated mem */
 	dma_addr_t stats_mem_phy;	/* Physical address of the stat block */
 	u32 stats_mem_sz;
-	StatInfo_t *stats_info;	/* Logical address of the stat block */
-} mac_info_t;
+	struct stat_block *stats_info;	/* Logical address of the stat block */
+};
 
 /* structure representing the user defined MAC addresses */
-typedef struct {
+struct usr_addr {
 	char addr[ETH_ALEN];
 	int usage_cnt;
-} usr_addr_t;
+};
 
 /* Default Tunable parameters of the NIC. */
 #define DEFAULT_FIFO_0_LEN 4096
@@ -717,36 +720,34 @@
 };
 
 /* Data structure to represent a LRO session */
-typedef struct lro {
+struct lro {
 	struct sk_buff	*parent;
 	struct sk_buff  *last_frag;
 	u8		*l2h;
 	struct iphdr	*iph;
 	struct tcphdr	*tcph;
 	u32		tcp_next_seq;
-	u32		tcp_ack;
+	__be32		tcp_ack;
 	int		total_len;
 	int		frags_len;
 	int		sg_num;
 	int		in_use;
-	u16		window;
+	__be16		window;
 	u32		cur_tsval;
 	u32		cur_tsecr;
 	u8		saw_ts;
-}lro_t;
+};
 
 /* Structure representing one instance of the NIC */
 struct s2io_nic {
 	int rxd_mode;
-#ifdef CONFIG_S2IO_NAPI
 	/*
 	 * Count of packets to be processed in a given iteration, it will be indicated
 	 * by the quota field of the device structure when NAPI is enabled.
 	 */
 	int pkts_to_process;
-#endif
 	struct net_device *dev;
-	mac_info_t mac_control;
+	struct mac_info mac_control;
 	struct config_param config;
 	struct pci_dev *pdev;
 	void __iomem *bar0;
@@ -754,8 +755,8 @@
 #define MAX_MAC_SUPPORTED   16
 #define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED
 
-	macaddr_t def_mac_addr[MAX_MAC_SUPPORTED];
-	macaddr_t pre_mac_addr[MAX_MAC_SUPPORTED];
+	struct mac_addr def_mac_addr[MAX_MAC_SUPPORTED];
+	struct mac_addr pre_mac_addr[MAX_MAC_SUPPORTED];
 
 	struct net_device_stats stats;
 	int high_dma_flag;
@@ -775,9 +776,7 @@
 	atomic_t rx_bufs_left[MAX_RX_RINGS];
 
 	spinlock_t tx_lock;
-#ifndef CONFIG_S2IO_NAPI
 	spinlock_t put_lock;
-#endif
 
 #define PROMISC     1
 #define ALL_MULTI   2
@@ -785,7 +784,7 @@
 #define MAX_ADDRS_SUPPORTED 64
 	u16 usr_addr_count;
 	u16 mc_addr_count;
-	usr_addr_t usr_addrs[MAX_ADDRS_SUPPORTED];
+	struct usr_addr usr_addrs[MAX_ADDRS_SUPPORTED];
 
 	u16 m_cast_flg;
 	u16 all_multi_pos;
@@ -841,7 +840,7 @@
 	u8 device_type;
 
 #define MAX_LRO_SESSIONS	32
-	lro_t lro0_n[MAX_LRO_SESSIONS];
+	struct lro lro0_n[MAX_LRO_SESSIONS];
 	unsigned long	clubbed_frms_cnt;
 	unsigned long	sending_both;
 	u8		lro;
@@ -855,8 +854,9 @@
 	spinlock_t	rx_lock;
 	atomic_t	isr_cnt;
 	u64 *ufo_in_band_v;
-#define VPD_PRODUCT_NAME_LEN 50
-	u8  product_name[VPD_PRODUCT_NAME_LEN];
+#define VPD_STRING_LEN 80
+	u8  product_name[VPD_STRING_LEN];
+	u8  serial_num[VPD_STRING_LEN];
 };
 
 #define RESET_ERROR 1;
@@ -975,43 +975,50 @@
 static int init_shared_mem(struct s2io_nic *sp);
 static void free_shared_mem(struct s2io_nic *sp);
 static int init_nic(struct s2io_nic *nic);
-static void rx_intr_handler(ring_info_t *ring_data);
-static void tx_intr_handler(fifo_info_t *fifo_data);
+static void rx_intr_handler(struct ring_info *ring_data);
+static void tx_intr_handler(struct fifo_info *fifo_data);
 static void alarm_intr_handler(struct s2io_nic *sp);
 
 static int s2io_starter(void);
+static void s2io_closer(void);
 static void s2io_tx_watchdog(struct net_device *dev);
 static void s2io_tasklet(unsigned long dev_addr);
 static void s2io_set_multicast(struct net_device *dev);
-static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp);
-static void s2io_link(nic_t * sp, int link);
-#if defined(CONFIG_S2IO_NAPI)
+static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp);
+static void s2io_link(struct s2io_nic * sp, int link);
+static void s2io_reset(struct s2io_nic * sp);
 static int s2io_poll(struct net_device *dev, int *budget);
-#endif
-static void s2io_init_pci(nic_t * sp);
+static void s2io_init_pci(struct s2io_nic * sp);
 static int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
 static void s2io_alarm_handle(unsigned long data);
-static int s2io_enable_msi(nic_t *nic);
+static int s2io_enable_msi(struct s2io_nic *nic);
 static irqreturn_t s2io_msi_handle(int irq, void *dev_id);
 static irqreturn_t
 s2io_msix_ring_handle(int irq, void *dev_id);
 static irqreturn_t
 s2io_msix_fifo_handle(int irq, void *dev_id);
 static irqreturn_t s2io_isr(int irq, void *dev_id);
-static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag);
+static int verify_xena_quiescence(struct s2io_nic *sp);
 static const struct ethtool_ops netdev_ethtool_ops;
 static void s2io_set_link(struct work_struct *work);
-static int s2io_set_swapper(nic_t * sp);
-static void s2io_card_down(nic_t *nic);
-static int s2io_card_up(nic_t *nic);
+static int s2io_set_swapper(struct s2io_nic * sp);
+static void s2io_card_down(struct s2io_nic *nic);
+static int s2io_card_up(struct s2io_nic *nic);
 static int get_xena_rev_id(struct pci_dev *pdev);
-static void restore_xmsi_data(nic_t *nic);
+static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit);
+static int s2io_add_isr(struct s2io_nic * sp);
+static void s2io_rem_isr(struct s2io_nic * sp);
 
-static int s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro, RxD_t *rxdp, nic_t *sp);
-static void clear_lro_session(lro_t *lro);
+static void restore_xmsi_data(struct s2io_nic *nic);
+
+static int
+s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
+		      struct RxD_t *rxdp, struct s2io_nic *sp);
+static void clear_lro_session(struct lro *lro);
 static void queue_rx_frame(struct sk_buff *skb);
-static void update_L3L4_header(nic_t *sp, lro_t *lro);
-static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, u32 tcp_len);
+static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro);
+static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
+			   struct sk_buff *skb, u32 tcp_len);
 
 #define s2io_tcp_mss(skb) skb_shinfo(skb)->gso_size
 #define s2io_udp_mss(skb) skb_shinfo(skb)->gso_size
diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c
new file mode 100644
index 0000000..7f800fe
--- /dev/null
+++ b/drivers/net/sc92031.c
@@ -0,0 +1,1620 @@
+/*  Silan SC92031 PCI Fast Ethernet Adapter driver
+ *
+ *  Based on vendor drivers:
+ *  Silan Fast Ethernet Netcard Driver:
+ *    MODULE_AUTHOR ("gaoyonghong");
+ *    MODULE_DESCRIPTION ("SILAN Fast Ethernet driver");
+ *    MODULE_LICENSE("GPL");
+ *  8139D Fast Ethernet driver:
+ *    (C) 2002 by gaoyonghong
+ *    MODULE_AUTHOR ("gaoyonghong");
+ *    MODULE_DESCRIPTION ("Rsltek 8139D PCI Fast Ethernet Adapter driver");
+ *    MODULE_LICENSE("GPL");
+ *  Both are almost identical and seem to be based on pci-skeleton.c
+ *
+ *  Rewritten for 2.6 by Cesar Eduardo Barros
+ */
+
+/* Note about set_mac_address: I don't know how to change the hardware
+ * matching, so you need to enable IFF_PROMISC when using it.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/crc32.h>
+
+#include <asm/irq.h>
+
+#define PCI_VENDOR_ID_SILAN		0x1904
+#define PCI_DEVICE_ID_SILAN_SC92031	0x2031
+#define PCI_DEVICE_ID_SILAN_8139D	0x8139
+
+#define SC92031_NAME "sc92031"
+#define SC92031_DESCRIPTION "Silan SC92031 PCI Fast Ethernet Adapter driver"
+#define SC92031_VERSION "2.0c"
+
+/* BAR 0 is MMIO, BAR 1 is PIO */
+#ifndef SC92031_USE_BAR
+#define SC92031_USE_BAR 0
+#endif
+
+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). */
+static int multicast_filter_limit = 64;
+module_param(multicast_filter_limit, int, 0);
+MODULE_PARM_DESC(multicast_filter_limit,
+	"Maximum number of filtered multicast addresses");
+
+static int media;
+module_param(media, int, 0);
+MODULE_PARM_DESC(media, "Media type (0x00 = autodetect,"
+	" 0x01 = 10M half, 0x02 = 10M full,"
+	" 0x04 = 100M half, 0x08 = 100M full)");
+
+/* Size of the in-memory receive ring. */
+#define  RX_BUF_LEN_IDX  3 /* 0==8K, 1==16K, 2==32K, 3==64K ,4==128K*/
+#define  RX_BUF_LEN	(8192 << RX_BUF_LEN_IDX)
+
+/* Number of Tx descriptor registers. */
+#define  NUM_TX_DESC	   4
+
+/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
+#define  MAX_ETH_FRAME_SIZE	  1536
+
+/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
+#define  TX_BUF_SIZE       MAX_ETH_FRAME_SIZE
+#define  TX_BUF_TOT_LEN    (TX_BUF_SIZE * NUM_TX_DESC)
+
+/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024, 7==end of packet. */
+#define  RX_FIFO_THRESH    7     /* Rx buffer level before first PCI xfer.  */
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define  TX_TIMEOUT     (4*HZ)
+
+#define  SILAN_STATS_NUM    2    /* number of ETHTOOL_GSTATS */
+
+/* media options */
+#define  AUTOSELECT    0x00
+#define  M10_HALF      0x01
+#define  M10_FULL      0x02
+#define  M100_HALF     0x04
+#define  M100_FULL     0x08
+
+ /* Symbolic offsets to registers. */
+enum  silan_registers {
+   Config0    = 0x00,         // Config0
+   Config1    = 0x04,         // Config1
+   RxBufWPtr  = 0x08,         // Rx buffer writer poiter
+   IntrStatus = 0x0C,         // Interrupt status
+   IntrMask   = 0x10,         // Interrupt mask
+   RxbufAddr  = 0x14,         // Rx buffer start address
+   RxBufRPtr  = 0x18,         // Rx buffer read pointer
+   Txstatusall = 0x1C,        // Transmit status of all descriptors
+   TxStatus0  = 0x20,	      // Transmit status (Four 32bit registers).
+   TxAddr0    = 0x30,         // Tx descriptors (also four 32bit).
+   RxConfig   = 0x40,         // Rx configuration
+   MAC0	      = 0x44,	      // Ethernet hardware address.
+   MAR0	      = 0x4C,	      // Multicast filter.
+   RxStatus0  = 0x54,         // Rx status
+   TxConfig   = 0x5C,         // Tx configuration
+   PhyCtrl    = 0x60,         // physical control
+   FlowCtrlConfig = 0x64,     // flow control
+   Miicmd0    = 0x68,         // Mii command0 register
+   Miicmd1    = 0x6C,         // Mii command1 register
+   Miistatus  = 0x70,         // Mii status register
+   Timercnt   = 0x74,         // Timer counter register
+   TimerIntr  = 0x78,         // Timer interrupt register
+   PMConfig   = 0x7C,         // Power Manager configuration
+   CRC0       = 0x80,         // Power Manager CRC ( Two 32bit regisers)
+   Wakeup0    = 0x88,         // power Manager wakeup( Eight 64bit regiser)
+   LSBCRC0    = 0xC8,         // power Manager LSBCRC(Two 32bit regiser)
+   TestD0     = 0xD0,
+   TestD4     = 0xD4,
+   TestD8     = 0xD8,
+};
+
+#define MII_BMCR            0        // Basic mode control register
+#define MII_BMSR            1        // Basic mode status register
+#define MII_JAB             16
+#define MII_OutputStatus    24
+
+#define BMCR_FULLDPLX       0x0100    // Full duplex
+#define BMCR_ANRESTART      0x0200    // Auto negotiation restart
+#define BMCR_ANENABLE       0x1000    // Enable auto negotiation
+#define BMCR_SPEED100       0x2000    // Select 100Mbps
+#define BMSR_LSTATUS        0x0004    // Link status
+#define PHY_16_JAB_ENB      0x1000
+#define PHY_16_PORT_ENB     0x1
+
+enum IntrStatusBits {
+   LinkFail       = 0x80000000,
+   LinkOK         = 0x40000000,
+   TimeOut        = 0x20000000,
+   RxOverflow     = 0x0040,
+   RxOK           = 0x0020,
+   TxOK           = 0x0001,
+   IntrBits = LinkFail|LinkOK|TimeOut|RxOverflow|RxOK|TxOK,
+};
+
+enum TxStatusBits {
+   TxCarrierLost = 0x20000000,
+   TxAborted     = 0x10000000,
+   TxOutOfWindow = 0x08000000,
+   TxNccShift    = 22,
+   EarlyTxThresShift = 16,
+   TxStatOK      = 0x8000,
+   TxUnderrun    = 0x4000,
+   TxOwn         = 0x2000,
+};
+
+enum RxStatusBits {
+   RxStatesOK   = 0x80000,
+   RxBadAlign   = 0x40000,
+   RxHugeFrame  = 0x20000,
+   RxSmallFrame = 0x10000,
+   RxCRCOK      = 0x8000,
+   RxCrlFrame   = 0x4000,
+   Rx_Broadcast = 0x2000,
+   Rx_Multicast = 0x1000,
+   RxAddrMatch  = 0x0800,
+   MiiErr       = 0x0400,
+};
+
+enum RxConfigBits {
+   RxFullDx    = 0x80000000,
+   RxEnb       = 0x40000000,
+   RxSmall     = 0x20000000,
+   RxHuge      = 0x10000000,
+   RxErr       = 0x08000000,
+   RxAllphys   = 0x04000000,
+   RxMulticast = 0x02000000,
+   RxBroadcast = 0x01000000,
+   RxLoopBack  = (1 << 23) | (1 << 22),
+   LowThresholdShift  = 12,
+   HighThresholdShift = 2,
+};
+
+enum TxConfigBits {
+   TxFullDx       = 0x80000000,
+   TxEnb          = 0x40000000,
+   TxEnbPad       = 0x20000000,
+   TxEnbHuge      = 0x10000000,
+   TxEnbFCS       = 0x08000000,
+   TxNoBackOff    = 0x04000000,
+   TxEnbPrem      = 0x02000000,
+   TxCareLostCrs  = 0x1000000,
+   TxExdCollNum   = 0xf00000,
+   TxDataRate     = 0x80000,
+};
+
+enum PhyCtrlconfigbits {
+   PhyCtrlAne         = 0x80000000,
+   PhyCtrlSpd100      = 0x40000000,
+   PhyCtrlSpd10       = 0x20000000,
+   PhyCtrlPhyBaseAddr = 0x1f000000,
+   PhyCtrlDux         = 0x800000,
+   PhyCtrlReset       = 0x400000,
+};
+
+enum FlowCtrlConfigBits {
+   FlowCtrlFullDX = 0x80000000,
+   FlowCtrlEnb    = 0x40000000,
+};
+
+enum Config0Bits {
+   Cfg0_Reset  = 0x80000000,
+   Cfg0_Anaoff = 0x40000000,
+   Cfg0_LDPS   = 0x20000000,
+};
+
+enum Config1Bits {
+   Cfg1_EarlyRx = 1 << 31,
+   Cfg1_EarlyTx = 1 << 30,
+
+   //rx buffer size
+   Cfg1_Rcv8K   = 0x0,
+   Cfg1_Rcv16K  = 0x1,
+   Cfg1_Rcv32K  = 0x3,
+   Cfg1_Rcv64K  = 0x7,
+   Cfg1_Rcv128K = 0xf,
+};
+
+enum MiiCmd0Bits {
+   Mii_Divider = 0x20000000,
+   Mii_WRITE   = 0x400000,
+   Mii_READ    = 0x200000,
+   Mii_SCAN    = 0x100000,
+   Mii_Tamod   = 0x80000,
+   Mii_Drvmod  = 0x40000,
+   Mii_mdc     = 0x20000,
+   Mii_mdoen   = 0x10000,
+   Mii_mdo     = 0x8000,
+   Mii_mdi     = 0x4000,
+};
+
+enum MiiStatusBits {
+    Mii_StatusBusy = 0x80000000,
+};
+
+enum PMConfigBits {
+   PM_Enable  = 1 << 31,
+   PM_LongWF  = 1 << 30,
+   PM_Magic   = 1 << 29,
+   PM_LANWake = 1 << 28,
+   PM_LWPTN   = (1 << 27 | 1<< 26),
+   PM_LinkUp  = 1 << 25,
+   PM_WakeUp  = 1 << 24,
+};
+
+/* Locking rules:
+ * priv->lock protects most of the fields of priv and most of the
+ * hardware registers. It does not have to protect against softirqs
+ * between sc92031_disable_interrupts and sc92031_enable_interrupts;
+ * it also does not need to be used in ->open and ->stop while the
+ * device interrupts are off.
+ * Not having to protect against softirqs is very useful due to heavy
+ * use of mdelay() at _sc92031_reset.
+ * Functions prefixed with _sc92031_ must be called with the lock held;
+ * functions prefixed with sc92031_ must be called without the lock held.
+ * Use mmiowb() before unlocking if the hardware was written to.
+ */
+
+/* Locking rules for the interrupt:
+ * - the interrupt and the tasklet never run at the same time
+ * - neither run between sc92031_disable_interrupts and
+ *   sc92031_enable_interrupt
+ */
+
+struct sc92031_priv {
+	spinlock_t		lock;
+	/* iomap.h cookie */
+	void __iomem		*port_base;
+	/* pci device structure */
+	struct pci_dev		*pdev;
+	/* tasklet */
+	struct tasklet_struct	tasklet;
+
+	/* CPU address of rx ring */
+	void			*rx_ring;
+	/* PCI address of rx ring */
+	dma_addr_t		rx_ring_dma_addr;
+	/* PCI address of rx ring read pointer */
+	dma_addr_t		rx_ring_tail;
+
+	/* tx ring write index */
+	unsigned		tx_head;
+	/* tx ring read index */
+	unsigned		tx_tail;
+	/* CPU address of tx bounce buffer */
+	void			*tx_bufs;
+	/* PCI address of tx bounce buffer */
+	dma_addr_t		tx_bufs_dma_addr;
+
+	/* copies of some hardware registers */
+	u32			intr_status;
+	atomic_t		intr_mask;
+	u32			rx_config;
+	u32			tx_config;
+	u32			pm_config;
+
+	/* copy of some flags from dev->flags */
+	unsigned int		mc_flags;
+
+	/* for ETHTOOL_GSTATS */
+	u64			tx_timeouts;
+	u64			rx_loss;
+
+	/* for dev->get_stats */
+	long			rx_value;
+	struct net_device_stats	stats;
+};
+
+/* I don't know which registers can be safely read; however, I can guess
+ * MAC0 is one of them. */
+static inline void _sc92031_dummy_read(void __iomem *port_base)
+{
+	ioread32(port_base + MAC0);
+}
+
+static u32 _sc92031_mii_wait(void __iomem *port_base)
+{
+	u32 mii_status;
+
+	do {
+		udelay(10);
+		mii_status = ioread32(port_base + Miistatus);
+	} while (mii_status & Mii_StatusBusy);
+
+	return mii_status;
+}
+
+static u32 _sc92031_mii_cmd(void __iomem *port_base, u32 cmd0, u32 cmd1)
+{
+	iowrite32(Mii_Divider, port_base + Miicmd0);
+
+	_sc92031_mii_wait(port_base);
+
+	iowrite32(cmd1, port_base + Miicmd1);
+	iowrite32(Mii_Divider | cmd0, port_base + Miicmd0);
+
+	return _sc92031_mii_wait(port_base);
+}
+
+static void _sc92031_mii_scan(void __iomem *port_base)
+{
+	_sc92031_mii_cmd(port_base, Mii_SCAN, 0x1 << 6);
+}
+
+static u16 _sc92031_mii_read(void __iomem *port_base, unsigned reg)
+{
+	return _sc92031_mii_cmd(port_base, Mii_READ, reg << 6) >> 13;
+}
+
+static void _sc92031_mii_write(void __iomem *port_base, unsigned reg, u16 val)
+{
+	_sc92031_mii_cmd(port_base, Mii_WRITE, (reg << 6) | ((u32)val << 11));
+}
+
+static void sc92031_disable_interrupts(struct net_device *dev)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+
+	/* tell the tasklet/interrupt not to enable interrupts */
+	atomic_set(&priv->intr_mask, 0);
+	wmb();
+
+	/* stop interrupts */
+	iowrite32(0, port_base + IntrMask);
+	_sc92031_dummy_read(port_base);
+	mmiowb();
+
+	/* wait for any concurrent interrupt/tasklet to finish */
+	synchronize_irq(dev->irq);
+	tasklet_disable(&priv->tasklet);
+}
+
+static void sc92031_enable_interrupts(struct net_device *dev)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+
+	tasklet_enable(&priv->tasklet);
+
+	atomic_set(&priv->intr_mask, IntrBits);
+	wmb();
+
+	iowrite32(IntrBits, port_base + IntrMask);
+	mmiowb();
+}
+
+static void _sc92031_disable_tx_rx(struct net_device *dev)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+
+	priv->rx_config &= ~RxEnb;
+	priv->tx_config &= ~TxEnb;
+	iowrite32(priv->rx_config, port_base + RxConfig);
+	iowrite32(priv->tx_config, port_base + TxConfig);
+}
+
+static void _sc92031_enable_tx_rx(struct net_device *dev)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+
+	priv->rx_config |= RxEnb;
+	priv->tx_config |= TxEnb;
+	iowrite32(priv->rx_config, port_base + RxConfig);
+	iowrite32(priv->tx_config, port_base + TxConfig);
+}
+
+static void _sc92031_tx_clear(struct net_device *dev)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+
+	while (priv->tx_head - priv->tx_tail > 0) {
+		priv->tx_tail++;
+		priv->stats.tx_dropped++;
+	}
+	priv->tx_head = priv->tx_tail = 0;
+}
+
+static void _sc92031_set_mar(struct net_device *dev)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+	u32 mar0 = 0, mar1 = 0;
+
+	if ((dev->flags & IFF_PROMISC)
+			|| dev->mc_count > multicast_filter_limit
+			|| (dev->flags & IFF_ALLMULTI))
+		mar0 = mar1 = 0xffffffff;
+	else if (dev->flags & IFF_MULTICAST) {
+		struct dev_mc_list *mc_list;
+
+		for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) {
+			u32 crc;
+			unsigned bit = 0;
+
+			crc = ~ether_crc(ETH_ALEN, mc_list->dmi_addr);
+			crc >>= 24;
+
+			if (crc & 0x01)	bit |= 0x02;
+			if (crc & 0x02)	bit |= 0x01;
+			if (crc & 0x10)	bit |= 0x20;
+			if (crc & 0x20)	bit |= 0x10;
+			if (crc & 0x40)	bit |= 0x08;
+			if (crc & 0x80)	bit |= 0x04;
+
+			if (bit > 31)
+				mar0 |= 0x1 << (bit - 32);
+			else
+				mar1 |= 0x1 << bit;
+		}
+	}
+
+	iowrite32(mar0, port_base + MAR0);
+	iowrite32(mar1, port_base + MAR0 + 4);
+}
+
+static void _sc92031_set_rx_config(struct net_device *dev)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+	unsigned int old_mc_flags;
+	u32 rx_config_bits = 0;
+
+	old_mc_flags = priv->mc_flags;
+
+	if (dev->flags & IFF_PROMISC)
+		rx_config_bits |= RxSmall | RxHuge | RxErr | RxBroadcast
+				| RxMulticast | RxAllphys;
+
+	if (dev->flags & (IFF_ALLMULTI | IFF_MULTICAST))
+		rx_config_bits |= RxMulticast;
+
+	if (dev->flags & IFF_BROADCAST)
+		rx_config_bits |= RxBroadcast;
+
+	priv->rx_config &= ~(RxSmall | RxHuge | RxErr | RxBroadcast
+			| RxMulticast | RxAllphys);
+	priv->rx_config |= rx_config_bits;
+
+	priv->mc_flags = dev->flags & (IFF_PROMISC | IFF_ALLMULTI
+			| IFF_MULTICAST | IFF_BROADCAST);
+
+	if (netif_carrier_ok(dev) && priv->mc_flags != old_mc_flags)
+		iowrite32(priv->rx_config, port_base + RxConfig);
+}
+
+static bool _sc92031_check_media(struct net_device *dev)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+	u16 bmsr;
+
+	bmsr = _sc92031_mii_read(port_base, MII_BMSR);
+	rmb();
+	if (bmsr & BMSR_LSTATUS) {
+		bool speed_100, duplex_full;
+		u32 flow_ctrl_config = 0;
+		u16 output_status = _sc92031_mii_read(port_base,
+				MII_OutputStatus);
+		_sc92031_mii_scan(port_base);
+
+		speed_100 = output_status & 0x2;
+		duplex_full = output_status & 0x4;
+
+		/* Initial Tx/Rx configuration */
+		priv->rx_config = (0x40 << LowThresholdShift) | (0x1c0 << HighThresholdShift);
+		priv->tx_config = 0x48800000;
+
+		/* NOTE: vendor driver had dead code here to enable tx padding */
+
+		if (!speed_100)
+			priv->tx_config |= 0x80000;
+
+		// configure rx mode
+		_sc92031_set_rx_config(dev);
+
+		if (duplex_full) {
+			priv->rx_config |= RxFullDx;
+			priv->tx_config |= TxFullDx;
+			flow_ctrl_config = FlowCtrlFullDX | FlowCtrlEnb;
+		} else {
+			priv->rx_config &= ~RxFullDx;
+			priv->tx_config &= ~TxFullDx;
+		}
+
+		_sc92031_set_mar(dev);
+		_sc92031_set_rx_config(dev);
+		_sc92031_enable_tx_rx(dev);
+		iowrite32(flow_ctrl_config, port_base + FlowCtrlConfig);
+
+		netif_carrier_on(dev);
+
+		if (printk_ratelimit())
+			printk(KERN_INFO "%s: link up, %sMbps, %s-duplex\n",
+				dev->name,
+				speed_100 ? "100" : "10",
+				duplex_full ? "full" : "half");
+		return true;
+	} else {
+		_sc92031_mii_scan(port_base);
+
+		netif_carrier_off(dev);
+
+		_sc92031_disable_tx_rx(dev);
+
+		if (printk_ratelimit())
+			printk(KERN_INFO "%s: link down\n", dev->name);
+		return false;
+	}
+}
+
+static void _sc92031_phy_reset(struct net_device *dev)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+	u32 phy_ctrl;
+
+	phy_ctrl = ioread32(port_base + PhyCtrl);
+	phy_ctrl &= ~(PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10);
+	phy_ctrl |= PhyCtrlAne | PhyCtrlReset;
+
+	switch (media) {
+	default:
+	case AUTOSELECT:
+		phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10;
+		break;
+	case M10_HALF:
+		phy_ctrl |= PhyCtrlSpd10;
+		break;
+	case M10_FULL:
+		phy_ctrl |= PhyCtrlDux | PhyCtrlSpd10;
+		break;
+	case M100_HALF:
+		phy_ctrl |= PhyCtrlSpd100;
+		break;
+	case M100_FULL:
+		phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100;
+		break;
+	}
+
+	iowrite32(phy_ctrl, port_base + PhyCtrl);
+	mdelay(10);
+
+	phy_ctrl &= ~PhyCtrlReset;
+	iowrite32(phy_ctrl, port_base + PhyCtrl);
+	mdelay(1);
+
+	_sc92031_mii_write(port_base, MII_JAB,
+			PHY_16_JAB_ENB | PHY_16_PORT_ENB);
+	_sc92031_mii_scan(port_base);
+
+	netif_carrier_off(dev);
+	netif_stop_queue(dev);
+}
+
+static void _sc92031_reset(struct net_device *dev)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+
+	/* disable PM */
+	iowrite32(0, port_base + PMConfig);
+
+	/* soft reset the chip */
+	iowrite32(Cfg0_Reset, port_base + Config0);
+	mdelay(200);
+
+	iowrite32(0, port_base + Config0);
+	mdelay(10);
+
+	/* disable interrupts */
+	iowrite32(0, port_base + IntrMask);
+
+	/* clear multicast address */
+	iowrite32(0, port_base + MAR0);
+	iowrite32(0, port_base + MAR0 + 4);
+
+	/* init rx ring */
+	iowrite32(priv->rx_ring_dma_addr, port_base + RxbufAddr);
+	priv->rx_ring_tail = priv->rx_ring_dma_addr;
+
+	/* init tx ring */
+	_sc92031_tx_clear(dev);
+
+	/* clear old register values */
+	priv->intr_status = 0;
+	atomic_set(&priv->intr_mask, 0);
+	priv->rx_config = 0;
+	priv->tx_config = 0;
+	priv->mc_flags = 0;
+
+	/* configure rx buffer size */
+	/* NOTE: vendor driver had dead code here to enable early tx/rx */
+	iowrite32(Cfg1_Rcv64K, port_base + Config1);
+
+	_sc92031_phy_reset(dev);
+	_sc92031_check_media(dev);
+
+	/* calculate rx fifo overflow */
+	priv->rx_value = 0;
+
+	/* enable PM */
+	iowrite32(priv->pm_config, port_base + PMConfig);
+
+	/* clear intr register */
+	ioread32(port_base + IntrStatus);
+}
+
+static void _sc92031_tx_tasklet(struct net_device *dev)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+
+	unsigned old_tx_tail;
+	unsigned entry;
+	u32 tx_status;
+
+	old_tx_tail = priv->tx_tail;
+	while (priv->tx_head - priv->tx_tail > 0) {
+		entry = priv->tx_tail % NUM_TX_DESC;
+		tx_status = ioread32(port_base + TxStatus0 + entry * 4);
+
+		if (!(tx_status & (TxStatOK | TxUnderrun | TxAborted)))
+			break;
+
+		priv->tx_tail++;
+
+		if (tx_status & TxStatOK) {
+			priv->stats.tx_bytes += tx_status & 0x1fff;
+			priv->stats.tx_packets++;
+			/* Note: TxCarrierLost is always asserted at 100mbps. */
+			priv->stats.collisions += (tx_status >> 22) & 0xf;
+		}
+
+		if (tx_status & (TxOutOfWindow | TxAborted)) {
+			priv->stats.tx_errors++;
+
+			if (tx_status & TxAborted)
+				priv->stats.tx_aborted_errors++;
+
+			if (tx_status & TxCarrierLost)
+				priv->stats.tx_carrier_errors++;
+
+			if (tx_status & TxOutOfWindow)
+				priv->stats.tx_window_errors++;
+		}
+
+		if (tx_status & TxUnderrun)
+			priv->stats.tx_fifo_errors++;
+	}
+
+	if (priv->tx_tail != old_tx_tail)
+		if (netif_queue_stopped(dev))
+			netif_wake_queue(dev);
+}
+
+static void _sc92031_rx_tasklet_error(u32 rx_status,
+		struct sc92031_priv *priv, unsigned rx_size)
+{
+	if(rx_size > (MAX_ETH_FRAME_SIZE + 4) || rx_size < 16) {
+		priv->stats.rx_errors++;
+		priv->stats.rx_length_errors++;
+	}
+
+	if (!(rx_status & RxStatesOK)) {
+		priv->stats.rx_errors++;
+
+		if (rx_status & (RxHugeFrame | RxSmallFrame))
+			priv->stats.rx_length_errors++;
+
+		if (rx_status & RxBadAlign)
+			priv->stats.rx_frame_errors++;
+
+		if (!(rx_status & RxCRCOK))
+			priv->stats.rx_crc_errors++;
+	} else
+		priv->rx_loss++;
+}
+
+static void _sc92031_rx_tasklet(struct net_device *dev)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+
+	dma_addr_t rx_ring_head;
+	unsigned rx_len;
+	unsigned rx_ring_offset;
+	void *rx_ring = priv->rx_ring;
+
+	rx_ring_head = ioread32(port_base + RxBufWPtr);
+	rmb();
+
+	/* rx_ring_head is only 17 bits in the RxBufWPtr register.
+	 * we need to change it to 32 bits physical address
+	 */
+	rx_ring_head &= (dma_addr_t)(RX_BUF_LEN - 1);
+	rx_ring_head |= priv->rx_ring_dma_addr & ~(dma_addr_t)(RX_BUF_LEN - 1);
+	if (rx_ring_head < priv->rx_ring_dma_addr)
+		rx_ring_head += RX_BUF_LEN;
+
+	if (rx_ring_head >= priv->rx_ring_tail)
+		rx_len = rx_ring_head - priv->rx_ring_tail;
+	else
+		rx_len = RX_BUF_LEN - (priv->rx_ring_tail - rx_ring_head);
+
+	if (!rx_len)
+		return;
+
+	if (unlikely(rx_len > RX_BUF_LEN)) {
+		if (printk_ratelimit())
+			printk(KERN_ERR "%s: rx packets length > rx buffer\n",
+					dev->name);
+		return;
+	}
+
+	rx_ring_offset = (priv->rx_ring_tail - priv->rx_ring_dma_addr) % RX_BUF_LEN;
+
+	while (rx_len) {
+		u32 rx_status;
+		unsigned rx_size, rx_size_align, pkt_size;
+		struct sk_buff *skb;
+
+		rx_status = le32_to_cpup((__le32 *)(rx_ring + rx_ring_offset));
+		rmb();
+
+		rx_size = rx_status >> 20;
+		rx_size_align = (rx_size + 3) & ~3;	// for 4 bytes aligned
+		pkt_size = rx_size - 4;	// Omit the four octet CRC from the length.
+
+		rx_ring_offset = (rx_ring_offset + 4) % RX_BUF_LEN;
+
+		if (unlikely(rx_status == 0
+				|| rx_size > (MAX_ETH_FRAME_SIZE + 4)
+				|| rx_size < 16
+				|| !(rx_status & RxStatesOK))) {
+			_sc92031_rx_tasklet_error(rx_status, priv, rx_size);
+			break;
+		}
+
+		if (unlikely(rx_size_align + 4 > rx_len)) {
+			if (printk_ratelimit())
+				printk(KERN_ERR "%s: rx_len is too small\n", dev->name);
+			break;
+		}
+
+		rx_len -= rx_size_align + 4;
+
+		skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN);
+		if (unlikely(!skb)) {
+			if (printk_ratelimit())
+				printk(KERN_ERR "%s: Couldn't allocate a skb_buff for a packet of size %u\n",
+						dev->name, pkt_size);
+			goto next;
+		}
+
+		skb_reserve(skb, NET_IP_ALIGN);
+
+		if ((rx_ring_offset + pkt_size) > RX_BUF_LEN) {
+			memcpy(skb_put(skb, RX_BUF_LEN - rx_ring_offset),
+				rx_ring + rx_ring_offset, RX_BUF_LEN - rx_ring_offset);
+			memcpy(skb_put(skb, pkt_size - (RX_BUF_LEN - rx_ring_offset)),
+				rx_ring, pkt_size - (RX_BUF_LEN - rx_ring_offset));
+		} else {
+			memcpy(skb_put(skb, pkt_size), rx_ring + rx_ring_offset, pkt_size);
+		}
+
+		skb->dev = dev;
+		skb->protocol = eth_type_trans(skb, dev);
+		dev->last_rx = jiffies;
+		netif_rx(skb);
+
+		priv->stats.rx_bytes += pkt_size;
+		priv->stats.rx_packets++;
+
+		if (rx_status & Rx_Multicast)
+			priv->stats.multicast++;
+
+	next:
+		rx_ring_offset = (rx_ring_offset + rx_size_align) % RX_BUF_LEN;
+	}
+	mb();
+
+	priv->rx_ring_tail = rx_ring_head;
+	iowrite32(priv->rx_ring_tail, port_base + RxBufRPtr);
+}
+
+static void _sc92031_link_tasklet(struct net_device *dev)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+
+	if (_sc92031_check_media(dev))
+		netif_wake_queue(dev);
+	else {
+		netif_stop_queue(dev);
+		priv->stats.tx_carrier_errors++;
+	}
+}
+
+static void sc92031_tasklet(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+	u32 intr_status, intr_mask;
+
+	intr_status = priv->intr_status;
+
+	spin_lock(&priv->lock);
+
+	if (unlikely(!netif_running(dev)))
+		goto out;
+
+	if (intr_status & TxOK)
+		_sc92031_tx_tasklet(dev);
+
+	if (intr_status & RxOK)
+		_sc92031_rx_tasklet(dev);
+
+	if (intr_status & RxOverflow)
+		priv->stats.rx_errors++;
+
+	if (intr_status & TimeOut) {
+		priv->stats.rx_errors++;
+		priv->stats.rx_length_errors++;
+	}
+
+	if (intr_status & (LinkFail | LinkOK))
+		_sc92031_link_tasklet(dev);
+
+out:
+	intr_mask = atomic_read(&priv->intr_mask);
+	rmb();
+
+	iowrite32(intr_mask, port_base + IntrMask);
+	mmiowb();
+
+	spin_unlock(&priv->lock);
+}
+
+static irqreturn_t sc92031_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+	u32 intr_status, intr_mask;
+
+	/* mask interrupts before clearing IntrStatus */
+	iowrite32(0, port_base + IntrMask);
+	_sc92031_dummy_read(port_base);
+
+	intr_status = ioread32(port_base + IntrStatus);
+	if (unlikely(intr_status == 0xffffffff))
+		return IRQ_NONE;	// hardware has gone missing
+
+	intr_status &= IntrBits;
+	if (!intr_status)
+		goto out_none;
+
+	priv->intr_status = intr_status;
+	tasklet_schedule(&priv->tasklet);
+
+	return IRQ_HANDLED;
+
+out_none:
+	intr_mask = atomic_read(&priv->intr_mask);
+	rmb();
+
+	iowrite32(intr_mask, port_base + IntrMask);
+	mmiowb();
+
+	return IRQ_NONE;
+}
+
+static struct net_device_stats *sc92031_get_stats(struct net_device *dev)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+
+	// FIXME I do not understand what is this trying to do.
+	if (netif_running(dev)) {
+		int temp;
+
+		spin_lock_bh(&priv->lock);
+
+		/* Update the error count. */
+		temp = (ioread32(port_base + RxStatus0) >> 16) & 0xffff;
+
+		if (temp == 0xffff) {
+			priv->rx_value += temp;
+			priv->stats.rx_fifo_errors = priv->rx_value;
+		} else {
+			priv->stats.rx_fifo_errors = temp + priv->rx_value;
+		}
+
+		spin_unlock_bh(&priv->lock);
+	}
+
+	return &priv->stats;
+}
+
+static int sc92031_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	int err = 0;
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+
+	unsigned len;
+	unsigned entry;
+	u32 tx_status;
+
+	if (unlikely(skb->len > TX_BUF_SIZE)) {
+		err = -EMSGSIZE;
+		priv->stats.tx_dropped++;
+		goto out;
+	}
+
+	spin_lock_bh(&priv->lock);
+
+	if (unlikely(!netif_carrier_ok(dev))) {
+		err = -ENOLINK;
+		priv->stats.tx_dropped++;
+		goto out_unlock;
+	}
+
+	BUG_ON(priv->tx_head - priv->tx_tail >= NUM_TX_DESC);
+
+	entry = priv->tx_head++ % NUM_TX_DESC;
+
+	skb_copy_and_csum_dev(skb, priv->tx_bufs + entry * TX_BUF_SIZE);
+
+	len = skb->len;
+	if (unlikely(len < ETH_ZLEN)) {
+		memset(priv->tx_bufs + entry * TX_BUF_SIZE + len,
+				0, ETH_ZLEN - len);
+		len = ETH_ZLEN;
+	}
+
+	wmb();
+
+	if (len < 100)
+		tx_status = len;
+	else if (len < 300)
+		tx_status = 0x30000 | len;
+	else
+		tx_status = 0x50000 | len;
+
+	iowrite32(priv->tx_bufs_dma_addr + entry * TX_BUF_SIZE,
+			port_base + TxAddr0 + entry * 4);
+	iowrite32(tx_status, port_base + TxStatus0 + entry * 4);
+	mmiowb();
+
+	dev->trans_start = jiffies;
+
+	if (priv->tx_head - priv->tx_tail >= NUM_TX_DESC)
+		netif_stop_queue(dev);
+
+out_unlock:
+	spin_unlock_bh(&priv->lock);
+
+out:
+	dev_kfree_skb(skb);
+
+	return err;
+}
+
+static int sc92031_open(struct net_device *dev)
+{
+	int err;
+	struct sc92031_priv *priv = netdev_priv(dev);
+	struct pci_dev *pdev = priv->pdev;
+
+	priv->rx_ring = pci_alloc_consistent(pdev, RX_BUF_LEN,
+			&priv->rx_ring_dma_addr);
+	if (unlikely(!priv->rx_ring)) {
+		err = -ENOMEM;
+		goto out_alloc_rx_ring;
+	}
+
+	priv->tx_bufs = pci_alloc_consistent(pdev, TX_BUF_TOT_LEN,
+			&priv->tx_bufs_dma_addr);
+	if (unlikely(!priv->tx_bufs)) {
+		err = -ENOMEM;
+		goto out_alloc_tx_bufs;
+	}
+	priv->tx_head = priv->tx_tail = 0;
+
+	err = request_irq(pdev->irq, sc92031_interrupt,
+			SA_SHIRQ, dev->name, dev);
+	if (unlikely(err < 0))
+		goto out_request_irq;
+
+	priv->pm_config = 0;
+
+	/* Interrupts already disabled by sc92031_stop or sc92031_probe */
+	spin_lock(&priv->lock);
+
+	_sc92031_reset(dev);
+	mmiowb();
+
+	spin_unlock(&priv->lock);
+	sc92031_enable_interrupts(dev);
+
+	if (netif_carrier_ok(dev))
+		netif_start_queue(dev);
+	else
+		netif_tx_disable(dev);
+
+	return 0;
+
+out_request_irq:
+	pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs,
+			priv->tx_bufs_dma_addr);
+out_alloc_tx_bufs:
+	pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring,
+			priv->rx_ring_dma_addr);
+out_alloc_rx_ring:
+	return err;
+}
+
+static int sc92031_stop(struct net_device *dev)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+	struct pci_dev *pdev = priv->pdev;
+
+	netif_tx_disable(dev);
+
+	/* Disable interrupts, stop Tx and Rx. */
+	sc92031_disable_interrupts(dev);
+
+	spin_lock(&priv->lock);
+
+	_sc92031_disable_tx_rx(dev);
+	_sc92031_tx_clear(dev);
+	mmiowb();
+
+	spin_unlock(&priv->lock);
+
+	free_irq(pdev->irq, dev);
+	pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs,
+			priv->tx_bufs_dma_addr);
+	pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring,
+			priv->rx_ring_dma_addr);
+
+	return 0;
+}
+
+static void sc92031_set_multicast_list(struct net_device *dev)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+
+	spin_lock_bh(&priv->lock);
+
+	_sc92031_set_mar(dev);
+	_sc92031_set_rx_config(dev);
+	mmiowb();
+
+	spin_unlock_bh(&priv->lock);
+}
+
+static void sc92031_tx_timeout(struct net_device *dev)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+
+	/* Disable interrupts by clearing the interrupt mask.*/
+	sc92031_disable_interrupts(dev);
+
+	spin_lock(&priv->lock);
+
+	priv->tx_timeouts++;
+
+	_sc92031_reset(dev);
+	mmiowb();
+
+	spin_unlock(&priv->lock);
+
+	/* enable interrupts */
+	sc92031_enable_interrupts(dev);
+
+	if (netif_carrier_ok(dev))
+		netif_wake_queue(dev);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void sc92031_poll_controller(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	if (sc92031_interrupt(dev->irq, dev) != IRQ_NONE)
+		sc92031_tasklet((unsigned long)dev);
+	enable_irq(dev->irq);
+}
+#endif
+
+static int sc92031_ethtool_get_settings(struct net_device *dev,
+		struct ethtool_cmd *cmd)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+	u8 phy_address;
+	u32 phy_ctrl;
+	u16 output_status;
+
+	spin_lock_bh(&priv->lock);
+
+	phy_address = ioread32(port_base + Miicmd1) >> 27;
+	phy_ctrl = ioread32(port_base + PhyCtrl);
+
+	output_status = _sc92031_mii_read(port_base, MII_OutputStatus);
+	_sc92031_mii_scan(port_base);
+	mmiowb();
+
+	spin_unlock_bh(&priv->lock);
+
+	cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full
+			| SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full
+			| SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII;
+
+	cmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
+
+	if ((phy_ctrl & (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10))
+			== (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10))
+		cmd->advertising |= ADVERTISED_Autoneg;
+
+	if ((phy_ctrl & PhyCtrlSpd10) == PhyCtrlSpd10)
+		cmd->advertising |= ADVERTISED_10baseT_Half;
+
+	if ((phy_ctrl & (PhyCtrlSpd10 | PhyCtrlDux))
+			== (PhyCtrlSpd10 | PhyCtrlDux))
+		cmd->advertising |= ADVERTISED_10baseT_Full;
+
+	if ((phy_ctrl & PhyCtrlSpd100) == PhyCtrlSpd100)
+		cmd->advertising |= ADVERTISED_100baseT_Half;
+
+	if ((phy_ctrl & (PhyCtrlSpd100 | PhyCtrlDux))
+			== (PhyCtrlSpd100 | PhyCtrlDux))
+		cmd->advertising |= ADVERTISED_100baseT_Full;
+
+	if (phy_ctrl & PhyCtrlAne)
+		cmd->advertising |= ADVERTISED_Autoneg;
+
+	cmd->speed = (output_status & 0x2) ? SPEED_100 : SPEED_10;
+	cmd->duplex = (output_status & 0x4) ? DUPLEX_FULL : DUPLEX_HALF;
+	cmd->port = PORT_MII;
+	cmd->phy_address = phy_address;
+	cmd->transceiver = XCVR_INTERNAL;
+	cmd->autoneg = (phy_ctrl & PhyCtrlAne) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+
+	return 0;
+}
+
+static int sc92031_ethtool_set_settings(struct net_device *dev,
+		struct ethtool_cmd *cmd)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+	u32 phy_ctrl;
+	u32 old_phy_ctrl;
+
+	if (!(cmd->speed == SPEED_10 || cmd->speed == SPEED_100))
+		return -EINVAL;
+	if (!(cmd->duplex == DUPLEX_HALF || cmd->duplex == DUPLEX_FULL))
+		return -EINVAL;
+	if (!(cmd->port == PORT_MII))
+		return -EINVAL;
+	if (!(cmd->phy_address == 0x1f))
+		return -EINVAL;
+	if (!(cmd->transceiver == XCVR_INTERNAL))
+		return -EINVAL;
+	if (!(cmd->autoneg == AUTONEG_DISABLE || cmd->autoneg == AUTONEG_ENABLE))
+		return -EINVAL;
+
+	if (cmd->autoneg == AUTONEG_ENABLE) {
+		if (!(cmd->advertising & (ADVERTISED_Autoneg
+				| ADVERTISED_100baseT_Full
+				| ADVERTISED_100baseT_Half
+				| ADVERTISED_10baseT_Full
+				| ADVERTISED_10baseT_Half)))
+			return -EINVAL;
+
+		phy_ctrl = PhyCtrlAne;
+
+		// FIXME: I'm not sure what the original code was trying to do
+		if (cmd->advertising & ADVERTISED_Autoneg)
+			phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10;
+		if (cmd->advertising & ADVERTISED_100baseT_Full)
+			phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100;
+		if (cmd->advertising & ADVERTISED_100baseT_Half)
+			phy_ctrl |= PhyCtrlSpd100;
+		if (cmd->advertising & ADVERTISED_10baseT_Full)
+			phy_ctrl |= PhyCtrlSpd10 | PhyCtrlDux;
+		if (cmd->advertising & ADVERTISED_10baseT_Half)
+			phy_ctrl |= PhyCtrlSpd10;
+	} else {
+		// FIXME: Whole branch guessed
+		phy_ctrl = 0;
+
+		if (cmd->speed == SPEED_10)
+			phy_ctrl |= PhyCtrlSpd10;
+		else /* cmd->speed == SPEED_100 */
+			phy_ctrl |= PhyCtrlSpd100;
+
+		if (cmd->duplex == DUPLEX_FULL)
+			phy_ctrl |= PhyCtrlDux;
+	}
+
+	spin_lock_bh(&priv->lock);
+
+	old_phy_ctrl = ioread32(port_base + PhyCtrl);
+	phy_ctrl |= old_phy_ctrl & ~(PhyCtrlAne | PhyCtrlDux
+			| PhyCtrlSpd100 | PhyCtrlSpd10);
+	if (phy_ctrl != old_phy_ctrl)
+		iowrite32(phy_ctrl, port_base + PhyCtrl);
+
+	spin_unlock_bh(&priv->lock);
+
+	return 0;
+}
+
+static void sc92031_ethtool_get_drvinfo(struct net_device *dev,
+		struct ethtool_drvinfo *drvinfo)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+	struct pci_dev *pdev = priv->pdev;
+
+	strcpy(drvinfo->driver, SC92031_NAME);
+	strcpy(drvinfo->version, SC92031_VERSION);
+	strcpy(drvinfo->bus_info, pci_name(pdev));
+}
+
+static void sc92031_ethtool_get_wol(struct net_device *dev,
+		struct ethtool_wolinfo *wolinfo)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+	u32 pm_config;
+
+	spin_lock_bh(&priv->lock);
+	pm_config = ioread32(port_base + PMConfig);
+	spin_unlock_bh(&priv->lock);
+
+	// FIXME: Guessed
+	wolinfo->supported = WAKE_PHY | WAKE_MAGIC
+			| WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;
+	wolinfo->wolopts = 0;
+
+	if (pm_config & PM_LinkUp)
+		wolinfo->wolopts |= WAKE_PHY;
+
+	if (pm_config & PM_Magic)
+		wolinfo->wolopts |= WAKE_MAGIC;
+
+	if (pm_config & PM_WakeUp)
+		// FIXME: Guessed
+		wolinfo->wolopts |= WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;
+}
+
+static int sc92031_ethtool_set_wol(struct net_device *dev,
+		struct ethtool_wolinfo *wolinfo)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+	u32 pm_config;
+
+	spin_lock_bh(&priv->lock);
+
+	pm_config = ioread32(port_base + PMConfig)
+			& ~(PM_LinkUp | PM_Magic | PM_WakeUp);
+
+	if (wolinfo->wolopts & WAKE_PHY)
+		pm_config |= PM_LinkUp;
+
+	if (wolinfo->wolopts & WAKE_MAGIC)
+		pm_config |= PM_Magic;
+
+	// FIXME: Guessed
+	if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST))
+		pm_config |= PM_WakeUp;
+
+	priv->pm_config = pm_config;
+	iowrite32(pm_config, port_base + PMConfig);
+	mmiowb();
+
+	spin_unlock_bh(&priv->lock);
+
+	return 0;
+}
+
+static int sc92031_ethtool_nway_reset(struct net_device *dev)
+{
+	int err = 0;
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem *port_base = priv->port_base;
+	u16 bmcr;
+
+	spin_lock_bh(&priv->lock);
+
+	bmcr = _sc92031_mii_read(port_base, MII_BMCR);
+	if (!(bmcr & BMCR_ANENABLE)) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	_sc92031_mii_write(port_base, MII_BMCR, bmcr | BMCR_ANRESTART);
+
+out:
+	_sc92031_mii_scan(port_base);
+	mmiowb();
+
+	spin_unlock_bh(&priv->lock);
+
+	return err;
+}
+
+static const char sc92031_ethtool_stats_strings[SILAN_STATS_NUM][ETH_GSTRING_LEN] = {
+	"tx_timeout",
+	"rx_loss",
+};
+
+static void sc92031_ethtool_get_strings(struct net_device *dev,
+		u32 stringset, u8 *data)
+{
+	if (stringset == ETH_SS_STATS)
+		memcpy(data, sc92031_ethtool_stats_strings,
+				SILAN_STATS_NUM * ETH_GSTRING_LEN);
+}
+
+static int sc92031_ethtool_get_stats_count(struct net_device *dev)
+{
+	return SILAN_STATS_NUM;
+}
+
+static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev,
+		struct ethtool_stats *stats, u64 *data)
+{
+	struct sc92031_priv *priv = netdev_priv(dev);
+
+	spin_lock_bh(&priv->lock);
+	data[0] = priv->tx_timeouts;
+	data[1] = priv->rx_loss;
+	spin_unlock_bh(&priv->lock);
+}
+
+static struct ethtool_ops sc92031_ethtool_ops = {
+	.get_settings		= sc92031_ethtool_get_settings,
+	.set_settings		= sc92031_ethtool_set_settings,
+	.get_drvinfo		= sc92031_ethtool_get_drvinfo,
+	.get_wol		= sc92031_ethtool_get_wol,
+	.set_wol		= sc92031_ethtool_set_wol,
+	.nway_reset		= sc92031_ethtool_nway_reset,
+	.get_link		= ethtool_op_get_link,
+	.get_tx_csum		= ethtool_op_get_tx_csum,
+	.get_sg			= ethtool_op_get_sg,
+	.get_tso		= ethtool_op_get_tso,
+	.get_strings		= sc92031_ethtool_get_strings,
+	.get_stats_count	= sc92031_ethtool_get_stats_count,
+	.get_ethtool_stats	= sc92031_ethtool_get_ethtool_stats,
+	.get_perm_addr		= ethtool_op_get_perm_addr,
+	.get_ufo		= ethtool_op_get_ufo,
+};
+
+static int __devinit sc92031_probe(struct pci_dev *pdev,
+		const struct pci_device_id *id)
+{
+	int err;
+	void __iomem* port_base;
+	struct net_device *dev;
+	struct sc92031_priv *priv;
+	u32 mac0, mac1;
+
+	err = pci_enable_device(pdev);
+	if (unlikely(err < 0))
+		goto out_enable_device;
+
+	pci_set_master(pdev);
+
+	err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+	if (unlikely(err < 0))
+		goto out_set_dma_mask;
+
+	err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+	if (unlikely(err < 0))
+		goto out_set_dma_mask;
+
+	err = pci_request_regions(pdev, SC92031_NAME);
+	if (unlikely(err < 0))
+		goto out_request_regions;
+
+	port_base = pci_iomap(pdev, SC92031_USE_BAR, 0);
+	if (unlikely(!port_base)) {
+		err = -EIO;
+		goto out_iomap;
+	}
+
+	dev = alloc_etherdev(sizeof(struct sc92031_priv));
+	if (unlikely(!dev)) {
+		err = -ENOMEM;
+		goto out_alloc_etherdev;
+	}
+
+	pci_set_drvdata(pdev, dev);
+
+#if SC92031_USE_BAR == 0
+	dev->mem_start = pci_resource_start(pdev, SC92031_USE_BAR);
+	dev->mem_end = pci_resource_end(pdev, SC92031_USE_BAR);
+#elif SC92031_USE_BAR == 1
+	dev->base_addr = pci_resource_start(pdev, SC92031_USE_BAR);
+#endif
+	dev->irq = pdev->irq;
+
+	/* faked with skb_copy_and_csum_dev */
+	dev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA;
+
+	dev->get_stats		= sc92031_get_stats;
+	dev->ethtool_ops	= &sc92031_ethtool_ops;
+	dev->hard_start_xmit	= sc92031_start_xmit;
+	dev->watchdog_timeo	= TX_TIMEOUT;
+	dev->open		= sc92031_open;
+	dev->stop		= sc92031_stop;
+	dev->set_multicast_list	= sc92031_set_multicast_list;
+	dev->tx_timeout		= sc92031_tx_timeout;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller	= sc92031_poll_controller;
+#endif
+
+	priv = netdev_priv(dev);
+	spin_lock_init(&priv->lock);
+	priv->port_base = port_base;
+	priv->pdev = pdev;
+	tasklet_init(&priv->tasklet, sc92031_tasklet, (unsigned long)dev);
+	/* Fudge tasklet count so the call to sc92031_enable_interrupts at
+	 * sc92031_open will work correctly */
+	tasklet_disable_nosync(&priv->tasklet);
+
+	/* PCI PM Wakeup */
+	iowrite32((~PM_LongWF & ~PM_LWPTN) | PM_Enable, port_base + PMConfig);
+
+	mac0 = ioread32(port_base + MAC0);
+	mac1 = ioread32(port_base + MAC0 + 4);
+	dev->dev_addr[0] = dev->perm_addr[0] = mac0 >> 24;
+	dev->dev_addr[1] = dev->perm_addr[1] = mac0 >> 16;
+	dev->dev_addr[2] = dev->perm_addr[2] = mac0 >> 8;
+	dev->dev_addr[3] = dev->perm_addr[3] = mac0;
+	dev->dev_addr[4] = dev->perm_addr[4] = mac1 >> 8;
+	dev->dev_addr[5] = dev->perm_addr[5] = mac1;
+
+	err = register_netdev(dev);
+	if (err < 0)
+		goto out_register_netdev;
+
+	return 0;
+
+out_register_netdev:
+	free_netdev(dev);
+out_alloc_etherdev:
+	pci_iounmap(pdev, port_base);
+out_iomap:
+	pci_release_regions(pdev);
+out_request_regions:
+out_set_dma_mask:
+	pci_disable_device(pdev);
+out_enable_device:
+	return err;
+}
+
+static void __devexit sc92031_remove(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct sc92031_priv *priv = netdev_priv(dev);
+	void __iomem* port_base = priv->port_base;
+
+	unregister_netdev(dev);
+	free_netdev(dev);
+	pci_iounmap(pdev, port_base);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+}
+
+static int sc92031_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct sc92031_priv *priv = netdev_priv(dev);
+
+	pci_save_state(pdev);
+
+	if (!netif_running(dev))
+		goto out;
+
+	netif_device_detach(dev);
+
+	/* Disable interrupts, stop Tx and Rx. */
+	sc92031_disable_interrupts(dev);
+
+	spin_lock(&priv->lock);
+
+	_sc92031_disable_tx_rx(dev);
+	_sc92031_tx_clear(dev);
+	mmiowb();
+
+	spin_unlock(&priv->lock);
+
+out:
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	return 0;
+}
+
+static int sc92031_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct sc92031_priv *priv = netdev_priv(dev);
+
+	pci_restore_state(pdev);
+	pci_set_power_state(pdev, PCI_D0);
+
+	if (!netif_running(dev))
+		goto out;
+
+	/* Interrupts already disabled by sc92031_suspend */
+	spin_lock(&priv->lock);
+
+	_sc92031_reset(dev);
+	mmiowb();
+
+	spin_unlock(&priv->lock);
+	sc92031_enable_interrupts(dev);
+
+	netif_device_attach(dev);
+
+	if (netif_carrier_ok(dev))
+		netif_wake_queue(dev);
+	else
+		netif_tx_disable(dev);
+
+out:
+	return 0;
+}
+
+static struct pci_device_id sc92031_pci_device_id_table[] __devinitdata = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_SILAN, PCI_DEVICE_ID_SILAN_SC92031) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_SILAN, PCI_DEVICE_ID_SILAN_8139D) },
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, sc92031_pci_device_id_table);
+
+static struct pci_driver sc92031_pci_driver = {
+	.name		= SC92031_NAME,
+	.id_table	= sc92031_pci_device_id_table,
+	.probe		= sc92031_probe,
+	.remove		= __devexit_p(sc92031_remove),
+	.suspend	= sc92031_suspend,
+	.resume		= sc92031_resume,
+};
+
+static int __init sc92031_init(void)
+{
+	printk(KERN_INFO SC92031_DESCRIPTION " " SC92031_VERSION "\n");
+	return pci_register_driver(&sc92031_pci_driver);
+}
+
+static void __exit sc92031_exit(void)
+{
+	pci_unregister_driver(&sc92031_pci_driver);
+}
+
+module_init(sc92031_init);
+module_exit(sc92031_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Cesar Eduardo Barros <cesarb@cesarb.net>");
+MODULE_DESCRIPTION(SC92031_DESCRIPTION);
+MODULE_VERSION(SC92031_VERSION);
diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c
deleted file mode 100644
index 96e06c5..0000000
--- a/drivers/net/sk_mca.c
+++ /dev/null
@@ -1,1216 +0,0 @@
-/*
-net-3-driver for the SKNET MCA-based cards
-
-This is an extension to the Linux operating system, and is covered by the
-same GNU General Public License that covers that work.
-
-Copyright 1999 by Alfred Arnold (alfred@ccac.rwth-aachen.de,
-                                 alfred.arnold@lancom.de)
-
-This driver is based both on the 3C523 driver and the SK_G16 driver.
-
-paper sources:
-  'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
-  Hans-Peter Messmer for the basic Microchannel stuff
-
-  'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer
-  for help on Ethernet driver programming
-
-  'Ethernet/IEEE 802.3 Family 1992 World Network Data Book/Handbook' by AMD
-  for documentation on the AM7990 LANCE
-
-  'SKNET Personal Technisches Manual', Version 1.2 by Schneider&Koch
-  for documentation on the Junior board
-
-  'SK-NET MC2+ Technical Manual", Version 1.1 by Schneider&Koch for
-  documentation on the MC2 bord
-
-  A big thank you to the S&K support for providing me so quickly with
-  documentation!
-
-  Also see http://www.syskonnect.com/
-
-  Missing things:
-
-  -> set debug level via ioctl instead of compile-time switches
-  -> I didn't follow the development of the 2.1.x kernels, so my
-     assumptions about which things changed with which kernel version
-     are probably nonsense
-
-History:
-  May 16th, 1999
-  	startup
-  May 22st, 1999
-	added private structure, methods
-        begun building data structures in RAM
-  May 23nd, 1999
-	can receive frames, send frames
-  May 24th, 1999
-        modularized initialization of LANCE
-        loadable as module
-	still Tx problem :-(
-  May 26th, 1999
-  	MC2 works
-  	support for multiple devices
-  	display media type for MC2+
-  May 28th, 1999
-	fixed problem in GetLANCE leaving interrupts turned off
-        increase TX queue to 4 packets to improve send performance
-  May 29th, 1999
-	a few corrections in statistics, caught rcvr overruns
-        reinitialization of LANCE/board in critical situations
-        MCA info implemented
-	implemented LANCE multicast filter
-  Jun 6th, 1999
-	additions for Linux 2.2
-  Dec 25th, 1999
-  	unfortunately there seem to be newer MC2+ boards that react
-  	on IRQ 3/5/9/10 instead of 3/5/10/11, so we have to autoprobe
-  	in questionable cases...
-  Dec 28th, 1999
-	integrated patches from David Weinehall & Bill Wendling for 2.3
-	kernels (isa_...functions).  Things are defined in a way that
-        it still works with 2.0.x 8-)
-  Dec 30th, 1999
-	added handling of the remaining interrupt conditions.  That
-        should cure the spurious hangs.
-  Jan 30th, 2000
-	newer kernels automatically probe more than one board, so the
-	'startslot' as a variable is also needed here
-  June 1st, 2000
-	added changes for recent 2.3 kernels
-
- *************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/time.h>
-#include <linux/mca-legacy.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/processor.h>
-#include <asm/io.h>
-
-#define _SK_MCA_DRIVER_
-#include "sk_mca.h"
-
-/* ------------------------------------------------------------------------
- * global static data - not more since we can handle multiple boards and
- * have to pack all state info into the device struct!
- * ------------------------------------------------------------------------ */
-
-static char *MediaNames[Media_Count] =
-    { "10Base2", "10BaseT", "10Base5", "Unknown" };
-
-static unsigned char poly[] =
-    { 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0,
-	1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0
-};
-
-/* ------------------------------------------------------------------------
- * private subfunctions
- * ------------------------------------------------------------------------ */
-
-/* dump parts of shared memory - only needed during debugging */
-
-#ifdef DEBUG
-static void dumpmem(struct net_device *dev, u32 start, u32 len)
-{
-	skmca_priv *priv = netdev_priv(dev);
-	int z;
-
-	for (z = 0; z < len; z++) {
-		if ((z & 15) == 0)
-			printk("%04x:", z);
-		printk(" %02x", readb(priv->base + start + z));
-		if ((z & 15) == 15)
-			printk("\n");
-	}
-}
-
-/* print exact time - ditto */
-
-static void PrTime(void)
-{
-	struct timeval tv;
-
-	do_gettimeofday(&tv);
-	printk("%9d:%06d: ", tv.tv_sec, tv.tv_usec);
-}
-#endif
-
-/* deduce resources out of POS registers */
-
-static void __init getaddrs(int slot, int junior, int *base, int *irq,
-		     skmca_medium * medium)
-{
-	u_char pos0, pos1, pos2;
-
-	if (junior) {
-		pos0 = mca_read_stored_pos(slot, 2);
-		*base = ((pos0 & 0x0e) << 13) + 0xc0000;
-		*irq = ((pos0 & 0x10) >> 4) + 10;
-		*medium = Media_Unknown;
-	} else {
-		/* reset POS 104 Bits 0+1 so the shared memory region goes to the
-		   configured area between 640K and 1M.  Afterwards, enable the MC2.
-		   I really don't know what rode SK to do this... */
-
-		mca_write_pos(slot, 4,
-			      mca_read_stored_pos(slot, 4) & 0xfc);
-		mca_write_pos(slot, 2,
-			      mca_read_stored_pos(slot, 2) | 0x01);
-
-		pos1 = mca_read_stored_pos(slot, 3);
-		pos2 = mca_read_stored_pos(slot, 4);
-		*base = ((pos1 & 0x07) << 14) + 0xc0000;
-		switch (pos2 & 0x0c) {
-		case 0:
-			*irq = 3;
-			break;
-		case 4:
-			*irq = 5;
-			break;
-		case 8:
-			*irq = -10;
-			break;
-		case 12:
-			*irq = -11;
-			break;
-		}
-		*medium = (pos2 >> 6) & 3;
-	}
-}
-
-/* check for both cards:
-   When the MC2 is turned off, it was configured for more than 15MB RAM,
-   is disabled and won't get detected using the standard probe.  We
-   therefore have to scan the slots manually :-( */
-
-static int __init dofind(int *junior, int firstslot)
-{
-	int slot;
-	unsigned int id;
-
-	for (slot = firstslot; slot < MCA_MAX_SLOT_NR; slot++) {
-		id = mca_read_stored_pos(slot, 0)
-		    + (((unsigned int) mca_read_stored_pos(slot, 1)) << 8);
-
-		*junior = 0;
-		if (id == SKNET_MCA_ID)
-			return slot;
-		*junior = 1;
-		if (id == SKNET_JUNIOR_MCA_ID)
-			return slot;
-	}
-	return MCA_NOTFOUND;
-}
-
-/* reset the whole board */
-
-static void ResetBoard(struct net_device *dev)
-{
-	skmca_priv *priv = netdev_priv(dev);
-
-	writeb(CTRL_RESET_ON, priv->ctrladdr);
-	udelay(10);
-	writeb(CTRL_RESET_OFF, priv->ctrladdr);
-}
-
-/* wait for LANCE interface to become not busy */
-
-static int WaitLANCE(struct net_device *dev)
-{
-	skmca_priv *priv = netdev_priv(dev);
-	int t = 0;
-
-	while ((readb(priv->ctrladdr) & STAT_IO_BUSY) ==
-	       STAT_IO_BUSY) {
-		udelay(1);
-		if (++t > 1000) {
-			printk("%s: LANCE access timeout", dev->name);
-			return 0;
-		}
-	}
-
-	return 1;
-}
-
-/* set LANCE register - must be atomic */
-
-static void SetLANCE(struct net_device *dev, u16 addr, u16 value)
-{
-	skmca_priv *priv = netdev_priv(dev);
-	unsigned long flags;
-
-	/* disable interrupts */
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	/* wait until no transfer is pending */
-
-	WaitLANCE(dev);
-
-	/* transfer register address to RAP */
-
-	writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
-	writew(addr, priv->ioregaddr);
-	writeb(IOCMD_GO, priv->cmdaddr);
-	udelay(1);
-	WaitLANCE(dev);
-
-	/* transfer data to register */
-
-	writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA, priv->ctrladdr);
-	writew(value, priv->ioregaddr);
-	writeb(IOCMD_GO, priv->cmdaddr);
-	udelay(1);
-	WaitLANCE(dev);
-
-	/* reenable interrupts */
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-/* get LANCE register */
-
-static u16 GetLANCE(struct net_device *dev, u16 addr)
-{
-	skmca_priv *priv = netdev_priv(dev);
-	unsigned long flags;
-	unsigned int res;
-
-	/* disable interrupts */
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	/* wait until no transfer is pending */
-
-	WaitLANCE(dev);
-
-	/* transfer register address to RAP */
-
-	writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
-	writew(addr, priv->ioregaddr);
-	writeb(IOCMD_GO, priv->cmdaddr);
-	udelay(1);
-	WaitLANCE(dev);
-
-	/* transfer data from register */
-
-	writeb(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA, priv->ctrladdr);
-	writeb(IOCMD_GO, priv->cmdaddr);
-	udelay(1);
-	WaitLANCE(dev);
-	res = readw(priv->ioregaddr);
-
-	/* reenable interrupts */
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	return res;
-}
-
-/* build up descriptors in shared RAM */
-
-static void InitDscrs(struct net_device *dev)
-{
-	skmca_priv *priv = netdev_priv(dev);
-	u32 bufaddr;
-
-	/* Set up Tx descriptors. The board has only 16K RAM so bits 16..23
-	   are always 0. */
-
-	bufaddr = RAM_DATABASE;
-	{
-		LANCE_TxDescr descr;
-		int z;
-
-		for (z = 0; z < TXCOUNT; z++) {
-			descr.LowAddr = bufaddr;
-			descr.Flags = 0;
-			descr.Len = 0xf000;
-			descr.Status = 0;
-			memcpy_toio(priv->base + RAM_TXBASE +
-				   (z * sizeof(LANCE_TxDescr)), &descr,
-				   sizeof(LANCE_TxDescr));
-			memset_io(priv->base + bufaddr, 0, RAM_BUFSIZE);
-			bufaddr += RAM_BUFSIZE;
-		}
-	}
-
-	/* do the same for the Rx descriptors */
-
-	{
-		LANCE_RxDescr descr;
-		int z;
-
-		for (z = 0; z < RXCOUNT; z++) {
-			descr.LowAddr = bufaddr;
-			descr.Flags = RXDSCR_FLAGS_OWN;
-			descr.MaxLen = -RAM_BUFSIZE;
-			descr.Len = 0;
-			memcpy_toio(priv->base + RAM_RXBASE +
-				   (z * sizeof(LANCE_RxDescr)), &descr,
-				   sizeof(LANCE_RxDescr));
-			memset_io(priv->base + bufaddr, 0, RAM_BUFSIZE);
-			bufaddr += RAM_BUFSIZE;
-		}
-	}
-}
-
-/* calculate the hash bit position for a given multicast address
-   taken more or less directly from the AMD datasheet... */
-
-static void UpdateCRC(unsigned char *CRC, int bit)
-{
-	int j;
-
-	/* shift CRC one bit */
-
-	memmove(CRC + 1, CRC, 32 * sizeof(unsigned char));
-	CRC[0] = 0;
-
-	/* if bit XOR controlbit = 1, set CRC = CRC XOR polynomial */
-
-	if (bit ^ CRC[32])
-		for (j = 0; j < 32; j++)
-			CRC[j] ^= poly[j];
-}
-
-static unsigned int GetHash(char *address)
-{
-	unsigned char CRC[33];
-	int i, byte, hashcode;
-
-	/* a multicast address has bit 0 in the first byte set */
-
-	if ((address[0] & 1) == 0)
-		return -1;
-
-	/* initialize CRC */
-
-	memset(CRC, 1, sizeof(CRC));
-
-	/* loop through address bits */
-
-	for (byte = 0; byte < 6; byte++)
-		for (i = 0; i < 8; i++)
-			UpdateCRC(CRC, (address[byte] >> i) & 1);
-
-	/* hashcode is the 6 least significant bits of the CRC */
-
-	hashcode = 0;
-	for (i = 0; i < 6; i++)
-		hashcode = (hashcode << 1) + CRC[i];
-	return hashcode;
-}
-
-/* feed ready-built initialization block into LANCE */
-
-static void InitLANCE(struct net_device *dev)
-{
-	skmca_priv *priv = netdev_priv(dev);
-
-	/* build up descriptors. */
-
-	InitDscrs(dev);
-
-	/* next RX descriptor to be read is the first one.  Since the LANCE
-	   will start from the beginning after initialization, we have to
-	   reset out pointers too. */
-
-	priv->nextrx = 0;
-
-	/* no TX descriptors active */
-
-	priv->nexttxput = priv->nexttxdone = priv->txbusy = 0;
-
-	/* set up the LANCE bus control register - constant for SKnet boards */
-
-	SetLANCE(dev, LANCE_CSR3,
-		 CSR3_BSWAP_OFF | CSR3_ALE_LOW | CSR3_BCON_HOLD);
-
-	/* write address of initialization block into LANCE */
-
-	SetLANCE(dev, LANCE_CSR1, RAM_INITBASE & 0xffff);
-	SetLANCE(dev, LANCE_CSR2, (RAM_INITBASE >> 16) & 0xff);
-
-	/* we don't get ready until the LANCE has read the init block */
-
-	netif_stop_queue(dev);
-
-	/* let LANCE read the initialization block.  LANCE is ready
-	   when we receive the corresponding interrupt. */
-
-	SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_INIT);
-}
-
-/* stop the LANCE so we can reinitialize it */
-
-static void StopLANCE(struct net_device *dev)
-{
-	/* can't take frames any more */
-
-	netif_stop_queue(dev);
-
-	/* disable interrupts, stop it */
-
-	SetLANCE(dev, LANCE_CSR0, CSR0_STOP);
-}
-
-/* initialize card and LANCE for proper operation */
-
-static void InitBoard(struct net_device *dev)
-{
-	skmca_priv *priv = netdev_priv(dev);
-	LANCE_InitBlock block;
-
-	/* Lay out the shared RAM - first we create the init block for the LANCE.
-	   We do not overwrite it later because we need it again when we switch
-	   promiscous mode on/off. */
-
-	block.Mode = 0;
-	if (dev->flags & IFF_PROMISC)
-		block.Mode |= LANCE_INIT_PROM;
-	memcpy(block.PAdr, dev->dev_addr, 6);
-	memset(block.LAdrF, 0, sizeof(block.LAdrF));
-	block.RdrP = (RAM_RXBASE & 0xffffff) | (LRXCOUNT << 29);
-	block.TdrP = (RAM_TXBASE & 0xffffff) | (LTXCOUNT << 29);
-
-	memcpy_toio(priv->base + RAM_INITBASE, &block, sizeof(block));
-
-	/* initialize LANCE. Implicitly sets up other structures in RAM. */
-
-	InitLANCE(dev);
-}
-
-/* deinitialize card and LANCE */
-
-static void DeinitBoard(struct net_device *dev)
-{
-	/* stop LANCE */
-
-	StopLANCE(dev);
-
-	/* reset board */
-
-	ResetBoard(dev);
-}
-
-/* probe for device's irq */
-
-static int __init ProbeIRQ(struct net_device *dev)
-{
-	unsigned long imaskval, njiffies, irq;
-	u16 csr0val;
-
-	/* enable all interrupts */
-
-	imaskval = probe_irq_on();
-
-	/* initialize the board. Wait for interrupt 'Initialization done'. */
-
-	ResetBoard(dev);
-	InitBoard(dev);
-
-	njiffies = jiffies + HZ;
-	do {
-		csr0val = GetLANCE(dev, LANCE_CSR0);
-	}
-	while (((csr0val & CSR0_IDON) == 0) && (jiffies != njiffies));
-
-	/* turn of interrupts again */
-
-	irq = probe_irq_off(imaskval);
-
-	/* if we found something, ack the interrupt */
-
-	if (irq)
-		SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_IDON);
-
-	/* back to idle state */
-
-	DeinitBoard(dev);
-
-	return irq;
-}
-
-/* ------------------------------------------------------------------------
- * interrupt handler(s)
- * ------------------------------------------------------------------------ */
-
-/* LANCE has read initialization block -> start it */
-
-static u16 irqstart_handler(struct net_device *dev, u16 oldcsr0)
-{
-	/* now we're ready to transmit */
-
-	netif_wake_queue(dev);
-
-	/* reset IDON bit, start LANCE */
-
-	SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_IDON | CSR0_STRT);
-	return GetLANCE(dev, LANCE_CSR0);
-}
-
-/* did we lose blocks due to a FIFO overrun ? */
-
-static u16 irqmiss_handler(struct net_device *dev, u16 oldcsr0)
-{
-	skmca_priv *priv = netdev_priv(dev);
-
-	/* update statistics */
-
-	priv->stat.rx_fifo_errors++;
-
-	/* reset MISS bit */
-
-	SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_MISS);
-	return GetLANCE(dev, LANCE_CSR0);
-}
-
-/* receive interrupt */
-
-static u16 irqrx_handler(struct net_device *dev, u16 oldcsr0)
-{
-	skmca_priv *priv = netdev_priv(dev);
-	LANCE_RxDescr descr;
-	unsigned int descraddr;
-
-	/* run through queue until we reach a descriptor we do not own */
-
-	descraddr = RAM_RXBASE + (priv->nextrx * sizeof(LANCE_RxDescr));
-	while (1) {
-		/* read descriptor */
-		memcpy_fromio(&descr, priv->base + descraddr,
-			     sizeof(LANCE_RxDescr));
-
-		/* if we reach a descriptor we do not own, we're done */
-		if ((descr.Flags & RXDSCR_FLAGS_OWN) != 0)
-			break;
-
-#ifdef DEBUG
-		PrTime();
-		printk("Receive packet on descr %d len %d\n", priv->nextrx,
-		       descr.Len);
-#endif
-
-		/* erroneous packet ? */
-		if ((descr.Flags & RXDSCR_FLAGS_ERR) != 0) {
-			priv->stat.rx_errors++;
-			if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
-				priv->stat.rx_crc_errors++;
-			else if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
-				priv->stat.rx_frame_errors++;
-			else if ((descr.Flags & RXDSCR_FLAGS_OFLO) != 0)
-				priv->stat.rx_fifo_errors++;
-		}
-
-		/* good packet ? */
-		else {
-			struct sk_buff *skb;
-
-			skb = dev_alloc_skb(descr.Len + 2);
-			if (skb == NULL)
-				priv->stat.rx_dropped++;
-			else {
-				memcpy_fromio(skb_put(skb, descr.Len),
-					     priv->base +
-					     descr.LowAddr, descr.Len);
-				skb->dev = dev;
-				skb->protocol = eth_type_trans(skb, dev);
-				skb->ip_summed = CHECKSUM_NONE;
-				priv->stat.rx_packets++;
-				priv->stat.rx_bytes += descr.Len;
-				netif_rx(skb);
-				dev->last_rx = jiffies;
-			}
-		}
-
-		/* give descriptor back to LANCE */
-		descr.Len = 0;
-		descr.Flags |= RXDSCR_FLAGS_OWN;
-
-		/* update descriptor in shared RAM */
-		memcpy_toio(priv->base + descraddr, &descr,
-			   sizeof(LANCE_RxDescr));
-
-		/* go to next descriptor */
-		priv->nextrx++;
-		descraddr += sizeof(LANCE_RxDescr);
-		if (priv->nextrx >= RXCOUNT) {
-			priv->nextrx = 0;
-			descraddr = RAM_RXBASE;
-		}
-	}
-
-	/* reset RINT bit */
-
-	SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_RINT);
-	return GetLANCE(dev, LANCE_CSR0);
-}
-
-/* transmit interrupt */
-
-static u16 irqtx_handler(struct net_device *dev, u16 oldcsr0)
-{
-	skmca_priv *priv = netdev_priv(dev);
-	LANCE_TxDescr descr;
-	unsigned int descraddr;
-
-	/* check descriptors at most until no busy one is left */
-
-	descraddr =
-	    RAM_TXBASE + (priv->nexttxdone * sizeof(LANCE_TxDescr));
-	while (priv->txbusy > 0) {
-		/* read descriptor */
-		memcpy_fromio(&descr, priv->base + descraddr,
-			     sizeof(LANCE_TxDescr));
-
-		/* if the LANCE still owns this one, we've worked out all sent packets */
-		if ((descr.Flags & TXDSCR_FLAGS_OWN) != 0)
-			break;
-
-#ifdef DEBUG
-		PrTime();
-		printk("Send packet done on descr %d\n", priv->nexttxdone);
-#endif
-
-		/* update statistics */
-		if ((descr.Flags & TXDSCR_FLAGS_ERR) == 0) {
-			priv->stat.tx_packets++;
-			priv->stat.tx_bytes++;
-		} else {
-			priv->stat.tx_errors++;
-			if ((descr.Status & TXDSCR_STATUS_UFLO) != 0) {
-				priv->stat.tx_fifo_errors++;
-				InitLANCE(dev);
-			}
-				else
-			    if ((descr.Status & TXDSCR_STATUS_LCOL) !=
-				0) priv->stat.tx_window_errors++;
-			else if ((descr.Status & TXDSCR_STATUS_LCAR) != 0)
-				priv->stat.tx_carrier_errors++;
-			else if ((descr.Status & TXDSCR_STATUS_RTRY) != 0)
-				priv->stat.tx_aborted_errors++;
-		}
-
-		/* go to next descriptor */
-		priv->nexttxdone++;
-		descraddr += sizeof(LANCE_TxDescr);
-		if (priv->nexttxdone >= TXCOUNT) {
-			priv->nexttxdone = 0;
-			descraddr = RAM_TXBASE;
-		}
-		priv->txbusy--;
-	}
-
-	/* reset TX interrupt bit */
-
-	SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_TINT);
-	oldcsr0 = GetLANCE(dev, LANCE_CSR0);
-
-	/* at least one descriptor is freed.  Therefore we can accept
-	   a new one */
-	/* inform upper layers we're in business again */
-
-	netif_wake_queue(dev);
-
-	return oldcsr0;
-}
-
-/* general interrupt entry */
-
-static irqreturn_t irq_handler(int irq, void *device)
-{
-	struct net_device *dev = (struct net_device *) device;
-	u16 csr0val;
-
-	/* read CSR0 to get interrupt cause */
-
-	csr0val = GetLANCE(dev, LANCE_CSR0);
-
-	/* in case we're not meant... */
-
-	if ((csr0val & CSR0_INTR) == 0)
-		return IRQ_NONE;
-
-#if 0
-	set_bit(LINK_STATE_RXSEM, &dev->state);
-#endif
-
-	/* loop through the interrupt bits until everything is clear */
-
-	do {
-		if ((csr0val & CSR0_IDON) != 0)
-			csr0val = irqstart_handler(dev, csr0val);
-		if ((csr0val & CSR0_RINT) != 0)
-			csr0val = irqrx_handler(dev, csr0val);
-		if ((csr0val & CSR0_MISS) != 0)
-			csr0val = irqmiss_handler(dev, csr0val);
-		if ((csr0val & CSR0_TINT) != 0)
-			csr0val = irqtx_handler(dev, csr0val);
-		if ((csr0val & CSR0_MERR) != 0) {
-			SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_MERR);
-			csr0val = GetLANCE(dev, LANCE_CSR0);
-		}
-		if ((csr0val & CSR0_BABL) != 0) {
-			SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_BABL);
-			csr0val = GetLANCE(dev, LANCE_CSR0);
-		}
-	}
-	while ((csr0val & CSR0_INTR) != 0);
-
-#if 0
-	clear_bit(LINK_STATE_RXSEM, &dev->state);
-#endif
-	return IRQ_HANDLED;
-}
-
-/* ------------------------------------------------------------------------
- * driver methods
- * ------------------------------------------------------------------------ */
-
-/* MCA info */
-
-static int skmca_getinfo(char *buf, int slot, void *d)
-{
-	int len = 0, i;
-	struct net_device *dev = (struct net_device *) d;
-	skmca_priv *priv;
-
-	/* can't say anything about an uninitialized device... */
-
-	if (dev == NULL)
-		return len;
-	priv = netdev_priv(dev);
-
-	/* print info */
-
-	len += sprintf(buf + len, "IRQ: %d\n", priv->realirq);
-	len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start,
-		       dev->mem_end - 1);
-	len +=
-	    sprintf(buf + len, "Transceiver: %s\n",
-		    MediaNames[priv->medium]);
-	len += sprintf(buf + len, "Device: %s\n", dev->name);
-	len += sprintf(buf + len, "MAC address:");
-	for (i = 0; i < 6; i++)
-		len += sprintf(buf + len, " %02x", dev->dev_addr[i]);
-	buf[len++] = '\n';
-	buf[len] = 0;
-
-	return len;
-}
-
-/* open driver.  Means also initialization and start of LANCE */
-
-static int skmca_open(struct net_device *dev)
-{
-	int result;
-	skmca_priv *priv = netdev_priv(dev);
-
-	/* register resources - only necessary for IRQ */
-	result =
-	    request_irq(priv->realirq, irq_handler,
-			IRQF_SHARED | IRQF_SAMPLE_RANDOM, "sk_mca", dev);
-	if (result != 0) {
-		printk("%s: failed to register irq %d\n", dev->name,
-		       dev->irq);
-		return result;
-	}
-	dev->irq = priv->realirq;
-
-	/* set up the card and LANCE */
-
-	InitBoard(dev);
-
-	/* set up flags */
-
-	netif_start_queue(dev);
-
-	return 0;
-}
-
-/* close driver.  Shut down board and free allocated resources */
-
-static int skmca_close(struct net_device *dev)
-{
-	/* turn off board */
-	DeinitBoard(dev);
-
-	/* release resources */
-	if (dev->irq != 0)
-		free_irq(dev->irq, dev);
-	dev->irq = 0;
-
-	return 0;
-}
-
-/* transmit a block. */
-
-static int skmca_tx(struct sk_buff *skb, struct net_device *dev)
-{
-	skmca_priv *priv = netdev_priv(dev);
-	LANCE_TxDescr descr;
-	unsigned int address;
-	int tmplen, retval = 0;
-	unsigned long flags;
-
-	/* if we get called with a NULL descriptor, the Ethernet layer thinks
-	   our card is stuck an we should reset it.  We'll do this completely: */
-
-	if (skb == NULL) {
-		DeinitBoard(dev);
-		InitBoard(dev);
-		return 0;	/* don't try to free the block here ;-) */
-	}
-
-	/* is there space in the Tx queue ? If no, the upper layer gave us a
-	   packet in spite of us not being ready and is really in trouble.
-	   We'll do the dropping for him: */
-	if (priv->txbusy >= TXCOUNT) {
-		priv->stat.tx_dropped++;
-		retval = -EIO;
-		goto tx_done;
-	}
-
-	/* get TX descriptor */
-	address = RAM_TXBASE + (priv->nexttxput * sizeof(LANCE_TxDescr));
-	memcpy_fromio(&descr, priv->base + address, sizeof(LANCE_TxDescr));
-
-	/* enter packet length as 2s complement - assure minimum length */
-	tmplen = skb->len;
-	if (tmplen < 60)
-		tmplen = 60;
-	descr.Len = 65536 - tmplen;
-
-	/* copy filler into RAM - in case we're filling up...
-	   we're filling a bit more than necessary, but that doesn't harm
-	   since the buffer is far larger... */
-	if (tmplen > skb->len) {
-		char *fill = "NetBSD is a nice OS too! ";
-		unsigned int destoffs = 0, l = strlen(fill);
-
-		while (destoffs < tmplen) {
-			memcpy_toio(priv->base + descr.LowAddr +
-				   destoffs, fill, l);
-			destoffs += l;
-		}
-	}
-
-	/* do the real data copying */
-	memcpy_toio(priv->base + descr.LowAddr, skb->data, skb->len);
-
-	/* hand descriptor over to LANCE - this is the first and last chunk */
-	descr.Flags =
-	    TXDSCR_FLAGS_OWN | TXDSCR_FLAGS_STP | TXDSCR_FLAGS_ENP;
-
-#ifdef DEBUG
-	PrTime();
-	printk("Send packet on descr %d len %d\n", priv->nexttxput,
-	       skb->len);
-#endif
-
-	/* one more descriptor busy */
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	priv->nexttxput++;
-	if (priv->nexttxput >= TXCOUNT)
-		priv->nexttxput = 0;
-	priv->txbusy++;
-
-	/* are we saturated ? */
-
-	if (priv->txbusy >= TXCOUNT)
-		netif_stop_queue(dev);
-
-	/* write descriptor back to RAM */
-	memcpy_toio(priv->base + address, &descr, sizeof(LANCE_TxDescr));
-
-	/* if no descriptors were active, give the LANCE a hint to read it
-	   immediately */
-
-	if (priv->txbusy == 0)
-		SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_TDMD);
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-      tx_done:
-
-	dev_kfree_skb(skb);
-
-	return retval;
-}
-
-/* return pointer to Ethernet statistics */
-
-static struct net_device_stats *skmca_stats(struct net_device *dev)
-{
-	skmca_priv *priv = netdev_priv(dev);
-
-	return &(priv->stat);
-}
-
-/* switch receiver mode.  We use the LANCE's multicast filter to prefilter
-   multicast addresses. */
-
-static void skmca_set_multicast_list(struct net_device *dev)
-{
-	skmca_priv *priv = netdev_priv(dev);
-	LANCE_InitBlock block;
-
-	/* first stop the LANCE... */
-	StopLANCE(dev);
-
-	/* ...then modify the initialization block... */
-	memcpy_fromio(&block, priv->base + RAM_INITBASE, sizeof(block));
-	if (dev->flags & IFF_PROMISC)
-		block.Mode |= LANCE_INIT_PROM;
-	else
-		block.Mode &= ~LANCE_INIT_PROM;
-
-	if (dev->flags & IFF_ALLMULTI) {	/* get all multicasts */
-		memset(block.LAdrF, 0xff, sizeof(block.LAdrF));
-	} else {		/* get selected/no multicasts */
-
-		struct dev_mc_list *mptr;
-		int code;
-
-		memset(block.LAdrF, 0, sizeof(block.LAdrF));
-		for (mptr = dev->mc_list; mptr != NULL; mptr = mptr->next) {
-			code = GetHash(mptr->dmi_addr);
-			block.LAdrF[(code >> 3) & 7] |= 1 << (code & 7);
-		}
-	}
-
-	memcpy_toio(priv->base + RAM_INITBASE, &block, sizeof(block));
-
-	/* ...then reinit LANCE with the correct flags */
-	InitLANCE(dev);
-}
-
-/* ------------------------------------------------------------------------
- * hardware check
- * ------------------------------------------------------------------------ */
-
-static int startslot;		/* counts through slots when probing multiple devices */
-
-static void cleanup_card(struct net_device *dev)
-{
-	skmca_priv *priv = netdev_priv(dev);
-	DeinitBoard(dev);
-	if (dev->irq != 0)
-		free_irq(dev->irq, dev);
-	iounmap(priv->base);
-	mca_mark_as_unused(priv->slot);
-	mca_set_adapter_procfn(priv->slot, NULL, NULL);
-}
-
-struct net_device * __init skmca_probe(int unit)
-{
-	struct net_device *dev;
-	int force_detect = 0;
-	int junior, slot, i;
-	int base = 0, irq = 0;
-	skmca_priv *priv;
-	skmca_medium medium;
-	int err;
-
-	/* can't work without an MCA bus ;-) */
-
-	if (MCA_bus == 0)
-		return ERR_PTR(-ENODEV);
-
-	dev = alloc_etherdev(sizeof(skmca_priv));
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	if (unit >= 0) {
-		sprintf(dev->name, "eth%d", unit);
-		netdev_boot_setup_check(dev);
-	}
-
-	SET_MODULE_OWNER(dev);
-
-	/* start address of 1 --> forced detection */
-
-	if (dev->mem_start == 1)
-		force_detect = 1;
-
-	/* search through slots */
-
-	base = dev->mem_start;
-	irq = dev->base_addr;
-	for (slot = startslot; (slot = dofind(&junior, slot)) != -1; slot++) {
-		/* deduce card addresses */
-
-		getaddrs(slot, junior, &base, &irq, &medium);
-
-		/* slot already in use ? */
-
-		if (mca_is_adapter_used(slot))
-			continue;
-
-		/* were we looking for something different ? */
-
-		if (dev->irq && dev->irq != irq)
-			continue;
-		if (dev->mem_start && dev->mem_start != base)
-			continue;
-
-		/* found something that matches */
-
-		break;
-	}
-
-	/* nothing found ? */
-
-	if (slot == -1) {
-		free_netdev(dev);
-		return (base || irq) ? ERR_PTR(-ENXIO) : ERR_PTR(-ENODEV);
-	}
-
-	/* make procfs entries */
-
-	if (junior)
-		mca_set_adapter_name(slot,
-				     "SKNET junior MC2 Ethernet Adapter");
-	else
-		mca_set_adapter_name(slot, "SKNET MC2+ Ethernet Adapter");
-	mca_set_adapter_procfn(slot, (MCA_ProcFn) skmca_getinfo, dev);
-
-	mca_mark_as_used(slot);
-
-	/* announce success */
-	printk("%s: SKNet %s adapter found in slot %d\n", dev->name,
-	       junior ? "Junior MC2" : "MC2+", slot + 1);
-
-	priv = netdev_priv(dev);
-	priv->base = ioremap(base, 0x4000);
-	if (!priv->base) {
-		mca_set_adapter_procfn(slot, NULL, NULL);
-		mca_mark_as_unused(slot);
-		free_netdev(dev);
-		return ERR_PTR(-ENOMEM);
-	}
-
-	priv->slot = slot;
-	priv->macbase = priv->base + 0x3fc0;
-	priv->ioregaddr = priv->base + 0x3ff0;
-	priv->ctrladdr = priv->base + 0x3ff2;
-	priv->cmdaddr = priv->base + 0x3ff3;
-	priv->medium = medium;
-	memset(&priv->stat, 0, sizeof(struct net_device_stats));
-	spin_lock_init(&priv->lock);
-
-	/* set base + irq for this device (irq not allocated so far) */
-	dev->irq = 0;
-	dev->mem_start = base;
-	dev->mem_end = base + 0x4000;
-
-	/* autoprobe ? */
-	if (irq < 0) {
-		int nirq;
-
-		printk
-		    ("%s: ambigous POS bit combination, must probe for IRQ...\n",
-		     dev->name);
-		nirq = ProbeIRQ(dev);
-		if (nirq <= 0)
-			printk("%s: IRQ probe failed, assuming IRQ %d",
-			       dev->name, priv->realirq = -irq);
-		else
-			priv->realirq = nirq;
-	} else
-		priv->realirq = irq;
-
-	/* set methods */
-	dev->open = skmca_open;
-	dev->stop = skmca_close;
-	dev->hard_start_xmit = skmca_tx;
-	dev->do_ioctl = NULL;
-	dev->get_stats = skmca_stats;
-	dev->set_multicast_list = skmca_set_multicast_list;
-	dev->flags |= IFF_MULTICAST;
-
-	/* copy out MAC address */
-	for (i = 0; i < 6; i++)
-		dev->dev_addr[i] = readb(priv->macbase + (i << 1));
-
-	/* print config */
-	printk("%s: IRQ %d, memory %#lx-%#lx, "
-	       "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n",
-	       dev->name, priv->realirq, dev->mem_start, dev->mem_end - 1,
-	       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-	       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
-	printk("%s: %s medium\n", dev->name, MediaNames[priv->medium]);
-
-	/* reset board */
-
-	ResetBoard(dev);
-
-	startslot = slot + 1;
-
-	err = register_netdev(dev);
-	if (err) {
-		cleanup_card(dev);
-		free_netdev(dev);
-		dev = ERR_PTR(err);
-	}
-	return dev;
-}
-
-/* ------------------------------------------------------------------------
- * modularization support
- * ------------------------------------------------------------------------ */
-
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-
-#define DEVMAX 5
-
-static struct net_device *moddevs[DEVMAX];
-
-int init_module(void)
-{
-	int z;
-
-	startslot = 0;
-	for (z = 0; z < DEVMAX; z++) {
-		struct net_device *dev = skmca_probe(-1);
-		if (IS_ERR(dev))
-			break;
-		moddevs[z] = dev;
-	}
-	if (!z)
-		return -EIO;
-	return 0;
-}
-
-void cleanup_module(void)
-{
-	int z;
-
-	for (z = 0; z < DEVMAX; z++) {
-		struct net_device *dev = moddevs[z];
-		if (dev) {
-			unregister_netdev(dev);
-			cleanup_card(dev);
-			free_netdev(dev);
-		}
-	}
-}
-#endif				/* MODULE */
diff --git a/drivers/net/sk_mca.h b/drivers/net/sk_mca.h
deleted file mode 100644
index 0dae056..0000000
--- a/drivers/net/sk_mca.h
+++ /dev/null
@@ -1,170 +0,0 @@
-#ifndef _SK_MCA_INCLUDE_
-#define _SK_MCA_INCLUDE_
-
-#ifdef _SK_MCA_DRIVER_
-
-/* Adapter ID's */
-#define SKNET_MCA_ID 0x6afd
-#define SKNET_JUNIOR_MCA_ID 0x6be9
-
-/* media enumeration - defined in a way that it fits onto the MC2+'s
-   POS registers... */
-
-typedef enum { Media_10Base2, Media_10BaseT,
-	Media_10Base5, Media_Unknown, Media_Count
-} skmca_medium;
-
-/* private structure */
-typedef struct {
-	unsigned int slot;	/* MCA-Slot-#                       */
-	void __iomem *base;
-	void __iomem *macbase;	/* base address of MAC address PROM */
-	void __iomem *ioregaddr;/* address of I/O-register (Lo)     */
-	void __iomem *ctrladdr;	/* address of control/stat register */
-	void __iomem *cmdaddr;	/* address of I/O-command register  */
-	int nextrx;		/* index of next RX descriptor to
-				   be read                          */
-	int nexttxput;		/* index of next free TX descriptor */
-	int nexttxdone;		/* index of next TX descriptor to
-				   be finished                      */
-	int txbusy;		/* # of busy TX descriptors         */
-	struct net_device_stats stat;	/* packet statistics            */
-	int realirq;		/* memorizes actual IRQ, even when
-				   currently not allocated          */
-	skmca_medium medium;	/* physical cannector               */
-	spinlock_t lock;
-} skmca_priv;
-
-/* card registers: control/status register bits */
-
-#define CTRL_ADR_DATA      0	/* Bit 0 = 0 ->access data register  */
-#define CTRL_ADR_RAP       1	/* Bit 0 = 1 ->access RAP register   */
-#define CTRL_RW_WRITE      0	/* Bit 1 = 0 ->write register        */
-#define CTRL_RW_READ       2	/* Bit 1 = 1 ->read register         */
-#define CTRL_RESET_ON      0	/* Bit 3 = 0 ->reset board           */
-#define CTRL_RESET_OFF     8	/* Bit 3 = 1 ->no reset of board     */
-
-#define STAT_ADR_DATA      0	/* Bit 0 of ctrl register read back  */
-#define STAT_ADR_RAP       1
-#define STAT_RW_WRITE      0	/* Bit 1 of ctrl register read back  */
-#define STAT_RW_READ       2
-#define STAT_RESET_ON      0	/* Bit 3 of ctrl register read back  */
-#define STAT_RESET_OFF     8
-#define STAT_IRQ_ACT       0	/* interrupt pending                 */
-#define STAT_IRQ_NOACT     16	/* no interrupt pending              */
-#define STAT_IO_NOBUSY     0	/* no transfer busy                  */
-#define STAT_IO_BUSY       32	/* transfer busy                     */
-
-/* I/O command register bits */
-
-#define IOCMD_GO           128	/* Bit 7 = 1 -> start register xfer  */
-
-/* LANCE registers */
-
-#define LANCE_CSR0         0	/* Status/Control                    */
-
-#define CSR0_ERR           0x8000	/* general error flag                */
-#define CSR0_BABL          0x4000	/* transmitter timeout               */
-#define CSR0_CERR          0x2000	/* collision error                   */
-#define CSR0_MISS          0x1000	/* lost Rx block                     */
-#define CSR0_MERR          0x0800	/* memory access error               */
-#define CSR0_RINT          0x0400	/* receiver interrupt                */
-#define CSR0_TINT          0x0200	/* transmitter interrupt             */
-#define CSR0_IDON          0x0100	/* initialization done               */
-#define CSR0_INTR          0x0080	/* general interrupt flag            */
-#define CSR0_INEA          0x0040	/* interrupt enable                  */
-#define CSR0_RXON          0x0020	/* receiver enabled                  */
-#define CSR0_TXON          0x0010	/* transmitter enabled               */
-#define CSR0_TDMD          0x0008	/* force transmission now            */
-#define CSR0_STOP          0x0004	/* stop LANCE                        */
-#define CSR0_STRT          0x0002	/* start LANCE                       */
-#define CSR0_INIT          0x0001	/* read initialization block         */
-
-#define LANCE_CSR1         1	/* addr bit 0..15 of initialization  */
-#define LANCE_CSR2         2	/*          16..23 block             */
-
-#define LANCE_CSR3         3	/* Bus control                       */
-#define CSR3_BCON_HOLD     0	/* Bit 0 = 0 -> BM1,BM0,HOLD         */
-#define CSR3_BCON_BUSRQ    1	/* Bit 0 = 1 -> BUSAK0,BYTE,BUSRQ    */
-#define CSR3_ALE_HIGH      0	/* Bit 1 = 0 -> ALE asserted high    */
-#define CSR3_ALE_LOW       2	/* Bit 1 = 1 -> ALE asserted low     */
-#define CSR3_BSWAP_OFF     0	/* Bit 2 = 0 -> no byte swap         */
-#define CSR3_BSWAP_ON      4	/* Bit 2 = 1 -> byte swap            */
-
-/* LANCE structures */
-
-typedef struct {		/* LANCE initialization block        */
-	u16 Mode;		/* mode flags                        */
-	u8 PAdr[6];		/* MAC address                       */
-	u8 LAdrF[8];		/* Multicast filter                  */
-	u32 RdrP;		/* Receive descriptor                */
-	u32 TdrP;		/* Transmit descriptor               */
-} LANCE_InitBlock;
-
-/* Mode flags init block */
-
-#define LANCE_INIT_PROM    0x8000	/* enable promiscous mode            */
-#define LANCE_INIT_INTL    0x0040	/* internal loopback                 */
-#define LANCE_INIT_DRTY    0x0020	/* disable retry                     */
-#define LANCE_INIT_COLL    0x0010	/* force collision                   */
-#define LANCE_INIT_DTCR    0x0008	/* disable transmit CRC              */
-#define LANCE_INIT_LOOP    0x0004	/* loopback                          */
-#define LANCE_INIT_DTX     0x0002	/* disable transmitter               */
-#define LANCE_INIT_DRX     0x0001	/* disable receiver                  */
-
-typedef struct {		/* LANCE Tx descriptor               */
-	u16 LowAddr;		/* bit 0..15 of address              */
-	u16 Flags;		/* bit 16..23 of address + Flags     */
-	u16 Len;		/* 2s complement of packet length    */
-	u16 Status;		/* Result of transmission            */
-} LANCE_TxDescr;
-
-#define TXDSCR_FLAGS_OWN   0x8000	/* LANCE owns descriptor             */
-#define TXDSCR_FLAGS_ERR   0x4000	/* summary error flag                */
-#define TXDSCR_FLAGS_MORE  0x1000	/* more than one retry needed?       */
-#define TXDSCR_FLAGS_ONE   0x0800	/* one retry?                        */
-#define TXDSCR_FLAGS_DEF   0x0400	/* transmission deferred?            */
-#define TXDSCR_FLAGS_STP   0x0200	/* first packet in chain?            */
-#define TXDSCR_FLAGS_ENP   0x0100	/* last packet in chain?             */
-
-#define TXDSCR_STATUS_BUFF 0x8000	/* buffer error?                     */
-#define TXDSCR_STATUS_UFLO 0x4000	/* silo underflow during transmit?   */
-#define TXDSCR_STATUS_LCOL 0x1000	/* late collision?                   */
-#define TXDSCR_STATUS_LCAR 0x0800	/* loss of carrier?                  */
-#define TXDSCR_STATUS_RTRY 0x0400	/* retry error?                      */
-
-typedef struct {		/* LANCE Rx descriptor               */
-	u16 LowAddr;		/* bit 0..15 of address              */
-	u16 Flags;		/* bit 16..23 of address + Flags     */
-	u16 MaxLen;		/* 2s complement of buffer length    */
-	u16 Len;		/* packet length                     */
-} LANCE_RxDescr;
-
-#define RXDSCR_FLAGS_OWN   0x8000	/* LANCE owns descriptor             */
-#define RXDSCR_FLAGS_ERR   0x4000	/* summary error flag                */
-#define RXDSCR_FLAGS_FRAM  0x2000	/* framing error flag                */
-#define RXDSCR_FLAGS_OFLO  0x1000	/* FIFO overflow?                    */
-#define RXDSCR_FLAGS_CRC   0x0800	/* CRC error?                        */
-#define RXDSCR_FLAGS_BUFF  0x0400	/* buffer error?                     */
-#define RXDSCR_FLAGS_STP   0x0200	/* first packet in chain?            */
-#define RXDCSR_FLAGS_ENP   0x0100	/* last packet in chain?             */
-
-/* RAM layout */
-
-#define TXCOUNT            4	/* length of TX descriptor queue     */
-#define LTXCOUNT           2	/* log2 of it                        */
-#define RXCOUNT            4	/* length of RX descriptor queue     */
-#define LRXCOUNT           2	/* log2 of it                        */
-
-#define RAM_INITBASE       0	/* LANCE init block                  */
-#define RAM_TXBASE         24	/* Start of TX descriptor queue      */
-#define RAM_RXBASE         \
-(RAM_TXBASE + (TXCOUNT * 8))	/* Start of RX descriptor queue      */
-#define RAM_DATABASE       \
-(RAM_RXBASE + (RXCOUNT * 8))	/* Start of data area for frames     */
-#define RAM_BUFSIZE        1580	/* max. frame size - should never be
-				   reached                           */
-
-#endif				/* _SK_MCA_DRIVER_ */
-
-#endif	/* _SK_MCA_INCLUDE_ */
diff --git a/drivers/net/skfp/can.c b/drivers/net/skfp/can.c
deleted file mode 100644
index 8a49abc..0000000
--- a/drivers/net/skfp/can.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/******************************************************************************
- *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *
- *	See the file "skfddi.c" for further information.
- *
- *	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.
- *
- *	The information in this file is provided "AS IS" without warranty.
- *
- ******************************************************************************/
-
-#ifndef	lint
-static const char xID_sccs[] = "@(#)can.c	1.5 97/04/07 (C) SK " ;
-#endif
-
-/*
- * canonical bit order
- */
-const u_char canonical[256] = {
-	0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,
-	0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
-	0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,
-	0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
-	0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,
-	0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
-	0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,
-	0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
-	0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,
-	0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
-	0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,
-	0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
-	0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,
-	0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
-	0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,
-	0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
-	0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,
-	0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
-	0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,
-	0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
-	0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,
-	0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
-	0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,
-	0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
-	0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,
-	0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
-	0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,
-	0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
-	0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,
-	0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
-	0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,
-	0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
-} ;
-
-#ifdef	MAKE_TABLE
-int byte_reverse(x)
-int x ;
-{
-	int     y = 0 ;
-
-	if (x & 0x01)
-		y |= 0x80 ;
-	if (x & 0x02)
-		y |= 0x40 ;
-	if (x & 0x04)
-		y |= 0x20 ;
-	if (x & 0x08)
-		y |= 0x10 ;
-	if (x & 0x10)
-		y |= 0x08 ;
-	if (x & 0x20)
-		y |= 0x04 ;
-	if (x & 0x40)
-		y |= 0x02 ;
-	if (x & 0x80)
-		y |= 0x01 ;
-	return(y) ;
-}
-#endif
diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c
index 5b47583..4fe624b 100644
--- a/drivers/net/skfp/drvfbi.c
+++ b/drivers/net/skfp/drvfbi.c
@@ -23,6 +23,7 @@
 #include "h/smc.h"
 #include "h/supern_2.h"
 #include "h/skfbiinc.h"
+#include <linux/bitrev.h>
 
 #ifndef	lint
 static const char ID_sccs[] = "@(#)drvfbi.c	1.63 99/02/11 (C) SK " ;
@@ -445,16 +446,14 @@
 	char PmdType ;
 	int	i ;
 
-	extern const u_char canonical[256] ;
-
 #if	(defined(ISA) || defined(MCA))
 	for (i = 0; i < 4 ;i++) {	/* read mac address from board */
 		smc->hw.fddi_phys_addr.a[i] =
-			canonical[(inpw(PR_A(i+SA_MAC))&0xff)] ;
+			bitrev8(inpw(PR_A(i+SA_MAC)));
 	}
 	for (i = 4; i < 6; i++) {
 		smc->hw.fddi_phys_addr.a[i] =
-			canonical[(inpw(PR_A(i+SA_MAC+PRA_OFF))&0xff)] ;
+			bitrev8(inpw(PR_A(i+SA_MAC+PRA_OFF)));
 	}
 #endif
 #ifdef	EISA
@@ -464,17 +463,17 @@
 	 */
 	for (i = 0; i < 4 ;i++) {	/* read mac address from board */
 		smc->hw.fddi_phys_addr.a[i] =
-			canonical[inp(PR_A(i+SA_MAC))] ;
+			bitrev8(inp(PR_A(i+SA_MAC)));
 	}
 	for (i = 4; i < 6; i++) {
 		smc->hw.fddi_phys_addr.a[i] =
-			canonical[inp(PR_A(i+SA_MAC+PRA_OFF))] ;
+			bitrev8(inp(PR_A(i+SA_MAC+PRA_OFF)));
 	}
 #endif
 #ifdef	PCI
 	for (i = 0; i < 6; i++) {	/* read mac address from board */
 		smc->hw.fddi_phys_addr.a[i] =
-			canonical[inp(ADDR(B2_MAC_0+i))] ;
+			bitrev8(inp(ADDR(B2_MAC_0+i)));
 	}
 #endif
 #ifndef	PCI
@@ -493,7 +492,7 @@
 	if (mac_addr) {
 		for (i = 0; i < 6 ;i++) {
 			smc->hw.fddi_canon_addr.a[i] = mac_addr[i] ;
-			smc->hw.fddi_home_addr.a[i] = canonical[mac_addr[i]] ;
+			smc->hw.fddi_home_addr.a[i] = bitrev8(mac_addr[i]);
 		}
 		return ;
 	}
@@ -501,7 +500,7 @@
 
 	for (i = 0; i < 6 ;i++) {
 		smc->hw.fddi_canon_addr.a[i] =
-			canonical[smc->hw.fddi_phys_addr.a[i]] ;
+			bitrev8(smc->hw.fddi_phys_addr.a[i]);
 	}
 }
 
@@ -1269,11 +1268,8 @@
 {
 	int i ;
 
-	extern const u_char canonical[256] ;
-
-	for (i = 0 ; i < 6 ; i++) {
-		bia_addr->a[i] = canonical[smc->hw.fddi_phys_addr.a[i]] ;
-	}
+	for (i = 0 ; i < 6 ; i++)
+		bia_addr->a[i] = bitrev8(smc->hw.fddi_phys_addr.a[i]);
 }
 
 void smt_start_watchdog(struct s_smc *smc)
diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c
index 0784f55..a45205d 100644
--- a/drivers/net/skfp/fplustm.c
+++ b/drivers/net/skfp/fplustm.c
@@ -22,7 +22,7 @@
 #include "h/fddi.h"
 #include "h/smc.h"
 #include "h/supern_2.h"
-#include "can.c"
+#include <linux/bitrev.h>
 
 #ifndef	lint
 static const char ID_sccs[] = "@(#)fplustm.c	1.32 99/02/23 (C) SK " ;
@@ -1073,7 +1073,7 @@
 	if (can) {
 		p = own->a ;
 		for (i = 0 ; i < 6 ; i++, p++)
-			*p = canonical[*p] ;
+			*p = bitrev8(*p);
 	}
 	slot = NULL;
 	for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){
diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c
index 99a776a..fe84780 100644
--- a/drivers/net/skfp/smt.c
+++ b/drivers/net/skfp/smt.c
@@ -18,6 +18,7 @@
 #include "h/fddi.h"
 #include "h/smc.h"
 #include "h/smt_p.h"
+#include <linux/bitrev.h>
 
 #define KERNEL
 #include "h/smtstate.h"
@@ -26,8 +27,6 @@
 static const char ID_sccs[] = "@(#)smt.c	2.43 98/11/23 (C) SK " ;
 #endif
 
-extern const u_char canonical[256] ;
-
 /*
  * FC in SMbuf
  */
@@ -180,7 +179,7 @@
 	driver_get_bia(smc,&smc->mib.fddiSMTStationId.sid_node) ;
 	for (i = 0 ; i < 6 ; i ++) {
 		smc->mib.fddiSMTStationId.sid_node.a[i] =
-			canonical[smc->mib.fddiSMTStationId.sid_node.a[i]] ;
+			bitrev8(smc->mib.fddiSMTStationId.sid_node.a[i]);
 	}
 	smc->mib.fddiSMTManufacturerData[0] =
 		smc->mib.fddiSMTStationId.sid_node.a[0] ;
@@ -2049,9 +2048,8 @@
 
 	SK_UNUSED(smc) ;
 
-	for (i = len; i ; i--, data++) {
-		*data = canonical[*(u_char *)data] ;
-	}
+	for (i = len; i ; i--, data++)
+		*data = bitrev8(*data);
 }
 #endif
 
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 45283f3..e482e7f 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -42,7 +42,7 @@
 #include "skge.h"
 
 #define DRV_NAME		"skge"
-#define DRV_VERSION		"1.9"
+#define DRV_VERSION		"1.10"
 #define PFX			DRV_NAME " "
 
 #define DEFAULT_TX_RING_SIZE	128
@@ -132,18 +132,93 @@
 }
 
 /* Wake on Lan only supported on Yukon chips with rev 1 or above */
-static int wol_supported(const struct skge_hw *hw)
+static u32 wol_supported(const struct skge_hw *hw)
 {
-	return !((hw->chip_id == CHIP_ID_GENESIS ||
-		  (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0)));
+	if (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev != 0)
+		return WAKE_MAGIC | WAKE_PHY;
+	else
+		return 0;
+}
+
+static u32 pci_wake_enabled(struct pci_dev *dev)
+{
+	int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+	u16 value;
+
+	/* If device doesn't support PM Capabilities, but request is to disable
+	 * wake events, it's a nop; otherwise fail */
+	if (!pm)
+		return 0;
+
+	pci_read_config_word(dev, pm + PCI_PM_PMC, &value);
+
+	value &= PCI_PM_CAP_PME_MASK;
+	value >>= ffs(PCI_PM_CAP_PME_MASK) - 1;   /* First bit of mask */
+
+	return value != 0;
+}
+
+static void skge_wol_init(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	enum pause_control save_mode;
+	u32 ctrl;
+
+	/* Bring hardware out of reset */
+	skge_write16(hw, B0_CTST, CS_RST_CLR);
+	skge_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR);
+
+	skge_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
+	skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
+
+	/* Force to 10/100 skge_reset will re-enable on resume	 */
+	save_mode = skge->flow_control;
+	skge->flow_control = FLOW_MODE_SYMMETRIC;
+
+	ctrl = skge->advertising;
+	skge->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full);
+
+	skge_phy_reset(skge);
+
+	skge->flow_control = save_mode;
+	skge->advertising = ctrl;
+
+	/* Set GMAC to no flow control and auto update for speed/duplex */
+	gma_write16(hw, port, GM_GP_CTRL,
+		    GM_GPCR_FC_TX_DIS|GM_GPCR_TX_ENA|GM_GPCR_RX_ENA|
+		    GM_GPCR_DUP_FULL|GM_GPCR_FC_RX_DIS|GM_GPCR_AU_FCT_DIS);
+
+	/* Set WOL address */
+	memcpy_toio(hw->regs + WOL_REGS(port, WOL_MAC_ADDR),
+		    skge->netdev->dev_addr, ETH_ALEN);
+
+	/* Turn on appropriate WOL control bits */
+	skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), WOL_CTL_CLEAR_RESULT);
+	ctrl = 0;
+	if (skge->wol & WAKE_PHY)
+		ctrl |= WOL_CTL_ENA_PME_ON_LINK_CHG|WOL_CTL_ENA_LINK_CHG_UNIT;
+	else
+		ctrl |= WOL_CTL_DIS_PME_ON_LINK_CHG|WOL_CTL_DIS_LINK_CHG_UNIT;
+
+	if (skge->wol & WAKE_MAGIC)
+		ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT;
+	else
+		ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;;
+
+	ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT;
+	skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl);
+
+	/* block receiver */
+	skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
 }
 
 static void skge_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
 	struct skge_port *skge = netdev_priv(dev);
 
-	wol->supported = wol_supported(skge->hw) ? WAKE_MAGIC : 0;
-	wol->wolopts = skge->wol ? WAKE_MAGIC : 0;
+	wol->supported = wol_supported(skge->hw);
+	wol->wolopts = skge->wol;
 }
 
 static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -151,23 +226,12 @@
 	struct skge_port *skge = netdev_priv(dev);
 	struct skge_hw *hw = skge->hw;
 
-	if (wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
+	if (wol->wolopts & wol_supported(hw))
 		return -EOPNOTSUPP;
 
-	if (wol->wolopts == WAKE_MAGIC && !wol_supported(hw))
-		return -EOPNOTSUPP;
-
-	skge->wol = wol->wolopts == WAKE_MAGIC;
-
-	if (skge->wol) {
-		memcpy_toio(hw->regs + WOL_MAC_ADDR, dev->dev_addr, ETH_ALEN);
-
-		skge_write16(hw, WOL_CTRL_STAT,
-			     WOL_CTL_ENA_PME_ON_MAGIC_PKT |
-			     WOL_CTL_ENA_MAGIC_PKT_UNIT);
-	} else
-		skge_write16(hw, WOL_CTRL_STAT, WOL_CTL_DEFAULT);
-
+	skge->wol = wol->wolopts;
+	if (!netif_running(dev))
+		skge_wol_init(skge);
 	return 0;
 }
 
@@ -2373,6 +2437,9 @@
 	size_t rx_size, tx_size;
 	int err;
 
+	if (!is_valid_ether_addr(dev->dev_addr))
+		return -EINVAL;
+
 	if (netif_msg_ifup(skge))
 		printk(KERN_INFO PFX "%s: enabling interface\n", dev->name);
 
@@ -2392,7 +2459,7 @@
 	BUG_ON(skge->dma & 7);
 
 	if ((u64)skge->dma >> 32 != ((u64) skge->dma + skge->mem_size) >> 32) {
-		printk(KERN_ERR PFX "pci_alloc_consistent region crosses 4G boundary\n");
+		dev_err(&hw->pdev->dev, "pci_alloc_consistent region crosses 4G boundary\n");
 		err = -EINVAL;
 		goto free_pci_mem;
 	}
@@ -3001,6 +3068,7 @@
 /* Handle device specific framing and timeout interrupts */
 static void skge_error_irq(struct skge_hw *hw)
 {
+	struct pci_dev *pdev = hw->pdev;
 	u32 hwstatus = skge_read32(hw, B0_HWE_ISRC);
 
 	if (hw->chip_id == CHIP_ID_GENESIS) {
@@ -3016,12 +3084,12 @@
 	}
 
 	if (hwstatus & IS_RAM_RD_PAR) {
-		printk(KERN_ERR PFX "Ram read data parity error\n");
+		dev_err(&pdev->dev, "Ram read data parity error\n");
 		skge_write16(hw, B3_RI_CTRL, RI_CLR_RD_PERR);
 	}
 
 	if (hwstatus & IS_RAM_WR_PAR) {
-		printk(KERN_ERR PFX "Ram write data parity error\n");
+		dev_err(&pdev->dev, "Ram write data parity error\n");
 		skge_write16(hw, B3_RI_CTRL, RI_CLR_WR_PERR);
 	}
 
@@ -3032,38 +3100,38 @@
 		skge_mac_parity(hw, 1);
 
 	if (hwstatus & IS_R1_PAR_ERR) {
-		printk(KERN_ERR PFX "%s: receive queue parity error\n",
-		       hw->dev[0]->name);
+		dev_err(&pdev->dev, "%s: receive queue parity error\n",
+			hw->dev[0]->name);
 		skge_write32(hw, B0_R1_CSR, CSR_IRQ_CL_P);
 	}
 
 	if (hwstatus & IS_R2_PAR_ERR) {
-		printk(KERN_ERR PFX "%s: receive queue parity error\n",
-		       hw->dev[1]->name);
+		dev_err(&pdev->dev, "%s: receive queue parity error\n",
+			hw->dev[1]->name);
 		skge_write32(hw, B0_R2_CSR, CSR_IRQ_CL_P);
 	}
 
 	if (hwstatus & (IS_IRQ_MST_ERR|IS_IRQ_STAT)) {
 		u16 pci_status, pci_cmd;
 
-		pci_read_config_word(hw->pdev, PCI_COMMAND, &pci_cmd);
-		pci_read_config_word(hw->pdev, PCI_STATUS, &pci_status);
+		pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
+		pci_read_config_word(pdev, PCI_STATUS, &pci_status);
 
-		printk(KERN_ERR PFX "%s: PCI error cmd=%#x status=%#x\n",
-			       pci_name(hw->pdev), pci_cmd, pci_status);
+		dev_err(&pdev->dev, "PCI error cmd=%#x status=%#x\n",
+			pci_cmd, pci_status);
 
 		/* Write the error bits back to clear them. */
 		pci_status &= PCI_STATUS_ERROR_BITS;
 		skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
-		pci_write_config_word(hw->pdev, PCI_COMMAND,
+		pci_write_config_word(pdev, PCI_COMMAND,
 				      pci_cmd | PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
-		pci_write_config_word(hw->pdev, PCI_STATUS, pci_status);
+		pci_write_config_word(pdev, PCI_STATUS, pci_status);
 		skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
 
 		/* if error still set then just ignore it */
 		hwstatus = skge_read32(hw, B0_HWE_ISRC);
 		if (hwstatus & IS_IRQ_STAT) {
-			printk(KERN_INFO PFX "unable to clear error (so ignoring them)\n");
+			dev_warn(&hw->pdev->dev, "unable to clear error (so ignoring them)\n");
 			hw->intr_mask &= ~IS_HW_ERR;
 		}
 	}
@@ -3277,8 +3345,8 @@
 			hw->phy_addr = PHY_ADDR_BCOM;
 			break;
 		default:
-			printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n",
-			       pci_name(hw->pdev), hw->phy_type);
+			dev_err(&hw->pdev->dev, "unsupported phy type 0x%x\n",
+			       hw->phy_type);
 			return -EOPNOTSUPP;
 		}
 		break;
@@ -3293,8 +3361,8 @@
 		break;
 
 	default:
-		printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n",
-		       pci_name(hw->pdev), hw->chip_id);
+		dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n",
+		       hw->chip_id);
 		return -EOPNOTSUPP;
 	}
 
@@ -3334,7 +3402,7 @@
 		/* avoid boards with stuck Hardware error bits */
 		if ((skge_read32(hw, B0_ISRC) & IS_HW_ERR) &&
 		    (skge_read32(hw, B0_HWE_ISRC) & IS_IRQ_SENSOR)) {
-			printk(KERN_WARNING PFX "stuck hardware sensor bit\n");
+			dev_warn(&hw->pdev->dev, "stuck hardware sensor bit\n");
 			hw->intr_mask &= ~IS_HW_ERR;
 		}
 
@@ -3408,7 +3476,7 @@
 	struct net_device *dev = alloc_etherdev(sizeof(*skge));
 
 	if (!dev) {
-		printk(KERN_ERR "skge etherdev alloc failed");
+		dev_err(&hw->pdev->dev, "etherdev alloc failed\n");
 		return NULL;
 	}
 
@@ -3452,6 +3520,7 @@
 	skge->duplex = -1;
 	skge->speed = -1;
 	skge->advertising = skge_supported_modes(hw);
+	skge->wol = pci_wake_enabled(hw->pdev) ? wol_supported(hw) : 0;
 
 	hw->dev[port] = dev;
 
@@ -3496,15 +3565,13 @@
 
 	err = pci_enable_device(pdev);
 	if (err) {
-		printk(KERN_ERR PFX "%s cannot enable PCI device\n",
-		       pci_name(pdev));
+		dev_err(&pdev->dev, "cannot enable PCI device\n");
 		goto err_out;
 	}
 
 	err = pci_request_regions(pdev, DRV_NAME);
 	if (err) {
-		printk(KERN_ERR PFX "%s cannot obtain PCI resources\n",
-		       pci_name(pdev));
+		dev_err(&pdev->dev, "cannot obtain PCI resources\n");
 		goto err_out_disable_pdev;
 	}
 
@@ -3519,8 +3586,7 @@
 	}
 
 	if (err) {
-		printk(KERN_ERR PFX "%s no usable DMA configuration\n",
-		       pci_name(pdev));
+		dev_err(&pdev->dev, "no usable DMA configuration\n");
 		goto err_out_free_regions;
 	}
 
@@ -3538,8 +3604,7 @@
 	err = -ENOMEM;
 	hw = kzalloc(sizeof(*hw), GFP_KERNEL);
 	if (!hw) {
-		printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n",
-		       pci_name(pdev));
+		dev_err(&pdev->dev, "cannot allocate hardware struct\n");
 		goto err_out_free_regions;
 	}
 
@@ -3550,8 +3615,7 @@
 
 	hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000);
 	if (!hw->regs) {
-		printk(KERN_ERR PFX "%s: cannot map device registers\n",
-		       pci_name(pdev));
+		dev_err(&pdev->dev, "cannot map device registers\n");
 		goto err_out_free_hw;
 	}
 
@@ -3567,23 +3631,19 @@
 	if (!dev)
 		goto err_out_led_off;
 
-	if (!is_valid_ether_addr(dev->dev_addr)) {
-		printk(KERN_ERR PFX "%s: bad (zero?) ethernet address in rom\n",
-		       pci_name(pdev));
-		err = -EIO;
-		goto err_out_free_netdev;
-	}
+	/* Some motherboards are broken and has zero in ROM. */
+	if (!is_valid_ether_addr(dev->dev_addr))
+		dev_warn(&pdev->dev, "bad (zero?) ethernet address in rom\n");
 
 	err = register_netdev(dev);
 	if (err) {
-		printk(KERN_ERR PFX "%s: cannot register net device\n",
-		       pci_name(pdev));
+		dev_err(&pdev->dev, "cannot register net device\n");
 		goto err_out_free_netdev;
 	}
 
 	err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, dev->name, hw);
 	if (err) {
-		printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
+		dev_err(&pdev->dev, "%s: cannot assign irq %d\n",
 		       dev->name, pdev->irq);
 		goto err_out_unregister;
 	}
@@ -3594,7 +3654,7 @@
 			skge_show_addr(dev1);
 		else {
 			/* Failure to register second port need not be fatal */
-			printk(KERN_WARNING PFX "register of second port failed\n");
+			dev_warn(&pdev->dev, "register of second port failed\n");
 			hw->dev[1] = NULL;
 			free_netdev(dev1);
 		}
@@ -3659,28 +3719,46 @@
 }
 
 #ifdef CONFIG_PM
+static int vaux_avail(struct pci_dev *pdev)
+{
+	int pm_cap;
+
+	pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+	if (pm_cap) {
+		u16 ctl;
+		pci_read_config_word(pdev, pm_cap + PCI_PM_PMC, &ctl);
+		if (ctl & PCI_PM_CAP_AUX_POWER)
+			return 1;
+	}
+	return 0;
+}
+
+
 static int skge_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct skge_hw *hw  = pci_get_drvdata(pdev);
-	int i, wol = 0;
+	int i, err, wol = 0;
 
-	pci_save_state(pdev);
+	err = pci_save_state(pdev);
+	if (err)
+		return err;
+
 	for (i = 0; i < hw->ports; i++) {
 		struct net_device *dev = hw->dev[i];
+		struct skge_port *skge = netdev_priv(dev);
 
-		if (netif_running(dev)) {
-			struct skge_port *skge = netdev_priv(dev);
+		if (netif_running(dev))
+			skge_down(dev);
+		if (skge->wol)
+			skge_wol_init(skge);
 
-			netif_carrier_off(dev);
-			if (skge->wol)
-				netif_stop_queue(dev);
-			else
-				skge_down(dev);
-			wol |= skge->wol;
-		}
-		netif_device_detach(dev);
+		wol |= skge->wol;
 	}
 
+	if (wol && vaux_avail(pdev))
+		skge_write8(hw, B0_POWER_CTRL,
+			    PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF);
+
 	skge_write32(hw, B0_IMSK, 0);
 	pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
 	pci_set_power_state(pdev, pci_choose_state(pdev, state));
@@ -3693,8 +3771,14 @@
 	struct skge_hw *hw  = pci_get_drvdata(pdev);
 	int i, err;
 
-	pci_set_power_state(pdev, PCI_D0);
-	pci_restore_state(pdev);
+	err = pci_set_power_state(pdev, PCI_D0);
+	if (err)
+		goto out;
+
+	err = pci_restore_state(pdev);
+	if (err)
+		goto out;
+
 	pci_enable_wake(pdev, PCI_D0, 0);
 
 	err = skge_reset(hw);
@@ -3704,7 +3788,6 @@
 	for (i = 0; i < hw->ports; i++) {
 		struct net_device *dev = hw->dev[i];
 
-		netif_device_attach(dev);
 		if (netif_running(dev)) {
 			err = skge_up(dev);
 
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index f6223c5..17b1b47 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -876,11 +876,13 @@
 	WOL_PATT_CNT_0	= 0x0f38,/* 32 bit	WOL Pattern Counter 3..0 */
 	WOL_PATT_CNT_4	= 0x0f3c,/* 24 bit	WOL Pattern Counter 6..4 */
 };
+#define WOL_REGS(port, x)	(x + (port)*0x80)
 
 enum {
 	WOL_PATT_RAM_1	= 0x1000,/*  WOL Pattern RAM Link 1 */
 	WOL_PATT_RAM_2	= 0x1400,/*  WOL Pattern RAM Link 2 */
 };
+#define WOL_PATT_RAM_BASE(port)	(WOL_PATT_RAM_1 + (port)*0x400)
 
 enum {
 	BASE_XMAC_1	= 0x2000,/* XMAC 1 registers */
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 822dd0b..f2ab3d5 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -49,7 +49,7 @@
 #include "sky2.h"
 
 #define DRV_NAME		"sky2"
-#define DRV_VERSION		"1.10"
+#define DRV_VERSION		"1.12"
 #define PFX			DRV_NAME " "
 
 /*
@@ -105,6 +105,7 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) },	/* DGE-560T */
 	{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4001) }, 	/* DGE-550SX */
 	{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4B02) },	/* DGE-560SX */
+	{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4B03) },	/* DGE-550T */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) }, /* 88E8021 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) }, /* 88E8022 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) }, /* 88E8061 */
@@ -126,6 +127,9 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, /* 88EC036 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, /* 88EC032 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */
+	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4369) }, /* 88EC042 */
+	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436A) }, /* 88E8058 */
+	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436B) }, /* 88E8071 */
 	{ 0 }
 };
 
@@ -140,7 +144,7 @@
 static const char *yukon2_name[] = {
 	"XL",		/* 0xb3 */
 	"EC Ultra", 	/* 0xb4 */
-	"UNKNOWN",	/* 0xb5 */
+	"Extreme",	/* 0xb5 */
 	"EC",		/* 0xb6 */
 	"FE",		/* 0xb7 */
 };
@@ -192,76 +196,52 @@
 	return v;
 }
 
-static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
+
+static void sky2_power_on(struct sky2_hw *hw)
 {
-	u16 power_control;
-	int vaux;
+	/* switch power to VCC (WA for VAUX problem) */
+	sky2_write8(hw, B0_POWER_CTRL,
+		    PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
 
-	pr_debug("sky2_set_power_state %d\n", state);
-	sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+	/* disable Core Clock Division, */
+	sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
 
-	power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_PMC);
-	vaux = (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL) &&
-		(power_control & PCI_PM_CAP_PME_D3cold);
+	if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+		/* enable bits are inverted */
+		sky2_write8(hw, B2_Y2_CLK_GATE,
+			    Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
+			    Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
+			    Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
+	else
+		sky2_write8(hw, B2_Y2_CLK_GATE, 0);
 
-	power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_CTRL);
+	if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
+		u32 reg1;
 
-	power_control |= PCI_PM_CTRL_PME_STATUS;
-	power_control &= ~(PCI_PM_CTRL_STATE_MASK);
-
-	switch (state) {
-	case PCI_D0:
-		/* switch power to VCC (WA for VAUX problem) */
-		sky2_write8(hw, B0_POWER_CTRL,
-			    PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
-
-		/* disable Core Clock Division, */
-		sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
-
-		if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
-			/* enable bits are inverted */
-			sky2_write8(hw, B2_Y2_CLK_GATE,
-				    Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
-				    Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
-				    Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
-		else
-			sky2_write8(hw, B2_Y2_CLK_GATE, 0);
-
-		if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
-			u32 reg1;
-
-			sky2_pci_write32(hw, PCI_DEV_REG3, 0);
-			reg1 = sky2_pci_read32(hw, PCI_DEV_REG4);
-			reg1 &= P_ASPM_CONTROL_MSK;
-			sky2_pci_write32(hw, PCI_DEV_REG4, reg1);
-			sky2_pci_write32(hw, PCI_DEV_REG5, 0);
-		}
-
-		break;
-
-	case PCI_D3hot:
-	case PCI_D3cold:
-		if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
-			sky2_write8(hw, B2_Y2_CLK_GATE, 0);
-		else
-			/* enable bits are inverted */
-			sky2_write8(hw, B2_Y2_CLK_GATE,
-				    Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
-				    Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
-				    Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
-
-		/* switch power to VAUX */
-		if (vaux && state != PCI_D3cold)
-			sky2_write8(hw, B0_POWER_CTRL,
-				    (PC_VAUX_ENA | PC_VCC_ENA |
-				     PC_VAUX_ON | PC_VCC_OFF));
-		break;
-	default:
-		printk(KERN_ERR PFX "Unknown power state %d\n", state);
+		sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+		reg1 = sky2_pci_read32(hw, PCI_DEV_REG4);
+		reg1 &= P_ASPM_CONTROL_MSK;
+		sky2_pci_write32(hw, PCI_DEV_REG4, reg1);
+		sky2_pci_write32(hw, PCI_DEV_REG5, 0);
 	}
+}
 
-	sky2_pci_write16(hw, hw->pm_cap + PCI_PM_CTRL, power_control);
-	sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+static void sky2_power_aux(struct sky2_hw *hw)
+{
+	if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+		sky2_write8(hw, B2_Y2_CLK_GATE, 0);
+	else
+		/* enable bits are inverted */
+		sky2_write8(hw, B2_Y2_CLK_GATE,
+			    Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
+			    Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
+			    Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
+
+	/* switch power to VAUX */
+	if (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL)
+		sky2_write8(hw, B0_POWER_CTRL,
+			    (PC_VAUX_ENA | PC_VCC_ENA |
+			     PC_VAUX_ON | PC_VCC_OFF));
 }
 
 static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port)
@@ -313,8 +293,10 @@
 	struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
 	u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg;
 
-	if (sky2->autoneg == AUTONEG_ENABLE &&
-	    !(hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
+	if (sky2->autoneg == AUTONEG_ENABLE
+	    && !(hw->chip_id == CHIP_ID_YUKON_XL
+		 || hw->chip_id == CHIP_ID_YUKON_EC_U
+		 || hw->chip_id == CHIP_ID_YUKON_EX)) {
 		u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
 
 		ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
@@ -341,8 +323,10 @@
 			/* enable automatic crossover */
 			ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO);
 
-			if (sky2->autoneg == AUTONEG_ENABLE &&
-			    (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
+			if (sky2->autoneg == AUTONEG_ENABLE
+			    && (hw->chip_id == CHIP_ID_YUKON_XL
+				|| hw->chip_id == CHIP_ID_YUKON_EC_U
+				|| hw->chip_id == CHIP_ID_YUKON_EX)) {
 				ctrl &= ~PHY_M_PC_DSC_MSK;
 				ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA;
 			}
@@ -497,7 +481,9 @@
 		/* restore page register */
 		gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
 		break;
+
 	case CHIP_ID_YUKON_EC_U:
+	case CHIP_ID_YUKON_EX:
 		pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
 
 		/* select page 3 to access LED control register */
@@ -539,7 +525,7 @@
 
 		/* set page register to 0 */
 		gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
-	} else {
+	} else if (hw->chip_id != CHIP_ID_YUKON_EX) {
 		gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
 
 		if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) {
@@ -591,6 +577,73 @@
 	spin_unlock_bh(&sky2->phy_lock);
 }
 
+/* Put device in state to listen for Wake On Lan */
+static void sky2_wol_init(struct sky2_port *sky2)
+{
+	struct sky2_hw *hw = sky2->hw;
+	unsigned port = sky2->port;
+	enum flow_control save_mode;
+	u16 ctrl;
+	u32 reg1;
+
+	/* Bring hardware out of reset */
+	sky2_write16(hw, B0_CTST, CS_RST_CLR);
+	sky2_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR);
+
+	sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
+	sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
+
+	/* Force to 10/100
+	 * sky2_reset will re-enable on resume
+	 */
+	save_mode = sky2->flow_mode;
+	ctrl = sky2->advertising;
+
+	sky2->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full);
+	sky2->flow_mode = FC_NONE;
+	sky2_phy_power(hw, port, 1);
+	sky2_phy_reinit(sky2);
+
+	sky2->flow_mode = save_mode;
+	sky2->advertising = ctrl;
+
+	/* Set GMAC to no flow control and auto update for speed/duplex */
+	gma_write16(hw, port, GM_GP_CTRL,
+		    GM_GPCR_FC_TX_DIS|GM_GPCR_TX_ENA|GM_GPCR_RX_ENA|
+		    GM_GPCR_DUP_FULL|GM_GPCR_FC_RX_DIS|GM_GPCR_AU_FCT_DIS);
+
+	/* Set WOL address */
+	memcpy_toio(hw->regs + WOL_REGS(port, WOL_MAC_ADDR),
+		    sky2->netdev->dev_addr, ETH_ALEN);
+
+	/* Turn on appropriate WOL control bits */
+	sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), WOL_CTL_CLEAR_RESULT);
+	ctrl = 0;
+	if (sky2->wol & WAKE_PHY)
+		ctrl |= WOL_CTL_ENA_PME_ON_LINK_CHG|WOL_CTL_ENA_LINK_CHG_UNIT;
+	else
+		ctrl |= WOL_CTL_DIS_PME_ON_LINK_CHG|WOL_CTL_DIS_LINK_CHG_UNIT;
+
+	if (sky2->wol & WAKE_MAGIC)
+		ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT;
+	else
+		ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;;
+
+	ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT;
+	sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl);
+
+	/* Turn on legacy PCI-Express PME mode */
+	sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+	reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+	reg1 |= PCI_Y2_PME_LEGACY;
+	sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+	sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+	/* block receiver */
+	sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
+
+}
+
 static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
 {
 	struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
@@ -684,7 +737,7 @@
 	sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
 	sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
 
-	if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
+	if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
 		sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8);
 		sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8);
 		if (hw->dev[port]->mtu > ETH_DATA_LEN) {
@@ -1467,6 +1520,9 @@
 			if (unlikely(netif_msg_tx_done(sky2)))
 				printk(KERN_DEBUG "%s: tx done %u\n",
 				       dev->name, idx);
+			sky2->net_stats.tx_packets++;
+			sky2->net_stats.tx_bytes += re->skb->len;
+
 			dev_kfree_skb_any(re->skb);
 		}
 
@@ -1641,7 +1697,9 @@
 	sky2_write8(hw, SK_REG(port, LNK_LED_REG),
 		    LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF);
 
-	if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) {
+	if (hw->chip_id == CHIP_ID_YUKON_XL
+	    || hw->chip_id == CHIP_ID_YUKON_EC_U
+	    || hw->chip_id == CHIP_ID_YUKON_EX) {
 		u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
 		u16 led = PHY_M_LEDC_LOS_CTRL(1);	/* link active */
 
@@ -1734,14 +1792,16 @@
 	sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF;
 
 	/* Pause bits are offset (9..8) */
-	if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)
+	if (hw->chip_id == CHIP_ID_YUKON_XL
+	    || hw->chip_id == CHIP_ID_YUKON_EC_U
+	    || hw->chip_id == CHIP_ID_YUKON_EX)
 		aux >>= 6;
 
 	sky2->flow_status = sky2_flow(aux & PHY_M_PS_RX_P_EN,
 				      aux & PHY_M_PS_TX_P_EN);
 
 	if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000
-	    && hw->chip_id != CHIP_ID_YUKON_EC_U)
+	    && !(hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX))
 		sky2->flow_status = FC_NONE;
 
 	if (aux & PHY_M_PS_RX_P_EN)
@@ -1794,48 +1854,37 @@
 }
 
 
-/* Transmit timeout is only called if we are running, carries is up
+/* Transmit timeout is only called if we are running, carrier is up
  * and tx queue is full (stopped).
+ * Called with netif_tx_lock held.
  */
 static void sky2_tx_timeout(struct net_device *dev)
 {
 	struct sky2_port *sky2 = netdev_priv(dev);
 	struct sky2_hw *hw = sky2->hw;
-	unsigned txq = txqaddr[sky2->port];
-	u16 report, done;
+	u32 imask;
 
 	if (netif_msg_timer(sky2))
 		printk(KERN_ERR PFX "%s: tx timeout\n", dev->name);
 
-	report = sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX);
-	done = sky2_read16(hw, Q_ADDR(txq, Q_DONE));
-
 	printk(KERN_DEBUG PFX "%s: transmit ring %u .. %u report=%u done=%u\n",
-	       dev->name,
-	       sky2->tx_cons, sky2->tx_prod, report, done);
+	       dev->name, sky2->tx_cons, sky2->tx_prod,
+	       sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX),
+	       sky2_read16(hw, Q_ADDR(txqaddr[sky2->port], Q_DONE)));
 
-	if (report != done) {
-		printk(KERN_INFO PFX "status burst pending (irq moderation?)\n");
+	imask = sky2_read32(hw, B0_IMSK);	/* block IRQ in hw */
+	sky2_write32(hw, B0_IMSK, 0);
+	sky2_read32(hw, B0_IMSK);
 
-		sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP);
-		sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
-	} else if (report != sky2->tx_cons) {
-		printk(KERN_INFO PFX "status report lost?\n");
+	netif_poll_disable(hw->dev[0]);		/* stop NAPI poll */
+	synchronize_irq(hw->pdev->irq);
 
-		netif_tx_lock_bh(dev);
-		sky2_tx_complete(sky2, report);
-		netif_tx_unlock_bh(dev);
-	} else {
-		printk(KERN_INFO PFX "hardware hung? flushing\n");
+	netif_start_queue(dev);			/* don't wakeup during flush */
+	sky2_tx_complete(sky2, sky2->tx_prod);	/* Flush transmit queue */
 
-		sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP);
-		sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET);
+	sky2_write32(hw, B0_IMSK, imask);
 
-		sky2_tx_clean(dev);
-
-		sky2_qset(hw, txq);
-		sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1);
-	}
+	sky2_phy_reinit(sky2);			/* this clears flow control etc */
 }
 
 static int sky2_change_mtu(struct net_device *dev, int new_mtu)
@@ -1849,8 +1898,9 @@
 	if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
 		return -EINVAL;
 
+	/* TSO on Yukon Ultra and MTU > 1500 not supported */
 	if (hw->chip_id == CHIP_ID_YUKON_EC_U && new_mtu > ETH_DATA_LEN)
-		return -EINVAL;
+		dev->features &= ~NETIF_F_TSO;
 
 	if (!netif_running(dev)) {
 		dev->mtu = new_mtu;
@@ -2089,6 +2139,8 @@
 				goto force_update;
 
 			skb->protocol = eth_type_trans(skb, dev);
+			sky2->net_stats.rx_packets++;
+			sky2->net_stats.rx_bytes += skb->len;
 			dev->last_rx = jiffies;
 
 #ifdef SKY2_VLAN_TAG_USED
@@ -2218,8 +2270,8 @@
 
 		pci_err = sky2_pci_read16(hw, PCI_STATUS);
 		if (net_ratelimit())
-			printk(KERN_ERR PFX "%s: pci hw error (0x%x)\n",
-			       pci_name(hw->pdev), pci_err);
+			dev_err(&hw->pdev->dev, "PCI hardware error (0x%x)\n",
+			        pci_err);
 
 		sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
 		sky2_pci_write16(hw, PCI_STATUS,
@@ -2234,8 +2286,8 @@
 		pex_err = sky2_pci_read32(hw, PEX_UNC_ERR_STAT);
 
 		if (net_ratelimit())
-			printk(KERN_ERR PFX "%s: pci express error (0x%x)\n",
-			       pci_name(hw->pdev), pex_err);
+			dev_err(&hw->pdev->dev, "PCI Express error (0x%x)\n",
+				pex_err);
 
 		/* clear the interrupt */
 		sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
@@ -2404,6 +2456,7 @@
 	switch (hw->chip_id) {
 	case CHIP_ID_YUKON_EC:
 	case CHIP_ID_YUKON_EC_U:
+	case CHIP_ID_YUKON_EX:
 		return 125;	/* 125 Mhz */
 	case CHIP_ID_YUKON_FE:
 		return 100;	/* 100 Mhz */
@@ -2423,34 +2476,62 @@
 }
 
 
-static int sky2_reset(struct sky2_hw *hw)
+static int __devinit sky2_init(struct sky2_hw *hw)
 {
-	u16 status;
 	u8 t8;
-	int i;
 
 	sky2_write8(hw, B0_CTST, CS_RST_CLR);
 
 	hw->chip_id = sky2_read8(hw, B2_CHIP_ID);
 	if (hw->chip_id < CHIP_ID_YUKON_XL || hw->chip_id > CHIP_ID_YUKON_FE) {
-		printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n",
-		       pci_name(hw->pdev), hw->chip_id);
+		dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n",
+			hw->chip_id);
 		return -EOPNOTSUPP;
 	}
 
+	if (hw->chip_id == CHIP_ID_YUKON_EX)
+		dev_warn(&hw->pdev->dev, "this driver not yet tested on this chip type\n"
+			 "Please report success or failure to <netdev@vger.kernel.org>\n");
+
+	/* Make sure and enable all clocks */
+	if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U)
+		sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+
 	hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
 
 	/* This rev is really old, and requires untested workarounds */
 	if (hw->chip_id == CHIP_ID_YUKON_EC && hw->chip_rev == CHIP_REV_YU_EC_A1) {
-		printk(KERN_ERR PFX "%s: unsupported revision Yukon-%s (0x%x) rev %d\n",
-		       pci_name(hw->pdev), yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
-		       hw->chip_id, hw->chip_rev);
+		dev_err(&hw->pdev->dev, "unsupported revision Yukon-%s (0x%x) rev %d\n",
+			yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
+			hw->chip_id, hw->chip_rev);
 		return -EOPNOTSUPP;
 	}
 
+	hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
+	hw->ports = 1;
+	t8 = sky2_read8(hw, B2_Y2_HW_RES);
+	if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) {
+		if (!(sky2_read8(hw, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC))
+			++hw->ports;
+	}
+
+	return 0;
+}
+
+static void sky2_reset(struct sky2_hw *hw)
+{
+	u16 status;
+	int i;
+
 	/* disable ASF */
 	if (hw->chip_id <= CHIP_ID_YUKON_EC) {
-		sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
+		if (hw->chip_id == CHIP_ID_YUKON_EX) {
+			status = sky2_read16(hw, HCU_CCSR);
+			status &= ~(HCU_CCSR_AHB_RST | HCU_CCSR_CPU_RST_MODE |
+				    HCU_CCSR_UC_STATE_MSK);
+			sky2_write16(hw, HCU_CCSR, status);
+		} else
+			sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
 		sky2_write16(hw, B0_CTST, Y2_ASF_DISABLE);
 	}
 
@@ -2472,15 +2553,7 @@
 		sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL);
 
 
-	hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
-	hw->ports = 1;
-	t8 = sky2_read8(hw, B2_Y2_HW_RES);
-	if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) {
-		if (!(sky2_read8(hw, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC))
-			++hw->ports;
-	}
-
-	sky2_set_power_state(hw, PCI_D0);
+	sky2_power_on(hw);
 
 	for (i = 0; i < hw->ports; i++) {
 		sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
@@ -2563,7 +2636,37 @@
 	sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
 	sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_START);
 	sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START);
+}
 
+static inline u8 sky2_wol_supported(const struct sky2_hw *hw)
+{
+	return sky2_is_copper(hw) ? (WAKE_PHY | WAKE_MAGIC) : 0;
+}
+
+static void sky2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	const struct sky2_port *sky2 = netdev_priv(dev);
+
+	wol->supported = sky2_wol_supported(sky2->hw);
+	wol->wolopts = sky2->wol;
+}
+
+static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct sky2_port *sky2 = netdev_priv(dev);
+	struct sky2_hw *hw = sky2->hw;
+
+	if (wol->wolopts & ~sky2_wol_supported(sky2->hw))
+		return -EOPNOTSUPP;
+
+	sky2->wol = wol->wolopts;
+
+	if (hw->chip_id == CHIP_ID_YUKON_EC_U)
+		sky2_write32(hw, B0_CTST, sky2->wol
+			     ? Y2_HW_WOL_ON : Y2_HW_WOL_OFF);
+
+	if (!netif_running(dev))
+		sky2_wol_init(sky2);
 	return 0;
 }
 
@@ -2814,25 +2917,9 @@
 	}
 }
 
-/* Use hardware MIB variables for critical path statistics and
- * transmit feedback not reported at interrupt.
- * Other errors are accounted for in interrupt handler.
- */
 static struct net_device_stats *sky2_get_stats(struct net_device *dev)
 {
 	struct sky2_port *sky2 = netdev_priv(dev);
-	u64 data[13];
-
-	sky2_phy_stats(sky2, data, ARRAY_SIZE(data));
-
-	sky2->net_stats.tx_bytes = data[0];
-	sky2->net_stats.rx_bytes = data[1];
-	sky2->net_stats.tx_packets = data[2] + data[4] + data[6];
-	sky2->net_stats.rx_packets = data[3] + data[5] + data[7];
-	sky2->net_stats.multicast = data[3] + data[5];
-	sky2->net_stats.collisions = data[10];
-	sky2->net_stats.tx_aborted_errors = data[12];
-
 	return &sky2->net_stats;
 }
 
@@ -3191,7 +3278,9 @@
 static const struct ethtool_ops sky2_ethtool_ops = {
 	.get_settings = sky2_get_settings,
 	.set_settings = sky2_set_settings,
-	.get_drvinfo = sky2_get_drvinfo,
+	.get_drvinfo  = sky2_get_drvinfo,
+	.get_wol      = sky2_get_wol,
+	.set_wol      = sky2_set_wol,
 	.get_msglevel = sky2_get_msglevel,
 	.set_msglevel = sky2_set_msglevel,
 	.nway_reset   = sky2_nway_reset,
@@ -3221,13 +3310,14 @@
 
 /* Initialize network device */
 static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
-						     unsigned port, int highmem)
+						     unsigned port,
+						     int highmem, int wol)
 {
 	struct sky2_port *sky2;
 	struct net_device *dev = alloc_etherdev(sizeof(*sky2));
 
 	if (!dev) {
-		printk(KERN_ERR "sky2 etherdev alloc failed");
+		dev_err(&hw->pdev->dev, "etherdev alloc failed");
 		return NULL;
 	}
 
@@ -3269,6 +3359,7 @@
 	sky2->speed = -1;
 	sky2->advertising = sky2_supported_modes(hw);
 	sky2->rx_csum = 1;
+	sky2->wol = wol;
 
 	spin_lock_init(&sky2->phy_lock);
 	sky2->tx_pending = TX_DEF_PENDING;
@@ -3278,11 +3369,9 @@
 
 	sky2->port = port;
 
-	if (hw->chip_id != CHIP_ID_YUKON_EC_U)
-		dev->features |= NETIF_F_TSO;
+	dev->features |= NETIF_F_TSO | NETIF_F_IP_CSUM | NETIF_F_SG;
 	if (highmem)
 		dev->features |= NETIF_F_HIGHDMA;
-	dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
 
 #ifdef SKY2_VLAN_TAG_USED
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
@@ -3343,8 +3432,7 @@
 
 	err = request_irq(pdev->irq, sky2_test_intr, 0, DRV_NAME, hw);
 	if (err) {
-		printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
-		       pci_name(pdev), pdev->irq);
+		dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq);
 		return err;
 	}
 
@@ -3355,9 +3443,8 @@
 
 	if (!hw->msi) {
 		/* MSI test failed, go back to INTx mode */
-		printk(KERN_INFO PFX "%s: No interrupt generated using MSI, "
-		       "switching to INTx mode.\n",
-		       pci_name(pdev));
+		dev_info(&pdev->dev, "No interrupt generated using MSI, "
+			 "switching to INTx mode.\n");
 
 		err = -EOPNOTSUPP;
 		sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ);
@@ -3371,62 +3458,62 @@
 	return err;
 }
 
+static int __devinit pci_wake_enabled(struct pci_dev *dev)
+{
+	int pm  = pci_find_capability(dev, PCI_CAP_ID_PM);
+	u16 value;
+
+	if (!pm)
+		return 0;
+	if (pci_read_config_word(dev, pm + PCI_PM_CTRL, &value))
+		return 0;
+	return value & PCI_PM_CTRL_PME_ENABLE;
+}
+
 static int __devinit sky2_probe(struct pci_dev *pdev,
 				const struct pci_device_id *ent)
 {
-	struct net_device *dev, *dev1 = NULL;
+	struct net_device *dev;
 	struct sky2_hw *hw;
-	int err, pm_cap, using_dac = 0;
+	int err, using_dac = 0, wol_default;
 
 	err = pci_enable_device(pdev);
 	if (err) {
-		printk(KERN_ERR PFX "%s cannot enable PCI device\n",
-		       pci_name(pdev));
+		dev_err(&pdev->dev, "cannot enable PCI device\n");
 		goto err_out;
 	}
 
 	err = pci_request_regions(pdev, DRV_NAME);
 	if (err) {
-		printk(KERN_ERR PFX "%s cannot obtain PCI resources\n",
-		       pci_name(pdev));
+		dev_err(&pdev->dev, "cannot obtain PCI resources\n");
 		goto err_out;
 	}
 
 	pci_set_master(pdev);
 
-	/* Find power-management capability. */
-	pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
-	if (pm_cap == 0) {
-		printk(KERN_ERR PFX "Cannot find PowerManagement capability, "
-		       "aborting.\n");
-		err = -EIO;
-		goto err_out_free_regions;
-	}
-
 	if (sizeof(dma_addr_t) > sizeof(u32) &&
 	    !(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) {
 		using_dac = 1;
 		err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
 		if (err < 0) {
-			printk(KERN_ERR PFX "%s unable to obtain 64 bit DMA "
-			       "for consistent allocations\n", pci_name(pdev));
+			dev_err(&pdev->dev, "unable to obtain 64 bit DMA "
+				"for consistent allocations\n");
 			goto err_out_free_regions;
 		}
-
 	} else {
 		err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 		if (err) {
-			printk(KERN_ERR PFX "%s no usable DMA configuration\n",
-			       pci_name(pdev));
+			dev_err(&pdev->dev, "no usable DMA configuration\n");
 			goto err_out_free_regions;
 		}
 	}
 
+	wol_default = pci_wake_enabled(pdev) ? WAKE_MAGIC : 0;
+
 	err = -ENOMEM;
 	hw = kzalloc(sizeof(*hw), GFP_KERNEL);
 	if (!hw) {
-		printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n",
-		       pci_name(pdev));
+		dev_err(&pdev->dev, "cannot allocate hardware struct\n");
 		goto err_out_free_regions;
 	}
 
@@ -3434,11 +3521,9 @@
 
 	hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000);
 	if (!hw->regs) {
-		printk(KERN_ERR PFX "%s: cannot map device registers\n",
-		       pci_name(pdev));
+		dev_err(&pdev->dev, "cannot map device registers\n");
 		goto err_out_free_hw;
 	}
-	hw->pm_cap = pm_cap;
 
 #ifdef __BIG_ENDIAN
 	/* The sk98lin vendor driver uses hardware byte swapping but
@@ -3458,18 +3543,22 @@
 	if (!hw->st_le)
 		goto err_out_iounmap;
 
-	err = sky2_reset(hw);
+	err = sky2_init(hw);
 	if (err)
 		goto err_out_iounmap;
 
-	printk(KERN_INFO PFX "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n",
+	dev_info(&pdev->dev, "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n",
 	       DRV_VERSION, (unsigned long long)pci_resource_start(pdev, 0),
 	       pdev->irq, yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
 	       hw->chip_id, hw->chip_rev);
 
-	dev = sky2_init_netdev(hw, 0, using_dac);
-	if (!dev)
+	sky2_reset(hw);
+
+	dev = sky2_init_netdev(hw, 0, using_dac, wol_default);
+	if (!dev) {
+		err = -ENOMEM;
 		goto err_out_free_pci;
+	}
 
 	if (!disable_msi && pci_enable_msi(pdev) == 0) {
 		err = sky2_test_msi(hw);
@@ -3481,32 +3570,33 @@
 
 	err = register_netdev(dev);
 	if (err) {
-		printk(KERN_ERR PFX "%s: cannot register net device\n",
-		       pci_name(pdev));
+		dev_err(&pdev->dev, "cannot register net device\n");
 		goto err_out_free_netdev;
 	}
 
 	err = request_irq(pdev->irq,  sky2_intr, hw->msi ? 0 : IRQF_SHARED,
 			  dev->name, hw);
 	if (err) {
-		printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
-		       pci_name(pdev), pdev->irq);
+		dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq);
 		goto err_out_unregister;
 	}
 	sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
 
 	sky2_show_addr(dev);
 
-	if (hw->ports > 1 && (dev1 = sky2_init_netdev(hw, 1, using_dac))) {
-		if (register_netdev(dev1) == 0)
-			sky2_show_addr(dev1);
-		else {
-			/* Failure to register second port need not be fatal */
-			printk(KERN_WARNING PFX
-			       "register of second port failed\n");
+	if (hw->ports > 1) {
+		struct net_device *dev1;
+
+		dev1 = sky2_init_netdev(hw, 1, using_dac, wol_default);
+		if (!dev1)
+			dev_warn(&pdev->dev, "allocation for second device failed\n");
+		else if ((err = register_netdev(dev1))) {
+			dev_warn(&pdev->dev,
+				 "register of second port failed (%d)\n", err);
 			hw->dev[1] = NULL;
 			free_netdev(dev1);
-		}
+		} else
+			sky2_show_addr(dev1);
 	}
 
 	setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw);
@@ -3555,7 +3645,8 @@
 		unregister_netdev(dev1);
 	unregister_netdev(dev0);
 
-	sky2_set_power_state(hw, PCI_D3hot);
+	sky2_power_aux(hw);
+
 	sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
 	sky2_write8(hw, B0_CTST, CS_RST_SET);
 	sky2_read8(hw, B0_CTST);
@@ -3580,27 +3671,31 @@
 static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct sky2_hw *hw = pci_get_drvdata(pdev);
-	int i;
-	pci_power_t pstate = pci_choose_state(pdev, state);
-
-	if (!(pstate == PCI_D3hot || pstate == PCI_D3cold))
-		return -EINVAL;
+	int i, wol = 0;
 
 	del_timer_sync(&hw->idle_timer);
 	netif_poll_disable(hw->dev[0]);
 
 	for (i = 0; i < hw->ports; i++) {
 		struct net_device *dev = hw->dev[i];
+		struct sky2_port *sky2 = netdev_priv(dev);
 
-		if (netif_running(dev)) {
+		if (netif_running(dev))
 			sky2_down(dev);
-			netif_device_detach(dev);
-		}
+
+		if (sky2->wol)
+			sky2_wol_init(sky2);
+
+		wol |= sky2->wol;
 	}
 
 	sky2_write32(hw, B0_IMSK, 0);
+	sky2_power_aux(hw);
+
 	pci_save_state(pdev);
-	sky2_set_power_state(hw, pstate);
+	pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
 	return 0;
 }
 
@@ -3609,21 +3704,22 @@
 	struct sky2_hw *hw = pci_get_drvdata(pdev);
 	int i, err;
 
-	pci_restore_state(pdev);
-	pci_enable_wake(pdev, PCI_D0, 0);
-	sky2_set_power_state(hw, PCI_D0);
-
-	err = sky2_reset(hw);
+	err = pci_set_power_state(pdev, PCI_D0);
 	if (err)
 		goto out;
 
+	err = pci_restore_state(pdev);
+	if (err)
+		goto out;
+
+	pci_enable_wake(pdev, PCI_D0, 0);
+	sky2_reset(hw);
+
 	sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
 
 	for (i = 0; i < hw->ports; i++) {
 		struct net_device *dev = hw->dev[i];
 		if (netif_running(dev)) {
-			netif_device_attach(dev);
-
 			err = sky2_up(dev);
 			if (err) {
 				printk(KERN_ERR PFX "%s: could not up: %d\n",
@@ -3636,11 +3732,43 @@
 
 	netif_poll_enable(hw->dev[0]);
 	sky2_idle_start(hw);
+	return 0;
 out:
+	dev_err(&pdev->dev, "resume failed (%d)\n", err);
+	pci_disable_device(pdev);
 	return err;
 }
 #endif
 
+static void sky2_shutdown(struct pci_dev *pdev)
+{
+	struct sky2_hw *hw = pci_get_drvdata(pdev);
+	int i, wol = 0;
+
+	del_timer_sync(&hw->idle_timer);
+	netif_poll_disable(hw->dev[0]);
+
+	for (i = 0; i < hw->ports; i++) {
+		struct net_device *dev = hw->dev[i];
+		struct sky2_port *sky2 = netdev_priv(dev);
+
+		if (sky2->wol) {
+			wol = 1;
+			sky2_wol_init(sky2);
+		}
+	}
+
+	if (wol)
+		sky2_power_aux(hw);
+
+	pci_enable_wake(pdev, PCI_D3hot, wol);
+	pci_enable_wake(pdev, PCI_D3cold, wol);
+
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, PCI_D3hot);
+
+}
+
 static struct pci_driver sky2_driver = {
 	.name = DRV_NAME,
 	.id_table = sky2_id_table,
@@ -3650,6 +3778,7 @@
 	.suspend = sky2_suspend,
 	.resume = sky2_resume,
 #endif
+	.shutdown = sky2_shutdown,
 };
 
 static int __init sky2_init_module(void)
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 6ed1d47..3b01895 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -32,6 +32,7 @@
 	PCI_Y2_PHY1_COMA = 1<<28, /* Set PHY 1 to Coma Mode (YUKON-2) */
 	PCI_Y2_PHY2_POWD = 1<<27, /* Set PHY 2 to Power Down (YUKON-2) */
 	PCI_Y2_PHY1_POWD = 1<<26, /* Set PHY 1 to Power Down (YUKON-2) */
+	PCI_Y2_PME_LEGACY= 1<<15, /* PCI Express legacy power management mode */
 };
 
 enum pci_dev_reg_2 {
@@ -370,12 +371,9 @@
 
 /*	B2_CHIP_ID		 8 bit 	Chip Identification Number */
 enum {
-	CHIP_ID_GENESIS	   = 0x0a, /* Chip ID for GENESIS */
-	CHIP_ID_YUKON	   = 0xb0, /* Chip ID for YUKON */
-	CHIP_ID_YUKON_LITE = 0xb1, /* Chip ID for YUKON-Lite (Rev. A1-A3) */
-	CHIP_ID_YUKON_LP   = 0xb2, /* Chip ID for YUKON-LP */
 	CHIP_ID_YUKON_XL   = 0xb3, /* Chip ID for YUKON-2 XL */
 	CHIP_ID_YUKON_EC_U = 0xb4, /* Chip ID for YUKON-2 EC Ultra */
+	CHIP_ID_YUKON_EX   = 0xb5, /* Chip ID for YUKON-2 Extreme */
 	CHIP_ID_YUKON_EC   = 0xb6, /* Chip ID for YUKON-2 EC */
  	CHIP_ID_YUKON_FE   = 0xb7, /* Chip ID for YUKON-2 FE */
 
@@ -767,6 +765,24 @@
 	POLL_LIST_ADDR_HI= 0x0e2c,/* 32 bit	Poll. List Start Addr (high) */
 };
 
+enum {
+	SMB_CFG		 = 0x0e40, /* 32 bit	SMBus Config Register */
+	SMB_CSR		 = 0x0e44, /* 32 bit	SMBus Control/Status Register */
+};
+
+enum {
+	CPU_WDOG	 = 0x0e48, /* 32 bit	Watchdog Register  */
+	CPU_CNTR	 = 0x0e4C, /* 32 bit	Counter Register  */
+	CPU_TIM		 = 0x0e50,/* 32 bit	Timer Compare Register  */
+	CPU_AHB_ADDR	 = 0x0e54, /* 32 bit	CPU AHB Debug  Register  */
+	CPU_AHB_WDATA	 = 0x0e58, /* 32 bit	CPU AHB Debug  Register  */
+	CPU_AHB_RDATA	 = 0x0e5C, /* 32 bit	CPU AHB Debug  Register  */
+	HCU_MAP_BASE	 = 0x0e60, /* 32 bit	Reset Mapping Base */
+	CPU_AHB_CTRL	 = 0x0e64, /* 32 bit	CPU AHB Debug  Register  */
+	HCU_CCSR	 = 0x0e68, /* 32 bit	CPU Control and Status Register */
+	HCU_HCSR	 = 0x0e6C, /* 32 bit	Host Control and Status Register */
+};
+
 /* ASF Subsystem Registers (Yukon-2 only) */
 enum {
 	B28_Y2_SMB_CONFIG  = 0x0e40,/* 32 bit	ASF SMBus Config Register */
@@ -837,33 +853,27 @@
 	GMAC_LINK_CTRL	= 0x0f10,/* 16 bit	Link Control Reg */
 
 /* Wake-up Frame Pattern Match Control Registers (YUKON only) */
-
-	WOL_REG_OFFS	= 0x20,/* HW-Bug: Address is + 0x20 against spec. */
-
 	WOL_CTRL_STAT	= 0x0f20,/* 16 bit	WOL Control/Status Reg */
 	WOL_MATCH_CTL	= 0x0f22,/*  8 bit	WOL Match Control Reg */
 	WOL_MATCH_RES	= 0x0f23,/*  8 bit	WOL Match Result Reg */
 	WOL_MAC_ADDR	= 0x0f24,/* 32 bit	WOL MAC Address */
-	WOL_PATT_PME	= 0x0f2a,/*  8 bit	WOL PME Match Enable (Yukon-2) */
-	WOL_PATT_ASFM	= 0x0f2b,/*  8 bit	WOL ASF Match Enable (Yukon-2) */
 	WOL_PATT_RPTR	= 0x0f2c,/*  8 bit	WOL Pattern Read Pointer */
 
 /* WOL Pattern Length Registers (YUKON only) */
-
 	WOL_PATT_LEN_LO	= 0x0f30,/* 32 bit	WOL Pattern Length 3..0 */
 	WOL_PATT_LEN_HI	= 0x0f34,/* 24 bit	WOL Pattern Length 6..4 */
 
 /* WOL Pattern Counter Registers (YUKON only) */
-
-
 	WOL_PATT_CNT_0	= 0x0f38,/* 32 bit	WOL Pattern Counter 3..0 */
 	WOL_PATT_CNT_4	= 0x0f3c,/* 24 bit	WOL Pattern Counter 6..4 */
 };
+#define WOL_REGS(port, x)	(x + (port)*0x80)
 
 enum {
 	WOL_PATT_RAM_1	= 0x1000,/*  WOL Pattern RAM Link 1 */
 	WOL_PATT_RAM_2	= 0x1400,/*  WOL Pattern RAM Link 2 */
 };
+#define WOL_PATT_RAM_BASE(port)	(WOL_PATT_RAM_1 + (port)*0x400)
 
 enum {
 	BASE_GMAC_1	= 0x2800,/* GMAC 1 registers */
@@ -1654,6 +1664,39 @@
 	Y2_ASF_CLR_ASFI = 1<<1,	/* Clear host IRQ */
 	Y2_ASF_HOST_IRQ = 1<<0,	/* Issue an IRQ to HOST system */
 };
+/*	HCU_CCSR	CPU Control and Status Register */
+enum {
+	HCU_CCSR_SMBALERT_MONITOR= 1<<27, /* SMBALERT pin monitor */
+	HCU_CCSR_CPU_SLEEP	= 1<<26, /* CPU sleep status */
+	/* Clock Stretching Timeout */
+	HCU_CCSR_CS_TO		= 1<<25,
+	HCU_CCSR_WDOG		= 1<<24, /* Watchdog Reset */
+
+	HCU_CCSR_CLR_IRQ_HOST	= 1<<17, /* Clear IRQ_HOST */
+	HCU_CCSR_SET_IRQ_HCU	= 1<<16, /* Set IRQ_HCU */
+
+	HCU_CCSR_AHB_RST	= 1<<9, /* Reset AHB bridge */
+	HCU_CCSR_CPU_RST_MODE	= 1<<8, /* CPU Reset Mode */
+
+	HCU_CCSR_SET_SYNC_CPU	= 1<<5,
+	HCU_CCSR_CPU_CLK_DIVIDE_MSK = 3<<3,/* CPU Clock Divide */
+	HCU_CCSR_CPU_CLK_DIVIDE_BASE= 1<<3,
+	HCU_CCSR_OS_PRSNT	= 1<<2, /* ASF OS Present */
+/* Microcontroller State */
+	HCU_CCSR_UC_STATE_MSK	= 3,
+	HCU_CCSR_UC_STATE_BASE	= 1<<0,
+	HCU_CCSR_ASF_RESET	= 0,
+	HCU_CCSR_ASF_HALTED	= 1<<1,
+	HCU_CCSR_ASF_RUNNING	= 1<<0,
+};
+
+/*	HCU_HCSR	Host Control and Status Register */
+enum {
+	HCU_HCSR_SET_IRQ_CPU	= 1<<16, /* Set IRQ_CPU */
+
+	HCU_HCSR_CLR_IRQ_HCU	= 1<<1, /* Clear IRQ_HCU */
+	HCU_HCSR_SET_IRQ_HOST	= 1<<0,	/* Set IRQ_HOST */
+};
 
 /*	STAT_CTRL		32 bit	Status BMU control register (Yukon-2 only) */
 enum {
@@ -1715,14 +1758,17 @@
 	GM_IS_RX_COMPL	= 1<<0,	/* Frame Reception Complete */
 
 #define GMAC_DEF_MSK     GM_IS_TX_FF_UR
+};
 
 /*	GMAC_LINK_CTRL	16 bit	GMAC Link Control Reg (YUKON only) */
-						/* Bits 15.. 2:	reserved */
+enum {						/* Bits 15.. 2:	reserved */
 	GMLC_RST_CLR	= 1<<1,	/* Clear GMAC Link Reset */
 	GMLC_RST_SET	= 1<<0,	/* Set   GMAC Link Reset */
+};
 
 
 /*	WOL_CTRL_STAT	16 bit	WOL Control/Status Reg */
+enum {
 	WOL_CTL_LINK_CHG_OCC		= 1<<15,
 	WOL_CTL_MAGIC_PKT_OCC		= 1<<14,
 	WOL_CTL_PATTERN_OCC		= 1<<13,
@@ -1741,17 +1787,6 @@
 	WOL_CTL_DIS_PATTERN_UNIT	= 1<<0,
 };
 
-#define WOL_CTL_DEFAULT				\
-	(WOL_CTL_DIS_PME_ON_LINK_CHG |	\
-	WOL_CTL_DIS_PME_ON_PATTERN |	\
-	WOL_CTL_DIS_PME_ON_MAGIC_PKT |	\
-	WOL_CTL_DIS_LINK_CHG_UNIT |		\
-	WOL_CTL_DIS_PATTERN_UNIT |		\
-	WOL_CTL_DIS_MAGIC_PKT_UNIT)
-
-/*	WOL_MATCH_CTL	 8 bit	WOL Match Control Reg */
-#define WOL_CTL_PATT_ENA(x)	(1 << (x))
-
 
 /* Control flags */
 enum {
@@ -1875,6 +1910,7 @@
 	u8		     autoneg;	/* AUTONEG_ENABLE, AUTONEG_DISABLE */
 	u8		     duplex;	/* DUPLEX_HALF, DUPLEX_FULL */
 	u8		     rx_csum;
+	u8		     wol;
  	enum flow_control    flow_mode;
  	enum flow_control    flow_status;
 
@@ -1887,7 +1923,6 @@
 	struct pci_dev	     *pdev;
 	struct net_device    *dev[2];
 
-	int		     pm_cap;
 	u8	     	     chip_id;
 	u8		     chip_rev;
 	u8		     pmd_type;
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index a0806d2..2f4b1de 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -1343,15 +1343,12 @@
 	printk(KERN_INFO "SLIP linefill/keepalive option.\n");
 #endif
 
-	slip_devs = kmalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL);
+	slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL);
 	if (!slip_devs) {
 		printk(KERN_ERR "SLIP: Can't allocate slip devices array!  Uaargh! (-> No SLIP available)\n");
 		return -ENOMEM;
 	}
 
-	/* Clear the pointer array, we allocate devices when we need them */
-	memset(slip_devs, 0, sizeof(struct net_device *)*slip_maxdev);
-
 	/* Fill in our line protocol discipline, and register it */
 	if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0)  {
 		printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status);
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
index 7122932..ae1ae34 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -482,8 +482,7 @@
 		count -= semi_count;
 		memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
 	} else {
-		/* Packet is in one chunk -- we can copy + cksum. */
-		eth_io_copy_and_sum(skb, xfer_start, count, 0);
+		memcpy_fromio(skb->data, xfer_start, count);
 	}
 
 }
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index d70bc97..a52b22d 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -454,8 +454,7 @@
 		count -= semi_count;
 		memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
 	} else {
-		/* Packet is in one chunk -- we can copy + cksum. */
-		eth_io_copy_and_sum(skb, xfer_start, count, 0);
+		memcpy_fromio(skb->data, xfer_start, count);
 	}
 
 	outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET);	/* Disable memory. */
diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
index 2c5319c..88a30e5 100644
--- a/drivers/net/smc-ultra32.c
+++ b/drivers/net/smc-ultra32.c
@@ -395,8 +395,7 @@
 			memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
 		}
 	} else {
-		/* Packet is in one chunk -- we can copy + cksum. */
-		eth_io_copy_and_sum(skb, xfer_start, count, 0);
+		memcpy_fromio(skb->data, xfer_start, count);
 	}
 }
 
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 43af614..c956141 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -1659,7 +1659,7 @@
 {
 	strncpy(info->driver, CARDNAME, sizeof(info->driver));
 	strncpy(info->version, version, sizeof(info->version));
-	strncpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+	strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info));
 }
 
 static int smc911x_ethtool_nwayreset(struct net_device *dev)
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index e62a958..49f4b77 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -1712,7 +1712,7 @@
 {
 	strncpy(info->driver, CARDNAME, sizeof(info->driver));
 	strncpy(info->version, version, sizeof(info->version));
-	strncpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+	strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info));
 }
 
 static int smc_ethtool_nwayreset(struct net_device *dev)
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 8ea2fc1..64ed8ff 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -280,72 +280,67 @@
 {
 	struct spider_net_descr *descr;
 
-	for (descr = chain->tail; !descr->bus_addr; descr = descr->next) {
-		pci_unmap_single(card->pdev, descr->bus_addr,
-				 SPIDER_NET_DESCR_SIZE, PCI_DMA_BIDIRECTIONAL);
+	descr = chain->ring;
+	do {
 		descr->bus_addr = 0;
-	}
+		descr->next_descr_addr = 0;
+		descr = descr->next;
+	} while (descr != chain->ring);
+
+	dma_free_coherent(&card->pdev->dev, chain->num_desc,
+	    chain->ring, chain->dma_addr);
 }
 
 /**
- * spider_net_init_chain - links descriptor chain
+ * spider_net_init_chain - alloc and link descriptor chain
  * @card: card structure
  * @chain: address of chain
- * @start_descr: address of descriptor array
- * @no: number of descriptors
  *
- * we manage a circular list that mirrors the hardware structure,
+ * We manage a circular list that mirrors the hardware structure,
  * except that the hardware uses bus addresses.
  *
- * returns 0 on success, <0 on failure
+ * Returns 0 on success, <0 on failure
  */
 static int
 spider_net_init_chain(struct spider_net_card *card,
-		       struct spider_net_descr_chain *chain,
-		       struct spider_net_descr *start_descr,
-		       int no)
+		       struct spider_net_descr_chain *chain)
 {
 	int i;
 	struct spider_net_descr *descr;
 	dma_addr_t buf;
+	size_t alloc_size;
 
-	descr = start_descr;
-	memset(descr, 0, sizeof(*descr) * no);
+	alloc_size = chain->num_desc * sizeof (struct spider_net_descr);
 
-	/* set up the hardware pointers in each descriptor */
-	for (i=0; i<no; i++, descr++) {
+	chain->ring = dma_alloc_coherent(&card->pdev->dev, alloc_size,
+		&chain->dma_addr, GFP_KERNEL);
+
+	if (!chain->ring)
+		return -ENOMEM;
+
+	descr = chain->ring;
+	memset(descr, 0, alloc_size);
+
+	/* Set up the hardware pointers in each descriptor */
+	buf = chain->dma_addr;
+	for (i=0; i < chain->num_desc; i++, descr++) {
 		descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
 
-		buf = pci_map_single(card->pdev, descr,
-				     SPIDER_NET_DESCR_SIZE,
-				     PCI_DMA_BIDIRECTIONAL);
-
-		if (pci_dma_mapping_error(buf))
-			goto iommu_error;
-
 		descr->bus_addr = buf;
+		descr->next_descr_addr = 0;
 		descr->next = descr + 1;
 		descr->prev = descr - 1;
 
+		buf += sizeof(struct spider_net_descr);
 	}
 	/* do actual circular list */
-	(descr-1)->next = start_descr;
-	start_descr->prev = descr-1;
+	(descr-1)->next = chain->ring;
+	chain->ring->prev = descr-1;
 
 	spin_lock_init(&chain->lock);
-	chain->head = start_descr;
-	chain->tail = start_descr;
-
+	chain->head = chain->ring;
+	chain->tail = chain->ring;
 	return 0;
-
-iommu_error:
-	descr = start_descr;
-	for (i=0; i < no; i++, descr++)
-		if (descr->bus_addr)
-			pci_unmap_single(card->pdev, descr->bus_addr,
-					 SPIDER_NET_DESCR_SIZE,
-					 PCI_DMA_BIDIRECTIONAL);
-	return -ENOMEM;
 }
 
 /**
@@ -372,21 +367,20 @@
 }
 
 /**
- * spider_net_prepare_rx_descr - reinitializes a rx descriptor
+ * spider_net_prepare_rx_descr - Reinitialize RX descriptor
  * @card: card structure
  * @descr: descriptor to re-init
  *
- * return 0 on succes, <0 on failure
+ * Return 0 on succes, <0 on failure.
  *
- * allocates a new rx skb, iommu-maps it and attaches it to the descriptor.
- * Activate the descriptor state-wise
+ * Allocates a new rx skb, iommu-maps it and attaches it to the
+ * descriptor. Mark the descriptor as activated, ready-to-use.
  */
 static int
 spider_net_prepare_rx_descr(struct spider_net_card *card,
 			    struct spider_net_descr *descr)
 {
 	dma_addr_t buf;
-	int error = 0;
 	int offset;
 	int bufsize;
 
@@ -414,7 +408,7 @@
 		(SPIDER_NET_RXBUF_ALIGN - 1);
 	if (offset)
 		skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset);
-	/* io-mmu-map the skb */
+	/* iommu-map the skb */
 	buf = pci_map_single(card->pdev, descr->skb->data,
 			SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
 	descr->buf_addr = buf;
@@ -425,11 +419,16 @@
 		card->spider_stats.rx_iommu_map_error++;
 		descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
 	} else {
+		descr->next_descr_addr = 0;
+		wmb();
 		descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED |
 					 SPIDER_NET_DMAC_NOINTR_COMPLETE;
+
+		wmb();
+		descr->prev->next_descr_addr = descr->bus_addr;
 	}
 
-	return error;
+	return 0;
 }
 
 /**
@@ -493,10 +492,10 @@
 }
 
 /**
- * spider_net_alloc_rx_skbs - allocates rx skbs in rx descriptor chains
+ * spider_net_alloc_rx_skbs - Allocates rx skbs in rx descriptor chains
  * @card: card structure
  *
- * returns 0 on success, <0 on failure
+ * Returns 0 on success, <0 on failure.
  */
 static int
 spider_net_alloc_rx_skbs(struct spider_net_card *card)
@@ -507,16 +506,16 @@
 	result = -ENOMEM;
 
 	chain = &card->rx_chain;
-	/* put at least one buffer into the chain. if this fails,
-	 * we've got a problem. if not, spider_net_refill_rx_chain
-	 * will do the rest at the end of this function */
+	/* Put at least one buffer into the chain. if this fails,
+	 * we've got a problem. If not, spider_net_refill_rx_chain
+	 * will do the rest at the end of this function. */
 	if (spider_net_prepare_rx_descr(card, chain->head))
 		goto error;
 	else
 		chain->head = chain->head->next;
 
-	/* this will allocate the rest of the rx buffers; if not, it's
-	 * business as usual later on */
+	/* This will allocate the rest of the rx buffers;
+	 * if not, it's business as usual later on. */
 	spider_net_refill_rx_chain(card);
 	spider_net_enable_rxdmac(card);
 	return 0;
@@ -707,7 +706,7 @@
 	}
 
 	/* If TX queue is short, don't even bother with interrupts */
-	if (cnt < card->num_tx_desc/4)
+	if (cnt < card->tx_chain.num_desc/4)
 		return cnt;
 
 	/* Set low-watermark 3/4th's of the way into the queue. */
@@ -915,16 +914,13 @@
  * spider_net_pass_skb_up - takes an skb from a descriptor and passes it on
  * @descr: descriptor to process
  * @card: card structure
- * @napi: whether caller is in NAPI context
  *
- * returns 1 on success, 0 if no packet was passed to the stack
- *
- * iommu-unmaps the skb, fills out skb structure and passes the data to the
- * stack. The descriptor state is not changed.
+ * Fills out skb structure and passes the data to the stack.
+ * The descriptor state is not changed.
  */
-static int
+static void
 spider_net_pass_skb_up(struct spider_net_descr *descr,
-		       struct spider_net_card *card, int napi)
+		       struct spider_net_card *card)
 {
 	struct sk_buff *skb;
 	struct net_device *netdev;
@@ -932,23 +928,8 @@
 
 	data_status = descr->data_status;
 	data_error = descr->data_error;
-
 	netdev = card->netdev;
 
-	/* unmap descriptor */
-	pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_FRAME,
-			PCI_DMA_FROMDEVICE);
-
-	/* the cases we'll throw away the packet immediately */
-	if (data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
-		if (netif_msg_rx_err(card))
-			pr_err("error in received descriptor found, "
-			       "data_status=x%08x, data_error=x%08x\n",
-			       data_status, data_error);
-		card->spider_stats.rx_desc_error++;
-		return 0;
-	}
-
 	skb = descr->skb;
 	skb->dev = netdev;
 	skb_put(skb, descr->valid_size);
@@ -977,57 +958,72 @@
 	}
 
 	/* pass skb up to stack */
-	if (napi)
-		netif_receive_skb(skb);
-	else
-		netif_rx_ni(skb);
+	netif_receive_skb(skb);
 
 	/* update netdevice statistics */
 	card->netdev_stats.rx_packets++;
 	card->netdev_stats.rx_bytes += skb->len;
-
-	return 1;
 }
 
+#ifdef DEBUG
+static void show_rx_chain(struct spider_net_card *card)
+{
+	struct spider_net_descr_chain *chain = &card->rx_chain;
+	struct spider_net_descr *start= chain->tail;
+	struct spider_net_descr *descr= start;
+	int status;
+
+	int cnt = 0;
+	int cstat = spider_net_get_descr_status(descr);
+	printk(KERN_INFO "RX chain tail at descr=%ld\n",
+	     (start - card->descr) - card->tx_chain.num_desc);
+	status = cstat;
+	do
+	{
+		status = spider_net_get_descr_status(descr);
+		if (cstat != status) {
+			printk(KERN_INFO "Have %d descrs with stat=x%08x\n", cnt, cstat);
+			cstat = status;
+			cnt = 0;
+		}
+		cnt ++;
+		descr = descr->next;
+	} while (descr != start);
+	printk(KERN_INFO "Last %d descrs with stat=x%08x\n", cnt, cstat);
+}
+#endif
+
 /**
  * spider_net_decode_one_descr - processes an rx descriptor
  * @card: card structure
- * @napi: whether caller is in NAPI context
  *
- * returns 1 if a packet has been sent to the stack, otherwise 0
+ * Returns 1 if a packet has been sent to the stack, otherwise 0
  *
- * processes an rx descriptor by iommu-unmapping the data buffer and passing
+ * Processes an rx descriptor by iommu-unmapping the data buffer and passing
  * the packet up to the stack. This function is called in softirq
  * context, e.g. either bottom half from interrupt or NAPI polling context
  */
 static int
-spider_net_decode_one_descr(struct spider_net_card *card, int napi)
+spider_net_decode_one_descr(struct spider_net_card *card)
 {
 	struct spider_net_descr_chain *chain = &card->rx_chain;
 	struct spider_net_descr *descr = chain->tail;
 	int status;
-	int result;
 
 	status = spider_net_get_descr_status(descr);
 
-	if (status == SPIDER_NET_DESCR_CARDOWNED) {
-		/* nothing in the descriptor yet */
-		result=0;
-		goto out;
-	}
-
-	if (status == SPIDER_NET_DESCR_NOT_IN_USE) {
-		/* not initialized yet, the ring must be empty */
-		spider_net_refill_rx_chain(card);
-		spider_net_enable_rxdmac(card);
-		result=0;
-		goto out;
-	}
+	/* Nothing in the descriptor, or ring must be empty */
+	if ((status == SPIDER_NET_DESCR_CARDOWNED) ||
+	    (status == SPIDER_NET_DESCR_NOT_IN_USE))
+		return 0;
 
 	/* descriptor definitively used -- move on tail */
 	chain->tail = descr->next;
 
-	result = 0;
+	/* unmap descriptor */
+	pci_unmap_single(card->pdev, descr->buf_addr,
+			SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
+
 	if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) ||
 	     (status == SPIDER_NET_DESCR_PROTECTION_ERROR) ||
 	     (status == SPIDER_NET_DESCR_FORCE_END) ) {
@@ -1035,31 +1031,55 @@
 			pr_err("%s: dropping RX descriptor with state %d\n",
 			       card->netdev->name, status);
 		card->netdev_stats.rx_dropped++;
-		pci_unmap_single(card->pdev, descr->buf_addr,
-				SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
-		dev_kfree_skb_irq(descr->skb);
-		goto refill;
+		goto bad_desc;
 	}
 
 	if ( (status != SPIDER_NET_DESCR_COMPLETE) &&
 	     (status != SPIDER_NET_DESCR_FRAME_END) ) {
-		if (netif_msg_rx_err(card)) {
-			pr_err("%s: RX descriptor with state %d\n",
+		if (netif_msg_rx_err(card))
+			pr_err("%s: RX descriptor with unkown state %d\n",
 			       card->netdev->name, status);
-			card->spider_stats.rx_desc_unk_state++;
-		}
-		goto refill;
+		card->spider_stats.rx_desc_unk_state++;
+		goto bad_desc;
 	}
 
-	/* ok, we've got a packet in descr */
-	result = spider_net_pass_skb_up(descr, card, napi);
-refill:
+	/* The cases we'll throw away the packet immediately */
+	if (descr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
+		if (netif_msg_rx_err(card))
+			pr_err("%s: error in received descriptor found, "
+			       "data_status=x%08x, data_error=x%08x\n",
+			       card->netdev->name,
+			       descr->data_status, descr->data_error);
+		goto bad_desc;
+	}
+
+	if (descr->dmac_cmd_status & 0xfefe) {
+		pr_err("%s: bad status, cmd_status=x%08x\n",
+			       card->netdev->name,
+			       descr->dmac_cmd_status);
+		pr_err("buf_addr=x%08x\n", descr->buf_addr);
+		pr_err("buf_size=x%08x\n", descr->buf_size);
+		pr_err("next_descr_addr=x%08x\n", descr->next_descr_addr);
+		pr_err("result_size=x%08x\n", descr->result_size);
+		pr_err("valid_size=x%08x\n", descr->valid_size);
+		pr_err("data_status=x%08x\n", descr->data_status);
+		pr_err("data_error=x%08x\n", descr->data_error);
+		pr_err("bus_addr=x%08x\n", descr->bus_addr);
+		pr_err("which=%ld\n", descr - card->rx_chain.ring);
+
+		card->spider_stats.rx_desc_error++;
+		goto bad_desc;
+	}
+
+	/* Ok, we've got a packet in descr */
+	spider_net_pass_skb_up(descr, card);
 	descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
-	/* change the descriptor state: */
-	if (!napi)
-		spider_net_refill_rx_chain(card);
-out:
-	return result;
+	return 1;
+
+bad_desc:
+	dev_kfree_skb_irq(descr->skb);
+	descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+	return 0;
 }
 
 /**
@@ -1085,7 +1105,7 @@
 	packets_to_do = min(*budget, netdev->quota);
 
 	while (packets_to_do) {
-		if (spider_net_decode_one_descr(card, 1)) {
+		if (spider_net_decode_one_descr(card)) {
 			packets_done++;
 			packets_to_do--;
 		} else {
@@ -1098,6 +1118,7 @@
 	netdev->quota -= packets_done;
 	*budget -= packets_done;
 	spider_net_refill_rx_chain(card);
+	spider_net_enable_rxdmac(card);
 
 	/* if all packets are in the stack, enable interrupts and return 0 */
 	/* if not, return 1 */
@@ -1227,24 +1248,6 @@
 }
 
 /**
- * spider_net_handle_rxram_full - cleans up RX ring upon RX RAM full interrupt
- * @card: card structure
- *
- * spider_net_handle_rxram_full empties the RX ring so that spider can put
- * more packets in it and empty its RX RAM. This is called in bottom half
- * context
- */
-static void
-spider_net_handle_rxram_full(struct spider_net_card *card)
-{
-	while (spider_net_decode_one_descr(card, 0))
-		;
-	spider_net_enable_rxchtails(card);
-	spider_net_enable_rxdmac(card);
-	netif_rx_schedule(card->netdev);
-}
-
-/**
  * spider_net_handle_error_irq - handles errors raised by an interrupt
  * @card: card structure
  * @status_reg: interrupt status register 0 (GHIINT0STS)
@@ -1366,10 +1369,10 @@
 	case SPIDER_NET_GRFAFLLINT: /* fallthrough */
 	case SPIDER_NET_GRMFLLINT:
 		if (netif_msg_intr(card) && net_ratelimit())
-			pr_debug("Spider RX RAM full, incoming packets "
+			pr_err("Spider RX RAM full, incoming packets "
 			       "might be discarded!\n");
 		spider_net_rx_irq_off(card);
-		tasklet_schedule(&card->rxram_full_tl);
+		netif_rx_schedule(card->netdev);
 		show_error = 0;
 		break;
 
@@ -1384,7 +1387,7 @@
 	case SPIDER_NET_GDCDCEINT: /* fallthrough */
 	case SPIDER_NET_GDBDCEINT: /* fallthrough */
 	case SPIDER_NET_GDADCEINT:
-		if (netif_msg_intr(card))
+		if (netif_msg_intr(card) && net_ratelimit())
 			pr_err("got descriptor chain end interrupt, "
 			       "restarting DMAC %c.\n",
 			       'D'-(i-SPIDER_NET_GDDDCEINT)/3);
@@ -1455,7 +1458,7 @@
 			break;
 	}
 
-	if ((show_error) && (netif_msg_intr(card)))
+	if ((show_error) && (netif_msg_intr(card)) && net_ratelimit())
 		pr_err("Got error interrupt on %s, GHIINT0STS = 0x%08x, "
 		       "GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n",
 		       card->netdev->name,
@@ -1651,27 +1654,18 @@
 spider_net_open(struct net_device *netdev)
 {
 	struct spider_net_card *card = netdev_priv(netdev);
-	struct spider_net_descr *descr;
-	int i, result;
+	int result;
 
-	result = -ENOMEM;
-	if (spider_net_init_chain(card, &card->tx_chain, card->descr,
-	                          card->num_tx_desc))
+	result = spider_net_init_chain(card, &card->tx_chain);
+	if (result)
 		goto alloc_tx_failed;
-
 	card->low_watermark = NULL;
 
-	/* rx_chain is after tx_chain, so offset is descr + tx_count */
-	if (spider_net_init_chain(card, &card->rx_chain,
-	                          card->descr + card->num_tx_desc,
-	                          card->num_rx_desc))
+	result = spider_net_init_chain(card, &card->rx_chain);
+	if (result)
 		goto alloc_rx_failed;
 
-	descr = card->rx_chain.head;
-	for (i=0; i < card->num_rx_desc; i++, descr++)
-		descr->next_descr_addr = descr->next->bus_addr;
-
-	/* allocate rx skbs */
+	/* Allocate rx skbs */
 	if (spider_net_alloc_rx_skbs(card))
 		goto alloc_skbs_failed;
 
@@ -1902,7 +1896,6 @@
 {
 	struct spider_net_card *card = netdev_priv(netdev);
 
-	tasklet_kill(&card->rxram_full_tl);
 	netif_poll_disable(netdev);
 	netif_carrier_off(netdev);
 	netif_stop_queue(netdev);
@@ -1914,7 +1907,7 @@
 	spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0);
 
 	/* free_irq(netdev->irq, netdev);*/
-	free_irq(to_pci_dev(netdev->class_dev.dev)->irq, netdev);
+	free_irq(to_pci_dev(netdev->dev.parent)->irq, netdev);
 
 	spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
 			     SPIDER_NET_DMA_TX_FEND_VALUE);
@@ -1924,6 +1917,7 @@
 
 	/* release chains */
 	spider_net_release_tx_chain(card, 1);
+	spider_net_free_rx_chain_contents(card);
 
 	spider_net_free_rx_chain_contents(card);
 
@@ -2046,9 +2040,6 @@
 
 	pci_set_drvdata(card->pdev, netdev);
 
-	card->rxram_full_tl.data = (unsigned long) card;
-	card->rxram_full_tl.func =
-		(void (*)(unsigned long)) spider_net_handle_rxram_full;
 	init_timer(&card->tx_timer);
 	card->tx_timer.function =
 		(void (*)(unsigned long)) spider_net_cleanup_tx_ring;
@@ -2057,8 +2048,8 @@
 
 	card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;
 
-	card->num_tx_desc = tx_descriptors;
-	card->num_rx_desc = rx_descriptors;
+	card->tx_chain.num_desc = tx_descriptors;
+	card->rx_chain.num_desc = rx_descriptors;
 
 	spider_net_setup_netdev_ops(netdev);
 
@@ -2107,12 +2098,8 @@
 {
 	struct net_device *netdev;
 	struct spider_net_card *card;
-	size_t alloc_size;
 
-	alloc_size = sizeof (*card) +
-		sizeof (struct spider_net_descr) * rx_descriptors +
-		sizeof (struct spider_net_descr) * tx_descriptors;
-	netdev = alloc_etherdev(alloc_size);
+	netdev = alloc_etherdev(sizeof(struct spider_net_card));
 	if (!netdev)
 		return NULL;
 
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h
index 3e196df..2fec5cf 100644
--- a/drivers/net/spider_net.h
+++ b/drivers/net/spider_net.h
@@ -24,7 +24,7 @@
 #ifndef _SPIDER_NET_H
 #define _SPIDER_NET_H
 
-#define VERSION "1.6 A"
+#define VERSION "1.6 B"
 
 #include "sungem_phy.h"
 
@@ -378,6 +378,9 @@
 	spinlock_t lock;
 	struct spider_net_descr *head;
 	struct spider_net_descr *tail;
+	struct spider_net_descr *ring;
+	int num_desc;
+	dma_addr_t dma_addr;
 };
 
 /* descriptor data_status bits */
@@ -397,8 +400,6 @@
  * 701b8000 would be correct, but every packets gets that flag */
 #define SPIDER_NET_DESTROY_RX_FLAGS	0x700b8000
 
-#define SPIDER_NET_DESCR_SIZE		32
-
 /* this will be bigger some time */
 struct spider_net_options {
 	int rx_csum; /* for rx: if 0 ip_summed=NONE,
@@ -441,25 +442,16 @@
 	struct spider_net_descr_chain rx_chain;
 	struct spider_net_descr *low_watermark;
 
-	struct net_device_stats netdev_stats;
-
-	struct spider_net_options options;
-
-	spinlock_t intmask_lock;
-	struct tasklet_struct rxram_full_tl;
 	struct timer_list tx_timer;
-
 	struct work_struct tx_timeout_task;
 	atomic_t tx_timeout_task_counter;
 	wait_queue_head_t waitq;
 
 	/* for ethtool */
 	int msg_enable;
-	int num_rx_desc;
-	int num_tx_desc;
+	struct net_device_stats netdev_stats;
 	struct spider_net_extra_stats spider_stats;
-
-	struct spider_net_descr descr[0];
+	struct spider_net_options options;
 };
 
 #define pr_err(fmt,arg...) \
diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c
index 91b9951..6bcf03f 100644
--- a/drivers/net/spider_net_ethtool.c
+++ b/drivers/net/spider_net_ethtool.c
@@ -158,9 +158,9 @@
 	struct spider_net_card *card = netdev->priv;
 
 	ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX;
-	ering->tx_pending = card->num_tx_desc;
+	ering->tx_pending = card->tx_chain.num_desc;
 	ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX;
-	ering->rx_pending = card->num_rx_desc;
+	ering->rx_pending = card->rx_chain.num_desc;
 }
 
 static int spider_net_get_stats_count(struct net_device *netdev)
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index f4bf62c..e136bae 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -58,11 +58,7 @@
 #define TG3_VLAN_TAG_USED 0
 #endif
 
-#ifdef NETIF_F_TSO
 #define TG3_TSO_SUPPORT	1
-#else
-#define TG3_TSO_SUPPORT	0
-#endif
 
 #include "tg3.h"
 
@@ -3384,7 +3380,7 @@
 		}
 next_pkt_nopost:
 		sw_idx++;
-		sw_idx %= TG3_RX_RCB_RING_SIZE(tp);
+		sw_idx &= (TG3_RX_RCB_RING_SIZE(tp) - 1);
 
 		/* Refresh hw_idx to see if there is new work */
 		if (sw_idx == hw_idx) {
@@ -3873,7 +3869,6 @@
 
 	entry = tp->tx_prod;
 	base_flags = 0;
-#if TG3_TSO_SUPPORT != 0
 	mss = 0;
 	if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
 	    (mss = skb_shinfo(skb)->gso_size) != 0) {
@@ -3906,11 +3901,6 @@
 	}
 	else if (skb->ip_summed == CHECKSUM_PARTIAL)
 		base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#else
-	mss = 0;
-	if (skb->ip_summed == CHECKSUM_PARTIAL)
-		base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#endif
 #if TG3_VLAN_TAG_USED
 	if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
 		base_flags |= (TXD_FLAG_VLAN |
@@ -3970,7 +3960,6 @@
 	return NETDEV_TX_OK;
 }
 
-#if TG3_TSO_SUPPORT != 0
 static int tg3_start_xmit_dma_bug(struct sk_buff *, struct net_device *);
 
 /* Use GSO to workaround a rare TSO bug that may be triggered when the
@@ -4002,7 +3991,6 @@
 
 	return NETDEV_TX_OK;
 }
-#endif
 
 /* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and
  * support TG3_FLG2_HW_TSO_1 or firmware TSO only.
@@ -4036,7 +4024,6 @@
 	base_flags = 0;
 	if (skb->ip_summed == CHECKSUM_PARTIAL)
 		base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#if TG3_TSO_SUPPORT != 0
 	mss = 0;
 	if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
 	    (mss = skb_shinfo(skb)->gso_size) != 0) {
@@ -4091,9 +4078,6 @@
 			}
 		}
 	}
-#else
-	mss = 0;
-#endif
 #if TG3_VLAN_TAG_USED
 	if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
 		base_flags |= (TXD_FLAG_VLAN |
@@ -5329,7 +5313,6 @@
 	return 0;
 }
 
-#if TG3_TSO_SUPPORT != 0
 
 #define TG3_TSO_FW_RELEASE_MAJOR	0x1
 #define TG3_TSO_FW_RELASE_MINOR		0x6
@@ -5906,7 +5889,6 @@
 	return 0;
 }
 
-#endif /* TG3_TSO_SUPPORT != 0 */
 
 /* tp->lock is held. */
 static void __tg3_set_mac_addr(struct tg3 *tp)
@@ -6120,7 +6102,6 @@
 		tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE);
 		tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE);
 	}
-#if TG3_TSO_SUPPORT != 0
 	else if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
 		int fw_len;
 
@@ -6135,7 +6116,6 @@
 		tw32(BUFMGR_MB_POOL_SIZE,
 		     NIC_SRAM_MBUF_POOL_SIZE5705 - fw_len - 0xa00);
 	}
-#endif
 
 	if (tp->dev->mtu <= ETH_DATA_LEN) {
 		tw32(BUFMGR_MB_RDMA_LOW_WATER,
@@ -6337,10 +6317,8 @@
 	if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)
 		rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
 
-#if TG3_TSO_SUPPORT != 0
 	if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
 		rdmac_mode |= (1 << 27);
-#endif
 
 	/* Receive/send statistics. */
 	if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
@@ -6511,10 +6489,8 @@
 	tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB);
 	tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ);
 	tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
-#if TG3_TSO_SUPPORT != 0
 	if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
 		tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE | 0x8);
-#endif
 	tw32(SNDBDI_MODE, SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE);
 	tw32(SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE);
 
@@ -6524,13 +6500,11 @@
 			return err;
 	}
 
-#if TG3_TSO_SUPPORT != 0
 	if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
 		err = tg3_load_tso_firmware(tp);
 		if (err)
 			return err;
 	}
-#endif
 
 	tp->tx_mode = TX_MODE_ENABLE;
 	tw32_f(MAC_TX_MODE, tp->tx_mode);
@@ -8062,7 +8036,6 @@
 	tp->msg_enable = value;
 }
 
-#if TG3_TSO_SUPPORT != 0
 static int tg3_set_tso(struct net_device *dev, u32 value)
 {
 	struct tg3 *tp = netdev_priv(dev);
@@ -8081,7 +8054,6 @@
 	}
 	return ethtool_op_set_tso(dev, value);
 }
-#endif
 
 static int tg3_nway_reset(struct net_device *dev)
 {
@@ -9212,10 +9184,8 @@
 	.set_tx_csum		= tg3_set_tx_csum,
 	.get_sg			= ethtool_op_get_sg,
 	.set_sg			= ethtool_op_set_sg,
-#if TG3_TSO_SUPPORT != 0
 	.get_tso		= ethtool_op_get_tso,
 	.set_tso		= tg3_set_tso,
-#endif
 	.self_test_count	= tg3_get_test_count,
 	.self_test		= tg3_self_test,
 	.get_strings		= tg3_get_strings,
@@ -11856,7 +11826,6 @@
 
 	tg3_init_bufmgr_config(tp);
 
-#if TG3_TSO_SUPPORT != 0
 	if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
 		tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
 	}
@@ -11881,7 +11850,6 @@
 			dev->features |= NETIF_F_TSO6;
 	}
 
-#endif
 
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 &&
 	    !(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) &&
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 7e4b23c..31c97a6 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -1709,75 +1709,13 @@
 		if (mii_info->speed != ugeth->oldspeed) {
 			switch (mii_info->speed) {
 			case 1000:
-#ifdef CONFIG_PPC_MPC836x
-/* FIXME: This code is for 100Mbs BUG fixing,
-remove this when it is fixed!!! */
-				if (ugeth->ug_info->enet_interface ==
-				    ENET_1000_GMII)
-				/* Run the commands which initialize the PHY */
-				{
-					tempval =
-					    (u32) mii_info->mdio_read(ugeth->
-						dev, mii_info->mii_id, 0x1b);
-					tempval |= 0x000f;
-					mii_info->mdio_write(ugeth->dev,
-						mii_info->mii_id, 0x1b,
-						(u16) tempval);
-					tempval =
-					    (u32) mii_info->mdio_read(ugeth->
-						dev, mii_info->mii_id,
-						MII_BMCR);
-					mii_info->mdio_write(ugeth->dev,
-						mii_info->mii_id, MII_BMCR,
-						(u16) (tempval | BMCR_RESET));
-				} else if (ugeth->ug_info->enet_interface ==
-					   ENET_1000_RGMII)
-				/* Run the commands which initialize the PHY */
-				{
-					tempval =
-					    (u32) mii_info->mdio_read(ugeth->
-						dev, mii_info->mii_id, 0x1b);
-					tempval = (tempval & ~0x000f) | 0x000b;
-					mii_info->mdio_write(ugeth->dev,
-						mii_info->mii_id, 0x1b,
-						(u16) tempval);
-					tempval =
-					    (u32) mii_info->mdio_read(ugeth->
-						dev, mii_info->mii_id,
-						MII_BMCR);
-					mii_info->mdio_write(ugeth->dev,
-						mii_info->mii_id, MII_BMCR,
-						(u16) (tempval | BMCR_RESET));
-				}
-				msleep(4000);
-#endif				/* CONFIG_MPC8360 */
-				adjust_enet_interface(ugeth);
+				ugeth->ug_info->enet_interface = ENET_1000_RGMII;
 				break;
 			case 100:
-			case 10:
-#ifdef CONFIG_PPC_MPC836x
-/* FIXME: This code is for 100Mbs BUG fixing,
-remove this lines when it will be fixed!!! */
 				ugeth->ug_info->enet_interface = ENET_100_RGMII;
-				tempval =
-				    (u32) mii_info->mdio_read(ugeth->dev,
-							      mii_info->mii_id,
-							      0x1b);
-				tempval = (tempval & ~0x000f) | 0x000b;
-				mii_info->mdio_write(ugeth->dev,
-						     mii_info->mii_id, 0x1b,
-						     (u16) tempval);
-				tempval =
-				    (u32) mii_info->mdio_read(ugeth->dev,
-							      mii_info->mii_id,
-							      MII_BMCR);
-				mii_info->mdio_write(ugeth->dev,
-						     mii_info->mii_id, MII_BMCR,
-						     (u16) (tempval |
-							    BMCR_RESET));
-				msleep(4000);
-#endif				/* CONFIG_MPC8360 */
-				adjust_enet_interface(ugeth);
+				break;
+			case 10:
+				ugeth->ug_info->enet_interface = ENET_10_RGMII;
 				break;
 			default:
 				ugeth_warn
@@ -1785,6 +1723,7 @@
 				     dev->name, mii_info->speed);
 				break;
 			}
+			adjust_enet_interface(ugeth);
 
 			ugeth_info("%s: Speed %dBT", dev->name,
 				   mii_info->speed);
@@ -2865,8 +2804,8 @@
 			if (UCC_GETH_TX_BD_RING_ALIGNMENT > 4)
 				align = UCC_GETH_TX_BD_RING_ALIGNMENT;
 			ugeth->tx_bd_ring_offset[j] =
-				(u32) (kmalloc((u32) (length + align),
-				GFP_KERNEL));
+				kmalloc((u32) (length + align), GFP_KERNEL);
+
 			if (ugeth->tx_bd_ring_offset[j] != 0)
 				ugeth->p_tx_bd_ring[j] =
 					(void*)((ugeth->tx_bd_ring_offset[j] +
@@ -2901,7 +2840,7 @@
 			if (UCC_GETH_RX_BD_RING_ALIGNMENT > 4)
 				align = UCC_GETH_RX_BD_RING_ALIGNMENT;
 			ugeth->rx_bd_ring_offset[j] =
-			    (u32) (kmalloc((u32) (length + align), GFP_KERNEL));
+				kmalloc((u32) (length + align), GFP_KERNEL);
 			if (ugeth->rx_bd_ring_offset[j] != 0)
 				ugeth->p_rx_bd_ring[j] =
 					(void*)((ugeth->rx_bd_ring_offset[j] +
@@ -2927,10 +2866,9 @@
 	/* Init Tx bds */
 	for (j = 0; j < ug_info->numQueuesTx; j++) {
 		/* Setup the skbuff rings */
-		ugeth->tx_skbuff[j] =
-		    (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) *
-					       ugeth->ug_info->bdRingLenTx[j],
-					       GFP_KERNEL);
+		ugeth->tx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) *
+					      ugeth->ug_info->bdRingLenTx[j],
+					      GFP_KERNEL);
 
 		if (ugeth->tx_skbuff[j] == NULL) {
 			ugeth_err("%s: Could not allocate tx_skbuff",
@@ -2959,10 +2897,9 @@
 	/* Init Rx bds */
 	for (j = 0; j < ug_info->numQueuesRx; j++) {
 		/* Setup the skbuff rings */
-		ugeth->rx_skbuff[j] =
-		    (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) *
-					       ugeth->ug_info->bdRingLenRx[j],
-					       GFP_KERNEL);
+		ugeth->rx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) *
+					      ugeth->ug_info->bdRingLenRx[j],
+					      GFP_KERNEL);
 
 		if (ugeth->rx_skbuff[j] == NULL) {
 			ugeth_err("%s: Could not allocate rx_skbuff",
@@ -3453,8 +3390,7 @@
 	 * allocated resources can be released when the channel is freed.
 	 */
 	if (!(ugeth->p_init_enet_param_shadow =
-	     (struct ucc_geth_init_pram *) kmalloc(sizeof(struct ucc_geth_init_pram),
-					      GFP_KERNEL))) {
+	      kmalloc(sizeof(struct ucc_geth_init_pram), GFP_KERNEL))) {
 		ugeth_err
 		    ("%s: Can not allocate memory for"
 			" p_UccInitEnetParamShadows.", __FUNCTION__);
@@ -4136,6 +4072,7 @@
 	static int mii_mng_configured = 0;
 	const phandle *ph;
 	const unsigned int *prop;
+	const void *mac_addr;
 
 	ugeth_vdbg("%s: IN", __FUNCTION__);
 
@@ -4261,7 +4198,12 @@
 
 	ugeth->ug_info = ug_info;
 	ugeth->dev = dev;
-	memcpy(dev->dev_addr, get_property(np, "mac-address", NULL), 6);
+
+	mac_addr = get_property(np, "mac-address", NULL);
+	if (mac_addr == NULL)
+		mac_addr = get_property(np, "local-mac-address", NULL);
+	if (mac_addr)
+		memcpy(dev->dev_addr, mac_addr, 6);
 
 	return 0;
 }
diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c
index 3c86592..6fda6d8 100644
--- a/drivers/net/ucc_geth_phy.c
+++ b/drivers/net/ucc_geth_phy.c
@@ -376,6 +376,8 @@
 	ugphy_vdbg("%s: IN", __FUNCTION__);
 
 	ucc_geth_phy_write(mii_info, 0x14, 0x0cd2);
+	ucc_geth_phy_write(mii_info, 0x1b,
+		(ucc_geth_phy_read(mii_info, 0x1b) & ~0x000f) | 0x000b);
 	ucc_geth_phy_write(mii_info, MII_BMCR,
 		  ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET);
 	msleep(4000);
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index 21f76f5..61708cf 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -235,6 +235,19 @@
 comment "Refer to the file README.mlppp, provided by PC300 package."
 	depends on WAN && HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
 
+config PC300TOO
+	tristate "Cyclades PC300 RSV/X21 alternative support"
+	depends on HDLC && PCI
+	help
+	  Alternative driver for PC300 RSV/X21 PCI cards made by
+	  Cyclades, Inc. If you have such a card, say Y here and see
+	  <http://www.kernel.org/pub/linux/utils/net/hdlc/>.
+
+	  To compile this as a module, choose M here: the module
+	  will be called pc300too.
+
+	  If unsure, say N here.
+
 config N2
 	tristate "SDL RISCom/N2 support"
 	depends on HDLC && ISA
@@ -344,17 +357,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called dlci.
 
-config DLCI_COUNT
-	int "Max open DLCI"
-	depends on DLCI
-	default "24"
-	help
-	  Maximal number of logical point-to-point frame relay connections
-	  (the identifiers of which are called DCLIs) that the driver can
-	  handle.
-
-	  The default is probably fine.
-
 config DLCI_MAX
 	int "Max DLCI per device"
 	depends on DLCI
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index 83ec2c8..d61fef3 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -41,6 +41,7 @@
 obj-$(CONFIG_C101)		+= c101.o
 obj-$(CONFIG_WANXL)		+= wanxl.o
 obj-$(CONFIG_PCI200SYN)		+= pci200syn.o
+obj-$(CONFIG_PC300TOO)		+= pc300too.o
 
 clean-files := wanxlfw.inc
 $(obj)/wanxl.o:	$(obj)/wanxlfw.inc
diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c
index db354e0..9040d7c 100644
--- a/drivers/net/wan/hdlc.c
+++ b/drivers/net/wan/hdlc.c
@@ -222,7 +222,7 @@
 	return -EINVAL;
 }
 
-void hdlc_setup(struct net_device *dev)
+static void hdlc_setup(struct net_device *dev)
 {
 	hdlc_device *hdlc = dev_to_hdlc(dev);
 
@@ -325,7 +325,6 @@
 EXPORT_SYMBOL(hdlc_open);
 EXPORT_SYMBOL(hdlc_close);
 EXPORT_SYMBOL(hdlc_ioctl);
-EXPORT_SYMBOL(hdlc_setup);
 EXPORT_SYMBOL(alloc_hdlcdev);
 EXPORT_SYMBOL(unregister_hdlc_device);
 EXPORT_SYMBOL(register_hdlc_protocol);
diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c
new file mode 100644
index 0000000..bc156b5
--- /dev/null
+++ b/drivers/net/wan/pc300too.c
@@ -0,0 +1,565 @@
+/*
+ * Cyclades PC300 synchronous serial card driver for Linux
+ *
+ * Copyright (C) 2000-2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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.
+ *
+ * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/>.
+ *
+ * Sources of information:
+ *    Hitachi HD64572 SCA-II User's Manual
+ *    Cyclades PC300 Linux driver
+ *
+ * This driver currently supports only PC300/RSV (V.24/V.35) and
+ * PC300/X21 cards.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/hdlc.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include "hd64572.h"
+
+static const char* version = "Cyclades PC300 driver version: 1.17";
+static const char* devname = "PC300";
+
+#undef DEBUG_PKT
+#define DEBUG_RINGS
+
+#define PC300_PLX_SIZE		0x80    /* PLX control window size (128 B) */
+#define PC300_SCA_SIZE		0x400   /* SCA window size (1 KB) */
+#define ALL_PAGES_ALWAYS_MAPPED
+#define NEED_DETECT_RAM
+#define NEED_SCA_MSCI_INTR
+#define MAX_TX_BUFFERS		10
+
+static int pci_clock_freq = 33000000;
+static int use_crystal_clock = 0;
+static unsigned int CLOCK_BASE;
+
+/* Masks to access the init_ctrl PLX register */
+#define PC300_CLKSEL_MASK	 (0x00000004UL)
+#define PC300_CHMEDIA_MASK(port) (0x00000020UL << ((port) * 3))
+#define PC300_CTYPE_MASK	 (0x00000800UL)
+
+
+enum { PC300_RSV = 1, PC300_X21, PC300_TE }; /* card types */
+
+/*
+ *      PLX PCI9050-1 local configuration and shared runtime registers.
+ *      This structure can be used to access 9050 registers (memory mapped).
+ */
+typedef struct {
+	u32 loc_addr_range[4];	/* 00-0Ch : Local Address Ranges */
+	u32 loc_rom_range;	/* 10h : Local ROM Range */
+	u32 loc_addr_base[4];	/* 14-20h : Local Address Base Addrs */
+	u32 loc_rom_base;	/* 24h : Local ROM Base */
+	u32 loc_bus_descr[4];	/* 28-34h : Local Bus Descriptors */
+	u32 rom_bus_descr;	/* 38h : ROM Bus Descriptor */
+	u32 cs_base[4];		/* 3C-48h : Chip Select Base Addrs */
+	u32 intr_ctrl_stat;	/* 4Ch : Interrupt Control/Status */
+	u32 init_ctrl;		/* 50h : EEPROM ctrl, Init Ctrl, etc */
+}plx9050;
+
+
+
+typedef struct port_s {
+	struct net_device *dev;
+	struct card_s *card;
+	spinlock_t lock;	/* TX lock */
+	sync_serial_settings settings;
+	int rxpart;		/* partial frame received, next frame invalid*/
+	unsigned short encoding;
+	unsigned short parity;
+	unsigned int iface;
+	u16 rxin;		/* rx ring buffer 'in' pointer */
+	u16 txin;		/* tx ring buffer 'in' and 'last' pointers */
+	u16 txlast;
+	u8 rxs, txs, tmc;	/* SCA registers */
+	u8 phy_node;		/* physical port # - 0 or 1 */
+}port_t;
+
+
+
+typedef struct card_s {
+	int type;		/* RSV, X21, etc. */
+	int n_ports;		/* 1 or 2 ports */
+	u8 __iomem *rambase;	/* buffer memory base (virtual) */
+	u8 __iomem *scabase;	/* SCA memory base (virtual) */
+	plx9050 __iomem *plxbase; /* PLX registers memory base (virtual) */
+	u32 init_ctrl_value;	/* Saved value - 9050 bug workaround */
+	u16 rx_ring_buffers;	/* number of buffers in a ring */
+	u16 tx_ring_buffers;
+	u16 buff_offset;	/* offset of first buffer of first channel */
+	u8 irq;			/* interrupt request level */
+
+	port_t ports[2];
+}card_t;
+
+
+#define sca_in(reg, card)	     readb(card->scabase + (reg))
+#define sca_out(value, reg, card)    writeb(value, card->scabase + (reg))
+#define sca_inw(reg, card)	     readw(card->scabase + (reg))
+#define sca_outw(value, reg, card)   writew(value, card->scabase + (reg))
+#define sca_inl(reg, card)	     readl(card->scabase + (reg))
+#define sca_outl(value, reg, card)   writel(value, card->scabase + (reg))
+
+#define port_to_card(port)	     (port->card)
+#define log_node(port)		     (port->phy_node)
+#define phy_node(port)		     (port->phy_node)
+#define winbase(card)		     (card->rambase)
+#define get_port(card, port)	     ((port) < (card)->n_ports ? \
+					 (&(card)->ports[port]) : (NULL))
+
+#include "hd6457x.c"
+
+
+static void pc300_set_iface(port_t *port)
+{
+	card_t *card = port->card;
+	u32 __iomem * init_ctrl = &card->plxbase->init_ctrl;
+	u16 msci = get_msci(port);
+	u8 rxs = port->rxs & CLK_BRG_MASK;
+	u8 txs = port->txs & CLK_BRG_MASK;
+
+	sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS,
+		port_to_card(port));
+	switch(port->settings.clock_type) {
+	case CLOCK_INT:
+		rxs |= CLK_BRG; /* BRG output */
+		txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */
+		break;
+
+	case CLOCK_TXINT:
+		rxs |= CLK_LINE; /* RXC input */
+		txs |= CLK_PIN_OUT | CLK_BRG; /* BRG output */
+		break;
+
+	case CLOCK_TXFROMRX:
+		rxs |= CLK_LINE; /* RXC input */
+		txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */
+		break;
+
+	default:		/* EXTernal clock */
+		rxs |= CLK_LINE; /* RXC input */
+		txs |= CLK_PIN_OUT | CLK_LINE; /* TXC input */
+		break;
+	}
+
+	port->rxs = rxs;
+	port->txs = txs;
+	sca_out(rxs, msci + RXS, card);
+	sca_out(txs, msci + TXS, card);
+	sca_set_port(port);
+
+	if (port->card->type == PC300_RSV) {
+		if (port->iface == IF_IFACE_V35)
+			writel(card->init_ctrl_value |
+			       PC300_CHMEDIA_MASK(port->phy_node), init_ctrl);
+		else
+			writel(card->init_ctrl_value &
+			       ~PC300_CHMEDIA_MASK(port->phy_node), init_ctrl);
+	}
+}
+
+
+
+static int pc300_open(struct net_device *dev)
+{
+	port_t *port = dev_to_port(dev);
+
+	int result = hdlc_open(dev);
+	if (result)
+		return result;
+
+	sca_open(dev);
+	pc300_set_iface(port);
+	return 0;
+}
+
+
+
+static int pc300_close(struct net_device *dev)
+{
+	sca_close(dev);
+	hdlc_close(dev);
+	return 0;
+}
+
+
+
+static int pc300_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	const size_t size = sizeof(sync_serial_settings);
+	sync_serial_settings new_line;
+	sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync;
+	int new_type;
+	port_t *port = dev_to_port(dev);
+
+#ifdef DEBUG_RINGS
+	if (cmd == SIOCDEVPRIVATE) {
+		sca_dump_rings(dev);
+		return 0;
+	}
+#endif
+	if (cmd != SIOCWANDEV)
+		return hdlc_ioctl(dev, ifr, cmd);
+
+	if (ifr->ifr_settings.type == IF_GET_IFACE) {
+		ifr->ifr_settings.type = port->iface;
+		if (ifr->ifr_settings.size < size) {
+			ifr->ifr_settings.size = size; /* data size wanted */
+			return -ENOBUFS;
+		}
+		if (copy_to_user(line, &port->settings, size))
+			return -EFAULT;
+		return 0;
+
+	}
+
+	if (port->card->type == PC300_X21 &&
+	    (ifr->ifr_settings.type == IF_IFACE_SYNC_SERIAL ||
+	     ifr->ifr_settings.type == IF_IFACE_X21))
+		new_type = IF_IFACE_X21;
+
+	else if (port->card->type == PC300_RSV &&
+		 (ifr->ifr_settings.type == IF_IFACE_SYNC_SERIAL ||
+		  ifr->ifr_settings.type == IF_IFACE_V35))
+		new_type = IF_IFACE_V35;
+
+	else if (port->card->type == PC300_RSV &&
+		 ifr->ifr_settings.type == IF_IFACE_V24)
+		new_type = IF_IFACE_V24;
+
+	else
+		return hdlc_ioctl(dev, ifr, cmd);
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (copy_from_user(&new_line, line, size))
+		return -EFAULT;
+
+	if (new_line.clock_type != CLOCK_EXT &&
+	    new_line.clock_type != CLOCK_TXFROMRX &&
+	    new_line.clock_type != CLOCK_INT &&
+	    new_line.clock_type != CLOCK_TXINT)
+		return -EINVAL;	/* No such clock setting */
+
+	if (new_line.loopback != 0 && new_line.loopback != 1)
+		return -EINVAL;
+
+	memcpy(&port->settings, &new_line, size); /* Update settings */
+	port->iface = new_type;
+	pc300_set_iface(port);
+	return 0;
+}
+
+
+
+static void pc300_pci_remove_one(struct pci_dev *pdev)
+{
+	int i;
+	card_t *card = pci_get_drvdata(pdev);
+
+	for (i = 0; i < 2; i++)
+		if (card->ports[i].card) {
+			struct net_device *dev = port_to_dev(&card->ports[i]);
+			unregister_hdlc_device(dev);
+		}
+
+	if (card->irq)
+		free_irq(card->irq, card);
+
+	if (card->rambase)
+		iounmap(card->rambase);
+	if (card->scabase)
+		iounmap(card->scabase);
+	if (card->plxbase)
+		iounmap(card->plxbase);
+
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+	if (card->ports[0].dev)
+		free_netdev(card->ports[0].dev);
+	if (card->ports[1].dev)
+		free_netdev(card->ports[1].dev);
+	kfree(card);
+}
+
+
+
+static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
+					const struct pci_device_id *ent)
+{
+	card_t *card;
+	u8 rev_id;
+	u32 __iomem *p;
+	int i;
+	u32 ramsize;
+	u32 ramphys;		/* buffer memory base */
+	u32 scaphys;		/* SCA memory base */
+	u32 plxphys;		/* PLX registers memory base */
+
+#ifndef MODULE
+	static int printed_version;
+	if (!printed_version++)
+		printk(KERN_INFO "%s\n", version);
+#endif
+
+	i = pci_enable_device(pdev);
+	if (i)
+		return i;
+
+	i = pci_request_regions(pdev, "PC300");
+	if (i) {
+		pci_disable_device(pdev);
+		return i;
+	}
+
+	card = kmalloc(sizeof(card_t), GFP_KERNEL);
+	if (card == NULL) {
+		printk(KERN_ERR "pc300: unable to allocate memory\n");
+		pci_release_regions(pdev);
+		pci_disable_device(pdev);
+		return -ENOBUFS;
+	}
+	memset(card, 0, sizeof(card_t));
+	pci_set_drvdata(pdev, card);
+
+	if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 ||
+	    pdev->device == PCI_DEVICE_ID_PC300_TE_2)
+		card->type = PC300_TE; /* not fully supported */
+	else if (card->init_ctrl_value & PC300_CTYPE_MASK)
+		card->type = PC300_X21;
+	else
+		card->type = PC300_RSV;
+
+	if (pdev->device == PCI_DEVICE_ID_PC300_RX_1 ||
+	    pdev->device == PCI_DEVICE_ID_PC300_TE_1)
+		card->n_ports = 1;
+	else
+		card->n_ports = 2;
+
+	for (i = 0; i < card->n_ports; i++)
+		if (!(card->ports[i].dev = alloc_hdlcdev(&card->ports[i]))) {
+			printk(KERN_ERR "pc300: unable to allocate memory\n");
+			pc300_pci_remove_one(pdev);
+			return -ENOMEM;
+		}
+
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+	if (pci_resource_len(pdev, 0) != PC300_PLX_SIZE ||
+	    pci_resource_len(pdev, 2) != PC300_SCA_SIZE ||
+	    pci_resource_len(pdev, 3) < 16384) {
+		printk(KERN_ERR "pc300: invalid card EEPROM parameters\n");
+		pc300_pci_remove_one(pdev);
+		return -EFAULT;
+	}
+
+	plxphys = pci_resource_start(pdev,0) & PCI_BASE_ADDRESS_MEM_MASK;
+	card->plxbase = ioremap(plxphys, PC300_PLX_SIZE);
+
+	scaphys = pci_resource_start(pdev,2) & PCI_BASE_ADDRESS_MEM_MASK;
+	card->scabase = ioremap(scaphys, PC300_SCA_SIZE);
+
+	ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK;
+	card->rambase = ioremap(ramphys, pci_resource_len(pdev,3));
+
+	if (card->plxbase == NULL ||
+	    card->scabase == NULL ||
+	    card->rambase == NULL) {
+		printk(KERN_ERR "pc300: ioremap() failed\n");
+		pc300_pci_remove_one(pdev);
+	}
+
+	/* PLX PCI 9050 workaround for local configuration register read bug */
+	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, scaphys);
+	card->init_ctrl_value = readl(&((plx9050 __iomem *)card->scabase)->init_ctrl);
+	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, plxphys);
+
+	/* Reset PLX */
+	p = &card->plxbase->init_ctrl;
+	writel(card->init_ctrl_value | 0x40000000, p);
+	readl(p);		/* Flush the write - do not use sca_flush */
+	udelay(1);
+
+	writel(card->init_ctrl_value, p);
+	readl(p);		/* Flush the write - do not use sca_flush */
+	udelay(1);
+
+	/* Reload Config. Registers from EEPROM */
+	writel(card->init_ctrl_value | 0x20000000, p);
+	readl(p);		/* Flush the write - do not use sca_flush */
+	udelay(1);
+
+	writel(card->init_ctrl_value, p);
+	readl(p);		/* Flush the write - do not use sca_flush */
+	udelay(1);
+
+	ramsize = sca_detect_ram(card, card->rambase,
+				 pci_resource_len(pdev, 3));
+
+	if (use_crystal_clock)
+		card->init_ctrl_value &= ~PC300_CLKSEL_MASK;
+	else
+		card->init_ctrl_value |= PC300_CLKSEL_MASK;
+
+	writel(card->init_ctrl_value, &card->plxbase->init_ctrl);
+	/* number of TX + RX buffers for one port */
+	i = ramsize / (card->n_ports * (sizeof(pkt_desc) + HDLC_MAX_MRU));
+	card->tx_ring_buffers = min(i / 2, MAX_TX_BUFFERS);
+	card->rx_ring_buffers = i - card->tx_ring_buffers;
+
+	card->buff_offset = card->n_ports * sizeof(pkt_desc) *
+		(card->tx_ring_buffers + card->rx_ring_buffers);
+
+	printk(KERN_INFO "pc300: PC300/%s, %u KB RAM at 0x%x, IRQ%u, "
+	       "using %u TX + %u RX packets rings\n",
+	       card->type == PC300_X21 ? "X21" :
+	       card->type == PC300_TE ? "TE" : "RSV",
+	       ramsize / 1024, ramphys, pdev->irq,
+	       card->tx_ring_buffers, card->rx_ring_buffers);
+
+	if (card->tx_ring_buffers < 1) {
+		printk(KERN_ERR "pc300: RAM test failed\n");
+		pc300_pci_remove_one(pdev);
+		return -EFAULT;
+	}
+
+	/* Enable interrupts on the PCI bridge, LINTi1 active low */
+	writew(0x0041, &card->plxbase->intr_ctrl_stat);
+
+	/* Allocate IRQ */
+	if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, devname, card)) {
+		printk(KERN_WARNING "pc300: could not allocate IRQ%d.\n",
+		       pdev->irq);
+		pc300_pci_remove_one(pdev);
+		return -EBUSY;
+	}
+	card->irq = pdev->irq;
+
+	sca_init(card, 0);
+
+	// COTE not set - allows better TX DMA settings
+	// sca_out(sca_in(PCR, card) | PCR_COTE, PCR, card);
+
+	sca_out(0x10, BTCR, card);
+
+	for (i = 0; i < card->n_ports; i++) {
+		port_t *port = &card->ports[i];
+		struct net_device *dev = port_to_dev(port);
+		hdlc_device *hdlc = dev_to_hdlc(dev);
+		port->phy_node = i;
+
+		spin_lock_init(&port->lock);
+		SET_MODULE_OWNER(dev);
+		dev->irq = card->irq;
+		dev->mem_start = ramphys;
+		dev->mem_end = ramphys + ramsize - 1;
+		dev->tx_queue_len = 50;
+		dev->do_ioctl = pc300_ioctl;
+		dev->open = pc300_open;
+		dev->stop = pc300_close;
+		hdlc->attach = sca_attach;
+		hdlc->xmit = sca_xmit;
+		port->settings.clock_type = CLOCK_EXT;
+		port->card = card;
+		if (card->type == PC300_X21)
+			port->iface = IF_IFACE_X21;
+		else
+			port->iface = IF_IFACE_V35;
+
+		if (register_hdlc_device(dev)) {
+			printk(KERN_ERR "pc300: unable to register hdlc "
+			       "device\n");
+			port->card = NULL;
+			pc300_pci_remove_one(pdev);
+			return -ENOBUFS;
+		}
+		sca_init_sync_port(port);	/* Set up SCA memory */
+
+		printk(KERN_INFO "%s: PC300 node %d\n",
+		       dev->name, port->phy_node);
+	}
+	return 0;
+}
+
+
+
+static struct pci_device_id pc300_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_1, PCI_ANY_ID,
+	  PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_2, PCI_ANY_ID,
+	  PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_TE_1, PCI_ANY_ID,
+	  PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_TE_2, PCI_ANY_ID,
+	  PCI_ANY_ID, 0, 0, 0 },
+	{ 0, }
+};
+
+
+static struct pci_driver pc300_pci_driver = {
+	.name =          "PC300",
+	.id_table =      pc300_pci_tbl,
+	.probe =         pc300_pci_init_one,
+	.remove =        pc300_pci_remove_one,
+};
+
+
+static int __init pc300_init_module(void)
+{
+#ifdef MODULE
+	printk(KERN_INFO "%s\n", version);
+#endif
+	if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) {
+		printk(KERN_ERR "pc300: Invalid PCI clock frequency\n");
+		return -EINVAL;
+	}
+	if (use_crystal_clock != 0 && use_crystal_clock != 1) {
+		printk(KERN_ERR "pc300: Invalid 'use_crystal_clock' value\n");
+		return -EINVAL;
+	}
+
+	CLOCK_BASE = use_crystal_clock ? 24576000 : pci_clock_freq;
+
+	return pci_module_init(&pc300_pci_driver);
+}
+
+
+
+static void __exit pc300_cleanup_module(void)
+{
+	pci_unregister_driver(&pc300_pci_driver);
+}
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("Cyclades PC300 serial port driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(pci, pc300_pci_tbl);
+module_param(pci_clock_freq, int, 0444);
+MODULE_PARM_DESC(pci_clock_freq, "System PCI clock frequency in Hz");
+module_param(use_crystal_clock, int, 0444);
+MODULE_PARM_DESC(use_crystal_clock,
+		 "Use 24.576 MHz clock instead of PCI clock");
+module_init(pc300_init_module);
+module_exit(pc300_cleanup_module);
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index 59ddd21..8dbcf83 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -331,8 +331,7 @@
 static void z8530_rx(struct z8530_channel *c)
 {
 	u8 ch,stat;
-	spin_lock(c->lock);
- 
+
 	while(1)
 	{
 		/* FIFO empty ? */
@@ -390,7 +389,6 @@
 	 */
 	write_zsctrl(c, ERR_RES);
 	write_zsctrl(c, RES_H_IUS);
-	spin_unlock(c->lock);
 }
 
 
@@ -406,7 +404,6 @@
  
 static void z8530_tx(struct z8530_channel *c)
 {
-	spin_lock(c->lock);
 	while(c->txcount) {
 		/* FIFO full ? */
 		if(!(read_zsreg(c, R0)&4))
@@ -434,7 +431,6 @@
 
 	z8530_tx_done(c);	 
 	write_zsctrl(c, RES_H_IUS);
-	spin_unlock(c->lock);
 }
 
 /**
@@ -452,7 +448,6 @@
 {
 	u8 status, altered;
 
-	spin_lock(chan->lock);
 	status=read_zsreg(chan, R0);
 	altered=chan->status^status;
 	
@@ -487,7 +482,6 @@
 	}	
 	write_zsctrl(chan, RES_EXT_INT);
 	write_zsctrl(chan, RES_H_IUS);
-	spin_unlock(chan->lock);
 }
 
 struct z8530_irqhandler z8530_sync=
@@ -511,7 +505,6 @@
  
 static void z8530_dma_rx(struct z8530_channel *chan)
 {
-	spin_lock(chan->lock);
 	if(chan->rxdma_on)
 	{
 		/* Special condition check only */
@@ -534,7 +527,6 @@
 		/* DMA is off right now, drain the slow way */
 		z8530_rx(chan);
 	}	
-	spin_unlock(chan->lock);
 }
 
 /**
@@ -547,7 +539,6 @@
  
 static void z8530_dma_tx(struct z8530_channel *chan)
 {
-	spin_lock(chan->lock);
 	if(!chan->dma_tx)
 	{
 		printk(KERN_WARNING "Hey who turned the DMA off?\n");
@@ -557,7 +548,6 @@
 	/* This shouldnt occur in DMA mode */
 	printk(KERN_ERR "DMA tx - bogus event!\n");
 	z8530_tx(chan);
-	spin_unlock(chan->lock);
 }
 
 /**
@@ -596,7 +586,6 @@
 		}
 	}
 
-	spin_lock(chan->lock);
 	if(altered&chan->dcdcheck)
 	{
 		if(status&chan->dcdcheck)
@@ -618,7 +607,6 @@
 
 	write_zsctrl(chan, RES_EXT_INT);
 	write_zsctrl(chan, RES_H_IUS);
-	spin_unlock(chan->lock);
 }
 
 struct z8530_irqhandler z8530_dma_sync=
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index 7f38012..a032681 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -433,7 +433,7 @@
 		memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
 	} else {
 		/* Packet is in one chunk -- we can copy + cksum. */
-		eth_io_copy_and_sum(skb, xfer_start, count, 0);
+		memcpy_fromio(skb->data, xfer_start, count);
 	}
 
 	/* Turn off 16 bit access so that reboot works.	 ISA brain-damage */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 4168b1a..0e790ef 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -352,6 +352,10 @@
 #define BCM43xx_UCODEFLAG_UNKPACTRL	0x0040
 #define BCM43xx_UCODEFLAG_JAPAN		0x0080
 
+/* Hardware Radio Enable masks */
+#define BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16)
+#define BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
+
 /* Generic-Interrupt reasons. */
 #define BCM43xx_IRQ_READY		(1 << 0)
 #define BCM43xx_IRQ_BEACON		(1 << 1)
@@ -758,7 +762,8 @@
 	    bad_frames_preempt:1,	/* Use "Bad Frames Preemption" (default off) */
 	    reg124_set_0x4:1,		/* Some variable to keep track of IRQ stuff. */
 	    short_preamble:1,		/* TRUE, if short preamble is enabled. */
-	    firmware_norelease:1;	/* Do not release the firmware. Used on suspend. */
+	    firmware_norelease:1,	/* Do not release the firmware. Used on suspend. */
+	    radio_hw_enable:1;		/* TRUE if radio is hardware enabled */
 
 	struct bcm43xx_stats stats;
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
index 7d383a2..8f198be 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
@@ -26,6 +26,7 @@
 */
 
 #include "bcm43xx_leds.h"
+#include "bcm43xx_radio.h"
 #include "bcm43xx.h"
 
 #include <asm/bitops.h>
@@ -108,6 +109,7 @@
 	switch (led_index) {
 	case 0:
 		led->behaviour = BCM43xx_LED_ACTIVITY;
+		led->activelow = 1;
 		if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ)
 			led->behaviour = BCM43xx_LED_RADIO_ALL;
 		break;
@@ -199,20 +201,21 @@
 			turn_on = activity;
 			break;
 		case BCM43xx_LED_RADIO_ALL:
-			turn_on = radio->enabled;
+			turn_on = radio->enabled && bcm43xx_is_hw_radio_enabled(bcm);
 			break;
 		case BCM43xx_LED_RADIO_A:
 		case BCM43xx_LED_BCM4303_2:
-			turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A);
+			turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
+				   phy->type == BCM43xx_PHYTYPE_A);
 			break;
 		case BCM43xx_LED_RADIO_B:
 		case BCM43xx_LED_BCM4303_1:
-			turn_on = (radio->enabled &&
+			turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
 				   (phy->type == BCM43xx_PHYTYPE_B ||
 				    phy->type == BCM43xx_PHYTYPE_G));
 			break;
 		case BCM43xx_LED_MODE_BG:
-			if (phy->type == BCM43xx_PHYTYPE_G &&
+			if (phy->type == BCM43xx_PHYTYPE_G && bcm43xx_is_hw_radio_enabled(bcm) &&
 			    1/*FIXME: using G rates.*/)
 				turn_on = 1;
 			break;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 63fc16f..2e400aa 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -2437,6 +2437,9 @@
 	if (err)
 		goto err_gpio_cleanup;
 	bcm43xx_radio_turn_on(bcm);
+	bcm->radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
+	dprintk(KERN_INFO PFX "Radio %s by hardware\n",
+		(bcm->radio_hw_enable == 0) ? "disabled" : "enabled");
 
 	bcm43xx_write16(bcm, 0x03E6, 0x0000);
 	err = bcm43xx_phy_init(bcm);
@@ -3173,9 +3176,24 @@
 
 static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
 {
+	bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
+	//TODO for APHY (temperature?)
+}
+
+static void bcm43xx_periodic_every1sec(struct bcm43xx_private *bcm)
+{
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	int radio_hw_enable;
 
+	/* check if radio hardware enabled status changed */
+	radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
+	if (unlikely(bcm->radio_hw_enable != radio_hw_enable)) {
+		bcm->radio_hw_enable = radio_hw_enable;
+		dprintk(KERN_INFO PFX "Radio hardware status changed to %s\n",
+		       (radio_hw_enable == 0) ? "disabled" : "enabled");
+		bcm43xx_leds_update(bcm, 0);
+	}
 	if (phy->type == BCM43xx_PHYTYPE_G) {
 		//TODO: update_aci_moving_average
 		if (radio->aci_enable && radio->aci_wlan_automatic) {
@@ -3199,21 +3217,21 @@
 			//TODO: implement rev1 workaround
 		}
 	}
-	bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
-	//TODO for APHY (temperature?)
 }
 
 static void do_periodic_work(struct bcm43xx_private *bcm)
 {
-	if (bcm->periodic_state % 8 == 0)
+	if (bcm->periodic_state % 120 == 0)
 		bcm43xx_periodic_every120sec(bcm);
-	if (bcm->periodic_state % 4 == 0)
+	if (bcm->periodic_state % 60 == 0)
 		bcm43xx_periodic_every60sec(bcm);
-	if (bcm->periodic_state % 2 == 0)
+	if (bcm->periodic_state % 30 == 0)
 		bcm43xx_periodic_every30sec(bcm);
-	bcm43xx_periodic_every15sec(bcm);
+	if (bcm->periodic_state % 15 == 0)
+		bcm43xx_periodic_every15sec(bcm);
+	bcm43xx_periodic_every1sec(bcm);
 
-	schedule_delayed_work(&bcm->periodic_work, HZ * 15);
+	schedule_delayed_work(&bcm->periodic_work, HZ);
 }
 
 static void bcm43xx_periodic_work_handler(struct work_struct *work)
@@ -3226,7 +3244,7 @@
 	unsigned long orig_trans_start = 0;
 
 	mutex_lock(&bcm->mutex);
-	if (unlikely(bcm->periodic_state % 4 == 0)) {
+	if (unlikely(bcm->periodic_state % 60 == 0)) {
 		/* Periodic work will take a long time, so we want it to
 		 * be preemtible.
 		 */
@@ -3258,7 +3276,7 @@
 
 	do_periodic_work(bcm);
 
-	if (unlikely(bcm->periodic_state % 4 == 0)) {
+	if (unlikely(bcm->periodic_state % 60 == 0)) {
 		spin_lock_irqsave(&bcm->irq_lock, flags);
 		tasklet_enable(&bcm->isr_tasklet);
 		bcm43xx_interrupt_enable(bcm, savedirqs);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index bb9c484..af19a07 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -1981,6 +1981,7 @@
 	}
 	radio->enabled = 1;
 	dprintk(KERN_INFO PFX "Radio turned on\n");
+	bcm43xx_leds_update(bcm, 0);
 }
 	
 void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
@@ -2001,6 +2002,7 @@
 		bcm43xx_phy_write(bcm, 0x0015, 0xAA00);
 	radio->enabled = 0;
 	dprintk(KERN_INFO PFX "Radio turned off\n");
+	bcm43xx_leds_update(bcm, 0);
 }
 
 void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
index 9ed1803..77a98a5 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
@@ -65,6 +65,22 @@
 void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm);
 void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm);
 
+static inline
+int bcm43xx_is_hw_radio_enabled(struct bcm43xx_private *bcm)
+{
+	/* function to return state of hardware enable of radio
+	 * returns 0 if radio disabled, 1 if radio enabled
+	 */
+	if (bcm->current_core->rev >= 3)
+		return ((bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI)
+					& BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK)
+					== 0) ? 1 : 0;
+	else
+		return ((bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO)
+					& BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK)
+					== 0) ? 0 : 1;
+}
+
 int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel,
 				int synthetic_pu_workaround);
 
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 04c19ce..9077e6e 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -84,7 +84,7 @@
 	if (strchr(dev->name, '%'))
 		ret = dev_alloc_name(dev, dev->name);
 
-	SET_NETDEV_DEV(dev, mdev->class_dev.dev);
+	SET_NETDEV_DEV(dev, mdev->dev.parent);
 	if (ret >= 0)
 		ret = register_netdevice(dev);
 
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 22cb3fb..c878a2f 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -9166,7 +9166,7 @@
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	mutex_lock(&priv->mutex);
-	if (wrqu->rts.disabled)
+	if (wrqu->rts.disabled || !wrqu->rts.fixed)
 		priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
 	else {
 		if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
@@ -9255,7 +9255,7 @@
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	mutex_lock(&priv->mutex);
-	if (wrqu->frag.disabled)
+	if (wrqu->frag.disabled || !wrqu->frag.fixed)
 		priv->ieee->fts = DEFAULT_FTS;
 	else {
 		if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 936c888..4e7f6cf 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -2059,7 +2059,7 @@
 	int err;
 	struct comp_id nic_id, sta_id;
 	unsigned int firmver;
-	char tmp[SYMBOL_MAX_VER_LEN+1];
+	char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
 
 	/* Get the hardware version */
 	err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
@@ -4293,8 +4293,8 @@
 	strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
 	strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
 	strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1);
-	if (dev->class_dev.dev)
-		strncpy(info->bus_info, dev->class_dev.dev->bus_id,
+	if (dev->dev.parent)
+		strncpy(info->bus_info, dev->dev.parent->bus_id,
 			sizeof(info->bus_info) - 1);
 	else
 		snprintf(info->bus_info, sizeof(info->bus_info) - 1,
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index d08ae8d..d1e5022 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -332,7 +332,7 @@
 
 	/* Finally, report what we've done */
 	printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
-	       "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id,
+	       "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
 	       link->irq.AssignedIRQ, link->io.BasePort1,
 	       link->io.BasePort1 + link->io.NumPorts1 - 1);
 
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index f057fd9..a037b11 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 
 #include <linux/netdevice.h>
+#include <linux/ethtool.h>
 #include <linux/pci.h>
 #include <linux/etherdevice.h>
 #include <linux/delay.h>
@@ -787,6 +788,17 @@
 }
 #endif
 
+static void islpci_ethtool_get_drvinfo(struct net_device *dev,
+                                       struct ethtool_drvinfo *info)
+{
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+}
+
+static struct ethtool_ops islpci_ethtool_ops = {
+	.get_drvinfo = islpci_ethtool_get_drvinfo,
+};
+
 struct net_device *
 islpci_setup(struct pci_dev *pdev)
 {
@@ -813,6 +825,7 @@
 	ndev->do_ioctl = &prism54_ioctl;
 	ndev->wireless_handlers =
 	    (struct iw_handler_def *) &prism54_handler_def;
+	ndev->ethtool_ops = &islpci_ethtool_ops;
 
 	ndev->hard_start_xmit = &islpci_eth_transmit;
 	/* ndev->set_multicast_list = &islpci_set_multicast_list; */
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
index a9aa166..736666d 100644
--- a/drivers/net/wireless/prism54/islpci_dev.h
+++ b/drivers/net/wireless/prism54/islpci_dev.h
@@ -211,4 +211,8 @@
 
 int islpci_free_memory(islpci_private *);
 struct net_device *islpci_setup(struct pci_dev *);
+
+#define DRV_NAME	"prism54"
+#define DRV_VERSION	"1.2"
+
 #endif				/* _ISLPCI_DEV_H */
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index 58257b4..3dcb13b 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -28,9 +28,6 @@
 #include "islpci_mgt.h"		/* for pc_debug */
 #include "isl_oid.h"
 
-#define DRV_NAME	"prism54"
-#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");
 MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
index cf2d148..af70460 100644
--- a/drivers/net/wireless/spectrum_cs.c
+++ b/drivers/net/wireless/spectrum_cs.c
@@ -806,7 +806,7 @@
 
 	/* Finally, report what we've done */
 	printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
-	       "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id,
+	       "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
 	       link->irq.AssignedIRQ, link->io.BasePort1,
 	       link->io.BasePort1 + link->io.NumPorts1 - 1);
 
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 78ea72f..12dfc0b 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -84,6 +84,18 @@
 	dev_info(zd_chip_dev(chip), "%s\n", buffer);
 }
 
+static zd_addr_t inc_addr(zd_addr_t addr)
+{
+	u16 a = (u16)addr;
+	/* Control registers use byte addressing, but everything else uses word
+	 * addressing. */
+	if ((a & 0xf000) == CR_START)
+		a += 2;
+	else
+		a += 1;
+	return (zd_addr_t)a;
+}
+
 /* Read a variable number of 32-bit values. Parameter count is not allowed to
  * exceed USB_MAX_IOREAD32_COUNT.
  */
@@ -114,7 +126,7 @@
 	for (i = 0; i < count; i++) {
 		int j = 2*i;
 		/* We read the high word always first. */
-		a16[j] = zd_inc_word(addr[i]);
+		a16[j] = inc_addr(addr[i]);
 		a16[j+1] = addr[i];
 	}
 
@@ -163,7 +175,7 @@
 		j = 2*i;
 		/* We write the high word always first. */
 		ioreqs16[j].value   = ioreqs[i].value >> 16;
-		ioreqs16[j].addr    = zd_inc_word(ioreqs[i].addr);
+		ioreqs16[j].addr    = inc_addr(ioreqs[i].addr);
 		ioreqs16[j+1].value = ioreqs[i].value;
 		ioreqs16[j+1].addr  = ioreqs[i].addr;
 	}
@@ -466,7 +478,8 @@
 
 	ZD_ASSERT(mutex_is_locked(&chip->mutex));
 	for (i = 0;;) {
-		r = zd_ioread32_locked(chip, &v, e2p_addr+i/2);
+		r = zd_ioread32_locked(chip, &v,
+			               (zd_addr_t)((u16)e2p_addr+i/2));
 		if (r)
 			return r;
 		v -= guard;
@@ -798,47 +811,18 @@
 static int zd1211_hw_init_hmac(struct zd_chip *chip)
 {
 	static const struct zd_ioreq32 ioreqs[] = {
-		{ CR_ACK_TIMEOUT_EXT,		0x20 },
-		{ CR_ADDA_MBIAS_WARMTIME,	0x30000808 },
 		{ CR_ZD1211_RETRY_MAX,		0x2 },
-		{ CR_SNIFFER_ON,		0 },
-		{ CR_RX_FILTER,			STA_RX_FILTER },
-		{ CR_GROUP_HASH_P1,		0x00 },
-		{ CR_GROUP_HASH_P2,		0x80000000 },
-		{ CR_REG1,			0xa4 },
-		{ CR_ADDA_PWR_DWN,		0x7f },
-		{ CR_BCN_PLCP_CFG,		0x00f00401 },
-		{ CR_PHY_DELAY,			0x00 },
-		{ CR_ACK_TIMEOUT_EXT,		0x80 },
-		{ CR_ADDA_PWR_DWN,		0x00 },
-		{ CR_ACK_TIME_80211,		0x100 },
-		{ CR_RX_PE_DELAY,		0x70 },
-		{ CR_PS_CTRL,			0x10000000 },
-		{ CR_RTS_CTS_RATE,		0x02030203 },
 		{ CR_RX_THRESHOLD,		0x000c0640 },
-		{ CR_AFTER_PNP,			0x1 },
-		{ CR_WEP_PROTECT,		0x114 },
 	};
 
-	int r;
-
 	dev_dbg_f(zd_chip_dev(chip), "\n");
 	ZD_ASSERT(mutex_is_locked(&chip->mutex));
-	r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
-#ifdef DEBUG
-	if (r) {
-		dev_err(zd_chip_dev(chip),
-			"error in zd_iowrite32a_locked. Error number %d\n", r);
-	}
-#endif /* DEBUG */
-	return r;
+	return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
 static int zd1211b_hw_init_hmac(struct zd_chip *chip)
 {
 	static const struct zd_ioreq32 ioreqs[] = {
-		{ CR_ACK_TIMEOUT_EXT,		0x20 },
-		{ CR_ADDA_MBIAS_WARMTIME,	0x30000808 },
 		{ CR_ZD1211B_RETRY_MAX,		0x02020202 },
 		{ CR_ZD1211B_TX_PWR_CTL4,	0x007f003f },
 		{ CR_ZD1211B_TX_PWR_CTL3,	0x007f003f },
@@ -847,6 +831,20 @@
 		{ CR_ZD1211B_AIFS_CTL1,		0x00280028 },
 		{ CR_ZD1211B_AIFS_CTL2,		0x008C003C },
 		{ CR_ZD1211B_TXOP,		0x01800824 },
+		{ CR_RX_THRESHOLD,		0x000c0eff, },
+	};
+
+	dev_dbg_f(zd_chip_dev(chip), "\n");
+	ZD_ASSERT(mutex_is_locked(&chip->mutex));
+	return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int hw_init_hmac(struct zd_chip *chip)
+{
+	int r;
+	static const struct zd_ioreq32 ioreqs[] = {
+		{ CR_ACK_TIMEOUT_EXT,		0x20 },
+		{ CR_ADDA_MBIAS_WARMTIME,	0x30000808 },
 		{ CR_SNIFFER_ON,		0 },
 		{ CR_RX_FILTER,			STA_RX_FILTER },
 		{ CR_GROUP_HASH_P1,		0x00 },
@@ -861,25 +859,16 @@
 		{ CR_RX_PE_DELAY,		0x70 },
 		{ CR_PS_CTRL,			0x10000000 },
 		{ CR_RTS_CTS_RATE,		0x02030203 },
-		{ CR_RX_THRESHOLD,		0x000c0eff, },
 		{ CR_AFTER_PNP,			0x1 },
 		{ CR_WEP_PROTECT,		0x114 },
+		{ CR_IFS_VALUE,			IFS_VALUE_DEFAULT },
 	};
 
-	int r;
-
-	dev_dbg_f(zd_chip_dev(chip), "\n");
 	ZD_ASSERT(mutex_is_locked(&chip->mutex));
 	r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
-	if (r) {
-		dev_dbg_f(zd_chip_dev(chip),
-			"error in zd_iowrite32a_locked. Error number %d\n", r);
-	}
-	return r;
-}
+	if (r)
+		return r;
 
-static int hw_init_hmac(struct zd_chip *chip)
-{
 	return chip->is_zd1211b ?
 		zd1211b_hw_init_hmac(chip) : zd1211_hw_init_hmac(chip);
 }
@@ -974,16 +963,14 @@
 	if (r)
 		return r;
 
-	/* Although the vendor driver defaults to a different value during
-	 * init, it overwrites the IFS value with the following every time
-	 * the channel changes. We should aim to be more intelligent... */
-	r = zd_iowrite32_locked(chip, IFS_VALUE_DEFAULT, CR_IFS_VALUE);
-	if (r)
-		return r;
-
 	return set_beacon_interval(chip, 100);
 }
 
+static zd_addr_t fw_reg_addr(struct zd_chip *chip, u16 offset)
+{
+	return (zd_addr_t)((u16)chip->fw_regs_base + offset);
+}
+
 #ifdef DEBUG
 static int dump_cr(struct zd_chip *chip, const zd_addr_t addr,
 	           const char *addr_string)
@@ -1018,9 +1005,11 @@
 
 static void dump_fw_registers(struct zd_chip *chip)
 {
-	static const zd_addr_t addr[4] = {
-		FW_FIRMWARE_VER, FW_USB_SPEED, FW_FIX_TX_RATE,
-		FW_LINK_STATUS
+	const zd_addr_t addr[4] = {
+		fw_reg_addr(chip, FW_REG_FIRMWARE_VER),
+		fw_reg_addr(chip, FW_REG_USB_SPEED),
+		fw_reg_addr(chip, FW_REG_FIX_TX_RATE),
+		fw_reg_addr(chip, FW_REG_LED_LINK_STATUS),
 	};
 
 	int r;
@@ -1046,7 +1035,8 @@
 	int r;
 	u16 version;
 
-	r = zd_ioread16_locked(chip, &version, FW_FIRMWARE_VER);
+	r = zd_ioread16_locked(chip, &version,
+		fw_reg_addr(chip, FW_REG_FIRMWARE_VER));
 	if (r)
 		return r;
 
@@ -1126,6 +1116,22 @@
 	return r;
 }
 
+static int read_fw_regs_offset(struct zd_chip *chip)
+{
+	int r;
+
+	ZD_ASSERT(mutex_is_locked(&chip->mutex));
+	r = zd_ioread16_locked(chip, (u16*)&chip->fw_regs_base,
+		               FWRAW_REGS_ADDR);
+	if (r)
+		return r;
+	dev_dbg_f(zd_chip_dev(chip), "fw_regs_base: %#06hx\n",
+		  (u16)chip->fw_regs_base);
+
+	return 0;
+}
+
+
 int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
 {
 	int r;
@@ -1145,7 +1151,7 @@
 	if (r)
 		goto out;
 
-	r = zd_usb_init_hw(&chip->usb);
+	r = read_fw_regs_offset(chip);
 	if (r)
 		goto out;
 
@@ -1325,15 +1331,15 @@
 
 int zd_chip_control_leds(struct zd_chip *chip, enum led_status status)
 {
-	static const zd_addr_t a[] = {
-		FW_LINK_STATUS,
+	const zd_addr_t a[] = {
+		fw_reg_addr(chip, FW_REG_LED_LINK_STATUS),
 		CR_LED,
 	};
 
 	int r;
 	u16 v[ARRAY_SIZE(a)];
 	struct zd_ioreq16 ioreqs[ARRAY_SIZE(a)] = {
-		[0] = { FW_LINK_STATUS },
+		[0] = { fw_reg_addr(chip, FW_REG_LED_LINK_STATUS) },
 		[1] = { CR_LED },
 	};
 	u16 other_led;
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index a4e3cee..b07569e 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -18,7 +18,6 @@
 #ifndef _ZD_CHIP_H
 #define _ZD_CHIP_H
 
-#include "zd_types.h"
 #include "zd_rf.h"
 #include "zd_usb.h"
 
@@ -27,6 +26,37 @@
  * adds a processor for handling the USB protocol.
  */
 
+/* Address space */
+enum {
+	/* CONTROL REGISTERS */
+	CR_START			= 0x9000,
+
+
+	/* FIRMWARE */
+	FW_START			= 0xee00,
+
+
+	/* EEPROM */
+	E2P_START			= 0xf800,
+	E2P_LEN				= 0x800,
+
+	/* EEPROM layout */
+	E2P_LOAD_CODE_LEN		= 0xe,		/* base 0xf800 */
+	E2P_LOAD_VECT_LEN		= 0x9,		/* base 0xf80e */
+	/* E2P_DATA indexes into this */
+	E2P_DATA_LEN			= 0x7e,		/* base 0xf817 */
+	E2P_BOOT_CODE_LEN		= 0x760,	/* base 0xf895 */
+	E2P_INTR_VECT_LEN		= 0xb,		/* base 0xfff5 */
+
+	/* Some precomputed offsets into the EEPROM */
+	E2P_DATA_OFFSET			= E2P_LOAD_CODE_LEN + E2P_LOAD_VECT_LEN,
+	E2P_BOOT_CODE_OFFSET		= E2P_DATA_OFFSET + E2P_DATA_LEN,
+};
+
+#define CTL_REG(offset) ((zd_addr_t)(CR_START + (offset)))
+#define E2P_DATA(offset) ((zd_addr_t)(E2P_START + E2P_DATA_OFFSET + (offset)))
+#define FWRAW_DATA(offset) ((zd_addr_t)(FW_START + (offset)))
+
 /* 8-bit hardware registers */
 #define CR0   CTL_REG(0x0000)
 #define CR1   CTL_REG(0x0004)
@@ -302,7 +332,7 @@
 
 #define CR_MAX_PHY_REG 255
 
-/* Taken from the ZYDAS driver, not all of them are relevant for the ZSD1211
+/* Taken from the ZYDAS driver, not all of them are relevant for the ZD1211
  * driver.
  */
 
@@ -594,81 +624,71 @@
 /*
  * Upper 16 bit contains the regulatory domain.
  */
-#define E2P_SUBID		E2P_REG(0x00)
-#define E2P_POD			E2P_REG(0x02)
-#define E2P_MAC_ADDR_P1		E2P_REG(0x04)
-#define E2P_MAC_ADDR_P2		E2P_REG(0x06)
-#define E2P_PWR_CAL_VALUE1	E2P_REG(0x08)
-#define E2P_PWR_CAL_VALUE2	E2P_REG(0x0a)
-#define E2P_PWR_CAL_VALUE3	E2P_REG(0x0c)
-#define E2P_PWR_CAL_VALUE4      E2P_REG(0x0e)
-#define E2P_PWR_INT_VALUE1	E2P_REG(0x10)
-#define E2P_PWR_INT_VALUE2	E2P_REG(0x12)
-#define E2P_PWR_INT_VALUE3	E2P_REG(0x14)
-#define E2P_PWR_INT_VALUE4	E2P_REG(0x16)
+#define E2P_SUBID		E2P_DATA(0x00)
+#define E2P_POD			E2P_DATA(0x02)
+#define E2P_MAC_ADDR_P1		E2P_DATA(0x04)
+#define E2P_MAC_ADDR_P2		E2P_DATA(0x06)
+#define E2P_PWR_CAL_VALUE1	E2P_DATA(0x08)
+#define E2P_PWR_CAL_VALUE2	E2P_DATA(0x0a)
+#define E2P_PWR_CAL_VALUE3	E2P_DATA(0x0c)
+#define E2P_PWR_CAL_VALUE4      E2P_DATA(0x0e)
+#define E2P_PWR_INT_VALUE1	E2P_DATA(0x10)
+#define E2P_PWR_INT_VALUE2	E2P_DATA(0x12)
+#define E2P_PWR_INT_VALUE3	E2P_DATA(0x14)
+#define E2P_PWR_INT_VALUE4	E2P_DATA(0x16)
 
 /* Contains a bit for each allowed channel. It gives for Europe (ETSI 0x30)
  * also only 11 channels. */
-#define E2P_ALLOWED_CHANNEL	E2P_REG(0x18)
+#define E2P_ALLOWED_CHANNEL	E2P_DATA(0x18)
 
-#define E2P_PHY_REG		E2P_REG(0x1a)
-#define E2P_DEVICE_VER		E2P_REG(0x20)
-#define E2P_36M_CAL_VALUE1	E2P_REG(0x28)
-#define E2P_36M_CAL_VALUE2      E2P_REG(0x2a)
-#define E2P_36M_CAL_VALUE3      E2P_REG(0x2c)
-#define E2P_36M_CAL_VALUE4	E2P_REG(0x2e)
-#define E2P_11A_INT_VALUE1	E2P_REG(0x30)
-#define E2P_11A_INT_VALUE2	E2P_REG(0x32)
-#define E2P_11A_INT_VALUE3	E2P_REG(0x34)
-#define E2P_11A_INT_VALUE4	E2P_REG(0x36)
-#define E2P_48M_CAL_VALUE1	E2P_REG(0x38)
-#define E2P_48M_CAL_VALUE2	E2P_REG(0x3a)
-#define E2P_48M_CAL_VALUE3	E2P_REG(0x3c)
-#define E2P_48M_CAL_VALUE4	E2P_REG(0x3e)
-#define E2P_48M_INT_VALUE1	E2P_REG(0x40)
-#define E2P_48M_INT_VALUE2	E2P_REG(0x42)
-#define E2P_48M_INT_VALUE3	E2P_REG(0x44)
-#define E2P_48M_INT_VALUE4	E2P_REG(0x46)
-#define E2P_54M_CAL_VALUE1	E2P_REG(0x48)	/* ??? */
-#define E2P_54M_CAL_VALUE2	E2P_REG(0x4a)
-#define E2P_54M_CAL_VALUE3	E2P_REG(0x4c)
-#define E2P_54M_CAL_VALUE4	E2P_REG(0x4e)
-#define E2P_54M_INT_VALUE1	E2P_REG(0x50)
-#define E2P_54M_INT_VALUE2	E2P_REG(0x52)
-#define E2P_54M_INT_VALUE3	E2P_REG(0x54)
-#define E2P_54M_INT_VALUE4	E2P_REG(0x56)
+#define E2P_PHY_REG		E2P_DATA(0x1a)
+#define E2P_DEVICE_VER		E2P_DATA(0x20)
+#define E2P_36M_CAL_VALUE1	E2P_DATA(0x28)
+#define E2P_36M_CAL_VALUE2      E2P_DATA(0x2a)
+#define E2P_36M_CAL_VALUE3      E2P_DATA(0x2c)
+#define E2P_36M_CAL_VALUE4	E2P_DATA(0x2e)
+#define E2P_11A_INT_VALUE1	E2P_DATA(0x30)
+#define E2P_11A_INT_VALUE2	E2P_DATA(0x32)
+#define E2P_11A_INT_VALUE3	E2P_DATA(0x34)
+#define E2P_11A_INT_VALUE4	E2P_DATA(0x36)
+#define E2P_48M_CAL_VALUE1	E2P_DATA(0x38)
+#define E2P_48M_CAL_VALUE2	E2P_DATA(0x3a)
+#define E2P_48M_CAL_VALUE3	E2P_DATA(0x3c)
+#define E2P_48M_CAL_VALUE4	E2P_DATA(0x3e)
+#define E2P_48M_INT_VALUE1	E2P_DATA(0x40)
+#define E2P_48M_INT_VALUE2	E2P_DATA(0x42)
+#define E2P_48M_INT_VALUE3	E2P_DATA(0x44)
+#define E2P_48M_INT_VALUE4	E2P_DATA(0x46)
+#define E2P_54M_CAL_VALUE1	E2P_DATA(0x48)	/* ??? */
+#define E2P_54M_CAL_VALUE2	E2P_DATA(0x4a)
+#define E2P_54M_CAL_VALUE3	E2P_DATA(0x4c)
+#define E2P_54M_CAL_VALUE4	E2P_DATA(0x4e)
+#define E2P_54M_INT_VALUE1	E2P_DATA(0x50)
+#define E2P_54M_INT_VALUE2	E2P_DATA(0x52)
+#define E2P_54M_INT_VALUE3	E2P_DATA(0x54)
+#define E2P_54M_INT_VALUE4	E2P_DATA(0x56)
 
-/* All 16 bit values */
-#define FW_FIRMWARE_VER         FW_REG(0)
-/* non-zero if USB high speed connection */
-#define FW_USB_SPEED            FW_REG(1)
-#define FW_FIX_TX_RATE          FW_REG(2)
-/* Seems to be able to control LEDs over the firmware */
-#define FW_LINK_STATUS          FW_REG(3)
-#define FW_SOFT_RESET           FW_REG(4)
-#define FW_FLASH_CHK            FW_REG(5)
+/* This word contains the base address of the FW_REG_ registers below */
+#define FWRAW_REGS_ADDR		FWRAW_DATA(0x1d)
 
+/* All 16 bit values, offset from the address in FWRAW_REGS_ADDR */
+enum {
+	FW_REG_FIRMWARE_VER	= 0,
+	/* non-zero if USB high speed connection */
+	FW_REG_USB_SPEED	= 1,
+	FW_REG_FIX_TX_RATE	= 2,
+	/* Seems to be able to control LEDs over the firmware */
+	FW_REG_LED_LINK_STATUS	= 3,
+	FW_REG_SOFT_RESET	= 4,
+	FW_REG_FLASH_CHK	= 5,
+};
+
+/* Values for FW_LINK_STATUS */
 #define FW_LINK_OFF		0x0
 #define FW_LINK_TX		0x1
 /* 0x2 - link led on? */
 
 enum {
-	CR_BASE_OFFSET			= 0x9000,
-	FW_START_OFFSET			= 0xee00,
-	FW_BASE_ADDR_OFFSET		= FW_START_OFFSET + 0x1d,
-	EEPROM_START_OFFSET		= 0xf800,
-	EEPROM_SIZE			= 0x800, /* words */
-	LOAD_CODE_SIZE			= 0xe, /* words */
-	LOAD_VECT_SIZE			= 0x10000 - 0xfff7, /* words */
-	EEPROM_REGS_OFFSET		= LOAD_CODE_SIZE + LOAD_VECT_SIZE,
-	EEPROM_REGS_SIZE		= 0x7e, /* words */
-	E2P_BASE_OFFSET			= EEPROM_START_OFFSET +
-		                          EEPROM_REGS_OFFSET,
-};
-
-#define FW_REG_TABLE_ADDR	USB_ADDR(FW_START_OFFSET + 0x1d)
-
-enum {
 	/* indices for ofdm_cal_values */
 	OFDM_36M_INDEX = 0,
 	OFDM_48M_INDEX = 1,
@@ -679,6 +699,8 @@
 	struct zd_usb usb;
 	struct zd_rf rf;
 	struct mutex mutex;
+	/* Base address of FW_REG_ registers */
+	zd_addr_t fw_regs_base;
 	u8 e2p_mac[ETH_ALEN];
 	/* EepSetPoint in the vendor driver */
 	u8 pwr_cal_values[E2P_CHANNEL_COUNT];
diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h
index fb22f62..deb99d1 100644
--- a/drivers/net/wireless/zd1211rw/zd_def.h
+++ b/drivers/net/wireless/zd1211rw/zd_def.h
@@ -23,6 +23,8 @@
 #include <linux/device.h>
 #include <linux/kernel.h>
 
+typedef u16 __nocast zd_addr_t;
+
 #define dev_printk_f(level, dev, fmt, args...) \
 	dev_printk(level, dev, "%s() " fmt, __func__, ##args)
 
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
index 26b8298..c4f36d3 100644
--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
@@ -2,7 +2,6 @@
 #define _ZD_IEEE80211_H
 
 #include <net/ieee80211.h>
-#include "zd_types.h"
 
 /* Additional definitions from the standards.
  */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
index 676b373..a57732e 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.h
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -18,8 +18,6 @@
 #ifndef _ZD_RF_H
 #define _ZD_RF_H
 
-#include "zd_types.h"
-
 #define UW2451_RF			0x2
 #define UCHIP_RF			0x3
 #define AL2230_RF			0x4
diff --git a/drivers/net/wireless/zd1211rw/zd_types.h b/drivers/net/wireless/zd1211rw/zd_types.h
deleted file mode 100644
index 0155a15..0000000
--- a/drivers/net/wireless/zd1211rw/zd_types.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* zd_types.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _ZD_TYPES_H
-#define _ZD_TYPES_H
-
-#include <linux/types.h>
-
-/* We have three register spaces mapped into the overall USB address space of
- * 64K words (16-bit values). There is the control register space of
- * double-word registers, the eeprom register space and the firmware register
- * space. The control register space is byte mapped, the others are word
- * mapped.
- *
- * For that reason, we are using byte offsets for control registers and word
- * offsets for everything else.
- */
-
-typedef u32 __nocast zd_addr_t;
-
-enum {
-	ADDR_BASE_MASK		= 0xff000000,
-	ADDR_OFFSET_MASK	= 0x0000ffff,
-	ADDR_ZERO_MASK		= 0x00ff0000,
-	NULL_BASE		= 0x00000000,
-	USB_BASE		= 0x01000000,
-	CR_BASE			= 0x02000000,
-	CR_MAX_OFFSET		= 0x0b30,
-	E2P_BASE		= 0x03000000,
-	E2P_MAX_OFFSET		= 0x007e,
-	FW_BASE			= 0x04000000,
-	FW_MAX_OFFSET		= 0x0005,
-};
-
-#define ZD_ADDR_BASE(addr) ((u32)(addr) & ADDR_BASE_MASK)
-#define ZD_OFFSET(addr) ((u32)(addr) & ADDR_OFFSET_MASK)
-
-#define ZD_ADDR(base, offset) \
-	((zd_addr_t)(((base) & ADDR_BASE_MASK) | ((offset) & ADDR_OFFSET_MASK)))
-
-#define ZD_NULL_ADDR    ((zd_addr_t)0)
-#define USB_REG(offset)  ZD_ADDR(USB_BASE, offset)	/* word addressing */
-#define CTL_REG(offset)  ZD_ADDR(CR_BASE, offset)	/* byte addressing */
-#define E2P_REG(offset)  ZD_ADDR(E2P_BASE, offset)	/* word addressing */
-#define FW_REG(offset)   ZD_ADDR(FW_BASE, offset)	/* word addressing */
-
-static inline zd_addr_t zd_inc_word(zd_addr_t addr)
-{
-	u32 base = ZD_ADDR_BASE(addr);
-	u32 offset = ZD_OFFSET(addr);
-
-	offset += base == CR_BASE ? 2 : 1;
-
-	return base | offset;
-}
-
-#endif /* _ZD_TYPES_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index a3217a8..aac8a1c 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -58,6 +58,10 @@
 	{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
 	/* "Driverless" devices that need ejecting */
 	{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
 	{}
@@ -73,96 +77,6 @@
 #define FW_ZD1211_PREFIX	"zd1211/zd1211_"
 #define FW_ZD1211B_PREFIX	"zd1211/zd1211b_"
 
-/* register address handling */
-
-#ifdef DEBUG
-static int check_addr(struct zd_usb *usb, zd_addr_t addr)
-{
-	u32 base = ZD_ADDR_BASE(addr);
-	u32 offset = ZD_OFFSET(addr);
-
-	if ((u32)addr & ADDR_ZERO_MASK)
-		goto invalid_address;
-	switch (base) {
-	case USB_BASE:
-		break;
-	case CR_BASE:
-		if (offset > CR_MAX_OFFSET) {
-			dev_dbg(zd_usb_dev(usb),
-				"CR offset %#010x larger than"
-				" CR_MAX_OFFSET %#10x\n",
-				offset, CR_MAX_OFFSET);
-			goto invalid_address;
-		}
-		if (offset & 1) {
-			dev_dbg(zd_usb_dev(usb),
-				"CR offset %#010x is not a multiple of 2\n",
-				offset);
-			goto invalid_address;
-		}
-		break;
-	case E2P_BASE:
-		if (offset > E2P_MAX_OFFSET) {
-			dev_dbg(zd_usb_dev(usb),
-				"E2P offset %#010x larger than"
-				" E2P_MAX_OFFSET %#010x\n",
-				offset, E2P_MAX_OFFSET);
-			goto invalid_address;
-		}
-		break;
-	case FW_BASE:
-		if (!usb->fw_base_offset) {
-			dev_dbg(zd_usb_dev(usb),
-			       "ERROR: fw base offset has not been set\n");
-			return -EAGAIN;
-		}
-		if (offset > FW_MAX_OFFSET) {
-			dev_dbg(zd_usb_dev(usb),
-				"FW offset %#10x is larger than"
-				" FW_MAX_OFFSET %#010x\n",
-				offset, FW_MAX_OFFSET);
-			goto invalid_address;
-		}
-		break;
-	default:
-		dev_dbg(zd_usb_dev(usb),
-			"address has unsupported base %#010x\n", addr);
-		goto invalid_address;
-	}
-
-	return 0;
-invalid_address:
-	dev_dbg(zd_usb_dev(usb),
-		"ERROR: invalid address: %#010x\n", addr);
-	return -EINVAL;
-}
-#endif /* DEBUG */
-
-static u16 usb_addr(struct zd_usb *usb, zd_addr_t addr)
-{
-	u32 base;
-	u16 offset;
-
-	base = ZD_ADDR_BASE(addr);
-	offset = ZD_OFFSET(addr);
-
-	ZD_ASSERT(check_addr(usb, addr) == 0);
-
-	switch (base) {
-	case CR_BASE:
-		offset += CR_BASE_OFFSET;
-		break;
-	case E2P_BASE:
-		offset += E2P_BASE_OFFSET;
-		break;
-	case FW_BASE:
-		offset += usb->fw_base_offset;
-		break;
-	}
-
-	return offset;
-}
-
 /* USB device initialization */
 
 static int request_fw_file(
@@ -295,14 +209,13 @@
 	if (r)
 		goto error;
 
-	r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START_OFFSET,
-		REBOOT);
+	r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START, REBOOT);
 	if (r)
 		goto error;
 
-	offset = ((EEPROM_REGS_OFFSET + EEPROM_REGS_SIZE) * sizeof(u16));
+	offset = (E2P_BOOT_CODE_OFFSET * sizeof(u16));
 	r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset,
-		E2P_BASE_OFFSET + EEPROM_REGS_SIZE, REBOOT);
+		E2P_START + E2P_BOOT_CODE_OFFSET, REBOOT);
 
 	/* At this point, the vendor driver downloads the whole firmware
 	 * image, hacks around with version IDs, and uploads it again,
@@ -331,7 +244,7 @@
 	if (r)
 		goto error;
 
-	fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET);
+	fw_bcdDevice = get_word(ub_fw->data, E2P_DATA_OFFSET);
 
 	if (fw_bcdDevice != bcdDevice) {
 		dev_info(&udev->dev,
@@ -357,8 +270,7 @@
 	if (r)
 		goto error;
 
-	r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START_OFFSET,
-		        REBOOT);
+	r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START, REBOOT);
 	if (r) {
 		dev_err(&udev->dev,
 			"Could not upload firmware code uph. Error number %d\n",
@@ -867,7 +779,7 @@
 	spin_lock_init(&intr->lock);
 	intr->interval = int_urb_interval(zd_usb_to_usbdev(usb));
 	init_completion(&intr->read_regs.completion);
-	intr->read_regs.cr_int_addr = cpu_to_le16(usb_addr(usb, CR_INTERRUPT));
+	intr->read_regs.cr_int_addr = cpu_to_le16((u16)CR_INTERRUPT);
 }
 
 static inline void init_usb_rx(struct zd_usb *usb)
@@ -899,22 +811,6 @@
 	init_usb_rx(usb);
 }
 
-int zd_usb_init_hw(struct zd_usb *usb)
-{
-	int r;
-	struct zd_chip *chip = zd_usb_to_chip(usb);
-
-	ZD_ASSERT(mutex_is_locked(&chip->mutex));
-	r = zd_ioread16_locked(chip, &usb->fw_base_offset,
-		        USB_REG((u16)FW_BASE_ADDR_OFFSET));
-	if (r)
-		return r;
-	dev_dbg_f(zd_usb_dev(usb), "fw_base_offset: %#06hx\n",
-		 usb->fw_base_offset);
-
-	return 0;
-}
-
 void zd_usb_clear(struct zd_usb *usb)
 {
 	usb_set_intfdata(usb->intf, NULL);
@@ -1265,7 +1161,7 @@
 		return -ENOMEM;
 	req->id = cpu_to_le16(USB_REQ_READ_REGS);
 	for (i = 0; i < count; i++)
-		req->addr[i] = cpu_to_le16(usb_addr(usb, addresses[i]));
+		req->addr[i] = cpu_to_le16((u16)addresses[i]);
 
 	udev = zd_usb_to_usbdev(usb);
 	prepare_read_regs_int(usb);
@@ -1330,7 +1226,7 @@
 	req->id = cpu_to_le16(USB_REQ_WRITE_REGS);
 	for (i = 0; i < count; i++) {
 		struct reg_data *rw  = &req->reg_writes[i];
-		rw->addr = cpu_to_le16(usb_addr(usb, ioreqs[i].addr));
+		rw->addr = cpu_to_le16((u16)ioreqs[i].addr);
 		rw->value = cpu_to_le16(ioreqs[i].value);
 	}
 
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index 317d37c..506ea6a 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -25,7 +25,6 @@
 #include <linux/usb.h>
 
 #include "zd_def.h"
-#include "zd_types.h"
 
 enum devicetype {
 	DEVICE_ZD1211  = 0,
@@ -181,15 +180,14 @@
 	spinlock_t lock;
 };
 
-/* Contains the usb parts. The structure doesn't require a lock, because intf
- * and fw_base_offset, will not be changed after initialization.
+/* Contains the usb parts. The structure doesn't require a lock because intf
+ * will not be changed after initialization.
  */
 struct zd_usb {
 	struct zd_usb_interrupt intr;
 	struct zd_usb_rx rx;
 	struct zd_usb_tx tx;
 	struct usb_interface *intf;
-	u16 fw_base_offset;
 };
 
 #define zd_usb_dev(usb) (&usb->intf->dev)
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index adce420..be92695 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -145,15 +145,6 @@
 
 	  When in doubt, say N.
 
-config HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
-	bool "Use polling mechanism for hot-plug events (for testing purpose)"
-	depends on HOTPLUG_PCI_SHPC
-	help
-	  Say Y here if you want to use the polling mechanism for hot-plug 
-	  events for early platform testing.
-
-	  When in doubt, say N.
-
 config HOTPLUG_PCI_RPA
 	tristate "RPA PCI Hotplug driver"
 	depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index bd1faeb..fca978f 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -773,13 +773,13 @@
 		goto out;
 
 	table = obj->buffer.pointer;
-	switch (((acpi_table_entry_header *)table)->type) {
-	case ACPI_MADT_IOSAPIC:
-		*gsi_base = ((struct acpi_table_iosapic *)table)->global_irq_base;
+	switch (((struct acpi_subtable_header *)table)->type) {
+	case ACPI_MADT_TYPE_IO_SAPIC:
+		*gsi_base = ((struct acpi_madt_io_sapic *)table)->global_irq_base;
 		result = 0;
 		break;
-	case ACPI_MADT_IOAPIC:
-		*gsi_base = ((struct acpi_table_ioapic *)table)->global_irq_base;
+	case ACPI_MADT_TYPE_IO_APIC:
+		*gsi_base = ((struct acpi_madt_io_apic *)table)->global_irq_base;
 		result = 0;
 		break;
 	default:
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 4fb12fc..d19fcae 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -44,15 +44,20 @@
 extern int pciehp_debug;
 extern int pciehp_force;
 
-/*#define dbg(format, arg...) do { if (pciehp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/
-#define dbg(format, arg...) do { if (pciehp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0)
-#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+#define dbg(format, arg...)						\
+	do {								\
+		if (pciehp_debug)					\
+			printk("%s: " format, MY_NAME , ## arg);	\
+	} while (0)
+#define err(format, arg...)						\
+	printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...)						\
+	printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...)						\
+	printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
 
-
+#define SLOT_NAME_SIZE 10
 struct slot {
-	struct slot *next;
 	u8 bus;
 	u8 device;
 	u32 number;
@@ -63,6 +68,8 @@
 	struct hpc_ops *hpc_ops;
 	struct hotplug_slot *hotplug_slot;
 	struct list_head	slot_list;
+	char name[SLOT_NAME_SIZE];
+	unsigned long last_emi_toggle;
 };
 
 struct event_info {
@@ -70,34 +77,15 @@
 	u8 hp_slot;
 };
 
-typedef u8(*php_intr_callback_t) (u8 hp_slot, void *instance_id);
-
-struct php_ctlr_state_s {
-	struct php_ctlr_state_s *pnext;
-	struct pci_dev *pci_dev;
-	unsigned int irq;
-	unsigned long flags;				/* spinlock's */
-	u32 slot_device_offset;
-	u32 num_slots;
-    	struct timer_list	int_poll_timer;		/* Added for poll event */
-	php_intr_callback_t 	attention_button_callback;
-	php_intr_callback_t 	switch_change_callback;
-	php_intr_callback_t 	presence_change_callback;
-	php_intr_callback_t 	power_fault_callback;
-	void 			*callback_instance_id;
-	struct ctrl_reg 	*creg;				/* Ptr to controller register space */
-};
-
 #define MAX_EVENTS		10
 struct controller {
 	struct controller *next;
 	struct mutex crit_sect;		/* critical section mutex */
 	struct mutex ctrl_lock;		/* controller lock */
-	struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */
 	int num_slots;			/* Number of slots on ctlr */
 	int slot_num_inc;		/* 1 or -1 */
 	struct pci_dev *pci_dev;
-	struct pci_bus *pci_bus;
+	struct list_head slot_list;
 	struct event_info event_queue[MAX_EVENTS];
 	struct slot *slot;
 	struct hpc_ops *hpc_ops;
@@ -112,6 +100,8 @@
 	u8 ctrlcap;
 	u16 vendor_id;
 	u8 cap_base;
+	struct timer_list poll_timer;
+	volatile int cmd_busy;
 };
 
 #define INT_BUTTON_IGNORE		0
@@ -131,8 +121,6 @@
 #define POWERON_STATE			3
 #define POWEROFF_STATE			4
 
-#define PCI_TO_PCI_BRIDGE_CLASS		0x00060400
-
 /* Error messages */
 #define INTERLOCK_OPEN			0x00000002
 #define ADD_NOT_SUPPORTED		0x00000003
@@ -144,10 +132,6 @@
 #define WRONG_BUS_FREQUENCY		0x0000000D
 #define POWER_FAILURE			0x0000000E
 
-#define REMOVE_NOT_SUPPORTED		0x00000003
-
-#define DISABLE_CARD			1
-
 /* Field definitions in Slot Capabilities Register */
 #define ATTN_BUTTN_PRSN	0x00000001
 #define	PWR_CTRL_PRSN	0x00000002
@@ -155,6 +139,7 @@
 #define ATTN_LED_PRSN	0x00000008
 #define PWR_LED_PRSN	0x00000010
 #define HP_SUPR_RM_SUP	0x00000020
+#define EMI_PRSN	0x00020000
 
 #define ATTN_BUTTN(cap)		(cap & ATTN_BUTTN_PRSN)
 #define POWER_CTRL(cap)		(cap & PWR_CTRL_PRSN)
@@ -162,130 +147,65 @@
 #define ATTN_LED(cap)		(cap & ATTN_LED_PRSN)
 #define PWR_LED(cap)		(cap & PWR_LED_PRSN) 
 #define HP_SUPR_RM(cap)		(cap & HP_SUPR_RM_SUP)
+#define EMI(cap)		(cap & EMI_PRSN)
 
-/*
- * error Messages
- */
-#define msg_initialization_err	"Initialization failure, error=%d\n"
-#define msg_button_on		"PCI slot #%s - powering on due to button press.\n"
-#define msg_button_off		"PCI slot #%s - powering off due to button press.\n"
-#define msg_button_cancel	"PCI slot #%s - action canceled due to button press.\n"
-#define msg_button_ignore	"PCI slot #%s - button press ignored.  (action in progress...)\n"
-
-/* controller functions */
-extern int	pciehp_event_start_thread	(void);
-extern void	pciehp_event_stop_thread	(void);
-extern int	pciehp_enable_slot		(struct slot *slot);
-extern int	pciehp_disable_slot		(struct slot *slot);
-
-extern u8	pciehp_handle_attention_button	(u8 hp_slot, void *inst_id);
-extern u8	pciehp_handle_switch_change	(u8 hp_slot, void *inst_id);
-extern u8	pciehp_handle_presence_change	(u8 hp_slot, void *inst_id);
-extern u8	pciehp_handle_power_fault	(u8 hp_slot, void *inst_id);
-/* extern void	long_delay (int delay); */
-
-/* pci functions */
-extern int	pciehp_configure_device		(struct slot *p_slot);
-extern int	pciehp_unconfigure_device	(struct slot *p_slot);
-
-
+extern int pciehp_event_start_thread(void);
+extern void pciehp_event_stop_thread(void);
+extern int pciehp_enable_slot(struct slot *slot);
+extern int pciehp_disable_slot(struct slot *slot);
+extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
+extern int pciehp_configure_device(struct slot *p_slot);
+extern int pciehp_unconfigure_device(struct slot *p_slot);
+int pcie_init(struct controller *ctrl, struct pcie_device *dev);
 
 /* Global variables */
 extern struct controller *pciehp_ctrl_list;
 
-/* Inline functions */
-
 static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device)
 {
-	struct slot *p_slot, *tmp_slot = NULL;
+	struct slot *slot;
 
-	p_slot = ctrl->slot;
-
-	while (p_slot && (p_slot->device != device)) {
-		tmp_slot = p_slot;
-		p_slot = p_slot->next;
-	}
-	if (p_slot == NULL) {
-		err("ERROR: pciehp_find_slot device=0x%x\n", device);
-		p_slot = tmp_slot;
+	list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
+		if (slot->device == device)
+			return slot;
 	}
 
-	return p_slot;
+	err("%s: slot (device=0x%x) not found\n", __FUNCTION__, device);
+	return NULL;
 }
 
-static inline int wait_for_ctrl_irq(struct controller *ctrl)
-{
-	int retval = 0;
-
-	DECLARE_WAITQUEUE(wait, current);
-
-	add_wait_queue(&ctrl->queue, &wait);
-	if (!pciehp_poll_mode)
-		/* Sleep for up to 1 second */
-		msleep_interruptible(1000);
-	else
-		msleep_interruptible(2500);
-	
-	remove_wait_queue(&ctrl->queue, &wait);
-	if (signal_pending(current))
-		retval =  -EINTR;
-
-	return retval;
-}
-
-#define SLOT_NAME_SIZE 10
-
-static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
-{
-	snprintf(buffer, buffer_size, "%04d_%04d", slot->bus, slot->number);
-}
-
-enum php_ctlr_type {
-	PCI,
-	ISA,
-	ACPI
-};
-
-int pcie_init(struct controller *ctrl, struct pcie_device *dev);
-
-/* This has no meaning for PCI Express, as there is only 1 slot per port */
-int pcie_get_ctlr_slot_config(struct controller *ctrl,
-		int *num_ctlr_slots,
-		int *first_device_num,
-		int *physical_slot_num,
-		u8 *ctrlcap);
-
 struct hpc_ops {
-	int	(*power_on_slot)	(struct slot *slot);
-	int	(*power_off_slot)	(struct slot *slot);
-	int	(*get_power_status)	(struct slot *slot, u8 *status);
-	int	(*get_attention_status)	(struct slot *slot, u8 *status);
-	int	(*set_attention_status)	(struct slot *slot, u8 status);
-	int	(*get_latch_status)	(struct slot *slot, u8 *status);
-	int	(*get_adapter_status)	(struct slot *slot, u8 *status);
-
-	int	(*get_max_bus_speed)	(struct slot *slot, enum pci_bus_speed *speed);
-	int	(*get_cur_bus_speed)	(struct slot *slot, enum pci_bus_speed *speed);
-
-	int	(*get_max_lnk_width)	(struct slot *slot, enum pcie_link_width *value);
-	int	(*get_cur_lnk_width)	(struct slot *slot, enum pcie_link_width *value);
-	
-	int	(*query_power_fault)	(struct slot *slot);
-	void	(*green_led_on)		(struct slot *slot);
-	void	(*green_led_off)	(struct slot *slot);
-	void	(*green_led_blink)	(struct slot *slot);
-	void	(*release_ctlr)		(struct controller *ctrl);
-	int	(*check_lnk_status)	(struct controller *ctrl);
+	int (*power_on_slot)(struct slot *slot);
+	int (*power_off_slot)(struct slot *slot);
+	int (*get_power_status)(struct slot *slot, u8 *status);
+	int (*get_attention_status)(struct slot *slot, u8 *status);
+	int (*set_attention_status)(struct slot *slot, u8 status);
+	int (*get_latch_status)(struct slot *slot, u8 *status);
+	int (*get_adapter_status)(struct slot *slot, u8 *status);
+	int (*get_emi_status)(struct slot *slot, u8 *status);
+	int (*toggle_emi)(struct slot *slot);
+	int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
+	int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
+	int (*get_max_lnk_width)(struct slot *slot, enum pcie_link_width *val);
+	int (*get_cur_lnk_width)(struct slot *slot, enum pcie_link_width *val);
+	int (*query_power_fault)(struct slot *slot);
+	void (*green_led_on)(struct slot *slot);
+	void (*green_led_off)(struct slot *slot);
+	void (*green_led_blink)(struct slot *slot);
+	void (*release_ctlr)(struct controller *ctrl);
+	int (*check_lnk_status)(struct controller *ctrl);
 };
 
-
 #ifdef CONFIG_ACPI
 #include <acpi/acpi.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/actypes.h>
 #include <linux/pci-acpi.h>
 
-#define pciehp_get_hp_hw_control_from_firmware(dev) \
+#define pciehp_get_hp_hw_control_from_firmware(dev)			\
 	pciehp_acpi_get_hp_hw_control_from_firmware(dev)
 static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev,
 			struct hotplug_params *hpp)
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index f13f313..a92eda6 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -34,6 +34,7 @@
 #include <linux/pci.h>
 #include "pciehp.h"
 #include <linux/interrupt.h>
+#include <linux/time.h>
 
 /* Global variables */
 int pciehp_debug;
@@ -87,6 +88,95 @@
   	.get_cur_bus_speed =	get_cur_bus_speed,
 };
 
+/*
+ * Check the status of the Electro Mechanical Interlock (EMI)
+ */
+static int get_lock_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = hotplug_slot->private;
+	return (slot->hpc_ops->get_emi_status(slot, value));
+}
+
+/*
+ * sysfs interface for the Electro Mechanical Interlock (EMI)
+ * 1 == locked, 0 == unlocked
+ */
+static ssize_t lock_read_file(struct hotplug_slot *slot, char *buf)
+{
+	int retval;
+	u8 value;
+
+	retval = get_lock_status(slot, &value);
+	if (retval)
+		goto lock_read_exit;
+	retval = sprintf (buf, "%d\n", value);
+
+lock_read_exit:
+	return retval;
+}
+
+/*
+ * Change the status of the Electro Mechanical Interlock (EMI)
+ * This is a toggle - in addition there must be at least 1 second
+ * in between toggles.
+ */
+static int set_lock_status(struct hotplug_slot *hotplug_slot, u8 status)
+{
+	struct slot *slot = hotplug_slot->private;
+	int retval;
+	u8 value;
+
+	mutex_lock(&slot->ctrl->crit_sect);
+
+	/* has it been >1 sec since our last toggle? */
+	if ((get_seconds() - slot->last_emi_toggle) < 1)
+		return -EINVAL;
+
+	/* see what our current state is */
+	retval = get_lock_status(hotplug_slot, &value);
+	if (retval || (value == status))
+		goto set_lock_exit;
+
+	slot->hpc_ops->toggle_emi(slot);
+set_lock_exit:
+	mutex_unlock(&slot->ctrl->crit_sect);
+	return 0;
+}
+
+/*
+ * sysfs interface which allows the user to toggle the Electro Mechanical
+ * Interlock.  Valid values are either 0 or 1.  0 == unlock, 1 == lock
+ */
+static ssize_t lock_write_file(struct hotplug_slot *slot, const char *buf,
+		size_t count)
+{
+	unsigned long llock;
+	u8 lock;
+	int retval = 0;
+
+	llock = simple_strtoul(buf, NULL, 10);
+	lock = (u8)(llock & 0xff);
+
+	switch (lock) {
+		case 0:
+		case 1:
+			retval = set_lock_status(slot, lock);
+			break;
+		default:
+			err ("%d is an invalid lock value\n", lock);
+			retval = -EINVAL;
+	}
+	if (retval)
+		return retval;
+	return count;
+}
+
+static struct hotplug_slot_attribute hotplug_slot_attr_lock = {
+	.attr = {.name = "lock", .mode = S_IFREG | S_IRUGO | S_IWUSR},
+	.show = lock_read_file,
+	.store = lock_write_file
+};
+
 /**
  * release_slot - free up the memory used by a slot
  * @hotplug_slot: slot to free
@@ -98,148 +188,108 @@
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	kfree(slot->hotplug_slot->info);
-	kfree(slot->hotplug_slot->name);
 	kfree(slot->hotplug_slot);
 	kfree(slot);
 }
 
+static void make_slot_name(struct slot *slot)
+{
+	snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d",
+		 slot->bus, slot->number);
+}
+
 static int init_slots(struct controller *ctrl)
 {
 	struct slot *slot;
-	struct hpc_ops *hpc_ops;
 	struct hotplug_slot *hotplug_slot;
-	struct hotplug_slot_info *hotplug_slot_info;
-	u8 number_of_slots;
-	u8 slot_device;
-	u32 slot_number;
-	int result = -ENOMEM;
+	struct hotplug_slot_info *info;
+	int retval = -ENOMEM;
+	int i;
 
-	number_of_slots = ctrl->num_slots;
-	slot_device = ctrl->slot_device_offset;
-	slot_number = ctrl->first_slot;
-
-	while (number_of_slots) {
+	for (i = 0; i < ctrl->num_slots; i++) {
 		slot = kzalloc(sizeof(*slot), GFP_KERNEL);
 		if (!slot)
 			goto error;
 
-		slot->hotplug_slot =
-				kzalloc(sizeof(*(slot->hotplug_slot)),
-						GFP_KERNEL);
-		if (!slot->hotplug_slot)
+		hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL);
+		if (!hotplug_slot)
 			goto error_slot;
-		hotplug_slot = slot->hotplug_slot;
+		slot->hotplug_slot = hotplug_slot;
 
-		hotplug_slot->info =
-			kzalloc(sizeof(*(hotplug_slot->info)),
-						GFP_KERNEL);
-		if (!hotplug_slot->info)
+		info = kzalloc(sizeof(*info), GFP_KERNEL);
+		if (!info)
 			goto error_hpslot;
-		hotplug_slot_info = hotplug_slot->info;
-		hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
-		if (!hotplug_slot->name)
-			goto error_info;
+		hotplug_slot->info = info;
 
+		hotplug_slot->name = slot->name;
+
+		slot->hp_slot = i;
 		slot->ctrl = ctrl;
-		slot->bus = ctrl->slot_bus;
-		slot->device = slot_device;
-		slot->hpc_ops = hpc_ops = ctrl->hpc_ops;
-
+		slot->bus = ctrl->pci_dev->subordinate->number;
+		slot->device = ctrl->slot_device_offset + i;
+		slot->hpc_ops = ctrl->hpc_ops;
 		slot->number = ctrl->first_slot;
-		slot->hp_slot = slot_device - ctrl->slot_device_offset;
 
 		/* register this slot with the hotplug pci core */
 		hotplug_slot->private = slot;
 		hotplug_slot->release = &release_slot;
-		make_slot_name(hotplug_slot->name, SLOT_NAME_SIZE, slot);
+		make_slot_name(slot);
 		hotplug_slot->ops = &pciehp_hotplug_slot_ops;
 
-		hpc_ops->get_power_status(slot,
-			&(hotplug_slot_info->power_status));
-		hpc_ops->get_attention_status(slot,
-			&(hotplug_slot_info->attention_status));
-		hpc_ops->get_latch_status(slot,
-			&(hotplug_slot_info->latch_status));
-		hpc_ops->get_adapter_status(slot,
-			&(hotplug_slot_info->adapter_status));
+		get_power_status(hotplug_slot, &info->power_status);
+		get_attention_status(hotplug_slot, &info->attention_status);
+		get_latch_status(hotplug_slot, &info->latch_status);
+		get_adapter_status(hotplug_slot, &info->adapter_status);
 
 		dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
-			"slot_device_offset=%x\n",
-			slot->bus, slot->device, slot->hp_slot, slot->number,
-			ctrl->slot_device_offset);
-		result = pci_hp_register(hotplug_slot);
-		if (result) {
-			err ("pci_hp_register failed with error %d\n", result);
-			goto error_name;
+		    "slot_device_offset=%x\n", slot->bus, slot->device,
+		    slot->hp_slot, slot->number, ctrl->slot_device_offset);
+		retval = pci_hp_register(hotplug_slot);
+		if (retval) {
+			err ("pci_hp_register failed with error %d\n", retval);
+			goto error_info;
+		}
+		/* create additional sysfs entries */
+		if (EMI(ctrl->ctrlcap)) {
+			retval = sysfs_create_file(&hotplug_slot->kobj,
+				&hotplug_slot_attr_lock.attr);
+			if (retval) {
+				pci_hp_deregister(hotplug_slot);
+				err("cannot create additional sysfs entries\n");
+				goto error_info;
+			}
 		}
 
-		slot->next = ctrl->slot;
-		ctrl->slot = slot;
-
-		number_of_slots--;
-		slot_device++;
-		slot_number += ctrl->slot_num_inc;
+		list_add(&slot->slot_list, &ctrl->slot_list);
 	}
 
 	return 0;
-
-error_name:
-	kfree(hotplug_slot->name);
 error_info:
-	kfree(hotplug_slot_info);
+	kfree(info);
 error_hpslot:
 	kfree(hotplug_slot);
 error_slot:
 	kfree(slot);
 error:
-	return result;
+	return retval;
 }
 
-
-static int cleanup_slots (struct controller * ctrl)
+static void cleanup_slots(struct controller *ctrl)
 {
-	struct slot *old_slot, *next_slot;
+	struct list_head *tmp;
+	struct list_head *next;
+	struct slot *slot;
 
-	old_slot = ctrl->slot;
-	ctrl->slot = NULL;
-
-	while (old_slot) {
-		next_slot = old_slot->next;
-		pci_hp_deregister (old_slot->hotplug_slot);
-		old_slot = next_slot;
+	list_for_each_safe(tmp, next, &ctrl->slot_list) {
+		slot = list_entry(tmp, struct slot, slot_list);
+		list_del(&slot->slot_list);
+		if (EMI(ctrl->ctrlcap))
+			sysfs_remove_file(&slot->hotplug_slot->kobj,
+				&hotplug_slot_attr_lock.attr);
+		pci_hp_deregister(slot->hotplug_slot);
 	}
-
-
-	return(0);
 }
 
-static int get_ctlr_slot_config(struct controller *ctrl)
-{
-	int num_ctlr_slots;		/* Not needed; PCI Express has 1 slot per port*/
-	int first_device_num;		/* Not needed */
-	int physical_slot_num;
-	u8 ctrlcap;			
-	int rc;
-
-	rc = pcie_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &ctrlcap);
-	if (rc) {
-		err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device);
-		return (-1);
-	}
-
-	ctrl->num_slots = num_ctlr_slots;	/* PCI Express has 1 slot per port */
-	ctrl->slot_device_offset = first_device_num;
-	ctrl->first_slot = physical_slot_num;
-	ctrl->ctrlcap = ctrlcap; 	
-
-	dbg("%s: bus(0x%x) num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) ctrlcap(%x) for b:d (%x:%x)\n",
-		__FUNCTION__, ctrl->slot_bus, num_ctlr_slots, first_device_num, physical_slot_num, ctrlcap, 
-		ctrl->bus, ctrl->device);
-
-	return (0);
-}
-
-
 /*
  * set_attention_status - Turns the Amber LED for a slot on, off or blink
  */
@@ -378,8 +428,6 @@
 	int rc;
 	struct controller *ctrl;
 	struct slot *t_slot;
-	int first_device_num = 0 ;	/* first PCI device number supported by this PCIE */  
-	int num_ctlr_slots;		/* number of slots supported by this HPC */
 	u8 value;
 	struct pci_dev *pdev;
 	
@@ -388,6 +436,7 @@
 		err("%s : out of memory\n", __FUNCTION__);
 		goto err_out_none;
 	}
+	INIT_LIST_HEAD(&ctrl->slot_list);
 
 	pdev = dev->port;
 	ctrl->pci_dev = pdev;
@@ -400,13 +449,6 @@
 
 	pci_set_drvdata(pdev, ctrl);
 
-	ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL);
-	if (!ctrl->pci_bus) {
-		err("%s: out of memory\n", __FUNCTION__);
-		rc = -ENOMEM;
-		goto err_out_unmap_mmio_region;
-	}
-	memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus));
 	ctrl->bus = pdev->bus->number;  /* ctrl bus */
 	ctrl->slot_bus = pdev->subordinate->number;  /* bus controlled by this HPC */
 
@@ -415,26 +457,14 @@
 	dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__,
 		ctrl->bus, ctrl->device, ctrl->function, pdev->irq);
 
-	/*
-	 *	Save configuration headers for this and subordinate PCI buses
-	 */
-
-	rc = get_ctlr_slot_config(ctrl);
-	if (rc) {
-		err(msg_initialization_err, rc);
-		goto err_out_free_ctrl_bus;
-	}
-	first_device_num = ctrl->slot_device_offset;
-	num_ctlr_slots = ctrl->num_slots; 
-
 	/* Setup the slot information structures */
 	rc = init_slots(ctrl);
 	if (rc) {
-		err(msg_initialization_err, 6);
-		goto err_out_free_ctrl_slot;
+		err("%s: slot initialization failed\n", PCIE_MODULE_NAME);
+		goto err_out_release_ctlr;
 	}
 
-	t_slot = pciehp_find_slot(ctrl, first_device_num);
+	t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
 
 	/*	Finish setting up the hot plug ctrl device */
 	ctrl->next_event = 0;
@@ -447,32 +477,18 @@
 		pciehp_ctrl_list = ctrl;
 	}
 
-	/* Wait for exclusive access to hardware */
-	mutex_lock(&ctrl->ctrl_lock);
-
 	t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
-	
 	if ((POWER_CTRL(ctrl->ctrlcap)) && !value) {
 		rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
-		if (rc) {
-			/* Done with exclusive hardware access */
-			mutex_unlock(&ctrl->ctrl_lock);
+		if (rc)
 			goto err_out_free_ctrl_slot;
-		} else
-			/* Wait for the command to complete */
-			wait_for_ctrl_irq (ctrl);
 	}
 
-	/* Done with exclusive hardware access */
-	mutex_unlock(&ctrl->ctrl_lock);
-
 	return 0;
 
 err_out_free_ctrl_slot:
 	cleanup_slots(ctrl);
-err_out_free_ctrl_bus:
-	kfree(ctrl->pci_bus);
-err_out_unmap_mmio_region:
+err_out_release_ctlr:
 	ctrl->hpc_ops->release_ctlr(ctrl);
 err_out_free_ctrl:
 	kfree(ctrl);
@@ -506,8 +522,6 @@
 	while (ctrl) {
 		cleanup_slots(ctrl);
 
-		kfree (ctrl->pci_bus);
-
 		ctrl->hpc_ops->release_ctlr(ctrl);
 
 		tctrl = ctrl;
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 372c63e..4283ef5 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -48,9 +48,8 @@
 	return p_slot->hotplug_slot->name;
 }
 
-u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
 {
-	struct controller *ctrl = (struct controller *) inst_id;
 	struct slot *p_slot;
 	u8 rc = 0;
 	u8 getstatus;
@@ -101,9 +100,8 @@
 
 }
 
-u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
 {
-	struct controller *ctrl = (struct controller *) inst_id;
 	struct slot *p_slot;
 	u8 rc = 0;
 	u8 getstatus;
@@ -143,9 +141,8 @@
 	return rc;
 }
 
-u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
 {
-	struct controller *ctrl = (struct controller *) inst_id;
 	struct slot *p_slot;
 	u8 presence_save, rc = 0;
 	struct event_info *taskInfo;
@@ -187,9 +184,8 @@
 	return rc;
 }
 
-u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
 {
-	struct controller *ctrl = (struct controller *) inst_id;
 	struct slot *p_slot;
 	u8 rc = 0;
 	struct event_info *taskInfo;
@@ -233,35 +229,25 @@
 
 static void set_slot_off(struct controller *ctrl, struct slot * pslot)
 {
-	/* Wait for exclusive access to hardware */
-	mutex_lock(&ctrl->ctrl_lock);
-
 	/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
 	if (POWER_CTRL(ctrl->ctrlcap)) {
 		if (pslot->hpc_ops->power_off_slot(pslot)) {   
-			err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
-			mutex_unlock(&ctrl->ctrl_lock);
+			err("%s: Issue of Slot Power Off command failed\n",
+			    __FUNCTION__);
 			return;
 		}
-		wait_for_ctrl_irq (ctrl);
 	}
 
-	if (PWR_LED(ctrl->ctrlcap)) {
+	if (PWR_LED(ctrl->ctrlcap))
 		pslot->hpc_ops->green_led_off(pslot);   
-		wait_for_ctrl_irq (ctrl);
-	}
 
-	if (ATTN_LED(ctrl->ctrlcap)) { 
-		if (pslot->hpc_ops->set_attention_status(pslot, 1)) {   
-			err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
-			mutex_unlock(&ctrl->ctrl_lock);
+	if (ATTN_LED(ctrl->ctrlcap)) {
+		if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
+			err("%s: Issue of Set Attention Led command failed\n",
+			    __FUNCTION__);
 			return;
 		}
-		wait_for_ctrl_irq (ctrl);
 	}
-
-	/* Done with exclusive hardware access */
-	mutex_unlock(&ctrl->ctrl_lock);
 }
 
 /**
@@ -274,7 +260,7 @@
 static int board_added(struct slot *p_slot)
 {
 	u8 hp_slot;
-	int rc = 0;
+	int retval = 0;
 	struct controller *ctrl = p_slot->ctrl;
 
 	hp_slot = p_slot->device - ctrl->slot_device_offset;
@@ -283,53 +269,38 @@
 			__FUNCTION__, p_slot->device,
 			ctrl->slot_device_offset, hp_slot);
 
-	/* Wait for exclusive access to hardware */
-	mutex_lock(&ctrl->ctrl_lock);
-
 	if (POWER_CTRL(ctrl->ctrlcap)) {
 		/* Power on slot */
-		rc = p_slot->hpc_ops->power_on_slot(p_slot);
-		if (rc) {
-			mutex_unlock(&ctrl->ctrl_lock);
-			return -1;
-		}
-
-		/* Wait for the command to complete */
-		wait_for_ctrl_irq (ctrl);
+		retval = p_slot->hpc_ops->power_on_slot(p_slot);
+		if (retval)
+			return retval;
 	}
 	
-	if (PWR_LED(ctrl->ctrlcap)) {
+	if (PWR_LED(ctrl->ctrlcap))
 		p_slot->hpc_ops->green_led_blink(p_slot);
-			
-		/* Wait for the command to complete */
-		wait_for_ctrl_irq (ctrl);
-	}
-
-	/* Done with exclusive hardware access */
-	mutex_unlock(&ctrl->ctrl_lock);
 
 	/* Wait for ~1 second */
-	wait_for_ctrl_irq (ctrl);
+	msleep(1000);
 
-	/*  Check link training status */
-	rc = p_slot->hpc_ops->check_lnk_status(ctrl);  
-	if (rc) {
+	/* Check link training status */
+	retval = p_slot->hpc_ops->check_lnk_status(ctrl);
+	if (retval) {
 		err("%s: Failed to check link status\n", __FUNCTION__);
 		set_slot_off(ctrl, p_slot);
-		return rc;
+		return retval;
 	}
 
 	/* Check for a power fault */
 	if (p_slot->hpc_ops->query_power_fault(p_slot)) {
 		dbg("%s: power fault detected\n", __FUNCTION__);
-		rc = POWER_FAILURE;
+		retval = POWER_FAILURE;
 		goto err_exit;
 	}
 
-	rc = pciehp_configure_device(p_slot);
-	if (rc) {
+	retval = pciehp_configure_device(p_slot);
+	if (retval) {
 		err("Cannot add device 0x%x:%x\n", p_slot->bus,
-				p_slot->device);
+		    p_slot->device);
 		goto err_exit;
 	}
 
@@ -338,26 +309,16 @@
 	 */
 	if (pcie_mch_quirk)
 		pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
-	if (PWR_LED(ctrl->ctrlcap)) {
-		/* Wait for exclusive access to hardware */
-  		mutex_lock(&ctrl->ctrl_lock);
-
+	if (PWR_LED(ctrl->ctrlcap))
   		p_slot->hpc_ops->green_led_on(p_slot);
-  
-  		/* Wait for the command to complete */
-  		wait_for_ctrl_irq (ctrl);
-  	
-  		/* Done with exclusive hardware access */
-  		mutex_unlock(&ctrl->ctrl_lock);
-  	}
+
 	return 0;
 
 err_exit:
 	set_slot_off(ctrl, p_slot);
-	return -1;
+	return retval;
 }
 
-
 /**
  * remove_board - Turns off slot and LED's
  *
@@ -366,44 +327,32 @@
 {
 	u8 device;
 	u8 hp_slot;
-	int rc;
+	int retval = 0;
 	struct controller *ctrl = p_slot->ctrl;
 
-	if (pciehp_unconfigure_device(p_slot))
-		return 1;
+	retval = pciehp_unconfigure_device(p_slot);
+	if (retval)
+		return retval;
 
 	device = p_slot->device;
-
 	hp_slot = p_slot->device - ctrl->slot_device_offset;
 	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 
 	dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
 
-	/* Wait for exclusive access to hardware */
-	mutex_lock(&ctrl->ctrl_lock);
-
 	if (POWER_CTRL(ctrl->ctrlcap)) {
 		/* power off slot */
-		rc = p_slot->hpc_ops->power_off_slot(p_slot);
-		if (rc) {
-			err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
-			mutex_unlock(&ctrl->ctrl_lock);
-			return rc;
+		retval = p_slot->hpc_ops->power_off_slot(p_slot);
+		if (retval) {
+			err("%s: Issue of Slot Disable command failed\n",
+			    __FUNCTION__);
+			return retval;
 		}
-		/* Wait for the command to complete */
-		wait_for_ctrl_irq (ctrl);
 	}
 
-	if (PWR_LED(ctrl->ctrlcap)) {
+	if (PWR_LED(ctrl->ctrlcap))
 		/* turn off Green LED */
 		p_slot->hpc_ops->green_led_off(p_slot);
-	
-		/* Wait for the command to complete */
-		wait_for_ctrl_irq (ctrl);
-	}
-
-	/* Done with exclusive hardware access */
-	mutex_unlock(&ctrl->ctrl_lock);
 
 	return 0;
 }
@@ -448,18 +397,10 @@
 		dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__,
 				p_slot->bus, p_slot->device);
 
-		if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
-			/* Wait for exclusive access to hardware */
-			mutex_lock(&p_slot->ctrl->ctrl_lock);
-
+		if (pciehp_enable_slot(p_slot) &&
+		    PWR_LED(p_slot->ctrl->ctrlcap))
 			p_slot->hpc_ops->green_led_off(p_slot);
 
-			/* Wait for the command to complete */
-			wait_for_ctrl_irq (p_slot->ctrl);
-
-			/* Done with exclusive hardware access */
-			mutex_unlock(&p_slot->ctrl->ctrl_lock);
-		}
 		p_slot->state = STATIC_STATE;
 	}
 
@@ -498,18 +439,10 @@
 		dbg("%s: adding bus:device(%x:%x)\n",
 				__FUNCTION__, p_slot->bus, p_slot->device);
 
-		if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
-			/* Wait for exclusive access to hardware */
-			mutex_lock(&p_slot->ctrl->ctrl_lock);
-
+		if (pciehp_enable_slot(p_slot) &&
+		    PWR_LED(p_slot->ctrl->ctrlcap))
 			p_slot->hpc_ops->green_led_off(p_slot);
 
-			/* Wait for the command to complete */
-			wait_for_ctrl_irq (p_slot->ctrl);
-
-			/* Done with exclusive hardware access */
-			mutex_unlock(&p_slot->ctrl->ctrl_lock);
-		}
 		p_slot->state = STATIC_STATE;
 	}
 
@@ -620,46 +553,24 @@
 
 					switch (p_slot->state) {
 					case BLINKINGOFF_STATE:
-						/* Wait for exclusive access to hardware */
-						mutex_lock(&ctrl->ctrl_lock);
-						
-						if (PWR_LED(ctrl->ctrlcap)) {
+						if (PWR_LED(ctrl->ctrlcap))
 							p_slot->hpc_ops->green_led_on(p_slot);
-							/* Wait for the command to complete */
-							wait_for_ctrl_irq (ctrl);
-						}
-						if (ATTN_LED(ctrl->ctrlcap)) {
-							p_slot->hpc_ops->set_attention_status(p_slot, 0);
 
-							/* Wait for the command to complete */
-							wait_for_ctrl_irq (ctrl);
-						}
-						/* Done with exclusive hardware access */
-						mutex_unlock(&ctrl->ctrl_lock);
+						if (ATTN_LED(ctrl->ctrlcap))
+							p_slot->hpc_ops->set_attention_status(p_slot, 0);
 						break;
 					case BLINKINGON_STATE:
-						/* Wait for exclusive access to hardware */
-						mutex_lock(&ctrl->ctrl_lock);
-
-						if (PWR_LED(ctrl->ctrlcap)) {
+						if (PWR_LED(ctrl->ctrlcap))
 							p_slot->hpc_ops->green_led_off(p_slot);
-							/* Wait for the command to complete */
-							wait_for_ctrl_irq (ctrl);
-						}
-						if (ATTN_LED(ctrl->ctrlcap)){
-							p_slot->hpc_ops->set_attention_status(p_slot, 0);
-							/* Wait for the command to complete */
-							wait_for_ctrl_irq (ctrl);
-						}
-						/* Done with exclusive hardware access */
-						mutex_unlock(&ctrl->ctrl_lock);
 
+						if (ATTN_LED(ctrl->ctrlcap))
+							p_slot->hpc_ops->set_attention_status(p_slot, 0);
 						break;
 					default:
 						warn("Not a valid state\n");
 						return;
 					}
-					info(msg_button_cancel, slot_name(p_slot));
+					info("PCI slot #%s - action canceled due to button press.\n", slot_name(p_slot));
 					p_slot->state = STATIC_STATE;
 				}
 				/* ***********Button Pressed (No action on 1st press...) */
@@ -672,34 +583,21 @@
 							/* slot is on */
 							dbg("slot is on\n");
 							p_slot->state = BLINKINGOFF_STATE;
-							info(msg_button_off, slot_name(p_slot));
+							info("PCI slot #%s - powering off due to button press.\n", slot_name(p_slot));
 						} else {
 							/* slot is off */
 							dbg("slot is off\n");
 							p_slot->state = BLINKINGON_STATE;
-							info(msg_button_on, slot_name(p_slot));
+							info("PCI slot #%s - powering on due to button press.\n", slot_name(p_slot));
 						}
 
-						/* Wait for exclusive access to hardware */
-						mutex_lock(&ctrl->ctrl_lock);
-
 						/* blink green LED and turn off amber */
-						if (PWR_LED(ctrl->ctrlcap)) {
+						if (PWR_LED(ctrl->ctrlcap))
 							p_slot->hpc_ops->green_led_blink(p_slot);
-							/* Wait for the command to complete */
-							wait_for_ctrl_irq (ctrl);
-						}
 
-						if (ATTN_LED(ctrl->ctrlcap)) {
+						if (ATTN_LED(ctrl->ctrlcap))
 							p_slot->hpc_ops->set_attention_status(p_slot, 0);
 
-							/* Wait for the command to complete */
-							wait_for_ctrl_irq (ctrl);
-						}
-
-						/* Done with exclusive hardware access */
-						mutex_unlock(&ctrl->ctrl_lock);
-
 						init_timer(&p_slot->task_event);
 						p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
 						p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
@@ -712,21 +610,11 @@
 				else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
 					if (POWER_CTRL(ctrl->ctrlcap)) {
 						dbg("power fault\n");
-						/* Wait for exclusive access to hardware */
-						mutex_lock(&ctrl->ctrl_lock);
-
-						if (ATTN_LED(ctrl->ctrlcap)) {
+						if (ATTN_LED(ctrl->ctrlcap))
 							p_slot->hpc_ops->set_attention_status(p_slot, 1);
-							wait_for_ctrl_irq (ctrl);
-						}
 
-						if (PWR_LED(ctrl->ctrlcap)) {
+						if (PWR_LED(ctrl->ctrlcap))
 							p_slot->hpc_ops->green_led_off(p_slot);
-							wait_for_ctrl_irq (ctrl);
-						}
-
-						/* Done with exclusive hardware access */
-						mutex_unlock(&ctrl->ctrl_lock);
 					}
 				}
 				/***********SURPRISE REMOVAL********************/
@@ -754,7 +642,6 @@
 	}
 }
 
-
 int pciehp_enable_slot(struct slot *p_slot)
 {
 	u8 getstatus = 0;
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 25d3aad..fbc64aa 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -35,6 +35,7 @@
 #include <linux/timer.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
+#include <linux/time.h>
 
 #include "../pci.h"
 #include "pciehp.h"
@@ -105,34 +106,30 @@
 	ROOTCTRL	=	offsetof(struct ctrl_reg, root_ctrl),
 	ROOTSTATUS	=	offsetof(struct ctrl_reg, root_status),
 };
-static int pcie_cap_base = 0;		/* Base of the PCI Express capability item structure */ 
 
-#define PCIE_CAP_ID(cb)	( cb + PCIECAPID )
-#define NXT_CAP_PTR(cb)	( cb + NXTCAPPTR )
-#define CAP_REG(cb)	( cb + CAPREG )
-#define DEV_CAP(cb)	( cb + DEVCAP )
-#define DEV_CTRL(cb)	( cb + DEVCTRL )
-#define DEV_STATUS(cb)	( cb + DEVSTATUS )
-#define LNK_CAP(cb)	( cb + LNKCAP )
-#define LNK_CTRL(cb)	( cb + LNKCTRL )
-#define LNK_STATUS(cb)	( cb + LNKSTATUS )
-#define SLOT_CAP(cb)	( cb + SLOTCAP )
-#define SLOT_CTRL(cb)	( cb + SLOTCTRL )
-#define SLOT_STATUS(cb)	( cb + SLOTSTATUS )
-#define ROOT_CTRL(cb)	( cb + ROOTCTRL )
-#define ROOT_STATUS(cb)	( cb + ROOTSTATUS )
+static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value)
+{
+	struct pci_dev *dev = ctrl->pci_dev;
+	return pci_read_config_word(dev, ctrl->cap_base + reg, value);
+}
 
-#define hp_register_read_word(pdev, reg , value)		\
-	pci_read_config_word(pdev, reg, &value)
+static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value)
+{
+	struct pci_dev *dev = ctrl->pci_dev;
+	return pci_read_config_dword(dev, ctrl->cap_base + reg, value);
+}
 
-#define hp_register_read_dword(pdev, reg , value)		\
-	pci_read_config_dword(pdev, reg, &value)
- 
-#define hp_register_write_word(pdev, reg , value)		\
-	pci_write_config_word(pdev, reg, value)
+static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value)
+{
+	struct pci_dev *dev = ctrl->pci_dev;
+	return pci_write_config_word(dev, ctrl->cap_base + reg, value);
+}
 
-#define hp_register_dwrite_word(pdev, reg , value)		\
-	pci_write_config_dword(pdev, reg, value)
+static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
+{
+	struct pci_dev *dev = ctrl->pci_dev;
+	return pci_write_config_dword(dev, ctrl->cap_base + reg, value);
+}
 
 /* Field definitions in PCI Express Capabilities Register */
 #define CAP_VER			0x000F
@@ -196,6 +193,7 @@
 #define ATTN_LED_CTRL			0x00C0
 #define PWR_LED_CTRL			0x0300
 #define PWR_CTRL			0x0400
+#define EMI_CTRL			0x0800
 
 /* Attention indicator and Power indicator states */
 #define LED_ON		0x01
@@ -206,6 +204,10 @@
 #define POWER_ON	0
 #define POWER_OFF	0x0400
 
+/* EMI Status defines */
+#define EMI_DISENGAGED	0
+#define EMI_ENGAGED	1
+
 /* Field definitions in Slot Status Register */
 #define ATTN_BUTTN_PRESSED	0x0001
 #define PWR_FAULT_DETECTED	0x0002
@@ -214,114 +216,117 @@
 #define CMD_COMPLETED		0x0010
 #define MRL_STATE		0x0020
 #define PRSN_STATE		0x0040
+#define EMI_STATE		0x0080
+#define EMI_STATUS_BIT		7
 
 static spinlock_t hpc_event_lock;
 
 DEFINE_DBG_BUFFER		/* Debug string buffer for entire HPC defined here */
-static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */
 static int ctlr_seq_num = 0;	/* Controller sequence # */
-static spinlock_t list_lock;
 
-static irqreturn_t pcie_isr(int IRQ, void *dev_id);
-
-static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
+static irqreturn_t pcie_isr(int irq, void *dev_id);
+static void start_int_poll_timer(struct controller *ctrl, int sec);
 
 /* This is the interrupt polling timeout function. */
-static void int_poll_timeout(unsigned long lphp_ctlr)
+static void int_poll_timeout(unsigned long data)
 {
-	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr;
+	struct controller *ctrl = (struct controller *)data;
 
 	DBG_ENTER_ROUTINE
 
-	if ( !php_ctlr ) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return;
-	}
-
 	/* Poll for interrupt events.  regs == NULL => polling */
-	pcie_isr( 0, (void *)php_ctlr );
+	pcie_isr(0, ctrl);
 
-	init_timer(&php_ctlr->int_poll_timer);
-
+	init_timer(&ctrl->poll_timer);
 	if (!pciehp_poll_time)
 		pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
 
-	start_int_poll_timer(php_ctlr, pciehp_poll_time);  
-	
-	return;
+	start_int_poll_timer(ctrl, pciehp_poll_time);
 }
 
 /* This function starts the interrupt polling timer. */
-static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
+static void start_int_poll_timer(struct controller *ctrl, int sec)
 {
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return;
+	/* Clamp to sane value */
+	if ((sec <= 0) || (sec > 60))
+        	sec = 2;
+
+	ctrl->poll_timer.function = &int_poll_timeout;
+	ctrl->poll_timer.data = (unsigned long)ctrl;
+	ctrl->poll_timer.expires = jiffies + sec * HZ;
+	add_timer(&ctrl->poll_timer);
+}
+
+static inline int pcie_wait_cmd(struct controller *ctrl)
+{
+	int retval = 0;
+	unsigned int msecs = pciehp_poll_mode ? 2500 : 1000;
+	unsigned long timeout = msecs_to_jiffies(msecs);
+	int rc;
+
+	rc = wait_event_interruptible_timeout(ctrl->queue,
+					      !ctrl->cmd_busy, timeout);
+	if (!rc)
+		dbg("Command not completed in 1000 msec\n");
+	else if (rc < 0) {
+		retval = -EINTR;
+		info("Command was interrupted by a signal\n");
 	}
 
-	if ( ( seconds <= 0 ) || ( seconds > 60 ) )
-        	seconds = 2;            /* Clamp to sane value */
-
-	php_ctlr->int_poll_timer.function = &int_poll_timeout;
-	php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr;    /* Instance data */
-	php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ;
-	add_timer(&php_ctlr->int_poll_timer);
-
-	return;
+	return retval;
 }
 
 static int pcie_write_cmd(struct slot *slot, u16 cmd)
 {
-	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	struct controller *ctrl = slot->ctrl;
 	int retval = 0;
 	u16 slot_status;
 
 	DBG_ENTER_ROUTINE 
-	
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return -1;
+
+	mutex_lock(&ctrl->ctrl_lock);
+
+	retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+	if (retval) {
+		err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+		goto out;
 	}
 
-	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-	if (retval) {
-			err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
-			return retval;
-		}
-	
 	if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { 
-		/* After 1 sec and CMD_COMPLETED still not set, just proceed forward to issue 
-		   the next command according to spec.  Just print out the error message */
-		dbg("%s : CMD_COMPLETED not clear after 1 sec.\n", __FUNCTION__);
+		/* After 1 sec and CMD_COMPLETED still not set, just
+		   proceed forward to issue the next command according
+		   to spec.  Just print out the error message */
+		dbg("%s: CMD_COMPLETED not clear after 1 sec.\n",
+		    __FUNCTION__);
 	}
 
-	retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), cmd | CMD_CMPL_INTR_ENABLE);
+	ctrl->cmd_busy = 1;
+	retval = pciehp_writew(ctrl, SLOTCTRL, (cmd | CMD_CMPL_INTR_ENABLE));
 	if (retval) {
-		err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
-		return retval;
+		err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
+		goto out;
 	}
 
+	/*
+	 * Wait for command completion.
+	 */
+	retval = pcie_wait_cmd(ctrl);
+ out:
+	mutex_unlock(&ctrl->ctrl_lock);
 	DBG_LEAVE_ROUTINE 
 	return retval;
 }
 
 static int hpc_check_lnk_status(struct controller *ctrl)
 {
-	struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
 	u16 lnk_status;
 	int retval = 0;
 
 	DBG_ENTER_ROUTINE 
 
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return -1;
-	}
-	
-	retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(ctrl->cap_base), lnk_status);
-
+	retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
 	if (retval) {
-		err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+		err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
 		return retval;
 	}
 
@@ -340,26 +345,21 @@
 
 static int hpc_get_attention_status(struct slot *slot, u8 *status)
 {
-	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	struct controller *ctrl = slot->ctrl;
 	u16 slot_ctrl;
 	u8 atten_led_state;
 	int retval = 0;
 	
 	DBG_ENTER_ROUTINE 
 
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return -1;
-	}
-
-	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+	retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
 	if (retval) {
-		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
 		return retval;
 	}
 
-	dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+	dbg("%s: SLOTCTRL %x, value read %x\n",
+	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
 
 	atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6;
 
@@ -385,27 +385,22 @@
 	return 0;
 }
 
-static int hpc_get_power_status(struct slot * slot, u8 *status)
+static int hpc_get_power_status(struct slot *slot, u8 *status)
 {
-	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	struct controller *ctrl = slot->ctrl;
 	u16 slot_ctrl;
 	u8 pwr_state;
 	int	retval = 0;
 	
 	DBG_ENTER_ROUTINE 
 
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return -1;
-	}
-
-	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+	retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
 	if (retval) {
-		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
 		return retval;
 	}
-	dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+	dbg("%s: SLOTCTRL %x value read %x\n",
+	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
 
 	pwr_state = (slot_ctrl & PWR_CTRL) >> 10;
 
@@ -428,21 +423,15 @@
 
 static int hpc_get_latch_status(struct slot *slot, u8 *status)
 {
-	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	struct controller *ctrl = slot->ctrl;
 	u16 slot_status;
 	int retval = 0;
 
 	DBG_ENTER_ROUTINE 
 
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return -1;
-	}
-
-	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
+	retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
 	if (retval) {
-		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
 		return retval;
 	}
 
@@ -454,22 +443,16 @@
 
 static int hpc_get_adapter_status(struct slot *slot, u8 *status)
 {
-	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	struct controller *ctrl = slot->ctrl;
 	u16 slot_status;
 	u8 card_state;
 	int retval = 0;
 
 	DBG_ENTER_ROUTINE 
 
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return -1;
-	}
-
-	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
+	retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
 	if (retval) {
-		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
 		return retval;
 	}
 	card_state = (u8)((slot_status & PRSN_STATE) >> 6);
@@ -479,24 +462,18 @@
 	return 0;
 }
 
-static int hpc_query_power_fault(struct slot * slot)
+static int hpc_query_power_fault(struct slot *slot)
 {
-	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	struct controller *ctrl = slot->ctrl;
 	u16 slot_status;
 	u8 pwr_fault;
 	int retval = 0;
 
 	DBG_ENTER_ROUTINE 
 
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return -1;
-	}
-
-	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
+	retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
 	if (retval) {
-		err("%s : Cannot check for power fault\n", __FUNCTION__);
+		err("%s: Cannot check for power fault\n", __FUNCTION__);
 		return retval;
 	}
 	pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);
@@ -505,28 +482,63 @@
 	return pwr_fault;
 }
 
-static int hpc_set_attention_status(struct slot *slot, u8 value)
+static int hpc_get_emi_status(struct slot *slot, u8 *status)
 {
-	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	struct controller *ctrl = slot->ctrl;
+	u16 slot_status;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE
+
+	retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+	if (retval) {
+		err("%s : Cannot check EMI status\n", __FUNCTION__);
+		return retval;
+	}
+	*status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT;
+
+	DBG_LEAVE_ROUTINE
+	return retval;
+}
+
+static int hpc_toggle_emi(struct slot *slot)
+{
+	struct controller *ctrl = slot->ctrl;
 	u16 slot_cmd = 0;
 	u16 slot_ctrl;
 	int rc = 0;
 
 	DBG_ENTER_ROUTINE
 
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return -1;
-	}
-
-	if (slot->hp_slot >= php_ctlr->num_slots) {
-		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-		return -1;
-	}
-	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+	rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
 	if (rc) {
-		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		err("%s : hp_register_read_word SLOT_CTRL failed\n",
+			__FUNCTION__);
+		return rc;
+	}
+
+	slot_cmd = (slot_ctrl | EMI_CTRL);
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE;
+
+	pcie_write_cmd(slot, slot_cmd);
+	slot->last_emi_toggle = get_seconds();
+	DBG_LEAVE_ROUTINE
+	return rc;
+}
+
+static int hpc_set_attention_status(struct slot *slot, u8 value)
+{
+	struct controller *ctrl = slot->ctrl;
+	u16 slot_cmd = 0;
+	u16 slot_ctrl;
+	int rc = 0;
+
+	DBG_ENTER_ROUTINE
+
+	rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
+	if (rc) {
+		err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
 		return rc;
 	}
 
@@ -547,7 +559,8 @@
 		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
 
 	pcie_write_cmd(slot, slot_cmd);
-	dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+	dbg("%s: SLOTCTRL %x write cmd %x\n",
+	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
 	
 	DBG_LEAVE_ROUTINE
 	return rc;
@@ -556,27 +569,16 @@
 
 static void hpc_set_green_led_on(struct slot *slot)
 {
-	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	struct controller *ctrl = slot->ctrl;
 	u16 slot_cmd;
 	u16 slot_ctrl;
 	int rc = 0;
        	
 	DBG_ENTER_ROUTINE
 
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return ;
-	}
-
-	if (slot->hp_slot >= php_ctlr->num_slots) {
-		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-		return ;
-	}
-
-	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+	rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
 	if (rc) {
-		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
 		return;
 	}
 	slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100;
@@ -585,34 +587,24 @@
 
 	pcie_write_cmd(slot, slot_cmd);
 
-	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+	dbg("%s: SLOTCTRL %x write cmd %x\n",
+	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
 	DBG_LEAVE_ROUTINE
 	return;
 }
 
 static void hpc_set_green_led_off(struct slot *slot)
 {
-	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	struct controller *ctrl = slot->ctrl;
 	u16 slot_cmd;
 	u16 slot_ctrl;
 	int rc = 0;
 
 	DBG_ENTER_ROUTINE
 
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return ;
-	}
-
-	if (slot->hp_slot >= php_ctlr->num_slots) {
-		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-		return ;
-	}
-
-	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+	rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
 	if (rc) {
-		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
 		return;
 	}
 
@@ -621,7 +613,8 @@
 	if (!pciehp_poll_mode)
 		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
 	pcie_write_cmd(slot, slot_cmd);
-	dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+	dbg("%s: SLOTCTRL %x write cmd %x\n",
+	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
 
 	DBG_LEAVE_ROUTINE
 	return;
@@ -629,27 +622,16 @@
 
 static void hpc_set_green_led_blink(struct slot *slot)
 {
-	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	struct controller *ctrl = slot->ctrl;
 	u16 slot_cmd;
 	u16 slot_ctrl;
 	int rc = 0; 
 	
 	DBG_ENTER_ROUTINE
 
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return ;
-	}
-
-	if (slot->hp_slot >= php_ctlr->num_slots) {
-		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-		return ;
-	}
-
-	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+	rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
 	if (rc) {
-		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
 		return;
 	}
 
@@ -659,126 +641,54 @@
 		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
 	pcie_write_cmd(slot, slot_cmd);
 
-	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+	dbg("%s: SLOTCTRL %x write cmd %x\n",
+	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
 	DBG_LEAVE_ROUTINE
 	return;
 }
 
-int pcie_get_ctlr_slot_config(struct controller *ctrl,
-	int *num_ctlr_slots,	/* number of slots in this HPC; only 1 in PCIE  */	
-	int *first_device_num,	/* PCI dev num of the first slot in this PCIE	*/
-	int *physical_slot_num,	/* phy slot num of the first slot in this PCIE	*/
-	u8 *ctrlcap)
-{
-	struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
-	u32 slot_cap;
-	int rc = 0;
-	
-	DBG_ENTER_ROUTINE 
-
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return -1;
-	}
-
-	*first_device_num = 0;
-	*num_ctlr_slots = 1; 
-
-	rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap);
-
-	if (rc) {
-		err("%s : hp_register_read_dword SLOT_CAP failed\n", __FUNCTION__);
-		return -1;
-	}
-	
-	*physical_slot_num = slot_cap >> 19;
-	dbg("%s: PSN %d \n", __FUNCTION__, *physical_slot_num);
-	
-	*ctrlcap = slot_cap & 0x0000007f;
-
-	DBG_LEAVE_ROUTINE 
-	return 0;
-}
-
 static void hpc_release_ctlr(struct controller *ctrl)
 {
-	struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
-	struct php_ctlr_state_s *p, *p_prev;
-
 	DBG_ENTER_ROUTINE 
 
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return ;
-	}
-
-	if (pciehp_poll_mode) {
-	    del_timer(&php_ctlr->int_poll_timer);
-	} else {	
-		if (php_ctlr->irq) {
-			free_irq(php_ctlr->irq, ctrl);
-			php_ctlr->irq = 0;
-		}
-	}
-	if (php_ctlr->pci_dev) 
-		php_ctlr->pci_dev = NULL;
-
-	spin_lock(&list_lock);
-	p = php_ctlr_list_head;
-	p_prev = NULL;
-	while (p) {
-		if (p == php_ctlr) {
-			if (p_prev)
-				p_prev->pnext = p->pnext;
-			else
-				php_ctlr_list_head = p->pnext;
-			break;
-		} else {
-			p_prev = p;
-			p = p->pnext;
-		}
-	}
-	spin_unlock(&list_lock);
-
-	kfree(php_ctlr);
+	if (pciehp_poll_mode)
+		del_timer(&ctrl->poll_timer);
+	else
+		free_irq(ctrl->pci_dev->irq, ctrl);
 
 	DBG_LEAVE_ROUTINE
-			  
 }
 
 static int hpc_power_on_slot(struct slot * slot)
 {
-	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	struct controller *ctrl = slot->ctrl;
 	u16 slot_cmd;
 	u16 slot_ctrl, slot_status;
-
 	int retval = 0;
 
 	DBG_ENTER_ROUTINE 
 
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return -1;
-	}
-
 	dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
-	if (slot->hp_slot >= php_ctlr->num_slots) {
-		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-		return -1;
-	}
 
 	/* Clear sticky power-fault bit from previous power failures */
-	hp_register_read_word(php_ctlr->pci_dev,
-			SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-	slot_status &= PWR_FAULT_DETECTED;
-	if (slot_status)
-		hp_register_write_word(php_ctlr->pci_dev,
-			SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
-	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+	retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
 	if (retval) {
-		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+		return retval;
+	}
+	slot_status &= PWR_FAULT_DETECTED;
+	if (slot_status) {
+		retval = pciehp_writew(ctrl, SLOTSTATUS, slot_status);
+		if (retval) {
+			err("%s: Cannot write to SLOTSTATUS register\n",
+			    __FUNCTION__);
+			return retval;
+		}
+	}
+
+	retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
+	if (retval) {
+		err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
 		return retval;
 	}
 
@@ -798,7 +708,8 @@
 		err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd);
 		return -1;
 	}
-	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+	dbg("%s: SLOTCTRL %x write cmd %x\n",
+	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
 
 	DBG_LEAVE_ROUTINE
 
@@ -807,29 +718,18 @@
 
 static int hpc_power_off_slot(struct slot * slot)
 {
-	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	struct controller *ctrl = slot->ctrl;
 	u16 slot_cmd;
 	u16 slot_ctrl;
-
 	int retval = 0;
 
 	DBG_ENTER_ROUTINE 
 
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return -1;
-	}
-
 	dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
-	slot->hp_slot = 0;
-	if (slot->hp_slot >= php_ctlr->num_slots) {
-		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-		return -1;
-	}
-	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
+	retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
 	if (retval) {
-		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
 		return retval;
 	}
 
@@ -854,47 +754,25 @@
 		err("%s: Write command failed!\n", __FUNCTION__);
 		return -1;
 	}
-	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+	dbg("%s: SLOTCTRL %x write cmd %x\n",
+	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
 
 	DBG_LEAVE_ROUTINE
 
 	return retval;
 }
 
-static irqreturn_t pcie_isr(int IRQ, void *dev_id)
+static irqreturn_t pcie_isr(int irq, void *dev_id)
 {
-	struct controller *ctrl = NULL;
-	struct php_ctlr_state_s *php_ctlr;
-	u8 schedule_flag = 0;
+	struct controller *ctrl = (struct controller *)dev_id;
 	u16 slot_status, intr_detect, intr_loc;
 	u16 temp_word;
 	int hp_slot = 0;	/* only 1 slot per PCI Express port */
 	int rc = 0;
 
-	if (!dev_id)
-		return IRQ_NONE;
-
-	if (!pciehp_poll_mode) { 
-		ctrl = dev_id;
-		php_ctlr = ctrl->hpc_ctlr_handle;
-	} else {
-		php_ctlr = dev_id;
-		ctrl = (struct controller *)php_ctlr->callback_instance_id;
-	}
-
-	if (!ctrl) {
-		dbg("%s: dev_id %p ctlr == NULL\n", __FUNCTION__, (void*) dev_id);
-		return IRQ_NONE;
-	}
-	
-	if (!php_ctlr) {
-		dbg("%s: php_ctlr == NULL\n", __FUNCTION__);
-		return IRQ_NONE;
-	}
-
-	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+	rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
 	if (rc) {
-		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
 		return IRQ_NONE;
 	}
 
@@ -910,33 +788,38 @@
 	dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc);
 	/* Mask Hot-plug Interrupt Enable */
 	if (!pciehp_poll_mode) {
-		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+		rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
 		if (rc) {
-			err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+			err("%s: Cannot read SLOT_CTRL register\n",
+			    __FUNCTION__);
 			return IRQ_NONE;
 		}
 
-		dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
+		dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n",
+		    __FUNCTION__, temp_word);
 		temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
+		rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
+		if (rc) {
+			err("%s: Cannot write to SLOTCTRL register\n",
+			    __FUNCTION__);
+			return IRQ_NONE;
+		}
 
-		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+		rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
 		if (rc) {
-			err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+			err("%s: Cannot read SLOT_STATUS register\n",
+			    __FUNCTION__);
 			return IRQ_NONE;
 		}
-		
-		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
-		if (rc) {
-			err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
-			return IRQ_NONE;
-		}
-		dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status); 
+		dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n",
+		    __FUNCTION__, slot_status);
 		
 		/* Clear command complete interrupt caused by this write */
 		temp_word = 0x1f;
-		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+		rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
 		if (rc) {
-			err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+			err("%s: Cannot write to SLOTSTATUS register\n",
+			    __FUNCTION__);
 			return IRQ_NONE;
 		}
 	}
@@ -945,60 +828,65 @@
 		/* 
 		 * Command Complete Interrupt Pending 
 		 */
+		ctrl->cmd_busy = 0;
 		wake_up_interruptible(&ctrl->queue);
 	}
 
-	if ((php_ctlr->switch_change_callback) && (intr_loc & MRL_SENS_CHANGED))
-		schedule_flag += php_ctlr->switch_change_callback(
-			hp_slot, php_ctlr->callback_instance_id);
-	if ((php_ctlr->attention_button_callback) && (intr_loc & ATTN_BUTTN_PRESSED))
-		schedule_flag += php_ctlr->attention_button_callback(
-			hp_slot, php_ctlr->callback_instance_id);
-	if ((php_ctlr->presence_change_callback) && (intr_loc & PRSN_DETECT_CHANGED))
-		schedule_flag += php_ctlr->presence_change_callback(
-			hp_slot , php_ctlr->callback_instance_id);
-	if ((php_ctlr->power_fault_callback) && (intr_loc & PWR_FAULT_DETECTED))
-		schedule_flag += php_ctlr->power_fault_callback(
-			hp_slot, php_ctlr->callback_instance_id);
+	if (intr_loc & MRL_SENS_CHANGED)
+		pciehp_handle_switch_change(hp_slot, ctrl);
+
+	if (intr_loc & ATTN_BUTTN_PRESSED)
+		pciehp_handle_attention_button(hp_slot, ctrl);
+
+	if (intr_loc & PRSN_DETECT_CHANGED)
+		pciehp_handle_presence_change(hp_slot, ctrl);
+
+	if (intr_loc & PWR_FAULT_DETECTED)
+		pciehp_handle_power_fault(hp_slot, ctrl);
 
 	/* Clear all events after serving them */
 	temp_word = 0x1F;
-	rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+	rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
 	if (rc) {
-		err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+		err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
 		return IRQ_NONE;
 	}
 	/* Unmask Hot-plug Interrupt Enable */
 	if (!pciehp_poll_mode) {
-		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+		rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
 		if (rc) {
-			err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+			err("%s: Cannot read SLOTCTRL register\n",
+			    __FUNCTION__);
 			return IRQ_NONE;
 		}
 
 		dbg("%s: Unmask Hot-plug Interrupt Enable\n", __FUNCTION__);
 		temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
 
-		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+		rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
 		if (rc) {
-			err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+			err("%s: Cannot write to SLOTCTRL register\n",
+			    __FUNCTION__);
 			return IRQ_NONE;
 		}
-	
-		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+
+		rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
 		if (rc) {
-			err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+			err("%s: Cannot read SLOT_STATUS register\n",
+			    __FUNCTION__);
 			return IRQ_NONE;
 		}
 		
 		/* Clear command complete interrupt caused by this write */
 		temp_word = 0x1F;
-		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+		rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
 		if (rc) {
-			err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+			err("%s: Cannot write to SLOTSTATUS failed\n",
+			    __FUNCTION__);
 			return IRQ_NONE;
 		}
-		dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word); 
+		dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n",
+		    __FUNCTION__, temp_word);
 	}
 	
 	return IRQ_HANDLED;
@@ -1006,27 +894,16 @@
 
 static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
 {
-	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	struct controller *ctrl = slot->ctrl;
 	enum pcie_link_speed lnk_speed;
 	u32	lnk_cap;
 	int retval = 0;
 
 	DBG_ENTER_ROUTINE 
 
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return -1;
-	}
-
-	if (slot->hp_slot >= php_ctlr->num_slots) {
-		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-		return -1;
-	}
-
-	retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap);
-
+	retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
 	if (retval) {
-		err("%s : hp_register_read_dword  LNK_CAP failed\n", __FUNCTION__);
+		err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
 		return retval;
 	}
 
@@ -1047,27 +924,16 @@
 
 static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value)
 {
-	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	struct controller *ctrl = slot->ctrl;
 	enum pcie_link_width lnk_wdth;
 	u32	lnk_cap;
 	int retval = 0;
 
 	DBG_ENTER_ROUTINE 
 
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return -1;
-	}
-
-	if (slot->hp_slot >= php_ctlr->num_slots) {
-		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-		return -1;
-	}
-
-	retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap);
-
+	retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
 	if (retval) {
-		err("%s : hp_register_read_dword  LNK_CAP failed\n", __FUNCTION__);
+		err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
 		return retval;
 	}
 
@@ -1109,27 +975,16 @@
 
 static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
 {
-	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	struct controller *ctrl = slot->ctrl;
 	enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN;
 	int retval = 0;
 	u16 lnk_status;
 
 	DBG_ENTER_ROUTINE 
 
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return -1;
-	}
-
-	if (slot->hp_slot >= php_ctlr->num_slots) {
-		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-		return -1;
-	}
-
-	retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status);
-
+	retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
 	if (retval) {
-		err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+		err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
 		return retval;
 	}
 
@@ -1150,27 +1005,16 @@
 
 static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value)
 {
-	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	struct controller *ctrl = slot->ctrl;
 	enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
 	int retval = 0;
 	u16 lnk_status;
 
 	DBG_ENTER_ROUTINE 
 
-	if (!php_ctlr) {
-		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-		return -1;
-	}
-
-	if (slot->hp_slot >= php_ctlr->num_slots) {
-		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-		return -1;
-	}
-
-	retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status);
-
+	retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
 	if (retval) {
-		err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+		err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
 		return retval;
 	}
 	
@@ -1218,6 +1062,8 @@
 	.get_attention_status		= hpc_get_attention_status,
 	.get_latch_status		= hpc_get_latch_status,
 	.get_adapter_status		= hpc_get_adapter_status,
+	.get_emi_status			= hpc_get_emi_status,
+	.toggle_emi			= hpc_toggle_emi,
 
 	.get_max_bus_speed		= hpc_get_max_lnk_speed,
 	.get_cur_bus_speed		= hpc_get_cur_lnk_speed,
@@ -1305,38 +1151,24 @@
 
 int pcie_init(struct controller * ctrl, struct pcie_device *dev)
 {
-	struct php_ctlr_state_s *php_ctlr, *p;
-	void *instance_id = ctrl;
 	int rc;
 	static int first = 1;
 	u16 temp_word;
 	u16 cap_reg;
 	u16 intr_enable = 0;
 	u32 slot_cap;
-	int cap_base, saved_cap_base;
+	int cap_base;
 	u16 slot_status, slot_ctrl;
 	struct pci_dev *pdev;
 
 	DBG_ENTER_ROUTINE
 	
-	spin_lock_init(&list_lock);	
-	php_ctlr = kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
-
-	if (!php_ctlr) {	/* allocate controller state data */
-		err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
-		goto abort;
-	}
-
-	memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s));
-	
 	pdev = dev->port;
-	php_ctlr->pci_dev = pdev;	/* save pci_dev in context */
+	ctrl->pci_dev = pdev;	/* save pci_dev in context */
 
 	dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n",
 			__FUNCTION__, pdev->vendor, pdev->device);
 
-	saved_cap_base = pcie_cap_base;
-
 	if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) {
 		dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__);
 		goto abort_free_ctlr;
@@ -1344,14 +1176,15 @@
 
 	ctrl->cap_base = cap_base;
 
-	dbg("%s: pcie_cap_base %x\n", __FUNCTION__, pcie_cap_base);
+	dbg("%s: pcie_cap_base %x\n", __FUNCTION__, cap_base);
 
-	rc = hp_register_read_word(pdev, CAP_REG(ctrl->cap_base), cap_reg);
+	rc = pciehp_readw(ctrl, CAPREG, &cap_reg);
 	if (rc) {
-		err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
+		err("%s: Cannot read CAPREG register\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
-	dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG(ctrl->cap_base), cap_reg);
+	dbg("%s: CAPREG offset %x cap_reg %x\n",
+	    __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg);
 
 	if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040)
 		&& ((cap_reg & DEV_PORT_TYPE) != 0x0060))) {
@@ -1359,31 +1192,34 @@
 		goto abort_free_ctlr;
 	}
 
-	rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap);
+	rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
 	if (rc) {
-		err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
+		err("%s: Cannot read SLOTCAP register\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
-	dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP(ctrl->cap_base), slot_cap);
+	dbg("%s: SLOTCAP offset %x slot_cap %x\n",
+	    __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap);
 
 	if (!(slot_cap & HP_CAP)) {
 		dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
 	/* For debugging purpose */
-	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+	rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
 	if (rc) {
-		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
-	dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), slot_status);
+	dbg("%s: SLOTSTATUS offset %x slot_status %x\n",
+	    __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status);
 
-	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), slot_ctrl);
+	rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
 	if (rc) {
-		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
-	dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), slot_ctrl);
+	dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
+	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
 
 	if (first) {
 		spin_lock_init(&hpc_event_lock);
@@ -1405,69 +1241,64 @@
 	/* setup wait queue */
 	init_waitqueue_head(&ctrl->queue);
 
-	/* find the IRQ */
-	php_ctlr->irq = dev->irq;
-
-	/* Save interrupt callback info */
-	php_ctlr->attention_button_callback = pciehp_handle_attention_button;
-	php_ctlr->switch_change_callback = pciehp_handle_switch_change;
-	php_ctlr->presence_change_callback = pciehp_handle_presence_change;
-	php_ctlr->power_fault_callback = pciehp_handle_power_fault;
-	php_ctlr->callback_instance_id = instance_id;
-
 	/* return PCI Controller Info */
-	php_ctlr->slot_device_offset = 0;
-	php_ctlr->num_slots = 1;
+	ctrl->slot_device_offset = 0;
+	ctrl->num_slots = 1;
+	ctrl->first_slot = slot_cap >> 19;
+	ctrl->ctrlcap = slot_cap & 0x0000007f;
 
 	/* Mask Hot-plug Interrupt Enable */
-	rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+	rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
 	if (rc) {
-		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
 
-	dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), temp_word);
+	dbg("%s: SLOTCTRL %x value read %x\n",
+	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
 	temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
 
-	rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+	rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
 	if (rc) {
-		err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+		err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
 
-	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+	rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
 	if (rc) {
-		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
 
 	temp_word = 0x1F; /* Clear all events */
-	rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+	rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
 	if (rc) {
-		err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+		err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
 
-	if (pciehp_poll_mode)  {/* Install interrupt polling code */
-		/* Install and start the interrupt polling timer */
-		init_timer(&php_ctlr->int_poll_timer);
-		start_int_poll_timer( php_ctlr, 10 );   /* start with 10 second delay */
+	if (pciehp_poll_mode) {
+		/* Install interrupt polling timer. Start with 10 sec delay */
+		init_timer(&ctrl->poll_timer);
+		start_int_poll_timer(ctrl, 10);
 	} else {
 		/* Installs the interrupt handler */
-		rc = request_irq(php_ctlr->irq, pcie_isr, IRQF_SHARED, MY_NAME, (void *) ctrl);
-		dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
+		rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED,
+				 MY_NAME, (void *)ctrl);
+		dbg("%s: request_irq %d for hpc%d (returns %d)\n",
+		    __FUNCTION__, ctrl->pci_dev->irq, ctlr_seq_num, rc);
 		if (rc) {
-			err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
+			err("Can't get irq %d for the hotplug controller\n",
+			    ctrl->pci_dev->irq);
 			goto abort_free_ctlr;
 		}
 	}
-
 	dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number,
 		PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq);
 
-	rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+	rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
 	if (rc) {
-		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
 		goto abort_free_irq;
 	}
 
@@ -1491,21 +1322,21 @@
 	}
 
 	/* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
-	rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+	rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
 	if (rc) {
-		err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+		err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
 		goto abort_free_irq;
 	}
-	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+	rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
 	if (rc) {
-		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
 		goto abort_disable_intr;
 	}
 	
 	temp_word =  0x1F; /* Clear all events */
-	rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+	rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
 	if (rc) {
-		err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+		err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
 		goto abort_disable_intr;
 	}
 	
@@ -1518,24 +1349,7 @@
 			goto abort_disable_intr;
 	}
 
-	/*  Add this HPC instance into the HPC list */
-	spin_lock(&list_lock);
-	if (php_ctlr_list_head == 0) {
-		php_ctlr_list_head = php_ctlr;
-		p = php_ctlr_list_head;
-		p->pnext = NULL;
-	} else {
-		p = php_ctlr_list_head;
-
-		while (p->pnext)
-			p = p->pnext;
-
-		p->pnext = php_ctlr;
-	}
-	spin_unlock(&list_lock);
-
 	ctlr_seq_num++;
-	ctrl->hpc_ctlr_handle = php_ctlr;
 	ctrl->hpc_ops = &pciehp_hpc_ops;
 
 	DBG_LEAVE_ROUTINE
@@ -1543,24 +1357,21 @@
 
 	/* We end up here for the many possible ways to fail this API.  */
 abort_disable_intr:
-	rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+	rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
 	if (!rc) {
 		temp_word &= ~(intr_enable | HP_INTR_ENABLE);
-		rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+		rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
 	}
 	if (rc)
 		err("%s : disabling interrupts failed\n", __FUNCTION__);
 
 abort_free_irq:
 	if (pciehp_poll_mode)
-		del_timer_sync(&php_ctlr->int_poll_timer);
+		del_timer_sync(&ctrl->poll_timer);
 	else
-		free_irq(php_ctlr->irq, ctrl);
+		free_irq(ctrl->pci_dev->irq, ctrl);
 
 abort_free_ctlr:
-	pcie_cap_base = saved_cap_base;
-	kfree(php_ctlr);
-abort:
 	DBG_LEAVE_ROUTINE
 	return -1;
 }
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
index 5d188c5..78cf071 100644
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -28,6 +28,8 @@
 #include <asm/sn/sn_feature_sets.h>
 #include <asm/sn/sn_sal.h>
 #include <asm/sn/types.h>
+#include <linux/acpi.h>
+#include <asm/sn/acpi.h>
 
 #include "../pci.h"
 
@@ -35,14 +37,17 @@
 MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)");
 MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver");
 
-#define PCIIO_ASIC_TYPE_TIOCA		4
+
+/* SAL call error codes. Keep in sync with prom header io/include/pcibr.h */
 #define PCI_SLOT_ALREADY_UP		2	/* slot already up */
 #define PCI_SLOT_ALREADY_DOWN		3	/* slot already down */
 #define PCI_L1_ERR			7	/* L1 console command error */
 #define PCI_EMPTY_33MHZ			15	/* empty 33 MHz bus */
+
+
+#define PCIIO_ASIC_TYPE_TIOCA		4
 #define PCI_L1_QSIZE			128	/* our L1 message buffer size */
 #define SN_MAX_HP_SLOTS			32	/* max hotplug slots */
-#define SGI_HOTPLUG_PROM_REV		0x0430	/* Min. required PROM version */
 #define SN_SLOT_NAME_SIZE		33	/* size of name string */
 
 /* internal list head */
@@ -227,7 +232,7 @@
 }
 
 static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
-			  int device_num)
+			  int device_num, char **ssdt)
 {
 	struct slot *slot = bss_hotplug_slot->private;
 	struct pcibus_info *pcibus_info;
@@ -240,7 +245,8 @@
 	 * Power-on and initialize the slot in the SN
 	 * PCI infrastructure.
 	 */
-	rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp);
+	rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp, ssdt);
+
 
 	if (rc == PCI_SLOT_ALREADY_UP) {
 		dev_dbg(slot->pci_bus->self, "is already active\n");
@@ -335,6 +341,7 @@
 	int func, num_funcs;
 	int new_ppb = 0;
 	int rc;
+	char *ssdt = NULL;
 	void pcibios_fixup_device_resources(struct pci_dev *);
 
 	/* Serialize the Linux PCI infrastructure */
@@ -342,14 +349,29 @@
 
 	/*
 	 * Power-on and initialize the slot in the SN
-	 * PCI infrastructure.
+	 * PCI infrastructure. Also, retrieve the ACPI SSDT
+	 * table for the slot (if ACPI capable PROM).
 	 */
-	rc = sn_slot_enable(bss_hotplug_slot, slot->device_num);
+	rc = sn_slot_enable(bss_hotplug_slot, slot->device_num, &ssdt);
 	if (rc) {
 		mutex_unlock(&sn_hotplug_mutex);
 		return rc;
 	}
 
+	if (ssdt)
+		ssdt = __va(ssdt);
+	/* Add the new SSDT for the slot to the ACPI namespace */
+	if (SN_ACPI_BASE_SUPPORT() && ssdt) {
+		acpi_status ret;
+
+		ret = acpi_load_table((struct acpi_table_header *)ssdt);
+		if (ACPI_FAILURE(ret)) {
+			printk(KERN_ERR "%s: acpi_load_table failed (0x%x)\n",
+			       __FUNCTION__, ret);
+			/* try to continue on */
+		}
+	}
+
 	num_funcs = pci_scan_slot(slot->pci_bus,
 				  PCI_DEVFN(slot->device_num + 1, 0));
 	if (!num_funcs) {
@@ -374,7 +396,10 @@
 			 * pdi_host_pcidev_info).
 			 */
 			pcibios_fixup_device_resources(dev);
-			sn_pci_fixup_slot(dev);
+			if (SN_ACPI_BASE_SUPPORT())
+				sn_acpi_slot_fixup(dev);
+			else
+				sn_io_slot_fixup(dev);
 			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
 				unsigned char sec_bus;
 				pci_read_config_byte(dev, PCI_SECONDARY_BUS,
@@ -388,6 +413,63 @@
 		}
 	}
 
+	/*
+	 * Add the slot's devices to the ACPI infrastructure */
+	if (SN_ACPI_BASE_SUPPORT() && ssdt) {
+		unsigned long adr;
+		struct acpi_device *pdevice;
+		struct acpi_device *device;
+		acpi_handle phandle;
+		acpi_handle chandle = NULL;
+		acpi_handle rethandle;
+		acpi_status ret;
+
+		phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;
+
+		if (acpi_bus_get_device(phandle, &pdevice)) {
+			dev_dbg(slot->pci_bus->self,
+				"no parent device, assuming NULL\n");
+			pdevice = NULL;
+		}
+
+		/*
+		 * Walk the rootbus node's immediate children looking for
+		 * the slot's device node(s). There can be more than
+		 * one for multifunction devices.
+		 */
+		for (;;) {
+			rethandle = NULL;
+			ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
+						   phandle, chandle,
+						   &rethandle);
+
+			if (ret == AE_NOT_FOUND || rethandle == NULL)
+				break;
+
+			chandle = rethandle;
+
+			ret = acpi_evaluate_integer(chandle, METHOD_NAME__ADR,
+						    NULL, &adr);
+
+			if (ACPI_SUCCESS(ret) &&
+			    (adr>>16) == (slot->device_num + 1)) {
+
+				ret = acpi_bus_add(&device, pdevice, chandle,
+						   ACPI_BUS_TYPE_DEVICE);
+				if (ACPI_FAILURE(ret)) {
+					printk(KERN_ERR "%s: acpi_bus_add "
+					       "failed (0x%x) for slot %d "
+					       "func %d\n", __FUNCTION__,
+					       ret, (int)(adr>>16),
+					       (int)(adr&0xffff));
+					/* try to continue on */
+				} else {
+					acpi_bus_start(device);
+				}
+			}
+		}
+	}
+
 	/* Call the driver for the new device */
 	pci_bus_add_devices(slot->pci_bus);
 	/* Call the drivers for the new devices subordinate to PPB */
@@ -412,6 +494,7 @@
 	struct pci_dev *dev;
 	int func;
 	int rc;
+	acpi_owner_id ssdt_id = 0;
 
 	/* Acquire update access to the bus */
 	mutex_lock(&sn_hotplug_mutex);
@@ -422,6 +505,52 @@
 	if (rc)
 		goto leaving;
 
+	/* free the ACPI resources for the slot */
+	if (SN_ACPI_BASE_SUPPORT() &&
+            PCI_CONTROLLER(slot->pci_bus)->acpi_handle) {
+		unsigned long adr;
+		struct acpi_device *device;
+		acpi_handle phandle;
+		acpi_handle chandle = NULL;
+		acpi_handle rethandle;
+		acpi_status ret;
+
+		/* Get the rootbus node pointer */
+		phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;
+
+		/*
+		 * Walk the rootbus node's immediate children looking for
+		 * the slot's device node(s). There can be more than
+		 * one for multifunction devices.
+		 */
+		for (;;) {
+			rethandle = NULL;
+			ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
+						   phandle, chandle,
+						   &rethandle);
+
+			if (ret == AE_NOT_FOUND || rethandle == NULL)
+				break;
+
+			chandle = rethandle;
+
+			ret = acpi_evaluate_integer(chandle,
+						    METHOD_NAME__ADR,
+						    NULL, &adr);
+			if (ACPI_SUCCESS(ret) &&
+			    (adr>>16) == (slot->device_num + 1)) {
+				/* retain the owner id */
+				acpi_get_id(chandle, &ssdt_id);
+
+				ret = acpi_bus_get_device(chandle,
+							  &device);
+				if (ACPI_SUCCESS(ret))
+					acpi_bus_trim(device, 1);
+			}
+		}
+
+	}
+
 	/* Free the SN resources assigned to the Linux device.*/
 	for (func = 0; func < 8;  func++) {
 		dev = pci_get_slot(slot->pci_bus,
@@ -434,6 +563,18 @@
 		}
 	}
 
+	/* Remove the SSDT for the slot from the ACPI namespace */
+	if (SN_ACPI_BASE_SUPPORT() && ssdt_id) {
+		acpi_status ret;
+		ret = acpi_unload_table_id(ssdt_id);
+		if (ACPI_FAILURE(ret)) {
+			printk(KERN_ERR "%s: acpi_unload_table_id "
+			       "failed (0x%x) for id %d\n",
+			       __FUNCTION__, ret, ssdt_id);
+			/* try to continue on */
+		}
+	}
+
 	/* free the collected sysdata pointers */
 	sn_bus_free_sysdata();
 
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index 3ca6a4f..01d31a1 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -106,7 +106,7 @@
 };
 
 /* Define AMD SHPC ID  */
-#define PCI_DEVICE_ID_AMD_GOLAM_7450	0x7450 
+#define PCI_DEVICE_ID_AMD_GOLAM_7450	0x7450
 #define PCI_DEVICE_ID_AMD_POGO_7458	0x7458
 
 /* AMD PCIX bridge registers */
@@ -221,7 +221,7 @@
 };
 
 static inline struct slot *get_slot(struct hotplug_slot *hotplug_slot)
-{ 
+{
 	return hotplug_slot->private;
 }
 
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index 590cd3c..5f4bc08 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -401,10 +401,6 @@
 {
 	int retval = 0;
 
-#ifdef CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
-	shpchp_poll_mode = 1;
-#endif
-
 	retval = pci_register_driver(&shpc_driver);
 	dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval);
 	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
index 6bb8473..b746bd2 100644
--- a/drivers/pci/hotplug/shpchp_ctrl.c
+++ b/drivers/pci/hotplug/shpchp_ctrl.c
@@ -64,7 +64,7 @@
 
 	/* Attention Button Change */
 	dbg("shpchp:  Attention button interrupt received.\n");
-	
+
 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
 
@@ -128,7 +128,7 @@
 
 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 
-	/* 
+	/*
 	 * Save the presence state
 	 */
 	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
@@ -184,12 +184,12 @@
 	return 1;
 }
 
-/* The following routines constitute the bulk of the 
+/* The following routines constitute the bulk of the
    hotplug controller logic
  */
 static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
 		enum pci_bus_speed speed)
-{ 
+{
 	int rc = 0;
 
 	dbg("%s: change to speed %d\n", __FUNCTION__, speed);
@@ -204,7 +204,7 @@
 static int fix_bus_speed(struct controller *ctrl, struct slot *pslot,
 		u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp,
 		enum pci_bus_speed msp)
-{ 
+{
 	int rc = 0;
 
 	/*
@@ -257,23 +257,23 @@
 		err("%s: Failed to power on slot\n", __FUNCTION__);
 		return -1;
 	}
-	
+
 	if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
 		if (slots_not_empty)
 			return WRONG_BUS_FREQUENCY;
-		
+
 		if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) {
 			err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
 			return WRONG_BUS_FREQUENCY;
 		}
-		
+
 		/* turn on board, blink green LED, turn off Amber LED */
 		if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
 			err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
 			return rc;
 		}
 	}
- 
+
 	rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp);
 	if (rc) {
 		err("%s: Can't get adapter speed or bus mode mismatch\n",
@@ -378,7 +378,7 @@
 		err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
 		return rc;
 	}
-	
+
 	rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
 	if (rc) {
 		err("%s: Issue of Set Attention command failed\n", __FUNCTION__);
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
index b7bede4..5183a45 100644
--- a/drivers/pci/hotplug/shpchp_hpc.c
+++ b/drivers/pci/hotplug/shpchp_hpc.c
@@ -35,38 +35,6 @@
 
 #include "shpchp.h"
 
-#ifdef DEBUG
-#define DBG_K_TRACE_ENTRY      ((unsigned int)0x00000001)	/* On function entry */
-#define DBG_K_TRACE_EXIT       ((unsigned int)0x00000002)	/* On function exit */
-#define DBG_K_INFO             ((unsigned int)0x00000004)	/* Info messages */
-#define DBG_K_ERROR            ((unsigned int)0x00000008)	/* Error messages */
-#define DBG_K_TRACE            (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
-#define DBG_K_STANDARD         (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
-/* Redefine this flagword to set debug level */
-#define DEBUG_LEVEL            DBG_K_STANDARD
-
-#define DEFINE_DBG_BUFFER     char __dbg_str_buf[256];
-
-#define DBG_PRINT( dbg_flags, args... )              \
-	do {                                             \
-	  if ( DEBUG_LEVEL & ( dbg_flags ) )             \
-	  {                                              \
-	    int len;                                     \
-	    len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
-		  __FILE__, __LINE__, __FUNCTION__ );    \
-	    sprintf( __dbg_str_buf + len, args );        \
-	    printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
-	  }                                              \
-	} while (0)
-
-#define DBG_ENTER_ROUTINE	DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
-#define DBG_LEAVE_ROUTINE	DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
-#else
-#define DEFINE_DBG_BUFFER
-#define DBG_ENTER_ROUTINE
-#define DBG_LEAVE_ROUTINE
-#endif				/* DEBUG */
-
 /* Slot Available Register I field definition */
 #define SLOT_33MHZ		0x0000001f
 #define SLOT_66MHZ_PCIX		0x00001f00
@@ -211,7 +179,6 @@
 #define SLOT_EVENT_LATCH	0x2
 #define SLOT_SERR_INT_MASK	0x3
 
-DEFINE_DBG_BUFFER		/* Debug string buffer for entire HPC defined here */
 static atomic_t shpchp_num_controllers = ATOMIC_INIT(0);
 
 static irqreturn_t shpc_isr(int irq, void *dev_id);
@@ -268,8 +235,6 @@
 {
 	struct controller *ctrl = (struct controller *)data;
 
-	DBG_ENTER_ROUTINE
-
 	/* Poll for interrupt events.  regs == NULL => polling */
 	shpc_isr(0, ctrl);
 
@@ -278,8 +243,6 @@
 		shpchp_poll_time = 2; /* default polling interval is 2 sec */
 
 	start_int_poll_timer(ctrl, shpchp_poll_time);
-
-	DBG_LEAVE_ROUTINE
 }
 
 /*
@@ -353,8 +316,6 @@
 	int retval = 0;
 	u16 temp_word;
 
-	DBG_ENTER_ROUTINE 
-
 	mutex_lock(&slot->ctrl->cmd_lock);
 
 	if (!shpc_poll_ctrl_busy(ctrl)) {
@@ -368,9 +329,9 @@
 	++t_slot;
 	temp_word =  (t_slot << 8) | (cmd & 0xFF);
 	dbg("%s: t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd);
-	
+
 	/* To make sure the Controller Busy bit is 0 before we send out the
-	 * command. 
+	 * command.
 	 */
 	shpc_writew(ctrl, CMD, temp_word);
 
@@ -389,20 +350,14 @@
 	}
  out:
 	mutex_unlock(&slot->ctrl->cmd_lock);
-
-	DBG_LEAVE_ROUTINE 
 	return retval;
 }
 
 static int hpc_check_cmd_status(struct controller *ctrl)
 {
-	u16 cmd_status;
 	int retval = 0;
+	u16 cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F;
 
-	DBG_ENTER_ROUTINE 
-
-	cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F;
-	
 	switch (cmd_status >> 1) {
 	case 0:
 		retval = 0;
@@ -423,7 +378,6 @@
 		retval = cmd_status;
 	}
 
-	DBG_LEAVE_ROUTINE 
 	return retval;
 }
 
@@ -431,13 +385,8 @@
 static int hpc_get_attention_status(struct slot *slot, u8 *status)
 {
 	struct controller *ctrl = slot->ctrl;
-	u32 slot_reg;
-	u8 state;
-	
-	DBG_ENTER_ROUTINE 
-
-	slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
-	state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT;
+	u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+	u8 state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT;
 
 	switch (state) {
 	case ATN_LED_STATE_ON:
@@ -454,20 +403,14 @@
 		break;
 	}
 
-	DBG_LEAVE_ROUTINE 
 	return 0;
 }
 
 static int hpc_get_power_status(struct slot * slot, u8 *status)
 {
 	struct controller *ctrl = slot->ctrl;
-	u32 slot_reg;
-	u8 state;
-	
-	DBG_ENTER_ROUTINE 
-
-	slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
-	state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT;
+	u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+	u8 state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT;
 
 	switch (state) {
 	case SLOT_STATE_PWRONLY:
@@ -484,7 +427,6 @@
 		break;
 	}
 
-	DBG_LEAVE_ROUTINE 
 	return 0;
 }
 
@@ -492,30 +434,21 @@
 static int hpc_get_latch_status(struct slot *slot, u8 *status)
 {
 	struct controller *ctrl = slot->ctrl;
-	u32 slot_reg;
+	u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
 
-	DBG_ENTER_ROUTINE 
-
-	slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
 	*status = !!(slot_reg & MRL_SENSOR);	/* 0 -> close; 1 -> open */
 
-	DBG_LEAVE_ROUTINE 
 	return 0;
 }
 
 static int hpc_get_adapter_status(struct slot *slot, u8 *status)
 {
 	struct controller *ctrl = slot->ctrl;
-	u32 slot_reg;
-	u8 state;
+	u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+	u8 state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT;
 
-	DBG_ENTER_ROUTINE 
-
-	slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
-	state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT;
 	*status = (state != 0x3) ? 1 : 0;
 
-	DBG_LEAVE_ROUTINE 
 	return 0;
 }
 
@@ -523,11 +456,8 @@
 {
 	struct controller *ctrl = slot->ctrl;
 
-	DBG_ENTER_ROUTINE 
-
 	*prog_int = shpc_readb(ctrl, PROG_INTERFACE);
 
-	DBG_LEAVE_ROUTINE 
 	return 0;
 }
 
@@ -539,8 +469,6 @@
 	u8 m66_cap  = !!(slot_reg & MHZ66_CAP);
 	u8 pi, pcix_cap;
 
-	DBG_ENTER_ROUTINE 
-
 	if ((retval = hpc_get_prog_int(slot, &pi)))
 		return retval;
 
@@ -582,21 +510,15 @@
 	}
 
 	dbg("Adapter speed = %d\n", *value);
-	DBG_LEAVE_ROUTINE 
 	return retval;
 }
 
 static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
 {
-	struct controller *ctrl = slot->ctrl;
-	u16 sec_bus_status;
-	u8 pi;
 	int retval = 0;
-
-	DBG_ENTER_ROUTINE 
-
-	pi = shpc_readb(ctrl, PROG_INTERFACE);
-	sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG);
+	struct controller *ctrl = slot->ctrl;
+	u16 sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG);
+	u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
 
 	if (pi == 2) {
 		*mode = (sec_bus_status & 0x0100) >> 8;
@@ -605,21 +527,14 @@
 	}
 
 	dbg("Mode 1 ECC cap = %d\n", *mode);
-	
-	DBG_LEAVE_ROUTINE 
 	return retval;
 }
 
 static int hpc_query_power_fault(struct slot * slot)
 {
 	struct controller *ctrl = slot->ctrl;
-	u32 slot_reg;
+	u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
 
-	DBG_ENTER_ROUTINE 
-
-	slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
-
-	DBG_LEAVE_ROUTINE
 	/* Note: Logic 0 => fault */
 	return !(slot_reg & POWER_FAULT);
 }
@@ -629,7 +544,7 @@
 	u8 slot_cmd = 0;
 
 	switch (value) {
-		case 0 :	
+		case 0 :
 			slot_cmd = SET_ATTN_OFF;	/* OFF */
 			break;
 		case 1:
@@ -666,8 +581,6 @@
 	int i;
 	u32 slot_reg, serr_int;
 
-	DBG_ENTER_ROUTINE 
-
 	/*
 	 * Mask event interrupts and SERRs of all slots
 	 */
@@ -708,61 +621,43 @@
 	 */
 	if (atomic_dec_and_test(&shpchp_num_controllers))
 		destroy_workqueue(shpchp_wq);
-
-	DBG_LEAVE_ROUTINE
 }
 
 static int hpc_power_on_slot(struct slot * slot)
 {
 	int retval;
 
-	DBG_ENTER_ROUTINE 
-
 	retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_PWR);
-	if (retval) {
+	if (retval)
 		err("%s: Write command failed!\n", __FUNCTION__);
-		return retval;
-	}
 
-	DBG_LEAVE_ROUTINE
-
-	return 0;
+	return retval;
 }
 
 static int hpc_slot_enable(struct slot * slot)
 {
 	int retval;
 
-	DBG_ENTER_ROUTINE 
-
 	/* Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */
 	retval = shpc_write_cmd(slot, slot->hp_slot,
 			SET_SLOT_ENABLE | SET_PWR_BLINK | SET_ATTN_OFF);
-	if (retval) {
+	if (retval)
 		err("%s: Write command failed!\n", __FUNCTION__);
-		return retval;
-	}
 
-	DBG_LEAVE_ROUTINE
-	return 0;
+	return retval;
 }
 
 static int hpc_slot_disable(struct slot * slot)
 {
 	int retval;
 
-	DBG_ENTER_ROUTINE 
-
 	/* Slot - Disable, Power Indicator - Off, Attention Indicator - On */
 	retval = shpc_write_cmd(slot, slot->hp_slot,
 			SET_SLOT_DISABLE | SET_PWR_OFF | SET_ATTN_ON);
-	if (retval) {
+	if (retval)
 		err("%s: Write command failed!\n", __FUNCTION__);
-		return retval;
-	}
 
-	DBG_LEAVE_ROUTINE
-	return 0;
+	return retval;
 }
 
 static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
@@ -771,8 +666,6 @@
 	struct controller *ctrl = slot->ctrl;
 	u8 pi, cmd;
 
-	DBG_ENTER_ROUTINE 
-
 	pi = shpc_readb(ctrl, PROG_INTERFACE);
 	if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX))
 		return -EINVAL;
@@ -828,7 +721,6 @@
 	if (retval)
 		err("%s: Write command failed!\n", __FUNCTION__);
 
-	DBG_LEAVE_ROUTINE
 	return retval;
 }
 
@@ -843,7 +735,7 @@
 	if (!intr_loc)
 		return IRQ_NONE;
 
-	dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); 
+	dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc);
 
 	if(!shpchp_poll_mode) {
 		/*
@@ -856,12 +748,12 @@
 		shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
 
 		intr_loc2 = shpc_readl(ctrl, INTR_LOC);
-		dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); 
+		dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2);
 	}
 
 	if (intr_loc & CMD_INTR_PENDING) {
-		/* 
-		 * Command Complete Interrupt Pending 
+		/*
+		 * Command Complete Interrupt Pending
 		 * RO only - clear by writing 1 to the Command Completion
 		 * Detect bit in Controller SERR-INT register
 		 */
@@ -875,7 +767,7 @@
 	if (!(intr_loc & ~CMD_INTR_PENDING))
 		goto out;
 
-	for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { 
+	for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {
 		/* To find out which slot has interrupt pending */
 		if (!(intr_loc & SLOT_INTR_PENDING(hp_slot)))
 			continue;
@@ -907,7 +799,7 @@
 		serr_int &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK);
 		shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
 	}
-	
+
 	return IRQ_HANDLED;
 }
 
@@ -920,8 +812,6 @@
 	u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1);
 	u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2);
 
-	DBG_ENTER_ROUTINE 
-
 	if (pi == 2) {
 		if (slot_avail2 & SLOT_133MHZ_PCIX_533)
 			bus_speed = PCI_SPEED_133MHz_PCIX_533;
@@ -954,7 +844,7 @@
 
 	*value = bus_speed;
 	dbg("Max bus speed = %d\n", bus_speed);
-	DBG_LEAVE_ROUTINE 
+
 	return retval;
 }
 
@@ -967,8 +857,6 @@
 	u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
 	u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7);
 
-	DBG_ENTER_ROUTINE 
-
 	if ((pi == 1) && (speed_mode > 4)) {
 		*value = PCI_SPEED_UNKNOWN;
 		return -ENODEV;
@@ -1024,7 +912,6 @@
 	}
 
 	dbg("Current bus speed = %d\n", bus_speed);
-	DBG_LEAVE_ROUTINE 
 	return retval;
 }
 
@@ -1032,7 +919,7 @@
 	.power_on_slot			= hpc_power_on_slot,
 	.slot_enable			= hpc_slot_enable,
 	.slot_disable			= hpc_slot_disable,
-	.set_bus_speed_mode		= hpc_set_bus_speed_mode,	  
+	.set_bus_speed_mode		= hpc_set_bus_speed_mode,
 	.set_attention_status	= hpc_set_attention_status,
 	.get_power_status		= hpc_get_power_status,
 	.get_attention_status	= hpc_get_attention_status,
@@ -1049,7 +936,7 @@
 	.green_led_on			= hpc_set_green_led_on,
 	.green_led_off			= hpc_set_green_led_off,
 	.green_led_blink		= hpc_set_green_led_blink,
-	
+
 	.release_ctlr			= hpc_release_ctlr,
 };
 
@@ -1061,8 +948,6 @@
 	u32 tempdword, slot_reg, slot_config;
 	u8 i;
 
-	DBG_ENTER_ROUTINE
-
 	ctrl->pci_dev = pdev;  /* pci_dev of the P2P bridge */
 
 	if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device ==
@@ -1108,9 +993,9 @@
 		ctrl->mmio_size = 0x24 + 0x4 * num_slots;
 	}
 
-	info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, 
+	info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor,
 		pdev->subsystem_device);
-	
+
 	rc = pci_enable_device(pdev);
 	if (rc) {
 		err("%s: pci_enable_device failed\n", __FUNCTION__);
@@ -1172,7 +1057,7 @@
 		slot_reg &= ~SLOT_REG_RSVDZ_MASK;
 		shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg);
 	}
-	
+
 	if (shpchp_poll_mode) {
 		/* Install interrupt polling timer. Start with 10 sec delay */
 		init_timer(&ctrl->poll_timer);
@@ -1184,7 +1069,7 @@
 			info("Can't get msi for the hotplug controller\n");
 			info("Use INTx for the hotplug controller\n");
 		}
-		
+
 		rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED,
 				 MY_NAME, (void *)ctrl);
 		dbg("%s: request_irq %d for hpc%d (returns %d)\n",
@@ -1235,13 +1120,11 @@
 		dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
 	}
 
-	DBG_LEAVE_ROUTINE
 	return 0;
 
 	/* We end up here for the many possible ways to fail this API.  */
 abort_iounmap:
 	iounmap(ctrl->creg);
 abort:
-	DBG_LEAVE_ROUTINE
 	return rc;
 }
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index ed3f7e1..68555c1 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -24,8 +24,6 @@
 #include "pci.h"
 #include "msi.h"
 
-static DEFINE_SPINLOCK(msi_lock);
-static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
 static struct kmem_cache* msi_cachep;
 
 static int pci_msi_enable = 1;
@@ -44,13 +42,13 @@
 {
 	struct msi_desc *entry;
 
-	entry = msi_desc[irq];
+	entry = get_irq_msi(irq);
 	BUG_ON(!entry || !entry->dev);
 	switch (entry->msi_attrib.type) {
 	case PCI_CAP_ID_MSI:
 		if (entry->msi_attrib.maskbit) {
-			int		pos;
-			u32		mask_bits;
+			int pos;
+			u32 mask_bits;
 
 			pos = (long)entry->mask_base;
 			pci_read_config_dword(entry->dev, pos, &mask_bits);
@@ -74,7 +72,7 @@
 
 void read_msi_msg(unsigned int irq, struct msi_msg *msg)
 {
-	struct msi_desc *entry = get_irq_data(irq);
+	struct msi_desc *entry = get_irq_msi(irq);
 	switch(entry->msi_attrib.type) {
 	case PCI_CAP_ID_MSI:
 	{
@@ -113,7 +111,7 @@
 
 void write_msi_msg(unsigned int irq, struct msi_msg *msg)
 {
-	struct msi_desc *entry = get_irq_data(irq);
+	struct msi_desc *entry = get_irq_msi(irq);
 	switch (entry->msi_attrib.type) {
 	case PCI_CAP_ID_MSI:
 	{
@@ -162,6 +160,7 @@
 }
 
 static int msi_free_irq(struct pci_dev* dev, int irq);
+
 static int msi_init(void)
 {
 	static int status = -ENOMEM;
@@ -169,13 +168,6 @@
 	if (!status)
 		return status;
 
-	if (pci_msi_quirk) {
-		pci_msi_enable = 0;
-		printk(KERN_WARNING "PCI: MSI quirk detected. MSI disabled.\n");
-		status = -EINVAL;
-		return status;
-	}
-
 	status = msi_cache_init();
 	if (status < 0) {
 		pci_msi_enable = 0;
@@ -200,46 +192,6 @@
 	return entry;
 }
 
-static void attach_msi_entry(struct msi_desc *entry, int irq)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&msi_lock, flags);
-	msi_desc[irq] = entry;
-	spin_unlock_irqrestore(&msi_lock, flags);
-}
-
-static int create_msi_irq(void)
-{
-	struct msi_desc *entry;
-	int irq;
-
-	entry = alloc_msi_entry();
-	if (!entry)
-		return -ENOMEM;
-
-	irq = create_irq();
-	if (irq < 0) {
-		kmem_cache_free(msi_cachep, entry);
-		return -EBUSY;
-	}
-
-	set_irq_data(irq, entry);
-
-	return irq;
-}
-
-static void destroy_msi_irq(unsigned int irq)
-{
-	struct msi_desc *entry;
-
-	entry = get_irq_data(irq);
-	set_irq_chip(irq, NULL);
-	set_irq_data(irq, NULL);
-	destroy_irq(irq);
-	kmem_cache_free(msi_cachep, entry);
-}
-
 static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
 {
 	u16 control;
@@ -278,36 +230,8 @@
 	pci_intx(dev, 1);  /* enable intx */
 }
 
-static int msi_lookup_irq(struct pci_dev *dev, int type)
-{
-	int irq;
-	unsigned long flags;
-
-	spin_lock_irqsave(&msi_lock, flags);
-	for (irq = 0; irq < NR_IRQS; irq++) {
-		if (!msi_desc[irq] || msi_desc[irq]->dev != dev ||
-			msi_desc[irq]->msi_attrib.type != type ||
-			msi_desc[irq]->msi_attrib.default_irq != dev->irq)
-			continue;
-		spin_unlock_irqrestore(&msi_lock, flags);
-		/* This pre-assigned MSI irq for this device
-		   already exits. Override dev->irq with this irq */
-		dev->irq = irq;
-		return 0;
-	}
-	spin_unlock_irqrestore(&msi_lock, flags);
-
-	return -EACCES;
-}
-
-void pci_scan_msi_device(struct pci_dev *dev)
-{
-	if (!dev)
-		return;
-}
-
 #ifdef CONFIG_PM
-int pci_save_msi_state(struct pci_dev *dev)
+static int __pci_save_msi_state(struct pci_dev *dev)
 {
 	int pos, i = 0;
 	u16 control;
@@ -345,7 +269,7 @@
 	return 0;
 }
 
-void pci_restore_msi_state(struct pci_dev *dev)
+static void __pci_restore_msi_state(struct pci_dev *dev)
 {
 	int i = 0, pos;
 	u16 control;
@@ -373,14 +297,16 @@
 	kfree(save_state);
 }
 
-int pci_save_msix_state(struct pci_dev *dev)
+static int __pci_save_msix_state(struct pci_dev *dev)
 {
 	int pos;
-	int temp;
 	int irq, head, tail = 0;
 	u16 control;
 	struct pci_cap_saved_state *save_state;
 
+	if (!dev->msix_enabled)
+		return 0;
+
 	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
 	if (pos <= 0 || dev->no_msi)
 		return 0;
@@ -398,38 +324,46 @@
 	*((u16 *)&save_state->data[0]) = control;
 
 	/* save the table */
-	temp = dev->irq;
-	if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
-		kfree(save_state);
-		return -EINVAL;
-	}
-
-	irq = head = dev->irq;
+	irq = head = dev->first_msi_irq;
 	while (head != tail) {
 		struct msi_desc *entry;
 
-		entry = msi_desc[irq];
+		entry = get_irq_msi(irq);
 		read_msi_msg(irq, &entry->msg_save);
 
-		tail = msi_desc[irq]->link.tail;
+		tail = entry->link.tail;
 		irq = tail;
 	}
-	dev->irq = temp;
 
 	save_state->cap_nr = PCI_CAP_ID_MSIX;
 	pci_add_saved_cap(dev, save_state);
 	return 0;
 }
 
-void pci_restore_msix_state(struct pci_dev *dev)
+int pci_save_msi_state(struct pci_dev *dev)
+{
+	int rc;
+
+	rc = __pci_save_msi_state(dev);
+	if (rc)
+		return rc;
+
+	rc = __pci_save_msix_state(dev);
+
+	return rc;
+}
+
+static void __pci_restore_msix_state(struct pci_dev *dev)
 {
 	u16 save;
 	int pos;
 	int irq, head, tail = 0;
 	struct msi_desc *entry;
-	int temp;
 	struct pci_cap_saved_state *save_state;
 
+	if (!dev->msix_enabled)
+		return;
+
 	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX);
 	if (!save_state)
 		return;
@@ -442,23 +376,25 @@
 		return;
 
 	/* route the table */
-	temp = dev->irq;
-	if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX))
-		return;
-	irq = head = dev->irq;
+	irq = head = dev->first_msi_irq;
 	while (head != tail) {
-		entry = msi_desc[irq];
+		entry = get_irq_msi(irq);
 		write_msi_msg(irq, &entry->msg_save);
 
-		tail = msi_desc[irq]->link.tail;
+		tail = entry->link.tail;
 		irq = tail;
 	}
-	dev->irq = temp;
 
 	pci_write_config_word(dev, msi_control_reg(pos), save);
 	enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
 }
-#endif
+
+void pci_restore_msi_state(struct pci_dev *dev)
+{
+	__pci_restore_msi_state(dev);
+	__pci_restore_msix_state(dev);
+}
+#endif	/* CONFIG_PM */
 
 /**
  * msi_capability_init - configure device's MSI capability structure
@@ -471,7 +407,6 @@
  **/
 static int msi_capability_init(struct pci_dev *dev)
 {
-	int status;
 	struct msi_desc *entry;
 	int pos, irq;
 	u16 control;
@@ -479,13 +414,10 @@
    	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
 	pci_read_config_word(dev, msi_control_reg(pos), &control);
 	/* MSI Entry Initialization */
-	irq = create_msi_irq();
-	if (irq < 0)
-		return irq;
+	entry = alloc_msi_entry();
+	if (!entry)
+		return -ENOMEM;
 
-	entry = get_irq_data(irq);
-	entry->link.head = irq;
-	entry->link.tail = irq;
 	entry->msi_attrib.type = PCI_CAP_ID_MSI;
 	entry->msi_attrib.is_64 = is_64bit_address(control);
 	entry->msi_attrib.entry_nr = 0;
@@ -511,13 +443,16 @@
 			maskbits);
 	}
 	/* Configure MSI capability structure */
-	status = arch_setup_msi_irq(irq, dev);
-	if (status < 0) {
-		destroy_msi_irq(irq);
-		return status;
+	irq = arch_setup_msi_irq(dev, entry);
+	if (irq < 0) {
+		kmem_cache_free(msi_cachep, entry);
+		return irq;
 	}
+	entry->link.head = irq;
+	entry->link.tail = irq;
+	dev->first_msi_irq = irq;
+	set_irq_msi(irq, entry);
 
-	attach_msi_entry(entry, irq);
 	/* Set MSI enabled bits	 */
 	enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
 
@@ -539,7 +474,6 @@
 				struct msix_entry *entries, int nvec)
 {
 	struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
-	int status;
 	int irq, pos, i, j, nr_entries, temp = 0;
 	unsigned long phys_addr;
 	u32 table_offset;
@@ -562,13 +496,11 @@
 
 	/* MSI-X Table Initialization */
 	for (i = 0; i < nvec; i++) {
-		irq = create_msi_irq();
-		if (irq < 0)
+		entry = alloc_msi_entry();
+		if (!entry)
 			break;
 
-		entry = get_irq_data(irq);
  		j = entries[i].entry;
- 		entries[i].vector = irq;
 		entry->msi_attrib.type = PCI_CAP_ID_MSIX;
 		entry->msi_attrib.is_64 = 1;
 		entry->msi_attrib.entry_nr = j;
@@ -577,6 +509,14 @@
 		entry->msi_attrib.pos = pos;
 		entry->dev = dev;
 		entry->mask_base = base;
+
+		/* Configure MSI-X capability structure */
+		irq = arch_setup_msi_irq(dev, entry);
+		if (irq < 0) {
+			kmem_cache_free(msi_cachep, entry);
+			break;
+		}
+ 		entries[i].vector = irq;
 		if (!head) {
 			entry->link.head = irq;
 			entry->link.tail = irq;
@@ -589,14 +529,8 @@
 		}
 		temp = irq;
 		tail = entry;
-		/* Configure MSI-X capability structure */
-		status = arch_setup_msi_irq(irq, dev);
-		if (status < 0) {
-			destroy_msi_irq(irq);
-			break;
-		}
 
-		attach_msi_entry(entry, irq);
+		set_irq_msi(irq, entry);
 	}
 	if (i != nvec) {
 		int avail = i - 1;
@@ -613,6 +547,7 @@
 			avail = -EBUSY;
 		return avail;
 	}
+	dev->first_msi_irq = entries[0].vector;
 	/* Set MSI-X enabled bits */
 	enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
 
@@ -660,13 +595,11 @@
  **/
 int pci_enable_msi(struct pci_dev* dev)
 {
-	int pos, temp, status;
+	int pos, status;
 
 	if (pci_msi_supported(dev) < 0)
 		return -EINVAL;
 
-	temp = dev->irq;
-
 	status = msi_init();
 	if (status < 0)
 		return status;
@@ -675,15 +608,14 @@
 	if (!pos)
 		return -EINVAL;
 
-	WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI));
+	WARN_ON(!!dev->msi_enabled);
 
 	/* Check whether driver already requested for MSI-X irqs */
 	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-	if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+	if (pos > 0 && dev->msix_enabled) {
 			printk(KERN_INFO "PCI: %s: Can't enable MSI.  "
-			       "Device already has MSI-X irq assigned\n",
+			       "Device already has MSI-X enabled\n",
 			       pci_name(dev));
-			dev->irq = temp;
 			return -EINVAL;
 	}
 	status = msi_capability_init(dev);
@@ -695,13 +627,15 @@
 	struct msi_desc *entry;
 	int pos, default_irq;
 	u16 control;
-	unsigned long flags;
 
 	if (!pci_msi_enable)
 		return;
 	if (!dev)
 		return;
 
+	if (!dev->msi_enabled)
+		return;
+
 	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
 	if (!pos)
 		return;
@@ -710,28 +644,26 @@
 	if (!(control & PCI_MSI_FLAGS_ENABLE))
 		return;
 
+
 	disable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
 
-	spin_lock_irqsave(&msi_lock, flags);
-	entry = msi_desc[dev->irq];
+	entry = get_irq_msi(dev->first_msi_irq);
 	if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
-		spin_unlock_irqrestore(&msi_lock, flags);
 		return;
 	}
-	if (irq_has_action(dev->irq)) {
-		spin_unlock_irqrestore(&msi_lock, flags);
+	if (irq_has_action(dev->first_msi_irq)) {
 		printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without "
 		       "free_irq() on MSI irq %d\n",
-		       pci_name(dev), dev->irq);
-		BUG_ON(irq_has_action(dev->irq));
+		       pci_name(dev), dev->first_msi_irq);
+		BUG_ON(irq_has_action(dev->first_msi_irq));
 	} else {
 		default_irq = entry->msi_attrib.default_irq;
-		spin_unlock_irqrestore(&msi_lock, flags);
-		msi_free_irq(dev, dev->irq);
+		msi_free_irq(dev, dev->first_msi_irq);
 
 		/* Restore dev->irq to its default pin-assertion irq */
 		dev->irq = default_irq;
 	}
+	dev->first_msi_irq = 0;
 }
 
 static int msi_free_irq(struct pci_dev* dev, int irq)
@@ -739,27 +671,20 @@
 	struct msi_desc *entry;
 	int head, entry_nr, type;
 	void __iomem *base;
-	unsigned long flags;
 
-	arch_teardown_msi_irq(irq);
-
-	spin_lock_irqsave(&msi_lock, flags);
-	entry = msi_desc[irq];
+	entry = get_irq_msi(irq);
 	if (!entry || entry->dev != dev) {
-		spin_unlock_irqrestore(&msi_lock, flags);
 		return -EINVAL;
 	}
 	type = entry->msi_attrib.type;
 	entry_nr = entry->msi_attrib.entry_nr;
 	head = entry->link.head;
 	base = entry->mask_base;
-	msi_desc[entry->link.head]->link.tail = entry->link.tail;
-	msi_desc[entry->link.tail]->link.head = entry->link.head;
-	entry->dev = NULL;
-	msi_desc[irq] = NULL;
-	spin_unlock_irqrestore(&msi_lock, flags);
+	get_irq_msi(entry->link.head)->link.tail = entry->link.tail;
+	get_irq_msi(entry->link.tail)->link.head = entry->link.head;
 
-	destroy_msi_irq(irq);
+	arch_teardown_msi_irq(irq);
+	kmem_cache_free(msi_cachep, entry);
 
 	if (type == PCI_CAP_ID_MSIX) {
 		writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE +
@@ -790,7 +715,7 @@
 int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
 {
 	int status, pos, nr_entries;
-	int i, j, temp;
+	int i, j;
 	u16 control;
 
 	if (!entries || pci_msi_supported(dev) < 0)
@@ -818,16 +743,14 @@
 				return -EINVAL;	/* duplicate entry */
 		}
 	}
-	temp = dev->irq;
-	WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSIX));
+	WARN_ON(!!dev->msix_enabled);
 
 	/* Check whether driver already requested for MSI irq */
    	if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 &&
-		!msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
+		dev->msi_enabled) {
 		printk(KERN_INFO "PCI: %s: Can't enable MSI-X.  "
 		       "Device already has an MSI irq assigned\n",
 		       pci_name(dev));
-		dev->irq = temp;
 		return -EINVAL;
 	}
 	status = msix_capability_init(dev, entries, nvec);
@@ -836,7 +759,8 @@
 
 void pci_disable_msix(struct pci_dev* dev)
 {
-	int pos, temp;
+	int irq, head, tail = 0, warning = 0;
+	int pos;
 	u16 control;
 
 	if (!pci_msi_enable)
@@ -844,6 +768,9 @@
 	if (!dev)
 		return;
 
+	if (!dev->msix_enabled)
+		return;
+
 	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
 	if (!pos)
 		return;
@@ -854,31 +781,23 @@
 
 	disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
 
-	temp = dev->irq;
-	if (!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
-		int irq, head, tail = 0, warning = 0;
-		unsigned long flags;
-
-		irq = head = dev->irq;
-		dev->irq = temp;			/* Restore pin IRQ */
-		while (head != tail) {
-			spin_lock_irqsave(&msi_lock, flags);
-			tail = msi_desc[irq]->link.tail;
-			spin_unlock_irqrestore(&msi_lock, flags);
-			if (irq_has_action(irq))
-				warning = 1;
-			else if (irq != head)	/* Release MSI-X irq */
-				msi_free_irq(dev, irq);
-			irq = tail;
-		}
-		msi_free_irq(dev, irq);
-		if (warning) {
-			printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
-			       "free_irq() on all MSI-X irqs\n",
-			       pci_name(dev));
-			BUG_ON(warning > 0);
-		}
+	irq = head = dev->first_msi_irq;
+	while (head != tail) {
+		tail = get_irq_msi(irq)->link.tail;
+		if (irq_has_action(irq))
+			warning = 1;
+		else if (irq != head)	/* Release MSI-X irq */
+			msi_free_irq(dev, irq);
+		irq = tail;
 	}
+	msi_free_irq(dev, irq);
+	if (warning) {
+		printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
+			"free_irq() on all MSI-X irqs\n",
+			pci_name(dev));
+		BUG_ON(warning > 0);
+	}
+	dev->first_msi_irq = 0;
 }
 
 /**
@@ -892,35 +811,26 @@
  **/
 void msi_remove_pci_irq_vectors(struct pci_dev* dev)
 {
-	int pos, temp;
-	unsigned long flags;
-
 	if (!pci_msi_enable || !dev)
  		return;
 
-	temp = dev->irq;		/* Save IOAPIC IRQ */
-	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
-	if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
-		if (irq_has_action(dev->irq)) {
+	if (dev->msi_enabled) {
+		if (irq_has_action(dev->first_msi_irq)) {
 			printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
 			       "called without free_irq() on MSI irq %d\n",
-			       pci_name(dev), dev->irq);
-			BUG_ON(irq_has_action(dev->irq));
+			       pci_name(dev), dev->first_msi_irq);
+			BUG_ON(irq_has_action(dev->first_msi_irq));
 		} else /* Release MSI irq assigned to this device */
-			msi_free_irq(dev, dev->irq);
-		dev->irq = temp;		/* Restore IOAPIC IRQ */
+			msi_free_irq(dev, dev->first_msi_irq);
 	}
-	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-	if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+	if (dev->msix_enabled) {
 		int irq, head, tail = 0, warning = 0;
 		void __iomem *base = NULL;
 
-		irq = head = dev->irq;
+		irq = head = dev->first_msi_irq;
 		while (head != tail) {
-			spin_lock_irqsave(&msi_lock, flags);
-			tail = msi_desc[irq]->link.tail;
-			base = msi_desc[irq]->mask_base;
-			spin_unlock_irqrestore(&msi_lock, flags);
+			tail = get_irq_msi(irq)->link.tail;
+			base = get_irq_msi(irq)->mask_base;
 			if (irq_has_action(irq))
 				warning = 1;
 			else if (irq != head) /* Release MSI-X irq */
@@ -935,7 +845,6 @@
 			       pci_name(dev));
 			BUG_ON(warning > 0);
 		}
-		dev->irq = temp;		/* Restore IOAPIC IRQ */
 	}
 }
 
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 92d5e8d..4438ae1 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -324,8 +324,7 @@
 	/* restore the PCI config space */
 	pci_restore_state(pci_dev);
 	/* if the device was enabled before suspend, reenable */
-	if (atomic_read(&pci_dev->enable_cnt))
-		retval = __pci_enable_device(pci_dev);
+	retval = __pci_reenable_device(pci_dev);
 	/* if the device was busmaster before the suspend, make it busmaster again */
 	if (pci_dev->is_busmaster)
 		pci_set_master(pci_dev);
@@ -422,7 +421,8 @@
  * If no error occurred, the driver remains registered even if 
  * no device was claimed during registration.
  */
-int __pci_register_driver(struct pci_driver *drv, struct module *owner)
+int __pci_register_driver(struct pci_driver *drv, struct module *owner,
+			  const char *mod_name)
 {
 	int error;
 
@@ -430,6 +430,7 @@
 	drv->driver.name = drv->name;
 	drv->driver.bus = &pci_bus_type;
 	drv->driver.owner = owner;
+	drv->driver.mod_name = mod_name;
 	drv->driver.kobj.ktype = &pci_driver_kobj_type;
 
 	if (pci_multithread_probe)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 206c834..84c757b 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -392,6 +392,14 @@
 	if (state > PCI_D3hot)
 		state = PCI_D3hot;
 
+	/*
+	 * If the device or the parent bridge can't support PCI PM, ignore
+	 * the request if we're doing anything besides putting it into D0
+	 * (which would only happen on boot).
+	 */
+	if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
+		return 0;
+
 	/* Validate current state:
 	 * Can enter D0 from any state, but if we can only go deeper 
 	 * to sleep if we're already in a low power state
@@ -403,13 +411,6 @@
 	} else if (dev->current_state == state)
 		return 0;        /* we're already there */
 
-	/*
-	 * If the device or the parent bridge can't support PCI PM, ignore
-	 * the request if we're doing anything besides putting it into D0
-	 * (which would only happen on boot).
-	 */
-	if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
-		return 0;
 
 	/* find PCI PM capability in list */
 	pm = pci_find_capability(dev, PCI_CAP_ID_PM);
@@ -633,8 +634,6 @@
 		pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]);
 	if ((i = pci_save_msi_state(dev)) != 0)
 		return i;
-	if ((i = pci_save_msix_state(dev)) != 0)
-		return i;
 	if ((i = pci_save_pcie_state(dev)) != 0)
 		return i;
 	if ((i = pci_save_pcix_state(dev)) != 0)
@@ -672,22 +671,11 @@
 	}
 	pci_restore_pcix_state(dev);
 	pci_restore_msi_state(dev);
-	pci_restore_msix_state(dev);
+
 	return 0;
 }
 
-/**
- * pci_enable_device_bars - Initialize some of a device for use
- * @dev: PCI device to be initialized
- * @bars: bitmask of BAR's that must be configured
- *
- *  Initialize device before it's used by a driver. Ask low-level code
- *  to enable selected I/O and memory resources. Wake up the device if it 
- *  was suspended. Beware, this function can fail.
- */
- 
-int
-pci_enable_device_bars(struct pci_dev *dev, int bars)
+static int do_pci_enable_device(struct pci_dev *dev, int bars)
 {
 	int err;
 
@@ -697,30 +685,47 @@
 	err = pcibios_enable_device(dev, bars);
 	if (err < 0)
 		return err;
+	pci_fixup_device(pci_fixup_enable, dev);
+
 	return 0;
 }
 
 /**
- * __pci_enable_device - Initialize device before it's used by a driver.
- * @dev: PCI device to be initialized
+ * __pci_reenable_device - Resume abandoned device
+ * @dev: PCI device to be resumed
  *
- *  Initialize device before it's used by a driver. Ask low-level code
- *  to enable I/O and memory. Wake up the device if it was suspended.
- *  Beware, this function can fail.
- *
- * Note this function is a backend and is not supposed to be called by
- * normal code, use pci_enable_device() instead.
+ *  Note this function is a backend of pci_default_resume and is not supposed
+ *  to be called by normal code, write proper resume handler and use it instead.
  */
 int
-__pci_enable_device(struct pci_dev *dev)
+__pci_reenable_device(struct pci_dev *dev)
+{
+	if (atomic_read(&dev->enable_cnt))
+		return do_pci_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1);
+	return 0;
+}
+
+/**
+ * pci_enable_device_bars - Initialize some of a device for use
+ * @dev: PCI device to be initialized
+ * @bars: bitmask of BAR's that must be configured
+ *
+ *  Initialize device before it's used by a driver. Ask low-level code
+ *  to enable selected I/O and memory resources. Wake up the device if it
+ *  was suspended. Beware, this function can fail.
+ */
+int
+pci_enable_device_bars(struct pci_dev *dev, int bars)
 {
 	int err;
 
-	err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
-	if (err)
-		return err;
-	pci_fixup_device(pci_fixup_enable, dev);
-	return 0;
+	if (atomic_add_return(1, &dev->enable_cnt) > 1)
+		return 0;		/* already enabled */
+
+	err = do_pci_enable_device(dev, bars);
+	if (err < 0)
+		atomic_dec(&dev->enable_cnt);
+	return err;
 }
 
 /**
@@ -736,13 +741,7 @@
  */
 int pci_enable_device(struct pci_dev *dev)
 {
-	int result;
-	if (atomic_add_return(1, &dev->enable_cnt) > 1)
-		return 0;		/* already enabled */
-	result = __pci_enable_device(dev);
-	if (result < 0)
-		atomic_dec(&dev->enable_cnt);
-	return result;
+	return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
 }
 
 /**
@@ -921,6 +920,47 @@
 	return -EBUSY;
 }
 
+/**
+ * pci_release_selected_regions - Release selected PCI I/O and memory resources
+ * @pdev: PCI device whose resources were previously reserved
+ * @bars: Bitmask of BARs to be released
+ *
+ * Release selected PCI I/O and memory resources previously reserved.
+ * Call this function only after all use of the PCI regions has ceased.
+ */
+void pci_release_selected_regions(struct pci_dev *pdev, int bars)
+{
+	int i;
+
+	for (i = 0; i < 6; i++)
+		if (bars & (1 << i))
+			pci_release_region(pdev, i);
+}
+
+/**
+ * pci_request_selected_regions - Reserve selected PCI I/O and memory resources
+ * @pdev: PCI device whose resources are to be reserved
+ * @bars: Bitmask of BARs to be requested
+ * @res_name: Name to be associated with resource
+ */
+int pci_request_selected_regions(struct pci_dev *pdev, int bars,
+				 const char *res_name)
+{
+	int i;
+
+	for (i = 0; i < 6; i++)
+		if (bars & (1 << i))
+			if(pci_request_region(pdev, i, res_name))
+				goto err_out;
+	return 0;
+
+err_out:
+	while(--i >= 0)
+		if (bars & (1 << i))
+			pci_release_region(pdev, i);
+
+	return -EBUSY;
+}
 
 /**
  *	pci_release_regions - Release reserved PCI I/O and memory resources
@@ -933,10 +973,7 @@
 
 void pci_release_regions(struct pci_dev *pdev)
 {
-	int i;
-	
-	for (i = 0; i < 6; i++)
-		pci_release_region(pdev, i);
+	pci_release_selected_regions(pdev, (1 << 6) - 1);
 }
 
 /**
@@ -954,18 +991,7 @@
  */
 int pci_request_regions(struct pci_dev *pdev, const char *res_name)
 {
-	int i;
-	
-	for (i = 0; i < 6; i++)
-		if(pci_request_region(pdev, i, res_name))
-			goto err_out;
-	return 0;
-
-err_out:
-	while(--i >= 0)
-		pci_release_region(pdev, i);
-		
-	return -EBUSY;
+	return pci_request_selected_regions(pdev, ((1 << 6) - 1), res_name);
 }
 
 /**
@@ -1148,7 +1174,23 @@
 	return 0;
 }
 #endif
-     
+
+/**
+ * pci_select_bars - Make BAR mask from the type of resource
+ * @pdev: the PCI device for which BAR mask is made
+ * @flags: resource type mask to be selected
+ *
+ * This helper routine makes bar mask from the type of resource.
+ */
+int pci_select_bars(struct pci_dev *dev, unsigned long flags)
+{
+	int i, bars = 0;
+	for (i = 0; i < PCI_NUM_RESOURCES; i++)
+		if (pci_resource_flags(dev, i) & flags)
+			bars |= (1 << i);
+	return bars;
+}
+
 static int __devinit pci_init(void)
 {
 	struct pci_dev *dev = NULL;
@@ -1181,12 +1223,6 @@
 
 device_initcall(pci_init);
 
-#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
-/* FIXME: Some boxes have multiple ISA bridges! */
-struct pci_dev *isa_bridge;
-EXPORT_SYMBOL(isa_bridge);
-#endif
-
 EXPORT_SYMBOL_GPL(pci_restore_bars);
 EXPORT_SYMBOL(pci_enable_device_bars);
 EXPORT_SYMBOL(pci_enable_device);
@@ -1197,6 +1233,8 @@
 EXPORT_SYMBOL(pci_request_regions);
 EXPORT_SYMBOL(pci_release_region);
 EXPORT_SYMBOL(pci_request_region);
+EXPORT_SYMBOL(pci_release_selected_regions);
+EXPORT_SYMBOL(pci_request_selected_regions);
 EXPORT_SYMBOL(pci_set_master);
 EXPORT_SYMBOL(pci_set_mwi);
 EXPORT_SYMBOL(pci_clear_mwi);
@@ -1205,13 +1243,10 @@
 EXPORT_SYMBOL(pci_set_consistent_dma_mask);
 EXPORT_SYMBOL(pci_assign_resource);
 EXPORT_SYMBOL(pci_find_parent_resource);
+EXPORT_SYMBOL(pci_select_bars);
 
 EXPORT_SYMBOL(pci_set_power_state);
 EXPORT_SYMBOL(pci_save_state);
 EXPORT_SYMBOL(pci_restore_state);
 EXPORT_SYMBOL(pci_enable_wake);
 
-/* Quirk info */
-
-EXPORT_SYMBOL(isa_dma_bridge_buggy);
-EXPORT_SYMBOL(pci_pci_problems);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 398852f..a4f2d58 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1,6 +1,6 @@
 /* Functions internal to the PCI core code */
 
-extern int __must_check __pci_enable_device(struct pci_dev *);
+extern int __must_check __pci_reenable_device(struct pci_dev *);
 extern int pci_uevent(struct device *dev, char **envp, int num_envp,
 		      char *buffer, int buffer_size);
 extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
@@ -43,12 +43,8 @@
 /* Lock for read/write access to pci device and bus lists */
 extern struct rw_semaphore pci_bus_sem;
 
-#ifdef CONFIG_PCI_MSI
-extern int pci_msi_quirk;
-#else
-#define pci_msi_quirk 0
-#endif
 extern unsigned int pci_pm_d3_delay;
+
 #ifdef CONFIG_PCI_MSI
 void disable_msi_mode(struct pci_dev *dev, int pos, int type);
 void pci_no_msi(void);
@@ -56,17 +52,15 @@
 static inline void disable_msi_mode(struct pci_dev *dev, int pos, int type) { }
 static inline void pci_no_msi(void) { }
 #endif
+
 #if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM)
 int pci_save_msi_state(struct pci_dev *dev);
-int pci_save_msix_state(struct pci_dev *dev);
 void pci_restore_msi_state(struct pci_dev *dev);
-void pci_restore_msix_state(struct pci_dev *dev);
 #else
 static inline int pci_save_msi_state(struct pci_dev *dev) { return 0; }
-static inline int pci_save_msix_state(struct pci_dev *dev) { return 0; }
 static inline void pci_restore_msi_state(struct pci_dev *dev) {}
-static inline void pci_restore_msix_state(struct pci_dev *dev) {}
 #endif
+
 static inline int pci_no_d1d2(struct pci_dev *dev)
 {
 	unsigned int parent_dstates = 0;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 0e0401d..2fe1d69 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -144,6 +144,32 @@
 	return size;
 }
 
+static u64 pci_size64(u64 base, u64 maxbase, u64 mask)
+{
+	u64 size = mask & maxbase;	/* Find the significant bits */
+	if (!size)
+		return 0;
+
+	/* Get the lowest of them to find the decode size, and
+	   from that the extent.  */
+	size = (size & ~(size-1)) - 1;
+
+	/* base == maxbase can be valid only if the BAR has
+	   already been programmed with all 1s.  */
+	if (base == maxbase && ((base | size) & mask) != mask)
+		return 0;
+
+	return size;
+}
+
+static inline int is_64bit_memory(u32 mask)
+{
+	if ((mask & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
+	    (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64))
+		return 1;
+	return 0;
+}
+
 static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
 {
 	unsigned int pos, reg, next;
@@ -151,6 +177,10 @@
 	struct resource *res;
 
 	for(pos=0; pos<howmany; pos = next) {
+		u64 l64;
+		u64 sz64;
+		u32 raw_sz;
+
 		next = pos+1;
 		res = &dev->resource[pos];
 		res->name = pci_name(dev);
@@ -163,9 +193,16 @@
 			continue;
 		if (l == 0xffffffff)
 			l = 0;
-		if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
+		raw_sz = sz;
+		if ((l & PCI_BASE_ADDRESS_SPACE) ==
+				PCI_BASE_ADDRESS_SPACE_MEMORY) {
 			sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK);
-			if (!sz)
+			/*
+			 * For 64bit prefetchable memory sz could be 0, if the
+			 * real size is bigger than 4G, so we need to check
+			 * szhi for that.
+			 */
+			if (!is_64bit_memory(l) && !sz)
 				continue;
 			res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
 			res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
@@ -178,30 +215,36 @@
 		}
 		res->end = res->start + (unsigned long) sz;
 		res->flags |= pci_calc_resource_flags(l);
-		if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
-		    == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+		if (is_64bit_memory(l)) {
 			u32 szhi, lhi;
+
 			pci_read_config_dword(dev, reg+4, &lhi);
 			pci_write_config_dword(dev, reg+4, ~0);
 			pci_read_config_dword(dev, reg+4, &szhi);
 			pci_write_config_dword(dev, reg+4, lhi);
-			szhi = pci_size(lhi, szhi, 0xffffffff);
+			sz64 = ((u64)szhi << 32) | raw_sz;
+			l64 = ((u64)lhi << 32) | l;
+			sz64 = pci_size64(l64, sz64, PCI_BASE_ADDRESS_MEM_MASK);
 			next++;
 #if BITS_PER_LONG == 64
-			res->start |= ((unsigned long) lhi) << 32;
-			res->end = res->start + sz;
-			if (szhi) {
-				/* This BAR needs > 4GB?  Wow. */
-				res->end |= (unsigned long)szhi<<32;
+			if (!sz64) {
+				res->start = 0;
+				res->end = 0;
+				res->flags = 0;
+				continue;
 			}
+			res->start = l64 & PCI_BASE_ADDRESS_MEM_MASK;
+			res->end = res->start + sz64;
 #else
-			if (szhi) {
-				printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev));
+			if (sz64 > 0x100000000ULL) {
+				printk(KERN_ERR "PCI: Unable to handle 64-bit "
+					"BAR for device %s\n", pci_name(dev));
 				res->start = 0;
 				res->flags = 0;
 			} else if (lhi) {
 				/* 64-bit wide address, treat as disabled */
-				pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK);
+				pci_write_config_dword(dev, reg,
+					l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK);
 				pci_write_config_dword(dev, reg+4, 0);
 				res->start = 0;
 				res->end = sz;
@@ -902,7 +945,6 @@
 		return NULL;
 
 	pci_device_add(dev, bus);
-	pci_scan_msi_device(dev);
 
 	return dev;
 }
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index c913ea4..11217bd 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -61,7 +61,8 @@
     
     This appears to be BIOS not version dependent. So presumably there is a 
     chipset level fix */
-int isa_dma_bridge_buggy;		/* Exported */
+int isa_dma_bridge_buggy;
+EXPORT_SYMBOL(isa_dma_bridge_buggy);
     
 static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev)
 {
@@ -83,6 +84,7 @@
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC,	PCI_DEVICE_ID_NEC_CBUS_3,	quirk_isa_dma_hangs );
 
 int pci_pci_problems;
+EXPORT_SYMBOL(pci_pci_problems);
 
 /*
  *	Chipsets where PCI->PCI transfers vanish or hang
@@ -94,6 +96,8 @@
 		pci_pci_problems |= PCIPCI_FAIL;
 	}
 }
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		quirk_nopcipci );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_496,		quirk_nopcipci );
 
 static void __devinit quirk_nopciamd(struct pci_dev *dev)
 {
@@ -105,9 +109,6 @@
 		pci_pci_problems |= PCIAGP_FAIL;
 	}
 }
-
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		quirk_nopcipci );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_496,		quirk_nopcipci );
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_8151_0,	quirk_nopciamd );
 
 /*
@@ -976,52 +977,51 @@
 			case 0x1626: /* L3C notebook */
 				asus_hides_smbus = 1;
 			}
-		if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB)
+		else if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB)
 			switch(dev->subsystem_device) {
 			case 0x80b1: /* P4GE-V */
 			case 0x80b2: /* P4PE */
 			case 0x8093: /* P4B533-V */
 				asus_hides_smbus = 1;
 			}
-		if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB)
+		else if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB)
 			switch(dev->subsystem_device) {
 			case 0x8030: /* P4T533 */
 				asus_hides_smbus = 1;
 			}
-		if (dev->device == PCI_DEVICE_ID_INTEL_7205_0)
+		else if (dev->device == PCI_DEVICE_ID_INTEL_7205_0)
 			switch (dev->subsystem_device) {
 			case 0x8070: /* P4G8X Deluxe */
 				asus_hides_smbus = 1;
 			}
-		if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH)
+		else if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH)
 			switch (dev->subsystem_device) {
 			case 0x80c9: /* PU-DLS */
 				asus_hides_smbus = 1;
 			}
-		if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
+		else if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
 			switch (dev->subsystem_device) {
 			case 0x1751: /* M2N notebook */
 			case 0x1821: /* M5N notebook */
 				asus_hides_smbus = 1;
 			}
-		if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
+		else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
 			switch (dev->subsystem_device) {
 			case 0x184b: /* W1N notebook */
 			case 0x186a: /* M6Ne notebook */
 				asus_hides_smbus = 1;
 			}
-		if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
+		else if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
 			switch (dev->subsystem_device) {
 			case 0x80f2: /* P4P800-X */
 				asus_hides_smbus = 1;
 			}
-		if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) {
+		else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB)
 			switch (dev->subsystem_device) {
 			case 0x1882: /* M6V notebook */
 			case 0x1977: /* A6VA notebook */
 				asus_hides_smbus = 1;
 			}
-		}
 	} else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_HP)) {
 		if (dev->device ==  PCI_DEVICE_ID_INTEL_82855PM_HB)
 			switch(dev->subsystem_device) {
@@ -1029,25 +1029,24 @@
 			case 0x0890: /* HP Compaq nc6000 */
 				asus_hides_smbus = 1;
 			}
-		if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
+		else if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
 			switch (dev->subsystem_device) {
 			case 0x12bc: /* HP D330L */
 			case 0x12bd: /* HP D530 */
 				asus_hides_smbus = 1;
 			}
-		if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) {
+		else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB)
 			switch (dev->subsystem_device) {
 			case 0x099c: /* HP Compaq nx6110 */
 				asus_hides_smbus = 1;
 			}
-		}
 	} else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_TOSHIBA)) {
 		if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
 			switch(dev->subsystem_device) {
 			case 0x0001: /* Toshiba Satellite A40 */
 				asus_hides_smbus = 1;
 			}
-		if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
+		else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
 			switch(dev->subsystem_device) {
 			case 0x0001: /* Toshiba Tecra M2 */
 				asus_hides_smbus = 1;
@@ -1136,6 +1135,14 @@
 		pci_write_config_byte(dev, 0x77, val & ~0x10);
 	}
 }
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_961,		quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_962,		quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_963,		quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_LPC,		quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_961,		quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_962,		quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_963,		quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_LPC,		quirk_sis_96x_smbus );
 
 /*
  * ... This is further complicated by the fact that some SiS96x south
@@ -1145,8 +1152,6 @@
  *
  * We can also enable the sis96x bit in the discovery register..
  */
-static int __devinitdata sis_96x_compatible = 0;
-
 #define SIS_DETECT_REGISTER 0x40
 
 static void quirk_sis_503(struct pci_dev *dev)
@@ -1162,9 +1167,6 @@
 		return;
 	}
 
-	/* Make people aware that we changed the config.. */
-	printk(KERN_WARNING "Uncovering SIS%x that hid as a SIS503 (compatible=%d)\n", devid, sis_96x_compatible);
-
 	/*
 	 * Ok, it now shows up as a 96x.. run the 96x quirk by
 	 * hand in case it has already been processed.
@@ -1173,20 +1175,10 @@
 	dev->device = devid;
 	quirk_sis_96x_smbus(dev);
 }
-
-static void __init quirk_sis_96x_compatible(struct pci_dev *dev)
-{
-	sis_96x_compatible = 1;
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_645,		quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_646,		quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_648,		quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_650,		quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_651,		quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_735,		quirk_sis_96x_compatible );
-
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_503,		quirk_sis_503 );
 DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_503,		quirk_sis_503 );
+
+
 /*
  * On ASUS A8V and A8V Deluxe boards, the onboard AC97 audio controller
  * and MC97 modem controller are disabled when a second PCI soundcard is
@@ -1217,21 +1209,8 @@
 	}
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc );
-
-
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_961,		quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_962,		quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_963,		quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_LPC,		quirk_sis_96x_smbus );
-
 DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc );
 
-
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_961,		quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_962,		quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_963,		quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_LPC,		quirk_sis_96x_smbus );
-
 #if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE)
 
 /*
@@ -1276,7 +1255,6 @@
 			break;
 	}
 }
-
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn);
 DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn);
 
@@ -1420,6 +1398,7 @@
 
 
 int pcie_mch_quirk;
+EXPORT_SYMBOL(pcie_mch_quirk);
 
 static void __devinit quirk_pcie_mch(struct pci_dev *pdev)
 {
@@ -1481,6 +1460,24 @@
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x260a, quirk_intel_pcie_pm);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x260b, quirk_intel_pcie_pm);
 
+/*
+ * Toshiba TC86C001 IDE controller reports the standard 8-byte BAR0 size
+ * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes.
+ * Re-allocate the region if needed...
+ */
+static void __init quirk_tc86c001_ide(struct pci_dev *dev)
+{
+	struct resource *r = &dev->resource[0];
+
+	if (r->start & 0x8) {
+		r->start = 0;
+		r->end = 0xf;
+	}
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2,
+			 PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE,
+			 quirk_tc86c001_ide);
+
 static void __devinit quirk_netmos(struct pci_dev *dev)
 {
 	unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4;
@@ -1646,6 +1643,7 @@
 	}
 	pci_do_fixups(dev, start, end);
 }
+EXPORT_SYMBOL(pci_fixup_device);
 
 /* Enable 1k I/O space granularity on the Intel P64H2 */
 static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev)
@@ -1673,6 +1671,31 @@
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	0x1460,		quirk_p64h2_1k_io);
 
+/* Fix the IOBL_ADR for 1k I/O space granularity on the Intel P64H2
+ * The IOBL_ADR gets re-written to 4k boundaries in pci_setup_bridge()
+ * in drivers/pci/setup-bus.c
+ */
+static void __devinit quirk_p64h2_1k_io_fix_iobl(struct pci_dev *dev)
+{
+	u16 en1k, iobl_adr, iobl_adr_1k;
+	struct resource *res = dev->resource + PCI_BRIDGE_RESOURCES;
+
+	pci_read_config_word(dev, 0x40, &en1k);
+
+	if (en1k & 0x200) {
+		pci_read_config_word(dev, PCI_IO_BASE, &iobl_adr);
+
+		iobl_adr_1k = iobl_adr | (res->start >> 8) | (res->end & 0xfc00);
+
+		if (iobl_adr != iobl_adr_1k) {
+			printk(KERN_INFO "PCI: Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1 KB Granularity\n",
+				iobl_adr,iobl_adr_1k);
+			pci_write_config_word(dev, PCI_IO_BASE, iobl_adr_1k);
+		}
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x1460,		quirk_p64h2_1k_io_fix_iobl);
+
 /* Under some circumstances, AER is not linked with extended capabilities.
  * Force it to be linked by setting the corresponding control bit in the
  * config space.
@@ -1695,9 +1718,6 @@
 			quirk_nvidia_ck804_pcie_aer_ext_cap);
 
 #ifdef CONFIG_PCI_MSI
-/* To disable MSI globally */
-int pci_msi_quirk;
-
 /* The Serverworks PCI-X chipset does not support MSI. We cannot easily rely
  * on setting PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually
  * some other busses controlled by the chipset even if Linux is not aware of it.
@@ -1706,8 +1726,8 @@
  */
 static void __init quirk_svw_msi(struct pci_dev *dev)
 {
-	pci_msi_quirk = 1;
-	printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n");
+	pci_no_msi();
+	printk(KERN_WARNING "PCI: MSI quirk detected. MSI deactivated.\n");
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi);
 
@@ -1788,8 +1808,3 @@
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
 			quirk_nvidia_ck804_msi_ht_cap);
 #endif /* CONFIG_PCI_MSI */
-
-EXPORT_SYMBOL(pcie_mch_quirk);
-#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pci_fixup_device);
-#endif
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index b2653c4..ff98ead 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -358,43 +358,6 @@
 }
 
 /**
- * pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id
- * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
- * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
- * @from: Previous PCI device found in search, or %NULL for new search.
- *
- * Iterates through the list of known PCI devices in the reverse order of
- * pci_find_device().
- * If a PCI device is found with a matching @vendor and @device, a pointer to
- * its device structure is returned.  Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL as the @from argument.
- * Otherwise if @from is not %NULL, searches continue from previous device
- * on the global list.
- */
-struct pci_dev *
-pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct pci_dev *from)
-{
-	struct list_head *n;
-	struct pci_dev *dev;
-
-	WARN_ON(in_interrupt());
-	down_read(&pci_bus_sem);
-	n = from ? from->global_list.prev : pci_devices.prev;
-
-	while (n && (n != &pci_devices)) {
-		dev = pci_dev_g(n);
-		if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
-		    (device == PCI_ANY_ID || dev->device == device))
-			goto exit;
-		n = n->prev;
-	}
-	dev = NULL;
-exit:
-	up_read(&pci_bus_sem);
-	return dev;
-}
-
-/**
  * pci_get_class - begin or continue searching for a PCI device by class
  * @class: search for a PCI device with this class designation
  * @from: Previous PCI device found in search, or %NULL for new search.
@@ -469,7 +432,6 @@
 EXPORT_SYMBOL(pci_find_present);
 
 EXPORT_SYMBOL(pci_find_device);
-EXPORT_SYMBOL(pci_find_device_reverse);
 EXPORT_SYMBOL(pci_find_slot);
 /* For boot time work */
 EXPORT_SYMBOL(pci_find_bus);
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 606a467..ac00424 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -110,7 +110,7 @@
 
 	down_read(&pcmcia_socket_list_rwsem);
 	list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
-		if (socket->dev.dev != dev)
+		if (socket->dev.parent != dev)
 			continue;
 		mutex_lock(&socket->skt_mutex);
 		socket_suspend(socket);
@@ -128,7 +128,7 @@
 
 	down_read(&pcmcia_socket_list_rwsem);
 	list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
-		if (socket->dev.dev != dev)
+		if (socket->dev.parent != dev)
 			continue;
 		mutex_lock(&socket->skt_mutex);
 		socket_resume(socket);
@@ -143,12 +143,12 @@
 
 struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt)
 {
-	struct class_device *cl_dev = class_device_get(&skt->dev);
-	if (!cl_dev)
+	struct device *dev = get_device(&skt->dev);
+	if (!dev)
 		return NULL;
-	skt = class_get_devdata(cl_dev);
+	skt = dev_get_drvdata(dev);
 	if (!try_module_get(skt->owner)) {
-		class_device_put(&skt->dev);
+		put_device(&skt->dev);
 		return NULL;
 	}
 	return (skt);
@@ -159,14 +159,14 @@
 void pcmcia_put_socket(struct pcmcia_socket *skt)
 {
 	module_put(skt->owner);
-	class_device_put(&skt->dev);
+	put_device(&skt->dev);
 }
 EXPORT_SYMBOL(pcmcia_put_socket);
 
 
-static void pcmcia_release_socket(struct class_device *class_dev)
+static void pcmcia_release_socket(struct device *dev)
 {
-	struct pcmcia_socket *socket = class_get_devdata(class_dev);
+	struct pcmcia_socket *socket = dev_get_drvdata(dev);
 
 	complete(&socket->socket_released);
 }
@@ -181,7 +181,7 @@
 	struct task_struct *tsk;
 	int ret;
 
-	if (!socket || !socket->ops || !socket->dev.dev || !socket->resource_ops)
+	if (!socket || !socket->ops || !socket->dev.parent || !socket->resource_ops)
 		return -EINVAL;
 
 	cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops);
@@ -226,9 +226,9 @@
 #endif
 
 	/* set proper values in socket->dev */
-	socket->dev.class_data = socket;
+	dev_set_drvdata(&socket->dev, socket);
 	socket->dev.class = &pcmcia_socket_class;
-	snprintf(socket->dev.class_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock);
+	snprintf(socket->dev.bus_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock);
 
 	/* base address = 0, map = 0 */
 	socket->cis_mem.flags = 0;
@@ -640,7 +640,7 @@
 	skt->ops->set_socket(skt, &skt->socket);
 
 	/* register with the device core */
-	ret = class_device_register(&skt->dev);
+	ret = device_register(&skt->dev);
 	if (ret) {
 		printk(KERN_WARNING "PCMCIA: unable to register socket 0x%p\n",
 			skt);
@@ -689,7 +689,7 @@
 	remove_wait_queue(&skt->thread_wait, &wait);
 
 	/* remove from the device core */
-	class_device_unregister(&skt->dev);
+	device_unregister(&skt->dev);
 
 	return 0;
 }
@@ -904,7 +904,7 @@
 EXPORT_SYMBOL(pcmcia_insert_card);
 
 
-static int pcmcia_socket_uevent(struct class_device *dev, char **envp,
+static int pcmcia_socket_uevent(struct device *dev, char **envp,
 			        int num_envp, char *buffer, int buffer_size)
 {
 	struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
@@ -930,8 +930,8 @@
 
 struct class pcmcia_socket_class = {
 	.name = "pcmcia_socket",
-	.uevent = pcmcia_socket_uevent,
-	.release = pcmcia_release_socket,
+	.dev_uevent = pcmcia_socket_uevent,
+	.dev_release = pcmcia_release_socket,
 	.class_release = pcmcia_release_socket_class,
 };
 EXPORT_SYMBOL(pcmcia_socket_class);
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index f573ea0..9fa207e 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -142,7 +142,7 @@
 
 int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c);
 
-#define cs_socket_name(skt)	((skt)->dev.class_id)
+#define cs_socket_name(skt)	((skt)->dev.bus_id)
 
 #ifdef DEBUG
 extern int cs_debug_level(int);
@@ -158,6 +158,6 @@
 #endif
 
 #define cs_err(skt, fmt, arg...) \
-	printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.class_id , ## arg)
+	printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.bus_id , ## arg)
 
 #endif /* _LINUX_CS_INTERNAL_H */
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 7355eb4..18e111e 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -572,7 +572,7 @@
 	p_dev->func   = function;
 
 	p_dev->dev.bus = &pcmcia_bus_type;
-	p_dev->dev.parent = s->dev.dev;
+	p_dev->dev.parent = s->dev.parent;
 	p_dev->dev.release = pcmcia_release_dev;
 	bus_id_len = sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no);
 
@@ -1328,10 +1328,10 @@
 	.resume = pcmcia_bus_resume,
 };
 
-static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev,
+static int __devinit pcmcia_bus_add_socket(struct device *dev,
 					   struct class_interface *class_intf)
 {
-	struct pcmcia_socket *socket = class_get_devdata(class_dev);
+	struct pcmcia_socket *socket = dev_get_drvdata(dev);
 	int ret;
 
 	socket = pcmcia_get_socket(socket);
@@ -1364,10 +1364,10 @@
 	return 0;
 }
 
-static void pcmcia_bus_remove_socket(struct class_device *class_dev,
+static void pcmcia_bus_remove_socket(struct device *dev,
 				     struct class_interface *class_intf)
 {
-	struct pcmcia_socket *socket = class_get_devdata(class_dev);
+	struct pcmcia_socket *socket = dev_get_drvdata(dev);
 
 	if (!socket)
 		return;
@@ -1389,8 +1389,8 @@
 /* the pcmcia_bus_interface is used to handle pcmcia socket devices */
 static struct class_interface pcmcia_bus_interface = {
 	.class = &pcmcia_socket_class,
-	.add = &pcmcia_bus_add_socket,
-	.remove = &pcmcia_bus_remove_socket,
+	.add_dev = &pcmcia_bus_add_socket,
+	.remove_dev = &pcmcia_bus_remove_socket,
 };
 
 
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index c2ea07a..df21e2d 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -161,7 +161,7 @@
 	pci_set_drvdata(dev, &sockets[i].socket);
 
 	for (i = 0; i<socket_count; i++) {
-		sockets[i].socket.dev.dev = &dev->dev;
+		sockets[i].socket.dev.parent = &dev->dev;
 		sockets[i].socket.ops = &i82092aa_operations;
 		sockets[i].socket.resource_ops = &pccard_nonstatic_ops;
 		ret = pcmcia_register_socket(&sockets[i].socket);
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index ea74f98..72ff2f6 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -1298,7 +1298,7 @@
     
     /* register sockets with the pcmcia core */
     for (i = 0; i < sockets; i++) {
-	    socket[i].socket.dev.dev = &i82365_device->dev;
+	    socket[i].socket.dev.parent = &i82365_device->dev;
 	    socket[i].socket.ops = &pcic_operations;
 	    socket[i].socket.resource_ops = &pccard_nonstatic_ops;
 	    socket[i].socket.owner = THIS_MODULE;
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
index bbf0258..4dbef07 100644
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -722,7 +722,7 @@
 	/* Set up interrupt handler(s) */
 
 	for (i = 0 ; i < pcc_sockets ; i++) {
-		socket[i].socket.dev.dev = &pcc_device.dev;
+		socket[i].socket.dev.parent = &pcc_device.dev;
 		socket[i].socket.ops = &pcc_operations;
 		socket[i].socket.resource_ops = &pccard_static_ops;
 		socket[i].socket.owner = THIS_MODULE;
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index 327372b..8849414 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -59,7 +59,6 @@
 
 #ifdef DEBUG
 extern int ds_pc_debug;
-#define cs_socket_name(skt)    ((skt)->dev.class_id)
 
 #define ds_dbg(lvl, fmt, arg...) do {		\
 	if (ds_pc_debug >= lvl)				\
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index b9201c2..0ce39de 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -48,7 +48,6 @@
 
 #ifdef DEBUG
 extern int ds_pc_debug;
-#define cs_socket_name(skt)    ((skt)->dev.class_id)
 
 #define ds_dbg(skt, lvl, fmt, arg...) do {			\
 	if (ds_pc_debug >= lvl)					\
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index 360c248..dd0ddf1 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -682,7 +682,7 @@
 
 		socket[i].socket.ops = &pd6729_operations;
 		socket[i].socket.resource_ops = &pccard_nonstatic_ops;
-		socket[i].socket.dev.dev = &dev->dev;
+		socket[i].socket.dev.parent = &dev->dev;
 		socket[i].socket.driver_data = &socket[i];
 	}
 
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index c3176b1..bfcaad6 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -616,7 +616,7 @@
 static struct resource *nonstatic_find_io_region(unsigned long base, int num,
 		   unsigned long align, struct pcmcia_socket *s)
 {
-	struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id);
+	struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.bus_id);
 	struct socket_data *s_data = s->resource_data;
 	struct pcmcia_align_data data;
 	unsigned long min = base;
@@ -650,7 +650,7 @@
 static struct resource * nonstatic_find_mem_region(u_long base, u_long num,
 		u_long align, int low, struct pcmcia_socket *s)
 {
-	struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id);
+	struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.bus_id);
 	struct socket_data *s_data = s->resource_data;
 	struct pcmcia_align_data data;
 	unsigned long min, max;
@@ -897,9 +897,10 @@
 
 /* sysfs interface to the resource database */
 
-static ssize_t show_io_db(struct class_device *class_dev, char *buf)
+static ssize_t show_io_db(struct device *dev,
+			  struct device_attribute *attr, char *buf)
 {
-	struct pcmcia_socket *s = class_get_devdata(class_dev);
+	struct pcmcia_socket *s = dev_get_drvdata(dev);
 	struct socket_data *data;
 	struct resource_map *p;
 	ssize_t ret = 0;
@@ -920,9 +921,11 @@
 	return (ret);
 }
 
-static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size_t count)
+static ssize_t store_io_db(struct device *dev,
+			   struct device_attribute *attr,
+			   const char *buf, size_t count)
 {
-	struct pcmcia_socket *s = class_get_devdata(class_dev);
+	struct pcmcia_socket *s = dev_get_drvdata(dev);
 	unsigned long start_addr, end_addr;
 	unsigned int add = ADD_MANAGED_RESOURCE;
 	ssize_t ret = 0;
@@ -947,11 +950,12 @@
 
 	return ret ? ret : count;
 }
-static CLASS_DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
+static DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
 
-static ssize_t show_mem_db(struct class_device *class_dev, char *buf)
+static ssize_t show_mem_db(struct device *dev,
+			   struct device_attribute *attr, char *buf)
 {
-	struct pcmcia_socket *s = class_get_devdata(class_dev);
+	struct pcmcia_socket *s = dev_get_drvdata(dev);
 	struct socket_data *data;
 	struct resource_map *p;
 	ssize_t ret = 0;
@@ -972,9 +976,11 @@
 	return (ret);
 }
 
-static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, size_t count)
+static ssize_t store_mem_db(struct device *dev,
+			    struct device_attribute *attr,
+			    const char *buf, size_t count)
 {
-	struct pcmcia_socket *s = class_get_devdata(class_dev);
+	struct pcmcia_socket *s = dev_get_drvdata(dev);
 	unsigned long start_addr, end_addr;
 	unsigned int add = ADD_MANAGED_RESOURCE;
 	ssize_t ret = 0;
@@ -999,25 +1005,25 @@
 
 	return ret ? ret : count;
 }
-static CLASS_DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
+static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
 
-static struct class_device_attribute *pccard_rsrc_attributes[] = {
-	&class_device_attr_available_resources_io,
-	&class_device_attr_available_resources_mem,
+static struct device_attribute *pccard_rsrc_attributes[] = {
+	&dev_attr_available_resources_io,
+	&dev_attr_available_resources_mem,
 	NULL,
 };
 
-static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev,
+static int __devinit pccard_sysfs_add_rsrc(struct device *dev,
 					   struct class_interface *class_intf)
 {
-	struct pcmcia_socket *s = class_get_devdata(class_dev);
-	struct class_device_attribute **attr;
+	struct pcmcia_socket *s = dev_get_drvdata(dev);
+	struct device_attribute **attr;
 	int ret = 0;
 	if (s->resource_ops != &pccard_nonstatic_ops)
 		return 0;
 
 	for (attr = pccard_rsrc_attributes; *attr; attr++) {
-		ret = class_device_create_file(class_dev, *attr);
+		ret = device_create_file(dev, *attr);
 		if (ret)
 			break;
 	}
@@ -1025,23 +1031,23 @@
 	return ret;
 }
 
-static void __devexit pccard_sysfs_remove_rsrc(struct class_device *class_dev,
+static void __devexit pccard_sysfs_remove_rsrc(struct device *dev,
 					       struct class_interface *class_intf)
 {
-	struct pcmcia_socket *s = class_get_devdata(class_dev);
-	struct class_device_attribute **attr;
+	struct pcmcia_socket *s = dev_get_drvdata(dev);
+	struct device_attribute **attr;
 
 	if (s->resource_ops != &pccard_nonstatic_ops)
 		return;
 
 	for (attr = pccard_rsrc_attributes; *attr; attr++)
-		class_device_remove_file(class_dev, *attr);
+		device_remove_file(dev, *attr);
 }
 
 static struct class_interface pccard_rsrc_interface = {
 	.class = &pcmcia_socket_class,
-	.add = &pccard_sysfs_add_rsrc,
-	.remove = __devexit_p(&pccard_sysfs_remove_rsrc),
+	.add_dev = &pccard_sysfs_add_rsrc,
+	.remove_dev = __devexit_p(&pccard_sysfs_remove_rsrc),
 };
 
 static int __init nonstatic_sysfs_init(void)
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index e433704..d2a3bea 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -478,10 +478,10 @@
  *
  * Returns: the number of characters added to the buffer
  */
-static ssize_t show_status(struct class_device *class_dev, char *buf)
+static ssize_t show_status(struct device *dev, char *buf)
 {
 	struct soc_pcmcia_socket *skt =
-		container_of(class_dev, struct soc_pcmcia_socket, socket.dev);
+		container_of(dev, struct soc_pcmcia_socket, socket.dev);
 	char *p = buf;
 
 	p+=sprintf(p, "slot     : %d\n", skt->nr);
@@ -747,7 +747,7 @@
 
 		add_timer(&skt->poll_timer);
 
-		class_device_create_file(&skt->socket.dev, &class_device_attr_status);
+		device_create_file(&skt->socket.dev, &device_attr_status);
 	}
 
 	dev_set_drvdata(dev, sinfo);
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index b005602..ea5765c 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -40,7 +40,8 @@
 
 #define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev)
 
-static ssize_t pccard_show_type(struct class_device *dev, char *buf)
+static ssize_t pccard_show_type(struct device *dev, struct device_attribute *attr,
+				char *buf)
 {
 	struct pcmcia_socket *s = to_socket(dev);
 
@@ -50,9 +51,10 @@
 		return sprintf(buf, "32-bit\n");
 	return sprintf(buf, "16-bit\n");
 }
-static CLASS_DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL);
+static DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL);
 
-static ssize_t pccard_show_voltage(struct class_device *dev, char *buf)
+static ssize_t pccard_show_voltage(struct device *dev, struct device_attribute *attr,
+				   char *buf)
 {
 	struct pcmcia_socket *s = to_socket(dev);
 
@@ -63,28 +65,31 @@
 			       s->socket.Vcc % 10);
 	return sprintf(buf, "X.XV\n");
 }
-static CLASS_DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL);
+static DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL);
 
-static ssize_t pccard_show_vpp(struct class_device *dev, char *buf)
+static ssize_t pccard_show_vpp(struct device *dev, struct device_attribute *attr,
+			       char *buf)
 {
 	struct pcmcia_socket *s = to_socket(dev);
 	if (!(s->state & SOCKET_PRESENT))
 		return -ENODEV;
 	return sprintf(buf, "%d.%dV\n", s->socket.Vpp / 10, s->socket.Vpp % 10);
 }
-static CLASS_DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL);
+static DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL);
 
-static ssize_t pccard_show_vcc(struct class_device *dev, char *buf)
+static ssize_t pccard_show_vcc(struct device *dev, struct device_attribute *attr,
+			       char *buf)
 {
 	struct pcmcia_socket *s = to_socket(dev);
 	if (!(s->state & SOCKET_PRESENT))
 		return -ENODEV;
 	return sprintf(buf, "%d.%dV\n", s->socket.Vcc / 10, s->socket.Vcc % 10);
 }
-static CLASS_DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL);
+static DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL);
 
 
-static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_insert(struct device *dev, struct device_attribute *attr,
+				   const char *buf, size_t count)
 {
 	ssize_t ret;
 	struct pcmcia_socket *s = to_socket(dev);
@@ -96,16 +101,20 @@
 
 	return ret ? ret : count;
 }
-static CLASS_DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert);
+static DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert);
 
 
-static ssize_t pccard_show_card_pm_state(struct class_device *dev, char *buf)
+static ssize_t pccard_show_card_pm_state(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
 {
 	struct pcmcia_socket *s = to_socket(dev);
 	return sprintf(buf, "%s\n", s->state & SOCKET_SUSPEND ? "off" : "on");
 }
 
-static ssize_t pccard_store_card_pm_state(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_card_pm_state(struct device *dev,
+					  struct device_attribute *attr,
+					  const char *buf, size_t count)
 {
 	ssize_t ret = -EINVAL;
 	struct pcmcia_socket *s = to_socket(dev);
@@ -120,9 +129,11 @@
 
 	return ret ? -ENODEV : count;
 }
-static CLASS_DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state);
+static DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state);
 
-static ssize_t pccard_store_eject(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_eject(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
 {
 	ssize_t ret;
 	struct pcmcia_socket *s = to_socket(dev);
@@ -134,16 +145,20 @@
 
 	return ret ? ret : count;
 }
-static CLASS_DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject);
+static DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject);
 
 
-static ssize_t pccard_show_irq_mask(struct class_device *dev, char *buf)
+static ssize_t pccard_show_irq_mask(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
 {
 	struct pcmcia_socket *s = to_socket(dev);
 	return sprintf(buf, "0x%04x\n", s->irq_mask);
 }
 
-static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_irq_mask(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
 {
 	ssize_t ret;
 	struct pcmcia_socket *s = to_socket(dev);
@@ -161,16 +176,19 @@
 
 	return ret ? ret : count;
 }
-static CLASS_DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask);
+static DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask);
 
 
-static ssize_t pccard_show_resource(struct class_device *dev, char *buf)
+static ssize_t pccard_show_resource(struct device *dev,
+				    struct device_attribute *attr, char *buf)
 {
 	struct pcmcia_socket *s = to_socket(dev);
 	return sprintf(buf, "%s\n", s->resource_setup_done ? "yes" : "no");
 }
 
-static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_resource(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
 {
 	unsigned long flags;
 	struct pcmcia_socket *s = to_socket(dev);
@@ -196,7 +214,7 @@
 
 	return count;
 }
-static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
+static DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
 
 
 static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count)
@@ -279,7 +297,7 @@
 		if (off + count > size)
 			count = size - off;
 
-		s = to_socket(container_of(kobj, struct class_device, kobj));
+		s = to_socket(container_of(kobj, struct device, kobj));
 
 		if (!(s->state & SOCKET_PRESENT))
 			return -ENODEV;
@@ -296,7 +314,7 @@
 
 static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count)
 {
-	struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj));
+	struct pcmcia_socket *s = to_socket(container_of(kobj, struct device, kobj));
 	cisdump_t *cis;
 	int error;
 
@@ -335,16 +353,16 @@
 }
 
 
-static struct class_device_attribute *pccard_socket_attributes[] = {
-	&class_device_attr_card_type,
-	&class_device_attr_card_voltage,
-	&class_device_attr_card_vpp,
-	&class_device_attr_card_vcc,
-	&class_device_attr_card_insert,
-	&class_device_attr_card_pm_state,
-	&class_device_attr_card_eject,
-	&class_device_attr_card_irq_mask,
-	&class_device_attr_available_resources_setup_done,
+static struct device_attribute *pccard_socket_attributes[] = {
+	&dev_attr_card_type,
+	&dev_attr_card_voltage,
+	&dev_attr_card_vpp,
+	&dev_attr_card_vcc,
+	&dev_attr_card_insert,
+	&dev_attr_card_pm_state,
+	&dev_attr_card_eject,
+	&dev_attr_card_irq_mask,
+	&dev_attr_available_resources_setup_done,
 	NULL,
 };
 
@@ -355,35 +373,35 @@
 	.write = pccard_store_cis,
 };
 
-static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev,
+static int __devinit pccard_sysfs_add_socket(struct device *dev,
 					     struct class_interface *class_intf)
 {
-	struct class_device_attribute **attr;
+	struct device_attribute **attr;
 	int ret = 0;
 
 	for (attr = pccard_socket_attributes; *attr; attr++) {
-		ret = class_device_create_file(class_dev, *attr);
+		ret = device_create_file(dev, *attr);
 		if (ret)
 			break;
 	}
 	if (!ret)
-		ret = sysfs_create_bin_file(&class_dev->kobj, &pccard_cis_attr);
+		ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
 
 	return ret;
 }
 
-static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev,
+static void __devexit pccard_sysfs_remove_socket(struct device *dev,
 						 struct class_interface *class_intf)
 {
-	struct class_device_attribute **attr;
+	struct device_attribute **attr;
 
-	sysfs_remove_bin_file(&class_dev->kobj, &pccard_cis_attr);
+	sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr);
 	for (attr = pccard_socket_attributes; *attr; attr++)
-		class_device_remove_file(class_dev, *attr);
+		device_remove_file(dev, *attr);
 }
 
 struct class_interface pccard_sysfs_interface = {
 	.class = &pcmcia_socket_class,
-	.add = &pccard_sysfs_add_socket,
-	.remove = __devexit_p(&pccard_sysfs_remove_socket),
+	.add_dev = &pccard_sysfs_add_socket,
+	.remove_dev = __devexit_p(&pccard_sysfs_remove_socket),
 };
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index 2d2f415..c158cf3 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -512,7 +512,7 @@
     for (i = 0; i < sockets; i++) {
 	    socket_table[i].socket.ops = &tcic_operations;
 	    socket_table[i].socket.resource_ops = &pccard_nonstatic_ops;
-	    socket_table[i].socket.dev.dev = &tcic_device.dev;
+	    socket_table[i].socket.dev.parent = &tcic_device.dev;
 	    ret = pcmcia_register_socket(&socket_table[i].socket);
 	    if (ret && i)
 		    pcmcia_unregister_socket(&socket_table[0].socket);
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index da471bd..a61d768 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -1104,7 +1104,7 @@
 	/* prepare pcmcia_socket */
 	socket->socket.ops = &yenta_socket_operations;
 	socket->socket.resource_ops = &pccard_nonstatic_ops;
-	socket->socket.dev.dev = &dev->dev;
+	socket->socket.dev.parent = &dev->dev;
 	socket->socket.driver_data = socket;
 	socket->socket.owner = THIS_MODULE;
 	socket->socket.features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD;
diff --git a/drivers/pnp/pnpacpi/Kconfig b/drivers/pnp/pnpacpi/Kconfig
index b185417..ad27e5e 100644
--- a/drivers/pnp/pnpacpi/Kconfig
+++ b/drivers/pnp/pnpacpi/Kconfig
@@ -2,8 +2,8 @@
 # Plug and Play ACPI configuration
 #
 config PNPACPI
-	bool "Plug and Play ACPI support (EXPERIMENTAL)"
-	depends on PNP && ACPI && EXPERIMENTAL
+	bool "Plug and Play ACPI support"
+	depends on PNP && ACPI
 	default y
 	---help---
 	  Linux uses the PNPACPI to autodetect built-in
diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c
index d42015c..2065e74 100644
--- a/drivers/pnp/system.c
+++ b/drivers/pnp/system.c
@@ -3,7 +3,8 @@
  *
  * Some code is based on pnpbios_core.c
  * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
- *
+ * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
+ *	Bjorn Helgaas <bjorn.helgaas@hp.com>
  */
 
 #include <linux/pnp.h>
@@ -21,18 +22,21 @@
 	{	"",			0	}
 };
 
-static void reserve_ioport_range(char *pnpid, int start, int end)
+static void reserve_range(char *pnpid, int start, int end, int port)
 {
 	struct resource *res;
 	char *regionid;
 
 	regionid = kmalloc(16, GFP_KERNEL);
-	if ( regionid == NULL )
+	if (regionid == NULL)
 		return;
 	snprintf(regionid, 16, "pnp %s", pnpid);
-	res = request_region(start,end-start+1,regionid);
-	if ( res == NULL )
-		kfree( regionid );
+	if (port)
+		res = request_region(start,end-start+1,regionid);
+	else
+		res = request_mem_region(start,end-start+1,regionid);
+	if (res == NULL)
+		kfree(regionid);
 	else
 		res->flags &= ~IORESOURCE_BUSY;
 	/*
@@ -41,26 +45,20 @@
 	 * have double reservations.
 	 */
 	printk(KERN_INFO
-		"pnp: %s: ioport range 0x%x-0x%x %s reserved\n",
-		pnpid, start, end,
-		NULL != res ? "has been" : "could not be"
-	);
-
-	return;
+		"pnp: %s: %s range 0x%x-0x%x %s reserved\n",
+		pnpid, port ? "ioport" : "iomem", start, end,
+		NULL != res ? "has been" : "could not be");
 }
 
-static void reserve_resources_of_dev( struct pnp_dev *dev )
+static void reserve_resources_of_dev(struct pnp_dev *dev)
 {
 	int i;
 
-	for (i=0;i<PNP_MAX_PORT;i++) {
+	for (i = 0; i < PNP_MAX_PORT; i++) {
 		if (!pnp_port_valid(dev, i))
-			/* end of resources */
 			continue;
 		if (pnp_port_start(dev, i) == 0)
-			/* disabled */
-			/* Do nothing */
-			continue;
+			continue;	/* disabled */
 		if (pnp_port_start(dev, i) < 0x100)
 			/*
 			 * Below 0x100 is only standard PC hardware
@@ -72,14 +70,18 @@
 			 */
 			continue;
 		if (pnp_port_end(dev, i) < pnp_port_start(dev, i))
-			/* invalid endpoint */
-			/* Do nothing */
+			continue;	/* invalid */
+
+		reserve_range(dev->dev.bus_id, pnp_port_start(dev, i),
+			pnp_port_end(dev, i), 1);
+	}
+
+	for (i = 0; i < PNP_MAX_MEM; i++) {
+		if (!pnp_mem_valid(dev, i))
 			continue;
-		reserve_ioport_range(
-			dev->dev.bus_id,
-			pnp_port_start(dev, i),
-			pnp_port_end(dev, i)
-		);
+
+		reserve_range(dev->dev.bus_id, pnp_mem_start(dev, i),
+			pnp_mem_end(dev, i), 0);
 	}
 
 	return;
diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile
index 8433eb7..d547cf5 100644
--- a/drivers/ps3/Makefile
+++ b/drivers/ps3/Makefile
@@ -1,2 +1 @@
-obj-y += system-bus.o
 obj-$(CONFIG_PS3_VUART) += vuart.o
diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c
index 6974f65..a72da8f 100644
--- a/drivers/ps3/vuart.c
+++ b/drivers/ps3/vuart.c
@@ -783,8 +783,8 @@
 
 	vuart_private.in_use++;
 	if (vuart_private.in_use == 1) {
-		result = ps3_alloc_vuart_irq((void*)&vuart_private.bmp.status,
-			&vuart_private.virq);
+		result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY,
+			(void*)&vuart_private.bmp.status, &vuart_private.virq);
 
 		if (result) {
 			dev_dbg(&dev->core,
diff --git a/drivers/ps3/vuart.h b/drivers/ps3/vuart.h
index 28fd89f..11c421c 100644
--- a/drivers/ps3/vuart.h
+++ b/drivers/ps3/vuart.h
@@ -21,37 +21,6 @@
 #if !defined(_PS3_VUART_H)
 #define _PS3_VUART_H
 
-struct ps3_vuart_stats {
-	unsigned long bytes_written;
-	unsigned long bytes_read;
-	unsigned long tx_interrupts;
-	unsigned long rx_interrupts;
-	unsigned long disconnect_interrupts;
-};
-
-/**
- * struct ps3_vuart_port_device - a device on a vuart port
- */
-
-struct ps3_vuart_port_device {
-	enum ps3_match_id match_id;
-	struct device core;
-
-	/* private driver variables */
-	unsigned int port_number;
-	unsigned long interrupt_mask;
-	struct {
-		spinlock_t lock;
-		struct list_head head;
-	} tx_list;
-	struct {
-		unsigned long bytes_held;
-		spinlock_t lock;
-		struct list_head head;
-	} rx_list;
-	struct ps3_vuart_stats stats;
-};
-
 /**
  * struct ps3_vuart_port_driver - a driver for a device on a vuart port
  */
@@ -68,9 +37,9 @@
 	/* int (*resume)(struct ps3_vuart_port_device *); */
 };
 
-int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev);
 int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv);
 void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv);
+
 int ps3_vuart_write(struct ps3_vuart_port_device *dev,
 	const void* buf, unsigned int bytes);
 int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
@@ -86,9 +55,4 @@
 	return container_of(_dev, struct ps3_vuart_port_device, core);
 }
 
-int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
-	unsigned int bytes);
-int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
-	unsigned int bytes);
-
 #endif
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 94d3df6..82f2ac8 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -305,7 +305,7 @@
 
 	case RTC_IRQP_READ:
 		if (ops->irq_set_freq)
-			err = put_user(rtc->irq_freq, (unsigned long *) arg);
+			err = put_user(rtc->irq_freq, (unsigned long __user *)uarg);
 		break;
 
 	case RTC_IRQP_SET:
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 4b72b8e..038118b 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -53,6 +53,25 @@
 #define PCF8563_SC_LV		0x80 /* low voltage */
 #define PCF8563_MO_C		0x80 /* century */
 
+struct pcf8563 {
+	struct i2c_client client;
+	/*
+	 * The meaning of MO_C bit varies by the chip type.
+	 * From PCF8563 datasheet: this bit is toggled when the years
+	 * register overflows from 99 to 00
+	 *   0 indicates the century is 20xx
+	 *   1 indicates the century is 19xx
+	 * From RTC8564 datasheet: this bit indicates change of
+	 * century. When the year digit data overflows from 99 to 00,
+	 * this bit is set. By presetting it to 0 while still in the
+	 * 20th century, it will be set in year 2000, ...
+	 * There seems no reliable way to know how the system use this
+	 * bit.  So let's do it heuristically, assuming we are live in
+	 * 1970...2069.
+	 */
+	int c_polarity;	/* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
+};
+
 static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind);
 static int pcf8563_detach(struct i2c_client *client);
 
@@ -62,6 +81,7 @@
  */
 static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
 {
+	struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
 	unsigned char buf[13] = { PCF8563_REG_ST1 };
 
 	struct i2c_msg msgs[] = {
@@ -94,8 +114,12 @@
 	tm->tm_mday = BCD2BIN(buf[PCF8563_REG_DM] & 0x3F);
 	tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;
 	tm->tm_mon = BCD2BIN(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
-	tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR])
-		+ (buf[PCF8563_REG_MO] & PCF8563_MO_C ? 0 : 100);
+	tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR]);
+	if (tm->tm_year < 70)
+		tm->tm_year += 100;	/* assume we are in 1970...2069 */
+	/* detect the polarity heuristically. see note above. */
+	pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ?
+		(tm->tm_year >= 100) : (tm->tm_year < 100);
 
 	dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
 		"mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -114,6 +138,7 @@
 
 static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
 {
+	struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
 	int i, err;
 	unsigned char buf[9];
 
@@ -135,7 +160,7 @@
 
 	/* year and century */
 	buf[PCF8563_REG_YR] = BIN2BCD(tm->tm_year % 100);
-	if (tm->tm_year < 100)
+	if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))
 		buf[PCF8563_REG_MO] |= PCF8563_MO_C;
 
 	buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
@@ -248,6 +273,7 @@
 
 static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind)
 {
+	struct pcf8563 *pcf8563;
 	struct i2c_client *client;
 	struct rtc_device *rtc;
 
@@ -260,11 +286,12 @@
 		goto exit;
 	}
 
-	if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+	if (!(pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL))) {
 		err = -ENOMEM;
 		goto exit;
 	}
 
+	client = &pcf8563->client;
 	client->addr = address;
 	client->driver = &pcf8563_driver;
 	client->adapter	= adapter;
@@ -301,7 +328,7 @@
 	i2c_detach_client(client);
 
 exit_kfree:
-	kfree(client);
+	kfree(pcf8563);
 
 exit:
 	return err;
@@ -309,6 +336,7 @@
 
 static int pcf8563_detach(struct i2c_client *client)
 {
+	struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
 	int err;
 	struct rtc_device *rtc = i2c_get_clientdata(client);
 
@@ -318,7 +346,7 @@
 	if ((err = i2c_detach_client(client)))
 		return err;
 
-	kfree(client);
+	kfree(pcf8563);
 
 	return 0;
 }
diff --git a/drivers/s390/Kconfig b/drivers/s390/Kconfig
index ae89b9b..165af39 100644
--- a/drivers/s390/Kconfig
+++ b/drivers/s390/Kconfig
@@ -103,14 +103,8 @@
  	depends on TN3215_CONSOLE || TN3270_CONSOLE
  	default y
  
-config SCLP
-	bool "Support for SCLP"
-	help
-	  Include support for the SCLP interface to the service element.
-
 config SCLP_TTY
 	bool "Support for SCLP line mode terminal"
-	depends on SCLP
 	help
 	  Include support for IBM SCLP line-mode terminals.
 
@@ -123,7 +117,6 @@
 
 config SCLP_VT220_TTY
 	bool "Support for SCLP VT220-compatible terminal"
-	depends on SCLP
 	help
 	  Include support for an IBM SCLP VT220-compatible terminal.
 
@@ -136,7 +129,6 @@
 
 config SCLP_CPI
 	tristate "Control-Program Identification"
-	depends on SCLP
 	help
 	  This option enables the hardware console interface for system
 	  identification. This is commonly used for workload management and
diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile
index 9803c93..5a88870 100644
--- a/drivers/s390/Makefile
+++ b/drivers/s390/Makefile
@@ -2,6 +2,8 @@
 # Makefile for the S/390 specific device drivers
 #
 
+CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
+
 obj-y += s390mach.o sysinfo.o s390_rdev.o
 obj-y += cio/ block/ char/ crypto/ net/ scsi/
 
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 492b68b..eb5dc62 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -37,6 +37,7 @@
  */
 debug_info_t *dasd_debug_area;
 struct dasd_discipline *dasd_diag_discipline_pointer;
+void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
 
 MODULE_AUTHOR("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
 MODULE_DESCRIPTION("Linux on S/390 DASD device driver,"
@@ -51,7 +52,6 @@
 static void dasd_setup_queue(struct dasd_device * device);
 static void dasd_free_queue(struct dasd_device * device);
 static void dasd_flush_request_queue(struct dasd_device *);
-static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
 static int dasd_flush_ccw_queue(struct dasd_device *, int);
 static void dasd_tasklet(struct dasd_device *);
 static void do_kick_device(struct work_struct *);
@@ -483,7 +483,7 @@
 /*
  * Add profiling information for cqr before execution.
  */
-static inline void
+static void
 dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
 		   struct request *req)
 {
@@ -505,7 +505,7 @@
 /*
  * Add profiling information for cqr after execution.
  */
-static inline void
+static void
 dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
 		 struct request *req)
 {
@@ -1022,8 +1022,6 @@
 		 irb->scsw.cstat == 0 &&
 		 !irb->esw.esw0.erw.cons)
 		era = dasd_era_none;
-	else if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags))
- 	        era = dasd_era_fatal; /* don't recover this request */
 	else if (irb->esw.esw0.erw.cons)
 		era = device->discipline->examine_error(cqr, irb);
 	else
@@ -1104,7 +1102,7 @@
 /*
  * Process ccw request queue.
  */
-static inline void
+static void
 __dasd_process_ccw_queue(struct dasd_device * device,
 			 struct list_head *final_queue)
 {
@@ -1127,7 +1125,9 @@
 				cqr->status = DASD_CQR_FAILED;
 				cqr->stopclk = get_clock();
 			} else {
-				if (cqr->irb.esw.esw0.erw.cons) {
+				if (cqr->irb.esw.esw0.erw.cons &&
+				    test_bit(DASD_CQR_FLAGS_USE_ERP,
+					     &cqr->flags)) {
 					erp_fn = device->discipline->
 						erp_action(cqr);
 					erp_fn(cqr);
@@ -1181,7 +1181,7 @@
 /*
  * Fetch requests from the block device queue.
  */
-static inline void
+static void
 __dasd_process_blk_queue(struct dasd_device * device)
 {
 	request_queue_t *queue;
@@ -1232,6 +1232,19 @@
 		if (IS_ERR(cqr)) {
 			if (PTR_ERR(cqr) == -ENOMEM)
 				break;	/* terminate request queue loop */
+			if (PTR_ERR(cqr) == -EAGAIN) {
+				/*
+				 * The current request cannot be build right
+				 * now, we have to try later. If this request
+				 * is the head-of-queue we stop the device
+				 * for 1/2 second.
+				 */
+				if (!list_empty(&device->ccw_queue))
+					break;
+				device->stopped |= DASD_STOPPED_PENDING;
+				dasd_set_timer(device, HZ/2);
+				break;
+			}
 			DBF_DEV_EVENT(DBF_ERR, device,
 				      "CCW creation failed (rc=%ld) "
 				      "on request %p",
@@ -1254,7 +1267,7 @@
  * Take a look at the first request on the ccw queue and check
  * if it reached its expire time. If so, terminate the IO.
  */
-static inline void
+static void
 __dasd_check_expire(struct dasd_device * device)
 {
 	struct dasd_ccw_req *cqr;
@@ -1285,7 +1298,7 @@
  * Take a look at the first request on the ccw queue and check
  * if it needs to be started.
  */
-static inline void
+static void
 __dasd_start_head(struct dasd_device * device)
 {
 	struct dasd_ccw_req *cqr;
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 4d01040..8b9d68f 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -170,7 +170,6 @@
 	/* log the erp chain if fatal error occurred */
 	if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) {
 		dasd_log_sense(cqr, irb);
-		dasd_log_ccw(cqr, 0, irb->scsw.cpa);
 	}
 
 	return era;
@@ -2640,7 +2639,6 @@
 
 	struct dasd_ccw_req *erp = NULL;
 	struct dasd_device *device = cqr->device;
-	__u32 cpa = cqr->irb.scsw.cpa;
 	struct dasd_ccw_req *temp_erp = NULL;
 
 	if (device->features & DASD_FEATURE_ERPLOG) {
@@ -2706,9 +2704,6 @@
 		}
 	}
 
-	if (erp->status == DASD_CQR_FAILED)
-		dasd_log_ccw(erp, 1, cpa);
-
 	/* enqueue added ERP request */
 	if (erp->status == DASD_CQR_FILLED) {
 		erp->status = DASD_CQR_QUEUED;
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 5943266..ed70852 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -136,7 +136,7 @@
 /*
  * Read a device busid/devno from a string.
  */
-static inline int
+static int
 dasd_busid(char **str, int *id0, int *id1, int *devno)
 {
 	int val, old_style;
@@ -182,7 +182,7 @@
  * only one: "ro" for read-only devices. The default feature set
  * is empty (value 0).
  */
-static inline int
+static int
 dasd_feature_list(char *str, char **endp)
 {
 	int features, len, rc;
@@ -341,7 +341,7 @@
 	return ERR_PTR(-EINVAL);
 }
 
-static inline char *
+static char *
 dasd_parse_next_element( char *parsestring ) {
 	char * residual_str;
 	residual_str = dasd_parse_keyword(parsestring);
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 53db58a..ab782bb 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -43,7 +43,7 @@
 #define DIAG_MAX_RETRIES	32
 #define DIAG_TIMEOUT		50 * HZ
 
-struct dasd_discipline dasd_diag_discipline;
+static struct dasd_discipline dasd_diag_discipline;
 
 struct dasd_diag_private {
 	struct dasd_diag_characteristics rdc_data;
@@ -90,7 +90,7 @@
  * block offset. On success, return zero and set end_block to contain the
  * number of blocks on the device minus the specified offset. Return non-zero
  * otherwise. */
-static __inline__ int
+static inline int
 mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
 	     blocknum_t offset, blocknum_t *end_block)
 {
@@ -117,7 +117,7 @@
 
 /* Remove block I/O environment for device. Return zero on success, non-zero
  * otherwise. */
-static __inline__ int
+static inline int
 mdsk_term_io(struct dasd_device * device)
 {
 	struct dasd_diag_private *private;
@@ -576,7 +576,7 @@
 		    "dump sense not available for DIAG data");
 }
 
-struct dasd_discipline dasd_diag_discipline = {
+static struct dasd_discipline dasd_diag_discipline = {
 	.owner = THIS_MODULE,
 	.name = "DIAG",
 	.ebcname = "DIAG",
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index fdaa471..cecab22 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -134,44 +134,7 @@
 	return (d1 + (d2 - 1)) / d2;
 }
 
-static inline int
-bytes_per_record(struct dasd_eckd_characteristics *rdc, int kl, int dl)
-{
-	unsigned int fl1, fl2, int1, int2;
-	int bpr;
-
-	switch (rdc->formula) {
-	case 0x01:
-		fl1 = round_up_multiple(ECKD_F2(rdc) + dl, ECKD_F1(rdc));
-		fl2 = round_up_multiple(kl ? ECKD_F2(rdc) + kl : 0,
-					ECKD_F1(rdc));
-		bpr = fl1 + fl2;
-		break;
-	case 0x02:
-		int1 = ceil_quot(dl + ECKD_F6(rdc), ECKD_F5(rdc) << 1);
-		int2 = ceil_quot(kl + ECKD_F6(rdc), ECKD_F5(rdc) << 1);
-		fl1 = round_up_multiple(ECKD_F1(rdc) * ECKD_F2(rdc) + dl +
-					ECKD_F6(rdc) + ECKD_F4(rdc) * int1,
-					ECKD_F1(rdc));
-		fl2 = round_up_multiple(ECKD_F1(rdc) * ECKD_F3(rdc) + kl +
-					ECKD_F6(rdc) + ECKD_F4(rdc) * int2,
-					ECKD_F1(rdc));
-		bpr = fl1 + fl2;
-		break;
-	default:
-		bpr = 0;
-		break;
-	}
-	return bpr;
-}
-
-static inline unsigned int
-bytes_per_track(struct dasd_eckd_characteristics *rdc)
-{
-	return *(unsigned int *) (rdc->byte_per_track) >> 8;
-}
-
-static inline unsigned int
+static unsigned int
 recs_per_track(struct dasd_eckd_characteristics * rdc,
 	       unsigned int kl, unsigned int dl)
 {
@@ -204,37 +167,39 @@
 	return 0;
 }
 
-static inline void
+static int
 check_XRC (struct ccw1         *de_ccw,
            struct DE_eckd_data *data,
            struct dasd_device  *device)
 {
         struct dasd_eckd_private *private;
+	int rc;
 
         private = (struct dasd_eckd_private *) device->private;
+	if (!private->rdc_data.facilities.XRC_supported)
+		return 0;
 
         /* switch on System Time Stamp - needed for XRC Support */
-        if (private->rdc_data.facilities.XRC_supported) {
+	data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid'   */
+	data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
 
-                data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid'   */
-                data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
+	rc = get_sync_clock(&data->ep_sys_time);
+	/* Ignore return code if sync clock is switched off. */
+	if (rc == -ENOSYS || rc == -EACCES)
+		rc = 0;
 
-                data->ep_sys_time = get_clock ();
+	de_ccw->count = sizeof (struct DE_eckd_data);
+	de_ccw->flags |= CCW_FLAG_SLI;
+	return rc;
+}
 
-                de_ccw->count = sizeof (struct DE_eckd_data);
-		de_ccw->flags |= CCW_FLAG_SLI;
-        }
-
-        return;
-
-} /* end check_XRC */
-
-static inline void
+static int
 define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
 	      int totrk, int cmd, struct dasd_device * device)
 {
 	struct dasd_eckd_private *private;
 	struct ch_t geo, beg, end;
+	int rc = 0;
 
 	private = (struct dasd_eckd_private *) device->private;
 
@@ -263,12 +228,12 @@
 	case DASD_ECKD_CCW_WRITE_KD_MT:
 		data->mask.perm = 0x02;
 		data->attributes.operation = private->attrib.operation;
-                check_XRC (ccw, data, device);
+		rc = check_XRC (ccw, data, device);
 		break;
 	case DASD_ECKD_CCW_WRITE_CKD:
 	case DASD_ECKD_CCW_WRITE_CKD_MT:
 		data->attributes.operation = DASD_BYPASS_CACHE;
-                check_XRC (ccw, data, device);
+		rc = check_XRC (ccw, data, device);
 		break;
 	case DASD_ECKD_CCW_ERASE:
 	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
@@ -276,7 +241,7 @@
 		data->mask.perm = 0x3;
 		data->mask.auth = 0x1;
 		data->attributes.operation = DASD_BYPASS_CACHE;
-                check_XRC (ccw, data, device);
+		rc = check_XRC (ccw, data, device);
 		break;
 	default:
 		DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd);
@@ -312,9 +277,10 @@
 	data->beg_ext.head = beg.head;
 	data->end_ext.cyl = end.cyl;
 	data->end_ext.head = end.head;
+	return rc;
 }
 
-static inline void
+static void
 locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
 	      int rec_on_trk, int no_rec, int cmd,
 	      struct dasd_device * device, int reclen)
@@ -548,7 +514,7 @@
 /*
  * Build CP for Perform Subsystem Function - SSC.
  */
-struct dasd_ccw_req *
+static struct dasd_ccw_req *
 dasd_eckd_build_psf_ssc(struct dasd_device *device)
 {
        struct dasd_ccw_req *cqr;
@@ -1200,7 +1166,12 @@
 		return cqr;
 	ccw = cqr->cpaddr;
 	/* First ccw is define extent. */
-	define_extent(ccw++, cqr->data, first_trk, last_trk, cmd, device);
+	if (define_extent(ccw++, cqr->data, first_trk,
+			  last_trk, cmd, device) == -EAGAIN) {
+		/* Clock not in sync and XRC is enabled. Try again later. */
+		dasd_sfree_request(cqr, device);
+		return ERR_PTR(-EAGAIN);
+	}
 	/* Build locate_record+read/write/ccws. */
 	idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data));
 	LO_data = (struct LO_eckd_data *) (idaws + cidaw);
@@ -1380,7 +1351,7 @@
 	cqr->device = device;
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
-	cqr->retries = 0;
+	cqr->retries = 2;	/* set retry counter to enable basic ERP */
 	cqr->expires = 2 * HZ;
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
@@ -1420,7 +1391,7 @@
 	cqr->device = device;
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
-	cqr->retries = 0;
+	cqr->retries = 2;	/* set retry counter to enable basic ERP */
 	cqr->expires = 2 * HZ;
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
@@ -1459,7 +1430,7 @@
 	cqr->device = device;
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
-	cqr->retries = 0;
+	cqr->retries = 2;	/* set retry counter to enable basic ERP */
 	cqr->expires = 2 * HZ;
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
@@ -1609,7 +1580,7 @@
  * Dump the range of CCWs into 'page' buffer
  * and return number of printed chars.
  */
-static inline int
+static int
 dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
 {
 	int len, count;
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
index e0bf30e..6cedc91 100644
--- a/drivers/s390/block/dasd_eer.c
+++ b/drivers/s390/block/dasd_eer.c
@@ -658,18 +658,24 @@
 	.owner		= THIS_MODULE,
 };
 
-static struct miscdevice dasd_eer_dev = {
-	.minor	    = MISC_DYNAMIC_MINOR,
-	.name	    = "dasd_eer",
-	.fops	    = &dasd_eer_fops,
-};
+static struct miscdevice *dasd_eer_dev = NULL;
 
 int __init dasd_eer_init(void)
 {
 	int rc;
 
-	rc = misc_register(&dasd_eer_dev);
+	dasd_eer_dev = kzalloc(sizeof(*dasd_eer_dev), GFP_KERNEL);
+	if (!dasd_eer_dev)
+		return -ENOMEM;
+
+	dasd_eer_dev->minor = MISC_DYNAMIC_MINOR;
+	dasd_eer_dev->name  = "dasd_eer";
+	dasd_eer_dev->fops  = &dasd_eer_fops;
+
+	rc = misc_register(dasd_eer_dev);
 	if (rc) {
+		kfree(dasd_eer_dev);
+		dasd_eer_dev = NULL;
 		MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
 		       "register misc device");
 		return rc;
@@ -680,5 +686,9 @@
 
 void dasd_eer_exit(void)
 {
-	WARN_ON(misc_deregister(&dasd_eer_dev) != 0);
+	if (dasd_eer_dev) {
+		WARN_ON(misc_deregister(dasd_eer_dev) != 0);
+		kfree(dasd_eer_dev);
+		dasd_eer_dev = NULL;
+	}
 }
diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c
index 58a6509..caa5d91 100644
--- a/drivers/s390/block/dasd_erp.c
+++ b/drivers/s390/block/dasd_erp.c
@@ -152,25 +152,6 @@
 
 }				/* end default_erp_postaction */
 
-/*
- * Print the hex dump of the memory used by a request. This includes
- * all error recovery ccws that have been chained in from of the
- * real request.
- */
-static inline void
-hex_dump_memory(struct dasd_device *device, void *data, int len)
-{
-	int *pint;
-
-	pint = (int *) data;
-	while (len > 0) {
-		DEV_MESSAGE(KERN_ERR, device, "%p: %08x %08x %08x %08x",
-			    pint, pint[0], pint[1], pint[2], pint[3]);
-		pint += 4;
-		len -= 16;
-	}
-}
-
 void
 dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
 {
@@ -182,69 +163,8 @@
 		device->discipline->dump_sense(device, cqr, irb);
 }
 
-void
-dasd_log_ccw(struct dasd_ccw_req * cqr, int caller, __u32 cpa)
-{
-	struct dasd_device *device;
-	struct dasd_ccw_req *lcqr;
-	struct ccw1 *ccw;
-	int cplength;
-
-	device = cqr->device;
-	/* log the channel program */
-	for (lcqr = cqr; lcqr != NULL; lcqr = lcqr->refers) {
-		DEV_MESSAGE(KERN_ERR, device,
-			    "(%s) ERP chain report for req: %p",
-			    caller == 0 ? "EXAMINE" : "ACTION", lcqr);
-		hex_dump_memory(device, lcqr, sizeof(struct dasd_ccw_req));
-
-		cplength = 1;
-		ccw = lcqr->cpaddr;
-		while (ccw++->flags & (CCW_FLAG_DC | CCW_FLAG_CC))
-			cplength++;
-
-		if (cplength > 40) {	/* log only parts of the CP */
-			DEV_MESSAGE(KERN_ERR, device, "%s",
-				    "Start of channel program:");
-			hex_dump_memory(device, lcqr->cpaddr,
-					40*sizeof(struct ccw1));
-
-			DEV_MESSAGE(KERN_ERR, device, "%s",
-				    "End of channel program:");
-			hex_dump_memory(device, lcqr->cpaddr + cplength - 10,
-					10*sizeof(struct ccw1));
-		} else {	/* log the whole CP */
-			DEV_MESSAGE(KERN_ERR, device, "%s",
-				    "Channel program (complete):");
-			hex_dump_memory(device, lcqr->cpaddr,
-					cplength*sizeof(struct ccw1));
-		}
-
-		if (lcqr != cqr)
-			continue;
-
-		/*
-		 * Log bytes arround failed CCW but only if we did
-		 * not log the whole CP of the CCW is outside the
-		 * logged CP.
-		 */
-		if (cplength > 40 ||
-		    ((addr_t) cpa < (addr_t) lcqr->cpaddr &&
-		     (addr_t) cpa > (addr_t) (lcqr->cpaddr + cplength + 4))) {
-
-			DEV_MESSAGE(KERN_ERR, device,
-				    "Failed CCW (%p) (area):",
-				    (void *) (long) cpa);
-			hex_dump_memory(device, cqr->cpaddr - 10,
-					20*sizeof(struct ccw1));
-		}
-	}
-
-}				/* end log_erp_chain */
-
 EXPORT_SYMBOL(dasd_default_erp_action);
 EXPORT_SYMBOL(dasd_default_erp_postaction);
 EXPORT_SYMBOL(dasd_alloc_erp_request);
 EXPORT_SYMBOL(dasd_free_erp_request);
 EXPORT_SYMBOL(dasd_log_sense);
-EXPORT_SYMBOL(dasd_log_ccw);
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index b857fd5..be0909e 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -75,7 +75,7 @@
 	.notify      = dasd_generic_notify,
 };
 
-static inline void
+static void
 define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
 	      int blksize, int beg, int nr)
 {
@@ -95,7 +95,7 @@
 	data->ext_end = nr - 1;
 }
 
-static inline void
+static void
 locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
 	      int block_nr, int block_ct)
 {
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index d163632..47ba446 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -147,7 +147,7 @@
 	 */
 	memset(&bpart, 0, sizeof(struct blkpg_partition));
 	memset(&barg, 0, sizeof(struct blkpg_ioctl_arg));
-	barg.data = (void __user *) &bpart;
+	barg.data = (void __force __user *) &bpart;
 	barg.op = BLKPG_DEL_PARTITION;
 	for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
 		ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg);
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index fb725e3..a2cc69e 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -559,7 +559,6 @@
 					    struct dasd_device *);
 void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *);
 void dasd_log_sense(struct dasd_ccw_req *, struct irb *);
-void dasd_log_ccw(struct dasd_ccw_req *, int, __u32);
 
 /* externals in dasd_3370_erp.c */
 dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *);
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index bfa010f..8b7e118 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -28,7 +28,7 @@
 static struct proc_dir_entry *dasd_devices_entry = NULL;
 static struct proc_dir_entry *dasd_statistics_entry = NULL;
 
-static inline char *
+static char *
 dasd_get_user_string(const char __user *user_buf, size_t user_len)
 {
 	char *buffer;
@@ -154,7 +154,7 @@
 	.release	= seq_release,
 };
 
-static inline int
+static int
 dasd_calc_metrics(char *page, char **start, off_t off,
 		  int count, int *eof, int len)
 {
@@ -167,8 +167,8 @@
 	return len;
 }
 
-static inline char *
-dasd_statistics_array(char *str, int *array, int shift)
+static char *
+dasd_statistics_array(char *str, unsigned int *array, int shift)
 {
 	int i;
 
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index be9b053..1340451 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -102,7 +102,7 @@
  * device needs to be enqueued before the semaphore is
  * freed.
  */
-static inline int
+static int
 dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info)
 {
 	int minor, found;
@@ -230,7 +230,7 @@
 					   SEGMENT_SHARED);
 		if (rc < 0) {
 			BUG_ON(rc == -EINVAL);
-			if (rc == -EIO || rc == -ENOENT)
+			if (rc != -EAGAIN)
 				goto removeseg;
 		} else {
 			dev_info->is_shared = 1;
@@ -253,7 +253,7 @@
 					   SEGMENT_EXCLUSIVE);
 		if (rc < 0) {
 			BUG_ON(rc == -EINVAL);
-			if (rc == -EIO || rc == -ENOENT)
+			if (rc != -EAGAIN)
 				goto removeseg;
 		} else {
 			dev_info->is_shared = 0;
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index c3e97b4..293e667 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -2,7 +2,8 @@
 # S/390 character devices
 #
 
-obj-y += ctrlchar.o keyboard.o defkeymap.o
+obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
+	 sclp_info.o
 
 obj-$(CONFIG_TN3270) += raw3270.o
 obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
@@ -11,7 +12,6 @@
 
 obj-$(CONFIG_TN3215) += con3215.o
 
-obj-$(CONFIG_SCLP) += sclp.o sclp_rw.o sclp_quiesce.o
 obj-$(CONFIG_SCLP_TTY) += sclp_tty.o
 obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o
 obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 25b5d7a..9a328f1 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -1121,7 +1121,7 @@
  * 3215 tty registration code called from tty_init().
  * Most kernel services (incl. kmalloc) are available at this poimt.
  */
-int __init
+static int __init
 tty3215_init(void)
 {
 	struct tty_driver *driver;
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index 7566be8..8e7f2d7 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -69,8 +69,7 @@
 /*
  * Setup timeout for a device. On timeout trigger an update.
  */
-void
-con3270_set_timer(struct con3270 *cp, int expires)
+static void con3270_set_timer(struct con3270 *cp, int expires)
 {
 	if (expires == 0) {
 		if (timer_pending(&cp->timer))
diff --git a/drivers/s390/char/defkeymap.c b/drivers/s390/char/defkeymap.c
index 17027d9..564baca 100644
--- a/drivers/s390/char/defkeymap.c
+++ b/drivers/s390/char/defkeymap.c
@@ -5,6 +5,8 @@
 #include <linux/types.h>
 #include <linux/keyboard.h>
 #include <linux/kd.h>
+#include <linux/kbd_kern.h>
+#include <linux/kbd_diacr.h>
 
 u_short plain_map[NR_KEYS] = {
 	0xf000,	0xf000,	0xf000,	0xf000,	0xf000,	0xf000,	0xf000,	0xf000,
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index 0893d30..e1a7462 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -23,7 +23,7 @@
 #include "raw3270.h"
 #include "ctrlchar.h"
 
-struct raw3270_fn fs3270_fn;
+static struct raw3270_fn fs3270_fn;
 
 struct fs3270 {
 	struct raw3270_view view;
@@ -401,7 +401,7 @@
 }
 
 /* View to a 3270 device. Can be console, tty or fullscreen. */
-struct raw3270_fn fs3270_fn = {
+static struct raw3270_fn fs3270_fn = {
 	.activate = fs3270_activate,
 	.deactivate = fs3270_deactivate,
 	.intv = (void *) fs3270_irq,
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
index 3e86fd1..f62f9a4 100644
--- a/drivers/s390/char/keyboard.c
+++ b/drivers/s390/char/keyboard.c
@@ -148,6 +148,7 @@
 	}
 }
 
+#if 0
 /*
  * Generate ebcdic -> ascii translation table from kbd_data.
  */
@@ -173,6 +174,7 @@
 		}
 	}
 }
+#endif
 
 /*
  * We have a combining character DIACR here, followed by the character CH.
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c
index a138b15..3a1a958 100644
--- a/drivers/s390/char/monreader.c
+++ b/drivers/s390/char/monreader.c
@@ -3,7 +3,7 @@
  *
  * Character device driver for reading z/VM *MONITOR service records.
  *
- * Copyright (C) 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH.
  *
  * Author: Gerald Schaefer <geraldsc@de.ibm.com>
  */
@@ -22,7 +22,7 @@
 #include <asm/ebcdic.h>
 #include <asm/extmem.h>
 #include <linux/poll.h>
-#include "../net/iucv.h"
+#include <net/iucv/iucv.h>
 
 
 //#define MON_DEBUG			/* Debug messages on/off */
@@ -50,14 +50,13 @@
 struct mon_msg {
 	u32 pos;
 	u32 mca_offset;
-	iucv_MessagePending local_eib;
+	struct iucv_message msg;
 	char msglim_reached;
 	char replied_msglim;
 };
 
 struct mon_private {
-	u16 pathid;
-	iucv_handle_t iucv_handle;
+	struct iucv_path *path;
 	struct mon_msg *msg_array[MON_MSGLIM];
 	unsigned int   write_index;
 	unsigned int   read_index;
@@ -75,8 +74,6 @@
 static DECLARE_WAIT_QUEUE_HEAD(mon_read_wait_queue);
 static DECLARE_WAIT_QUEUE_HEAD(mon_conn_wait_queue);
 
-static u8 iucv_host[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
 static u8 user_data_connect[16] = {
 	/* Version code, must be 0x01 for shared mode */
 	0x01,
@@ -100,8 +97,7 @@
  * Create the 8 bytes EBCDIC DCSS segment name from
  * an ASCII name, incl. padding
  */
-static inline void
-dcss_mkname(char *ascii_name, char *ebcdic_name)
+static inline void dcss_mkname(char *ascii_name, char *ebcdic_name)
 {
 	int i;
 
@@ -119,8 +115,7 @@
  * print appropriate error message for segment_load()/segment_type()
  * return code
  */
-static void
-mon_segment_warn(int rc, char* seg_name)
+static void mon_segment_warn(int rc, char* seg_name)
 {
 	switch (rc) {
 	case -ENOENT:
@@ -166,44 +161,37 @@
 	}
 }
 
-static inline unsigned long
-mon_mca_start(struct mon_msg *monmsg)
+static inline unsigned long mon_mca_start(struct mon_msg *monmsg)
 {
-	return monmsg->local_eib.ln1msg1.iprmmsg1_u32;
+	return *(u32 *) &monmsg->msg.rmmsg;
 }
 
-static inline unsigned long
-mon_mca_end(struct mon_msg *monmsg)
+static inline unsigned long mon_mca_end(struct mon_msg *monmsg)
 {
-	return monmsg->local_eib.ln1msg2.ipbfln1f;
+	return *(u32 *) &monmsg->msg.rmmsg[4];
 }
 
-static inline u8
-mon_mca_type(struct mon_msg *monmsg, u8 index)
+static inline u8 mon_mca_type(struct mon_msg *monmsg, u8 index)
 {
 	return *((u8 *) mon_mca_start(monmsg) + monmsg->mca_offset + index);
 }
 
-static inline u32
-mon_mca_size(struct mon_msg *monmsg)
+static inline u32 mon_mca_size(struct mon_msg *monmsg)
 {
 	return mon_mca_end(monmsg) - mon_mca_start(monmsg) + 1;
 }
 
-static inline u32
-mon_rec_start(struct mon_msg *monmsg)
+static inline u32 mon_rec_start(struct mon_msg *monmsg)
 {
 	return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 4));
 }
 
-static inline u32
-mon_rec_end(struct mon_msg *monmsg)
+static inline u32 mon_rec_end(struct mon_msg *monmsg)
 {
 	return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 8));
 }
 
-static inline int
-mon_check_mca(struct mon_msg *monmsg)
+static inline int mon_check_mca(struct mon_msg *monmsg)
 {
 	if ((mon_rec_end(monmsg) <= mon_rec_start(monmsg)) ||
 	    (mon_rec_start(monmsg) < mon_dcss_start) ||
@@ -221,20 +209,17 @@
 	return 0;
 }
 
-static inline int
-mon_send_reply(struct mon_msg *monmsg, struct mon_private *monpriv)
+static inline int mon_send_reply(struct mon_msg *monmsg,
+				 struct mon_private *monpriv)
 {
-	u8 prmmsg[8];
 	int rc;
 
 	P_DEBUG("read, REPLY: pathid = 0x%04X, msgid = 0x%08X, trgcls = "
 		"0x%08X\n\n",
-		monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid,
-		monmsg->local_eib.iptrgcls);
-	rc = iucv_reply_prmmsg(monmsg->local_eib.ippathid,
-				monmsg->local_eib.ipmsgid,
-				monmsg->local_eib.iptrgcls,
-				0, prmmsg);
+		monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class);
+
+	rc = iucv_message_reply(monpriv->path, &monmsg->msg,
+				IUCV_IPRMDATA, NULL, 0);
 	atomic_dec(&monpriv->msglim_count);
 	if (likely(!monmsg->msglim_reached)) {
 		monmsg->pos = 0;
@@ -251,10 +236,19 @@
 	return 0;
 }
 
-static inline struct mon_private *
-mon_alloc_mem(void)
+static inline void mon_free_mem(struct mon_private *monpriv)
 {
-	int i,j;
+	int i;
+
+	for (i = 0; i < MON_MSGLIM; i++)
+		if (monpriv->msg_array[i])
+			kfree(monpriv->msg_array[i]);
+	kfree(monpriv);
+}
+
+static inline struct mon_private *mon_alloc_mem(void)
+{
+	int i;
 	struct mon_private *monpriv;
 
 	monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL);
@@ -267,16 +261,15 @@
 						    GFP_KERNEL);
 		if (!monpriv->msg_array[i]) {
 			P_ERROR("open, no memory for msg_array\n");
-			for (j = 0; j < i; j++)
-				kfree(monpriv->msg_array[j]);
+			mon_free_mem(monpriv);
 			return NULL;
 		}
 	}
 	return monpriv;
 }
 
-static inline void
-mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv)
+static inline void mon_read_debug(struct mon_msg *monmsg,
+				  struct mon_private *monpriv)
 {
 #ifdef MON_DEBUG
 	u8 msg_type[2], mca_type;
@@ -284,7 +277,7 @@
 
 	records_len = mon_rec_end(monmsg) - mon_rec_start(monmsg) + 1;
 
-	memcpy(msg_type, &monmsg->local_eib.iptrgcls, 2);
+	memcpy(msg_type, &monmsg->msg.class, 2);
 	EBCASC(msg_type, 2);
 	mca_type = mon_mca_type(monmsg, 0);
 	EBCASC(&mca_type, 1);
@@ -292,8 +285,7 @@
 	P_DEBUG("read, mon_read_index = %i, mon_write_index = %i\n",
 		monpriv->read_index, monpriv->write_index);
 	P_DEBUG("read, pathid = 0x%04X, msgid = 0x%08X, trgcls = 0x%08X\n",
-		monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid,
-		monmsg->local_eib.iptrgcls);
+		monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class);
 	P_DEBUG("read, msg_type = '%c%c', mca_type = '%c' / 0x%X / 0x%X\n",
 		msg_type[0], msg_type[1], mca_type ? mca_type : 'X',
 		mon_mca_type(monmsg, 1), mon_mca_type(monmsg, 2));
@@ -306,8 +298,7 @@
 #endif
 }
 
-static inline void
-mon_next_mca(struct mon_msg *monmsg)
+static inline void mon_next_mca(struct mon_msg *monmsg)
 {
 	if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12))
 		return;
@@ -316,8 +307,7 @@
 	monmsg->pos = 0;
 }
 
-static inline struct mon_msg *
-mon_next_message(struct mon_private *monpriv)
+static inline struct mon_msg *mon_next_message(struct mon_private *monpriv)
 {
 	struct mon_msg *monmsg;
 
@@ -342,39 +332,37 @@
 /******************************************************************************
  *                               IUCV handler                                 *
  *****************************************************************************/
-static void
-mon_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data)
+static void mon_iucv_path_complete(struct iucv_path *path, u8 ipuser[16])
 {
-	struct mon_private *monpriv = (struct mon_private *) pgm_data;
+	struct mon_private *monpriv = path->private;
 
 	P_DEBUG("IUCV connection completed\n");
 	P_DEBUG("IUCV ACCEPT (from *MONITOR): Version = 0x%02X, Event = "
 		"0x%02X, Sample = 0x%02X\n",
-		eib->ipuser[0], eib->ipuser[1], eib->ipuser[2]);
+		ipuser[0], ipuser[1], ipuser[2]);
 	atomic_set(&monpriv->iucv_connected, 1);
 	wake_up(&mon_conn_wait_queue);
 }
 
-static void
-mon_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data)
+static void mon_iucv_path_severed(struct iucv_path *path, u8 ipuser[16])
 {
-	struct mon_private *monpriv = (struct mon_private *) pgm_data;
+	struct mon_private *monpriv = path->private;
 
-	P_ERROR("IUCV connection severed with rc = 0x%X\n",
-		(u8) eib->ipuser[0]);
+	P_ERROR("IUCV connection severed with rc = 0x%X\n", ipuser[0]);
+	iucv_path_sever(path, NULL);
 	atomic_set(&monpriv->iucv_severed, 1);
 	wake_up(&mon_conn_wait_queue);
 	wake_up_interruptible(&mon_read_wait_queue);
 }
 
-static void
-mon_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data)
+static void mon_iucv_message_pending(struct iucv_path *path,
+				     struct iucv_message *msg)
 {
-	struct mon_private *monpriv = (struct mon_private *) pgm_data;
+	struct mon_private *monpriv = path->private;
 
 	P_DEBUG("IUCV message pending\n");
-	memcpy(&monpriv->msg_array[monpriv->write_index]->local_eib, eib,
-	       sizeof(iucv_MessagePending));
+	memcpy(&monpriv->msg_array[monpriv->write_index]->msg,
+	       msg, sizeof(*msg));
 	if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) {
 		P_WARNING("IUCV message pending, message limit (%i) reached\n",
 			  MON_MSGLIM);
@@ -385,54 +373,45 @@
 	wake_up_interruptible(&mon_read_wait_queue);
 }
 
-static iucv_interrupt_ops_t mon_iucvops = {
-	.ConnectionComplete = mon_iucv_ConnectionComplete,
-	.ConnectionSevered  = mon_iucv_ConnectionSevered,
-	.MessagePending     = mon_iucv_MessagePending,
+static struct iucv_handler monreader_iucv_handler = {
+	.path_complete	 = mon_iucv_path_complete,
+	.path_severed	 = mon_iucv_path_severed,
+	.message_pending = mon_iucv_message_pending,
 };
 
 /******************************************************************************
  *                               file operations                              *
  *****************************************************************************/
-static int
-mon_open(struct inode *inode, struct file *filp)
+static int mon_open(struct inode *inode, struct file *filp)
 {
-	int rc, i;
 	struct mon_private *monpriv;
+	int rc;
 
 	/*
 	 * only one user allowed
 	 */
+	rc = -EBUSY;
 	if (test_and_set_bit(MON_IN_USE, &mon_in_use))
-		return -EBUSY;
+		goto out;
 
+	rc = -ENOMEM;
 	monpriv = mon_alloc_mem();
 	if (!monpriv)
-		return -ENOMEM;
+		goto out_use;
 
 	/*
-	 * Register with IUCV and connect to *MONITOR service
+	 * Connect to *MONITOR service
 	 */
-	monpriv->iucv_handle = iucv_register_program("my_monreader    ",
-							MON_SERVICE,
-							NULL,
-							&mon_iucvops,
-							monpriv);
-	if (!monpriv->iucv_handle) {
-		P_ERROR("failed to register with iucv driver\n");
-		rc = -EIO;
-		goto out_error;
-	}
-	P_INFO("open, registered with IUCV\n");
-
-	rc = iucv_connect(&monpriv->pathid, MON_MSGLIM, user_data_connect,
-			  MON_SERVICE, iucv_host, IPRMDATA, NULL, NULL,
-			  monpriv->iucv_handle, NULL);
+	monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL);
+	if (!monpriv->path)
+		goto out_priv;
+	rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler,
+			       MON_SERVICE, NULL, user_data_connect, monpriv);
 	if (rc) {
 		P_ERROR("iucv connection to *MONITOR failed with "
 			"IPUSER SEVER code = %i\n", rc);
 		rc = -EIO;
-		goto out_unregister;
+		goto out_path;
 	}
 	/*
 	 * Wait for connection confirmation
@@ -444,24 +423,23 @@
 		atomic_set(&monpriv->iucv_severed, 0);
 		atomic_set(&monpriv->iucv_connected, 0);
 		rc = -EIO;
-		goto out_unregister;
+		goto out_path;
 	}
 	P_INFO("open, established connection to *MONITOR service\n\n");
 	filp->private_data = monpriv;
 	return nonseekable_open(inode, filp);
 
-out_unregister:
-	iucv_unregister_program(monpriv->iucv_handle);
-out_error:
-	for (i = 0; i < MON_MSGLIM; i++)
-		kfree(monpriv->msg_array[i]);
-	kfree(monpriv);
+out_path:
+	kfree(monpriv->path);
+out_priv:
+	mon_free_mem(monpriv);
+out_use:
 	clear_bit(MON_IN_USE, &mon_in_use);
+out:
 	return rc;
 }
 
-static int
-mon_close(struct inode *inode, struct file *filp)
+static int mon_close(struct inode *inode, struct file *filp)
 {
 	int rc, i;
 	struct mon_private *monpriv = filp->private_data;
@@ -469,18 +447,12 @@
 	/*
 	 * Close IUCV connection and unregister
 	 */
-	rc = iucv_sever(monpriv->pathid, user_data_sever);
+	rc = iucv_path_sever(monpriv->path, user_data_sever);
 	if (rc)
 		P_ERROR("close, iucv_sever failed with rc = %i\n", rc);
 	else
 		P_INFO("close, terminated connection to *MONITOR service\n");
 
-	rc = iucv_unregister_program(monpriv->iucv_handle);
-	if (rc)
-		P_ERROR("close, iucv_unregister failed with rc = %i\n", rc);
-	else
-		P_INFO("close, unregistered with IUCV\n");
-
 	atomic_set(&monpriv->iucv_severed, 0);
 	atomic_set(&monpriv->iucv_connected, 0);
 	atomic_set(&monpriv->read_ready, 0);
@@ -495,8 +467,8 @@
 	return 0;
 }
 
-static ssize_t
-mon_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
+static ssize_t mon_read(struct file *filp, char __user *data,
+			size_t count, loff_t *ppos)
 {
 	struct mon_private *monpriv = filp->private_data;
 	struct mon_msg *monmsg;
@@ -563,8 +535,7 @@
 	return count;
 }
 
-static unsigned int
-mon_poll(struct file *filp, struct poll_table_struct *p)
+static unsigned int mon_poll(struct file *filp, struct poll_table_struct *p)
 {
 	struct mon_private *monpriv = filp->private_data;
 
@@ -593,8 +564,7 @@
 /******************************************************************************
  *                              module init/exit                              *
  *****************************************************************************/
-static int __init
-mon_init(void)
+static int __init mon_init(void)
 {
 	int rc;
 
@@ -603,22 +573,34 @@
 		return -ENODEV;
 	}
 
+	/*
+	 * Register with IUCV and connect to *MONITOR service
+	 */
+	rc = iucv_register(&monreader_iucv_handler, 1);
+	if (rc) {
+		P_ERROR("failed to register with iucv driver\n");
+		return rc;
+	}
+	P_INFO("open, registered with IUCV\n");
+
 	rc = segment_type(mon_dcss_name);
 	if (rc < 0) {
 		mon_segment_warn(rc, mon_dcss_name);
-		return rc;
+		goto out_iucv;
 	}
 	if (rc != SEG_TYPE_SC) {
 		P_ERROR("segment %s has unsupported type, should be SC\n",
 			mon_dcss_name);
-		return -EINVAL;
+		rc = -EINVAL;
+		goto out_iucv;
 	}
 
 	rc = segment_load(mon_dcss_name, SEGMENT_SHARED,
 			  &mon_dcss_start, &mon_dcss_end);
 	if (rc < 0) {
 		mon_segment_warn(rc, mon_dcss_name);
-		return -EINVAL;
+		rc = -EINVAL;
+		goto out_iucv;
 	}
 	dcss_mkname(mon_dcss_name, &user_data_connect[8]);
 
@@ -634,14 +616,16 @@
 
 out:
 	segment_unload(mon_dcss_name);
+out_iucv:
+	iucv_unregister(&monreader_iucv_handler, 1);
 	return rc;
 }
 
-static void __exit
-mon_exit(void)
+static void __exit mon_exit(void)
 {
 	segment_unload(mon_dcss_name);
 	WARN_ON(misc_deregister(&mon_dev) != 0);
+	iucv_unregister(&monreader_iucv_handler, 1);
 	return;
 }
 
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
index cdb24f5..9e451ac 100644
--- a/drivers/s390/char/monwriter.c
+++ b/drivers/s390/char/monwriter.c
@@ -67,8 +67,8 @@
 	return -EINVAL;
 }
 
-static inline struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
-						struct monwrite_hdr *monhdr)
+static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
+					 struct monwrite_hdr *monhdr)
 {
 	struct mon_buf *entry, *next;
 
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 7a84014..8facd14 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -29,7 +29,7 @@
 #include <linux/device.h>
 #include <linux/mutex.h>
 
-struct class *class3270;
+static struct class *class3270;
 
 /* The main 3270 data structure. */
 struct raw3270 {
@@ -86,7 +86,7 @@
 /*
  * Encode array for 12 bit 3270 addresses.
  */
-unsigned char raw3270_ebcgraf[64] =	{
+static unsigned char raw3270_ebcgraf[64] =	{
 	0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
 	0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
 	0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index 8a056df..f171de3 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -59,7 +59,8 @@
 /* Internal state: is a request active at the sclp? */
 static volatile enum sclp_running_state_t {
 	sclp_running_state_idle,
-	sclp_running_state_running
+	sclp_running_state_running,
+	sclp_running_state_reset_pending
 } sclp_running_state = sclp_running_state_idle;
 
 /* Internal state: is a read request pending? */
@@ -88,15 +89,15 @@
 
 /* Timeout intervals in seconds.*/
 #define SCLP_BUSY_INTERVAL	10
-#define SCLP_RETRY_INTERVAL	15
+#define SCLP_RETRY_INTERVAL	30
 
 static void sclp_process_queue(void);
 static int sclp_init_mask(int calculate);
 static int sclp_init(void);
 
 /* Perform service call. Return 0 on success, non-zero otherwise. */
-static int
-service_call(sclp_cmdw_t command, void *sccb)
+int
+sclp_service_call(sclp_cmdw_t command, void *sccb)
 {
 	int cc;
 
@@ -113,19 +114,17 @@
 	return 0;
 }
 
-/* Request timeout handler. Restart the request queue. If DATA is non-zero,
- * force restart of running request. */
-static void
-sclp_request_timeout(unsigned long data)
-{
-	unsigned long flags;
+static inline void __sclp_make_read_req(void);
 
-	if (data) {
-		spin_lock_irqsave(&sclp_lock, flags);
-		sclp_running_state = sclp_running_state_idle;
-		spin_unlock_irqrestore(&sclp_lock, flags);
+static void
+__sclp_queue_read_req(void)
+{
+	if (sclp_reading_state == sclp_reading_state_idle) {
+		sclp_reading_state = sclp_reading_state_reading;
+		__sclp_make_read_req();
+		/* Add request to head of queue */
+		list_add(&sclp_read_req.list, &sclp_req_queue);
 	}
-	sclp_process_queue();
 }
 
 /* Set up request retry timer. Called while sclp_lock is locked. */
@@ -140,6 +139,29 @@
 	add_timer(&sclp_request_timer);
 }
 
+/* Request timeout handler. Restart the request queue. If DATA is non-zero,
+ * force restart of running request. */
+static void
+sclp_request_timeout(unsigned long data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sclp_lock, flags);
+	if (data) {
+		if (sclp_running_state == sclp_running_state_running) {
+			/* Break running state and queue NOP read event request
+			 * to get a defined interface state. */
+			__sclp_queue_read_req();
+			sclp_running_state = sclp_running_state_idle;
+		}
+	} else {
+		__sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ,
+					 sclp_request_timeout, 0);
+	}
+	spin_unlock_irqrestore(&sclp_lock, flags);
+	sclp_process_queue();
+}
+
 /* Try to start a request. Return zero if the request was successfully
  * started or if it will be started at a later time. Return non-zero otherwise.
  * Called while sclp_lock is locked. */
@@ -151,7 +173,7 @@
 	if (sclp_running_state != sclp_running_state_idle)
 		return 0;
 	del_timer(&sclp_request_timer);
-	rc = service_call(req->command, req->sccb);
+	rc = sclp_service_call(req->command, req->sccb);
 	req->start_count++;
 
 	if (rc == 0) {
@@ -191,7 +213,15 @@
 		rc = __sclp_start_request(req);
 		if (rc == 0)
 			break;
-		/* Request failed. */
+		/* Request failed */
+		if (req->start_count > 1) {
+			/* Cannot abort already submitted request - could still
+			 * be active at the SCLP */
+			__sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ,
+						 sclp_request_timeout, 0);
+			break;
+		}
+		/* Post-processing for aborted request */
 		list_del(&req->list);
 		if (req->callback) {
 			spin_unlock_irqrestore(&sclp_lock, flags);
@@ -221,7 +251,8 @@
 	list_add_tail(&req->list, &sclp_req_queue);
 	rc = 0;
 	/* Start if request is first in list */
-	if (req->list.prev == &sclp_req_queue) {
+	if (sclp_running_state == sclp_running_state_idle &&
+	    req->list.prev == &sclp_req_queue) {
 		rc = __sclp_start_request(req);
 		if (rc)
 			list_del(&req->list);
@@ -294,7 +325,7 @@
 	sccb = (struct sccb_header *) sclp_read_sccb;
 	clear_page(sccb);
 	memset(&sclp_read_req, 0, sizeof(struct sclp_req));
-	sclp_read_req.command = SCLP_CMDW_READDATA;
+	sclp_read_req.command = SCLP_CMDW_READ_EVENT_DATA;
 	sclp_read_req.status = SCLP_REQ_QUEUED;
 	sclp_read_req.start_count = 0;
 	sclp_read_req.callback = sclp_read_cb;
@@ -334,6 +365,8 @@
 	finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
 	evbuf_pending = S390_lowcore.ext_params & 0x3;
 	if (finished_sccb) {
+		del_timer(&sclp_request_timer);
+		sclp_running_state = sclp_running_state_reset_pending;
 		req = __sclp_find_req(finished_sccb);
 		if (req) {
 			/* Request post-processing */
@@ -348,13 +381,8 @@
 		sclp_running_state = sclp_running_state_idle;
 	}
 	if (evbuf_pending && sclp_receive_mask != 0 &&
-	    sclp_reading_state == sclp_reading_state_idle &&
-	    sclp_activation_state == sclp_activation_state_active ) {
-		sclp_reading_state = sclp_reading_state_reading;
-		__sclp_make_read_req();
-		/* Add request to head of queue */
-		list_add(&sclp_read_req.list, &sclp_req_queue);
-	}
+	    sclp_activation_state == sclp_activation_state_active)
+		__sclp_queue_read_req();
 	spin_unlock(&sclp_lock);
 	sclp_process_queue();
 }
@@ -374,6 +402,7 @@
 	unsigned long flags;
 	unsigned long cr0, cr0_sync;
 	u64 timeout;
+	int irq_context;
 
 	/* We'll be disabling timer interrupts, so we need a custom timeout
 	 * mechanism */
@@ -386,7 +415,9 @@
 	}
 	local_irq_save(flags);
 	/* Prevent bottom half from executing once we force interrupts open */
-	local_bh_disable();
+	irq_context = in_interrupt();
+	if (!irq_context)
+		local_bh_disable();
 	/* Enable service-signal interruption, disable timer interrupts */
 	trace_hardirqs_on();
 	__ctl_store(cr0, 0, 0);
@@ -402,19 +433,19 @@
 		    get_clock() > timeout &&
 		    del_timer(&sclp_request_timer))
 			sclp_request_timer.function(sclp_request_timer.data);
-		barrier();
 		cpu_relax();
 	}
 	local_irq_disable();
 	__ctl_load(cr0, 0, 0);
-	_local_bh_enable();
+	if (!irq_context)
+		_local_bh_enable();
 	local_irq_restore(flags);
 }
 
 EXPORT_SYMBOL(sclp_sync_wait);
 
 /* Dispatch changes in send and receive mask to registered listeners. */
-static inline void
+static void
 sclp_dispatch_state_change(void)
 {
 	struct list_head *l;
@@ -597,7 +628,7 @@
 	sccb = (struct init_sccb *) sclp_init_sccb;
 	clear_page(sccb);
 	memset(&sclp_init_req, 0, sizeof(struct sclp_req));
-	sclp_init_req.command = SCLP_CMDW_WRITEMASK;
+	sclp_init_req.command = SCLP_CMDW_WRITE_EVENT_MASK;
 	sclp_init_req.status = SCLP_REQ_FILLED;
 	sclp_init_req.start_count = 0;
 	sclp_init_req.callback = NULL;
@@ -800,7 +831,7 @@
 	for (retry = 0; retry <= SCLP_INIT_RETRY; retry++) {
 		__sclp_make_init_req(0, 0);
 		sccb = (struct init_sccb *) sclp_init_req.sccb;
-		rc = service_call(sclp_init_req.command, sccb);
+		rc = sclp_service_call(sclp_init_req.command, sccb);
 		if (rc == -EIO)
 			break;
 		sclp_init_req.status = SCLP_REQ_RUNNING;
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index 2c71d6e..7d29ab4 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -12,7 +12,7 @@
 
 #include <linux/types.h>
 #include <linux/list.h>
-
+#include <asm/sclp.h>
 #include <asm/ebcdic.h>
 
 /* maximum number of pages concerning our own memory management */
@@ -49,9 +49,11 @@
 
 typedef unsigned int sclp_cmdw_t;
 
-#define SCLP_CMDW_READDATA	0x00770005
-#define SCLP_CMDW_WRITEDATA	0x00760005
-#define SCLP_CMDW_WRITEMASK	0x00780005
+#define SCLP_CMDW_READ_EVENT_DATA	0x00770005
+#define SCLP_CMDW_WRITE_EVENT_DATA	0x00760005
+#define SCLP_CMDW_WRITE_EVENT_MASK	0x00780005
+#define SCLP_CMDW_READ_SCP_INFO		0x00020001
+#define SCLP_CMDW_READ_SCP_INFO_FORCED	0x00120001
 
 #define GDS_ID_MDSMU		0x1310
 #define GDS_ID_MDSRouteInfo	0x1311
@@ -66,13 +68,6 @@
 
 typedef u32 sccb_mask_t;	/* ATTENTION: assumes 32bit mask !!! */
 
-struct sccb_header {
-	u16	length;
-	u8	function_code;
-	u8	control_mask[3];
-	u16	response_code;
-} __attribute__((packed));
-
 struct gds_subvector {
 	u8	length;
 	u8	key;
@@ -131,6 +126,7 @@
 int sclp_remove_processed(struct sccb_header *sccb);
 int sclp_deactivate(void);
 int sclp_reactivate(void);
+int sclp_service_call(sclp_cmdw_t command, void *sccb);
 
 /* useful inlines */
 
diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c
index 86864f6..ead1043 100644
--- a/drivers/s390/char/sclp_con.c
+++ b/drivers/s390/char/sclp_con.c
@@ -66,7 +66,7 @@
 	} while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback));
 }
 
-static inline void
+static void
 sclp_conbuf_emit(void)
 {
 	struct sclp_buffer* buffer;
diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c
index 4f873ae..65aa2c8 100644
--- a/drivers/s390/char/sclp_cpi.c
+++ b/drivers/s390/char/sclp_cpi.c
@@ -169,7 +169,7 @@
 	}
 
 	/* prepare request data structure presented to SCLP driver */
-	req->command = SCLP_CMDW_WRITEDATA;
+	req->command = SCLP_CMDW_WRITE_EVENT_DATA;
 	req->sccb = sccb;
 	req->status = SCLP_REQ_FILLED;
 	req->callback = cpi_callback;
diff --git a/drivers/s390/char/sclp_info.c b/drivers/s390/char/sclp_info.c
new file mode 100644
index 0000000..7bcbe64
--- /dev/null
+++ b/drivers/s390/char/sclp_info.c
@@ -0,0 +1,57 @@
+/*
+ *  drivers/s390/char/sclp_info.c
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <asm/sclp.h>
+#include "sclp.h"
+
+struct sclp_readinfo_sccb s390_readinfo_sccb;
+
+void __init sclp_readinfo_early(void)
+{
+	sclp_cmdw_t command;
+	struct sccb_header *sccb;
+	int ret;
+
+	__ctl_set_bit(0, 9); /* enable service signal subclass mask */
+
+	sccb = &s390_readinfo_sccb.header;
+	command = SCLP_CMDW_READ_SCP_INFO_FORCED;
+	while (1) {
+		u16 response;
+
+		memset(&s390_readinfo_sccb, 0, sizeof(s390_readinfo_sccb));
+		sccb->length = sizeof(s390_readinfo_sccb);
+		sccb->control_mask[2] = 0x80;
+
+		ret = sclp_service_call(command, &s390_readinfo_sccb);
+
+		if (ret == -EIO)
+			goto out;
+		if (ret == -EBUSY)
+			continue;
+
+		__load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
+				PSW_MASK_WAIT | PSW_DEFAULT_KEY);
+		local_irq_disable();
+		barrier();
+
+		response = sccb->response_code;
+
+		if (response == 0x10)
+			break;
+
+		if (response != 0x1f0 || command == SCLP_CMDW_READ_SCP_INFO)
+			break;
+
+		command = SCLP_CMDW_READ_SCP_INFO;
+	}
+out:
+	__ctl_clear_bit(0, 9); /* disable service signal subclass mask */
+}
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
index 0c92d39..2486783 100644
--- a/drivers/s390/char/sclp_rw.c
+++ b/drivers/s390/char/sclp_rw.c
@@ -460,7 +460,7 @@
 		sccb->msg_buf.header.type = EvTyp_PMsgCmd;
 	else
 		return -ENOSYS;
-	buffer->request.command = SCLP_CMDW_WRITEDATA;
+	buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
 	buffer->request.status = SCLP_REQ_FILLED;
 	buffer->request.callback = sclp_writedata_callback;
 	buffer->request.callback_data = buffer;
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index 2d173e5..90536f6 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -721,7 +721,7 @@
 	.ioctl = sclp_tty_ioctl,
 };
 
-int __init
+static int __init
 sclp_tty_init(void)
 {
 	struct tty_driver *driver;
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index 723bf41..544f137 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -207,7 +207,7 @@
 		request->sclp_req.status = SCLP_REQ_FAILED;
 		return -EIO;
 	}
-	request->sclp_req.command = SCLP_CMDW_WRITEDATA;
+	request->sclp_req.command = SCLP_CMDW_WRITE_EVENT_DATA;
 	request->sclp_req.status = SCLP_REQ_FILLED;
 	request->sclp_req.callback = sclp_vt220_callback;
 	request->sclp_req.callback_data = (void *) request;
@@ -669,7 +669,7 @@
 /*
  * Register driver with SCLP and Linux and initialize internal tty structures.
  */
-int __init
+static int __init
 sclp_vt220_tty_init(void)
 {
 	struct tty_driver *driver;
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index c9f1c4c..bb4ff53 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -3,7 +3,7 @@
  *    tape device driver for 3480/3490E/3590 tapes.
  *
  *  S390 and zSeries version
- *    Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright IBM Corp. 2001,2006
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *		 Tuan Ngo-Anh <ngoanh@de.ibm.com>
  *		 Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -99,7 +99,11 @@
 	TO_DIS,		/* Tape display */
 	TO_ASSIGN,	/* Assign tape to channel path */
 	TO_UNASSIGN,	/* Unassign tape from channel path */
-	TO_SIZE		/* #entries in tape_op_t */
+	TO_CRYPT_ON,	/* Enable encrpytion */
+	TO_CRYPT_OFF,	/* Disable encrpytion */
+	TO_KEKL_SET,	/* Set KEK label */
+	TO_KEKL_QUERY,	/* Query KEK label */
+	TO_SIZE,	/* #entries in tape_op_t */
 };
 
 /* Forward declaration */
@@ -112,6 +116,7 @@
 	TAPE_REQUEST_IN_IO,	/* request is currently in IO */
 	TAPE_REQUEST_DONE,	/* request is completed. */
 	TAPE_REQUEST_CANCEL,	/* request should be canceled. */
+	TAPE_REQUEST_LONG_BUSY, /* request has to be restarted after long busy */
 };
 
 /* Tape CCW request */
@@ -164,10 +169,11 @@
  * The discipline irq function either returns an error code (<0) which
  * means that the request has failed with an error or one of the following:
  */
-#define TAPE_IO_SUCCESS 0	/* request successful */
-#define TAPE_IO_PENDING 1	/* request still running */
-#define TAPE_IO_RETRY	2	/* retry to current request */
-#define TAPE_IO_STOP	3	/* stop the running request */
+#define TAPE_IO_SUCCESS		0	/* request successful */
+#define TAPE_IO_PENDING		1	/* request still running */
+#define TAPE_IO_RETRY		2	/* retry to current request */
+#define TAPE_IO_STOP		3	/* stop the running request */
+#define TAPE_IO_LONG_BUSY	4	/* delay the running request */
 
 /* Char Frontend Data */
 struct tape_char_data {
@@ -242,6 +248,10 @@
 
 	/* Function to start or stop the next request later. */
 	struct delayed_work		tape_dnr;
+
+	/* Timer for long busy */
+	struct timer_list		lb_timeout;
+
 };
 
 /* Externals from tape_core.c */
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 9df912f..50f5eda 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -2,7 +2,7 @@
  *  drivers/s390/char/tape_3590.c
  *    tape device discipline for 3590 tapes.
  *
- *    Copyright (C) IBM Corp. 2001,2006
+ *    Copyright IBM Corp. 2001,2006
  *    Author(s): Stefan Bader <shbader@de.ibm.com>
  *		 Michael Holzheu <holzheu@de.ibm.com>
  *		 Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/bio.h>
+#include <asm/ebcdic.h>
 
 #define TAPE_DBF_AREA	tape_3590_dbf
 
@@ -30,7 +31,7 @@
  * - Read Device (buffered) log: BRA
  * - Read Library log:		 BRA
  * - Swap Devices:		 BRA
- * - Long Busy:			 BRA
+ * - Long Busy:			 implemented
  * - Special Intercept:		 BRA
  * - Read Alternate:		 implemented
  *******************************************************************/
@@ -94,6 +95,332 @@
 	[0xae] = "Subsystem environmental alert",
 };
 
+static int crypt_supported(struct tape_device *device)
+{
+	return TAPE390_CRYPT_SUPPORTED(TAPE_3590_CRYPT_INFO(device));
+}
+
+static int crypt_enabled(struct tape_device *device)
+{
+	return TAPE390_CRYPT_ON(TAPE_3590_CRYPT_INFO(device));
+}
+
+static void ext_to_int_kekl(struct tape390_kekl *in,
+			    struct tape3592_kekl *out)
+{
+	int i;
+
+	memset(out, 0, sizeof(*out));
+	if (in->type == TAPE390_KEKL_TYPE_HASH)
+		out->flags |= 0x40;
+	if (in->type_on_tape == TAPE390_KEKL_TYPE_HASH)
+		out->flags |= 0x80;
+	strncpy(out->label, in->label, 64);
+	for (i = strlen(in->label); i < sizeof(out->label); i++)
+		out->label[i] = ' ';
+	ASCEBC(out->label, sizeof(out->label));
+}
+
+static void int_to_ext_kekl(struct tape3592_kekl *in,
+			    struct tape390_kekl *out)
+{
+	memset(out, 0, sizeof(*out));
+	if(in->flags & 0x40)
+		out->type = TAPE390_KEKL_TYPE_HASH;
+	else
+		out->type = TAPE390_KEKL_TYPE_LABEL;
+	if(in->flags & 0x80)
+		out->type_on_tape = TAPE390_KEKL_TYPE_HASH;
+	else
+		out->type_on_tape = TAPE390_KEKL_TYPE_LABEL;
+	memcpy(out->label, in->label, sizeof(in->label));
+	EBCASC(out->label, sizeof(in->label));
+	strstrip(out->label);
+}
+
+static void int_to_ext_kekl_pair(struct tape3592_kekl_pair *in,
+				 struct tape390_kekl_pair *out)
+{
+	if (in->count == 0) {
+		out->kekl[0].type = TAPE390_KEKL_TYPE_NONE;
+		out->kekl[0].type_on_tape = TAPE390_KEKL_TYPE_NONE;
+		out->kekl[1].type = TAPE390_KEKL_TYPE_NONE;
+		out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE;
+	} else if (in->count == 1) {
+		int_to_ext_kekl(&in->kekl[0], &out->kekl[0]);
+		out->kekl[1].type = TAPE390_KEKL_TYPE_NONE;
+		out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE;
+	} else if (in->count == 2) {
+		int_to_ext_kekl(&in->kekl[0], &out->kekl[0]);
+		int_to_ext_kekl(&in->kekl[1], &out->kekl[1]);
+	} else {
+		printk("Invalid KEKL number: %d\n", in->count);
+		BUG();
+	}
+}
+
+static int check_ext_kekl(struct tape390_kekl *kekl)
+{
+	if (kekl->type == TAPE390_KEKL_TYPE_NONE)
+		goto invalid;
+	if (kekl->type > TAPE390_KEKL_TYPE_HASH)
+		goto invalid;
+	if (kekl->type_on_tape == TAPE390_KEKL_TYPE_NONE)
+		goto invalid;
+	if (kekl->type_on_tape > TAPE390_KEKL_TYPE_HASH)
+		goto invalid;
+	if ((kekl->type == TAPE390_KEKL_TYPE_HASH) &&
+	    (kekl->type_on_tape == TAPE390_KEKL_TYPE_LABEL))
+		goto invalid;
+
+	return 0;
+invalid:
+	return -EINVAL;
+}
+
+static int check_ext_kekl_pair(struct tape390_kekl_pair *kekls)
+{
+	if (check_ext_kekl(&kekls->kekl[0]))
+		goto invalid;
+	if (check_ext_kekl(&kekls->kekl[1]))
+		goto invalid;
+
+	return 0;
+invalid:
+	return -EINVAL;
+}
+
+/*
+ * Query KEKLs
+ */
+static int tape_3592_kekl_query(struct tape_device *device,
+				struct tape390_kekl_pair *ext_kekls)
+{
+	struct tape_request *request;
+	struct tape3592_kekl_query_order *order;
+	struct tape3592_kekl_query_data *int_kekls;
+	int rc;
+
+	DBF_EVENT(6, "tape3592_kekl_query\n");
+	int_kekls = kmalloc(sizeof(*int_kekls), GFP_KERNEL|GFP_DMA);
+	if (!int_kekls)
+		return -ENOMEM;
+	request = tape_alloc_request(2, sizeof(*order));
+	if (IS_ERR(request)) {
+		rc = PTR_ERR(request);
+		goto fail_malloc;
+	}
+	order = request->cpdata;
+	memset(order,0,sizeof(*order));
+	order->code = 0xe2;
+	order->max_count = 2;
+	request->op = TO_KEKL_QUERY;
+	tape_ccw_cc(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order);
+	tape_ccw_end(request->cpaddr + 1, READ_SS_DATA, sizeof(*int_kekls),
+		     int_kekls);
+	rc = tape_do_io(device, request);
+	if (rc)
+		goto fail_request;
+	int_to_ext_kekl_pair(&int_kekls->kekls, ext_kekls);
+
+	rc = 0;
+fail_request:
+	tape_free_request(request);
+fail_malloc:
+	kfree(int_kekls);
+	return rc;
+}
+
+/*
+ * IOCTL: Query KEKLs
+ */
+static int tape_3592_ioctl_kekl_query(struct tape_device *device,
+				      unsigned long arg)
+{
+	int rc;
+	struct tape390_kekl_pair *ext_kekls;
+
+	DBF_EVENT(6, "tape_3592_ioctl_kekl_query\n");
+	if (!crypt_supported(device))
+		return -ENOSYS;
+	if (!crypt_enabled(device))
+		return -EUNATCH;
+	ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL);
+	if (!ext_kekls)
+		return -ENOMEM;
+	rc = tape_3592_kekl_query(device, ext_kekls);
+	if (rc != 0)
+		goto fail;
+	if (copy_to_user((char __user *) arg, ext_kekls, sizeof(*ext_kekls))) {
+		rc = -EFAULT;
+		goto fail;
+	}
+	rc = 0;
+fail:
+	kfree(ext_kekls);
+	return rc;
+}
+
+static int tape_3590_mttell(struct tape_device *device, int mt_count);
+
+/*
+ * Set KEKLs
+ */
+static int tape_3592_kekl_set(struct tape_device *device,
+			      struct tape390_kekl_pair *ext_kekls)
+{
+	struct tape_request *request;
+	struct tape3592_kekl_set_order *order;
+
+	DBF_EVENT(6, "tape3592_kekl_set\n");
+	if (check_ext_kekl_pair(ext_kekls)) {
+		DBF_EVENT(6, "invalid kekls\n");
+		return -EINVAL;
+	}
+	if (tape_3590_mttell(device, 0) != 0)
+		return -EBADSLT;
+	request = tape_alloc_request(1, sizeof(*order));
+	if (IS_ERR(request))
+		return PTR_ERR(request);
+	order = request->cpdata;
+	memset(order, 0, sizeof(*order));
+	order->code = 0xe3;
+	order->kekls.count = 2;
+	ext_to_int_kekl(&ext_kekls->kekl[0], &order->kekls.kekl[0]);
+	ext_to_int_kekl(&ext_kekls->kekl[1], &order->kekls.kekl[1]);
+	request->op = TO_KEKL_SET;
+	tape_ccw_end(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order);
+
+	return tape_do_io_free(device, request);
+}
+
+/*
+ * IOCTL: Set KEKLs
+ */
+static int tape_3592_ioctl_kekl_set(struct tape_device *device,
+				    unsigned long arg)
+{
+	int rc;
+	struct tape390_kekl_pair *ext_kekls;
+
+	DBF_EVENT(6, "tape_3592_ioctl_kekl_set\n");
+	if (!crypt_supported(device))
+		return -ENOSYS;
+	if (!crypt_enabled(device))
+		return -EUNATCH;
+	ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL);
+	if (!ext_kekls)
+		return -ENOMEM;
+	if (copy_from_user(ext_kekls, (char __user *)arg, sizeof(*ext_kekls))) {
+		rc = -EFAULT;
+		goto out;
+	}
+	rc = tape_3592_kekl_set(device, ext_kekls);
+out:
+	kfree(ext_kekls);
+	return rc;
+}
+
+/*
+ * Enable encryption
+ */
+static int tape_3592_enable_crypt(struct tape_device *device)
+{
+	struct tape_request *request;
+	char *data;
+
+	DBF_EVENT(6, "tape_3592_enable_crypt\n");
+	if (!crypt_supported(device))
+		return -ENOSYS;
+	request = tape_alloc_request(2, 72);
+	if (IS_ERR(request))
+		return PTR_ERR(request);
+	data = request->cpdata;
+	memset(data,0,72);
+
+	data[0]       = 0x05;
+	data[36 + 0]  = 0x03;
+	data[36 + 1]  = 0x03;
+	data[36 + 4]  = 0x40;
+	data[36 + 6]  = 0x01;
+	data[36 + 14] = 0x2f;
+	data[36 + 18] = 0xc3;
+	data[36 + 35] = 0x72;
+	request->op = TO_CRYPT_ON;
+	tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data);
+	tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36);
+	return tape_do_io_free(device, request);
+}
+
+/*
+ * Disable encryption
+ */
+static int tape_3592_disable_crypt(struct tape_device *device)
+{
+	struct tape_request *request;
+	char *data;
+
+	DBF_EVENT(6, "tape_3592_disable_crypt\n");
+	if (!crypt_supported(device))
+		return -ENOSYS;
+	request = tape_alloc_request(2, 72);
+	if (IS_ERR(request))
+		return PTR_ERR(request);
+	data = request->cpdata;
+	memset(data,0,72);
+
+	data[0]       = 0x05;
+	data[36 + 0]  = 0x03;
+	data[36 + 1]  = 0x03;
+	data[36 + 35] = 0x32;
+
+	request->op = TO_CRYPT_OFF;
+	tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data);
+	tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36);
+
+	return tape_do_io_free(device, request);
+}
+
+/*
+ * IOCTL: Set encryption status
+ */
+static int tape_3592_ioctl_crypt_set(struct tape_device *device,
+				     unsigned long arg)
+{
+	struct tape390_crypt_info info;
+
+	DBF_EVENT(6, "tape_3592_ioctl_crypt_set\n");
+	if (!crypt_supported(device))
+		return -ENOSYS;
+	if (copy_from_user(&info, (char __user *)arg, sizeof(info)))
+		return -EFAULT;
+	if (info.status & ~TAPE390_CRYPT_ON_MASK)
+		return -EINVAL;
+	if (info.status & TAPE390_CRYPT_ON_MASK)
+		return tape_3592_enable_crypt(device);
+	else
+		return tape_3592_disable_crypt(device);
+}
+
+static int tape_3590_sense_medium(struct tape_device *device);
+
+/*
+ * IOCTL: Query enryption status
+ */
+static int tape_3592_ioctl_crypt_query(struct tape_device *device,
+				       unsigned long arg)
+{
+	DBF_EVENT(6, "tape_3592_ioctl_crypt_query\n");
+	if (!crypt_supported(device))
+		return -ENOSYS;
+	tape_3590_sense_medium(device);
+	if (copy_to_user((char __user *) arg, &TAPE_3590_CRYPT_INFO(device),
+		sizeof(TAPE_3590_CRYPT_INFO(device))))
+		return -EFAULT;
+	else
+		return 0;
+}
+
 /*
  * 3590 IOCTL Overload
  */
@@ -109,6 +436,14 @@
 
 		return tape_std_display(device, &disp);
 	}
+	case TAPE390_KEKL_SET:
+		return tape_3592_ioctl_kekl_set(device, arg);
+	case TAPE390_KEKL_QUERY:
+		return tape_3592_ioctl_kekl_query(device, arg);
+	case TAPE390_CRYPT_SET:
+		return tape_3592_ioctl_crypt_set(device, arg);
+	case TAPE390_CRYPT_QUERY:
+		return tape_3592_ioctl_crypt_query(device, arg);
 	default:
 		return -EINVAL;	/* no additional ioctls */
 	}
@@ -248,6 +583,12 @@
 	case TO_READ_ATTMSG:
 		tape_3590_read_attmsg(p->device);
 		break;
+	case TO_CRYPT_ON:
+		tape_3592_enable_crypt(p->device);
+		break;
+	case TO_CRYPT_OFF:
+		tape_3592_disable_crypt(p->device);
+		break;
 	default:
 		DBF_EVENT(3, "T3590: work handler undefined for "
 			  "operation 0x%02x\n", p->op);
@@ -365,6 +706,33 @@
 }
 #endif
 
+static void tape_3590_med_state_set(struct tape_device *device,
+				    struct tape_3590_med_sense *sense)
+{
+	struct tape390_crypt_info *c_info;
+
+	c_info = &TAPE_3590_CRYPT_INFO(device);
+
+	if (sense->masst == MSENSE_UNASSOCIATED) {
+		tape_med_state_set(device, MS_UNLOADED);
+		TAPE_3590_CRYPT_INFO(device).medium_status = 0;
+		return;
+	}
+	if (sense->masst != MSENSE_ASSOCIATED_MOUNT) {
+		PRINT_ERR("Unknown medium state: %x\n", sense->masst);
+		return;
+	}
+	tape_med_state_set(device, MS_LOADED);
+	c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK;
+	if (sense->flags & MSENSE_CRYPT_MASK) {
+		PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags);
+		c_info->medium_status |= TAPE390_MEDIUM_ENCRYPTED_MASK;
+	} else	{
+		DBF_EVENT(6, "Medium is not encrypted %04x\n", sense->flags);
+		c_info->medium_status &= ~TAPE390_MEDIUM_ENCRYPTED_MASK;
+	}
+}
+
 /*
  * The done handler is called at device/channel end and wakes up the sleeping
  * process
@@ -372,9 +740,10 @@
 static int
 tape_3590_done(struct tape_device *device, struct tape_request *request)
 {
-	struct tape_3590_med_sense *sense;
+	struct tape_3590_disc_data *disc_data;
 
 	DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]);
+	disc_data = device->discdata;
 
 	switch (request->op) {
 	case TO_BSB:
@@ -394,13 +763,20 @@
 		break;
 	case TO_RUN:
 		tape_med_state_set(device, MS_UNLOADED);
+		tape_3590_schedule_work(device, TO_CRYPT_OFF);
 		break;
 	case TO_MSEN:
-		sense = (struct tape_3590_med_sense *) request->cpdata;
-		if (sense->masst == MSENSE_UNASSOCIATED)
-			tape_med_state_set(device, MS_UNLOADED);
-		if (sense->masst == MSENSE_ASSOCIATED_MOUNT)
-			tape_med_state_set(device, MS_LOADED);
+		tape_3590_med_state_set(device, request->cpdata);
+		break;
+	case TO_CRYPT_ON:
+		TAPE_3590_CRYPT_INFO(device).status
+			|= TAPE390_CRYPT_ON_MASK;
+		*(device->modeset_byte) |= 0x03;
+		break;
+	case TO_CRYPT_OFF:
+		TAPE_3590_CRYPT_INFO(device).status
+			&= ~TAPE390_CRYPT_ON_MASK;
+		*(device->modeset_byte) &= ~0x03;
 		break;
 	case TO_RBI:	/* RBI seems to succeed even without medium loaded. */
 	case TO_NOP:	/* Same to NOP. */
@@ -409,8 +785,9 @@
 	case TO_DIS:
 	case TO_ASSIGN:
 	case TO_UNASSIGN:
-		break;
 	case TO_SIZE:
+	case TO_KEKL_SET:
+	case TO_KEKL_QUERY:
 		break;
 	}
 	return TAPE_IO_SUCCESS;
@@ -540,10 +917,8 @@
 tape_3590_erp_long_busy(struct tape_device *device,
 			struct tape_request *request, struct irb *irb)
 {
-	/* FIXME: how about WAITING for a minute ? */
-	PRINT_WARN("(%s): Device is busy! Please wait a minute!\n",
-		   device->cdev->dev.bus_id);
-	return tape_3590_erp_basic(device, request, irb, -EBUSY);
+	DBF_EVENT(6, "Device is busy\n");
+	return TAPE_IO_LONG_BUSY;
 }
 
 /*
@@ -951,6 +1326,34 @@
 		   device->cdev->dev.bus_id, sense->mc);
 }
 
+static int tape_3590_crypt_error(struct tape_device *device,
+				 struct tape_request *request, struct irb *irb)
+{
+	u8 cu_rc, ekm_rc1;
+	u16 ekm_rc2;
+	u32 drv_rc;
+	char *bus_id, *sense;
+
+	sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data;
+	bus_id = device->cdev->dev.bus_id;
+	cu_rc = sense[0];
+	drv_rc = *((u32*) &sense[5]) & 0xffffff;
+	ekm_rc1 = sense[9];
+	ekm_rc2 = *((u16*) &sense[10]);
+	if ((cu_rc == 0) && (ekm_rc2 == 0xee31))
+		/* key not defined on EKM */
+		return tape_3590_erp_basic(device, request, irb, -EKEYREJECTED);
+	if ((cu_rc == 1) || (cu_rc == 2))
+		/* No connection to EKM */
+		return tape_3590_erp_basic(device, request, irb, -ENOTCONN);
+
+	PRINT_ERR("(%s): Unable to get encryption key from EKM\n", bus_id);
+	PRINT_ERR("(%s): CU=%02X DRIVE=%06X EKM=%02X:%04X\n", bus_id, cu_rc,
+		drv_rc, ekm_rc1, ekm_rc2);
+
+	return tape_3590_erp_basic(device, request, irb, -ENOKEY);
+}
+
 /*
  *  3590 error Recovery routine:
  *  If possible, it tries to recover from the error. If this is not possible,
@@ -979,6 +1382,8 @@
 
 	sense = (struct tape_3590_sense *) irb->ecw;
 
+	DBF_EVENT(6, "Unit Check: RQC = %x\n", sense->rc_rqc);
+
 	/*
 	 * First check all RC-QRCs where we want to do something special
 	 *   - "break":     basic error recovery is done
@@ -999,6 +1404,8 @@
 	case 0x2231:
 		tape_3590_print_era_msg(device, irb);
 		return tape_3590_erp_special_interrupt(device, request, irb);
+	case 0x2240:
+		return tape_3590_crypt_error(device, request, irb);
 
 	case 0x3010:
 		DBF_EVENT(2, "(%08x): Backward at Beginning of Partition\n",
@@ -1020,6 +1427,7 @@
 		DBF_EVENT(2, "(%08x): Rewind Unload complete\n",
 			  device->cdev_id);
 		tape_med_state_set(device, MS_UNLOADED);
+		tape_3590_schedule_work(device, TO_CRYPT_OFF);
 		return tape_3590_erp_basic(device, request, irb, 0);
 
 	case 0x4010:
@@ -1030,9 +1438,15 @@
 		PRINT_WARN("(%s): Tape operation when medium not loaded\n",
 			   device->cdev->dev.bus_id);
 		tape_med_state_set(device, MS_UNLOADED);
+		tape_3590_schedule_work(device, TO_CRYPT_OFF);
 		return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);
 	case 0x4012:		/* Device Long Busy */
+		/* XXX: Also use long busy handling here? */
+		DBF_EVENT(6, "(%08x): LONG BUSY\n", device->cdev_id);
 		tape_3590_print_era_msg(device, irb);
+		return tape_3590_erp_basic(device, request, irb, -EBUSY);
+	case 0x4014:
+		DBF_EVENT(6, "(%08x): Crypto LONG BUSY\n", device->cdev_id);
 		return tape_3590_erp_long_busy(device, request, irb);
 
 	case 0x5010:
@@ -1064,6 +1478,7 @@
 	case 0x5120:
 	case 0x1120:
 		tape_med_state_set(device, MS_UNLOADED);
+		tape_3590_schedule_work(device, TO_CRYPT_OFF);
 		return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);
 
 	case 0x6020:
@@ -1142,21 +1557,47 @@
 {
 	int rc;
 	struct tape_3590_disc_data *data;
+	char *rdc_data;
 
 	DBF_EVENT(6, "3590 device setup\n");
-	data = kmalloc(sizeof(struct tape_3590_disc_data),
-		       GFP_KERNEL | GFP_DMA);
+	data = kzalloc(sizeof(struct tape_3590_disc_data), GFP_KERNEL | GFP_DMA);
 	if (data == NULL)
 		return -ENOMEM;
 	data->read_back_op = READ_PREVIOUS;
 	device->discdata = data;
 
-	if ((rc = tape_std_assign(device)) == 0) {
-		/* Try to find out if medium is loaded */
-		if ((rc = tape_3590_sense_medium(device)) != 0)
-			DBF_LH(3, "3590 medium sense returned %d\n", rc);
+	rdc_data = kmalloc(64, GFP_KERNEL | GFP_DMA);
+	if (!rdc_data) {
+		rc = -ENOMEM;
+		goto fail_kmalloc;
 	}
+	rc = read_dev_chars(device->cdev, (void**)&rdc_data, 64);
+	if (rc) {
+		DBF_LH(3, "Read device characteristics failed!\n");
+		goto fail_kmalloc;
+	}
+	rc = tape_std_assign(device);
+	if (rc)
+		goto fail_rdc_data;
+	if (rdc_data[31] == 0x13) {
+		PRINT_INFO("Device has crypto support\n");
+		data->crypt_info.capability |= TAPE390_CRYPT_SUPPORTED_MASK;
+		tape_3592_disable_crypt(device);
+	} else {
+		DBF_EVENT(6, "Device has NO crypto support\n");
+	}
+	/* Try to find out if medium is loaded */
+	rc = tape_3590_sense_medium(device);
+	if (rc) {
+		DBF_LH(3, "3590 medium sense returned %d\n", rc);
+		goto fail_rdc_data;
+	}
+	return 0;
 
+fail_rdc_data:
+	kfree(rdc_data);
+fail_kmalloc:
+	kfree(data);
 	return rc;
 }
 
diff --git a/drivers/s390/char/tape_3590.h b/drivers/s390/char/tape_3590.h
index cf274b9..aa51388 100644
--- a/drivers/s390/char/tape_3590.h
+++ b/drivers/s390/char/tape_3590.h
@@ -2,7 +2,7 @@
  *  drivers/s390/char/tape_3590.h
  *    tape device discipline for 3590 tapes.
  *
- *    Copyright (C) IBM Corp. 2001,2006
+ *    Copyright IBM Corp. 2001,2006
  *    Author(s): Stefan Bader <shbader@de.ibm.com>
  *		 Michael Holzheu <holzheu@de.ibm.com>
  *		 Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -38,16 +38,22 @@
 #define MSENSE_UNASSOCIATED	 0x00
 #define MSENSE_ASSOCIATED_MOUNT	 0x01
 #define MSENSE_ASSOCIATED_UMOUNT 0x02
+#define MSENSE_CRYPT_MASK	 0x00000010
 
 #define TAPE_3590_MAX_MSG	 0xb0
 
 /* Datatypes */
 
 struct tape_3590_disc_data {
-	unsigned char modeset_byte;
+	struct tape390_crypt_info crypt_info;
 	int read_back_op;
 };
 
+#define TAPE_3590_CRYPT_INFO(device) \
+	((struct tape_3590_disc_data*)(device->discdata))->crypt_info
+#define TAPE_3590_READ_BACK_OP(device) \
+	((struct tape_3590_disc_data*)(device->discdata))->read_back_op
+
 struct tape_3590_sense {
 
 	unsigned int command_rej:1;
@@ -118,7 +124,48 @@
 struct tape_3590_med_sense {
 	unsigned int macst:4;
 	unsigned int masst:4;
-	char pad[127];
+	char pad1[7];
+	unsigned int flags;
+	char pad2[116];
+} __attribute__ ((packed));
+
+/* Datastructures for 3592 encryption support */
+
+struct tape3592_kekl {
+	__u8 flags;
+	char label[64];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_pair {
+	__u8 count;
+	struct tape3592_kekl kekl[2];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_query_data {
+	__u16 len;
+	__u8  fmt;
+	__u8  mc;
+	__u32 id;
+	__u8  flags;
+	struct tape3592_kekl_pair kekls;
+	char reserved[116];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_query_order {
+	__u8 code;
+	__u8 flags;
+	char reserved1[2];
+	__u8 max_count;
+	char reserved2[35];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_set_order {
+	__u8 code;
+	__u8 flags;
+	char reserved1[2];
+	__u8 op;
+	struct tape3592_kekl_pair kekls;
+	char reserved2[120];
 } __attribute__ ((packed));
 
 #endif /* _TAPE_3590_H */
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index c8a89b3..dd0ecae 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -73,7 +73,7 @@
 /*
  * Post finished request.
  */
-static inline void
+static void
 tapeblock_end_request(struct request *req, int uptodate)
 {
 	if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
@@ -108,7 +108,7 @@
 /*
  * Feed the tape device CCW queue with requests supplied in a list.
  */
-static inline int
+static int
 tapeblock_start_request(struct tape_device *device, struct request *req)
 {
 	struct tape_request *	ccw_req;
diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c
index 31198c8..9faea04 100644
--- a/drivers/s390/char/tape_char.c
+++ b/drivers/s390/char/tape_char.c
@@ -3,7 +3,7 @@
  *    character device frontend for tape device driver
  *
  *  S390 and zSeries version
- *    Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright IBM Corp. 2001,2006
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *		 Michael Holzheu <holzheu@de.ibm.com>
  *		 Tuan Ngo-Anh <ngoanh@de.ibm.com>
@@ -89,22 +89,7 @@
 	device->nt = NULL;
 }
 
-/*
- * Terminate write command (we write two TMs and skip backward over last)
- * This ensures that the tape is always correctly terminated.
- * When the user writes afterwards a new file, he will overwrite the
- * second TM and therefore one TM will remain to separate the
- * two files on the tape...
- */
-static inline void
-tapechar_terminate_write(struct tape_device *device)
-{
-	if (tape_mtop(device, MTWEOF, 1) == 0 &&
-	    tape_mtop(device, MTWEOF, 1) == 0)
-		tape_mtop(device, MTBSR, 1);
-}
-
-static inline int
+static int
 tapechar_check_idalbuffer(struct tape_device *device, size_t block_size)
 {
 	struct idal_buffer *new;
@@ -137,7 +122,7 @@
 /*
  * Tape device read function
  */
-ssize_t
+static ssize_t
 tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
 {
 	struct tape_device *device;
@@ -201,7 +186,7 @@
 /*
  * Tape device write function
  */
-ssize_t
+static ssize_t
 tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t *ppos)
 {
 	struct tape_device *device;
@@ -291,7 +276,7 @@
 /*
  * Character frontend tape device open function.
  */
-int
+static int
 tapechar_open (struct inode *inode, struct file *filp)
 {
 	struct tape_device *device;
@@ -326,7 +311,7 @@
  * Character frontend tape device release function.
  */
 
-int
+static int
 tapechar_release(struct inode *inode, struct file *filp)
 {
 	struct tape_device *device;
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index c6c2e91..e2a8a1a 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -3,7 +3,7 @@
  *    basic function of the tape device driver
  *
  *  S390 and zSeries version
- *    Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright IBM Corp. 2001,2006
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *		 Michael Holzheu <holzheu@de.ibm.com>
  *		 Tuan Ngo-Anh <ngoanh@de.ibm.com>
@@ -26,9 +26,11 @@
 #include "tape_std.h"
 
 #define PRINTK_HEADER "TAPE_CORE: "
+#define LONG_BUSY_TIMEOUT 180 /* seconds */
 
 static void __tape_do_irq (struct ccw_device *, unsigned long, struct irb *);
 static void tape_delayed_next_request(struct work_struct *);
+static void tape_long_busy_timeout(unsigned long data);
 
 /*
  * One list to contain all tape devices of all disciplines, so
@@ -69,10 +71,12 @@
 	[TO_LOAD] = "LOA",	[TO_READ_CONFIG] = "RCF",
 	[TO_READ_ATTMSG] = "RAT",
 	[TO_DIS] = "DIS",	[TO_ASSIGN] = "ASS",
-	[TO_UNASSIGN] = "UAS"
+	[TO_UNASSIGN] = "UAS",  [TO_CRYPT_ON] = "CON",
+	[TO_CRYPT_OFF] = "COF",	[TO_KEKL_SET] = "KLS",
+	[TO_KEKL_QUERY] = "KLQ",
 };
 
-static inline int
+static int
 busid_to_int(char *bus_id)
 {
 	int	dec;
@@ -252,7 +256,7 @@
 /*
  * Stop running ccw. Has to be called with the device lock held.
  */
-static inline int
+static int
 __tape_cancel_io(struct tape_device *device, struct tape_request *request)
 {
 	int retries;
@@ -346,6 +350,9 @@
 		return -EINVAL;
 	}
 
+	init_timer(&device->lb_timeout);
+	device->lb_timeout.function = tape_long_busy_timeout;
+
 	/* Let the discipline have a go at the device. */
 	device->discipline = discipline;
 	if (!try_module_get(discipline->owner)) {
@@ -385,7 +392,7 @@
 	return rc;
 }
 
-static inline void
+static void
 tape_cleanup_device(struct tape_device *device)
 {
 	tapeblock_cleanup_device(device);
@@ -563,7 +570,7 @@
 	return ret;
 }
 
-static inline void
+static void
 __tape_discard_requests(struct tape_device *device)
 {
 	struct tape_request *	request;
@@ -703,7 +710,7 @@
 	kfree(request);
 }
 
-static inline int
+static int
 __tape_start_io(struct tape_device *device, struct tape_request *request)
 {
 	int rc;
@@ -733,7 +740,7 @@
 	return rc;
 }
 
-static inline void
+static void
 __tape_start_next_request(struct tape_device *device)
 {
 	struct list_head *l, *n;
@@ -801,7 +808,23 @@
 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
 }
 
-static inline void
+static void tape_long_busy_timeout(unsigned long data)
+{
+	struct tape_request *request;
+	struct tape_device *device;
+
+	device = (struct tape_device *) data;
+	spin_lock_irq(get_ccwdev_lock(device->cdev));
+	request = list_entry(device->req_queue.next, struct tape_request, list);
+	if (request->status != TAPE_REQUEST_LONG_BUSY)
+		BUG();
+	DBF_LH(6, "%08x: Long busy timeout.\n", device->cdev_id);
+	__tape_start_next_request(device);
+	device->lb_timeout.data = (unsigned long) tape_put_device(device);
+	spin_unlock_irq(get_ccwdev_lock(device->cdev));
+}
+
+static void
 __tape_end_request(
 	struct tape_device *	device,
 	struct tape_request *	request,
@@ -878,7 +901,7 @@
  * and starts it if the tape is idle. Has to be called with
  * the device lock held.
  */
-static inline int
+static int
 __tape_start_request(struct tape_device *device, struct tape_request *request)
 {
 	int rc;
@@ -1094,7 +1117,22 @@
 	/* May be an unsolicited irq */
 	if(request != NULL)
 		request->rescnt = irb->scsw.count;
-
+	else if ((irb->scsw.dstat == 0x85 || irb->scsw.dstat == 0x80) &&
+		 !list_empty(&device->req_queue)) {
+		/* Not Ready to Ready after long busy ? */
+		struct tape_request *req;
+		req = list_entry(device->req_queue.next,
+				 struct tape_request, list);
+		if (req->status == TAPE_REQUEST_LONG_BUSY) {
+			DBF_EVENT(3, "(%08x): del timer\n", device->cdev_id);
+			if (del_timer(&device->lb_timeout)) {
+				device->lb_timeout.data = (unsigned long)
+					tape_put_device(device);
+				__tape_start_next_request(device);
+			}
+			return;
+		}
+	}
 	if (irb->scsw.dstat != 0x0c) {
 		/* Set the 'ONLINE' flag depending on sense byte 1 */
 		if(*(((__u8 *) irb->ecw) + 1) & SENSE_DRIVE_ONLINE)
@@ -1142,6 +1180,15 @@
 			break;
 		case TAPE_IO_PENDING:
 			break;
+		case TAPE_IO_LONG_BUSY:
+			device->lb_timeout.data =
+				(unsigned long)tape_get_device_reference(device);
+			device->lb_timeout.expires = jiffies +
+				LONG_BUSY_TIMEOUT * HZ;
+			DBF_EVENT(3, "(%08x): add timer\n", device->cdev_id);
+			add_timer(&device->lb_timeout);
+			request->status = TAPE_REQUEST_LONG_BUSY;
+			break;
 		case TAPE_IO_RETRY:
 			rc = __tape_start_io(device, request);
 			if (rc)
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 0984462..bc33068 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -36,7 +36,7 @@
 struct tty_driver *tty3270_driver;
 static int tty3270_max_index;
 
-struct raw3270_fn tty3270_fn;
+static struct raw3270_fn tty3270_fn;
 
 struct tty3270_cell {
 	unsigned char character;
@@ -119,8 +119,7 @@
 /*
  * Setup timeout for a device. On timeout trigger an update.
  */
-void
-tty3270_set_timer(struct tty3270 *tp, int expires)
+static void tty3270_set_timer(struct tty3270 *tp, int expires)
 {
 	if (expires == 0) {
 		if (timer_pending(&tp->timer) && del_timer(&tp->timer))
@@ -841,7 +840,7 @@
 	}
 }
 
-struct raw3270_fn tty3270_fn = {
+static struct raw3270_fn tty3270_fn = {
 	.activate = tty3270_activate,
 	.deactivate = tty3270_deactivate,
 	.intv = (void *) tty3270_irq,
@@ -1754,8 +1753,7 @@
 	.set_termios = tty3270_set_termios
 };
 
-void
-tty3270_notifier(int index, int active)
+static void tty3270_notifier(int index, int active)
 {
 	if (active)
 		tty_register_device(tty3270_driver, index, NULL);
@@ -1767,8 +1765,7 @@
  * 3270 tty registration code called from tty_init().
  * Most kernel services (incl. kmalloc) are available at this poimt.
  */
-int __init
-tty3270_init(void)
+static int __init tty3270_init(void)
 {
 	struct tty_driver *driver;
 	int ret;
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index 6cb2304..8432a76 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -3,7 +3,7 @@
  *	character device driver for reading z/VM system service records
  *
  *
- *	Copyright (C) 2004 IBM Corporation
+ *	Copyright 2004 IBM Corporation
  *	character device driver for reading z/VM system service records,
  *	Version 1.0
  *	Author(s): Xenia Tkatschow <xenia@us.ibm.com>
@@ -21,7 +21,7 @@
 #include <asm/cpcmd.h>
 #include <asm/debug.h>
 #include <asm/ebcdic.h>
-#include "../net/iucv.h"
+#include <net/iucv/iucv.h>
 #include <linux/kmod.h>
 #include <linux/cdev.h>
 #include <linux/device.h>
@@ -60,12 +60,11 @@
 	char system_service[8];
 	char internal_name[8];
 	char recording_name[8];
-	u16 pathid;
+	struct iucv_path *path;
 	int connection_established;
 	int iucv_path_severed;
-	iucv_MessagePending local_interrupt_buffer;
+	struct iucv_message local_interrupt_buffer;
 	atomic_t receive_ready;
-	iucv_handle_t iucv_handle;
 	int minor_num;
 	char * buffer;
 	char * current_position;
@@ -97,40 +96,21 @@
 };
 
 
-static u8 iucvMagic[16] = {
-	0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
-	0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
+static void vmlogrdr_iucv_path_complete(struct iucv_path *, u8 ipuser[16]);
+static void vmlogrdr_iucv_path_severed(struct iucv_path *, u8 ipuser[16]);
+static void vmlogrdr_iucv_message_pending(struct iucv_path *,
+					  struct iucv_message *);
+
+
+static struct iucv_handler vmlogrdr_iucv_handler = {
+	.path_complete	 = vmlogrdr_iucv_path_complete,
+	.path_severed	 = vmlogrdr_iucv_path_severed,
+	.message_pending = vmlogrdr_iucv_message_pending,
 };
 
 
-static u8 mask[] = {
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
-};
-
-
-static u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-
-static void
-vmlogrdr_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data);
-static void
-vmlogrdr_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data);
-static void
-vmlogrdr_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data);
-
-
-static iucv_interrupt_ops_t vmlogrdr_iucvops = {
-	.ConnectionComplete = vmlogrdr_iucv_ConnectionComplete,
-	.ConnectionSevered  = vmlogrdr_iucv_ConnectionSevered,
-	.MessagePending     = vmlogrdr_iucv_MessagePending,
-};
-
-
-DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue);
-DECLARE_WAIT_QUEUE_HEAD(read_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD(read_wait_queue);
 
 /*
  * pointer to system service private structure
@@ -177,28 +157,29 @@
 static int recording_class_AB;
 
 
-static void
-vmlogrdr_iucv_ConnectionComplete (iucv_ConnectionComplete * eib,
-				   void * pgm_data)
+static void vmlogrdr_iucv_path_complete(struct iucv_path *path, u8 ipuser[16])
 {
-	struct vmlogrdr_priv_t * logptr = pgm_data;
+	struct vmlogrdr_priv_t * logptr = path->private;
+
 	spin_lock(&logptr->priv_lock);
 	logptr->connection_established = 1;
 	spin_unlock(&logptr->priv_lock);
 	wake_up(&conn_wait_queue);
-	return;
 }
 
 
-static void
-vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data)
+static void vmlogrdr_iucv_path_severed(struct iucv_path *path, u8 ipuser[16])
 {
-	u8 reason = (u8) eib->ipuser[8];
-	struct vmlogrdr_priv_t * logptr = pgm_data;
+	struct vmlogrdr_priv_t * logptr = path->private;
+	u8 reason = (u8) ipuser[8];
 
 	printk (KERN_ERR "vmlogrdr: connection severed with"
 		" reason %i\n", reason);
 
+	iucv_path_sever(path, NULL);
+	kfree(path);
+	logptr->path = NULL;
+
 	spin_lock(&logptr->priv_lock);
 	logptr->connection_established = 0;
 	logptr->iucv_path_severed = 1;
@@ -210,10 +191,10 @@
 }
 
 
-static void
-vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data)
+static void vmlogrdr_iucv_message_pending(struct iucv_path *path,
+					  struct iucv_message *msg)
 {
-	struct vmlogrdr_priv_t * logptr = pgm_data;
+	struct vmlogrdr_priv_t * logptr = path->private;
 
 	/*
 	 * This function is the bottom half so it should be quick.
@@ -221,15 +202,15 @@
 	 * the usage count
 	 */
 	spin_lock(&logptr->priv_lock);
-	memcpy(&(logptr->local_interrupt_buffer), eib, sizeof(*eib));
+	memcpy(&logptr->local_interrupt_buffer, msg, sizeof(*msg));
 	atomic_inc(&logptr->receive_ready);
 	spin_unlock(&logptr->priv_lock);
 	wake_up_interruptible(&read_wait_queue);
 }
 
 
-static int
-vmlogrdr_get_recording_class_AB(void) {
+static int vmlogrdr_get_recording_class_AB(void)
+{
 	char cp_command[]="QUERY COMMAND RECORDING ";
 	char cp_response[80];
 	char *tail;
@@ -259,8 +240,9 @@
 }
 
 
-static int
-vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) {
+static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr,
+			      int action, int purge)
+{
 
 	char cp_command[80];
 	char cp_response[160];
@@ -318,8 +300,7 @@
 }
 
 
-static int
-vmlogrdr_open (struct inode *inode, struct file *filp)
+static int vmlogrdr_open (struct inode *inode, struct file *filp)
 {
 	int dev_num = 0;
 	struct vmlogrdr_priv_t * logptr = NULL;
@@ -329,10 +310,7 @@
 	dev_num = iminor(inode);
 	if (dev_num > MAXMINOR)
 		return -ENODEV;
-
 	logptr = &sys_ser[dev_num];
-	if (logptr == NULL)
-		return -ENODEV;
 
 	/*
 	 * only allow for blocking reads to be open
@@ -345,52 +323,38 @@
 	if (logptr->dev_in_use)	{
 		spin_unlock_bh(&logptr->priv_lock);
 		return -EBUSY;
-	} else {
-		logptr->dev_in_use = 1;
-		spin_unlock_bh(&logptr->priv_lock);
 	}
-
+	logptr->dev_in_use = 1;
+	logptr->connection_established = 0;
+	logptr->iucv_path_severed = 0;
 	atomic_set(&logptr->receive_ready, 0);
 	logptr->buffer_free = 1;
+	spin_unlock_bh(&logptr->priv_lock);
 
 	/* set the file options */
 	filp->private_data = logptr;
 	filp->f_op = &vmlogrdr_fops;
 
 	/* start recording for this service*/
-	ret=0;
-	if (logptr->autorecording)
+	if (logptr->autorecording) {
 		ret = vmlogrdr_recording(logptr,1,logptr->autopurge);
-	if (ret)
-		printk (KERN_WARNING "vmlogrdr: failed to start "
-			"recording automatically\n");
-
-	/* Register with iucv driver */
-	logptr->iucv_handle = iucv_register_program(iucvMagic,
-			logptr->system_service, mask, &vmlogrdr_iucvops,
-			logptr);
-
-	if (logptr->iucv_handle == NULL) {
-		printk (KERN_ERR "vmlogrdr: failed to register with"
-			"iucv driver\n");
-		goto not_registered;
+		if (ret)
+			printk (KERN_WARNING "vmlogrdr: failed to start "
+				"recording automatically\n");
 	}
 
 	/* create connection to the system service */
-	spin_lock_bh(&logptr->priv_lock);
-	logptr->connection_established = 0;
-	logptr->iucv_path_severed = 0;
-	spin_unlock_bh(&logptr->priv_lock);
-
-	connect_rc = iucv_connect (&(logptr->pathid), 10, iucvMagic,
-					logptr->system_service, iucv_host, 0,
-					NULL, NULL,
-					logptr->iucv_handle, NULL);
+	logptr->path = iucv_path_alloc(10, 0, GFP_KERNEL);
+	if (!logptr->path)
+		goto out_dev;
+	connect_rc = iucv_path_connect(logptr->path, &vmlogrdr_iucv_handler,
+				       logptr->system_service, NULL, NULL,
+				       logptr);
 	if (connect_rc) {
 		printk (KERN_ERR "vmlogrdr: iucv connection to %s "
 			"failed with rc %i \n", logptr->system_service,
 			connect_rc);
-		goto not_connected;
+		goto out_path;
 	}
 
 	/* We've issued the connect and now we must wait for a
@@ -399,35 +363,28 @@
 	 */
 	wait_event(conn_wait_queue, (logptr->connection_established)
 		   || (logptr->iucv_path_severed));
-	if (logptr->iucv_path_severed) {
-		goto not_connected;
-	}
-
+	if (logptr->iucv_path_severed)
+		goto out_record;
  	return nonseekable_open(inode, filp);
 
-not_connected:
-	iucv_unregister_program(logptr->iucv_handle);
-	logptr->iucv_handle = NULL;
-not_registered:
+out_record:
 	if (logptr->autorecording)
 		vmlogrdr_recording(logptr,0,logptr->autopurge);
+out_path:
+	kfree(logptr->path);	/* kfree(NULL) is ok. */
+	logptr->path = NULL;
+out_dev:
 	logptr->dev_in_use = 0;
 	return -EIO;
-
-
 }
 
 
-static int
-vmlogrdr_release (struct inode *inode, struct file *filp)
+static int vmlogrdr_release (struct inode *inode, struct file *filp)
 {
 	int ret;
 
 	struct vmlogrdr_priv_t * logptr = filp->private_data;
 
-	iucv_unregister_program(logptr->iucv_handle);
-	logptr->iucv_handle = NULL;
-
 	if (logptr->autorecording) {
 		ret = vmlogrdr_recording(logptr,0,logptr->autopurge);
 		if (ret)
@@ -440,8 +397,8 @@
 }
 
 
-static int
-vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) {
+static int vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv)
+{
 	int rc, *temp;
 	/* we need to keep track of two data sizes here:
 	 * The number of bytes we need to receive from iucv and
@@ -462,8 +419,7 @@
 			 * We need to return the total length of the record
                          * + size of FENCE in the first 4 bytes of the buffer.
 		         */
-			iucv_data_count =
-				priv->local_interrupt_buffer.ln1msg2.ipbfln1f;
+			iucv_data_count = priv->local_interrupt_buffer.length;
 			user_data_count = sizeof(int);
 			temp = (int*)priv->buffer;
 			*temp= iucv_data_count + sizeof(FENCE);
@@ -475,14 +431,10 @@
 		 */
 		if (iucv_data_count > NET_BUFFER_SIZE)
 			iucv_data_count = NET_BUFFER_SIZE;
-		rc = iucv_receive(priv->pathid,
-				  priv->local_interrupt_buffer.ipmsgid,
-				  priv->local_interrupt_buffer.iptrgcls,
-				  buffer,
-				  iucv_data_count,
-				  NULL,
-				  NULL,
-				  &priv->residual_length);
+		rc = iucv_message_receive(priv->path,
+					  &priv->local_interrupt_buffer,
+					  0, buffer, iucv_data_count,
+					  &priv->residual_length);
 		spin_unlock_bh(&priv->priv_lock);
 		/* An rc of 5 indicates that the record was bigger then
 		 * the buffer, which is OK for us. A 9 indicates that the
@@ -514,8 +466,8 @@
 }
 
 
-static ssize_t
-vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos)
+static ssize_t vmlogrdr_read(struct file *filp, char __user *data,
+			     size_t count, loff_t * ppos)
 {
 	int rc;
 	struct vmlogrdr_priv_t * priv = filp->private_data;
@@ -547,8 +499,10 @@
 	return count;
 }
 
-static ssize_t
-vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) {
+static ssize_t vmlogrdr_autopurge_store(struct device * dev,
+					struct device_attribute *attr,
+					const char * buf, size_t count)
+{
 	struct vmlogrdr_priv_t *priv = dev->driver_data;
 	ssize_t ret = count;
 
@@ -566,8 +520,10 @@
 }
 
 
-static ssize_t
-vmlogrdr_autopurge_show(struct device *dev, struct device_attribute *attr, char *buf) {
+static ssize_t vmlogrdr_autopurge_show(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
 	struct vmlogrdr_priv_t *priv = dev->driver_data;
 	return sprintf(buf, "%u\n", priv->autopurge);
 }
@@ -577,8 +533,10 @@
 		   vmlogrdr_autopurge_store);
 
 
-static ssize_t
-vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) {
+static ssize_t vmlogrdr_purge_store(struct device * dev,
+				    struct device_attribute *attr,
+				    const char * buf, size_t count)
+{
 
 	char cp_command[80];
 	char cp_response[80];
@@ -618,9 +576,10 @@
 static DEVICE_ATTR(purge, 0200, NULL, vmlogrdr_purge_store);
 
 
-static ssize_t
-vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr, const char *buf,
-			     size_t count) {
+static ssize_t vmlogrdr_autorecording_store(struct device *dev,
+					    struct device_attribute *attr,
+					    const char *buf, size_t count)
+{
 	struct vmlogrdr_priv_t *priv = dev->driver_data;
 	ssize_t ret = count;
 
@@ -638,8 +597,10 @@
 }
 
 
-static ssize_t
-vmlogrdr_autorecording_show(struct device *dev, struct device_attribute *attr, char *buf) {
+static ssize_t vmlogrdr_autorecording_show(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf)
+{
 	struct vmlogrdr_priv_t *priv = dev->driver_data;
 	return sprintf(buf, "%u\n", priv->autorecording);
 }
@@ -649,9 +610,10 @@
 		   vmlogrdr_autorecording_store);
 
 
-static ssize_t
-vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) {
-
+static ssize_t vmlogrdr_recording_store(struct device * dev,
+					struct device_attribute *attr,
+					const char * buf, size_t count)
+{
 	struct vmlogrdr_priv_t *priv = dev->driver_data;
 	ssize_t ret;
 
@@ -676,8 +638,9 @@
 static DEVICE_ATTR(recording, 0200, NULL, vmlogrdr_recording_store);
 
 
-static ssize_t
-vmlogrdr_recording_status_show(struct device_driver *driver, char *buf) {
+static ssize_t vmlogrdr_recording_status_show(struct device_driver *driver,
+					      char *buf)
+{
 
 	char cp_command[] = "QUERY RECORDING ";
 	int len;
@@ -710,52 +673,63 @@
 };
 
 
-static int
-vmlogrdr_register_driver(void) {
+static int vmlogrdr_register_driver(void)
+{
 	int ret;
 
+	/* Register with iucv driver */
+	ret = iucv_register(&vmlogrdr_iucv_handler, 1);
+	if (ret) {
+		printk (KERN_ERR "vmlogrdr: failed to register with"
+			"iucv driver\n");
+		goto out;
+	}
+
 	ret = driver_register(&vmlogrdr_driver);
 	if (ret) {
 		printk(KERN_ERR "vmlogrdr: failed to register driver.\n");
-		return ret;
+		goto out_iucv;
 	}
 
 	ret = driver_create_file(&vmlogrdr_driver,
 				 &driver_attr_recording_status);
 	if (ret) {
 		printk(KERN_ERR "vmlogrdr: failed to add driver attribute.\n");
-		goto unregdriver;
+		goto out_driver;
 	}
 
 	vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr");
 	if (IS_ERR(vmlogrdr_class)) {
 		printk(KERN_ERR "vmlogrdr: failed to create class.\n");
-		ret=PTR_ERR(vmlogrdr_class);
-		vmlogrdr_class=NULL;
-		goto unregattr;
+		ret = PTR_ERR(vmlogrdr_class);
+		vmlogrdr_class = NULL;
+		goto out_attr;
 	}
 	return 0;
 
-unregattr:
+out_attr:
 	driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status);
-unregdriver:
+out_driver:
 	driver_unregister(&vmlogrdr_driver);
+out_iucv:
+	iucv_unregister(&vmlogrdr_iucv_handler, 1);
+out:
 	return ret;
 }
 
 
-static void
-vmlogrdr_unregister_driver(void) {
+static void vmlogrdr_unregister_driver(void)
+{
 	class_destroy(vmlogrdr_class);
 	vmlogrdr_class = NULL;
 	driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status);
 	driver_unregister(&vmlogrdr_driver);
-	return;
+	iucv_unregister(&vmlogrdr_iucv_handler, 1);
 }
 
 
-static int
-vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) {
+static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
+{
 	struct device *dev;
 	int ret;
 
@@ -804,9 +778,10 @@
 }
 
 
-static int
-vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) {
-	class_device_destroy(vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num));
+static int vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv)
+{
+	class_device_destroy(vmlogrdr_class,
+			     MKDEV(vmlogrdr_major, priv->minor_num));
 	if (priv->device != NULL) {
 		sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group);
 		device_unregister(priv->device);
@@ -816,8 +791,8 @@
 }
 
 
-static int
-vmlogrdr_register_cdev(dev_t dev) {
+static int vmlogrdr_register_cdev(dev_t dev)
+{
 	int rc = 0;
 	vmlogrdr_cdev = cdev_alloc();
 	if (!vmlogrdr_cdev) {
@@ -837,9 +812,10 @@
 }
 
 
-static void
-vmlogrdr_cleanup(void) {
+static void vmlogrdr_cleanup(void)
+{
         int i;
+
 	if (vmlogrdr_cdev) {
 		cdev_del(vmlogrdr_cdev);
 		vmlogrdr_cdev=NULL;
@@ -856,8 +832,7 @@
 }
 
 
-static int
-vmlogrdr_init(void)
+static int vmlogrdr_init(void)
 {
 	int rc;
 	int i;
@@ -907,8 +882,7 @@
 }
 
 
-static void
-vmlogrdr_exit(void)
+static void vmlogrdr_exit(void)
 {
 	vmlogrdr_cleanup();
 	printk (KERN_INFO "vmlogrdr: driver unloaded\n");
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index 12c2d6b..aa65df4 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -43,7 +43,7 @@
  * Function: blacklist_range
  * (Un-)blacklist the devices from-to
  */
-static inline void
+static void
 blacklist_range (range_action action, unsigned int from, unsigned int to,
 		 unsigned int ssid)
 {
@@ -69,7 +69,7 @@
  * Get devno/busid from given string.
  * Shamelessly grabbed from dasd_devmap.c.
  */
-static inline int
+static int
 blacklist_busid(char **str, int *id0, int *ssid, int *devno)
 {
 	int val, old_style;
@@ -123,10 +123,10 @@
 	return 1;
 }
 
-static inline int
+static int
 blacklist_parse_parameters (char *str, range_action action)
 {
-	unsigned int from, to, from_id0, to_id0, from_ssid, to_ssid;
+	int from, to, from_id0, to_id0, from_ssid, to_ssid;
 
 	while (*str != 0 && *str != '\n') {
 		range_action ra = action;
@@ -227,7 +227,7 @@
  * Function: blacklist_parse_proc_parameters
  * parse the stuff which is piped to /proc/cio_ignore
  */
-static inline void
+static void
 blacklist_parse_proc_parameters (char *buf)
 {
 	if (strncmp (buf, "free ", 5) == 0) {
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 38954f5..d48e3ca 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -53,7 +53,7 @@
 
 static struct bus_type ccwgroup_bus_type;
 
-static inline void
+static void
 __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
 {
 	int i;
@@ -104,7 +104,7 @@
 	kfree(gdev);
 }
 
-static inline int
+static int
 __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
 {
 	char str[8];
@@ -424,7 +424,7 @@
 	return 0;
 }
 
-static inline struct ccwgroup_device *
+static struct ccwgroup_device *
 __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
 {
 	struct ccwgroup_device *gdev;
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index cbab8d2..6f05a44 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -93,7 +93,7 @@
 		u16 sch;	  /* subchannel */
 		u8 chpid[8];	  /* chpids 0-7 */
 		u16 fla[8];	  /* full link addresses 0-7 */
-	} *ssd_area;
+	} __attribute__ ((packed)) *ssd_area;
 
 	ssd_area = page;
 
@@ -277,7 +277,7 @@
 	return 0;
 }
 
-static inline void
+static void
 s390_set_chpid_offline( __u8 chpid)
 {
 	char dbf_txt[15];
@@ -338,7 +338,7 @@
 	return 0x80 >> chp;
 }
 
-static inline int
+static int
 s390_process_res_acc_new_sch(struct subchannel_id schid)
 {
 	struct schib schib;
@@ -444,7 +444,7 @@
 		u32 andesc[28];
 		/* incident-specific information */
 		u32 isinfo[28];
-	} *lir;
+	} __attribute__ ((packed)) *lir;
 
 	lir = data;
 	if (!(lir->iq&0x80))
@@ -461,154 +461,146 @@
 	return (u16) (lir->indesc[0]&0x000000ff);
 }
 
-int
-chsc_process_crw(void)
+struct chsc_sei_area {
+	struct chsc_header request;
+	u32 reserved1;
+	u32 reserved2;
+	u32 reserved3;
+	struct chsc_header response;
+	u32 reserved4;
+	u8  flags;
+	u8  vf;		/* validity flags */
+	u8  rs;		/* reporting source */
+	u8  cc;		/* content code */
+	u16 fla;	/* full link address */
+	u16 rsid;	/* reporting source id */
+	u32 reserved5;
+	u32 reserved6;
+	u8 ccdf[4096 - 16 - 24];	/* content-code dependent field */
+	/* ccdf has to be big enough for a link-incident record */
+} __attribute__ ((packed));
+
+static int chsc_process_sei_link_incident(struct chsc_sei_area *sei_area)
 {
-	int chpid, ret;
+	int chpid;
+
+	CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x)\n",
+		      sei_area->rs, sei_area->rsid);
+	if (sei_area->rs != 4)
+		return 0;
+	chpid = __get_chpid_from_lir(sei_area->ccdf);
+	if (chpid < 0)
+		CIO_CRW_EVENT(4, "chsc: link incident - invalid LIR\n");
+	else
+		s390_set_chpid_offline(chpid);
+
+	return 0;
+}
+
+static int chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
+{
 	struct res_acc_data res_data;
-	struct {
-		struct chsc_header request;
-		u32 reserved1;
-		u32 reserved2;
-		u32 reserved3;
-		struct chsc_header response;
-		u32 reserved4;
-		u8  flags;
-		u8  vf;		/* validity flags */
-		u8  rs;		/* reporting source */
-		u8  cc;		/* content code */
-		u16 fla;	/* full link address */
-		u16 rsid;	/* reporting source id */
-		u32 reserved5;
-		u32 reserved6;
-		u32 ccdf[96];	/* content-code dependent field */
-		/* ccdf has to be big enough for a link-incident record */
-	} *sei_area;
+	struct device *dev;
+	int status;
+	int rc;
+
+	CIO_CRW_EVENT(4, "chsc: resource accessibility event (rs=%02x, "
+		      "rs_id=%04x)\n", sei_area->rs, sei_area->rsid);
+	if (sei_area->rs != 4)
+		return 0;
+	/* allocate a new channel path structure, if needed */
+	status = get_chp_status(sei_area->rsid);
+	if (status < 0)
+		new_channel_path(sei_area->rsid);
+	else if (!status)
+		return 0;
+	dev = get_device(&css[0]->chps[sei_area->rsid]->dev);
+	memset(&res_data, 0, sizeof(struct res_acc_data));
+	res_data.chp = to_channelpath(dev);
+	if ((sei_area->vf & 0xc0) != 0) {
+		res_data.fla = sei_area->fla;
+		if ((sei_area->vf & 0xc0) == 0xc0)
+			/* full link address */
+			res_data.fla_mask = 0xffff;
+		else
+			/* link address */
+			res_data.fla_mask = 0xff00;
+	}
+	rc = s390_process_res_acc(&res_data);
+	put_device(dev);
+
+	return rc;
+}
+
+static int chsc_process_sei(struct chsc_sei_area *sei_area)
+{
+	int rc;
+
+	/* Check if we might have lost some information. */
+	if (sei_area->flags & 0x40)
+		CIO_CRW_EVENT(2, "chsc: event overflow\n");
+	/* which kind of information was stored? */
+	rc = 0;
+	switch (sei_area->cc) {
+	case 1: /* link incident*/
+		rc = chsc_process_sei_link_incident(sei_area);
+		break;
+	case 2: /* i/o resource accessibiliy */
+		rc = chsc_process_sei_res_acc(sei_area);
+		break;
+	default: /* other stuff */
+		CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n",
+			      sei_area->cc);
+		break;
+	}
+
+	return rc;
+}
+
+int chsc_process_crw(void)
+{
+	struct chsc_sei_area *sei_area;
+	int ret;
+	int rc;
 
 	if (!sei_page)
 		return 0;
-	/*
-	 * build the chsc request block for store event information
-	 * and do the call
-	 * This function is only called by the machine check handler thread,
-	 * so we don't need locking for the sei_page.
-	 */
+	/* Access to sei_page is serialized through machine check handler
+	 * thread, so no need for locking. */
 	sei_area = sei_page;
 
 	CIO_TRACE_EVENT( 2, "prcss");
 	ret = 0;
 	do {
-		int ccode, status;
-		struct device *dev;
 		memset(sei_area, 0, sizeof(*sei_area));
-		memset(&res_data, 0, sizeof(struct res_acc_data));
 		sei_area->request.length = 0x0010;
 		sei_area->request.code = 0x000e;
+		if (chsc(sei_area))
+			break;
 
-		ccode = chsc(sei_area);
-		if (ccode > 0)
-			return 0;
-
-		switch (sei_area->response.code) {
-			/* for debug purposes, check for problems */
-		case 0x0001:
-			CIO_CRW_EVENT(4, "chsc_process_crw: event information "
-					"successfully stored\n");
-			break; /* everything ok */
-		case 0x0002:
-			CIO_CRW_EVENT(2,
-				      "chsc_process_crw: invalid command!\n");
-			return 0;
-		case 0x0003:
-			CIO_CRW_EVENT(2, "chsc_process_crw: error in chsc "
-				      "request block!\n");
-			return 0;
-		case 0x0005:
-			CIO_CRW_EVENT(2, "chsc_process_crw: no event "
-				      "information stored\n");
-			return 0;
-		default:
-			CIO_CRW_EVENT(2, "chsc_process_crw: chsc response %d\n",
+		if (sei_area->response.code == 0x0001) {
+			CIO_CRW_EVENT(4, "chsc: sei successful\n");
+			rc = chsc_process_sei(sei_area);
+			if (rc)
+				ret = rc;
+		} else {
+			CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n",
 				      sei_area->response.code);
-			return 0;
-		}
-
-		/* Check if we might have lost some information. */
-		if (sei_area->flags & 0x40)
-			CIO_CRW_EVENT(2, "chsc_process_crw: Event information "
-				       "has been lost due to overflow!\n");
-
-		if (sei_area->rs != 4) {
-			CIO_CRW_EVENT(2, "chsc_process_crw: reporting source "
-				      "(%04X) isn't a chpid!\n",
-				      sei_area->rsid);
-			continue;
-		}
-
-		/* which kind of information was stored? */
-		switch (sei_area->cc) {
-		case 1: /* link incident*/
-			CIO_CRW_EVENT(4, "chsc_process_crw: "
-				      "channel subsystem reports link incident,"
-				      " reporting source is chpid %x\n",
-				      sei_area->rsid);
-			chpid = __get_chpid_from_lir(sei_area->ccdf);
-			if (chpid < 0)
-				CIO_CRW_EVENT(4, "%s: Invalid LIR, skipping\n",
-					      __FUNCTION__);
-			else
-				s390_set_chpid_offline(chpid);
-			break;
-			
-		case 2: /* i/o resource accessibiliy */
-			CIO_CRW_EVENT(4, "chsc_process_crw: "
-				      "channel subsystem reports some I/O "
-				      "devices may have become accessible\n");
-			pr_debug("Data received after sei: \n");
-			pr_debug("Validity flags: %x\n", sei_area->vf);
-			
-			/* allocate a new channel path structure, if needed */
-			status = get_chp_status(sei_area->rsid);
-			if (status < 0)
-				new_channel_path(sei_area->rsid);
-			else if (!status)
-				break;
-			dev = get_device(&css[0]->chps[sei_area->rsid]->dev);
-			res_data.chp = to_channelpath(dev);
-			pr_debug("chpid: %x", sei_area->rsid);
-			if ((sei_area->vf & 0xc0) != 0) {
-				res_data.fla = sei_area->fla;
-				if ((sei_area->vf & 0xc0) == 0xc0) {
-					pr_debug(" full link addr: %x",
-						 sei_area->fla);
-					res_data.fla_mask = 0xffff;
-				} else {
-					pr_debug(" link addr: %x",
-						 sei_area->fla);
-					res_data.fla_mask = 0xff00;
-				}
-			}
-			ret = s390_process_res_acc(&res_data);
-			pr_debug("\n\n");
-			put_device(dev);
-			break;
-			
-		default: /* other stuff */
-			CIO_CRW_EVENT(4, "chsc_process_crw: event %d\n",
-				      sei_area->cc);
+			ret = 0;
 			break;
 		}
 	} while (sei_area->flags & 0x80);
+
 	return ret;
 }
 
-static inline int
+static int
 __chp_add_new_sch(struct subchannel_id schid)
 {
 	struct schib schib;
 	int ret;
 
-	if (stsch(schid, &schib))
+	if (stsch_err(schid, &schib))
 		/* We're through */
 		return need_rescan ? -EAGAIN : -ENXIO;
 
@@ -709,7 +701,7 @@
 	return chp_add(chpid);
 }
 
-static inline int check_for_io_on_path(struct subchannel *sch, int index)
+static int check_for_io_on_path(struct subchannel *sch, int index)
 {
 	int cc;
 
@@ -741,7 +733,7 @@
 		sch->driver->termination(&sch->dev);
 }
 
-static inline void
+static void
 __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
 {
 	int chp, old_lpm;
@@ -967,8 +959,8 @@
 static void
 chsc_remove_chp_cmg_attr(struct channel_path *chp)
 {
-	sysfs_remove_bin_file(&chp->dev.kobj, &chp_measurement_chars_attr);
-	sysfs_remove_bin_file(&chp->dev.kobj, &chp_measurement_attr);
+	device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
+	device_remove_bin_file(&chp->dev, &chp_measurement_attr);
 }
 
 static int
@@ -976,14 +968,12 @@
 {
 	int ret;
 
-	ret = sysfs_create_bin_file(&chp->dev.kobj,
-				    &chp_measurement_chars_attr);
+	ret = device_create_bin_file(&chp->dev, &chp_measurement_chars_attr);
 	if (ret)
 		return ret;
-	ret = sysfs_create_bin_file(&chp->dev.kobj, &chp_measurement_attr);
+	ret = device_create_bin_file(&chp->dev, &chp_measurement_attr);
 	if (ret)
-		sysfs_remove_bin_file(&chp->dev.kobj,
-				      &chp_measurement_chars_attr);
+		device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
 	return ret;
 }
 
@@ -1042,7 +1032,7 @@
 		u32 : 4;
 		u32 fmt : 4;
 		u32 : 16;
-	} *secm_area;
+	} __attribute__ ((packed)) *secm_area;
 	int ret, ccode;
 
 	secm_area = page;
@@ -1253,7 +1243,7 @@
 		struct chsc_header response;
 		u32 zeroes2;
 		struct channel_path_desc desc;
-	} *scpd_area;
+	} __attribute__ ((packed)) *scpd_area;
 
 	scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 	if (!scpd_area)
@@ -1350,7 +1340,7 @@
 		u32 cmg : 8;
 		u32 zeroes3;
 		u32 data[NR_MEASUREMENT_CHARS];
-	} *scmc_area;
+	} __attribute__ ((packed)) *scmc_area;
 
 	scmc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 	if (!scmc_area)
@@ -1517,7 +1507,7 @@
 		u32 reserved5:4;
 		u32 format2:4;
 		u32 reserved6:24;
-	} *sda_area;
+	} __attribute__ ((packed)) *sda_area;
 
 	sda_area = (void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);
 	if (!sda_area)
@@ -1569,7 +1559,7 @@
 		u32 reserved4;
 		u32 general_char[510];
 		u32 chsc_char[518];
-	} *scsc_area;
+	} __attribute__ ((packed)) *scsc_area;
 
 	scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 	if (!scsc_area) {
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index a259245..0fb2b02 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -10,17 +10,17 @@
 struct chsc_header {
 	u16 length;
 	u16 code;
-};
+} __attribute__ ((packed));
 
 #define NR_MEASUREMENT_CHARS 5
 struct cmg_chars {
 	u32 values[NR_MEASUREMENT_CHARS];
-};
+} __attribute__ ((packed));
 
 #define NR_MEASUREMENT_ENTRIES 8
 struct cmg_entry {
 	u32 values[NR_MEASUREMENT_ENTRIES];
-};
+} __attribute__ ((packed));
 
 struct channel_path_desc {
 	u8 flags;
@@ -31,7 +31,7 @@
 	u8 zeroes;
 	u8 chla;
 	u8 chpp;
-};
+} __attribute__ ((packed));
 
 struct channel_path {
 	int id;
@@ -47,6 +47,9 @@
 extern void s390_process_css( void );
 extern void chsc_validate_chpids(struct subchannel *);
 extern void chpid_is_actually_online(int);
+extern int css_get_ssd_info(struct subchannel *);
+extern int chsc_process_crw(void);
+extern int chp_process_crw(int, int);
 
 struct css_general_char {
 	u64 : 41;
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index ae1bf23..b3a56dc 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -122,7 +122,7 @@
  * Use tpi to get a pending interrupt, call the interrupt handler and
  * return a pointer to the subchannel structure.
  */
-static inline int
+static int
 cio_tpi(void)
 {
 	struct tpi_info *tpi_info;
@@ -152,7 +152,7 @@
 	return 1;
 }
 
-static inline int
+static int
 cio_start_handle_notoper(struct subchannel *sch, __u8 lpm)
 {
 	char dbf_text[15];
@@ -585,7 +585,7 @@
 		 * This device must not be known to Linux. So we simply
 		 * say that there is no device and return ENODEV.
 		 */
-		CIO_MSG_EVENT(0, "Blacklisted device detected "
+		CIO_MSG_EVENT(4, "Blacklisted device detected "
 			      "at devno %04X, subchannel set %x\n",
 			      sch->schib.pmcw.dev, sch->schid.ssid);
 		err = -ENODEV;
@@ -646,7 +646,7 @@
 		 * Make sure that the i/o interrupt did not "overtake"
 		 * the last HZ timer interrupt.
 		 */
-		account_ticks();
+		account_ticks(S390_lowcore.int_clock);
 	/*
 	 * Get interrupt information from lowcore
 	 */
@@ -832,7 +832,7 @@
 }
 
 #endif
-static inline int
+static int
 __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
 {
 	int retry, cc;
@@ -850,7 +850,20 @@
 	return -EBUSY; /* uhm... */
 }
 
-static inline int
+/* we can't use the normal udelay here, since it enables external interrupts */
+
+static void udelay_reset(unsigned long usecs)
+{
+	uint64_t start_cc, end_cc;
+
+	asm volatile ("STCK %0" : "=m" (start_cc));
+	do {
+		cpu_relax();
+		asm volatile ("STCK %0" : "=m" (end_cc));
+	} while (((end_cc - start_cc)/4096) < usecs);
+}
+
+static int
 __clear_subchannel_easy(struct subchannel_id schid)
 {
 	int retry;
@@ -865,7 +878,7 @@
 			if (schid_equal(&ti.schid, &schid))
 				return 0;
 		}
-		udelay(100);
+		udelay_reset(100);
 	}
 	return -EBUSY;
 }
@@ -882,11 +895,11 @@
 	int rc;
 
 	pgm_check_occured = 0;
-	s390_reset_pgm_handler = cio_reset_pgm_check_handler;
+	s390_base_pgm_handler_fn = cio_reset_pgm_check_handler;
 	rc = stsch(schid, addr);
-	s390_reset_pgm_handler = NULL;
+	s390_base_pgm_handler_fn = NULL;
 
-	/* The program check handler could have changed pgm_check_occured */
+	/* The program check handler could have changed pgm_check_occured. */
 	barrier();
 
 	if (pgm_check_occured)
@@ -944,7 +957,7 @@
 	/* Reset subchannels. */
 	for_each_subchannel(__shutdown_subchannel_easy,  NULL);
 	/* Reset channel paths. */
-	s390_reset_mcck_handler = s390_reset_chpids_mcck_handler;
+	s390_base_mcck_handler_fn = s390_reset_chpids_mcck_handler;
 	/* Enable channel report machine checks. */
 	__ctl_set_bit(14, 28);
 	/* Temporarily reenable machine checks. */
@@ -969,7 +982,7 @@
 	local_mcck_disable();
 	/* Disable channel report machine checks. */
 	__ctl_clear_bit(14, 28);
-	s390_reset_mcck_handler = NULL;
+	s390_base_mcck_handler_fn = NULL;
 }
 
 static struct reset_call css_reset_call = {
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 828b2d3..90b22fa 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -519,8 +519,8 @@
 /* insert a single device into the cmb_area list
  * called with cmb_area.lock held from alloc_cmb
  */
-static inline int alloc_cmb_single (struct ccw_device *cdev,
-				    struct cmb_data *cmb_data)
+static int alloc_cmb_single(struct ccw_device *cdev,
+			    struct cmb_data *cmb_data)
 {
 	struct cmb *cmb;
 	struct ccw_device_private *node;
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 9d6c024..fe0ace7 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -30,7 +30,7 @@
 
 int css_characteristics_avail = 0;
 
-inline int
+int
 for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data)
 {
 	struct subchannel_id schid;
@@ -108,9 +108,6 @@
 	}
 }
 
-extern int css_get_ssd_info(struct subchannel *sch);
-
-
 int css_sch_device_register(struct subchannel *sch)
 {
 	int ret;
@@ -187,7 +184,7 @@
 	return dev ? to_subchannel(dev) : NULL;
 }
 
-static inline int css_get_subchannel_status(struct subchannel *sch)
+static int css_get_subchannel_status(struct subchannel *sch)
 {
 	struct schib schib;
 
@@ -299,7 +296,7 @@
 		/* Will be done on the slow path. */
 		return -EAGAIN;
 	}
-	if (stsch(schid, &schib) || !schib.pmcw.dnv) {
+	if (stsch_err(schid, &schib) || !schib.pmcw.dnv) {
 		/* Unusable - ignore. */
 		return 0;
 	}
@@ -417,7 +414,7 @@
 		      need_reprobe);
 }
 
-DECLARE_WORK(css_reprobe_work, reprobe_all);
+static DECLARE_WORK(css_reprobe_work, reprobe_all);
 
 /* Schedule reprobing of all unregistered subchannels. */
 void css_schedule_reprobe(void)
@@ -578,7 +575,7 @@
 
 static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store);
 
-static inline int __init setup_css(int nr)
+static int __init setup_css(int nr)
 {
 	u32 tod_high;
 	int ret;
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 3464c5b..ca2bab9 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -143,6 +143,8 @@
 extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
 extern int css_init_done;
 extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
+extern int css_process_crw(int, int);
+extern void css_reiterate_subchannels(void);
 
 #define __MAX_SUBCHANNEL 65535
 #define __MAX_SSID 3
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 8035790..e322111 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -138,7 +138,6 @@
 
 static int io_subchannel_probe (struct subchannel *);
 static int io_subchannel_remove (struct subchannel *);
-void io_subchannel_irq (struct device *);
 static int io_subchannel_notify(struct device *, int);
 static void io_subchannel_verify(struct device *);
 static void io_subchannel_ioterm(struct device *);
@@ -235,11 +234,8 @@
 	ssize_t ret = 0;
 	int chp;
 
-	if (ssd)
-		for (chp = 0; chp < 8; chp++)
-			ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]);
-	else
-		ret += sprintf (buf, "n/a");
+	for (chp = 0; chp < 8; chp++)
+		ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]);
 	ret += sprintf (buf+ret, "\n");
 	return min((ssize_t)PAGE_SIZE, ret);
 }
@@ -552,13 +548,13 @@
 	.attrs = ccwdev_attrs,
 };
 
-static inline int
+static int
 device_add_files (struct device *dev)
 {
 	return sysfs_create_group(&dev->kobj, &ccwdev_attr_group);
 }
 
-static inline void
+static void
 device_remove_files(struct device *dev)
 {
 	sysfs_remove_group(&dev->kobj, &ccwdev_attr_group);
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 29db634..b66338b 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -74,6 +74,7 @@
 extern wait_queue_head_t ccw_device_init_wq;
 extern atomic_t ccw_device_init_count;
 
+void io_subchannel_irq (struct device *pdev);
 void io_subchannel_recog_done(struct ccw_device *cdev);
 
 int ccw_device_cancel_halt_clear(struct ccw_device *);
@@ -118,6 +119,7 @@
 /* qdio needs this. */
 void ccw_device_set_timeout(struct ccw_device *, int);
 extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *);
+extern struct bus_type ccw_bus_type;
 
 /* Channel measurement facility related */
 void retry_set_schib(struct ccw_device *cdev);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index eed1457..51238e7 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -206,7 +206,7 @@
  * been varied online on the SE so we have to find out by magic (i. e. driving
  * the channel subsystem to device selection and updating our path masks).
  */
-static inline void
+static void
 __recover_lost_chpids(struct subchannel *sch, int old_lpm)
 {
 	int mask, i;
@@ -387,7 +387,7 @@
 		put_device (&cdev->dev);
 }
 
-static inline int cmp_pgid(struct pgid *p1, struct pgid *p2)
+static int cmp_pgid(struct pgid *p1, struct pgid *p2)
 {
 	char *c1;
 	char *c2;
@@ -842,6 +842,8 @@
 call_handler_unsol:
 		if (cdev->handler)
 			cdev->handler (cdev, 0, irb);
+		if (cdev->private->flags.doverify)
+			ccw_device_online_verify(cdev, 0);
 		return;
 	}
 	/* Accumulate status and find out if a basic sense is needed. */
@@ -892,7 +894,7 @@
 /*
  * Got an interrupt for a basic sense.
  */
-void
+static void
 ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
 {
 	struct irb *irb;
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index d269607..d7b25b8 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -302,7 +302,7 @@
 	wake_up(&cdev->private->wait_q);
 }
 
-static inline int
+static int
 __ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, __u8 lpm)
 {
 	int ret;
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
index bdcf930..6b1caea 100644
--- a/drivers/s390/cio/device_status.c
+++ b/drivers/s390/cio/device_status.c
@@ -25,7 +25,7 @@
  * Check for any kind of channel or interface control check but don't
  * issue the message for the console device
  */
-static inline void
+static void
 ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb)
 {
 	if (!(irb->scsw.cstat & (SCHN_STAT_CHN_DATA_CHK |
@@ -72,7 +72,7 @@
 /*
  * Copy valid bits from the extended control word to device irb.
  */
-static inline void
+static void
 ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb)
 {
 	/*
@@ -94,7 +94,7 @@
 /*
  * Check if extended status word is valid.
  */
-static inline int
+static int
 ccw_device_accumulate_esw_valid(struct irb *irb)
 {
 	if (!irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND)
@@ -109,7 +109,7 @@
 /*
  * Copy valid bits from the extended status word to device irb.
  */
-static inline void
+static void
 ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
 {
 	struct irb *cdev_irb;
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index 6fd1940..d726cd5 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -66,7 +66,6 @@
 /******************** HERE WE GO ***********************************/
 
 static const char version[] = "QDIO base support version 2";
-extern struct bus_type ccw_bus_type;
 
 static int qdio_performance_stats = 0;
 static int proc_perf_file_registration;
@@ -138,7 +137,7 @@
 }
 
 /*check ccq  */
-static inline int
+static int
 qdio_check_ccq(struct qdio_q *q, unsigned int ccq)
 {
 	char dbf_text[15];
@@ -153,7 +152,7 @@
 	return -EIO;
 }
 /* EQBS: extract buffer states */
-static inline int
+static int
 qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
 	     unsigned int *start, unsigned int *cnt)
 {
@@ -188,7 +187,7 @@
 }
 
 /* SQBS: set buffer states */
-static inline int
+static int
 qdio_do_sqbs(struct qdio_q *q, unsigned char state,
 	     unsigned int *start, unsigned int *cnt)
 {
@@ -315,7 +314,7 @@
  * returns QDIO_SIGA_ERROR_ACCESS_EXCEPTION as cc, when SIGA returns
  * an access exception 
  */
-static inline int 
+static int
 qdio_siga_output(struct qdio_q *q)
 {
 	int cc;
@@ -349,7 +348,7 @@
 	return cc;
 }
 
-static inline int 
+static int
 qdio_siga_input(struct qdio_q *q)
 {
 	int cc;
@@ -421,7 +420,7 @@
 	tasklet_hi_schedule(&tiqdio_tasklet);
 }
 
-static inline void
+static void
 qdio_mark_tiq(struct qdio_q *q)
 {
 	unsigned long flags;
@@ -471,7 +470,7 @@
 	tasklet_schedule(&q->tasklet);
 }
 
-static inline int
+static int
 qdio_stop_polling(struct qdio_q *q)
 {
 #ifdef QDIO_USE_PROCESSING_STATE
@@ -525,7 +524,7 @@
  * sophisticated locking outside of unmark_q, so that we don't need to
  * disable the interrupts :-) 
 */
-static inline void
+static void
 qdio_unmark_q(struct qdio_q *q)
 {
 	unsigned long flags;
@@ -691,7 +690,7 @@
         return q->first_to_check;
 }
 
-static inline int
+static int
 qdio_get_outbound_buffer_frontier(struct qdio_q *q)
 {
 	struct qdio_irq *irq;
@@ -774,7 +773,7 @@
 }
 
 /* all buffers are processed */
-static inline int
+static int
 qdio_is_outbound_q_done(struct qdio_q *q)
 {
 	int no_used;
@@ -796,7 +795,7 @@
 	return (no_used==0);
 }
 
-static inline int
+static int
 qdio_has_outbound_q_moved(struct qdio_q *q)
 {
 	int i;
@@ -816,7 +815,7 @@
 	}
 }
 
-static inline void
+static void
 qdio_kick_outbound_q(struct qdio_q *q)
 {
 	int result;
@@ -905,7 +904,7 @@
 	}
 }
 
-static inline void
+static void
 qdio_kick_outbound_handler(struct qdio_q *q)
 {
 	int start, end, real_end, count;
@@ -942,7 +941,7 @@
 	q->error_status_flags=0;
 }
 
-static inline void
+static void
 __qdio_outbound_processing(struct qdio_q *q)
 {
 	int siga_attempts;
@@ -1002,7 +1001,7 @@
 /************************* INBOUND ROUTINES *******************************/
 
 
-static inline int
+static int
 qdio_get_inbound_buffer_frontier(struct qdio_q *q)
 {
 	struct qdio_irq *irq;
@@ -1133,7 +1132,7 @@
 	return q->first_to_check;
 }
 
-static inline int
+static int
 qdio_has_inbound_q_moved(struct qdio_q *q)
 {
 	int i;
@@ -1167,7 +1166,7 @@
 }
 
 /* means, no more buffers to be filled */
-static inline int
+static int
 tiqdio_is_inbound_q_done(struct qdio_q *q)
 {
 	int no_used;
@@ -1228,7 +1227,7 @@
 	return 0;
 }
 
-static inline int
+static int
 qdio_is_inbound_q_done(struct qdio_q *q)
 {
 	int no_used;
@@ -1296,7 +1295,7 @@
 	}
 }
 
-static inline void
+static void
 qdio_kick_inbound_handler(struct qdio_q *q)
 {
 	int count, start, end, real_end, i;
@@ -1343,7 +1342,7 @@
 	}
 }
 
-static inline void
+static void
 __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
 {
 	struct qdio_irq *irq_ptr;
@@ -1442,7 +1441,7 @@
 	__tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount));
 }
 
-static inline void
+static void
 __qdio_inbound_processing(struct qdio_q *q)
 {
 	int q_laps=0;
@@ -1493,7 +1492,7 @@
 /************************* MAIN ROUTINES *******************************/
 
 #ifdef QDIO_USE_PROCESSING_STATE
-static inline int
+static int
 tiqdio_reset_processing_state(struct qdio_q *q, int q_laps)
 {
 	if (!q) {
@@ -1545,7 +1544,7 @@
 }
 #endif /* QDIO_USE_PROCESSING_STATE */
 
-static inline void
+static void
 tiqdio_inbound_checks(void)
 {
 	struct qdio_q *q;
@@ -1949,7 +1948,7 @@
 	mb();
 }
 
-static inline void
+static void
 qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb)
 {
 	char dbf_text[15];
@@ -1966,7 +1965,7 @@
 		
 }
 
-static inline void
+static void
 qdio_handle_pci(struct qdio_irq *irq_ptr)
 {
 	int i;
@@ -2002,7 +2001,7 @@
 
 static void qdio_establish_handle_irq(struct ccw_device*, int, int);
 
-static inline void
+static void
 qdio_handle_activate_check(struct ccw_device *cdev, unsigned long intparm,
 			   int cstat, int dstat)
 {
@@ -2229,7 +2228,7 @@
 	return cc;
 }
 
-static inline void
+static void
 qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac,
 			    unsigned long token)
 {
@@ -2740,7 +2739,7 @@
 	return 0;
 }
 
-static inline void
+static void
 qdio_allocate_do_dbf(struct qdio_initialize *init_data)
 {
 	char dbf_text[20]; /* if a printf printed out more than 8 chars */
@@ -2773,7 +2772,7 @@
 	QDIO_DBF_HEX0(0,setup,&init_data->output_sbal_addr_array,sizeof(void*));
 }
 
-static inline void
+static void
 qdio_allocate_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt)
 {
 	irq_ptr->input_qs[i]->is_iqdio_q = iqfmt;
@@ -2792,7 +2791,7 @@
 	irq_ptr->qdr->qdf0[i].dkey=QDIO_STORAGE_KEY;
 }
 
-static inline void
+static void
 qdio_allocate_fill_output_desc(struct qdio_irq *irq_ptr, int i,
 			       int j, int iqfmt)
 {
@@ -2813,7 +2812,7 @@
 }
 
 
-static inline void
+static void
 qdio_initialize_set_siga_flags_input(struct qdio_irq *irq_ptr)
 {
 	int i;
@@ -2839,7 +2838,7 @@
 	}
 }
 
-static inline void
+static void
 qdio_initialize_set_siga_flags_output(struct qdio_irq *irq_ptr)
 {
 	int i;
@@ -2865,7 +2864,7 @@
 	}
 }
 
-static inline int
+static int
 qdio_establish_irq_check_for_errors(struct ccw_device *cdev, int cstat,
 				    int dstat)
 {
@@ -3014,7 +3013,7 @@
 	return 0;
 }
 
-int qdio_fill_irq(struct qdio_initialize *init_data)
+static int qdio_fill_irq(struct qdio_initialize *init_data)
 {
 	int i;
 	char dbf_text[15];
@@ -3367,7 +3366,7 @@
 }
 
 /* buffers filled forwards again to make Rick happy */
-static inline void
+static void
 qdio_do_qdio_fill_input(struct qdio_q *q, unsigned int qidx,
 			unsigned int count, struct qdio_buffer *buffers)
 {
@@ -3386,7 +3385,7 @@
 	}
 }
 
-static inline void
+static void
 qdio_do_qdio_fill_output(struct qdio_q *q, unsigned int qidx,
 			 unsigned int count, struct qdio_buffer *buffers)
 {
@@ -3407,7 +3406,7 @@
 	}
 }
 
-static inline void
+static void
 do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags,
 		       unsigned int qidx, unsigned int count,
 		       struct qdio_buffer *buffers)
@@ -3443,7 +3442,7 @@
 	qdio_mark_q(q);
 }
 
-static inline void
+static void
 do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags,
 			unsigned int qidx, unsigned int count,
 			struct qdio_buffer *buffers)
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 81b5899..c7d1355 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -465,7 +465,7 @@
  * Flush all requests from the request/pending queue of an AP device.
  * @ap_dev: pointer to the AP device.
  */
-static inline void __ap_flush_queue(struct ap_device *ap_dev)
+static void __ap_flush_queue(struct ap_device *ap_dev)
 {
 	struct ap_message *ap_msg, *next;
 
@@ -587,7 +587,7 @@
 /**
  * Pick one of the 16 ap domains.
  */
-static inline int ap_select_domain(void)
+static int ap_select_domain(void)
 {
 	int queue_depth, device_type, count, max_count, best_domain;
 	int rc, i, j;
@@ -825,7 +825,7 @@
  *	   required, bit 2^1 is set if the poll timer needs to get armed
  * Returns 0 if the device is still present, -ENODEV if not.
  */
-static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
+static int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
 {
 	struct ap_queue_status status;
 	struct ap_message *ap_msg;
@@ -872,7 +872,7 @@
  *	   required, bit 2^1 is set if the poll timer needs to get armed
  * Returns 0 if the device is still present, -ENODEV if not.
  */
-static inline int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
+static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
 {
 	struct ap_queue_status status;
 	struct ap_message *ap_msg;
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index 1edc10a..b9e59bc 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -791,7 +791,7 @@
 	return rc;
 }
 
-long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
+static long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
 			 unsigned long arg)
 {
 	if (cmd == ICARSAMODEXPO)
@@ -833,8 +833,8 @@
  */
 static struct proc_dir_entry *zcrypt_entry;
 
-static inline int sprintcl(unsigned char *outaddr, unsigned char *addr,
-			   unsigned int len)
+static int sprintcl(unsigned char *outaddr, unsigned char *addr,
+		    unsigned int len)
 {
 	int hl, i;
 
@@ -845,8 +845,8 @@
 	return hl;
 }
 
-static inline int sprintrw(unsigned char *outaddr, unsigned char *addr,
-			   unsigned int len)
+static int sprintrw(unsigned char *outaddr, unsigned char *addr,
+		    unsigned int len)
 {
 	int hl, inl, c, cx;
 
@@ -865,8 +865,8 @@
 	return hl;
 }
 
-static inline int sprinthx(unsigned char *title, unsigned char *outaddr,
-			   unsigned char *addr, unsigned int len)
+static int sprinthx(unsigned char *title, unsigned char *outaddr,
+		    unsigned char *addr, unsigned int len)
 {
 	int hl, inl, r, rx;
 
@@ -885,8 +885,8 @@
 	return hl;
 }
 
-static inline int sprinthx4(unsigned char *title, unsigned char *outaddr,
-			    unsigned int *array, unsigned int len)
+static int sprinthx4(unsigned char *title, unsigned char *outaddr,
+		     unsigned int *array, unsigned int len)
 {
 	int hl, r;
 
@@ -943,7 +943,7 @@
 	zcrypt_qdepth_mask(workarea);
 	len += sprinthx("Waiting work element counts",
 			resp_buff+len, workarea, AP_DEVICES);
-	zcrypt_perdev_reqcnt((unsigned int *) workarea);
+	zcrypt_perdev_reqcnt((int *) workarea);
 	len += sprinthx4("Per-device successfully completed request counts",
 			 resp_buff+len,(unsigned int *) workarea, AP_DEVICES);
 	*eof = 1;
diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c
index 32e3701..818ffe0 100644
--- a/drivers/s390/crypto/zcrypt_pcica.c
+++ b/drivers/s390/crypto/zcrypt_pcica.c
@@ -191,10 +191,10 @@
  *
  * Returns 0 on success or -EFAULT.
  */
-static inline int convert_type84(struct zcrypt_device *zdev,
-				 struct ap_message *reply,
-				 char __user *outputdata,
-				 unsigned int outputdatalength)
+static int convert_type84(struct zcrypt_device *zdev,
+			  struct ap_message *reply,
+			  char __user *outputdata,
+			  unsigned int outputdatalength)
 {
 	struct type84_hdr *t84h = reply->message;
 	char *data;
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index b7153c1..252443b 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -709,7 +709,8 @@
  *	  PCIXCC/CEX2C device to the request distributor
  * @xcRB: pointer to the send_cprb request buffer
  */
-long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, struct ica_xcRB *xcRB)
+static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev,
+				    struct ica_xcRB *xcRB)
 {
 	struct ap_message ap_msg;
 	struct response_type resp_type = {
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
index 5262515..f98fa46 100644
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -22,13 +22,6 @@
 	  available.  This option is also available as a module which will be
 	  called ctc.ko.  If you do not know what it is, it's safe to say "Y".
 
-config IUCV
-	tristate "IUCV support (VM only)"
-	help
-	  Select this option if you want to use inter-user communication
-	  under VM or VIF. If unsure, say "Y" to enable a fast communication
-	  link between VM guests.
-
 config NETIUCV
 	tristate "IUCV network device support (VM only)"
 	depends on IUCV && NETDEVICES
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile
index 4777e36..bbe3ab2 100644
--- a/drivers/s390/net/Makefile
+++ b/drivers/s390/net/Makefile
@@ -4,7 +4,6 @@
 
 ctc-objs := ctcmain.o ctcdbug.o
 
-obj-$(CONFIG_IUCV) += iucv.o
 obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
 obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
 obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 95f4e10..7809a79 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -121,7 +121,7 @@
 #define DEBUG
 #endif
 
- char debug_buffer[255];
+static char debug_buffer[255];
 /**
  * Debug Facility Stuff
  */
@@ -223,16 +223,14 @@
 /* Functions */
 static int add_claw_reads(struct net_device *dev,
 	struct ccwbk* p_first, struct ccwbk* p_last);
-static void inline ccw_check_return_code (struct ccw_device *cdev,
-        int return_code);
-static void inline ccw_check_unit_check (struct chbk * p_ch,
-	unsigned char sense );
+static void ccw_check_return_code (struct ccw_device *cdev, int return_code);
+static void ccw_check_unit_check (struct chbk * p_ch, unsigned char sense );
 static int find_link(struct net_device *dev, char *host_name, char *ws_name );
 static int claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid);
 static int init_ccw_bk(struct net_device *dev);
 static void probe_error( struct ccwgroup_device *cgdev);
 static struct net_device_stats *claw_stats(struct net_device *dev);
-static int inline pages_to_order_of_mag(int num_of_pages);
+static int pages_to_order_of_mag(int num_of_pages);
 static struct sk_buff *claw_pack_skb(struct claw_privbk *privptr);
 #ifdef DEBUG
 static void dumpit (char *buf, int len);
@@ -1310,7 +1308,7 @@
 *    of magnitude get_free_pages() has an upper order of 9           *
 *--------------------------------------------------------------------*/
 
-static int inline
+static int
 pages_to_order_of_mag(int num_of_pages)
 {
 	int	order_of_mag=1;		/* assume 2 pages */
@@ -1482,7 +1480,7 @@
  *                                                                   *
  *-------------------------------------------------------------------*/
 
-static void inline
+static void
 ccw_check_return_code(struct ccw_device *cdev, int return_code)
 {
 #ifdef FUNCTRACE
@@ -1529,7 +1527,7 @@
 *       ccw_check_unit_check                                         *
 *--------------------------------------------------------------------*/
 
-static void inline
+static void
 ccw_check_unit_check(struct chbk * p_ch, unsigned char sense )
 {
 	struct net_device *dev = p_ch->ndev;
diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c
index 03cc263..5a84fbb 100644
--- a/drivers/s390/net/ctcmain.c
+++ b/drivers/s390/net/ctcmain.c
@@ -369,7 +369,7 @@
  * @param ch The channel where this skb has been received.
  * @param pskb The received skb.
  */
-static __inline__ void
+static void
 ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
 {
 	struct net_device *dev = ch->netdev;
@@ -512,7 +512,7 @@
  * @param ch          The channel, the error belongs to.
  * @param return_code The error code to inspect.
  */
-static void inline
+static void
 ccw_check_return_code(struct channel *ch, int return_code, char *msg)
 {
 	DBF_TEXT(trace, 5, __FUNCTION__);
@@ -547,7 +547,7 @@
  * @param ch    The channel, the sense code belongs to.
  * @param sense The sense code to inspect.
  */
-static void inline
+static void
 ccw_unit_check(struct channel *ch, unsigned char sense)
 {
 	DBF_TEXT(trace, 5, __FUNCTION__);
@@ -603,7 +603,7 @@
 	}
 }
 
-static __inline__ int
+static int
 ctc_checkalloc_buffer(struct channel *ch, int warn)
 {
 	DBF_TEXT(trace, 5, __FUNCTION__);
diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c
index e965f03..76728ae 100644
--- a/drivers/s390/net/cu3088.c
+++ b/drivers/s390/net/cu3088.c
@@ -57,7 +57,7 @@
 
 static struct ccw_driver cu3088_driver;
 
-struct device *cu3088_root_dev;
+static struct device *cu3088_root_dev;
 
 static ssize_t
 group_write(struct device_driver *drv, const char *buf, size_t count)
diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c
deleted file mode 100644
index 229aeb5..0000000
--- a/drivers/s390/net/iucv.c
+++ /dev/null
@@ -1,2540 +0,0 @@
-/*
- * IUCV network driver
- *
- * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s):
- *    Original source:
- *      Alan Altmark (Alan_Altmark@us.ibm.com)  Sept. 2000
- *      Xenia Tkatschow (xenia@us.ibm.com)
- *    2Gb awareness and general cleanup:
- *      Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
- *
- * Documentation used:
- *    The original source
- *    CP Programming Service, IBM document # SC24-5760
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/* #define DEBUG */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-
-#include <linux/spinlock.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <asm/atomic.h>
-#include "iucv.h"
-#include <asm/io.h>
-#include <asm/s390_ext.h>
-#include <asm/ebcdic.h>
-#include <asm/smp.h>
-#include <asm/s390_rdev.h>
-
-/* FLAGS:
- * All flags are defined in the field IPFLAGS1 of each function
- * and can be found in CP Programming Services.
- * IPSRCCLS - Indicates you have specified a source class
- * IPFGMCL  - Indicates you have specified a target class
- * IPFGPID  - Indicates you have specified a pathid
- * IPFGMID  - Indicates you have specified a message ID
- * IPANSLST - Indicates that you are using an address list for
- *            reply data
- * IPBUFLST - Indicates that you are using an address list for
- *            message data
- */
-
-#define IPSRCCLS 	0x01
-#define IPFGMCL         0x01
-#define IPFGPID         0x02
-#define IPFGMID         0x04
-#define IPANSLST        0x08
-#define IPBUFLST        0x40
-
-static int
-iucv_bus_match (struct device *dev, struct device_driver *drv)
-{
-	return 0;
-}
-
-struct bus_type iucv_bus = {
-	.name = "iucv",
-	.match = iucv_bus_match,
-};
-
-struct device *iucv_root;
-
-/* General IUCV interrupt structure */
-typedef struct {
-	__u16 ippathid;
-	__u8  res1;
-	__u8  iptype;
-	__u32 res2;
-	__u8  ipvmid[8];
-	__u8  res3[24];
-} iucv_GeneralInterrupt;
-
-static iucv_GeneralInterrupt *iucv_external_int_buffer = NULL;
-
-/* Spin Lock declaration */
-
-static DEFINE_SPINLOCK(iucv_lock);
-
-static int messagesDisabled = 0;
-
-/***************INTERRUPT HANDLING ***************/
-
-typedef struct {
-	struct list_head queue;
-	iucv_GeneralInterrupt data;
-} iucv_irqdata;
-
-static struct list_head  iucv_irq_queue;
-static DEFINE_SPINLOCK(iucv_irq_queue_lock);
-
-/*
- *Internal function prototypes
- */
-static void iucv_tasklet_handler(unsigned long);
-static void iucv_irq_handler(__u16);
-
-static DECLARE_TASKLET(iucv_tasklet,iucv_tasklet_handler,0);
-
-/************ FUNCTION ID'S ****************************/
-
-#define ACCEPT          10
-#define CONNECT         11
-#define DECLARE_BUFFER  12
-#define PURGE           9
-#define QUERY           0
-#define QUIESCE         13
-#define RECEIVE         5
-#define REJECT          8
-#define REPLY           6
-#define RESUME          14
-#define RETRIEVE_BUFFER 2
-#define SEND            4
-#define SETMASK         16
-#define SEVER           15
-
-/**
- * Structure: handler
- * members: list - list management.
- *          structure: id
- *             userid - 8 char array of machine identification
- *             user_data - 16 char array for user identification
- *             mask - 24 char array used to compare the 2 previous
- *          interrupt_table - vector of interrupt functions.
- *          pgm_data -  ulong, application data that is passed
- *                      to the interrupt handlers
-*/
-typedef struct handler_t {
-	struct list_head list;
-	struct {
-		__u8 userid[8];
-		__u8 user_data[16];
-		__u8 mask[24];
-	}                    id;
-	iucv_interrupt_ops_t *interrupt_table;
-	void                 *pgm_data;
-} handler;
-
-/**
- * iucv_handler_table: List of registered handlers.
- */
-static struct list_head iucv_handler_table;
-
-/**
- * iucv_pathid_table: an array of *handler pointing into
- *                    iucv_handler_table for fast indexing by pathid;
- */
-static handler **iucv_pathid_table;
-
-static unsigned long max_connections;
-
-/**
- * iucv_cpuid: contains the logical cpu number of the cpu which
- * has declared the iucv buffer by issuing DECLARE_BUFFER.
- * If no cpu has done the initialization iucv_cpuid contains -1.
- */
-static int iucv_cpuid = -1;
-/**
- * register_flag: is 0 when external interrupt has not been registered
- */
-static int register_flag;
-
-/****************FIVE 40-BYTE PARAMETER STRUCTURES******************/
-/* Data struct 1: iparml_control
- * Used for iucv_accept
- *          iucv_connect
- *          iucv_quiesce
- *          iucv_resume
- *          iucv_sever
- *          iucv_retrieve_buffer
- * Data struct 2: iparml_dpl     (data in parameter list)
- * Used for iucv_send_prmmsg
- *          iucv_send2way_prmmsg
- *          iucv_send2way_prmmsg_array
- *          iucv_reply_prmmsg
- * Data struct 3: iparml_db       (data in a buffer)
- * Used for iucv_receive
- *          iucv_receive_array
- *          iucv_reject
- *          iucv_reply
- *          iucv_reply_array
- *          iucv_send
- *          iucv_send_array
- *          iucv_send2way
- *          iucv_send2way_array
- *          iucv_declare_buffer
- * Data struct 4: iparml_purge
- * Used for iucv_purge
- *          iucv_query
- * Data struct 5: iparml_set_mask
- * Used for iucv_set_mask
- */
-
-typedef struct {
-	__u16 ippathid;
-	__u8  ipflags1;
-	__u8  iprcode;
-	__u16 ipmsglim;
-	__u16 res1;
-	__u8  ipvmid[8];
-	__u8  ipuser[16];
-	__u8  iptarget[8];
-} iparml_control;
-
-typedef struct {
-	__u16 ippathid;
-	__u8  ipflags1;
-	__u8  iprcode;
-	__u32 ipmsgid;
-	__u32 iptrgcls;
-	__u8  iprmmsg[8];
-	__u32 ipsrccls;
-	__u32 ipmsgtag;
-	__u32 ipbfadr2;
-	__u32 ipbfln2f;
-	__u32 res;
-} iparml_dpl;
-
-typedef struct {
-	__u16 ippathid;
-	__u8  ipflags1;
-	__u8  iprcode;
-	__u32 ipmsgid;
-	__u32 iptrgcls;
-	__u32 ipbfadr1;
-	__u32 ipbfln1f;
-	__u32 ipsrccls;
-	__u32 ipmsgtag;
-	__u32 ipbfadr2;
-	__u32 ipbfln2f;
-	__u32 res;
-} iparml_db;
-
-typedef struct {
-	__u16 ippathid;
-	__u8  ipflags1;
-	__u8  iprcode;
-	__u32 ipmsgid;
-	__u8  ipaudit[3];
-	__u8  res1[5];
-	__u32 res2;
-	__u32 ipsrccls;
-	__u32 ipmsgtag;
-	__u32 res3[3];
-} iparml_purge;
-
-typedef struct {
-	__u8  ipmask;
-	__u8  res1[2];
-	__u8  iprcode;
-	__u32 res2[9];
-} iparml_set_mask;
-
-typedef struct {
-	union {
-		iparml_control  p_ctrl;
-		iparml_dpl      p_dpl;
-		iparml_db       p_db;
-		iparml_purge    p_purge;
-		iparml_set_mask p_set_mask;
-	} param;
-	atomic_t in_use;
-	__u32    res;
-}  __attribute__ ((aligned(8))) iucv_param;
-#define PARAM_POOL_SIZE (PAGE_SIZE / sizeof(iucv_param))
-
-static iucv_param * iucv_param_pool;
-
-MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
-MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver");
-MODULE_LICENSE("GPL");
-
-/*
- * Debugging stuff
- *******************************************************************************/
-
-
-#ifdef DEBUG
-static int debuglevel = 0;
-
-module_param(debuglevel, int, 0);
-MODULE_PARM_DESC(debuglevel,
- "Specifies the debug level (0=off ... 3=all)");
-
-static void
-iucv_dumpit(char *title, void *buf, int len)
-{
-	int i;
-	__u8 *p = (__u8 *)buf;
-
-	if (debuglevel < 3)
-		return;
-
-	printk(KERN_DEBUG "%s\n", title);
-	printk("  ");
-	for (i = 0; i < len; i++) {
-		if (!(i % 16) && i != 0)
-			printk ("\n  ");
-		else if (!(i % 4) && i != 0)
-			printk(" ");
-		printk("%02X", *p++);
-	}
-	if (len % 16)
-		printk ("\n");
-	return;
-}
-#define iucv_debug(lvl, fmt, args...) \
-do { \
-	if (debuglevel >= lvl) \
-		printk(KERN_DEBUG "%s: " fmt "\n", __FUNCTION__ , ## args); \
-} while (0)
-
-#else
-
-#define iucv_debug(lvl, fmt, args...)	do { } while (0)
-#define iucv_dumpit(title, buf, len)	do { } while (0)
-
-#endif
-
-/*
- * Internal functions
- *******************************************************************************/
-
-/**
- * print start banner
- */
-static void
-iucv_banner(void)
-{
-	printk(KERN_INFO "IUCV lowlevel driver initialized\n");
-}
-
-/**
- * iucv_init - Initialization
- *
- * Allocates and initializes various data structures.
- */
-static int
-iucv_init(void)
-{
-	int ret;
-
-	if (iucv_external_int_buffer)
-		return 0;
-
-	if (!MACHINE_IS_VM) {
-		printk(KERN_ERR "IUCV: IUCV connection needs VM as base\n");
-		return -EPROTONOSUPPORT;
-	}
-
-	ret = bus_register(&iucv_bus);
-	if (ret) {
-		printk(KERN_ERR "IUCV: failed to register bus.\n");
-		return ret;
-	}
-
-	iucv_root = s390_root_dev_register("iucv");
-	if (IS_ERR(iucv_root)) {
-		printk(KERN_ERR "IUCV: failed to register iucv root.\n");
-		bus_unregister(&iucv_bus);
-		return PTR_ERR(iucv_root);
-	}
-
-	/* Note: GFP_DMA used used to get memory below 2G */
-	iucv_external_int_buffer = kzalloc(sizeof(iucv_GeneralInterrupt),
-					   GFP_KERNEL|GFP_DMA);
-	if (!iucv_external_int_buffer) {
-		printk(KERN_WARNING
-		       "%s: Could not allocate external interrupt buffer\n",
-		       __FUNCTION__);
-		s390_root_dev_unregister(iucv_root);
-		bus_unregister(&iucv_bus);
-		return -ENOMEM;
-	}
-
-	/* Initialize parameter pool */
-	iucv_param_pool = kzalloc(sizeof(iucv_param) * PARAM_POOL_SIZE,
-				  GFP_KERNEL|GFP_DMA);
-	if (!iucv_param_pool) {
-		printk(KERN_WARNING "%s: Could not allocate param pool\n",
-		       __FUNCTION__);
-		kfree(iucv_external_int_buffer);
-		iucv_external_int_buffer = NULL;
-		s390_root_dev_unregister(iucv_root);
-		bus_unregister(&iucv_bus);
-		return -ENOMEM;
-	}
-
-	/* Initialize irq queue */
-	INIT_LIST_HEAD(&iucv_irq_queue);
-
-	/* Initialize handler table */
-	INIT_LIST_HEAD(&iucv_handler_table);
-
-	iucv_banner();
-	return 0;
-}
-
-/**
- * iucv_exit - De-Initialization
- *
- * Frees everything allocated from iucv_init.
- */
-static int iucv_retrieve_buffer (void);
-
-static void
-iucv_exit(void)
-{
-	iucv_retrieve_buffer();
-	kfree(iucv_external_int_buffer);
-	iucv_external_int_buffer = NULL;
-	kfree(iucv_param_pool);
-	iucv_param_pool = NULL;
-	s390_root_dev_unregister(iucv_root);
-	bus_unregister(&iucv_bus);
-	printk(KERN_INFO "IUCV lowlevel driver unloaded\n");
-}
-
-/**
- * grab_param: - Get a parameter buffer from the pre-allocated pool.
- *
- * This function searches for an unused element in the pre-allocated pool
- * of parameter buffers. If one is found, it marks it "in use" and returns
- * a pointer to it. The calling function is responsible for releasing it
- * when it has finished its usage.
- *
- * Returns: A pointer to iucv_param.
- */
-static __inline__ iucv_param *
-grab_param(void)
-{
-	iucv_param *ptr;
-        static int hint = 0;
-
-	ptr = iucv_param_pool + hint;
-	do {
-		ptr++;
-		if (ptr >= iucv_param_pool + PARAM_POOL_SIZE)
-			ptr = iucv_param_pool;
-	} while (atomic_cmpxchg(&ptr->in_use, 0, 1) != 0);
-	hint = ptr - iucv_param_pool;
-
-	memset(&ptr->param, 0, sizeof(ptr->param));
-	return ptr;
-}
-
-/**
- * release_param - Release a parameter buffer.
- * @p: A pointer to a struct iucv_param, previously obtained by calling
- *     grab_param().
- *
- * This function marks the specified parameter buffer "unused".
- */
-static __inline__ void
-release_param(void *p)
-{
-	atomic_set(&((iucv_param *)p)->in_use, 0);
-}
-
-/**
- * iucv_add_handler: - Add a new handler
- * @new_handler: handle that is being entered into chain.
- *
- * Places new handle on iucv_handler_table, if identical handler is not
- * found.
- *
- * Returns: 0 on success, !0 on failure (handler already in chain).
- */
-static int
-iucv_add_handler (handler *new)
-{
-	ulong flags;
-
-	iucv_debug(1, "entering");
-	iucv_dumpit("handler:", new, sizeof(handler));
-
-	spin_lock_irqsave (&iucv_lock, flags);
-	if (!list_empty(&iucv_handler_table)) {
-		struct list_head *lh;
-
-		/**
-		 * Search list for handler with identical id. If one
-		 * is found, the new handler is _not_ added.
-		 */
-		list_for_each(lh, &iucv_handler_table) {
-			handler *h = list_entry(lh, handler, list);
-			if (!memcmp(&new->id, &h->id, sizeof(h->id))) {
-				iucv_debug(1, "ret 1");
-				spin_unlock_irqrestore (&iucv_lock, flags);
-				return 1;
-			}
-		}
-	}
-	/**
-	 * If we get here, no handler was found.
-	 */
-	INIT_LIST_HEAD(&new->list);
-	list_add(&new->list, &iucv_handler_table);
-	spin_unlock_irqrestore (&iucv_lock, flags);
-
-	iucv_debug(1, "exiting");
-	return 0;
-}
-
-/**
- * b2f0:
- * @code: identifier of IUCV call to CP.
- * @parm: pointer to 40 byte iparml area passed to CP
- *
- * Calls CP to execute IUCV commands.
- *
- * Returns: return code from CP's IUCV call
- */
-static inline ulong b2f0(__u32 code, void *parm)
-{
-	register unsigned long reg0 asm ("0");
-	register unsigned long reg1 asm ("1");
-	iucv_dumpit("iparml before b2f0 call:", parm, sizeof(iucv_param));
-
-	reg0 = code;
-	reg1 = virt_to_phys(parm);
-	asm volatile(".long 0xb2f01000" : : "d" (reg0), "a" (reg1));
-
-	iucv_dumpit("iparml after b2f0 call:", parm, sizeof(iucv_param));
-
-	return (unsigned long)*((__u8 *)(parm + 3));
-}
-
-/*
- * Name: iucv_add_pathid
- * Purpose: Adds a path id to the system.
- * Input: pathid -  pathid that is going to be entered into system
- *        handle -  address of handler that the pathid will be associated
- *		   with.
- *        pgm_data - token passed in by application.
- * Output: 0: successful addition of pathid
- *	   - EINVAL - pathid entry is being used by another application
- *	   - ENOMEM - storage allocation for a new pathid table failed
-*/
-static int
-__iucv_add_pathid(__u16 pathid, handler *handler)
-{
-
-	iucv_debug(1, "entering");
-
-	iucv_debug(1, "handler is pointing to %p", handler);
-
-	if (pathid > (max_connections - 1))
-		return -EINVAL;
-
-	if (iucv_pathid_table[pathid]) {
-		iucv_debug(1, "pathid entry is %p", iucv_pathid_table[pathid]);
-		printk(KERN_WARNING
-		       "%s: Pathid being used, error.\n", __FUNCTION__);
-		return -EINVAL;
-	}
-	iucv_pathid_table[pathid] = handler;
-
-	iucv_debug(1, "exiting");
-	return 0;
-}				/* end of add_pathid function */
-
-static int
-iucv_add_pathid(__u16 pathid, handler *handler)
-{
-	ulong flags;
-	int rc;
-
-	spin_lock_irqsave (&iucv_lock, flags);
-	rc = __iucv_add_pathid(pathid, handler);
-	spin_unlock_irqrestore (&iucv_lock, flags);
-	return rc;
-}
-
-static void
-iucv_remove_pathid(__u16 pathid)
-{
-	ulong flags;
-
-	if (pathid > (max_connections - 1))
-		return;
-
-	spin_lock_irqsave (&iucv_lock, flags);
-	iucv_pathid_table[pathid] = NULL;
-	spin_unlock_irqrestore (&iucv_lock, flags);
-}
-
-/**
- * iucv_declare_buffer_cpuid
- * Register at VM for subsequent IUCV operations. This is executed
- * on the reserved CPU iucv_cpuid. Called from iucv_declare_buffer().
- */
-static void
-iucv_declare_buffer_cpuid (void *result)
-{
-	iparml_db *parm;
-
-	parm = (iparml_db *)grab_param();
-	parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer);
-	if ((*((ulong *)result) = b2f0(DECLARE_BUFFER, parm)) == 1)
-		*((ulong *)result) = parm->iprcode;
-	release_param(parm);
-}
-
-/**
- * iucv_retrieve_buffer_cpuid:
- * Unregister IUCV usage at VM. This is always executed on the same
- * cpu that registered the buffer to VM.
- * Called from iucv_retrieve_buffer().
- */
-static void
-iucv_retrieve_buffer_cpuid (void *cpu)
-{
-	iparml_control *parm;
-
-	parm = (iparml_control *)grab_param();
-	b2f0(RETRIEVE_BUFFER, parm);
-	release_param(parm);
-}
-
-/**
- * Name: iucv_declare_buffer
- * Purpose: Specifies the guests real address of an external
- *          interrupt.
- * Input: void
- * Output: iprcode - return code from b2f0 call
- */
-static int
-iucv_declare_buffer (void)
-{
-	unsigned long flags;
-	ulong b2f0_result;
-
-	iucv_debug(1, "entering");
-	b2f0_result = -ENODEV;
-	spin_lock_irqsave (&iucv_lock, flags);
-	if (iucv_cpuid == -1) {
-		/* Reserve any cpu for use by iucv. */
-		iucv_cpuid = smp_get_cpu(CPU_MASK_ALL);
-		spin_unlock_irqrestore (&iucv_lock, flags);
-		smp_call_function_on(iucv_declare_buffer_cpuid,
-			&b2f0_result, 0, 1, iucv_cpuid);
-		if (b2f0_result) {
-			smp_put_cpu(iucv_cpuid);
-			iucv_cpuid = -1;
-		}
-		iucv_debug(1, "Address of EIB = %p", iucv_external_int_buffer);
-	} else {
-		spin_unlock_irqrestore (&iucv_lock, flags);
-		b2f0_result = 0;
-	}
-	iucv_debug(1, "exiting");
-	return b2f0_result;
-}
-
-/**
- * iucv_retrieve_buffer:
- *
- * Terminates all use of IUCV.
- * Returns: return code from CP
- */
-static int
-iucv_retrieve_buffer (void)
-{
-	iucv_debug(1, "entering");
-	if (iucv_cpuid != -1) {
-		smp_call_function_on(iucv_retrieve_buffer_cpuid,
-				     NULL, 0, 1, iucv_cpuid);
-		/* Release the cpu reserved by iucv_declare_buffer. */
-		smp_put_cpu(iucv_cpuid);
-		iucv_cpuid = -1;
-	}
-	iucv_debug(1, "exiting");
-	return 0;
-}
-
-/**
- * iucv_remove_handler:
- * @users_handler: handler to be removed
- *
- * Remove handler when application unregisters.
- */
-static void
-iucv_remove_handler(handler *handler)
-{
-	unsigned long flags;
-
-	if ((!iucv_pathid_table) || (!handler))
-		return;
-
-	iucv_debug(1, "entering");
-
-	spin_lock_irqsave (&iucv_lock, flags);
-	list_del(&handler->list);
-	if (list_empty(&iucv_handler_table)) {
-		if (register_flag) {
-			unregister_external_interrupt(0x4000, iucv_irq_handler);
-			register_flag = 0;
-		}
-	}
-	spin_unlock_irqrestore (&iucv_lock, flags);
-
-	iucv_debug(1, "exiting");
-	return;
-}
-
-/**
- * iucv_register_program:
- * @pgmname:  user identification
- * @userid:   machine identification
- * @pgmmask:  Indicates which bits in the pgmname and userid combined will be
- *            used to determine who is given control.
- * @ops:      Address of interrupt handler table.
- * @pgm_data: Application data to be passed to interrupt handlers.
- *
- * Registers an application with IUCV.
- * Returns:
- *           The address of handler, or NULL on failure.
- * NOTE on pgmmask:
- *   If pgmname, userid and pgmmask are provided, pgmmask is entered into the
- *   handler as is.
- *   If pgmmask is NULL, the internal mask is set to all 0xff's
- *   When userid is NULL, the first 8 bytes of the internal mask are forced
- *   to 0x00.
- *   If pgmmask and userid are NULL, the first 8 bytes of the internal mask
- *   are forced to 0x00 and the last 16 bytes to 0xff.
- */
-
-iucv_handle_t
-iucv_register_program (__u8 pgmname[16],
-		       __u8 userid[8],
-		       __u8 pgmmask[24],
-		       iucv_interrupt_ops_t * ops, void *pgm_data)
-{
-	ulong rc = 0;		/* return code from function calls */
-	handler *new_handler;
-
-	iucv_debug(1, "entering");
-
-	if (ops == NULL) {
-		/* interrupt table is not defined */
-		printk(KERN_WARNING "%s: Interrupt table is not defined, "
-		       "exiting\n", __FUNCTION__);
-		return NULL;
-	}
-	if (!pgmname) {
-		printk(KERN_WARNING "%s: pgmname not provided\n", __FUNCTION__);
-		return NULL;
-	}
-
-	/* Allocate handler entry */
-	new_handler = kmalloc(sizeof(handler), GFP_ATOMIC);
-	if (new_handler == NULL) {
-		printk(KERN_WARNING "%s: storage allocation for new handler "
-		       "failed.\n", __FUNCTION__);
-		return NULL;
-	}
-
-	if (!iucv_pathid_table) {
-		if (iucv_init()) {
-			kfree(new_handler);
-			return NULL;
-		}
-
-		max_connections = iucv_query_maxconn();
-		iucv_pathid_table = kcalloc(max_connections, sizeof(handler *),
-					GFP_ATOMIC);
-		if (iucv_pathid_table == NULL) {
-			printk(KERN_WARNING "%s: iucv_pathid_table storage "
-			       "allocation failed\n", __FUNCTION__);
-			kfree(new_handler);
-			return NULL;
-		}
-	}
-	memset(new_handler, 0, sizeof (handler));
-	memcpy(new_handler->id.user_data, pgmname,
-		sizeof (new_handler->id.user_data));
-	if (userid) {
-		memcpy (new_handler->id.userid, userid,
-			sizeof (new_handler->id.userid));
-		ASCEBC (new_handler->id.userid,
-			sizeof (new_handler->id.userid));
-		EBC_TOUPPER (new_handler->id.userid,
-			     sizeof (new_handler->id.userid));
-
-		if (pgmmask) {
-			memcpy (new_handler->id.mask, pgmmask,
-				sizeof (new_handler->id.mask));
-		} else {
-			memset (new_handler->id.mask, 0xFF,
-				sizeof (new_handler->id.mask));
-		}
-	} else {
-		if (pgmmask) {
-			memcpy (new_handler->id.mask, pgmmask,
-				sizeof (new_handler->id.mask));
-		} else {
-			memset (new_handler->id.mask, 0xFF,
-				sizeof (new_handler->id.mask));
-		}
-		memset (new_handler->id.userid, 0x00,
-			sizeof (new_handler->id.userid));
-	}
-	/* fill in the rest of handler */
-	new_handler->pgm_data = pgm_data;
-	new_handler->interrupt_table = ops;
-
-	/*
-	 * Check if someone else is registered with same pgmname, userid
-	 * and mask. If someone is already registered with same pgmname,
-	 * userid and mask, registration will fail and NULL will be returned
-	 * to the application.
-	 * If identical handler not found, then handler is added to list.
-	 */
-	rc = iucv_add_handler(new_handler);
-	if (rc) {
-		printk(KERN_WARNING "%s: Someone already registered with same "
-		       "pgmname, userid, pgmmask\n", __FUNCTION__);
-		kfree (new_handler);
-		return NULL;
-	}
-
-	rc = iucv_declare_buffer();
-	if (rc) {
-		char *err = "Unknown";
-		iucv_remove_handler(new_handler);
-		kfree(new_handler);
-		switch(rc) {
-		case 0x03:
-			err = "Directory error";
-			break;
-		case 0x0a:
-			err = "Invalid length";
-			break;
-		case 0x13:
-			err = "Buffer already exists";
-			break;
-		case 0x3e:
-			err = "Buffer overlap";
-			break;
-		case 0x5c:
-			err = "Paging or storage error";
-			break;
-		}
-		printk(KERN_WARNING "%s: iucv_declare_buffer "
-		       "returned error 0x%02lx (%s)\n", __FUNCTION__, rc, err);
-		return NULL;
-	}
-	if (!register_flag) {
-		/* request the 0x4000 external interrupt */
-		rc = register_external_interrupt (0x4000, iucv_irq_handler);
-		if (rc) {
-			iucv_remove_handler(new_handler);
-			kfree (new_handler);
-			printk(KERN_WARNING "%s: "
-			       "register_external_interrupt returned %ld\n",
-			       __FUNCTION__, rc);
-			return NULL;
-
-		}
-		register_flag = 1;
-	}
-	iucv_debug(1, "exiting");
-	return new_handler;
-}				/* end of register function */
-
-/**
- * iucv_unregister_program:
- * @handle: address of handler
- *
- * Unregister application with IUCV.
- * Returns:
- *   0 on success, -EINVAL, if specified handle is invalid.
- */
-
-int
-iucv_unregister_program (iucv_handle_t handle)
-{
-	handler *h = NULL;
-	struct list_head *lh;
-	int i;
-	ulong flags;
-
-	iucv_debug(1, "entering");
-	iucv_debug(1, "address of handler is %p", h);
-
-	/* Checking if handle is valid  */
-	spin_lock_irqsave (&iucv_lock, flags);
-	list_for_each(lh, &iucv_handler_table) {
-		if ((handler *)handle == list_entry(lh, handler, list)) {
-			h = (handler *)handle;
-			break;
-		}
-	}
-	if (!h) {
-		spin_unlock_irqrestore (&iucv_lock, flags);
-		if (handle)
-			printk(KERN_WARNING
-			       "%s: Handler not found in iucv_handler_table.\n",
-			       __FUNCTION__);
-		else
-			printk(KERN_WARNING
-			       "%s: NULL handle passed by application.\n",
-			       __FUNCTION__);
-		return -EINVAL;
-	}
-
-	/**
-	 * First, walk thru iucv_pathid_table and sever any pathid which is
-	 * still pointing to the handler to be removed.
-	 */
-	for (i = 0; i < max_connections; i++)
-		if (iucv_pathid_table[i] == h) {
-			spin_unlock_irqrestore (&iucv_lock, flags);
-			iucv_sever(i, h->id.user_data);
-			spin_lock_irqsave(&iucv_lock, flags);
-		}
-	spin_unlock_irqrestore (&iucv_lock, flags);
-
-	iucv_remove_handler(h);
-	kfree(h);
-
-	iucv_debug(1, "exiting");
-	return 0;
-}
-
-/**
- * iucv_accept:
- * @pathid:             Path identification number
- * @msglim_reqstd:      The number of outstanding messages requested.
- * @user_data:          Data specified by the iucv_connect function.
- * @flags1:             Contains options for this path.
- *     - IPPRTY (0x20)   Specifies if you want to send priority message.
- *     - IPRMDATA (0x80) Specifies whether your program can handle a message
- *                       in the parameter list.
- *     - IPQUSCE (0x40)  Specifies whether you want to quiesce the path being
- *		         established.
- * @handle:             Address of handler.
- * @pgm_data:           Application data passed to interrupt handlers.
- * @flags1_out:         Pointer to an int. If not NULL, on return the options for
- *                      the path are stored at the given location:
- *     - IPPRTY (0x20)  Indicates you may send a priority message.
- * @msglim:             Pointer to an __u16. If not NULL, on return the maximum
- *                      number of outstanding messages is stored at the given
- *                      location.
- *
- * This function is issued after the user receives a Connection Pending external
- * interrupt and now wishes to complete the IUCV communication path.
- * Returns:
- *   return code from CP
- */
-int
-iucv_accept(__u16 pathid, __u16 msglim_reqstd,
-	     __u8 user_data[16], int flags1,
-	     iucv_handle_t handle, void *pgm_data,
-	     int *flags1_out, __u16 * msglim)
-{
-	ulong b2f0_result = 0;
-	ulong flags;
-	struct list_head *lh;
-	handler *h = NULL;
-	iparml_control *parm;
-
-	iucv_debug(1, "entering");
-	iucv_debug(1, "pathid = %d", pathid);
-
-	/* Checking if handle is valid  */
-	spin_lock_irqsave (&iucv_lock, flags);
-	list_for_each(lh, &iucv_handler_table) {
-		if ((handler *)handle == list_entry(lh, handler, list)) {
-			h = (handler *)handle;
-			break;
-		}
-	}
-	spin_unlock_irqrestore (&iucv_lock, flags);
-
-	if (!h) {
-		if (handle)
-			printk(KERN_WARNING
-			       "%s: Handler not found in iucv_handler_table.\n",
-			       __FUNCTION__);
-		else
-			printk(KERN_WARNING
-			       "%s: NULL handle passed by application.\n",
-			       __FUNCTION__);
-		return -EINVAL;
-	}
-
-	parm = (iparml_control *)grab_param();
-
-	parm->ippathid = pathid;
-	parm->ipmsglim = msglim_reqstd;
-	if (user_data)
-		memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
-
-	parm->ipflags1 = (__u8)flags1;
-	b2f0_result = b2f0(ACCEPT, parm);
-
-	if (!b2f0_result) {
-		if (msglim)
-			*msglim = parm->ipmsglim;
-		if (pgm_data)
-			h->pgm_data = pgm_data;
-		if (flags1_out)
-			*flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0;
-	}
-	release_param(parm);
-
-	iucv_debug(1, "exiting");
-	return b2f0_result;
-}
-
-/**
- * iucv_connect:
- * @pathid:        Path identification number
- * @msglim_reqstd: Number of outstanding messages requested
- * @user_data:     16-byte user data
- * @userid:        8-byte of user identification
- * @system_name:   8-byte identifying the system name
- * @flags1:        Specifies options for this path:
- *     - IPPRTY (0x20)   Specifies if you want to send priority message.
- *     - IPRMDATA (0x80) Specifies whether your program can handle a message
- *                       in  the parameter list.
- *     - IPQUSCE (0x40)  Specifies whether you want to quiesce the path being
- *                       established.
- *     - IPLOCAL (0x01)  Allows an application to force the partner to be on the
- *                       local system. If local is specified then target class
- *                       cannot be specified.
- * @flags1_out:    Pointer to an int. If not NULL, on return the options for
- *                 the path are stored at the given location:
- *     - IPPRTY (0x20)   Indicates you may send a priority message.
- * @msglim:        Pointer to an __u16. If not NULL, on return the maximum
- *                 number of outstanding messages is stored at the given
- *                 location.
- * @handle:        Address of handler.
- * @pgm_data:      Application data to be passed to interrupt handlers.
- *
- * This function establishes an IUCV path. Although the connect may complete
- * successfully, you are not able to use the path until you receive an IUCV
- * Connection Complete external interrupt.
- * Returns: return code from CP, or one of the following
- *     - ENOMEM
- *     - return code from iucv_declare_buffer
- *     - EINVAL - invalid handle passed by application
- *     - EINVAL - pathid address is NULL
- *     - ENOMEM - pathid table storage allocation failed
- *     - return code from internal function add_pathid
- */
-int
-iucv_connect (__u16 *pathid, __u16 msglim_reqstd,
-	      __u8 user_data[16], __u8 userid[8],
-	      __u8 system_name[8], int flags1,
-	      int *flags1_out, __u16 * msglim,
-	      iucv_handle_t handle, void *pgm_data)
-{
-	iparml_control *parm;
-	iparml_control local_parm;
-	struct list_head *lh;
-	ulong b2f0_result = 0;
-	ulong flags;
-	int add_pathid_result = 0;
-	handler *h = NULL;
-	__u8 no_memory[16] = "NO MEMORY";
-
-	iucv_debug(1, "entering");
-
-	/* Checking if handle is valid  */
-	spin_lock_irqsave (&iucv_lock, flags);
-	list_for_each(lh, &iucv_handler_table) {
-		if ((handler *)handle == list_entry(lh, handler, list)) {
-			h = (handler *)handle;
-			break;
-		}
-	}
-	spin_unlock_irqrestore (&iucv_lock, flags);
-
-	if (!h) {
-		if (handle)
-			printk(KERN_WARNING
-			       "%s: Handler not found in iucv_handler_table.\n",
-			       __FUNCTION__);
-		else
-			printk(KERN_WARNING
-			       "%s: NULL handle passed by application.\n",
-			       __FUNCTION__);
-		return -EINVAL;
-	}
-
-	if (pathid == NULL) {
-		printk(KERN_WARNING "%s: NULL pathid pointer\n",
-		       __FUNCTION__);
-		return -EINVAL;
-	}
-
-	parm = (iparml_control *)grab_param();
-
-	parm->ipmsglim = msglim_reqstd;
-
-	if (user_data)
-		memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
-
-	if (userid) {
-		memcpy(parm->ipvmid, userid, sizeof(parm->ipvmid));
-		ASCEBC(parm->ipvmid, sizeof(parm->ipvmid));
-		EBC_TOUPPER(parm->ipvmid, sizeof(parm->ipvmid));
-	}
-
-	if (system_name) {
-		memcpy(parm->iptarget, system_name, sizeof(parm->iptarget));
-		ASCEBC(parm->iptarget, sizeof(parm->iptarget));
-		EBC_TOUPPER(parm->iptarget, sizeof(parm->iptarget));
-	}
-
-	/* In order to establish an IUCV connection, the procedure is:
-         *
-         * b2f0(CONNECT)
-         * take the ippathid from the b2f0 call
-         * register the handler to the ippathid
-         *
-         * Unfortunately, the ConnectionEstablished message gets sent after the
-         * b2f0(CONNECT) call but before the register is handled.
-         *
-         * In order for this race condition to be eliminated, the IUCV Control
-         * Interrupts must be disabled for the above procedure.
-         *
-         * David Kennedy <dkennedy@linuxcare.com>
-         */
-
-	/* Enable everything but IUCV Control messages */
-	iucv_setmask(~(AllInterrupts));
-	messagesDisabled = 1;
-
-	spin_lock_irqsave (&iucv_lock, flags);
-	parm->ipflags1 = (__u8)flags1;
-	b2f0_result = b2f0(CONNECT, parm);
-	memcpy(&local_parm, parm, sizeof(local_parm));
-	release_param(parm);
-	parm = &local_parm;
-	if (!b2f0_result)
-		add_pathid_result = __iucv_add_pathid(parm->ippathid, h);
-	spin_unlock_irqrestore (&iucv_lock, flags);
-
-	if (b2f0_result) {
-		iucv_setmask(~0);
-		messagesDisabled = 0;
-		return b2f0_result;
-	}
-
-	*pathid = parm->ippathid;
-
-	/* Enable everything again */
-	iucv_setmask(IUCVControlInterruptsFlag);
-
-	if (msglim)
-		*msglim = parm->ipmsglim;
-	if (flags1_out)
-		*flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0;
-
-	if (add_pathid_result) {
-		iucv_sever(*pathid, no_memory);
-		printk(KERN_WARNING "%s: add_pathid failed with rc ="
-			" %d\n", __FUNCTION__, add_pathid_result);
-		return(add_pathid_result);
-	}
-
-	iucv_debug(1, "exiting");
-	return b2f0_result;
-}
-
-/**
- * iucv_purge:
- * @pathid: Path identification number
- * @msgid:  Message ID of message to purge.
- * @srccls: Message class of the message to purge.
- * @audit:  Pointer to an __u32. If not NULL, on return, information about
- *          asynchronous errors that may have affected the normal completion
- *          of this message ist stored at the given location.
- *
- * Cancels a message you have sent.
- * Returns: return code from CP
- */
-int
-iucv_purge (__u16 pathid, __u32 msgid, __u32 srccls, __u32 *audit)
-{
-	iparml_purge *parm;
-	ulong b2f0_result = 0;
-
-	iucv_debug(1, "entering");
-	iucv_debug(1, "pathid = %d", pathid);
-
-	parm = (iparml_purge *)grab_param();
-
-	parm->ipmsgid = msgid;
-	parm->ippathid = pathid;
-	parm->ipsrccls = srccls;
-	parm->ipflags1 |= (IPSRCCLS | IPFGMID | IPFGPID);
-	b2f0_result = b2f0(PURGE, parm);
-
-	if (!b2f0_result && audit) {
-		memcpy(audit, parm->ipaudit, sizeof(parm->ipaudit));
-		/* parm->ipaudit has only 3 bytes */
-		*audit >>= 8;
-	}
-
-	release_param(parm);
-
-	iucv_debug(1, "b2f0_result = %ld", b2f0_result);
-	iucv_debug(1, "exiting");
-	return b2f0_result;
-}
-
-/**
- * iucv_query_generic:
- * @want_maxconn: Flag, describing which value is to be returned.
- *
- * Helper function for iucv_query_maxconn() and iucv_query_bufsize().
- *
- * Returns: The buffersize, if want_maxconn is 0; the maximum number of
- *           connections, if want_maxconn is 1 or an error-code < 0 on failure.
- */
-static int
-iucv_query_generic(int want_maxconn)
-{
-	register unsigned long reg0 asm ("0");
-	register unsigned long reg1 asm ("1");
-	iparml_purge *parm = (iparml_purge *)grab_param();
-	int bufsize, maxconn;
-	int ccode;
-
-	/**
-	 * Call b2f0 and store R0 (max buffer size),
-	 * R1 (max connections) and CC.
-	 */
-	reg0 = QUERY;
-	reg1 = virt_to_phys(parm);
-	asm volatile(
-		"	.long	0xb2f01000\n"
-		"	ipm	%0\n"
-		"	srl	%0,28\n"
-		: "=d" (ccode), "+d" (reg0), "+d" (reg1) : : "cc");
-	bufsize = reg0;
-	maxconn = reg1;
-	release_param(parm);
-
-	if (ccode)
-		return -EPERM;
-	if (want_maxconn)
-		return maxconn;
-	return bufsize;
-}
-
-/**
- * iucv_query_maxconn:
- *
- * Determines the maximum number of connections thay may be established.
- *
- * Returns: Maximum number of connections that can be.
- */
-ulong
-iucv_query_maxconn(void)
-{
-	return iucv_query_generic(1);
-}
-
-/**
- * iucv_query_bufsize:
- *
- * Determines the size of the external interrupt buffer.
- *
- * Returns: Size of external interrupt buffer.
- */
-ulong
-iucv_query_bufsize (void)
-{
-	return iucv_query_generic(0);
-}
-
-/**
- * iucv_quiesce:
- * @pathid:    Path identification number
- * @user_data: 16-byte user data
- *
- * Temporarily suspends incoming messages on an IUCV path.
- * You can later reactivate the path by invoking the iucv_resume function.
- * Returns: return code from CP
- */
-int
-iucv_quiesce (__u16 pathid, __u8 user_data[16])
-{
-	iparml_control *parm;
-	ulong b2f0_result = 0;
-
-	iucv_debug(1, "entering");
-	iucv_debug(1, "pathid = %d", pathid);
-
-	parm = (iparml_control *)grab_param();
-
-	memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
-	parm->ippathid = pathid;
-
-	b2f0_result = b2f0(QUIESCE, parm);
-	release_param(parm);
-
-	iucv_debug(1, "b2f0_result = %ld", b2f0_result);
-	iucv_debug(1, "exiting");
-
-	return b2f0_result;
-}
-
-/**
- * iucv_receive:
- * @pathid: Path identification number.
- * @buffer: Address of buffer to receive. Must be below 2G.
- * @buflen: Length of buffer to receive.
- * @msgid:  Specifies the message ID.
- * @trgcls: Specifies target class.
- * @flags1_out: Receives options for path on return.
- *    - IPNORPY (0x10)  Specifies whether a reply is required
- *    - IPPRTY (0x20)   Specifies if you want to send priority message
- *    - IPRMDATA (0x80) Specifies the data is contained in the parameter list
- * @residual_buffer: Receives the address of buffer updated by the number
- *                   of bytes you have received on return.
- * @residual_length: On return, receives one of the following values:
- *    - 0                          If the receive buffer is the same length as
- *                                 the message.
- *    - Remaining bytes in buffer  If the receive buffer is longer than the
- *                                 message.
- *    - Remaining bytes in message If the receive buffer is shorter than the
- *                                 message.
- *
- * This function receives messages that are being sent to you over established
- * paths.
- * Returns: return code from CP IUCV call; If the receive buffer is shorter
- *   than the message, always 5
- *   -EINVAL - buffer address is pointing to NULL
- */
-int
-iucv_receive (__u16 pathid, __u32 msgid, __u32 trgcls,
-	      void *buffer, ulong buflen,
-	      int *flags1_out, ulong * residual_buffer, ulong * residual_length)
-{
-	iparml_db *parm;
-	ulong b2f0_result;
-	int moved = 0;	/* number of bytes moved from parmlist to buffer */
-
-	iucv_debug(2, "entering");
-
-	if (!buffer)
-		return -EINVAL;
-
-	parm = (iparml_db *)grab_param();
-
-	parm->ipbfadr1 = (__u32) (addr_t) buffer;
-	parm->ipbfln1f = (__u32) ((ulong) buflen);
-	parm->ipmsgid = msgid;
-	parm->ippathid = pathid;
-	parm->iptrgcls = trgcls;
-	parm->ipflags1 = (IPFGPID | IPFGMID | IPFGMCL);
-
-	b2f0_result = b2f0(RECEIVE, parm);
-
-	if (!b2f0_result || b2f0_result == 5) {
-		if (flags1_out) {
-			iucv_debug(2, "*flags1_out = %d", *flags1_out);
-			*flags1_out = (parm->ipflags1 & (~0x07));
-			iucv_debug(2, "*flags1_out = %d", *flags1_out);
-		}
-
-		if (!(parm->ipflags1 & IPRMDATA)) {	/*msg not in parmlist */
-			if (residual_length)
-				*residual_length = parm->ipbfln1f;
-
-			if (residual_buffer)
-				*residual_buffer = parm->ipbfadr1;
-		} else {
-			moved = min_t (unsigned long, buflen, 8);
-
-			memcpy ((char *) buffer,
-				(char *) &parm->ipbfadr1, moved);
-
-			if (buflen < 8)
-				b2f0_result = 5;
-
-			if (residual_length)
-				*residual_length = abs (buflen - 8);
-
-			if (residual_buffer)
-				*residual_buffer = (ulong) (buffer + moved);
-		}
-	}
-	release_param(parm);
-
-	iucv_debug(2, "exiting");
-	return b2f0_result;
-}
-
-/*
- * Name: iucv_receive_array
- * Purpose: This function receives messages that are being sent to you
- *          over established paths.
- * Input: pathid - path identification number
- *        buffer - address of array of buffers
- *        buflen - total length of buffers
- *        msgid - specifies the message ID.
- *        trgcls - specifies target class
- * Output:
- *        flags1_out: Options for path.
- *          IPNORPY - 0x10 specifies whether a reply is required
- *          IPPRTY - 0x20 specifies if you want to send priority message
- *         IPRMDATA - 0x80 specifies the data is contained in the parameter list
- *       residual_buffer - address points to the current list entry IUCV
- *                         is working on.
- *       residual_length -
- *              Contains one of the following values, if the receive buffer is:
- *               The same length as the message, this field is zero.
- *               Longer than the message, this field contains the number of
- *                bytes remaining in the buffer.
- *               Shorter than the message, this field contains the residual
- *                count (that is, the number of bytes remaining in the
- *                message that does not fit into the buffer. In this case
- *		  b2f0_result = 5.
- * Return: b2f0_result - return code from CP
- *         (-EINVAL) - buffer address is NULL
- */
-int
-iucv_receive_array (__u16 pathid,
-		    __u32 msgid, __u32 trgcls,
-		    iucv_array_t * buffer, ulong buflen,
-		    int *flags1_out,
-		    ulong * residual_buffer, ulong * residual_length)
-{
-	iparml_db *parm;
-	ulong b2f0_result;
-	int i = 0, moved = 0, need_to_move = 8, dyn_len;
-
-	iucv_debug(2, "entering");
-
-	if (!buffer)
-		return -EINVAL;
-
-	parm = (iparml_db *)grab_param();
-
-	parm->ipbfadr1 = (__u32) ((ulong) buffer);
-	parm->ipbfln1f = (__u32) buflen;
-	parm->ipmsgid = msgid;
-	parm->ippathid = pathid;
-	parm->iptrgcls = trgcls;
-	parm->ipflags1 = (IPBUFLST | IPFGPID | IPFGMID | IPFGMCL);
-
-	b2f0_result = b2f0(RECEIVE, parm);
-
-	if (!b2f0_result || b2f0_result == 5) {
-
-		if (flags1_out) {
-			iucv_debug(2, "*flags1_out = %d", *flags1_out);
-			*flags1_out = (parm->ipflags1 & (~0x07));
-			iucv_debug(2, "*flags1_out = %d", *flags1_out);
-		}
-
-		if (!(parm->ipflags1 & IPRMDATA)) {	/*msg not in parmlist */
-
-			if (residual_length)
-				*residual_length = parm->ipbfln1f;
-
-			if (residual_buffer)
-				*residual_buffer = parm->ipbfadr1;
-
-		} else {
-			/* copy msg from parmlist to users array. */
-
-			while ((moved < 8) && (moved < buflen)) {
-				dyn_len =
-				    min_t (unsigned int,
-					 (buffer + i)->length, need_to_move);
-
-				memcpy ((char *)((ulong)((buffer + i)->address)),
-					((char *) &parm->ipbfadr1) + moved,
-					dyn_len);
-
-				moved += dyn_len;
-				need_to_move -= dyn_len;
-
-				(buffer + i)->address =
-				    	(__u32)
-				((ulong)(__u8 *) ((ulong)(buffer + i)->address)
-						+ dyn_len);
-
-				(buffer + i)->length -= dyn_len;
-				i++;
-			}
-
-			if (need_to_move)	/* buflen < 8 bytes */
-				b2f0_result = 5;
-
-			if (residual_length)
-				*residual_length = abs (buflen - 8);
-
-			if (residual_buffer) {
-				if (!moved)
-					*residual_buffer = (ulong) buffer;
-				else
-					*residual_buffer =
-					    (ulong) (buffer + (i - 1));
-			}
-
-		}
-	}
-	release_param(parm);
-
-	iucv_debug(2, "exiting");
-	return b2f0_result;
-}
-
-/**
- * iucv_reject:
- * @pathid: Path identification number.
- * @msgid:  Message ID of the message to reject.
- * @trgcls: Target class of the message to reject.
- * Returns: return code from CP
- *
- * Refuses a specified message. Between the time you are notified of a
- * message and the time that you complete the message, the message may
- * be rejected.
- */
-int
-iucv_reject (__u16 pathid, __u32 msgid, __u32 trgcls)
-{
-	iparml_db *parm;
-	ulong b2f0_result = 0;
-
-	iucv_debug(1, "entering");
-	iucv_debug(1, "pathid = %d", pathid);
-
-	parm = (iparml_db *)grab_param();
-
-	parm->ippathid = pathid;
-	parm->ipmsgid = msgid;
-	parm->iptrgcls = trgcls;
-	parm->ipflags1 = (IPFGMCL | IPFGMID | IPFGPID);
-
-	b2f0_result = b2f0(REJECT, parm);
-	release_param(parm);
-
-	iucv_debug(1, "b2f0_result = %ld", b2f0_result);
-	iucv_debug(1, "exiting");
-
-	return b2f0_result;
-}
-
-/*
- * Name: iucv_reply
- * Purpose: This function responds to the two-way messages that you
- *          receive. You must identify completely the message to
- *          which you wish to reply. ie, pathid, msgid, and trgcls.
- * Input: pathid - path identification number
- *        msgid - specifies the message ID.
- *        trgcls - specifies target class
- *        flags1 - option for path
- *                 IPPRTY- 0x20 - specifies if you want to send priority message
- *        buffer - address of reply buffer
- *        buflen - length of reply buffer
- * Output: ipbfadr2 - Address of buffer updated by the number
- *                    of bytes you have moved.
- *         ipbfln2f - Contains one of the following values:
- *              If the answer buffer is the same length as the reply, this field
- *               contains zero.
- *              If the answer buffer is longer than the reply, this field contains
- *               the number of bytes remaining in the buffer.
- *              If the answer buffer is shorter than the reply, this field contains
- *               a residual count (that is, the number of bytes remianing in the
- *               reply that does not fit into the buffer. In this
- *                case b2f0_result = 5.
- * Return: b2f0_result - return code from CP
- *         (-EINVAL) - buffer address is NULL
- */
-int
-iucv_reply (__u16 pathid,
-	    __u32 msgid, __u32 trgcls,
-	    int flags1,
-	    void *buffer, ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f)
-{
-	iparml_db *parm;
-	ulong b2f0_result;
-
-	iucv_debug(2, "entering");
-
-	if (!buffer)
-		return -EINVAL;
-
-	parm = (iparml_db *)grab_param();
-
-	parm->ipbfadr2 = (__u32) ((ulong) buffer);
-	parm->ipbfln2f = (__u32) buflen;	/* length of message */
-	parm->ippathid = pathid;
-	parm->ipmsgid = msgid;
-	parm->iptrgcls = trgcls;
-	parm->ipflags1 = (__u8) flags1;	/* priority message */
-
-	b2f0_result = b2f0(REPLY, parm);
-
-	if ((!b2f0_result) || (b2f0_result == 5)) {
-		if (ipbfadr2)
-			*ipbfadr2 = parm->ipbfadr2;
-		if (ipbfln2f)
-			*ipbfln2f = parm->ipbfln2f;
-	}
-	release_param(parm);
-
-	iucv_debug(2, "exiting");
-
-	return b2f0_result;
-}
-
-/*
- * Name: iucv_reply_array
- * Purpose: This function responds to the two-way messages that you
- *          receive. You must identify completely the message to
- *          which you wish to reply. ie, pathid, msgid, and trgcls.
- *          The array identifies a list of addresses and lengths of
- *          discontiguous buffers that contains the reply data.
- * Input: pathid - path identification number
- *        msgid - specifies the message ID.
- *        trgcls - specifies target class
- *        flags1 - option for path
- *                 IPPRTY- specifies if you want to send priority message
- *        buffer - address of array of reply buffers
- *        buflen - total length of reply buffers
- * Output: ipbfadr2 - Address of buffer which IUCV is currently working on.
- *         ipbfln2f - Contains one of the following values:
- *              If the answer buffer is the same length as the reply, this field
- *               contains zero.
- *              If the answer buffer is longer than the reply, this field contains
- *               the number of bytes remaining in the buffer.
- *              If the answer buffer is shorter than the reply, this field contains
- *               a residual count (that is, the number of bytes remianing in the
- *               reply that does not fit into the buffer. In this
- *               case b2f0_result = 5.
- * Return: b2f0_result - return code from CP
- *             (-EINVAL) - buffer address is NULL
-*/
-int
-iucv_reply_array (__u16 pathid,
-		  __u32 msgid, __u32 trgcls,
-		  int flags1,
-		  iucv_array_t * buffer,
-		  ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f)
-{
-	iparml_db *parm;
-	ulong b2f0_result;
-
-	iucv_debug(2, "entering");
-
-	if (!buffer)
-		return -EINVAL;
-
-	parm = (iparml_db *)grab_param();
-
-	parm->ipbfadr2 = (__u32) ((ulong) buffer);
-	parm->ipbfln2f = buflen;	/* length of message */
-	parm->ippathid = pathid;
-	parm->ipmsgid = msgid;
-	parm->iptrgcls = trgcls;
-	parm->ipflags1 = (IPANSLST | flags1);
-
-	b2f0_result = b2f0(REPLY, parm);
-
-	if ((!b2f0_result) || (b2f0_result == 5)) {
-
-		if (ipbfadr2)
-			*ipbfadr2 = parm->ipbfadr2;
-		if (ipbfln2f)
-			*ipbfln2f = parm->ipbfln2f;
-	}
-	release_param(parm);
-
-	iucv_debug(2, "exiting");
-
-	return b2f0_result;
-}
-
-/*
- * Name: iucv_reply_prmmsg
- * Purpose: This function responds to the two-way messages that you
- *          receive. You must identify completely the message to
- *          which you wish to reply. ie, pathid, msgid, and trgcls.
- *          Prmmsg signifies the data is moved into the
- *          parameter list.
- * Input: pathid - path identification number
- *        msgid - specifies the message ID.
- *        trgcls - specifies target class
- *        flags1 - option for path
- *                 IPPRTY- specifies if you want to send priority message
- *        prmmsg - 8-bytes of data to be placed into the parameter
- *                 list.
- * Output: NA
- * Return: b2f0_result - return code from CP
-*/
-int
-iucv_reply_prmmsg (__u16 pathid,
-		   __u32 msgid, __u32 trgcls, int flags1, __u8 prmmsg[8])
-{
-	iparml_dpl *parm;
-	ulong b2f0_result;
-
-	iucv_debug(2, "entering");
-
-	parm = (iparml_dpl *)grab_param();
-
-	parm->ippathid = pathid;
-	parm->ipmsgid = msgid;
-	parm->iptrgcls = trgcls;
-	memcpy(parm->iprmmsg, prmmsg, sizeof (parm->iprmmsg));
-	parm->ipflags1 = (IPRMDATA | flags1);
-
-	b2f0_result = b2f0(REPLY, parm);
-	release_param(parm);
-
-	iucv_debug(2, "exiting");
-
-	return b2f0_result;
-}
-
-/**
- * iucv_resume:
- * @pathid:    Path identification number
- * @user_data: 16-byte of user data
- *
- * This function restores communication over a quiesced path.
- * Returns: return code from CP
- */
-int
-iucv_resume (__u16 pathid, __u8 user_data[16])
-{
-	iparml_control *parm;
-	ulong b2f0_result = 0;
-
-	iucv_debug(1, "entering");
-	iucv_debug(1, "pathid = %d", pathid);
-
-	parm = (iparml_control *)grab_param();
-
-	memcpy (parm->ipuser, user_data, sizeof (*user_data));
-	parm->ippathid = pathid;
-
-	b2f0_result = b2f0(RESUME, parm);
-	release_param(parm);
-
-	iucv_debug(1, "exiting");
-
-	return b2f0_result;
-}
-
-/*
- * Name: iucv_send
- * Purpose: sends messages
- * Input: pathid - ushort, pathid
- *        msgid  - ulong *, id of message returned to caller
- *        trgcls - ulong, target message class
- *        srccls - ulong, source message class
- *        msgtag - ulong, message tag
- *	  flags1  - Contains options for this path.
- *		IPPRTY - Ox20 - specifies if you want to send a priority message.
- *        buffer - pointer to buffer
- *        buflen - ulong, length of buffer
- * Output: b2f0_result - return code from b2f0 call
- *         msgid - returns message id
- */
-int
-iucv_send (__u16 pathid, __u32 * msgid,
-	   __u32 trgcls, __u32 srccls,
-	   __u32 msgtag, int flags1, void *buffer, ulong buflen)
-{
-	iparml_db *parm;
-	ulong b2f0_result;
-
-	iucv_debug(2, "entering");
-
-	if (!buffer)
-		return -EINVAL;
-
-	parm = (iparml_db *)grab_param();
-
-	parm->ipbfadr1 = (__u32) ((ulong) buffer);
-	parm->ippathid = pathid;
-	parm->iptrgcls = trgcls;
-	parm->ipbfln1f = (__u32) buflen;	/* length of message */
-	parm->ipsrccls = srccls;
-	parm->ipmsgtag = msgtag;
-	parm->ipflags1 = (IPNORPY | flags1);	/* one way priority message */
-
-	b2f0_result = b2f0(SEND, parm);
-
-	if ((!b2f0_result) && (msgid))
-		*msgid = parm->ipmsgid;
-	release_param(parm);
-
-	iucv_debug(2, "exiting");
-
-	return b2f0_result;
-}
-
-/*
- * Name: iucv_send_array
- * Purpose: This function transmits data to another application.
- *          The contents of buffer is the address of the array of
- *          addresses and lengths of discontiguous buffers that hold
- *          the message text. This is a one-way message and the
- *          receiver will not reply to the message.
- * Input: pathid - path identification number
- *        trgcls - specifies target class
- *        srccls - specifies the source message class
- *        msgtag - specifies a tag to be associated witht the message
- *        flags1 - option for path
- *                 IPPRTY- specifies if you want to send priority message
- *        buffer - address of array of send buffers
- *        buflen - total length of send buffers
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- *         (-EINVAL) - buffer address is NULL
- */
-int
-iucv_send_array (__u16 pathid,
-		 __u32 * msgid,
-		 __u32 trgcls,
-		 __u32 srccls,
-		 __u32 msgtag, int flags1, iucv_array_t * buffer, ulong buflen)
-{
-	iparml_db *parm;
-	ulong b2f0_result;
-
-	iucv_debug(2, "entering");
-
-	if (!buffer)
-		return -EINVAL;
-
-	parm = (iparml_db *)grab_param();
-
-	parm->ippathid = pathid;
-	parm->iptrgcls = trgcls;
-	parm->ipbfadr1 = (__u32) ((ulong) buffer);
-	parm->ipbfln1f = (__u32) buflen;	/* length of message */
-	parm->ipsrccls = srccls;
-	parm->ipmsgtag = msgtag;
-	parm->ipflags1 = (IPNORPY | IPBUFLST | flags1);
-	b2f0_result = b2f0(SEND, parm);
-
-	if ((!b2f0_result) && (msgid))
-		*msgid = parm->ipmsgid;
-	release_param(parm);
-
-	iucv_debug(2, "exiting");
-	return b2f0_result;
-}
-
-/*
- * Name: iucv_send_prmmsg
- * Purpose: This function transmits data to another application.
- *          Prmmsg specifies that the 8-bytes of data are to be moved
- *          into the parameter list. This is a one-way message and the
- *          receiver will not reply to the message.
- * Input: pathid - path identification number
- *        trgcls - specifies target class
- *        srccls - specifies the source message class
- *        msgtag - specifies a tag to be associated with the message
- *        flags1 - option for path
- *                 IPPRTY- specifies if you want to send priority message
- *        prmmsg - 8-bytes of data to be placed into parameter list
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
-*/
-int
-iucv_send_prmmsg (__u16 pathid,
-		  __u32 * msgid,
-		  __u32 trgcls,
-		  __u32 srccls, __u32 msgtag, int flags1, __u8 prmmsg[8])
-{
-	iparml_dpl *parm;
-	ulong b2f0_result;
-
-	iucv_debug(2, "entering");
-
-	parm = (iparml_dpl *)grab_param();
-
-	parm->ippathid = pathid;
-	parm->iptrgcls = trgcls;
-	parm->ipsrccls = srccls;
-	parm->ipmsgtag = msgtag;
-	parm->ipflags1 = (IPRMDATA | IPNORPY | flags1);
-	memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg));
-
-	b2f0_result = b2f0(SEND, parm);
-
-	if ((!b2f0_result) && (msgid))
-		*msgid = parm->ipmsgid;
-	release_param(parm);
-
-	iucv_debug(2, "exiting");
-
-	return b2f0_result;
-}
-
-/*
- * Name: iucv_send2way
- * Purpose: This function transmits data to another application.
- *          Data to be transmitted is in a buffer. The receiver
- *          of the send is expected to reply to the message and
- *          a buffer is provided into which IUCV moves the reply
- *          to this message.
- * Input: pathid - path identification number
- *        trgcls - specifies target class
- *        srccls - specifies the source message class
- *        msgtag - specifies a tag associated with the message
- *        flags1 - option for path
- *                 IPPRTY- specifies if you want to send priority message
- *        buffer - address of send buffer
- *        buflen - length of send buffer
- *        ansbuf - address of buffer to reply with
- *        anslen - length of buffer to reply with
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- *         (-EINVAL) - buffer or ansbuf address is NULL
- */
-int
-iucv_send2way (__u16 pathid,
-	       __u32 * msgid,
-	       __u32 trgcls,
-	       __u32 srccls,
-	       __u32 msgtag,
-	       int flags1,
-	       void *buffer, ulong buflen, void *ansbuf, ulong anslen)
-{
-	iparml_db *parm;
-	ulong b2f0_result;
-
-	iucv_debug(2, "entering");
-
-	if (!buffer || !ansbuf)
-		return -EINVAL;
-
-	parm = (iparml_db *)grab_param();
-
-	parm->ippathid = pathid;
-	parm->iptrgcls = trgcls;
-	parm->ipbfadr1 = (__u32) ((ulong) buffer);
-	parm->ipbfln1f = (__u32) buflen;	/* length of message */
-	parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
-	parm->ipbfln2f = (__u32) anslen;
-	parm->ipsrccls = srccls;
-	parm->ipmsgtag = msgtag;
-	parm->ipflags1 = flags1;	/* priority message */
-
-	b2f0_result = b2f0(SEND, parm);
-
-	if ((!b2f0_result) && (msgid))
-		*msgid = parm->ipmsgid;
-	release_param(parm);
-
-	iucv_debug(2, "exiting");
-
-	return b2f0_result;
-}
-
-/*
- * Name: iucv_send2way_array
- * Purpose: This function transmits data to another application.
- *          The contents of buffer is the address of the array of
- *          addresses and lengths of discontiguous buffers that hold
- *          the message text. The receiver of the send is expected to
- *          reply to the message and a buffer is provided into which
- *          IUCV moves the reply to this message.
- * Input: pathid - path identification number
- *        trgcls - specifies target class
- *        srccls - specifies the source message class
- *        msgtag - spcifies a tag to be associated with the message
- *        flags1 - option for path
- *                 IPPRTY- specifies if you want to send priority message
- *        buffer - address of array of send buffers
- *        buflen - total length of send buffers
- *        ansbuf - address of buffer to reply with
- *        anslen - length of buffer to reply with
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- *         (-EINVAL) - buffer address is NULL
- */
-int
-iucv_send2way_array (__u16 pathid,
-		     __u32 * msgid,
-		     __u32 trgcls,
-		     __u32 srccls,
-		     __u32 msgtag,
-		     int flags1,
-		     iucv_array_t * buffer,
-		     ulong buflen, iucv_array_t * ansbuf, ulong anslen)
-{
-	iparml_db *parm;
-	ulong b2f0_result;
-
-	iucv_debug(2, "entering");
-
-	if (!buffer || !ansbuf)
-		return -EINVAL;
-
-	parm = (iparml_db *)grab_param();
-
-	parm->ippathid = pathid;
-	parm->iptrgcls = trgcls;
-	parm->ipbfadr1 = (__u32) ((ulong) buffer);
-	parm->ipbfln1f = (__u32) buflen;	/* length of message */
-	parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
-	parm->ipbfln2f = (__u32) anslen;
-	parm->ipsrccls = srccls;
-	parm->ipmsgtag = msgtag;
-	parm->ipflags1 = (IPBUFLST | IPANSLST | flags1);
-	b2f0_result = b2f0(SEND, parm);
-	if ((!b2f0_result) && (msgid))
-		*msgid = parm->ipmsgid;
-	release_param(parm);
-
-	iucv_debug(2, "exiting");
-	return b2f0_result;
-}
-
-/*
- * Name: iucv_send2way_prmmsg
- * Purpose: This function transmits data to another application.
- *          Prmmsg specifies that the 8-bytes of data are to be moved
- *          into the parameter list. This is a two-way message and the
- *          receiver of the message is expected to reply. A buffer
- *          is provided into which IUCV moves the reply to this
- *          message.
- * Input: pathid - path identification number
- *        trgcls - specifies target class
- *        srccls - specifies the source message class
- *        msgtag - specifies a tag to be associated with the message
- *        flags1 - option for path
- *                 IPPRTY- specifies if you want to send priority message
- *        prmmsg - 8-bytes of data to be placed in parameter list
- *        ansbuf - address of buffer to reply with
- *        anslen - length of buffer to reply with
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- *         (-EINVAL) - buffer address is NULL
-*/
-int
-iucv_send2way_prmmsg (__u16 pathid,
-		      __u32 * msgid,
-		      __u32 trgcls,
-		      __u32 srccls,
-		      __u32 msgtag,
-		      ulong flags1, __u8 prmmsg[8], void *ansbuf, ulong anslen)
-{
-	iparml_dpl *parm;
-	ulong b2f0_result;
-
-	iucv_debug(2, "entering");
-
-	if (!ansbuf)
-		return -EINVAL;
-
-	parm = (iparml_dpl *)grab_param();
-
-	parm->ippathid = pathid;
-	parm->iptrgcls = trgcls;
-	parm->ipsrccls = srccls;
-	parm->ipmsgtag = msgtag;
-	parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
-	parm->ipbfln2f = (__u32) anslen;
-	parm->ipflags1 = (IPRMDATA | flags1);	/* message in prmlist */
-	memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg));
-
-	b2f0_result = b2f0(SEND, parm);
-
-	if ((!b2f0_result) && (msgid))
-		*msgid = parm->ipmsgid;
-	release_param(parm);
-
-	iucv_debug(2, "exiting");
-
-	return b2f0_result;
-}
-
-/*
- * Name: iucv_send2way_prmmsg_array
- * Purpose: This function transmits data to another application.
- *          Prmmsg specifies that the 8-bytes of data are to be moved
- *          into the parameter list. This is a two-way message and the
- *          receiver of the message is expected to reply. A buffer
- *          is provided into which IUCV moves the reply to this
- *          message. The contents of ansbuf is the address of the
- *          array of addresses and lengths of discontiguous buffers
- *          that contain the reply.
- * Input: pathid - path identification number
- *        trgcls - specifies target class
- *        srccls - specifies the source message class
- *        msgtag - specifies a tag to be associated with the message
- *        flags1 - option for path
- *                 IPPRTY- specifies if you want to send priority message
- *        prmmsg - 8-bytes of data to be placed into the parameter list
- *        ansbuf - address of buffer to reply with
- *        anslen - length of buffer to reply with
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- *         (-EINVAL) - ansbuf address is NULL
- */
-int
-iucv_send2way_prmmsg_array (__u16 pathid,
-			    __u32 * msgid,
-			    __u32 trgcls,
-			    __u32 srccls,
-			    __u32 msgtag,
-			    int flags1,
-			    __u8 prmmsg[8],
-			    iucv_array_t * ansbuf, ulong anslen)
-{
-	iparml_dpl *parm;
-	ulong b2f0_result;
-
-	iucv_debug(2, "entering");
-
-	if (!ansbuf)
-		return -EINVAL;
-
-	parm = (iparml_dpl *)grab_param();
-
-	parm->ippathid = pathid;
-	parm->iptrgcls = trgcls;
-	parm->ipsrccls = srccls;
-	parm->ipmsgtag = msgtag;
-	parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
-	parm->ipbfln2f = (__u32) anslen;
-	parm->ipflags1 = (IPRMDATA | IPANSLST | flags1);
-	memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg));
-	b2f0_result = b2f0(SEND, parm);
-	if ((!b2f0_result) && (msgid))
-		*msgid = parm->ipmsgid;
-	release_param(parm);
-
-	iucv_debug(2, "exiting");
-	return b2f0_result;
-}
-
-void
-iucv_setmask_cpuid (void *result)
-{
-        iparml_set_mask *parm;
-
-        iucv_debug(1, "entering");
-        parm = (iparml_set_mask *)grab_param();
-        parm->ipmask = *((__u8*)result);
-        *((ulong *)result) = b2f0(SETMASK, parm);
-        release_param(parm);
-
-        iucv_debug(1, "b2f0_result = %ld", *((ulong *)result));
-        iucv_debug(1, "exiting");
-}
-
-/*
- * Name: iucv_setmask
- * Purpose: This function enables or disables the following IUCV
- *          external interruptions: Nonpriority and priority message
- *          interrupts, nonpriority and priority reply interrupts.
- * Input: SetMaskFlag - options for interrupts
- *           0x80 - Nonpriority_MessagePendingInterruptsFlag
- *           0x40 - Priority_MessagePendingInterruptsFlag
- *           0x20 - Nonpriority_MessageCompletionInterruptsFlag
- *           0x10 - Priority_MessageCompletionInterruptsFlag
- *           0x08 - IUCVControlInterruptsFlag
- * Output: NA
- * Return: b2f0_result - return code from CP
-*/
-int
-iucv_setmask (int SetMaskFlag)
-{
-	union {
-		ulong result;
-		__u8  param;
-	} u;
-	int cpu;
-
-	u.param = SetMaskFlag;
-	cpu = get_cpu();
-	smp_call_function_on(iucv_setmask_cpuid, &u, 0, 1, iucv_cpuid);
-	put_cpu();
-
-	return u.result;
-}
-
-/**
- * iucv_sever:
- * @pathid:    Path identification number
- * @user_data: 16-byte of user data
- *
- * This function terminates an iucv path.
- * Returns: return code from CP
- */
-int
-iucv_sever(__u16 pathid, __u8 user_data[16])
-{
-	iparml_control *parm;
-	ulong b2f0_result = 0;
-
-	iucv_debug(1, "entering");
-	parm = (iparml_control *)grab_param();
-
-	memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
-	parm->ippathid = pathid;
-
-	b2f0_result = b2f0(SEVER, parm);
-
-	if (!b2f0_result)
-		iucv_remove_pathid(pathid);
-	release_param(parm);
-
-	iucv_debug(1, "exiting");
-	return b2f0_result;
-}
-
-/*
- * Interrupt Handlers
- *******************************************************************************/
-
-/**
- * iucv_irq_handler:
- * @regs: Current registers
- * @code: irq code
- *
- * Handles external interrupts coming in from CP.
- * Places the interrupt buffer on a queue and schedules iucv_tasklet_handler().
- */
-static void
-iucv_irq_handler(__u16 code)
-{
-	iucv_irqdata *irqdata;
-
-	irqdata = kmalloc(sizeof(iucv_irqdata), GFP_ATOMIC);
-	if (!irqdata) {
-		printk(KERN_WARNING "%s: out of memory\n", __FUNCTION__);
-		return;
-	}
-
-	memcpy(&irqdata->data, iucv_external_int_buffer,
-	       sizeof(iucv_GeneralInterrupt));
-
-	spin_lock(&iucv_irq_queue_lock);
-	list_add_tail(&irqdata->queue, &iucv_irq_queue);
-	spin_unlock(&iucv_irq_queue_lock);
-
-	tasklet_schedule(&iucv_tasklet);
-}
-
-/**
- * iucv_do_int:
- * @int_buf: Pointer to copy of external interrupt buffer
- *
- * The workhorse for handling interrupts queued by iucv_irq_handler().
- * This function is called from the bottom half iucv_tasklet_handler().
- */
-static void
-iucv_do_int(iucv_GeneralInterrupt * int_buf)
-{
-	handler *h = NULL;
-	struct list_head *lh;
-	ulong flags;
-	iucv_interrupt_ops_t *interrupt = NULL;	/* interrupt addresses */
-	__u8 temp_buff1[24], temp_buff2[24];	/* masked handler id. */
-	int rc = 0, j = 0;
-	__u8 no_listener[16] = "NO LISTENER";
-
-	iucv_debug(2, "entering, pathid %d, type %02X",
-		 int_buf->ippathid, int_buf->iptype);
-	iucv_dumpit("External Interrupt Buffer:",
-		    int_buf, sizeof(iucv_GeneralInterrupt));
-
-	ASCEBC (no_listener, 16);
-
-	if (int_buf->iptype != 01) {
-		if ((int_buf->ippathid) > (max_connections - 1)) {
-			printk(KERN_WARNING "%s: Got interrupt with pathid %d"
-			       " > max_connections (%ld)\n", __FUNCTION__,
-			       int_buf->ippathid, max_connections - 1);
-		} else {
-			h = iucv_pathid_table[int_buf->ippathid];
-			interrupt = h->interrupt_table;
-			iucv_dumpit("Handler:", h, sizeof(handler));
-		}
-	}
-
-	/* end of if statement */
-	switch (int_buf->iptype) {
-		case 0x01:		/* connection pending */
-			if (messagesDisabled) {
-			    iucv_setmask(~0);
-			    messagesDisabled = 0;
-			}
-			spin_lock_irqsave(&iucv_lock, flags);
-			list_for_each(lh, &iucv_handler_table) {
-				h = list_entry(lh, handler, list);
-				memcpy(temp_buff1, &(int_buf->ipvmid), 24);
-				memcpy(temp_buff2, &(h->id.userid), 24);
-				for (j = 0; j < 24; j++) {
-					temp_buff1[j] &= (h->id.mask)[j];
-					temp_buff2[j] &= (h->id.mask)[j];
-				}
-
-				iucv_dumpit("temp_buff1:",
-					    temp_buff1, sizeof(temp_buff1));
-				iucv_dumpit("temp_buff2",
-					    temp_buff2, sizeof(temp_buff2));
-
-				if (!memcmp (temp_buff1, temp_buff2, 24)) {
-
-					iucv_debug(2,
-						   "found a matching handler");
-					break;
-				} else
-					h = NULL;
-			}
-			spin_unlock_irqrestore (&iucv_lock, flags);
-			if (h) {
-				/* ADD PATH TO PATHID TABLE */
-				rc = iucv_add_pathid(int_buf->ippathid, h);
-				if (rc) {
-					iucv_sever (int_buf->ippathid,
-						    no_listener);
-					iucv_debug(1,
-						   "add_pathid failed, rc = %d",
-						   rc);
-				} else {
-					interrupt = h->interrupt_table;
-					if (interrupt->ConnectionPending) {
-						EBCASC (int_buf->ipvmid, 8);
-						interrupt->ConnectionPending(
-							(iucv_ConnectionPending *)int_buf,
-							h->pgm_data);
-					} else
-						iucv_sever(int_buf->ippathid,
-							   no_listener);
-				}
-			} else
-				iucv_sever(int_buf->ippathid, no_listener);
-			break;
-
-		case 0x02:		/*connection complete */
-			if (messagesDisabled) {
-			    iucv_setmask(~0);
-			    messagesDisabled = 0;
-			}
-			if (h) {
-				if (interrupt->ConnectionComplete)
-				{
-					interrupt->ConnectionComplete(
-						(iucv_ConnectionComplete *)int_buf,
-						h->pgm_data);
-				}
-				else
-					iucv_debug(1,
-						   "ConnectionComplete not called");
-			} else
-				iucv_sever(int_buf->ippathid, no_listener);
-			break;
-
-		case 0x03:		/* connection severed */
-			if (messagesDisabled) {
-			    iucv_setmask(~0);
-			    messagesDisabled = 0;
-			}
-			if (h) {
-				if (interrupt->ConnectionSevered)
-					interrupt->ConnectionSevered(
-						(iucv_ConnectionSevered *)int_buf,
-						h->pgm_data);
-
-				else
-					iucv_sever (int_buf->ippathid, no_listener);
-			} else
-				iucv_sever(int_buf->ippathid, no_listener);
-			break;
-
-		case 0x04:		/* connection quiesced */
-			if (messagesDisabled) {
-			    iucv_setmask(~0);
-			    messagesDisabled = 0;
-			}
-			if (h) {
-				if (interrupt->ConnectionQuiesced)
-					interrupt->ConnectionQuiesced(
-						(iucv_ConnectionQuiesced *)int_buf,
-						h->pgm_data);
-				else
-					iucv_debug(1,
-						   "ConnectionQuiesced not called");
-			}
-			break;
-
-		case 0x05:		/* connection resumed */
-			if (messagesDisabled) {
-			    iucv_setmask(~0);
-			    messagesDisabled = 0;
-			}
-			if (h) {
-				if (interrupt->ConnectionResumed)
-					interrupt->ConnectionResumed(
-						(iucv_ConnectionResumed *)int_buf,
-						h->pgm_data);
-				else
-					iucv_debug(1,
-						   "ConnectionResumed not called");
-			}
-			break;
-
-		case 0x06:		/* priority message complete */
-		case 0x07:		/* nonpriority message complete */
-			if (h) {
-				if (interrupt->MessageComplete)
-					interrupt->MessageComplete(
-						(iucv_MessageComplete *)int_buf,
-						h->pgm_data);
-				else
-					iucv_debug(2,
-						   "MessageComplete not called");
-			}
-			break;
-
-		case 0x08:		/* priority message pending  */
-		case 0x09:		/* nonpriority message pending  */
-			if (h) {
-				if (interrupt->MessagePending)
-					interrupt->MessagePending(
-						(iucv_MessagePending *) int_buf,
-						h->pgm_data);
-				else
-					iucv_debug(2,
-						   "MessagePending not called");
-			}
-			break;
-		default:		/* unknown iucv type */
-			printk(KERN_WARNING "%s: unknown iucv interrupt\n",
-			       __FUNCTION__);
-			break;
-	}			/* end switch */
-
-	iucv_debug(2, "exiting pathid %d, type %02X",
-		 int_buf->ippathid, int_buf->iptype);
-
-	return;
-}
-
-/**
- * iucv_tasklet_handler:
- *
- * This function loops over the queue of irq buffers and runs iucv_do_int()
- * on every queue element.
- */
-static void
-iucv_tasklet_handler(unsigned long ignored)
-{
-	struct list_head head;
-	struct list_head *next;
-	ulong  flags;
-
-	spin_lock_irqsave(&iucv_irq_queue_lock, flags);
-	list_add(&head, &iucv_irq_queue);
-	list_del_init(&iucv_irq_queue);
-	spin_unlock_irqrestore (&iucv_irq_queue_lock, flags);
-
-	next = head.next;
-	while (next != &head) {
-		iucv_irqdata *p = list_entry(next, iucv_irqdata, queue);
-
-		next = next->next;
-		iucv_do_int(&p->data);
-		kfree(p);
-	}
-
-	return;
-}
-
-subsys_initcall(iucv_init);
-module_exit(iucv_exit);
-
-/**
- * Export all public stuff
- */
-EXPORT_SYMBOL (iucv_bus);
-EXPORT_SYMBOL (iucv_root);
-EXPORT_SYMBOL (iucv_accept);
-EXPORT_SYMBOL (iucv_connect);
-#if 0
-EXPORT_SYMBOL (iucv_purge);
-EXPORT_SYMBOL (iucv_query_maxconn);
-EXPORT_SYMBOL (iucv_query_bufsize);
-EXPORT_SYMBOL (iucv_quiesce);
-#endif
-EXPORT_SYMBOL (iucv_receive);
-#if 0
-EXPORT_SYMBOL (iucv_receive_array);
-#endif
-EXPORT_SYMBOL (iucv_reject);
-#if 0
-EXPORT_SYMBOL (iucv_reply);
-EXPORT_SYMBOL (iucv_reply_array);
-EXPORT_SYMBOL (iucv_resume);
-#endif
-EXPORT_SYMBOL (iucv_reply_prmmsg);
-EXPORT_SYMBOL (iucv_send);
-EXPORT_SYMBOL (iucv_send2way);
-EXPORT_SYMBOL (iucv_send2way_array);
-EXPORT_SYMBOL (iucv_send2way_prmmsg);
-EXPORT_SYMBOL (iucv_send2way_prmmsg_array);
-#if 0
-EXPORT_SYMBOL (iucv_send_array);
-EXPORT_SYMBOL (iucv_send_prmmsg);
-EXPORT_SYMBOL (iucv_setmask);
-#endif
-EXPORT_SYMBOL (iucv_sever);
-EXPORT_SYMBOL (iucv_register_program);
-EXPORT_SYMBOL (iucv_unregister_program);
diff --git a/drivers/s390/net/iucv.h b/drivers/s390/net/iucv.h
deleted file mode 100644
index 5b6b1b7..0000000
--- a/drivers/s390/net/iucv.h
+++ /dev/null
@@ -1,849 +0,0 @@
-/*
- *  drivers/s390/net/iucv.h
- *    IUCV base support.
- *
- *  S390 version
- *    Copyright (C) 2000 IBM Corporation
- *    Author(s):Alan Altmark (Alan_Altmark@us.ibm.com)
- *		Xenia Tkatschow (xenia@us.ibm.com)
- *
- *
- * Functionality:
- * To explore any of the IUCV functions, one must first register
- * their program using iucv_register_program(). Once your program has
- * successfully completed a register, it can exploit the other functions.
- * For furthur reference on all IUCV functionality, refer to the
- * CP Programming Services book, also available on the web
- * thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
- *
- *      Definition of Return Codes
- *      -All positive return codes including zero are reflected back
- *       from CP except for iucv_register_program. The definition of each
- *       return code can be found in CP Programming Services book.
- *       Also available on the web thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
- *      - Return Code of:
- *             (-EINVAL) Invalid value
- *             (-ENOMEM) storage allocation failed
- *	pgmask defined in iucv_register_program will be set depending on input
- *	paramters.
- *
- */
-
-#include <linux/types.h>
-#include <asm/debug.h>
-
-/**
- * Debug Facility stuff
- */
-#define IUCV_DBF_SETUP_NAME "iucv_setup"
-#define IUCV_DBF_SETUP_LEN 32
-#define IUCV_DBF_SETUP_PAGES 2
-#define IUCV_DBF_SETUP_NR_AREAS 1
-#define IUCV_DBF_SETUP_LEVEL 3
-
-#define IUCV_DBF_DATA_NAME "iucv_data"
-#define IUCV_DBF_DATA_LEN 128
-#define IUCV_DBF_DATA_PAGES 2
-#define IUCV_DBF_DATA_NR_AREAS 1
-#define IUCV_DBF_DATA_LEVEL 2
-
-#define IUCV_DBF_TRACE_NAME "iucv_trace"
-#define IUCV_DBF_TRACE_LEN 16
-#define IUCV_DBF_TRACE_PAGES 4
-#define IUCV_DBF_TRACE_NR_AREAS 1
-#define IUCV_DBF_TRACE_LEVEL 3
-
-#define IUCV_DBF_TEXT(name,level,text) \
-	do { \
-		debug_text_event(iucv_dbf_##name,level,text); \
-	} while (0)
-
-#define IUCV_DBF_HEX(name,level,addr,len) \
-	do { \
-		debug_event(iucv_dbf_##name,level,(void*)(addr),len); \
-	} while (0)
-
-DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf);
-
-#define IUCV_DBF_TEXT_(name,level,text...)				\
-	do {								\
-		char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf);	\
-		sprintf(iucv_dbf_txt_buf, text);		  	\
-		debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \
-		put_cpu_var(iucv_dbf_txt_buf);				\
-	} while (0)
-
-#define IUCV_DBF_SPRINTF(name,level,text...) \
-	do { \
-		debug_sprintf_event(iucv_dbf_trace, level, ##text ); \
-		debug_sprintf_event(iucv_dbf_trace, level, text ); \
-	} while (0)
-
-/**
- * some more debug stuff
- */
-#define IUCV_HEXDUMP16(importance,header,ptr) \
-PRINT_##importance(header "%02x %02x %02x %02x  %02x %02x %02x %02x  " \
-		   "%02x %02x %02x %02x  %02x %02x %02x %02x\n", \
-		   *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \
-		   *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \
-		   *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \
-		   *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \
-		   *(((char*)ptr)+12),*(((char*)ptr)+13), \
-		   *(((char*)ptr)+14),*(((char*)ptr)+15)); \
-PRINT_##importance(header "%02x %02x %02x %02x  %02x %02x %02x %02x  " \
-		   "%02x %02x %02x %02x  %02x %02x %02x %02x\n", \
-		   *(((char*)ptr)+16),*(((char*)ptr)+17), \
-		   *(((char*)ptr)+18),*(((char*)ptr)+19), \
-		   *(((char*)ptr)+20),*(((char*)ptr)+21), \
-		   *(((char*)ptr)+22),*(((char*)ptr)+23), \
-		   *(((char*)ptr)+24),*(((char*)ptr)+25), \
-		   *(((char*)ptr)+26),*(((char*)ptr)+27), \
-		   *(((char*)ptr)+28),*(((char*)ptr)+29), \
-		   *(((char*)ptr)+30),*(((char*)ptr)+31));
-
-static inline void
-iucv_hex_dump(unsigned char *buf, size_t len)
-{
-	size_t i;
-
-	for (i = 0; i < len; i++) {
-		if (i && !(i % 16))
-			printk("\n");
-		printk("%02x ", *(buf + i));
-	}
-	printk("\n");
-}
-/**
- * end of debug stuff
- */
-
-#define uchar  unsigned char
-#define ushort unsigned short
-#define ulong  unsigned long
-#define iucv_handle_t void *
-
-/* flags1:
- * All flags are defined in the field IPFLAGS1 of each function
- * and can be found in CP Programming Services.
- * IPLOCAL  - Indicates the connect can only be satisfied on the
- *            local system
- * IPPRTY   - Indicates a priority message
- * IPQUSCE  - Indicates you do not want to receive messages on a
- *            path until an iucv_resume is issued
- * IPRMDATA - Indicates that the message is in the parameter list
- */
-#define IPLOCAL   	0x01
-#define IPPRTY         	0x20
-#define IPQUSCE        	0x40
-#define IPRMDATA       	0x80
-
-/* flags1_out:
- * All flags are defined in the output field of IPFLAGS1 for each function
- * and can be found in CP Programming Services.
- * IPNORPY - Specifies this is a one-way message and no reply is expected.
- * IPPRTY   - Indicates a priority message is permitted. Defined in flags1.
- */
-#define IPNORPY         0x10
-
-#define Nonpriority_MessagePendingInterruptsFlag         0x80
-#define Priority_MessagePendingInterruptsFlag            0x40
-#define Nonpriority_MessageCompletionInterruptsFlag      0x20
-#define Priority_MessageCompletionInterruptsFlag         0x10
-#define IUCVControlInterruptsFlag                        0x08
-#define AllInterrupts                                    0xf8
-/*
- * Mapping of external interrupt buffers should be used with the corresponding
- * interrupt types.
- * Names: iucv_ConnectionPending    ->  connection pending
- *        iucv_ConnectionComplete   ->  connection complete
- *        iucv_ConnectionSevered    ->  connection severed
- *        iucv_ConnectionQuiesced   ->  connection quiesced
- *        iucv_ConnectionResumed    ->  connection resumed
- *        iucv_MessagePending       ->  message pending
- *        iucv_MessageComplete      ->  message complete
- */
-typedef struct {
-	u16 ippathid;
-	uchar ipflags1;
-	uchar iptype;
-	u16 ipmsglim;
-	u16 res1;
-	uchar ipvmid[8];
-	uchar ipuser[16];
-	u32 res3;
-	uchar ippollfg;
-	uchar res4[3];
-} iucv_ConnectionPending;
-
-typedef struct {
-	u16 ippathid;
-	uchar ipflags1;
-	uchar iptype;
-	u16 ipmsglim;
-	u16 res1;
-	uchar res2[8];
-	uchar ipuser[16];
-	u32 res3;
-	uchar ippollfg;
-	uchar res4[3];
-} iucv_ConnectionComplete;
-
-typedef struct {
-	u16 ippathid;
-	uchar res1;
-	uchar iptype;
-	u32 res2;
-	uchar res3[8];
-	uchar ipuser[16];
-	u32 res4;
-	uchar ippollfg;
-	uchar res5[3];
-} iucv_ConnectionSevered;
-
-typedef struct {
-	u16 ippathid;
-	uchar res1;
-	uchar iptype;
-	u32 res2;
-	uchar res3[8];
-	uchar ipuser[16];
-	u32 res4;
-	uchar ippollfg;
-	uchar res5[3];
-} iucv_ConnectionQuiesced;
-
-typedef struct {
-	u16 ippathid;
-	uchar res1;
-	uchar iptype;
-	u32 res2;
-	uchar res3[8];
-	uchar ipuser[16];
-	u32 res4;
-	uchar ippollfg;
-	uchar res5[3];
-} iucv_ConnectionResumed;
-
-typedef struct {
-	u16 ippathid;
-	uchar ipflags1;
-	uchar iptype;
-	u32 ipmsgid;
-	u32 iptrgcls;
-	union u2 {
-		u32 iprmmsg1_u32;
-		uchar iprmmsg1[4];
-	} ln1msg1;
-	union u1 {
-		u32 ipbfln1f;
-		uchar iprmmsg2[4];
-	} ln1msg2;
-	u32 res1[3];
-	u32 ipbfln2f;
-	uchar ippollfg;
-	uchar res2[3];
-} iucv_MessagePending;
-
-typedef struct {
-	u16 ippathid;
-	uchar ipflags1;
-	uchar iptype;
-	u32 ipmsgid;
-	u32 ipaudit;
-	uchar iprmmsg[8];
-	u32 ipsrccls;
-	u32 ipmsgtag;
-	u32 res;
-	u32 ipbfln2f;
-	uchar ippollfg;
-	uchar res2[3];
-} iucv_MessageComplete;
-
-/*
- * iucv_interrupt_ops_t: Is a vector of functions that handle
- * IUCV interrupts.
- * Parameter list:
- *         eib - is a pointer to a 40-byte area described
- *               with one of the structures above.
- *         pgm_data - this data is strictly for the
- *                    interrupt handler that is passed by
- *                    the application. This may be an address
- *                    or token.
-*/
-typedef struct {
-	void (*ConnectionPending) (iucv_ConnectionPending * eib,
-				   void *pgm_data);
-	void (*ConnectionComplete) (iucv_ConnectionComplete * eib,
-				    void *pgm_data);
-	void (*ConnectionSevered) (iucv_ConnectionSevered * eib,
-				   void *pgm_data);
-	void (*ConnectionQuiesced) (iucv_ConnectionQuiesced * eib,
-				    void *pgm_data);
-	void (*ConnectionResumed) (iucv_ConnectionResumed * eib,
-				   void *pgm_data);
-	void (*MessagePending) (iucv_MessagePending * eib, void *pgm_data);
-	void (*MessageComplete) (iucv_MessageComplete * eib, void *pgm_data);
-} iucv_interrupt_ops_t;
-
-/*
- *iucv_array_t : Defines buffer array.
- * Inside the array may be 31- bit addresses and 31-bit lengths.
-*/
-typedef struct {
-	u32 address;
-	u32 length;
-} iucv_array_t __attribute__ ((aligned (8)));
-
-extern struct bus_type iucv_bus;
-extern struct device *iucv_root;
-
-/*   -prototypes-    */
-/*
- * Name: iucv_register_program
- * Purpose: Registers an application with IUCV
- * Input: prmname - user identification
- *        userid  - machine identification
- *        pgmmask - indicates which bits in the prmname and userid combined will be
- *  		    used to determine who is given control
- *        ops     - address of vector of interrupt handlers
- *        pgm_data- application data passed to interrupt handlers
- * Output: NA
- * Return: address of handler
- *         (0) - Error occurred, registration not completed.
- * NOTE: Exact cause of failure will be recorded in syslog.
-*/
-iucv_handle_t iucv_register_program (uchar pgmname[16],
-				     uchar userid[8],
-				     uchar pgmmask[24],
-				     iucv_interrupt_ops_t * ops,
-				     void *pgm_data);
-
-/*
- * Name: iucv_unregister_program
- * Purpose: Unregister application with IUCV
- * Input: address of handler
- * Output: NA
- * Return: (0) - Normal return
- *         (-EINVAL) - Internal error, wild pointer
-*/
-int iucv_unregister_program (iucv_handle_t handle);
-
-/*
- * Name: iucv_accept
- * Purpose: This function is issued after the user receives a Connection Pending external
- *          interrupt and now wishes to complete the IUCV communication path.
- * Input:  pathid - u16 , Path identification number
- *         msglim_reqstd - u16, The number of outstanding messages requested.
- *         user_data - uchar[16], Data specified by the iucv_connect function.
- *	   flags1 - int, Contains options for this path.
- *           -IPPRTY   - 0x20- Specifies if you want to send priority message.
- *           -IPRMDATA - 0x80, Specifies whether your program can handle a message
- *            	in  the parameter list.
- *           -IPQUSCE  - 0x40, Specifies whether you want to quiesce the path being
- *		established.
- *         handle - iucv_handle_t, Address of handler.
- *         pgm_data - void *, Application data passed to interrupt handlers.
- *         flags1_out - int * Contains information about the path
- *           - IPPRTY - 0x20, Indicates you may send priority messages.
- *         msglim - *u16, Number of outstanding messages.
- * Output: return code from CP IUCV call.
-*/
-
-int iucv_accept (u16 pathid,
-		 u16 msglim_reqstd,
-		 uchar user_data[16],
-		 int flags1,
-		 iucv_handle_t handle,
-		 void *pgm_data, int *flags1_out, u16 * msglim);
-
-/*
- * Name: iucv_connect
- * Purpose: This function establishes an IUCV path. Although the connect may complete
- *	    successfully, you are not able to use the path until you receive an IUCV
- *          Connection Complete external interrupt.
- * Input: pathid - u16 *, Path identification number
- *        msglim_reqstd - u16, Number of outstanding messages requested
- *        user_data - uchar[16], 16-byte user data
- *	  userid - uchar[8], User identification
- *        system_name - uchar[8], 8-byte identifying the system name
- *	  flags1 - int, Contains options for this path.
- *          -IPPRTY -   0x20, Specifies if you want to send priority message.
- *          -IPRMDATA - 0x80, Specifies whether your program can handle a message
- *            	 in  the parameter list.
- *          -IPQUSCE -  0x40, Specifies whether you want to quiesce the path being
- *		established.
- *          -IPLOCAL -  0X01, Allows an application to force the partner to be on
- *		the local system. If local is specified then target class cannot be
- *		specified.
- *        flags1_out - int * Contains information about the path
- *           - IPPRTY - 0x20, Indicates you may send priority messages.
- *        msglim - * u16, Number of outstanding messages
- *        handle - iucv_handle_t, Address of handler
- *        pgm_data - void *, Application data passed to interrupt handlers
- * Output: return code from CP IUCV call
- *         rc - return code from iucv_declare_buffer
- *         -EINVAL - Invalid handle passed by application
- *         -EINVAL - Pathid address is NULL
- *         add_pathid_result - Return code from internal function add_pathid
-*/
-int
-    iucv_connect (u16 * pathid,
-		  u16 msglim_reqstd,
-		  uchar user_data[16],
-		  uchar userid[8],
-		  uchar system_name[8],
-		  int flags1,
-		  int *flags1_out,
-		  u16 * msglim, iucv_handle_t handle, void *pgm_data);
-
-/*
- * Name: iucv_purge
- * Purpose: This function cancels a message that you have sent.
- * Input: pathid - Path identification number.
- *        msgid - Specifies the message ID of the message to be purged.
- *        srccls - Specifies the source message class.
- * Output: audit - Contains information about asynchronous error
- *                 that may have affected the normal completion
- *                 of this message.
- * Return: Return code from CP IUCV call.
-*/
-int iucv_purge (u16 pathid, u32 msgid, u32 srccls, __u32 *audit);
-/*
- * Name: iucv_query_maxconn
- * Purpose: This function determines the maximum number of communication paths you
- *	    may establish.
- * Return:  maxconn - ulong, Maximum number of connection the virtual machine may
- *          establish.
-*/
-ulong iucv_query_maxconn (void);
-
-/*
- * Name: iucv_query_bufsize
- * Purpose: This function determines how large an external interrupt
- *          buffer IUCV requires to store information.
- * Return:  bufsize - ulong, Size of external interrupt buffer.
- */
-ulong iucv_query_bufsize (void);
-
-/*
- * Name: iucv_quiesce
- * Purpose: This function temporarily suspends incoming messages on an
- *          IUCV path. You can later reactivate the path by invoking
- *          the iucv_resume function.
- * Input: pathid - Path identification number
- *        user_data  - 16-bytes of user data
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_quiesce (u16 pathid, uchar user_data[16]);
-
-/*
- * Name: iucv_receive
- * Purpose: This function receives messages that are being sent to you
- *          over established paths. Data will be returned in buffer for length of
- *          buflen.
- * Input:
- *       pathid - Path identification number.
- *       buffer - Address of buffer to receive.
- *       buflen - Length of buffer to receive.
- *       msgid - Specifies the message ID.
- *       trgcls - Specifies target class.
- * Output:
- *	 flags1_out: int *, Contains information about this path.
- *         IPNORPY - 0x10 Specifies this is a one-way message and no reply is
- *	   expected.
- *         IPPRTY  - 0x20 Specifies if you want to send priority message.
- *         IPRMDATA - 0x80 specifies the data is contained in the parameter list
- *       residual_buffer - address of buffer updated by the number
- *                         of bytes you have received.
- *       residual_length -
- *              Contains one of the following values, if the receive buffer is:
- *               The same length as the message, this field is zero.
- *               Longer than the message, this field contains the number of
- *                bytes remaining in the buffer.
- *               Shorter than the message, this field contains the residual
- *                count (that is, the number of bytes remaining in the
- *                message that does not fit into the buffer. In this
- *                case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- *         (-EINVAL) - buffer address is pointing to NULL
-*/
-int iucv_receive (u16 pathid,
-		  u32 msgid,
-		  u32 trgcls,
-		  void *buffer,
-		  ulong buflen,
-		  int *flags1_out,
-		  ulong * residual_buffer, ulong * residual_length);
-
- /*
-  * Name: iucv_receive_array
-  * Purpose: This function receives messages that are being sent to you
-  *          over established paths. Data will be returned in first buffer for
-  *          length of first buffer.
-  * Input: pathid - Path identification number.
-  *        msgid - specifies the message ID.
-  *        trgcls - Specifies target class.
-  *        buffer - Address of array of buffers.
-  *        buflen - Total length of buffers.
-  * Output:
-  *        flags1_out: int *, Contains information about this path.
-  *          IPNORPY - 0x10 Specifies this is a one-way message and no reply is
-  *          expected.
-  *          IPPRTY  - 0x20 Specifies if you want to send priority message.
-  *          IPRMDATA - 0x80 specifies the data is contained in the parameter list
-  *       residual_buffer - address points to the current list entry IUCV
-  *                         is working on.
-  *       residual_length -
-  *              Contains one of the following values, if the receive buffer is:
-  *               The same length as the message, this field is zero.
-  *               Longer than the message, this field contains the number of
-  *                bytes remaining in the buffer.
-  *               Shorter than the message, this field contains the residual
-  *                count (that is, the number of bytes remaining in the
-  *                message that does not fit into the buffer. In this
-  *                case b2f0_result = 5.
-  * Return: Return code from CP IUCV call.
-  *         (-EINVAL) - Buffer address is NULL.
-  */
-int iucv_receive_array (u16 pathid,
-			u32 msgid,
-			u32 trgcls,
-			iucv_array_t * buffer,
-			ulong buflen,
-			int *flags1_out,
-			ulong * residual_buffer, ulong * residual_length);
-
-/*
- * Name: iucv_reject
- * Purpose: The reject function refuses a specified message. Between the
- *          time you are notified of a message and the time that you
- *          complete the message, the message may be rejected.
- * Input: pathid - Path identification number.
- *        msgid - Specifies the message ID.
- *        trgcls - Specifies target class.
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_reject (u16 pathid, u32 msgid, u32 trgcls);
-
-/*
- * Name: iucv_reply
- * Purpose: This function responds to the two-way messages that you
- *          receive. You must identify completely the message to
- *          which you wish to reply. ie, pathid, msgid, and trgcls.
- * Input: pathid - Path identification number.
- *        msgid - Specifies the message ID.
- *        trgcls - Specifies target class.
- *        flags1 - Option for path.
- *          IPPRTY- 0x20, Specifies if you want to send priority message.
- *        buffer - Address of reply buffer.
- *        buflen - Length of reply buffer.
- * Output: residual_buffer - Address of buffer updated by the number
- *                    of bytes you have moved.
- *         residual_length - Contains one of the following values:
- *		If the answer buffer is the same length as the reply, this field
- *		 contains zero.
- *		If the answer buffer is longer than the reply, this field contains
- *		 the number of bytes remaining in the buffer.
- *		If the answer buffer is shorter than the reply, this field contains
- *		 a residual count (that is, the number of bytes remianing in the
- *		 reply that does not fit into the buffer. In this
- *               case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- *         (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_reply (u16 pathid,
-		u32 msgid,
-		u32 trgcls,
-		int flags1,
-		void *buffer, ulong buflen, ulong * residual_buffer,
-		ulong * residual_length);
-
-/*
- * Name: iucv_reply_array
- * Purpose: This function responds to the two-way messages that you
- *          receive. You must identify completely the message to
- *          which you wish to reply. ie, pathid, msgid, and trgcls.
- *          The array identifies a list of addresses and lengths of
- *          discontiguous buffers that contains the reply data.
- * Input: pathid - Path identification number
- *        msgid - Specifies the message ID.
- *        trgcls - Specifies target class.
- *        flags1 - Option for path.
- *          IPPRTY- 0x20, Specifies if you want to send priority message.
- *        buffer - Address of array of reply buffers.
- *        buflen - Total length of reply buffers.
- * Output: residual_buffer - Address of buffer which IUCV is currently working on.
- *         residual_length - Contains one of the following values:
- *              If the answer buffer is the same length as the reply, this field
- *               contains zero.
- *              If the answer buffer is longer than the reply, this field contains
- *               the number of bytes remaining in the buffer.
- *              If the answer buffer is shorter than the reply, this field contains
- *               a residual count (that is, the number of bytes remianing in the
- *               reply that does not fit into the buffer. In this
- *               case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- *         (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_reply_array (u16 pathid,
-		      u32 msgid,
-		      u32 trgcls,
-		      int flags1,
-		      iucv_array_t * buffer,
-		      ulong buflen, ulong * residual_address,
-		      ulong * residual_length);
-
-/*
- * Name: iucv_reply_prmmsg
- * Purpose: This function responds to the two-way messages that you
- *          receive. You must identify completely the message to
- *          which you wish to reply. ie, pathid, msgid, and trgcls.
- *          Prmmsg signifies the data is moved into the
- *          parameter list.
- * Input: pathid - Path identification number.
- *        msgid - Specifies the message ID.
- *        trgcls - Specifies target class.
- *        flags1 - Option for path.
- *          IPPRTY- 0x20 Specifies if you want to send priority message.
- *        prmmsg - 8-bytes of data to be placed into the parameter.
- *                 list.
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_reply_prmmsg (u16 pathid,
-		       u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8]);
-
-/*
- * Name: iucv_resume
- * Purpose: This function restores communications over a quiesced path
- * Input: pathid - Path identification number.
- *        user_data  - 16-bytes of user data.
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_resume (u16 pathid, uchar user_data[16]);
-
-/*
- * Name: iucv_send
- * Purpose: This function transmits data to another application.
- *          Data to be transmitted is in a buffer and this is a
- *          one-way message and the receiver will not reply to the
- *          message.
- * Input: pathid - Path identification number.
- *        trgcls - Specifies target class.
- *        srccls - Specifies the source message class.
- *        msgtag - Specifies a tag to be associated with the message.
- *        flags1 - Option for path.
- *          IPPRTY- 0x20 Specifies if you want to send priority message.
- *        buffer - Address of send buffer.
- *        buflen - Length of send buffer.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- *         (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_send (u16 pathid,
-	       u32 * msgid,
-	       u32 trgcls,
-	       u32 srccls, u32 msgtag, int flags1, void *buffer, ulong buflen);
-
-/*
- * Name: iucv_send_array
- * Purpose: This function transmits data to another application.
- *          The contents of buffer is the address of the array of
- *          addresses and lengths of discontiguous buffers that hold
- *          the message text. This is a one-way message and the
- *          receiver will not reply to the message.
- * Input: pathid - Path identification number.
- *        trgcls - Specifies target class.
- *        srccls - Specifies the source message class.
- *        msgtag - Specifies a tag to be associated witht the message.
- *        flags1 - Option for path.
- *          IPPRTY- specifies if you want to send priority message.
- *        buffer - Address of array of send buffers.
- *        buflen - Total length of send buffers.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- *         (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_send_array (u16 pathid,
-		     u32 * msgid,
-		     u32 trgcls,
-		     u32 srccls,
-		     u32 msgtag,
-		     int flags1, iucv_array_t * buffer, ulong buflen);
-
-/*
- * Name: iucv_send_prmmsg
- * Purpose: This function transmits data to another application.
- *          Prmmsg specifies that the 8-bytes of data are to be moved
- *          into the parameter list. This is a one-way message and the
- *          receiver will not reply to the message.
- * Input: pathid - Path identification number.
- *        trgcls - Specifies target class.
- *        srccls - Specifies the source message class.
- *        msgtag - Specifies a tag to be associated with the message.
- *        flags1 - Option for path.
- *          IPPRTY- 0x20 specifies if you want to send priority message.
- *        prmmsg - 8-bytes of data to be placed into parameter list.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
-*/
-int iucv_send_prmmsg (u16 pathid,
-		      u32 * msgid,
-		      u32 trgcls,
-		      u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8]);
-
-/*
- * Name: iucv_send2way
- * Purpose: This function transmits data to another application.
- *          Data to be transmitted is in a buffer. The receiver
- *          of the send is expected to reply to the message and
- *          a buffer is provided into which IUCV moves the reply
- *          to this message.
- * Input: pathid - Path identification number.
- *        trgcls - Specifies target class.
- *        srccls - Specifies the source message class.
- *        msgtag - Specifies a tag associated with the message.
- *        flags1 - Option for path.
- *          IPPRTY- 0x20 Specifies if you want to send priority message.
- *        buffer - Address of send buffer.
- *        buflen - Length of send buffer.
- *        ansbuf - Address of buffer into which IUCV moves the reply of
- *                 this message.
- *        anslen - Address of length of buffer.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- *         (-EINVAL) - Buffer or ansbuf address is NULL.
-*/
-int iucv_send2way (u16 pathid,
-		   u32 * msgid,
-		   u32 trgcls,
-		   u32 srccls,
-		   u32 msgtag,
-		   int flags1,
-		   void *buffer, ulong buflen, void *ansbuf, ulong anslen);
-
-/*
- * Name: iucv_send2way_array
- * Purpose: This function transmits data to another application.
- *          The contents of buffer is the address of the array of
- *          addresses and lengths of discontiguous buffers that hold
- *          the message text. The receiver of the send is expected to
- *          reply to the message and a buffer is provided into which
- *          IUCV moves the reply to this message.
- * Input: pathid - Path identification number.
- *        trgcls - Specifies target class.
- *        srccls - Specifies the source message class.
- *        msgtag - Specifies a tag to be associated with the message.
- *        flags1 - Option for path.
- *          IPPRTY- 0x20 Specifies if you want to send priority message.
- *        buffer - Sddress of array of send buffers.
- *        buflen - Total length of send buffers.
- *        ansbuf - Address of array of buffer into which IUCV moves the reply
- *                 of this message.
- *        anslen - Address of length reply buffers.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- *         (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_send2way_array (u16 pathid,
-			 u32 * msgid,
-			 u32 trgcls,
-			 u32 srccls,
-			 u32 msgtag,
-			 int flags1,
-			 iucv_array_t * buffer,
-			 ulong buflen, iucv_array_t * ansbuf, ulong anslen);
-
-/*
- * Name: iucv_send2way_prmmsg
- * Purpose: This function transmits data to another application.
- *          Prmmsg specifies that the 8-bytes of data are to be moved
- *          into the parameter list. This is a two-way message and the
- *          receiver of the message is expected to reply. A buffer
- *          is provided into which IUCV moves the reply to this
- *          message.
- * Input: pathid - Rath identification number.
- *        trgcls - Specifies target class.
- *        srccls - Specifies the source message class.
- *        msgtag - Specifies a tag to be associated with the message.
- *        flags1 - Option for path.
- *          IPPRTY- 0x20 Specifies if you want to send priority message.
- *        prmmsg - 8-bytes of data to be placed in parameter list.
- *        ansbuf - Address of buffer into which IUCV moves the reply of
- *                 this message.
- *        anslen - Address of length of buffer.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- *         (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_send2way_prmmsg (u16 pathid,
-			  u32 * msgid,
-			  u32 trgcls,
-			  u32 srccls,
-			  u32 msgtag,
-			  ulong flags1,
-			  uchar prmmsg[8], void *ansbuf, ulong anslen);
-
-/*
- * Name: iucv_send2way_prmmsg_array
- * Purpose: This function transmits data to another application.
- *          Prmmsg specifies that the 8-bytes of data are to be moved
- *          into the parameter list. This is a two-way message and the
- *          receiver of the message is expected to reply. A buffer
- *          is provided into which IUCV moves the reply to this
- *          message. The contents of ansbuf is the address of the
- *          array of addresses and lengths of discontiguous buffers
- *          that contain the reply.
- * Input: pathid - Path identification number.
- *        trgcls - Specifies target class.
- *        srccls - Specifies the source message class.
- *        msgtag - Specifies a tag to be associated with the message.
- *        flags1 - Option for path.
- *          IPPRTY- 0x20 specifies if you want to send priority message.
- *        prmmsg - 8-bytes of data to be placed into the parameter list.
- *        ansbuf - Address of array of buffer into which IUCV moves the reply
- *                 of this message.
- *        anslen - Address of length of reply buffers.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- *         (-EINVAL) - Ansbuf address is NULL.
-*/
-int iucv_send2way_prmmsg_array (u16 pathid,
-				u32 * msgid,
-				u32 trgcls,
-				u32 srccls,
-				u32 msgtag,
-				int flags1,
-				uchar prmmsg[8],
-				iucv_array_t * ansbuf, ulong anslen);
-
-/*
- * Name: iucv_setmask
- * Purpose: This function enables or disables the following IUCV
- *          external interruptions: Nonpriority and priority message
- *          interrupts, nonpriority and priority reply interrupts.
- * Input: SetMaskFlag - options for interrupts
- *           0x80 - Nonpriority_MessagePendingInterruptsFlag
- *           0x40 - Priority_MessagePendingInterruptsFlag
- *           0x20 - Nonpriority_MessageCompletionInterruptsFlag
- *           0x10 - Priority_MessageCompletionInterruptsFlag
- *           0x08 - IUCVControlInterruptsFlag
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_setmask (int SetMaskFlag);
-
-/*
- * Name: iucv_sever
- * Purpose: This function terminates an IUCV path.
- * Input: pathid - Path identification number.
- *        user_data - 16-bytes of user data.
- * Output: NA
- * Return: Return code from CP IUCV call.
- *         (-EINVAL) - Interal error, wild pointer.
-*/
-int iucv_sever (u16 pathid, uchar user_data[16]);
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index e5665b6..b97dd15 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -828,7 +828,7 @@
 /**
  * Emit buffer of a lan comand.
  */
-void
+static void
 lcs_lancmd_timeout(unsigned long data)
 {
 	struct lcs_reply *reply, *list_reply, *r;
@@ -1360,7 +1360,7 @@
 	return 0;
 }
 
-void
+static void
 lcs_schedule_recovery(struct lcs_card *card)
 {
 	LCS_DBF_TEXT(2, trace, "startrec");
@@ -1990,7 +1990,7 @@
 
 }
 
-DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store);
+static DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store);
 
 static ssize_t
 lcs_dev_recover_store(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index d7d1cc0..6387b48 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -1,7 +1,7 @@
 /*
  * IUCV network driver
  *
- * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
  * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
  *
  * Sysfs integration and all bugs therein by Cornelia Huck
@@ -58,13 +58,94 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
-#include "iucv.h"
+#include <net/iucv/iucv.h>
 #include "fsm.h"
 
 MODULE_AUTHOR
     ("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)");
 MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver");
 
+/**
+ * Debug Facility stuff
+ */
+#define IUCV_DBF_SETUP_NAME "iucv_setup"
+#define IUCV_DBF_SETUP_LEN 32
+#define IUCV_DBF_SETUP_PAGES 2
+#define IUCV_DBF_SETUP_NR_AREAS 1
+#define IUCV_DBF_SETUP_LEVEL 3
+
+#define IUCV_DBF_DATA_NAME "iucv_data"
+#define IUCV_DBF_DATA_LEN 128
+#define IUCV_DBF_DATA_PAGES 2
+#define IUCV_DBF_DATA_NR_AREAS 1
+#define IUCV_DBF_DATA_LEVEL 2
+
+#define IUCV_DBF_TRACE_NAME "iucv_trace"
+#define IUCV_DBF_TRACE_LEN 16
+#define IUCV_DBF_TRACE_PAGES 4
+#define IUCV_DBF_TRACE_NR_AREAS 1
+#define IUCV_DBF_TRACE_LEVEL 3
+
+#define IUCV_DBF_TEXT(name,level,text) \
+	do { \
+		debug_text_event(iucv_dbf_##name,level,text); \
+	} while (0)
+
+#define IUCV_DBF_HEX(name,level,addr,len) \
+	do { \
+		debug_event(iucv_dbf_##name,level,(void*)(addr),len); \
+	} while (0)
+
+DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf);
+
+#define IUCV_DBF_TEXT_(name,level,text...)				\
+	do {								\
+		char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf);	\
+		sprintf(iucv_dbf_txt_buf, text);			\
+		debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \
+		put_cpu_var(iucv_dbf_txt_buf);				\
+	} while (0)
+
+#define IUCV_DBF_SPRINTF(name,level,text...) \
+	do { \
+		debug_sprintf_event(iucv_dbf_trace, level, ##text ); \
+		debug_sprintf_event(iucv_dbf_trace, level, text ); \
+	} while (0)
+
+/**
+ * some more debug stuff
+ */
+#define IUCV_HEXDUMP16(importance,header,ptr) \
+PRINT_##importance(header "%02x %02x %02x %02x  %02x %02x %02x %02x  " \
+		   "%02x %02x %02x %02x  %02x %02x %02x %02x\n", \
+		   *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \
+		   *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \
+		   *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \
+		   *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \
+		   *(((char*)ptr)+12),*(((char*)ptr)+13), \
+		   *(((char*)ptr)+14),*(((char*)ptr)+15)); \
+PRINT_##importance(header "%02x %02x %02x %02x  %02x %02x %02x %02x  " \
+		   "%02x %02x %02x %02x  %02x %02x %02x %02x\n", \
+		   *(((char*)ptr)+16),*(((char*)ptr)+17), \
+		   *(((char*)ptr)+18),*(((char*)ptr)+19), \
+		   *(((char*)ptr)+20),*(((char*)ptr)+21), \
+		   *(((char*)ptr)+22),*(((char*)ptr)+23), \
+		   *(((char*)ptr)+24),*(((char*)ptr)+25), \
+		   *(((char*)ptr)+26),*(((char*)ptr)+27), \
+		   *(((char*)ptr)+28),*(((char*)ptr)+29), \
+		   *(((char*)ptr)+30),*(((char*)ptr)+31));
+
+static inline void iucv_hex_dump(unsigned char *buf, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len; i++) {
+		if (i && !(i % 16))
+			printk("\n");
+		printk("%02x ", *(buf + i));
+	}
+	printk("\n");
+}
 
 #define PRINTK_HEADER " iucv: "       /* for debugging */
 
@@ -73,6 +154,25 @@
 	.bus  = &iucv_bus,
 };
 
+static int netiucv_callback_connreq(struct iucv_path *,
+				    u8 ipvmid[8], u8 ipuser[16]);
+static void netiucv_callback_connack(struct iucv_path *, u8 ipuser[16]);
+static void netiucv_callback_connrej(struct iucv_path *, u8 ipuser[16]);
+static void netiucv_callback_connsusp(struct iucv_path *, u8 ipuser[16]);
+static void netiucv_callback_connres(struct iucv_path *, u8 ipuser[16]);
+static void netiucv_callback_rx(struct iucv_path *, struct iucv_message *);
+static void netiucv_callback_txdone(struct iucv_path *, struct iucv_message *);
+
+static struct iucv_handler netiucv_handler = {
+	.path_pending	  = netiucv_callback_connreq,
+	.path_complete	  = netiucv_callback_connack,
+	.path_severed	  = netiucv_callback_connrej,
+	.path_quiesced	  = netiucv_callback_connsusp,
+	.path_resumed	  = netiucv_callback_connres,
+	.message_pending  = netiucv_callback_rx,
+	.message_complete = netiucv_callback_txdone
+};
+
 /**
  * Per connection profiling data
  */
@@ -92,9 +192,8 @@
  * Representation of one iucv connection
  */
 struct iucv_connection {
-	struct iucv_connection    *next;
-	iucv_handle_t             handle;
-	__u16                     pathid;
+	struct list_head	  list;
+	struct iucv_path	  *path;
 	struct sk_buff            *rx_buff;
 	struct sk_buff            *tx_buff;
 	struct sk_buff_head       collect_queue;
@@ -112,12 +211,9 @@
 /**
  * Linked list of all connection structs.
  */
-struct iucv_connection_struct {
-	struct iucv_connection *iucv_connections;
-	rwlock_t iucv_rwlock;
-};
-
-static struct iucv_connection_struct iucv_conns;
+static struct list_head iucv_connection_list =
+	LIST_HEAD_INIT(iucv_connection_list);
+static rwlock_t iucv_connection_rwlock = RW_LOCK_UNLOCKED;
 
 /**
  * Representation of event-data for the
@@ -142,11 +238,11 @@
 /**
  * Link level header for a packet.
  */
-typedef struct ll_header_t {
-	__u16 next;
-} ll_header;
+struct ll_header {
+	u16 next;
+};
 
-#define NETIUCV_HDRLEN           (sizeof(ll_header))
+#define NETIUCV_HDRLEN		 (sizeof(struct ll_header))
 #define NETIUCV_BUFSIZE_MAX      32768
 #define NETIUCV_BUFSIZE_DEFAULT  NETIUCV_BUFSIZE_MAX
 #define NETIUCV_MTU_MAX          (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN)
@@ -158,36 +254,26 @@
  * Compatibility macros for busy handling
  * of network devices.
  */
-static __inline__ void netiucv_clear_busy(struct net_device *dev)
+static inline void netiucv_clear_busy(struct net_device *dev)
 {
-	clear_bit(0, &(((struct netiucv_priv *)dev->priv)->tbusy));
+	struct netiucv_priv *priv = netdev_priv(dev);
+	clear_bit(0, &priv->tbusy);
 	netif_wake_queue(dev);
 }
 
-static __inline__ int netiucv_test_and_set_busy(struct net_device *dev)
+static inline int netiucv_test_and_set_busy(struct net_device *dev)
 {
+	struct netiucv_priv *priv = netdev_priv(dev);
 	netif_stop_queue(dev);
-	return test_and_set_bit(0, &((struct netiucv_priv *)dev->priv)->tbusy);
+	return test_and_set_bit(0, &priv->tbusy);
 }
 
-static __u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-static __u8 iucvMagic[16] = {
+static u8 iucvMagic[16] = {
 	0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
 	0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
 };
 
 /**
- * This mask means the 16-byte IUCV "magic" and the origin userid must
- * match exactly as specified in order to give connection_pending()
- * control.
- */
-static __u8 netiucv_mask[] = {
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
-};
-
-/**
  * Convert an iucv userId to its printable
  * form (strip whitespace at end).
  *
@@ -195,8 +281,7 @@
  *
  * @returns The printable string (static data!!)
  */
-static __inline__ char *
-netiucv_printname(char *name)
+static inline char *netiucv_printname(char *name)
 {
 	static char tmp[9];
 	char *p = tmp;
@@ -379,8 +464,7 @@
 
 DEFINE_PER_CPU(char[256], iucv_dbf_txt_buf);
 
-static void
-iucv_unregister_dbf_views(void)
+static void iucv_unregister_dbf_views(void)
 {
 	if (iucv_dbf_setup)
 		debug_unregister(iucv_dbf_setup);
@@ -389,8 +473,7 @@
 	if (iucv_dbf_trace)
 		debug_unregister(iucv_dbf_trace);
 }
-static int
-iucv_register_dbf_views(void)
+static int iucv_register_dbf_views(void)
 {
 	iucv_dbf_setup = debug_register(IUCV_DBF_SETUP_NAME,
 					IUCV_DBF_SETUP_PAGES,
@@ -422,125 +505,111 @@
 	return 0;
 }
 
-/**
+/*
  * Callback-wrappers, called from lowlevel iucv layer.
- *****************************************************************************/
+ */
 
-static void
-netiucv_callback_rx(iucv_MessagePending *eib, void *pgm_data)
+static void netiucv_callback_rx(struct iucv_path *path,
+				struct iucv_message *msg)
 {
-	struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
+	struct iucv_connection *conn = path->private;
 	struct iucv_event ev;
 
 	ev.conn = conn;
-	ev.data = (void *)eib;
-
+	ev.data = msg;
 	fsm_event(conn->fsm, CONN_EVENT_RX, &ev);
 }
 
-static void
-netiucv_callback_txdone(iucv_MessageComplete *eib, void *pgm_data)
+static void netiucv_callback_txdone(struct iucv_path *path,
+				    struct iucv_message *msg)
 {
-	struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
+	struct iucv_connection *conn = path->private;
 	struct iucv_event ev;
 
 	ev.conn = conn;
-	ev.data = (void *)eib;
+	ev.data = msg;
 	fsm_event(conn->fsm, CONN_EVENT_TXDONE, &ev);
 }
 
-static void
-netiucv_callback_connack(iucv_ConnectionComplete *eib, void *pgm_data)
+static void netiucv_callback_connack(struct iucv_path *path, u8 ipuser[16])
 {
-	struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
-	struct iucv_event ev;
+	struct iucv_connection *conn = path->private;
 
-	ev.conn = conn;
-	ev.data = (void *)eib;
-	fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, &ev);
+	fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, conn);
 }
 
-static void
-netiucv_callback_connreq(iucv_ConnectionPending *eib, void *pgm_data)
+static int netiucv_callback_connreq(struct iucv_path *path,
+				    u8 ipvmid[8], u8 ipuser[16])
 {
-	struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
+	struct iucv_connection *conn = path->private;
 	struct iucv_event ev;
+	int rc;
 
-	ev.conn = conn;
-	ev.data = (void *)eib;
-	fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev);
+	if (memcmp(iucvMagic, ipuser, sizeof(ipuser)))
+		/* ipuser must match iucvMagic. */
+		return -EINVAL;
+	rc = -EINVAL;
+	read_lock_bh(&iucv_connection_rwlock);
+	list_for_each_entry(conn, &iucv_connection_list, list) {
+		if (strncmp(ipvmid, conn->userid, 8))
+			continue;
+		/* Found a matching connection for this path. */
+		conn->path = path;
+		ev.conn = conn;
+		ev.data = path;
+		fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev);
+		rc = 0;
+	}
+	read_unlock_bh(&iucv_connection_rwlock);
+	return rc;
 }
 
-static void
-netiucv_callback_connrej(iucv_ConnectionSevered *eib, void *pgm_data)
+static void netiucv_callback_connrej(struct iucv_path *path, u8 ipuser[16])
 {
-	struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
-	struct iucv_event ev;
+	struct iucv_connection *conn = path->private;
 
-	ev.conn = conn;
-	ev.data = (void *)eib;
-	fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, &ev);
+	fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, conn);
 }
 
-static void
-netiucv_callback_connsusp(iucv_ConnectionQuiesced *eib, void *pgm_data)
+static void netiucv_callback_connsusp(struct iucv_path *path, u8 ipuser[16])
 {
-	struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
-	struct iucv_event ev;
+	struct iucv_connection *conn = path->private;
 
-	ev.conn = conn;
-	ev.data = (void *)eib;
-	fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, &ev);
+	fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, conn);
 }
 
-static void
-netiucv_callback_connres(iucv_ConnectionResumed *eib, void *pgm_data)
+static void netiucv_callback_connres(struct iucv_path *path, u8 ipuser[16])
 {
-	struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
-	struct iucv_event ev;
+	struct iucv_connection *conn = path->private;
 
-	ev.conn = conn;
-	ev.data = (void *)eib;
-	fsm_event(conn->fsm, CONN_EVENT_CONN_RES, &ev);
+	fsm_event(conn->fsm, CONN_EVENT_CONN_RES, conn);
 }
 
-static iucv_interrupt_ops_t netiucv_ops = {
-	.ConnectionPending  = netiucv_callback_connreq,
-	.ConnectionComplete = netiucv_callback_connack,
-	.ConnectionSevered  = netiucv_callback_connrej,
-	.ConnectionQuiesced = netiucv_callback_connsusp,
-	.ConnectionResumed  = netiucv_callback_connres,
-	.MessagePending     = netiucv_callback_rx,
-	.MessageComplete    = netiucv_callback_txdone
-};
-
 /**
  * Dummy NOP action for all statemachines
  */
-static void
-fsm_action_nop(fsm_instance *fi, int event, void *arg)
+static void fsm_action_nop(fsm_instance *fi, int event, void *arg)
 {
 }
 
-/**
+/*
  * Actions of the connection statemachine
- *****************************************************************************/
+ */
 
 /**
- * Helper function for conn_action_rx()
- * Unpack a just received skb and hand it over to
- * upper layers.
+ * netiucv_unpack_skb
+ * @conn: The connection where this skb has been received.
+ * @pskb: The received skb.
  *
- * @param conn The connection where this skb has been received.
- * @param pskb The received skb.
+ * Unpack a just received skb and hand it over to upper layers.
+ * Helper function for conn_action_rx.
  */
-//static __inline__ void
-static void
-netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb)
+static void netiucv_unpack_skb(struct iucv_connection *conn,
+			       struct sk_buff *pskb)
 {
 	struct net_device     *dev = conn->netdev;
-	struct netiucv_priv   *privptr = dev->priv;
-	__u16          offset = 0;
+	struct netiucv_priv   *privptr = netdev_priv(dev);
+	u16 offset = 0;
 
 	skb_put(pskb, NETIUCV_HDRLEN);
 	pskb->dev = dev;
@@ -549,7 +618,7 @@
 
 	while (1) {
 		struct sk_buff *skb;
-		ll_header *header = (ll_header *)pskb->data;
+		struct ll_header *header = (struct ll_header *) pskb->data;
 
 		if (!header->next)
 			break;
@@ -595,40 +664,37 @@
 	}
 }
 
-static void
-conn_action_rx(fsm_instance *fi, int event, void *arg)
+static void conn_action_rx(fsm_instance *fi, int event, void *arg)
 {
-	struct iucv_event *ev = (struct iucv_event *)arg;
+	struct iucv_event *ev = arg;
 	struct iucv_connection *conn = ev->conn;
-	iucv_MessagePending *eib = (iucv_MessagePending *)ev->data;
-	struct netiucv_priv *privptr =(struct netiucv_priv *)conn->netdev->priv;
-
-	__u32 msglen = eib->ln1msg2.ipbfln1f;
+	struct iucv_message *msg = ev->data;
+	struct netiucv_priv *privptr = netdev_priv(conn->netdev);
 	int rc;
 
 	IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
 
 	if (!conn->netdev) {
-		/* FRITZ: How to tell iucv LL to drop the msg? */
+		iucv_message_reject(conn->path, msg);
 		PRINT_WARN("Received data for unlinked connection\n");
 		IUCV_DBF_TEXT(data, 2,
-			"Received data for unlinked connection\n");
+			      "Received data for unlinked connection\n");
 		return;
 	}
-	if (msglen > conn->max_buffsize) {
-		/* FRITZ: How to tell iucv LL to drop the msg? */
+	if (msg->length > conn->max_buffsize) {
+		iucv_message_reject(conn->path, msg);
 		privptr->stats.rx_dropped++;
 		PRINT_WARN("msglen %d > max_buffsize %d\n",
-			msglen, conn->max_buffsize);
+			   msg->length, conn->max_buffsize);
 		IUCV_DBF_TEXT_(data, 2, "msglen %d > max_buffsize %d\n",
-			msglen, conn->max_buffsize);
+			       msg->length, conn->max_buffsize);
 		return;
 	}
 	conn->rx_buff->data = conn->rx_buff->tail = conn->rx_buff->head;
 	conn->rx_buff->len = 0;
-	rc = iucv_receive(conn->pathid, eib->ipmsgid, eib->iptrgcls,
-			  conn->rx_buff->data, msglen, NULL, NULL, NULL);
-	if (rc || msglen < 5) {
+	rc = iucv_message_receive(conn->path, msg, 0, conn->rx_buff->data,
+				  msg->length, NULL);
+	if (rc || msg->length < 5) {
 		privptr->stats.rx_errors++;
 		PRINT_WARN("iucv_receive returned %08x\n", rc);
 		IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_receive\n", rc);
@@ -637,26 +703,26 @@
 	netiucv_unpack_skb(conn, conn->rx_buff);
 }
 
-static void
-conn_action_txdone(fsm_instance *fi, int event, void *arg)
+static void conn_action_txdone(fsm_instance *fi, int event, void *arg)
 {
-	struct iucv_event *ev = (struct iucv_event *)arg;
+	struct iucv_event *ev = arg;
 	struct iucv_connection *conn = ev->conn;
-	iucv_MessageComplete *eib = (iucv_MessageComplete *)ev->data;
+	struct iucv_message *msg = ev->data;
+	struct iucv_message txmsg;
 	struct netiucv_priv *privptr = NULL;
-			         /* Shut up, gcc! skb is always below 2G. */
-	__u32 single_flag = eib->ipmsgtag;
-	__u32 txbytes = 0;
-	__u32 txpackets = 0;
-	__u32 stat_maxcq = 0;
+	u32 single_flag = msg->tag;
+	u32 txbytes = 0;
+	u32 txpackets = 0;
+	u32 stat_maxcq = 0;
 	struct sk_buff *skb;
 	unsigned long saveflags;
-	ll_header header;
+	struct ll_header header;
+	int rc;
 
 	IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
 
-	if (conn && conn->netdev && conn->netdev->priv)
-		privptr = (struct netiucv_priv *)conn->netdev->priv;
+	if (conn && conn->netdev)
+		privptr = netdev_priv(conn->netdev);
 	conn->prof.tx_pending--;
 	if (single_flag) {
 		if ((skb = skb_dequeue(&conn->commit_queue))) {
@@ -688,56 +754,55 @@
 		conn->prof.maxmulti = conn->collect_len;
 	conn->collect_len = 0;
 	spin_unlock_irqrestore(&conn->collect_lock, saveflags);
-	if (conn->tx_buff->len) {
-		int rc;
-
-		header.next = 0;
-		memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header,
-		       NETIUCV_HDRLEN);
-
-		conn->prof.send_stamp = xtime;
-		rc = iucv_send(conn->pathid, NULL, 0, 0, 0, 0,
-			       conn->tx_buff->data, conn->tx_buff->len);
-		conn->prof.doios_multi++;
-		conn->prof.txlen += conn->tx_buff->len;
-		conn->prof.tx_pending++;
-		if (conn->prof.tx_pending > conn->prof.tx_max_pending)
-			conn->prof.tx_max_pending = conn->prof.tx_pending;
-		if (rc) {
-			conn->prof.tx_pending--;
-			fsm_newstate(fi, CONN_STATE_IDLE);
-			if (privptr)
-				privptr->stats.tx_errors += txpackets;
-			PRINT_WARN("iucv_send returned %08x\n",	rc);
-			IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc);
-		} else {
-			if (privptr) {
-				privptr->stats.tx_packets += txpackets;
-				privptr->stats.tx_bytes += txbytes;
-			}
-			if (stat_maxcq > conn->prof.maxcqueue)
-				conn->prof.maxcqueue = stat_maxcq;
-		}
-	} else
+	if (conn->tx_buff->len == 0) {
 		fsm_newstate(fi, CONN_STATE_IDLE);
+		return;
+	}
+
+	header.next = 0;
+	memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN);
+	conn->prof.send_stamp = xtime;
+	txmsg.class = 0;
+	txmsg.tag = 0;
+	rc = iucv_message_send(conn->path, &txmsg, 0, 0,
+			       conn->tx_buff->data, conn->tx_buff->len);
+	conn->prof.doios_multi++;
+	conn->prof.txlen += conn->tx_buff->len;
+	conn->prof.tx_pending++;
+	if (conn->prof.tx_pending > conn->prof.tx_max_pending)
+		conn->prof.tx_max_pending = conn->prof.tx_pending;
+	if (rc) {
+		conn->prof.tx_pending--;
+		fsm_newstate(fi, CONN_STATE_IDLE);
+		if (privptr)
+			privptr->stats.tx_errors += txpackets;
+		PRINT_WARN("iucv_send returned %08x\n",	rc);
+		IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc);
+	} else {
+		if (privptr) {
+			privptr->stats.tx_packets += txpackets;
+			privptr->stats.tx_bytes += txbytes;
+		}
+		if (stat_maxcq > conn->prof.maxcqueue)
+			conn->prof.maxcqueue = stat_maxcq;
+	}
 }
 
-static void
-conn_action_connaccept(fsm_instance *fi, int event, void *arg)
+static void conn_action_connaccept(fsm_instance *fi, int event, void *arg)
 {
-	struct iucv_event *ev = (struct iucv_event *)arg;
+	struct iucv_event *ev = arg;
 	struct iucv_connection *conn = ev->conn;
-	iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data;
+	struct iucv_path *path = ev->data;
 	struct net_device *netdev = conn->netdev;
-	struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;
+	struct netiucv_priv *privptr = netdev_priv(netdev);
 	int rc;
-	__u16 msglimit;
-	__u8 udata[16];
 
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
 
-	rc = iucv_accept(eib->ippathid, NETIUCV_QUEUELEN_DEFAULT, udata, 0,
-			 conn->handle, conn, NULL, &msglimit);
+	conn->path = path;
+	path->msglim = NETIUCV_QUEUELEN_DEFAULT;
+	path->flags = 0;
+	rc = iucv_path_accept(path, &netiucv_handler, NULL, conn);
 	if (rc) {
 		PRINT_WARN("%s: IUCV accept failed with error %d\n",
 		       netdev->name, rc);
@@ -745,183 +810,126 @@
 		return;
 	}
 	fsm_newstate(fi, CONN_STATE_IDLE);
-	conn->pathid = eib->ippathid;
-	netdev->tx_queue_len = msglimit;
+	netdev->tx_queue_len = conn->path->msglim;
 	fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev);
 }
 
-static void
-conn_action_connreject(fsm_instance *fi, int event, void *arg)
+static void conn_action_connreject(fsm_instance *fi, int event, void *arg)
 {
-	struct iucv_event *ev = (struct iucv_event *)arg;
-	struct iucv_connection *conn = ev->conn;
-	struct net_device *netdev = conn->netdev;
-	iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data;
-	__u8 udata[16];
+	struct iucv_event *ev = arg;
+	struct iucv_path *path = ev->data;
 
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
-
-	iucv_sever(eib->ippathid, udata);
-	if (eib->ippathid != conn->pathid) {
-		PRINT_INFO("%s: IR Connection Pending; "
-			"pathid %d does not match original pathid %d\n",
-			netdev->name, eib->ippathid, conn->pathid);
-		IUCV_DBF_TEXT_(data, 2,
-			"connreject: IR pathid %d, conn. pathid %d\n",
-			eib->ippathid, conn->pathid);
-		iucv_sever(conn->pathid, udata);
-	}
+	iucv_path_sever(path, NULL);
 }
 
-static void
-conn_action_connack(fsm_instance *fi, int event, void *arg)
+static void conn_action_connack(fsm_instance *fi, int event, void *arg)
 {
-	struct iucv_event *ev = (struct iucv_event *)arg;
-	struct iucv_connection *conn = ev->conn;
-	iucv_ConnectionComplete *eib = (iucv_ConnectionComplete *)ev->data;
+	struct iucv_connection *conn = arg;
 	struct net_device *netdev = conn->netdev;
-	struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;
+	struct netiucv_priv *privptr = netdev_priv(netdev);
 
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
-
 	fsm_deltimer(&conn->timer);
 	fsm_newstate(fi, CONN_STATE_IDLE);
-	if (eib->ippathid != conn->pathid) {
-		PRINT_INFO("%s: IR Connection Complete; "
-			"pathid %d does not match original pathid %d\n",
-			netdev->name, eib->ippathid, conn->pathid);
-		IUCV_DBF_TEXT_(data, 2,
-			"connack: IR pathid %d, conn. pathid %d\n",
-			eib->ippathid, conn->pathid);
-		conn->pathid = eib->ippathid;
-	}
-	netdev->tx_queue_len = eib->ipmsglim;
+	netdev->tx_queue_len = conn->path->msglim;
 	fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev);
 }
 
-static void
-conn_action_conntimsev(fsm_instance *fi, int event, void *arg)
+static void conn_action_conntimsev(fsm_instance *fi, int event, void *arg)
 {
-	struct iucv_connection *conn = (struct iucv_connection *)arg;
-	__u8 udata[16];
+	struct iucv_connection *conn = arg;
 
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
-
 	fsm_deltimer(&conn->timer);
-	iucv_sever(conn->pathid, udata);
+	iucv_path_sever(conn->path, NULL);
 	fsm_newstate(fi, CONN_STATE_STARTWAIT);
 }
 
-static void
-conn_action_connsever(fsm_instance *fi, int event, void *arg)
+static void conn_action_connsever(fsm_instance *fi, int event, void *arg)
 {
-	struct iucv_event *ev = (struct iucv_event *)arg;
-	struct iucv_connection *conn = ev->conn;
+	struct iucv_connection *conn = arg;
 	struct net_device *netdev = conn->netdev;
-	struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;
-	__u8 udata[16];
+	struct netiucv_priv *privptr = netdev_priv(netdev);
 
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
 
 	fsm_deltimer(&conn->timer);
-	iucv_sever(conn->pathid, udata);
+	iucv_path_sever(conn->path, NULL);
 	PRINT_INFO("%s: Remote dropped connection\n", netdev->name);
 	IUCV_DBF_TEXT(data, 2,
-		"conn_action_connsever: Remote dropped connection\n");
+		      "conn_action_connsever: Remote dropped connection\n");
 	fsm_newstate(fi, CONN_STATE_STARTWAIT);
 	fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);
 }
 
-static void
-conn_action_start(fsm_instance *fi, int event, void *arg)
+static void conn_action_start(fsm_instance *fi, int event, void *arg)
 {
-	struct iucv_event *ev = (struct iucv_event *)arg;
-	struct iucv_connection *conn = ev->conn;
-	__u16 msglimit;
+	struct iucv_connection *conn = arg;
 	int rc;
 
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
 
-	if (!conn->handle) {
-		IUCV_DBF_TEXT(trace, 5, "calling iucv_register_program\n");
-		conn->handle =
-			iucv_register_program(iucvMagic, conn->userid,
-					      netiucv_mask,
-					      &netiucv_ops, conn);
-		fsm_newstate(fi, CONN_STATE_STARTWAIT);
-		if (!conn->handle) {
-			fsm_newstate(fi, CONN_STATE_REGERR);
-			conn->handle = NULL;
-			IUCV_DBF_TEXT(setup, 2,
-				"NULL from iucv_register_program\n");
-			return;
-		}
-
-		PRINT_DEBUG("%s('%s'): registered successfully\n",
-			 conn->netdev->name, conn->userid);
-	}
-
+	fsm_newstate(fi, CONN_STATE_STARTWAIT);
 	PRINT_DEBUG("%s('%s'): connecting ...\n",
-		 conn->netdev->name, conn->userid);
+		    conn->netdev->name, conn->userid);
 
-	/* We must set the state before calling iucv_connect because the callback
-	 * handler could be called at any point after the connection request is
-	 * sent */
+	/*
+	 * We must set the state before calling iucv_connect because the
+	 * callback handler could be called at any point after the connection
+	 * request is sent
+	 */
 
 	fsm_newstate(fi, CONN_STATE_SETUPWAIT);
-	rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic,
-			  conn->userid, iucv_host, 0, NULL, &msglimit,
-			  conn->handle, conn);
+	conn->path = iucv_path_alloc(NETIUCV_QUEUELEN_DEFAULT, 0, GFP_KERNEL);
+	rc = iucv_path_connect(conn->path, &netiucv_handler, conn->userid,
+			       NULL, iucvMagic, conn);
 	switch (rc) {
-		case 0:
-			conn->netdev->tx_queue_len = msglimit;
-			fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC,
-				CONN_EVENT_TIMER, conn);
-			return;
-		case 11:
-			PRINT_INFO("%s: User %s is currently not available.\n",
-			       conn->netdev->name,
-			       netiucv_printname(conn->userid));
-			fsm_newstate(fi, CONN_STATE_STARTWAIT);
-			return;
-		case 12:
-			PRINT_INFO("%s: User %s is currently not ready.\n",
-			       conn->netdev->name,
-			       netiucv_printname(conn->userid));
-			fsm_newstate(fi, CONN_STATE_STARTWAIT);
-			return;
-		case 13:
-			PRINT_WARN("%s: Too many IUCV connections.\n",
-			       conn->netdev->name);
-			fsm_newstate(fi, CONN_STATE_CONNERR);
-			break;
-		case 14:
-			PRINT_WARN(
-			       "%s: User %s has too many IUCV connections.\n",
-			       conn->netdev->name,
-			       netiucv_printname(conn->userid));
-			fsm_newstate(fi, CONN_STATE_CONNERR);
-			break;
-		case 15:
-			PRINT_WARN(
-			       "%s: No IUCV authorization in CP directory.\n",
-			       conn->netdev->name);
-			fsm_newstate(fi, CONN_STATE_CONNERR);
-			break;
-		default:
-			PRINT_WARN("%s: iucv_connect returned error %d\n",
-			       conn->netdev->name, rc);
-			fsm_newstate(fi, CONN_STATE_CONNERR);
-			break;
+	case 0:
+		conn->netdev->tx_queue_len = conn->path->msglim;
+		fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC,
+			     CONN_EVENT_TIMER, conn);
+		return;
+	case 11:
+		PRINT_INFO("%s: User %s is currently not available.\n",
+			   conn->netdev->name,
+			   netiucv_printname(conn->userid));
+		fsm_newstate(fi, CONN_STATE_STARTWAIT);
+		break;
+	case 12:
+		PRINT_INFO("%s: User %s is currently not ready.\n",
+			   conn->netdev->name,
+			   netiucv_printname(conn->userid));
+		fsm_newstate(fi, CONN_STATE_STARTWAIT);
+		break;
+	case 13:
+		PRINT_WARN("%s: Too many IUCV connections.\n",
+			   conn->netdev->name);
+		fsm_newstate(fi, CONN_STATE_CONNERR);
+		break;
+	case 14:
+		PRINT_WARN("%s: User %s has too many IUCV connections.\n",
+			   conn->netdev->name,
+			   netiucv_printname(conn->userid));
+		fsm_newstate(fi, CONN_STATE_CONNERR);
+		break;
+	case 15:
+		PRINT_WARN("%s: No IUCV authorization in CP directory.\n",
+			   conn->netdev->name);
+		fsm_newstate(fi, CONN_STATE_CONNERR);
+		break;
+	default:
+		PRINT_WARN("%s: iucv_connect returned error %d\n",
+			   conn->netdev->name, rc);
+		fsm_newstate(fi, CONN_STATE_CONNERR);
+		break;
 	}
 	IUCV_DBF_TEXT_(setup, 5, "iucv_connect rc is %d\n", rc);
-	IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n");
-	iucv_unregister_program(conn->handle);
-	conn->handle = NULL;
+	kfree(conn->path);
+	conn->path = NULL;
 }
 
-static void
-netiucv_purge_skb_queue(struct sk_buff_head *q)
+static void netiucv_purge_skb_queue(struct sk_buff_head *q)
 {
 	struct sk_buff *skb;
 
@@ -931,36 +939,34 @@
 	}
 }
 
-static void
-conn_action_stop(fsm_instance *fi, int event, void *arg)
+static void conn_action_stop(fsm_instance *fi, int event, void *arg)
 {
-	struct iucv_event *ev = (struct iucv_event *)arg;
+	struct iucv_event *ev = arg;
 	struct iucv_connection *conn = ev->conn;
 	struct net_device *netdev = conn->netdev;
-	struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;
+	struct netiucv_priv *privptr = netdev_priv(netdev);
 
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
 
 	fsm_deltimer(&conn->timer);
 	fsm_newstate(fi, CONN_STATE_STOPPED);
 	netiucv_purge_skb_queue(&conn->collect_queue);
-	if (conn->handle)
-		IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n");
-		iucv_unregister_program(conn->handle);
-	conn->handle = NULL;
+	if (conn->path) {
+		IUCV_DBF_TEXT(trace, 5, "calling iucv_path_sever\n");
+		iucv_path_sever(conn->path, iucvMagic);
+		kfree(conn->path);
+		conn->path = NULL;
+	}
 	netiucv_purge_skb_queue(&conn->commit_queue);
 	fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);
 }
 
-static void
-conn_action_inval(fsm_instance *fi, int event, void *arg)
+static void conn_action_inval(fsm_instance *fi, int event, void *arg)
 {
-	struct iucv_event *ev = (struct iucv_event *)arg;
-	struct iucv_connection *conn = ev->conn;
+	struct iucv_connection *conn = arg;
 	struct net_device *netdev = conn->netdev;
 
-	PRINT_WARN("%s: Cannot connect without username\n",
-	       netdev->name);
+	PRINT_WARN("%s: Cannot connect without username\n", netdev->name);
 	IUCV_DBF_TEXT(data, 2, "conn_action_inval called\n");
 }
 
@@ -999,29 +1005,27 @@
 static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node);
 
 
-/**
+/*
  * Actions for interface - statemachine.
- *****************************************************************************/
+ */
 
 /**
- * Startup connection by sending CONN_EVENT_START to it.
+ * dev_action_start
+ * @fi: An instance of an interface statemachine.
+ * @event: The event, just happened.
+ * @arg: Generic pointer, casted from struct net_device * upon call.
  *
- * @param fi    An instance of an interface statemachine.
- * @param event The event, just happened.
- * @param arg   Generic pointer, casted from struct net_device * upon call.
+ * Startup connection by sending CONN_EVENT_START to it.
  */
-static void
-dev_action_start(fsm_instance *fi, int event, void *arg)
+static void dev_action_start(fsm_instance *fi, int event, void *arg)
 {
-	struct net_device   *dev = (struct net_device *)arg;
-	struct netiucv_priv *privptr = dev->priv;
-	struct iucv_event   ev;
+	struct net_device   *dev = arg;
+	struct netiucv_priv *privptr = netdev_priv(dev);
 
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
 
-	ev.conn = privptr->conn;
 	fsm_newstate(fi, DEV_STATE_STARTWAIT);
-	fsm_event(privptr->conn->fsm, CONN_EVENT_START, &ev);
+	fsm_event(privptr->conn->fsm, CONN_EVENT_START, privptr->conn);
 }
 
 /**
@@ -1034,8 +1038,8 @@
 static void
 dev_action_stop(fsm_instance *fi, int event, void *arg)
 {
-	struct net_device   *dev = (struct net_device *)arg;
-	struct netiucv_priv *privptr = dev->priv;
+	struct net_device   *dev = arg;
+	struct netiucv_priv *privptr = netdev_priv(dev);
 	struct iucv_event   ev;
 
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
@@ -1057,8 +1061,8 @@
 static void
 dev_action_connup(fsm_instance *fi, int event, void *arg)
 {
-	struct net_device   *dev = (struct net_device *)arg;
-	struct netiucv_priv *privptr = dev->priv;
+	struct net_device   *dev = arg;
+	struct netiucv_priv *privptr = netdev_priv(dev);
 
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
 
@@ -1131,11 +1135,13 @@
  *
  * @return 0 on success, -ERRNO on failure. (Never fails.)
  */
-static int
-netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
+static int netiucv_transmit_skb(struct iucv_connection *conn,
+				struct sk_buff *skb)
+{
+	struct iucv_message msg;
 	unsigned long saveflags;
-	ll_header header;
-	int       rc = 0;
+	struct ll_header header;
+	int rc;
 
 	if (fsm_getstate(conn->fsm) != CONN_STATE_IDLE) {
 		int l = skb->len + NETIUCV_HDRLEN;
@@ -1145,11 +1151,12 @@
 		    (conn->max_buffsize - NETIUCV_HDRLEN)) {
 			rc = -EBUSY;
 			IUCV_DBF_TEXT(data, 2,
-				"EBUSY from netiucv_transmit_skb\n");
+				      "EBUSY from netiucv_transmit_skb\n");
 		} else {
 			atomic_inc(&skb->users);
 			skb_queue_tail(&conn->collect_queue, skb);
 			conn->collect_len += l;
+			rc = 0;
 		}
 		spin_unlock_irqrestore(&conn->collect_lock, saveflags);
 	} else {
@@ -1188,9 +1195,10 @@
 		fsm_newstate(conn->fsm, CONN_STATE_TX);
 		conn->prof.send_stamp = xtime;
 
-		rc = iucv_send(conn->pathid, NULL, 0, 0, 1 /* single_flag */,
-			0, nskb->data, nskb->len);
-			       /* Shut up, gcc! nskb is always below 2G. */
+		msg.tag = 1;
+		msg.class = 0;
+		rc = iucv_message_send(conn->path, &msg, 0, 0,
+				       nskb->data, nskb->len);
 		conn->prof.doios_single++;
 		conn->prof.txlen += skb->len;
 		conn->prof.tx_pending++;
@@ -1200,7 +1208,7 @@
 			struct netiucv_priv *privptr;
 			fsm_newstate(conn->fsm, CONN_STATE_IDLE);
 			conn->prof.tx_pending--;
-			privptr = (struct netiucv_priv *)conn->netdev->priv;
+			privptr = netdev_priv(conn->netdev);
 			if (privptr)
 				privptr->stats.tx_errors++;
 			if (copied)
@@ -1226,9 +1234,9 @@
 	return rc;
 }
 
-/**
+/*
  * Interface API for upper network layers
- *****************************************************************************/
+ */
 
 /**
  * Open an interface.
@@ -1238,9 +1246,11 @@
  *
  * @return 0 on success, -ERRNO on failure. (Never fails.)
  */
-static int
-netiucv_open(struct net_device *dev) {
-	fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_START,dev);
+static int netiucv_open(struct net_device *dev)
+{
+	struct netiucv_priv *priv = netdev_priv(dev);
+
+	fsm_event(priv->fsm, DEV_EVENT_START, dev);
 	return 0;
 }
 
@@ -1252,9 +1262,11 @@
  *
  * @return 0 on success, -ERRNO on failure. (Never fails.)
  */
-static int
-netiucv_close(struct net_device *dev) {
-	fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_STOP, dev);
+static int netiucv_close(struct net_device *dev)
+{
+	struct netiucv_priv *priv = netdev_priv(dev);
+
+	fsm_event(priv->fsm, DEV_EVENT_STOP, dev);
 	return 0;
 }
 
@@ -1271,8 +1283,8 @@
  */
 static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	int          rc = 0;
-	struct netiucv_priv *privptr = dev->priv;
+	struct netiucv_priv *privptr = netdev_priv(dev);
+	int rc;
 
 	IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
 	/**
@@ -1312,40 +1324,41 @@
 		return -EBUSY;
 	}
 	dev->trans_start = jiffies;
-	if (netiucv_transmit_skb(privptr->conn, skb))
-		rc = 1;
+	rc = netiucv_transmit_skb(privptr->conn, skb) != 0;
 	netiucv_clear_busy(dev);
 	return rc;
 }
 
 /**
+ * netiucv_stats
+ * @dev: Pointer to interface struct.
+ *
  * Returns interface statistics of a device.
  *
- * @param dev Pointer to interface struct.
- *
- * @return Pointer to stats struct of this interface.
+ * Returns pointer to stats struct of this interface.
  */
-static struct net_device_stats *
-netiucv_stats (struct net_device * dev)
+static struct net_device_stats *netiucv_stats (struct net_device * dev)
 {
+	struct netiucv_priv *priv = netdev_priv(dev);
+
 	IUCV_DBF_TEXT(trace, 5, __FUNCTION__);
-	return &((struct netiucv_priv *)dev->priv)->stats;
+	return &priv->stats;
 }
 
 /**
+ * netiucv_change_mtu
+ * @dev: Pointer to interface struct.
+ * @new_mtu: The new MTU to use for this interface.
+ *
  * Sets MTU of an interface.
  *
- * @param dev     Pointer to interface struct.
- * @param new_mtu The new MTU to use for this interface.
- *
- * @return 0 on success, -EINVAL if MTU is out of valid range.
+ * Returns 0 on success, -EINVAL if MTU is out of valid range.
  *         (valid range is 576 .. NETIUCV_MTU_MAX).
  */
-static int
-netiucv_change_mtu (struct net_device * dev, int new_mtu)
+static int netiucv_change_mtu(struct net_device * dev, int new_mtu)
 {
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
-	if ((new_mtu < 576) || (new_mtu > NETIUCV_MTU_MAX)) {
+	if (new_mtu < 576 || new_mtu > NETIUCV_MTU_MAX) {
 		IUCV_DBF_TEXT(setup, 2, "given MTU out of valid range\n");
 		return -EINVAL;
 	}
@@ -1353,12 +1366,12 @@
 	return 0;
 }
 
-/**
+/*
  * attributes in sysfs
- *****************************************************************************/
+ */
 
-static ssize_t
-user_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t user_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1366,8 +1379,8 @@
 	return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid));
 }
 
-static ssize_t
-user_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t user_write(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 	struct net_device *ndev = priv->conn->netdev;
@@ -1375,80 +1388,70 @@
 	char    *tmp;
 	char 	username[9];
 	int 	i;
-	struct iucv_connection **clist = &iucv_conns.iucv_connections;
-	unsigned long flags;
+	struct iucv_connection *cp;
 
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
-	if (count>9) {
-		PRINT_WARN("netiucv: username too long (%d)!\n", (int)count);
+	if (count > 9) {
+		PRINT_WARN("netiucv: username too long (%d)!\n", (int) count);
 		IUCV_DBF_TEXT_(setup, 2,
-			"%d is length of username\n", (int)count);
+			       "%d is length of username\n", (int) count);
 		return -EINVAL;
 	}
 
 	tmp = strsep((char **) &buf, "\n");
-	for (i=0, p=tmp; i<8 && *p; i++, p++) {
-		if (isalnum(*p) || (*p == '$'))
+	for (i = 0, p = tmp; i < 8 && *p; i++, p++) {
+		if (isalnum(*p) || (*p == '$')) {
 			username[i]= toupper(*p);
-		else if (*p == '\n') {
+			continue;
+		}
+		if (*p == '\n') {
 			/* trailing lf, grr */
 			break;
-		} else {
-			PRINT_WARN("netiucv: Invalid char %c in username!\n",
-				*p);
-			IUCV_DBF_TEXT_(setup, 2,
-				"username: invalid character %c\n",
-				*p);
-			return -EINVAL;
 		}
+		PRINT_WARN("netiucv: Invalid char %c in username!\n", *p);
+		IUCV_DBF_TEXT_(setup, 2,
+			       "username: invalid character %c\n", *p);
+		return -EINVAL;
 	}
-	while (i<8)
+	while (i < 8)
 		username[i++] = ' ';
 	username[8] = '\0';
 
-	if (memcmp(username, priv->conn->userid, 9)) {
-		/* username changed */
-		if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
-			PRINT_WARN(
-				"netiucv: device %s active, connected to %s\n",
-				dev->bus_id, priv->conn->userid);
-			PRINT_WARN("netiucv: user cannot be updated\n");
-			IUCV_DBF_TEXT(setup, 2, "user_write: device active\n");
-			return -EBUSY;
+	if (memcmp(username, priv->conn->userid, 9) &&
+	    (ndev->flags & (IFF_UP | IFF_RUNNING))) {
+		/* username changed while the interface is active. */
+		PRINT_WARN("netiucv: device %s active, connected to %s\n",
+			   dev->bus_id, priv->conn->userid);
+		PRINT_WARN("netiucv: user cannot be updated\n");
+		IUCV_DBF_TEXT(setup, 2, "user_write: device active\n");
+		return -EBUSY;
+	}
+	read_lock_bh(&iucv_connection_rwlock);
+	list_for_each_entry(cp, &iucv_connection_list, list) {
+		if (!strncmp(username, cp->userid, 9) && cp->netdev != ndev) {
+			read_unlock_bh(&iucv_connection_rwlock);
+			PRINT_WARN("netiucv: Connection to %s already "
+				   "exists\n", username);
+			return -EEXIST;
 		}
 	}
-	read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
-	while (*clist) {
-                if (!strncmp(username, (*clist)->userid, 9) ||
-		    ((*clist)->netdev != ndev))
-                        break;
-                clist = &((*clist)->next);
-        }
-	read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
-        if (*clist) {
-                PRINT_WARN("netiucv: Connection to %s already exists\n",
-                        username);
-                return -EEXIST;
-        }
+	read_unlock_bh(&iucv_connection_rwlock);
 	memcpy(priv->conn->userid, username, 9);
-
 	return count;
-
 }
 
 static DEVICE_ATTR(user, 0644, user_show, user_write);
 
-static ssize_t
-buffer_show (struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct netiucv_priv *priv = dev->driver_data;
+static ssize_t buffer_show (struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{	struct netiucv_priv *priv = dev->driver_data;
 
 	IUCV_DBF_TEXT(trace, 5, __FUNCTION__);
 	return sprintf(buf, "%d\n", priv->conn->max_buffsize);
 }
 
-static ssize_t
-buffer_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t buffer_write (struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 	struct net_device *ndev = priv->conn->netdev;
@@ -1502,8 +1505,8 @@
 
 static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write);
 
-static ssize_t
-dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr,
+			     char *buf)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1513,8 +1516,8 @@
 
 static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL);
 
-static ssize_t
-conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t conn_fsm_show (struct device *dev,
+			      struct device_attribute *attr, char *buf)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1524,8 +1527,8 @@
 
 static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL);
 
-static ssize_t
-maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t maxmulti_show (struct device *dev,
+			      struct device_attribute *attr, char *buf)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1533,8 +1536,9 @@
 	return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti);
 }
 
-static ssize_t
-maxmulti_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t maxmulti_write (struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1545,8 +1549,8 @@
 
 static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write);
 
-static ssize_t
-maxcq_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr,
+			   char *buf)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1554,8 +1558,8 @@
 	return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue);
 }
 
-static ssize_t
-maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1566,8 +1570,8 @@
 
 static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write);
 
-static ssize_t
-sdoio_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr,
+			   char *buf)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1575,8 +1579,8 @@
 	return sprintf(buf, "%ld\n", priv->conn->prof.doios_single);
 }
 
-static ssize_t
-sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1587,8 +1591,8 @@
 
 static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write);
 
-static ssize_t
-mdoio_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr,
+			   char *buf)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1596,8 +1600,8 @@
 	return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi);
 }
 
-static ssize_t
-mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1608,8 +1612,8 @@
 
 static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write);
 
-static ssize_t
-txlen_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t txlen_show (struct device *dev, struct device_attribute *attr,
+			   char *buf)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1617,8 +1621,8 @@
 	return sprintf(buf, "%ld\n", priv->conn->prof.txlen);
 }
 
-static ssize_t
-txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t txlen_write (struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1629,8 +1633,8 @@
 
 static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write);
 
-static ssize_t
-txtime_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t txtime_show (struct device *dev, struct device_attribute *attr,
+			    char *buf)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1638,8 +1642,8 @@
 	return sprintf(buf, "%ld\n", priv->conn->prof.tx_time);
 }
 
-static ssize_t
-txtime_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t txtime_write (struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1650,8 +1654,8 @@
 
 static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write);
 
-static ssize_t
-txpend_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t txpend_show (struct device *dev, struct device_attribute *attr,
+			    char *buf)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1659,8 +1663,8 @@
 	return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending);
 }
 
-static ssize_t
-txpend_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t txpend_write (struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1671,8 +1675,8 @@
 
 static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write);
 
-static ssize_t
-txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr,
+			    char *buf)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1680,8 +1684,8 @@
 	return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending);
 }
 
-static ssize_t
-txmpnd_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
 {
 	struct netiucv_priv *priv = dev->driver_data;
 
@@ -1721,8 +1725,7 @@
 	.attrs = netiucv_stat_attrs,
 };
 
-static inline int
-netiucv_add_files(struct device *dev)
+static inline int netiucv_add_files(struct device *dev)
 {
 	int ret;
 
@@ -1736,18 +1739,16 @@
 	return ret;
 }
 
-static inline void
-netiucv_remove_files(struct device *dev)
+static inline void netiucv_remove_files(struct device *dev)
 {
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
 	sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group);
 	sysfs_remove_group(&dev->kobj, &netiucv_attr_group);
 }
 
-static int
-netiucv_register_device(struct net_device *ndev)
+static int netiucv_register_device(struct net_device *ndev)
 {
-	struct netiucv_priv *priv = ndev->priv;
+	struct netiucv_priv *priv = netdev_priv(ndev);
 	struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);
 	int ret;
 
@@ -1786,8 +1787,7 @@
 	return ret;
 }
 
-static void
-netiucv_unregister_device(struct device *dev)
+static void netiucv_unregister_device(struct device *dev)
 {
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
 	netiucv_remove_files(dev);
@@ -1798,107 +1798,89 @@
  * Allocate and initialize a new connection structure.
  * Add it to the list of netiucv connections;
  */
-static struct iucv_connection *
-netiucv_new_connection(struct net_device *dev, char *username)
+static struct iucv_connection *netiucv_new_connection(struct net_device *dev,
+						      char *username)
 {
-	unsigned long flags;
-	struct iucv_connection **clist = &iucv_conns.iucv_connections;
-	struct iucv_connection *conn =
-		kzalloc(sizeof(struct iucv_connection), GFP_KERNEL);
+	struct iucv_connection *conn;
 
-	if (conn) {
-		skb_queue_head_init(&conn->collect_queue);
-		skb_queue_head_init(&conn->commit_queue);
-		spin_lock_init(&conn->collect_lock);
-		conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT;
-		conn->netdev = dev;
+	conn = kzalloc(sizeof(*conn), GFP_KERNEL);
+	if (!conn)
+		goto out;
+	skb_queue_head_init(&conn->collect_queue);
+	skb_queue_head_init(&conn->commit_queue);
+	spin_lock_init(&conn->collect_lock);
+	conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT;
+	conn->netdev = dev;
 
-		conn->rx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT,
-					  GFP_KERNEL | GFP_DMA);
-		if (!conn->rx_buff) {
-			kfree(conn);
-			return NULL;
-		}
-		conn->tx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT,
-					  GFP_KERNEL | GFP_DMA);
-		if (!conn->tx_buff) {
-			kfree_skb(conn->rx_buff);
-			kfree(conn);
-			return NULL;
-		}
-		conn->fsm = init_fsm("netiucvconn", conn_state_names,
-				     conn_event_names, NR_CONN_STATES,
-				     NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN,
-				     GFP_KERNEL);
-		if (!conn->fsm) {
-			kfree_skb(conn->tx_buff);
-			kfree_skb(conn->rx_buff);
-			kfree(conn);
-			return NULL;
-		}
-		fsm_settimer(conn->fsm, &conn->timer);
-		fsm_newstate(conn->fsm, CONN_STATE_INVALID);
+	conn->rx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA);
+	if (!conn->rx_buff)
+		goto out_conn;
+	conn->tx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA);
+	if (!conn->tx_buff)
+		goto out_rx;
+	conn->fsm = init_fsm("netiucvconn", conn_state_names,
+			     conn_event_names, NR_CONN_STATES,
+			     NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN,
+			     GFP_KERNEL);
+	if (!conn->fsm)
+		goto out_tx;
 
-		if (username) {
-			memcpy(conn->userid, username, 9);
-			fsm_newstate(conn->fsm, CONN_STATE_STOPPED);
-		}
+	fsm_settimer(conn->fsm, &conn->timer);
+	fsm_newstate(conn->fsm, CONN_STATE_INVALID);
 
-		write_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
-		conn->next = *clist;
-		*clist = conn;
-		write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
+	if (username) {
+		memcpy(conn->userid, username, 9);
+		fsm_newstate(conn->fsm, CONN_STATE_STOPPED);
 	}
+
+	write_lock_bh(&iucv_connection_rwlock);
+	list_add_tail(&conn->list, &iucv_connection_list);
+	write_unlock_bh(&iucv_connection_rwlock);
 	return conn;
+
+out_tx:
+	kfree_skb(conn->tx_buff);
+out_rx:
+	kfree_skb(conn->rx_buff);
+out_conn:
+	kfree(conn);
+out:
+	return NULL;
 }
 
 /**
  * Release a connection structure and remove it from the
  * list of netiucv connections.
  */
-static void
-netiucv_remove_connection(struct iucv_connection *conn)
+static void netiucv_remove_connection(struct iucv_connection *conn)
 {
-	struct iucv_connection **clist = &iucv_conns.iucv_connections;
-	unsigned long flags;
-
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
-	if (conn == NULL)
-		return;
-	write_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
-	while (*clist) {
-		if (*clist == conn) {
-			*clist = conn->next;
-			write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
-			if (conn->handle) {
-				iucv_unregister_program(conn->handle);
-				conn->handle = NULL;
-			}
-			fsm_deltimer(&conn->timer);
-			kfree_fsm(conn->fsm);
-			kfree_skb(conn->rx_buff);
-			kfree_skb(conn->tx_buff);
-			return;
-		}
-		clist = &((*clist)->next);
+	write_lock_bh(&iucv_connection_rwlock);
+	list_del_init(&conn->list);
+	write_unlock_bh(&iucv_connection_rwlock);
+	if (conn->path) {
+		iucv_path_sever(conn->path, iucvMagic);
+		kfree(conn->path);
+		conn->path = NULL;
 	}
-	write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
+	fsm_deltimer(&conn->timer);
+	kfree_fsm(conn->fsm);
+	kfree_skb(conn->rx_buff);
+	kfree_skb(conn->tx_buff);
 }
 
 /**
  * Release everything of a net device.
  */
-static void
-netiucv_free_netdevice(struct net_device *dev)
+static void netiucv_free_netdevice(struct net_device *dev)
 {
-	struct netiucv_priv *privptr;
+	struct netiucv_priv *privptr = netdev_priv(dev);
 
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
 
 	if (!dev)
 		return;
 
-	privptr = (struct netiucv_priv *)dev->priv;
 	if (privptr) {
 		if (privptr->conn)
 			netiucv_remove_connection(privptr->conn);
@@ -1913,11 +1895,8 @@
 /**
  * Initialize a net device. (Called from kernel in alloc_netdev())
  */
-static void
-netiucv_setup_netdevice(struct net_device *dev)
+static void netiucv_setup_netdevice(struct net_device *dev)
 {
-        memset(dev->priv, 0, sizeof(struct netiucv_priv));
-
 	dev->mtu	         = NETIUCV_MTU_DEFAULT;
 	dev->hard_start_xmit     = netiucv_tx;
 	dev->open	         = netiucv_open;
@@ -1936,8 +1915,7 @@
 /**
  * Allocate and initialize everything of a net device.
  */
-static struct net_device *
-netiucv_init_netdevice(char *username)
+static struct net_device *netiucv_init_netdevice(char *username)
 {
 	struct netiucv_priv *privptr;
 	struct net_device *dev;
@@ -1946,40 +1924,40 @@
 			   netiucv_setup_netdevice);
 	if (!dev)
 		return NULL;
-	if (dev_alloc_name(dev, dev->name) < 0) {
-		free_netdev(dev);
-		return NULL;
-	}
+	if (dev_alloc_name(dev, dev->name) < 0)
+		goto out_netdev;
 
-	privptr = (struct netiucv_priv *)dev->priv;
+	privptr = netdev_priv(dev);
 	privptr->fsm = init_fsm("netiucvdev", dev_state_names,
 				dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS,
 				dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
-	if (!privptr->fsm) {
-		free_netdev(dev);
-		return NULL;
-	}
+	if (!privptr->fsm)
+		goto out_netdev;
+
 	privptr->conn = netiucv_new_connection(dev, username);
 	if (!privptr->conn) {
-		kfree_fsm(privptr->fsm);
-		free_netdev(dev);
 		IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n");
-		return NULL;
+		goto out_fsm;
 	}
 	fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
-
 	return dev;
+
+out_fsm:
+	kfree_fsm(privptr->fsm);
+out_netdev:
+	free_netdev(dev);
+	return NULL;
 }
 
-static ssize_t
-conn_write(struct device_driver *drv, const char *buf, size_t count)
+static ssize_t conn_write(struct device_driver *drv,
+			  const char *buf, size_t count)
 {
-	char *p;
+	const char *p;
 	char username[9];
-	int i, ret;
+	int i, rc;
 	struct net_device *dev;
-	struct iucv_connection **clist = &iucv_conns.iucv_connections;
-	unsigned long flags;
+	struct netiucv_priv *priv;
+	struct iucv_connection *cp;
 
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
 	if (count>9) {
@@ -1988,83 +1966,82 @@
 		return -EINVAL;
 	}
 
-	for (i=0, p=(char *)buf; i<8 && *p; i++, p++) {
-		if (isalnum(*p) || (*p == '$'))
-			username[i]= toupper(*p);
-		else if (*p == '\n') {
+	for (i = 0, p = buf; i < 8 && *p; i++, p++) {
+		if (isalnum(*p) || *p == '$') {
+			username[i] = toupper(*p);
+			continue;
+		}
+		if (*p == '\n')
 			/* trailing lf, grr */
 			break;
-		} else {
-			PRINT_WARN("netiucv: Invalid character in username!\n");
-			IUCV_DBF_TEXT_(setup, 2,
-				"conn_write: invalid character %c\n", *p);
-			return -EINVAL;
-		}
+		PRINT_WARN("netiucv: Invalid character in username!\n");
+		IUCV_DBF_TEXT_(setup, 2,
+			       "conn_write: invalid character %c\n", *p);
+		return -EINVAL;
 	}
-	while (i<8)
+	while (i < 8)
 		username[i++] = ' ';
 	username[8] = '\0';
 
-	read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
-	while (*clist) {
-		if (!strncmp(username, (*clist)->userid, 9))
-			break;
-		clist = &((*clist)->next);
+	read_lock_bh(&iucv_connection_rwlock);
+	list_for_each_entry(cp, &iucv_connection_list, list) {
+		if (!strncmp(username, cp->userid, 9)) {
+			read_unlock_bh(&iucv_connection_rwlock);
+			PRINT_WARN("netiucv: Connection to %s already "
+				   "exists\n", username);
+			return -EEXIST;
+		}
 	}
-	read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
-	if (*clist) {
-		PRINT_WARN("netiucv: Connection to %s already exists\n",
-			username);
-		return -EEXIST;
-	}
+	read_unlock_bh(&iucv_connection_rwlock);
+
 	dev = netiucv_init_netdevice(username);
 	if (!dev) {
-		PRINT_WARN(
-		       "netiucv: Could not allocate network device structure "
-		       "for user '%s'\n", netiucv_printname(username));
+		PRINT_WARN("netiucv: Could not allocate network device "
+			   "structure for user '%s'\n",
+			   netiucv_printname(username));
 		IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n");
 		return -ENODEV;
 	}
 
-	if ((ret = netiucv_register_device(dev))) {
+	rc = netiucv_register_device(dev);
+	if (rc) {
 		IUCV_DBF_TEXT_(setup, 2,
-			"ret %d from netiucv_register_device\n", ret);
+			"ret %d from netiucv_register_device\n", rc);
 		goto out_free_ndev;
 	}
 
 	/* sysfs magic */
-	SET_NETDEV_DEV(dev,
-			(struct device*)((struct netiucv_priv*)dev->priv)->dev);
+	priv = netdev_priv(dev);
+	SET_NETDEV_DEV(dev, priv->dev);
 
-	if ((ret = register_netdev(dev))) {
-		netiucv_unregister_device((struct device*)
-			((struct netiucv_priv*)dev->priv)->dev);
-		goto out_free_ndev;
-	}
+	rc = register_netdev(dev);
+	if (rc)
+		goto out_unreg;
 
 	PRINT_INFO("%s: '%s'\n", dev->name, netiucv_printname(username));
 
 	return count;
 
+out_unreg:
+	netiucv_unregister_device(priv->dev);
 out_free_ndev:
 	PRINT_WARN("netiucv: Could not register '%s'\n", dev->name);
 	IUCV_DBF_TEXT(setup, 2, "conn_write: could not register\n");
 	netiucv_free_netdevice(dev);
-	return ret;
+	return rc;
 }
 
-DRIVER_ATTR(connection, 0200, NULL, conn_write);
+static DRIVER_ATTR(connection, 0200, NULL, conn_write);
 
-static ssize_t
-remove_write (struct device_driver *drv, const char *buf, size_t count)
+static ssize_t remove_write (struct device_driver *drv,
+			     const char *buf, size_t count)
 {
-	struct iucv_connection **clist = &iucv_conns.iucv_connections;
-	unsigned long flags;
+	struct iucv_connection *cp;
         struct net_device *ndev;
         struct netiucv_priv *priv;
         struct device *dev;
         char name[IFNAMSIZ];
-        char *p;
+	const char *p;
         int i;
 
         IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
@@ -2072,33 +2049,27 @@
         if (count >= IFNAMSIZ)
                 count = IFNAMSIZ - 1;;
 
-        for (i=0, p=(char *)buf; i<count && *p; i++, p++) {
-                if ((*p == '\n') || (*p == ' ')) {
+	for (i = 0, p = buf; i < count && *p; i++, p++) {
+		if (*p == '\n' || *p == ' ')
                         /* trailing lf, grr */
                         break;
-                } else {
-                        name[i]=*p;
-                }
+		name[i] = *p;
         }
         name[i] = '\0';
 
-	read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
-        while (*clist) {
-                ndev = (*clist)->netdev;
-                priv = (struct netiucv_priv*)ndev->priv;
+	read_lock_bh(&iucv_connection_rwlock);
+	list_for_each_entry(cp, &iucv_connection_list, list) {
+		ndev = cp->netdev;
+		priv = netdev_priv(ndev);
                 dev = priv->dev;
-
-                if (strncmp(name, ndev->name, count)) {
-                        clist = &((*clist)->next);
-                        continue;
-                }
-		read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
+		if (strncmp(name, ndev->name, count))
+			continue;
+		read_unlock_bh(&iucv_connection_rwlock);
                 if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
-                        PRINT_WARN(
-                                "netiucv: net device %s active with peer %s\n",
-                                ndev->name, priv->conn->userid);
+			PRINT_WARN("netiucv: net device %s active with peer "
+				   "%s\n", ndev->name, priv->conn->userid);
                         PRINT_WARN("netiucv: %s cannot be removed\n",
-                                ndev->name);
+				   ndev->name);
 			IUCV_DBF_TEXT(data, 2, "remove_write: still active\n");
                         return -EBUSY;
                 }
@@ -2106,75 +2077,94 @@
                 netiucv_unregister_device(dev);
                 return count;
         }
-	read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
+	read_unlock_bh(&iucv_connection_rwlock);
         PRINT_WARN("netiucv: net device %s unknown\n", name);
 	IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n");
         return -EINVAL;
 }
 
-DRIVER_ATTR(remove, 0200, NULL, remove_write);
+static DRIVER_ATTR(remove, 0200, NULL, remove_write);
 
-static void
-netiucv_banner(void)
+static struct attribute * netiucv_drv_attrs[] = {
+	&driver_attr_connection.attr,
+	&driver_attr_remove.attr,
+	NULL,
+};
+
+static struct attribute_group netiucv_drv_attr_group = {
+	.attrs = netiucv_drv_attrs,
+};
+
+static void netiucv_banner(void)
 {
 	PRINT_INFO("NETIUCV driver initialized\n");
 }
 
-static void __exit
-netiucv_exit(void)
+static void __exit netiucv_exit(void)
 {
+	struct iucv_connection *cp;
+	struct net_device *ndev;
+	struct netiucv_priv *priv;
+	struct device *dev;
+
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
-	while (iucv_conns.iucv_connections) {
-		struct net_device *ndev = iucv_conns.iucv_connections->netdev;
-		struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv;
-		struct device *dev = priv->dev;
+	while (!list_empty(&iucv_connection_list)) {
+		cp = list_entry(iucv_connection_list.next,
+				struct iucv_connection, list);
+		list_del(&cp->list);
+		ndev = cp->netdev;
+		priv = netdev_priv(ndev);
+		dev = priv->dev;
 
 		unregister_netdev(ndev);
 		netiucv_unregister_device(dev);
 	}
 
-	driver_remove_file(&netiucv_driver, &driver_attr_connection);
-	driver_remove_file(&netiucv_driver, &driver_attr_remove);
+	sysfs_remove_group(&netiucv_driver.kobj, &netiucv_drv_attr_group);
 	driver_unregister(&netiucv_driver);
+	iucv_unregister(&netiucv_handler, 1);
 	iucv_unregister_dbf_views();
 
 	PRINT_INFO("NETIUCV driver unloaded\n");
 	return;
 }
 
-static int __init
-netiucv_init(void)
+static int __init netiucv_init(void)
 {
-	int ret;
+	int rc;
 
-	ret = iucv_register_dbf_views();
-	if (ret) {
-		PRINT_WARN("netiucv_init failed, "
-			"iucv_register_dbf_views rc = %d\n", ret);
-		return ret;
-	}
+	rc = iucv_register_dbf_views();
+	if (rc)
+		goto out;
+	rc = iucv_register(&netiucv_handler, 1);
+	if (rc)
+		goto out_dbf;
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
-	ret = driver_register(&netiucv_driver);
-	if (ret) {
+	rc = driver_register(&netiucv_driver);
+	if (rc) {
 		PRINT_ERR("NETIUCV: failed to register driver.\n");
-		IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", ret);
-		iucv_unregister_dbf_views();
-		return ret;
+		IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc);
+		goto out_iucv;
 	}
 
-	/* Add entry for specifying connections. */
-	ret = driver_create_file(&netiucv_driver, &driver_attr_connection);
-	if (!ret) {
-		ret = driver_create_file(&netiucv_driver, &driver_attr_remove);
-		netiucv_banner();
-		rwlock_init(&iucv_conns.iucv_rwlock);
-	} else {
-		PRINT_ERR("NETIUCV: failed to add driver attribute.\n");
-		IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret);
-		driver_unregister(&netiucv_driver);
-		iucv_unregister_dbf_views();
+	rc = sysfs_create_group(&netiucv_driver.kobj, &netiucv_drv_attr_group);
+	if (rc) {
+		PRINT_ERR("NETIUCV: failed to add driver attributes.\n");
+		IUCV_DBF_TEXT_(setup, 2,
+			       "ret %d - netiucv_drv_attr_group\n", rc);
+		goto out_driver;
 	}
-	return ret;
+	netiucv_banner();
+	return rc;
+
+out_driver:
+	driver_unregister(&netiucv_driver);
+out_iucv:
+	iucv_unregister(&netiucv_handler, 1);
+out_dbf:
+	iucv_unregister_dbf_views();
+out:
+	return rc;
 }
 
 module_init(netiucv_init);
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
index 6bb558a..7c735e1 100644
--- a/drivers/s390/net/qeth_eddp.c
+++ b/drivers/s390/net/qeth_eddp.c
@@ -49,7 +49,7 @@
 	return buffers_needed;
 }
 
-static inline void
+static void
 qeth_eddp_free_context(struct qeth_eddp_context *ctx)
 {
 	int i;
@@ -91,7 +91,7 @@
 	}
 }
 
-static inline int
+static int
 qeth_eddp_buf_ref_context(struct qeth_qdio_out_buffer *buf,
 			  struct qeth_eddp_context *ctx)
 {
@@ -196,7 +196,7 @@
 	return flush_cnt;
 }
 
-static inline void
+static void
 qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx,
 			      struct qeth_eddp_data *eddp, int data_len)
 {
@@ -256,7 +256,7 @@
 	ctx->offset += eddp->thl;
 }
 
-static inline void
+static void
 qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
 			__wsum *hcsum)
 {
@@ -302,7 +302,7 @@
 	}
 }
 
-static inline void
+static void
 qeth_eddp_create_segment_data_tcp(struct qeth_eddp_context *ctx,
 				  struct qeth_eddp_data *eddp, int data_len,
 				  __wsum hcsum)
@@ -349,7 +349,7 @@
 	((struct tcphdr *)eddp->th_in_ctx)->check = csum_fold(hcsum);
 }
 
-static inline __wsum
+static __wsum
 qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, int data_len)
 {
 	__wsum phcsum; /* pseudo header checksum */
@@ -363,7 +363,7 @@
 	return csum_partial((u8 *)&eddp->th, eddp->thl, phcsum);
 }
 
-static inline __wsum
+static __wsum
 qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, int data_len)
 {
 	__be32 proto;
@@ -381,7 +381,7 @@
 	return phcsum;
 }
 
-static inline struct qeth_eddp_data *
+static struct qeth_eddp_data *
 qeth_eddp_create_eddp_data(struct qeth_hdr *qh, u8 *nh, u8 nhl, u8 *th, u8 thl)
 {
 	struct qeth_eddp_data *eddp;
@@ -399,7 +399,7 @@
 	return eddp;
 }
 
-static inline void
+static void
 __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
 			     struct qeth_eddp_data *eddp)
 {
@@ -464,7 +464,7 @@
 	}
 }
 
-static inline int
+static int
 qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
 			   struct sk_buff *skb, struct qeth_hdr *qhdr)
 {
@@ -505,7 +505,7 @@
 	return 0;
 }
 
-static inline void
+static void
 qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
 			 int hdr_len)
 {
@@ -529,7 +529,7 @@
 			    (skb_shinfo(skb)->gso_segs + 1);
 }
 
-static inline struct qeth_eddp_context *
+static struct qeth_eddp_context *
 qeth_eddp_create_context_generic(struct qeth_card *card, struct sk_buff *skb,
 				 int hdr_len)
 {
@@ -581,7 +581,7 @@
 	return ctx;
 }
 
-static inline struct qeth_eddp_context *
+static struct qeth_eddp_context *
 qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb,
 			     struct qeth_hdr *qhdr)
 {
@@ -625,5 +625,3 @@
 	}
 	return NULL;
 }
-
-
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index d2efa5f..2257e45 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -651,7 +651,7 @@
 		return 0;
 }
 
-static inline int
+static int
 __qeth_address_exists_in_list(struct list_head *list, struct qeth_ipaddr *addr,
 		              int same_type)
 {
@@ -795,7 +795,7 @@
 	return rc;
 }
 
-static inline void
+static void
 __qeth_delete_all_mc(struct qeth_card *card, unsigned long *flags)
 {
 	struct qeth_ipaddr *addr, *tmp;
@@ -882,7 +882,7 @@
 static void qeth_add_multicast_ipv6(struct qeth_card *);
 #endif
 
-static inline int
+static int
 qeth_set_thread_start_bit(struct qeth_card *card, unsigned long thread)
 {
 	unsigned long flags;
@@ -920,7 +920,7 @@
 	wake_up(&card->wait_q);
 }
 
-static inline int
+static int
 __qeth_do_run_thread(struct qeth_card *card, unsigned long thread)
 {
 	unsigned long flags;
@@ -1764,9 +1764,9 @@
 	qeth_release_buffer(channel,iob);
 }
 
-static inline void
+static void
 qeth_prepare_control_data(struct qeth_card *card, int len,
-struct qeth_cmd_buffer *iob)
+			  struct qeth_cmd_buffer *iob)
 {
 	qeth_setup_ccw(&card->write,iob->data,len);
 	iob->callback = qeth_release_buffer;
@@ -2160,7 +2160,7 @@
 	return 0;
 }
 
-static inline struct sk_buff *
+static struct sk_buff *
 qeth_get_skb(unsigned int length, struct qeth_hdr *hdr)
 {
 	struct sk_buff* skb;
@@ -2179,7 +2179,7 @@
 	return skb;
 }
 
-static inline struct sk_buff *
+static struct sk_buff *
 qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
 		  struct qdio_buffer_element **__element, int *__offset,
 		  struct qeth_hdr **hdr)
@@ -2264,7 +2264,7 @@
 	return NULL;
 }
 
-static inline __be16
+static __be16
 qeth_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
 	struct qeth_card *card;
@@ -2297,7 +2297,7 @@
 	return htons(ETH_P_802_2);
 }
 
-static inline void
+static void
 qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb,
 			 struct qeth_hdr *hdr)
 {
@@ -2351,7 +2351,7 @@
 	fake_llc->ethertype = ETH_P_IP;
 }
 
-static inline void
+static void
 qeth_rebuild_skb_fake_ll_eth(struct qeth_card *card, struct sk_buff *skb,
 			 struct qeth_hdr *hdr)
 {
@@ -2420,7 +2420,7 @@
 	*((__u32 *)skb->cb) = ++card->seqno.pkt_seqno;
 }
 
-static inline __u16
+static __u16
 qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
 		 struct qeth_hdr *hdr)
 {
@@ -2476,7 +2476,7 @@
 	return vlan_id;
 }
 
-static inline void
+static void
 qeth_process_inbound_buffer(struct qeth_card *card,
 			    struct qeth_qdio_buffer *buf, int index)
 {
@@ -2528,7 +2528,7 @@
 	}
 }
 
-static inline struct qeth_buffer_pool_entry *
+static struct qeth_buffer_pool_entry *
 qeth_get_buffer_pool_entry(struct qeth_card *card)
 {
 	struct qeth_buffer_pool_entry *entry;
@@ -2543,7 +2543,7 @@
 	return NULL;
 }
 
-static inline void
+static void
 qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf)
 {
 	struct qeth_buffer_pool_entry *pool_entry;
@@ -2570,7 +2570,7 @@
 	buf->state = QETH_QDIO_BUF_EMPTY;
 }
 
-static inline void
+static void
 qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
 			 struct qeth_qdio_out_buffer *buf)
 {
@@ -2595,7 +2595,7 @@
 	atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY);
 }
 
-static inline void
+static void
 qeth_queue_input_buffer(struct qeth_card *card, int index)
 {
 	struct qeth_qdio_q *queue = card->qdio.in_q;
@@ -2699,7 +2699,7 @@
 			card->perf_stats.inbound_start_time;
 }
 
-static inline int
+static int
 qeth_handle_send_error(struct qeth_card *card,
 		       struct qeth_qdio_out_buffer *buffer,
 		       unsigned int qdio_err, unsigned int siga_err)
@@ -2821,7 +2821,7 @@
  * Switched to packing state if the number of used buffers on a queue
  * reaches a certain limit.
  */
-static inline void
+static void
 qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue)
 {
 	if (!queue->do_pack) {
@@ -2842,7 +2842,7 @@
  * In that case 1 is returned to inform the caller. If no buffer
  * has to be flushed, zero is returned.
  */
-static inline int
+static int
 qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
 {
 	struct qeth_qdio_out_buffer *buffer;
@@ -2877,7 +2877,7 @@
  * Checks if there is a packing buffer and prepares it to be flushed.
  * In that case returns 1, otherwise zero.
  */
-static inline int
+static int
 qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue)
 {
 	struct qeth_qdio_out_buffer *buffer;
@@ -2894,7 +2894,7 @@
 	return 0;
 }
 
-static inline void
+static void
 qeth_check_outbound_queue(struct qeth_qdio_out_q *queue)
 {
 	int index;
@@ -3594,7 +3594,7 @@
 	}
 }
 
-static inline int
+static int
 qeth_send_packet(struct qeth_card *, struct sk_buff *);
 
 static int
@@ -3759,7 +3759,7 @@
 	return 0;
 }
 
-static inline int
+static int
 qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
 {
 	int cast_type = RTN_UNSPEC;
@@ -3806,7 +3806,7 @@
 	return cast_type;
 }
 
-static inline int
+static int
 qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
 		        int ipv, int cast_type)
 {
@@ -3853,7 +3853,7 @@
 	}
 }
 
-static inline struct qeth_hdr *
+static struct qeth_hdr *
 __qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv)
 {
 #ifdef CONFIG_QETH_VLAN
@@ -3882,14 +3882,14 @@
 		qeth_push_skb(card, skb, sizeof(struct qeth_hdr)));
 }
 
-static inline void
+static void
 __qeth_free_new_skb(struct sk_buff *orig_skb, struct sk_buff *new_skb)
 {
 	if (orig_skb != new_skb)
 		dev_kfree_skb_any(new_skb);
 }
 
-static inline struct sk_buff *
+static struct sk_buff *
 qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb,
 		 struct qeth_hdr **hdr, int ipv)
 {
@@ -3940,7 +3940,7 @@
 	return ct | QETH_CAST_UNICAST;
 }
 
-static inline void
+static void
 qeth_layer2_get_packet_type(struct qeth_card *card, struct qeth_hdr *hdr,
 			    struct sk_buff *skb)
 {
@@ -3977,7 +3977,7 @@
 	}
 }
 
-static inline void
+static void
 qeth_layer2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
 			struct sk_buff *skb, int cast_type)
 {
@@ -4068,7 +4068,7 @@
 	}
 }
 
-static inline void
+static void
 __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
 		   int is_tso, int *next_element_to_fill)
 {
@@ -4112,7 +4112,7 @@
 	*next_element_to_fill = element;
 }
 
-static inline int
+static int
 qeth_fill_buffer(struct qeth_qdio_out_q *queue,
 		 struct qeth_qdio_out_buffer *buf,
 		 struct sk_buff *skb)
@@ -4171,7 +4171,7 @@
 	return flush_cnt;
 }
 
-static inline int
+static int
 qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue,
 			 struct sk_buff *skb, struct qeth_hdr *hdr,
 			 int elements_needed,
@@ -4222,7 +4222,7 @@
 	return -EBUSY;
 }
 
-static inline int
+static int
 qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
 		    struct sk_buff *skb, struct qeth_hdr *hdr,
 		    int elements_needed, struct qeth_eddp_context *ctx)
@@ -4328,7 +4328,7 @@
 	return rc;
 }
 
-static inline int
+static int
 qeth_get_elements_no(struct qeth_card *card, void *hdr,
 		     struct sk_buff *skb, int elems)
 {
@@ -4349,7 +4349,7 @@
 }
 
 
-static inline int
+static int
 qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
 {
 	int ipv = 0;
@@ -4536,7 +4536,7 @@
 }
 
 
-static inline const char *
+static const char *
 qeth_arp_get_error_cause(int *rc)
 {
 	switch (*rc) {
@@ -4597,7 +4597,7 @@
 	return rc;
 }
 
-static inline void
+static void
 qeth_copy_arp_entries_stripped(struct qeth_arp_query_info *qinfo,
 		               struct qeth_arp_query_data *qdata,
 			       int entry_size, int uentry_size)
@@ -5214,7 +5214,7 @@
 	spin_unlock_irqrestore(&card->vlanlock, flags);
 }
 
-static inline void
+static void
 qeth_free_vlan_buffer(struct qeth_card *card, struct qeth_qdio_out_buffer *buf,
 		      unsigned short vid)
 {
@@ -5625,7 +5625,7 @@
 	spin_unlock_irqrestore(&card->ip_lock, flags);
 }
 
-static inline void
+static void
 qeth_add_mc(struct qeth_card *card, struct in_device *in4_dev)
 {
 	struct qeth_ipaddr *ipm;
@@ -5711,7 +5711,7 @@
 }
 
 #ifdef CONFIG_QETH_IPV6
-static inline void
+static void
 qeth_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev)
 {
 	struct qeth_ipaddr *ipm;
@@ -6022,7 +6022,7 @@
 
 	return rc;
 }
-static inline void
+static void
 qeth_fill_netmask(u8 *netmask, unsigned int len)
 {
 	int i,j;
@@ -6626,7 +6626,7 @@
 	return rc;
 }
 
-static inline int
+static int
 qeth_setadapter_hstr(struct qeth_card *card)
 {
 	int rc;
@@ -6889,7 +6889,7 @@
 	return rc;
 }
 
-static inline int
+static int
 qeth_start_ipa_arp_processing(struct qeth_card *card)
 {
 	int rc;
@@ -7529,7 +7529,7 @@
 	wake_up(&card->wait_q);
 }
 
-static inline int
+static int
 qeth_threads_running(struct qeth_card *card, unsigned long threads)
 {
 	unsigned long flags;
@@ -8118,7 +8118,7 @@
 	spin_unlock_irqrestore(&card->ip_lock, flags);
 }
 
-static inline void
+static void
 qeth_convert_addr_to_bits(u8 *addr, u8 *bits, int len)
 {
 	int i, j;
diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c
index 5836737..d518419 100644
--- a/drivers/s390/net/qeth_sys.c
+++ b/drivers/s390/net/qeth_sys.c
@@ -328,7 +328,7 @@
 static DEVICE_ATTR(buffer_count, 0644, qeth_dev_bufcnt_show,
 		qeth_dev_bufcnt_store);
 
-static inline ssize_t
+static ssize_t
 qeth_dev_route_show(struct qeth_card *card, struct qeth_routing_info *route,
 		    char *buf)
 {
@@ -368,7 +368,7 @@
 	return qeth_dev_route_show(card, &card->options.route4, buf);
 }
 
-static inline ssize_t
+static ssize_t
 qeth_dev_route_store(struct qeth_card *card, struct qeth_routing_info *route,
 		enum qeth_prot_versions prot, const char *buf, size_t count)
 {
@@ -998,7 +998,7 @@
 	.store	= _store,						     \
 };
 
-int
+static int
 qeth_check_layer2(struct qeth_card *card)
 {
 	if (card->options.layer2)
@@ -1100,7 +1100,7 @@
 			qeth_dev_ipato_invert4_show,
 			qeth_dev_ipato_invert4_store);
 
-static inline ssize_t
+static ssize_t
 qeth_dev_ipato_add_show(char *buf, struct qeth_card *card,
 			enum qeth_prot_versions proto)
 {
@@ -1146,7 +1146,7 @@
 	return qeth_dev_ipato_add_show(buf, card, QETH_PROT_IPV4);
 }
 
-static inline int
+static int
 qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto,
 		  u8 *addr, int *mask_bits)
 {
@@ -1178,7 +1178,7 @@
 	return 0;
 }
 
-static inline ssize_t
+static ssize_t
 qeth_dev_ipato_add_store(const char *buf, size_t count,
 			 struct qeth_card *card, enum qeth_prot_versions proto)
 {
@@ -1223,7 +1223,7 @@
 			qeth_dev_ipato_add4_show,
 			qeth_dev_ipato_add4_store);
 
-static inline ssize_t
+static ssize_t
 qeth_dev_ipato_del_store(const char *buf, size_t count,
 			 struct qeth_card *card, enum qeth_prot_versions proto)
 {
@@ -1361,7 +1361,7 @@
 	.attrs = (struct attribute **)qeth_ipato_device_attrs,
 };
 
-static inline ssize_t
+static ssize_t
 qeth_dev_vipa_add_show(char *buf, struct qeth_card *card,
 			enum qeth_prot_versions proto)
 {
@@ -1407,7 +1407,7 @@
 	return qeth_dev_vipa_add_show(buf, card, QETH_PROT_IPV4);
 }
 
-static inline int
+static int
 qeth_parse_vipae(const char* buf, enum qeth_prot_versions proto,
 		 u8 *addr)
 {
@@ -1418,7 +1418,7 @@
 	return 0;
 }
 
-static inline ssize_t
+static ssize_t
 qeth_dev_vipa_add_store(const char *buf, size_t count,
 			 struct qeth_card *card, enum qeth_prot_versions proto)
 {
@@ -1451,7 +1451,7 @@
 			qeth_dev_vipa_add4_show,
 			qeth_dev_vipa_add4_store);
 
-static inline ssize_t
+static ssize_t
 qeth_dev_vipa_del_store(const char *buf, size_t count,
 			 struct qeth_card *card, enum qeth_prot_versions proto)
 {
@@ -1542,7 +1542,7 @@
 	.attrs = (struct attribute **)qeth_vipa_device_attrs,
 };
 
-static inline ssize_t
+static ssize_t
 qeth_dev_rxip_add_show(char *buf, struct qeth_card *card,
 		       enum qeth_prot_versions proto)
 {
@@ -1588,7 +1588,7 @@
 	return qeth_dev_rxip_add_show(buf, card, QETH_PROT_IPV4);
 }
 
-static inline int
+static int
 qeth_parse_rxipe(const char* buf, enum qeth_prot_versions proto,
 		 u8 *addr)
 {
@@ -1599,7 +1599,7 @@
 	return 0;
 }
 
-static inline ssize_t
+static ssize_t
 qeth_dev_rxip_add_store(const char *buf, size_t count,
 			struct qeth_card *card, enum qeth_prot_versions proto)
 {
@@ -1632,7 +1632,7 @@
 			qeth_dev_rxip_add4_show,
 			qeth_dev_rxip_add4_store);
 
-static inline ssize_t
+static ssize_t
 qeth_dev_rxip_del_store(const char *buf, size_t count,
 			struct qeth_card *card, enum qeth_prot_versions proto)
 {
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
index b8179c2..3ccca58 100644
--- a/drivers/s390/net/smsgiucv.c
+++ b/drivers/s390/net/smsgiucv.c
@@ -1,7 +1,7 @@
 /*
  * IUCV special message driver
  *
- * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
  * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  *
  * This program is free software; you can redistribute it and/or modify
@@ -23,10 +23,10 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/device.h>
+#include <net/iucv/iucv.h>
 #include <asm/cpcmd.h>
 #include <asm/ebcdic.h>
-
-#include "iucv.h"
+#include "smsgiucv.h"
 
 struct smsg_callback {
 	struct list_head list;
@@ -39,38 +39,46 @@
    ("(C) 2003 IBM Corporation by Martin Schwidefsky (schwidefsky@de.ibm.com)");
 MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver");
 
-static iucv_handle_t smsg_handle;
-static unsigned short smsg_pathid;
+static struct iucv_path *smsg_path;
+
 static DEFINE_SPINLOCK(smsg_list_lock);
 static struct list_head smsg_list = LIST_HEAD_INIT(smsg_list);
 
-static void
-smsg_connection_complete(iucv_ConnectionComplete *eib, void *pgm_data)
+static int smsg_path_pending(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]);
+static void smsg_message_pending(struct iucv_path *, struct iucv_message *);
+
+static struct iucv_handler smsg_handler = {
+	.path_pending	 = smsg_path_pending,
+	.message_pending = smsg_message_pending,
+};
+
+static int smsg_path_pending(struct iucv_path *path, u8 ipvmid[8],
+			     u8 ipuser[16])
 {
+	if (strncmp(ipvmid, "*MSG    ", sizeof(ipvmid)) != 0)
+		return -EINVAL;
+	/* Path pending from *MSG. */
+	return iucv_path_accept(path, &smsg_handler, "SMSGIUCV        ", NULL);
 }
 
-
-static void
-smsg_message_pending(iucv_MessagePending *eib, void *pgm_data)
+static void smsg_message_pending(struct iucv_path *path,
+				 struct iucv_message *msg)
 {
 	struct smsg_callback *cb;
-	unsigned char *msg;
+	unsigned char *buffer;
 	unsigned char sender[9];
-	unsigned short len;
 	int rc, i;
 
-	len = eib->ln1msg2.ipbfln1f;
-	msg = kmalloc(len + 1, GFP_ATOMIC|GFP_DMA);
-	if (!msg) {
-		iucv_reject(eib->ippathid, eib->ipmsgid, eib->iptrgcls);
+	buffer = kmalloc(msg->length + 1, GFP_ATOMIC | GFP_DMA);
+	if (!buffer) {
+		iucv_message_reject(path, msg);
 		return;
 	}
-	rc = iucv_receive(eib->ippathid, eib->ipmsgid, eib->iptrgcls,
-			  msg, len, NULL, NULL, NULL);
+	rc = iucv_message_receive(path, msg, 0, buffer, msg->length, NULL);
 	if (rc == 0) {
-		msg[len] = 0;
-		EBCASC(msg, len);
-		memcpy(sender, msg, 8);
+		buffer[msg->length] = 0;
+		EBCASC(buffer, msg->length);
+		memcpy(sender, buffer, 8);
 		sender[8] = 0;
 		/* Remove trailing whitespace from the sender name. */
 		for (i = 7; i >= 0; i--) {
@@ -80,27 +88,17 @@
 		}
 		spin_lock(&smsg_list_lock);
 		list_for_each_entry(cb, &smsg_list, list)
-			if (strncmp(msg + 8, cb->prefix, cb->len) == 0) {
-				cb->callback(sender, msg + 8);
+			if (strncmp(buffer + 8, cb->prefix, cb->len) == 0) {
+				cb->callback(sender, buffer + 8);
 				break;
 			}
 		spin_unlock(&smsg_list_lock);
 	}
-	kfree(msg);
+	kfree(buffer);
 }
 
-static iucv_interrupt_ops_t smsg_ops = {
-	.ConnectionComplete = smsg_connection_complete,
-	.MessagePending     = smsg_message_pending,
-};
-
-static struct device_driver smsg_driver = {
-	.name = "SMSGIUCV",
-	.bus  = &iucv_bus,
-};
-
-int
-smsg_register_callback(char *prefix, void (*callback)(char *from, char *str))
+int smsg_register_callback(char *prefix,
+			   void (*callback)(char *from, char *str))
 {
 	struct smsg_callback *cb;
 
@@ -110,18 +108,18 @@
 	cb->prefix = prefix;
 	cb->len = strlen(prefix);
 	cb->callback = callback;
-	spin_lock(&smsg_list_lock);
+	spin_lock_bh(&smsg_list_lock);
 	list_add_tail(&cb->list, &smsg_list);
-	spin_unlock(&smsg_list_lock);
+	spin_unlock_bh(&smsg_list_lock);
 	return 0;
 }
 
-void
-smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str))
+void smsg_unregister_callback(char *prefix,
+			      void (*callback)(char *from, char *str))
 {
 	struct smsg_callback *cb, *tmp;
 
-	spin_lock(&smsg_list_lock);
+	spin_lock_bh(&smsg_list_lock);
 	cb = NULL;
 	list_for_each_entry(tmp, &smsg_list, list)
 		if (tmp->callback == callback &&
@@ -130,55 +128,58 @@
 			list_del(&cb->list);
 			break;
 		}
-	spin_unlock(&smsg_list_lock);
+	spin_unlock_bh(&smsg_list_lock);
 	kfree(cb);
 }
 
-static void __exit
-smsg_exit(void)
+static struct device_driver smsg_driver = {
+	.name = "SMSGIUCV",
+	.bus  = &iucv_bus,
+};
+
+static void __exit smsg_exit(void)
 {
-	if (smsg_handle > 0) {
-		cpcmd("SET SMSG OFF", NULL, 0, NULL);
-		iucv_sever(smsg_pathid, NULL);
-		iucv_unregister_program(smsg_handle);
-		driver_unregister(&smsg_driver);
-	}
-	return;
+	cpcmd("SET SMSG IUCV", NULL, 0, NULL);
+	iucv_unregister(&smsg_handler, 1);
+	driver_unregister(&smsg_driver);
 }
 
-static int __init
-smsg_init(void)
+static int __init smsg_init(void)
 {
-	static unsigned char pgmmask[24] = {
-		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
-	};
 	int rc;
 
 	rc = driver_register(&smsg_driver);
-	if (rc != 0) {
-		printk(KERN_ERR "SMSGIUCV: failed to register driver.\n");
-		return rc;
-	}
-	smsg_handle = iucv_register_program("SMSGIUCV        ", "*MSG    ",
-					    pgmmask, &smsg_ops, NULL);
-	if (!smsg_handle) {
+	if (rc != 0)
+		goto out;
+	rc = iucv_register(&smsg_handler, 1);
+	if (rc) {
 		printk(KERN_ERR "SMSGIUCV: failed to register to iucv");
-		driver_unregister(&smsg_driver);
-		return -EIO;	/* better errno ? */
+		rc = -EIO;	/* better errno ? */
+		goto out_driver;
 	}
-	rc = iucv_connect (&smsg_pathid, 255, NULL, "*MSG    ", NULL, 0,
-			   NULL, NULL, smsg_handle, NULL);
+	smsg_path = iucv_path_alloc(255, 0, GFP_KERNEL);
+	if (!smsg_path) {
+		rc = -ENOMEM;
+		goto out_register;
+	}
+	rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG    ",
+			       NULL, NULL, NULL);
 	if (rc) {
 		printk(KERN_ERR "SMSGIUCV: failed to connect to *MSG");
-		iucv_unregister_program(smsg_handle);
-		driver_unregister(&smsg_driver);
-		smsg_handle = NULL;
-		return -EIO;
+		rc = -EIO;	/* better errno ? */
+		goto out_free;
 	}
 	cpcmd("SET SMSG IUCV", NULL, 0, NULL);
 	return 0;
+
+out_free:
+	iucv_path_free(smsg_path);
+out_register:
+	iucv_unregister(&smsg_handler, 1);
+out_driver:
+	driver_unregister(&smsg_driver);
+out:
+	return rc;
 }
 
 module_init(smsg_init);
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
index e088b5e..806bb1a 100644
--- a/drivers/s390/s390mach.c
+++ b/drivers/s390/s390mach.c
@@ -13,22 +13,18 @@
 #include <linux/errno.h>
 #include <linux/workqueue.h>
 #include <linux/time.h>
+#include <linux/device.h>
 #include <linux/kthread.h>
-
+#include <asm/etr.h>
 #include <asm/lowcore.h>
-
+#include <asm/cio.h>
+#include "cio/cio.h"
+#include "cio/chsc.h"
+#include "cio/css.h"
 #include "s390mach.h"
 
 static struct semaphore m_sem;
 
-extern int css_process_crw(int, int);
-extern int chsc_process_crw(void);
-extern int chp_process_crw(int, int);
-extern void css_reiterate_subchannels(void);
-
-extern struct workqueue_struct *slow_path_wq;
-extern struct work_struct slow_path_work;
-
 static NORET_TYPE void
 s390_handle_damage(char *msg)
 {
@@ -470,6 +466,19 @@
 			s390_handle_damage("unable to revalidate registers.");
 	}
 
+	if (mci->cd) {
+		/* Timing facility damage */
+		s390_handle_damage("TOD clock damaged");
+	}
+
+	if (mci->ed && mci->ec) {
+		/* External damage */
+		if (S390_lowcore.external_damage_code & (1U << ED_ETR_SYNC))
+			etr_sync_check();
+		if (S390_lowcore.external_damage_code & (1U << ED_ETR_SWITCH))
+			etr_switch_to_local();
+	}
+
 	if (mci->se)
 		/* Storage error uncorrected */
 		s390_handle_damage("received storage error uncorrected "
@@ -508,7 +517,7 @@
 machine_check_init(void)
 {
 	init_MUTEX_LOCKED(&m_sem);
-	ctl_clear_bit(14, 25);	/* disable external damage MCH */
+	ctl_set_bit(14, 25);	/* enable external damage MCH */
 	ctl_set_bit(14, 27);    /* enable system recovery MCH */
 #ifdef CONFIG_MACHCHK_WARNING
 	ctl_set_bit(14, 24);	/* enable warning MCH */
@@ -529,7 +538,11 @@
 static int __init
 machine_check_crw_init (void)
 {
-	kthread_run(s390_collect_crw_info, &m_sem, "kmcheck");
+	struct task_struct *task;
+
+	task = kthread_run(s390_collect_crw_info, &m_sem, "kmcheck");
+	if (IS_ERR(task))
+		return PTR_ERR(task);
 	ctl_set_bit(14, 28);	/* enable channel report MCH */
 	return 0;
 }
diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h
index 7abb42a..d3ca428 100644
--- a/drivers/s390/s390mach.h
+++ b/drivers/s390/s390mach.h
@@ -102,4 +102,7 @@
 	return ccode;
 }
 
+#define ED_ETR_SYNC	12	/* External damage ETR sync check */
+#define ED_ETR_SWITCH	13	/* External damage ETR switch to local */
+
 #endif /* __s390mach */
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 85093b7..39a8852 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -47,13 +47,12 @@
 static void zfcp_ns_gid_pn_handler(unsigned long);
 
 /* miscellaneous */
-static inline int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t);
-static inline void zfcp_sg_list_free(struct zfcp_sg_list *);
-static inline int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *,
-					      void __user *, size_t);
-static inline int zfcp_sg_list_copy_to_user(void __user *,
-					    struct zfcp_sg_list *, size_t);
-
+static int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t);
+static void zfcp_sg_list_free(struct zfcp_sg_list *);
+static int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *,
+				       void __user *, size_t);
+static int zfcp_sg_list_copy_to_user(void __user *,
+				     struct zfcp_sg_list *, size_t);
 static long zfcp_cfdc_dev_ioctl(struct file *, unsigned int, unsigned long);
 
 #define ZFCP_CFDC_IOC_MAGIC                     0xDD
@@ -605,7 +604,7 @@
  * elements of the scatter-gather list. The maximum size of a single element
  * in the scatter-gather list is PAGE_SIZE.
  */
-static inline int
+static int
 zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size)
 {
 	struct scatterlist *sg;
@@ -652,7 +651,7 @@
  * Memory for each element in the scatter-gather list is freed.
  * Finally sg_list->sg is freed itself and sg_list->count is reset.
  */
-static inline void
+static void
 zfcp_sg_list_free(struct zfcp_sg_list *sg_list)
 {
 	struct scatterlist *sg;
@@ -697,7 +696,7 @@
  * @size: number of bytes to be copied
  * Return: 0 on success, -EFAULT if copy_from_user fails.
  */
-static inline int
+static int
 zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list,
 			    void __user *user_buffer,
                             size_t size)
@@ -735,7 +734,7 @@
  * @size: number of bytes to be copied
  * Return: 0 on success, -EFAULT if copy_to_user fails
  */
-static inline int
+static int
 zfcp_sg_list_copy_to_user(void __user  *user_buffer,
 			  struct zfcp_sg_list *sg_list,
                           size_t size)
@@ -1799,7 +1798,7 @@
  * @code: reason code
  * @rc_table: table of reason codes and descriptions
  */
-static inline const char *
+static const char *
 zfcp_rc_description(u8 code, const struct zfcp_rc_entry *rc_table)
 {
 	const char *descr = "unknown reason code";
@@ -1847,7 +1846,7 @@
  * @rjt_par: reject parameter acc. to FC-PH/FC-FS
  * @rc_table: table of reason codes and descriptions
  */
-static inline void
+static void
 zfcp_print_els_rjt(struct zfcp_ls_rjt_par *rjt_par,
 		   const struct zfcp_rc_entry *rc_table)
 {
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 0aa3b1a..d8191d1 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -31,7 +31,7 @@
 
 #define ZFCP_LOG_AREA			ZFCP_LOG_AREA_OTHER
 
-static inline int
+static int
 zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck)
 {
 	unsigned long long sec;
@@ -106,7 +106,7 @@
 	return len;
 }
 
-static inline int
+static int
 zfcp_dbf_view_header(debug_info_t * id, struct debug_view *view, int area,
 		     debug_entry_t * entry, char *out_buf)
 {
@@ -130,7 +130,7 @@
 	return len;
 }
 
-inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
+void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
 {
 	struct zfcp_adapter *adapter = fsf_req->adapter;
 	struct fsf_qtcb *qtcb = fsf_req->qtcb;
@@ -241,7 +241,7 @@
 	spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
 }
 
-inline void
+void
 zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter,
 			     struct fsf_status_read_buffer *status_buffer)
 {
@@ -295,7 +295,7 @@
 	spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
 }
 
-inline void
+void
 zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, unsigned int status,
 			unsigned int qdio_error, unsigned int siga_error,
 			int sbal_index, int sbal_count)
@@ -316,7 +316,7 @@
 	spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
 }
 
-static inline int
+static int
 zfcp_hba_dbf_view_response(char *out_buf,
 			   struct zfcp_hba_dbf_record_response *rec)
 {
@@ -403,7 +403,7 @@
 	return len;
 }
 
-static inline int
+static int
 zfcp_hba_dbf_view_status(char *out_buf, struct zfcp_hba_dbf_record_status *rec)
 {
 	int len = 0;
@@ -424,7 +424,7 @@
 	return len;
 }
 
-static inline int
+static int
 zfcp_hba_dbf_view_qdio(char *out_buf, struct zfcp_hba_dbf_record_qdio *rec)
 {
 	int len = 0;
@@ -469,7 +469,7 @@
 	return len;
 }
 
-struct debug_view zfcp_hba_dbf_view = {
+static struct debug_view zfcp_hba_dbf_view = {
 	"structured",
 	NULL,
 	&zfcp_dbf_view_header,
@@ -478,7 +478,7 @@
 	NULL
 };
 
-inline void
+void
 _zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req,
 			      u32 s_id, u32 d_id, void *buffer, int buflen)
 {
@@ -519,7 +519,7 @@
 	spin_unlock_irqrestore(&adapter->san_dbf_lock, flags);
 }
 
-inline void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
 {
 	struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
 	struct zfcp_port *port = ct->port;
@@ -531,7 +531,7 @@
 				      ct->req->length);
 }
 
-inline void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
 {
 	struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
 	struct zfcp_port *port = ct->port;
@@ -543,7 +543,7 @@
 				      ct->resp->length);
 }
 
-static inline void
+static void
 _zfcp_san_dbf_event_common_els(const char *tag, int level,
 			       struct zfcp_fsf_req *fsf_req, u32 s_id,
 			       u32 d_id, u8 ls_code, void *buffer, int buflen)
@@ -585,7 +585,7 @@
 	spin_unlock_irqrestore(&adapter->san_dbf_lock, flags);
 }
 
-inline void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req)
 {
 	struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data;
 
@@ -597,7 +597,7 @@
 				       els->req->length);
 }
 
-inline void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req)
 {
 	struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data;
 
@@ -608,7 +608,7 @@
 				       els->resp->length);
 }
 
-inline void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req)
 {
 	struct zfcp_adapter *adapter = fsf_req->adapter;
 	struct fsf_status_read_buffer *status_buffer =
@@ -693,7 +693,7 @@
 	return len;
 }
 
-struct debug_view zfcp_san_dbf_view = {
+static struct debug_view zfcp_san_dbf_view = {
 	"structured",
 	NULL,
 	&zfcp_dbf_view_header,
@@ -702,7 +702,7 @@
 	NULL
 };
 
-static inline void
+static void
 _zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level,
 			    struct zfcp_adapter *adapter,
 			    struct scsi_cmnd *scsi_cmnd,
@@ -786,7 +786,7 @@
 	spin_unlock_irqrestore(&adapter->scsi_dbf_lock, flags);
 }
 
-inline void
+void
 zfcp_scsi_dbf_event_result(const char *tag, int level,
 			   struct zfcp_adapter *adapter,
 			   struct scsi_cmnd *scsi_cmnd,
@@ -796,7 +796,7 @@
 			adapter, scsi_cmnd, fsf_req, 0);
 }
 
-inline void
+void
 zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter,
 			  struct scsi_cmnd *scsi_cmnd,
 			  struct zfcp_fsf_req *new_fsf_req,
@@ -806,7 +806,7 @@
 			adapter, scsi_cmnd, new_fsf_req, old_req_id);
 }
 
-inline void
+void
 zfcp_scsi_dbf_event_devreset(const char *tag, u8 flag, struct zfcp_unit *unit,
 			     struct scsi_cmnd *scsi_cmnd)
 {
@@ -884,7 +884,7 @@
 	return len;
 }
 
-struct debug_view zfcp_scsi_dbf_view = {
+static struct debug_view zfcp_scsi_dbf_view = {
 	"structured",
 	NULL,
 	&zfcp_dbf_view_header,
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index c88babc..88642de 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -200,7 +200,7 @@
  * returns:	0	- initiated action successfully
  *		<0	- failed to initiate action
  */
-int
+static int
 zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, int clear_mask)
 {
 	int retval;
@@ -295,7 +295,7 @@
  * zfcp_erp_adisc - send ADISC ELS command
  * @port: port structure
  */
-int
+static int
 zfcp_erp_adisc(struct zfcp_port *port)
 {
 	struct zfcp_adapter *adapter = port->adapter;
@@ -380,7 +380,7 @@
  *
  * If ADISC failed (LS_RJT or timed out) forced reopen of the port is triggered.
  */
-void
+static void
 zfcp_erp_adisc_handler(unsigned long data)
 {
 	struct zfcp_send_els *send_els;
@@ -3141,7 +3141,6 @@
 		break;
 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
 		if (result != ZFCP_ERP_SUCCEEDED) {
-			struct zfcp_port *port;
 			list_for_each_entry(port, &adapter->port_list_head, list)
 				if (port->rport &&
 				    !atomic_test_mask(ZFCP_STATUS_PORT_WKA,
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index b8794d7..cda0cc0 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -119,8 +119,8 @@
 extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *);
 extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t);
 extern char *zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *);
-extern void set_host_byte(u32 *, char);
-extern void set_driver_byte(u32 *, char);
+extern void set_host_byte(int *, char);
+extern void set_driver_byte(int *, char);
 extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *);
 extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *);
 
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 067f151..4b3ae3f 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -4563,7 +4563,7 @@
 /*
  * set qtcb pointer in fsf_req and initialize QTCB
  */
-static inline void
+static void
 zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req)
 {
 	if (likely(fsf_req->qtcb != NULL)) {
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index dbd9f48..1e12a78 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -21,22 +21,22 @@
 
 #include "zfcp_ext.h"
 
-static inline void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int);
+static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int);
 static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_get
 	(struct zfcp_qdio_queue *, int, int);
 static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_resp
 	(struct zfcp_fsf_req *, int, int);
-static inline volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain
+static volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain
 	(struct zfcp_fsf_req *, unsigned long);
-static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_next
+static volatile struct qdio_buffer_element *zfcp_qdio_sbale_next
 	(struct zfcp_fsf_req *, unsigned long);
-static inline int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int);
+static int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int);
 static inline int zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *);
-static inline void zfcp_qdio_sbale_fill
+static void zfcp_qdio_sbale_fill
 	(struct zfcp_fsf_req *, unsigned long, void *, int);
-static inline int zfcp_qdio_sbals_from_segment
+static int zfcp_qdio_sbals_from_segment
 	(struct zfcp_fsf_req *, unsigned long, void *, unsigned long);
-static inline int zfcp_qdio_sbals_from_buffer
+static int zfcp_qdio_sbals_from_buffer
 	(struct zfcp_fsf_req *, unsigned long, void *, unsigned long, int);
 
 static qdio_handler_t zfcp_qdio_request_handler;
@@ -201,7 +201,7 @@
  * returns:	error flag
  *
  */
-static inline int
+static int
 zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status,
 			      unsigned int qdio_error, unsigned int siga_error,
 			      int first_element, int elements_processed)
@@ -462,7 +462,7 @@
  * zfcp_qdio_sbale_req - return pointer to SBALE of request_queue for
  *	a struct zfcp_fsf_req
  */
-inline volatile struct qdio_buffer_element *
+volatile struct qdio_buffer_element *
 zfcp_qdio_sbale_req(struct zfcp_fsf_req *fsf_req, int sbal, int sbale)
 {
 	return zfcp_qdio_sbale_get(&fsf_req->adapter->request_queue,
@@ -484,7 +484,7 @@
  * zfcp_qdio_sbale_curr - return current SBALE on request_queue for
  *	a struct zfcp_fsf_req
  */
-inline volatile struct qdio_buffer_element *
+volatile struct qdio_buffer_element *
 zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req)
 {
 	return zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr,
@@ -499,7 +499,7 @@
  *
  * Note: We can assume at least one free SBAL in the request_queue when called.
  */
-static inline void
+static void
 zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals)
 {
 	int count = atomic_read(&fsf_req->adapter->request_queue.free_count);
@@ -517,7 +517,7 @@
  *
  * This function changes sbal_curr, sbale_curr, sbal_number of fsf_req.
  */
-static inline volatile struct qdio_buffer_element *
+static volatile struct qdio_buffer_element *
 zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
 {
 	volatile struct qdio_buffer_element *sbale;
@@ -554,7 +554,7 @@
 /**
  * zfcp_qdio_sbale_next - switch to next SBALE, chain SBALs if needed
  */
-static inline volatile struct qdio_buffer_element *
+static volatile struct qdio_buffer_element *
 zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
 {
 	if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL)
@@ -569,7 +569,7 @@
  * zfcp_qdio_sbals_zero - initialize SBALs between first and last in queue
  *	with zero from
  */
-static inline int
+static int
 zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *queue, int first, int last)
 {
 	struct qdio_buffer **buf = queue->buffer;
@@ -603,7 +603,7 @@
  * zfcp_qdio_sbale_fill - set address and lenght in current SBALE
  *	on request_queue
  */
-static inline void
+static void
 zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
 		     void *addr, int length)
 {
@@ -624,7 +624,7 @@
  * Alignment and length of the segment determine how many SBALEs are needed
  * for the memory segment.
  */
-static inline int
+static int
 zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
 			     void *start_addr, unsigned long total_length)
 {
@@ -659,7 +659,7 @@
  * @sg_count: number of elements in scatter-gather list
  * @max_sbals: upper bound for number of SBALs to be used
  */
-inline int
+int
 zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
                         struct scatterlist *sg,	int sg_count, int max_sbals)
 {
@@ -707,7 +707,7 @@
  * @length: length of buffer
  * @max_sbals: upper bound for number of SBALs to be used
  */
-static inline int
+static int
 zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
 			    void *buffer, unsigned long length, int max_sbals)
 {
@@ -728,7 +728,7 @@
  * @scsi_cmnd: either scatter-gather list or buffer contained herein is used
  *	to fill SBALs
  */
-inline int
+int
 zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req,
 			      unsigned long sbtype, struct scsi_cmnd *scsi_cmnd)
 {
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 452d96f..99db020 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -90,7 +90,7 @@
 	return fcp_sns_info_ptr;
 }
 
-fcp_dl_t *
+static fcp_dl_t *
 zfcp_get_fcp_dl_ptr(struct fcp_cmnd_iu * fcp_cmd)
 {
 	int additional_length = fcp_cmd->add_fcp_cdb_length << 2;
@@ -124,19 +124,19 @@
  * regarding the specified byte
  */
 static inline void
-set_byte(u32 * result, char status, char pos)
+set_byte(int *result, char status, char pos)
 {
 	*result |= status << (pos * 8);
 }
 
 void
-set_host_byte(u32 * result, char status)
+set_host_byte(int *result, char status)
 {
 	set_byte(result, status, 2);
 }
 
 void
-set_driver_byte(u32 * result, char status)
+set_driver_byte(int *result, char status)
 {
 	set_byte(result, status, 3);
 }
@@ -280,7 +280,7 @@
 	return retval;
 }
 
-void
+static void
 zfcp_scsi_command_sync_handler(struct scsi_cmnd *scpnt)
 {
 	struct completion *wait = (struct completion *) scpnt->SCp.ptr;
@@ -324,7 +324,7 @@
  * returns:	0 - success, SCSI command enqueued
  *		!0 - failure
  */
-int
+static int
 zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
 		       void (*done) (struct scsi_cmnd *))
 {
@@ -380,7 +380,7 @@
  * will handle late commands.  (Usually, the normal completion of late
  * commands is ignored with respect to the running abort operation.)
  */
-int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
+static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
 {
  	struct Scsi_Host *scsi_host;
  	struct zfcp_adapter *adapter;
@@ -445,7 +445,7 @@
 	return retval;
 }
 
-int
+static int
 zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
 {
 	int retval;
@@ -541,7 +541,7 @@
 /**
  * zfcp_scsi_eh_host_reset_handler - handler for host and bus reset
  */
-int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
+static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
 {
 	struct zfcp_unit *unit;
 	struct zfcp_adapter *adapter;
diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c
index 1e788e8..090743d 100644
--- a/drivers/s390/sysinfo.c
+++ b/drivers/s390/sysinfo.c
@@ -9,8 +9,14 @@
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 #include <asm/ebcdic.h>
 
+/* Sigh, math-emu. Don't ask. */
+#include <asm/sfp-util.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/single.h>
+
 struct sysinfo_1_1_1 {
 	char reserved_0[32];
 	char manufacturer[16];
@@ -198,7 +204,7 @@
 		 * if the higher order 8 bits are not zero. Printing
 		 * a floating point number in the kernel is a no-no,
 		 * always print the number as 32 bit unsigned integer.
-		 * The user-space needs to know about the stange
+		 * The user-space needs to know about the strange
 		 * encoding of the alternate cpu capability.
 		 */
 		len += sprintf(page + len, "Capability:           %u %u\n",
@@ -351,3 +357,58 @@
 
 __initcall(create_proc_sysinfo);
 
+/*
+ * CPU capability might have changed. Therefore recalculate loops_per_jiffy.
+ */
+void s390_adjust_jiffies(void)
+{
+	struct sysinfo_1_2_2 *info;
+	const unsigned int fmil = 0x4b189680;	/* 1e7 as 32-bit float. */
+	FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+	FP_DECL_EX;
+	unsigned int capability;
+
+	info = (void *) get_zeroed_page(GFP_KERNEL);
+	if (!info)
+		return;
+
+	if (stsi(info, 1, 2, 2) != -ENOSYS) {
+		/*
+		 * Major sigh. The cpu capability encoding is "special".
+		 * If the first 9 bits of info->capability are 0 then it
+		 * is a 32 bit unsigned integer in the range 0 .. 2^23.
+		 * If the first 9 bits are != 0 then it is a 32 bit float.
+		 * In addition a lower value indicates a proportionally
+		 * higher cpu capacity. Bogomips are the other way round.
+		 * To get to a halfway suitable number we divide 1e7
+		 * by the cpu capability number. Yes, that means a floating
+		 * point division .. math-emu here we come :-)
+		 */
+		FP_UNPACK_SP(SA, &fmil);
+		if ((info->capability >> 23) == 0)
+			FP_FROM_INT_S(SB, info->capability, 32, int);
+		else
+			FP_UNPACK_SP(SB, &info->capability);
+		FP_DIV_S(SR, SA, SB);
+		FP_TO_INT_S(capability, SR, 32, 0);
+	} else
+		/*
+		 * Really old machine without stsi block for basic
+		 * cpu information. Report 42.0 bogomips.
+		 */
+		capability = 42;
+	loops_per_jiffy = capability * (500000/HZ);
+	free_page((unsigned long) info);
+}
+
+/*
+ * calibrate the delay loop
+ */
+void __init calibrate_delay(void)
+{
+	s390_adjust_jiffies();
+	/* Print the good old Bogomips line .. */
+	printk(KERN_DEBUG "Calibrating delay loop (skipped)... "
+	       "%lu.%02lu BogoMIPS preset\n", loops_per_jiffy/(500000/HZ),
+	       (loops_per_jiffy/(5000/HZ)) % 100);
+}
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index 3c912ee..8b5334c 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -528,12 +528,16 @@
 /* Allocate structure and insert basic data such as SCSI chip frequency
  * data and a pointer to the device
  */
-struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev)
+struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev,
+			     int hotplug)
 {
 	struct NCR_ESP *esp, *elink;
 	struct Scsi_Host *esp_host;
 
-	esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP));
+	if (hotplug)
+		esp_host = scsi_host_alloc(tpnt, sizeof(struct NCR_ESP));
+	else
+		esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP));
 	if(!esp_host)
 		panic("Cannot register ESP SCSI host");
 	esp = (struct NCR_ESP *) esp_host->hostdata;
diff --git a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h
index 521e3f8..d85cb73 100644
--- a/drivers/scsi/NCR53C9x.h
+++ b/drivers/scsi/NCR53C9x.h
@@ -652,7 +652,7 @@
 
 /* External functions */
 extern void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs);
-extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *);
+extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *, int);
 extern void esp_deallocate(struct NCR_ESP *);
 extern void esp_release(void);
 extern void esp_initialize(struct NCR_ESP *);
diff --git a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c
index 329a8f2..23f7c24 100644
--- a/drivers/scsi/blz1230.c
+++ b/drivers/scsi/blz1230.c
@@ -121,7 +121,8 @@
 		 */
 		address = ZTWO_VADDR(board);
 		eregs = (struct ESP_regs *)(address + REAL_BLZ1230_ESP_ADDR);
-		esp = esp_allocate(tpnt, (void *)board+REAL_BLZ1230_ESP_ADDR);
+		esp = esp_allocate(tpnt, (void *)board + REAL_BLZ1230_ESP_ADDR,
+				   0);
 
 		esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
 		udelay(5);
diff --git a/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c
index b6c137b..b6203ec 100644
--- a/drivers/scsi/blz2060.c
+++ b/drivers/scsi/blz2060.c
@@ -100,7 +100,7 @@
 	    unsigned long board = z->resource.start;
 	    if (request_mem_region(board+BLZ2060_ESP_ADDR,
 				   sizeof(struct ESP_regs), "NCR53C9x")) {
-		esp = esp_allocate(tpnt, (void *)board+BLZ2060_ESP_ADDR);
+		esp = esp_allocate(tpnt, (void *)board + BLZ2060_ESP_ADDR, 0);
 
 		/* Do command transfer with programmed I/O */
 		esp->do_pio_cmds = 1;
diff --git a/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c
index 7c7cfb5..c6b98a4 100644
--- a/drivers/scsi/cyberstorm.c
+++ b/drivers/scsi/cyberstorm.c
@@ -126,7 +126,7 @@
 					   sizeof(struct ESP_regs));
 			return 0;
 		}
-		esp = esp_allocate(tpnt, (void *)board+CYBER_ESP_ADDR);
+		esp = esp_allocate(tpnt, (void *)board + CYBER_ESP_ADDR, 0);
 
 		/* Do command transfer with programmed I/O */
 		esp->do_pio_cmds = 1;
diff --git a/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c
index d88cb9c..e336e85 100644
--- a/drivers/scsi/cyberstormII.c
+++ b/drivers/scsi/cyberstormII.c
@@ -98,7 +98,7 @@
 		address = (unsigned long)ZTWO_VADDR(board);
 		eregs = (struct ESP_regs *)(address + CYBERII_ESP_ADDR);
 
-		esp = esp_allocate(tpnt, (void *)board+CYBERII_ESP_ADDR);
+		esp = esp_allocate(tpnt, (void *)board + CYBERII_ESP_ADDR, 0);
 
 		esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
 		udelay(5);
diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c
index c29ccbc..d42ad66 100644
--- a/drivers/scsi/dec_esp.c
+++ b/drivers/scsi/dec_esp.c
@@ -18,7 +18,7 @@
  * 20001005	- Initialization fixes for 2.4.0-test9
  * 			  Florian Lohoff <flo@rfc822.org>
  *
- *	Copyright (C) 2002, 2003, 2005  Maciej W. Rozycki
+ *	Copyright (C) 2002, 2003, 2005, 2006  Maciej W. Rozycki
  */
 
 #include <linux/kernel.h>
@@ -30,6 +30,7 @@
 #include <linux/proc_fs.h>
 #include <linux/spinlock.h>
 #include <linux/stat.h>
+#include <linux/tc.h>
 
 #include <asm/dma.h>
 #include <asm/irq.h>
@@ -42,7 +43,6 @@
 #include <asm/dec/ioasic_ints.h>
 #include <asm/dec/machtype.h>
 #include <asm/dec/system.h>
-#include <asm/dec/tc.h>
 
 #define DEC_SCSI_SREG 0
 #define DEC_SCSI_DMAREG 0x40000
@@ -98,51 +98,33 @@
 static irqreturn_t scsi_dma_err_int(int, void *);
 static irqreturn_t scsi_dma_int(int, void *);
 
-static int dec_esp_detect(struct scsi_host_template * tpnt);
-
-static int dec_esp_release(struct Scsi_Host *shost)
-{
-	if (shost->irq)
-		free_irq(shost->irq, NULL);
-	if (shost->io_port && shost->n_io_port)
-		release_region(shost->io_port, shost->n_io_port);
-	scsi_unregister(shost);
-	return 0;
-}
-
-static struct scsi_host_template driver_template = {
-	.proc_name		= "dec_esp",
-	.proc_info		= esp_proc_info,
+static struct scsi_host_template dec_esp_template = {
+	.module			= THIS_MODULE,
 	.name			= "NCR53C94",
-	.detect			= dec_esp_detect,
-	.slave_alloc		= esp_slave_alloc,
-	.slave_destroy		= esp_slave_destroy,
-	.release		= dec_esp_release,
 	.info			= esp_info,
 	.queuecommand		= esp_queue,
 	.eh_abort_handler	= esp_abort,
 	.eh_bus_reset_handler	= esp_reset,
+	.slave_alloc		= esp_slave_alloc,
+	.slave_destroy		= esp_slave_destroy,
+	.proc_info		= esp_proc_info,
+	.proc_name		= "dec_esp",
 	.can_queue		= 7,
-	.this_id		= 7,
 	.sg_tablesize		= SG_ALL,
 	.cmd_per_lun		= 1,
 	.use_clustering		= DISABLE_CLUSTERING,
 };
 
-
-#include "scsi_module.c"
+static struct NCR_ESP *dec_esp_platform;
 
 /***************************************************************** Detection */
-static int dec_esp_detect(struct scsi_host_template * tpnt)
+static int dec_esp_platform_probe(void)
 {
 	struct NCR_ESP *esp;
-	struct ConfigDev *esp_dev;
-	int slot;
-	unsigned long mem_start;
+	int err = 0;
 
 	if (IOASIC) {
-		esp_dev = 0;
-		esp = esp_allocate(tpnt, (void *) esp_dev);
+		esp = esp_allocate(&dec_esp_template, NULL, 1);
 
 		/* Do command transfer with programmed I/O */
 		esp->do_pio_cmds = 1;
@@ -200,112 +182,175 @@
 		/* Check for differential SCSI-bus */
 		esp->diff = 0;
 
+		err = request_irq(esp->irq, esp_intr, IRQF_DISABLED,
+				  "ncr53c94", esp->ehost);
+		if (err)
+			goto err_alloc;
+		err = request_irq(dec_interrupt[DEC_IRQ_ASC_MERR],
+				  scsi_dma_merr_int, IRQF_DISABLED,
+				  "ncr53c94 error", esp->ehost);
+		if (err)
+			goto err_irq;
+		err = request_irq(dec_interrupt[DEC_IRQ_ASC_ERR],
+				  scsi_dma_err_int, IRQF_DISABLED,
+				  "ncr53c94 overrun", esp->ehost);
+		if (err)
+			goto err_irq_merr;
+		err = request_irq(dec_interrupt[DEC_IRQ_ASC_DMA], scsi_dma_int,
+				  IRQF_DISABLED, "ncr53c94 dma", esp->ehost);
+		if (err)
+			goto err_irq_err;
+
 		esp_initialize(esp);
 
-		if (request_irq(esp->irq, esp_intr, IRQF_DISABLED,
-				"ncr53c94", esp->ehost))
-			goto err_dealloc;
-		if (request_irq(dec_interrupt[DEC_IRQ_ASC_MERR],
-				scsi_dma_merr_int, IRQF_DISABLED,
-				"ncr53c94 error", esp->ehost))
-			goto err_free_irq;
-		if (request_irq(dec_interrupt[DEC_IRQ_ASC_ERR],
-				scsi_dma_err_int, IRQF_DISABLED,
-				"ncr53c94 overrun", esp->ehost))
-			goto err_free_irq_merr;
-		if (request_irq(dec_interrupt[DEC_IRQ_ASC_DMA],
-				scsi_dma_int, IRQF_DISABLED,
-				"ncr53c94 dma", esp->ehost))
-			goto err_free_irq_err;
-
-	}
-
-	if (TURBOCHANNEL) {
-		while ((slot = search_tc_card("PMAZ-AA")) >= 0) {
-			claim_tc_card(slot);
-
-			esp_dev = 0;
-			esp = esp_allocate(tpnt, (void *) esp_dev);
-
-			mem_start = get_tc_base_addr(slot);
-
-			/* Store base addr into esp struct */
-			esp->slot = CPHYSADDR(mem_start);
-
-			esp->dregs = 0;
-			esp->eregs = (void *)CKSEG1ADDR(mem_start +
-							DEC_SCSI_SREG);
-			esp->do_pio_cmds = 1;
-
-			/* Set the command buffer */
-			esp->esp_command = (volatile unsigned char *) pmaz_cmd_buffer;
-
-			/* get virtual dma address for command buffer */
-			esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer);
-
-			esp->cfreq = get_tc_speed();
-
-			esp->irq = get_tc_irq_nr(slot);
-
-			/* Required functions */
-			esp->dma_bytes_sent = &dma_bytes_sent;
-			esp->dma_can_transfer = &dma_can_transfer;
-			esp->dma_dump_state = &dma_dump_state;
-			esp->dma_init_read = &pmaz_dma_init_read;
-			esp->dma_init_write = &pmaz_dma_init_write;
-			esp->dma_ints_off = &pmaz_dma_ints_off;
-			esp->dma_ints_on = &pmaz_dma_ints_on;
-			esp->dma_irq_p = &dma_irq_p;
-			esp->dma_ports_p = &dma_ports_p;
-			esp->dma_setup = &pmaz_dma_setup;
-
-			/* Optional functions */
-			esp->dma_barrier = 0;
-			esp->dma_drain = &pmaz_dma_drain;
-			esp->dma_invalidate = 0;
-			esp->dma_irq_entry = 0;
-			esp->dma_irq_exit = 0;
-			esp->dma_poll = 0;
-			esp->dma_reset = 0;
-			esp->dma_led_off = 0;
-			esp->dma_led_on = 0;
-
-			esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one;
-			esp->dma_mmu_get_scsi_sgl = 0;
-			esp->dma_mmu_release_scsi_one = 0;
-			esp->dma_mmu_release_scsi_sgl = 0;
-			esp->dma_advance_sg = 0;
-
- 			if (request_irq(esp->irq, esp_intr, IRQF_DISABLED,
- 					 "PMAZ_AA", esp->ehost)) {
- 				esp_deallocate(esp);
- 				release_tc_card(slot);
- 				continue;
- 			}
-			esp->scsi_id = 7;
-			esp->diff = 0;
-			esp_initialize(esp);
+		err = scsi_add_host(esp->ehost, NULL);
+		if (err) {
+			printk(KERN_ERR "ESP: Unable to register adapter\n");
+			goto err_irq_dma;
 		}
+
+		scsi_scan_host(esp->ehost);
+
+		dec_esp_platform = esp;
 	}
 
-	if(nesps) {
-		printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
-		esps_running = esps_in_use;
-		return esps_in_use;
-	}
 	return 0;
 
-err_free_irq_err:
-	free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], scsi_dma_err_int);
-err_free_irq_merr:
-	free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], scsi_dma_merr_int);
-err_free_irq:
-	free_irq(esp->irq, esp_intr);
-err_dealloc:
+err_irq_dma:
+	free_irq(dec_interrupt[DEC_IRQ_ASC_DMA], esp->ehost);
+err_irq_err:
+	free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], esp->ehost);
+err_irq_merr:
+	free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], esp->ehost);
+err_irq:
+	free_irq(esp->irq, esp->ehost);
+err_alloc:
 	esp_deallocate(esp);
-	return 0;
+	scsi_host_put(esp->ehost);
+	return err;
 }
 
+static int __init dec_esp_probe(struct device *dev)
+{
+	struct NCR_ESP *esp;
+	resource_size_t start, len;
+	int err;
+
+	esp = esp_allocate(&dec_esp_template,  NULL, 1);
+
+	dev_set_drvdata(dev, esp);
+
+	start = to_tc_dev(dev)->resource.start;
+	len = to_tc_dev(dev)->resource.end - start + 1;
+
+	if (!request_mem_region(start, len, dev->bus_id)) {
+		printk(KERN_ERR "%s: Unable to reserve MMIO resource\n",
+		       dev->bus_id);
+		err = -EBUSY;
+		goto err_alloc;
+	}
+
+	/* Store base addr into esp struct.  */
+	esp->slot = start;
+
+	esp->dregs = 0;
+	esp->eregs = (void *)CKSEG1ADDR(start + DEC_SCSI_SREG);
+	esp->do_pio_cmds = 1;
+
+	/* Set the command buffer.  */
+	esp->esp_command = (volatile unsigned char *)pmaz_cmd_buffer;
+
+	/* Get virtual dma address for command buffer.  */
+	esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer);
+
+	esp->cfreq = tc_get_speed(to_tc_dev(dev)->bus);
+
+	esp->irq = to_tc_dev(dev)->interrupt;
+
+	/* Required functions.  */
+	esp->dma_bytes_sent = &dma_bytes_sent;
+	esp->dma_can_transfer = &dma_can_transfer;
+	esp->dma_dump_state = &dma_dump_state;
+	esp->dma_init_read = &pmaz_dma_init_read;
+	esp->dma_init_write = &pmaz_dma_init_write;
+	esp->dma_ints_off = &pmaz_dma_ints_off;
+	esp->dma_ints_on = &pmaz_dma_ints_on;
+	esp->dma_irq_p = &dma_irq_p;
+	esp->dma_ports_p = &dma_ports_p;
+	esp->dma_setup = &pmaz_dma_setup;
+
+	/* Optional functions.  */
+	esp->dma_barrier = 0;
+	esp->dma_drain = &pmaz_dma_drain;
+	esp->dma_invalidate = 0;
+	esp->dma_irq_entry = 0;
+	esp->dma_irq_exit = 0;
+	esp->dma_poll = 0;
+	esp->dma_reset = 0;
+	esp->dma_led_off = 0;
+	esp->dma_led_on = 0;
+
+	esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one;
+	esp->dma_mmu_get_scsi_sgl = 0;
+	esp->dma_mmu_release_scsi_one = 0;
+	esp->dma_mmu_release_scsi_sgl = 0;
+	esp->dma_advance_sg = 0;
+
+	err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, "PMAZ_AA",
+			  esp->ehost);
+	if (err) {
+		printk(KERN_ERR "%s: Unable to get IRQ %d\n",
+		       dev->bus_id, esp->irq);
+		goto err_resource;
+	}
+
+	esp->scsi_id = 7;
+	esp->diff = 0;
+	esp_initialize(esp);
+
+	err = scsi_add_host(esp->ehost, dev);
+	if (err) {
+		printk(KERN_ERR "%s: Unable to register adapter\n",
+		       dev->bus_id);
+		goto err_irq;
+	}
+
+	scsi_scan_host(esp->ehost);
+
+	return 0;
+
+err_irq:
+	free_irq(esp->irq, esp->ehost);
+
+err_resource:
+	release_mem_region(start, len);
+
+err_alloc:
+	esp_deallocate(esp);
+	scsi_host_put(esp->ehost);
+	return err;
+}
+
+static void __exit dec_esp_platform_remove(void)
+{
+	struct NCR_ESP *esp = dec_esp_platform;
+
+	free_irq(esp->irq, esp->ehost);
+	esp_deallocate(esp);
+	scsi_host_put(esp->ehost);
+	dec_esp_platform = NULL;
+}
+
+static void __exit dec_esp_remove(struct device *dev)
+{
+	struct NCR_ESP *esp = dev_get_drvdata(dev);
+
+	free_irq(esp->irq, esp->ehost);
+	esp_deallocate(esp);
+	scsi_host_put(esp->ehost);
+}
+
+
 /************************************************************* DMA Functions */
 static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id)
 {
@@ -576,3 +621,67 @@
 {
 	sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer);
 }
+
+
+#ifdef CONFIG_TC
+static int __init dec_esp_tc_probe(struct device *dev);
+static int __exit dec_esp_tc_remove(struct device *dev);
+
+static const struct tc_device_id dec_esp_tc_table[] = {
+        { "DEC     ", "PMAZ-AA " },
+        { }
+};
+MODULE_DEVICE_TABLE(tc, dec_esp_tc_table);
+
+static struct tc_driver dec_esp_tc_driver = {
+        .id_table       = dec_esp_tc_table,
+        .driver         = {
+                .name   = "dec_esp",
+                .bus    = &tc_bus_type,
+                .probe  = dec_esp_tc_probe,
+                .remove = __exit_p(dec_esp_tc_remove),
+        },
+};
+
+static int __init dec_esp_tc_probe(struct device *dev)
+{
+	int status = dec_esp_probe(dev);
+	if (!status)
+		get_device(dev);
+	return status;
+}
+
+static int __exit dec_esp_tc_remove(struct device *dev)
+{
+	put_device(dev);
+	dec_esp_remove(dev);
+	return 0;
+}
+#endif
+
+static int __init dec_esp_init(void)
+{
+	int status;
+
+	status = tc_register_driver(&dec_esp_tc_driver);
+	if (!status)
+		dec_esp_platform_probe();
+
+	if (nesps) {
+		pr_info("ESP: Total of %d ESP hosts found, "
+			"%d actually in use.\n", nesps, esps_in_use);
+		esps_running = esps_in_use;
+	}
+
+	return status;
+}
+
+static void __exit dec_esp_exit(void)
+{
+	dec_esp_platform_remove();
+	tc_unregister_driver(&dec_esp_tc_driver);
+}
+
+
+module_init(dec_esp_init);
+module_exit(dec_esp_exit);
diff --git a/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c
index 2a1c5c2..4266a21 100644
--- a/drivers/scsi/fastlane.c
+++ b/drivers/scsi/fastlane.c
@@ -142,7 +142,7 @@
 		if (board < 0x1000000) {
 			goto err_release;
 		}
-		esp = esp_allocate(tpnt, (void *)board+FASTLANE_ESP_ADDR);
+		esp = esp_allocate(tpnt, (void *)board + FASTLANE_ESP_ADDR, 0);
 
 		/* Do command transfer with programmed I/O */
 		esp->do_pio_cmds = 1;
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index b318500..821386c 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -7558,9 +7558,6 @@
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
 	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C,
 	      0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
-	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
-	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B8,
-	      0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
 	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7,
 	      0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 4376840..8f55e14 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -1375,7 +1375,7 @@
 	}
 
 	BUG_ON(tcp_mtask->xmstate != XMSTATE_IDLE);
-	if (mtask->hdr->itt == cpu_to_be32(ISCSI_RESERVED_TAG)) {
+	if (mtask->hdr->itt == RESERVED_ITT) {
 		struct iscsi_session *session = conn->session;
 
 		spin_lock_bh(&session->lock);
diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c
index bfac444..19dd4b9 100644
--- a/drivers/scsi/jazz_esp.c
+++ b/drivers/scsi/jazz_esp.c
@@ -75,7 +75,7 @@
      */
     if (1) {
 	esp_dev = NULL;
-	esp = esp_allocate(tpnt, (void *) esp_dev);
+	esp = esp_allocate(tpnt, esp_dev, 0);
 	
 	/* Do command transfer with programmed I/O */
 	esp->do_pio_cmds = 1;
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index d37048c..7c75771 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -113,8 +113,7 @@
         hdr->opcode = ISCSI_OP_SCSI_CMD;
         hdr->flags = ISCSI_ATTR_SIMPLE;
         int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
-        hdr->itt = ctask->itt | (conn->id << ISCSI_CID_SHIFT) |
-                         (session->age << ISCSI_AGE_SHIFT);
+        hdr->itt = build_itt(ctask->itt, conn->id, session->age);
         hdr->data_length = cpu_to_be32(sc->request_bufflen);
         hdr->cmdsn = cpu_to_be32(session->cmdsn);
         session->cmdsn++;
@@ -270,7 +269,7 @@
 			goto out;
 		}
 
-		senselen = be16_to_cpu(*(uint16_t *)data);
+		senselen = be16_to_cpu(*(__be16 *)data);
 		if (datalen < senselen)
 			goto invalid_datalen;
 
@@ -338,7 +337,7 @@
 
 		if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) {
 			memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
-			itt = rejected_pdu.itt & ISCSI_ITT_MASK;
+			itt = get_itt(rejected_pdu.itt);
 			printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected "
 				"due to DataDigest error.\n", itt,
 				rejected_pdu.opcode);
@@ -367,10 +366,10 @@
 	struct iscsi_mgmt_task *mtask;
 	uint32_t itt;
 
-	if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG))
-		itt = hdr->itt & ISCSI_ITT_MASK;
+	if (hdr->itt != RESERVED_ITT)
+		itt = get_itt(hdr->itt);
 	else
-		itt = hdr->itt;
+		itt = ~0U;
 
 	if (itt < session->cmds_max) {
 		ctask = session->cmds[itt];
@@ -440,7 +439,7 @@
 			iscsi_tmf_rsp(conn, hdr);
 			break;
 		case ISCSI_OP_NOOP_IN:
-			if (hdr->ttt != ISCSI_RESERVED_TAG || datalen) {
+			if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
 				rc = ISCSI_ERR_PROTO;
 				break;
 			}
@@ -457,7 +456,7 @@
 			rc = ISCSI_ERR_BAD_OPCODE;
 			break;
 		}
-	} else if (itt == ISCSI_RESERVED_TAG) {
+	} else if (itt == ~0U) {
 		rc = iscsi_check_assign_cmdsn(session,
 					     (struct iscsi_nopin*)hdr);
 		if (rc)
@@ -470,7 +469,7 @@
 				break;
 			}
 
-			if (hdr->ttt == ISCSI_RESERVED_TAG)
+			if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
 				break;
 
 			if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0))
@@ -516,24 +515,24 @@
 	struct iscsi_cmd_task *ctask;
 	uint32_t itt;
 
-	if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) {
-		if ((hdr->itt & ISCSI_AGE_MASK) !=
+	if (hdr->itt != RESERVED_ITT) {
+		if (((__force u32)hdr->itt & ISCSI_AGE_MASK) !=
 		    (session->age << ISCSI_AGE_SHIFT)) {
 			printk(KERN_ERR "iscsi: received itt %x expected "
-				"session age (%x)\n", hdr->itt,
+				"session age (%x)\n", (__force u32)hdr->itt,
 				session->age & ISCSI_AGE_MASK);
 			return ISCSI_ERR_BAD_ITT;
 		}
 
-		if ((hdr->itt & ISCSI_CID_MASK) !=
+		if (((__force u32)hdr->itt & ISCSI_CID_MASK) !=
 		    (conn->id << ISCSI_CID_SHIFT)) {
 			printk(KERN_ERR "iscsi: received itt %x, expected "
-				"CID (%x)\n", hdr->itt, conn->id);
+				"CID (%x)\n", (__force u32)hdr->itt, conn->id);
 			return ISCSI_ERR_BAD_ITT;
 		}
-		itt = hdr->itt & ISCSI_ITT_MASK;
+		itt = get_itt(hdr->itt);
 	} else
-		itt = hdr->itt;
+		itt = ~0U;
 
 	if (itt < session->cmds_max) {
 		ctask = session->cmds[itt];
@@ -896,9 +895,8 @@
 	/*
 	 * pre-format CmdSN for outgoing PDU.
 	 */
-	if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) {
-		hdr->itt = mtask->itt | (conn->id << ISCSI_CID_SHIFT) |
-			   (session->age << ISCSI_AGE_SHIFT);
+	if (hdr->itt != RESERVED_ITT) {
+		hdr->itt = build_itt(mtask->itt, conn->id, session->age);
 		nop->cmdsn = cpu_to_be32(session->cmdsn);
 		if (conn->c_stage == ISCSI_CONN_STARTED &&
 		    !(hdr->opcode & ISCSI_OP_IMMEDIATE))
@@ -1064,7 +1062,7 @@
 
 	spin_lock_bh(&session->lock);
 	ctask->mtask = (struct iscsi_mgmt_task *)
-			session->mgmt_cmds[(hdr->itt & ISCSI_ITT_MASK) -
+			session->mgmt_cmds[get_itt(hdr->itt) -
 					ISCSI_MGMT_ITT_OFFSET];
 
 	if (conn->tmabort_state == TMABORT_INITIAL) {
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index 3586fac..bcb4902 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -351,7 +351,7 @@
 	for (chipnum = 0; chipnum < chipspresent; chipnum ++) {
 		struct NCR_ESP * esp;
 
-		esp = esp_allocate(tpnt, (void *) NULL);
+		esp = esp_allocate(tpnt, NULL, 0);
 		esp->eregs = (struct ESP_regs *) get_base(chipnum);
 
 		esp->dma_irq_p = &esp_dafb_dma_irq_p;
diff --git a/drivers/scsi/mca_53c9x.c b/drivers/scsi/mca_53c9x.c
index 998a8bb..d693d0f 100644
--- a/drivers/scsi/mca_53c9x.c
+++ b/drivers/scsi/mca_53c9x.c
@@ -122,7 +122,7 @@
 		if ((slot = mca_find_adapter(*id_to_check, 0)) !=
 		  MCA_NOTFOUND) 
 		{
-			esp = esp_allocate(tpnt, (void *) NULL);
+			esp = esp_allocate(tpnt, NULL, 0);
 
 			pos[0] = mca_read_stored_pos(slot, 2);
 			pos[1] = mca_read_stored_pos(slot, 3);
diff --git a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c
index c116a6a..26a6d55 100644
--- a/drivers/scsi/oktagon_esp.c
+++ b/drivers/scsi/oktagon_esp.c
@@ -133,7 +133,7 @@
 		eregs = (struct ESP_regs *)(address + OKTAGON_ESP_ADDR);
 
 		/* This line was 5 lines lower */
-		esp = esp_allocate(tpnt, (void *)board+OKTAGON_ESP_ADDR);
+		esp = esp_allocate(tpnt, (void *)board + OKTAGON_ESP_ADDR, 0);
 
 		/* we have to shift the registers only one bit for oktagon */
 		esp->shift = 1;
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index 7d23110..bd6bbf6 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -521,10 +521,10 @@
 		break;
 	  default: ; /* probably FILL */
 	}
-	aux->filemark_cnt = ntohl(STp->filemark_cnt);
-	aux->phys_fm = ntohl(0xffffffff);
-	aux->last_mark_ppos = ntohl(STp->last_mark_ppos);
-	aux->last_mark_lbn  = ntohl(STp->last_mark_lbn);
+	aux->filemark_cnt = htonl(STp->filemark_cnt);
+	aux->phys_fm = htonl(0xffffffff);
+	aux->last_mark_ppos = htonl(STp->last_mark_ppos);
+	aux->last_mark_lbn  = htonl(STp->last_mark_lbn);
 }
 
 /*
diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h
index 1e426f5..2cc7b5a 100644
--- a/drivers/scsi/osst.h
+++ b/drivers/scsi/osst.h
@@ -288,11 +288,11 @@
 #else
 #error "Please fix <asm/byteorder.h>"
 #endif
-        u16             max_speed;              /* Maximum speed supported in KBps */
+        __be16          max_speed;              /* Maximum speed supported in KBps */
         u8              reserved10, reserved11;
-        u16             ctl;                    /* Continuous Transfer Limit in blocks */
-        u16             speed;                  /* Current Speed, in KBps */
-        u16             buffer_size;            /* Buffer Size, in 512 bytes */
+        __be16          ctl;                    /* Continuous Transfer Limit in blocks */
+        __be16          speed;                  /* Current Speed, in KBps */
+        __be16          buffer_size;            /* Buffer Size, in 512 bytes */
         u8              reserved18, reserved19;
 } osst_capabilities_page_t;
 
@@ -352,8 +352,8 @@
 	u8		reserved2;
 	u8		density;
 	u8		reserved3,reserved4;
-	u16		segtrk;
-	u16		trks;
+	__be16		segtrk;
+	__be16		trks;
 	u8		reserved5,reserved6,reserved7,reserved8,reserved9,reserved10;
 } osst_tape_paramtr_page_t;
 
@@ -369,18 +369,18 @@
 typedef struct os_partition_s {
         __u8    partition_num;
         __u8    par_desc_ver;
-        __u16   wrt_pass_cntr;
-        __u32   first_frame_ppos;
-        __u32   last_frame_ppos;
-        __u32   eod_frame_ppos;
+        __be16  wrt_pass_cntr;
+        __be32  first_frame_ppos;
+        __be32  last_frame_ppos;
+        __be32  eod_frame_ppos;
 } os_partition_t;
 
 /*
  * DAT entry
  */
 typedef struct os_dat_entry_s {
-        __u32   blk_sz;
-        __u16   blk_cnt;
+        __be32  blk_sz;
+        __be16  blk_cnt;
         __u8    flags;
         __u8    reserved;
 } os_dat_entry_t;
@@ -412,23 +412,23 @@
  * AUX
  */
 typedef struct os_aux_s {
-        __u32           format_id;              /* hardware compability AUX is based on */
+        __be32          format_id;              /* hardware compability AUX is based on */
         char            application_sig[4];     /* driver used to write this media */
-        __u32           hdwr;                   /* reserved */
-        __u32           update_frame_cntr;      /* for configuration frame */
+        __be32          hdwr;                   /* reserved */
+        __be32          update_frame_cntr;      /* for configuration frame */
         __u8            frame_type;
         __u8            frame_type_reserved;
         __u8            reserved_18_19[2];
         os_partition_t  partition;
         __u8            reserved_36_43[8];
-        __u32           frame_seq_num;
-        __u32           logical_blk_num_high;
-        __u32           logical_blk_num;
+        __be32          frame_seq_num;
+        __be32          logical_blk_num_high;
+        __be32          logical_blk_num;
         os_dat_t        dat;
         __u8            reserved188_191[4];
-        __u32           filemark_cnt;
-        __u32           phys_fm;
-        __u32           last_mark_ppos;
+        __be32          filemark_cnt;
+        __be32          phys_fm;
+        __be32          last_mark_ppos;
         __u8            reserved204_223[20];
 
         /*
@@ -436,8 +436,8 @@
          *
          * Linux specific fields:
          */
-         __u32          next_mark_ppos;         /* when known, points to next marker */
-	 __u32		last_mark_lbn;		/* storing log_blk_num of last mark is extends ADR spec */
+         __be32         next_mark_ppos;         /* when known, points to next marker */
+	 __be32		last_mark_lbn;		/* storing log_blk_num of last mark is extends ADR spec */
          __u8           linux_specific[24];
 
         __u8            reserved_256_511[256];
@@ -450,19 +450,19 @@
 	__u8		reserved_1;
 	__u8		fm_tab_ent_sz;
 	__u8		reserved_3;
-	__u16		fm_tab_ent_cnt;
+	__be16		fm_tab_ent_cnt;
 	__u8		reserved6_15[10];
-	__u32		fm_tab_ent[OS_FM_TAB_MAX];
+	__be32		fm_tab_ent[OS_FM_TAB_MAX];
 } os_fm_tab_t;
 
 typedef struct os_ext_trk_ey_s {
 	__u8		et_part_num;
 	__u8		fmt;
-	__u16		fm_tab_off;
+	__be16		fm_tab_off;
 	__u8		reserved4_7[4];
-	__u32		last_hlb_hi;
-	__u32		last_hlb;
-	__u32		last_pp;
+	__be32		last_hlb_hi;
+	__be32		last_hlb;
+	__be32		last_pp;
 	__u8		reserved20_31[12];
 } os_ext_trk_ey_t;
 
@@ -479,17 +479,17 @@
         char            ident_str[8];
         __u8            major_rev;
         __u8            minor_rev;
-	__u16		ext_trk_tb_off;
+	__be16		ext_trk_tb_off;
         __u8            reserved12_15[4];
         __u8            pt_par_num;
         __u8            pt_reserved1_3[3];
         os_partition_t  partition[16];
-	__u32		cfg_col_width;
-	__u32		dat_col_width;
-	__u32		qfa_col_width;
+	__be32		cfg_col_width;
+	__be32		dat_col_width;
+	__be32		qfa_col_width;
 	__u8		cartridge[16];
 	__u8		reserved304_511[208];
-	__u32		old_filemark_list[16680/4];		/* in ADR 1.4 __u8 track_table[16680] */
+	__be32		old_filemark_list[16680/4];		/* in ADR 1.4 __u8 track_table[16680] */
 	os_ext_trk_tb_t	ext_track_tb;
 	__u8		reserved17272_17735[464];
 	os_fm_tab_t	dat_fm_tab;
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index 6b60536..80fb3f8 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -53,7 +53,7 @@
 	struct ConfigDev *esp_dev;
 
 	esp_dev = 0;
-	esp = esp_allocate(tpnt, (void *) esp_dev);
+	esp = esp_allocate(tpnt, esp_dev, 0);
 
 	/* Do command transfer with DMA */
 	esp->do_pio_cmds = 0;
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
index 08e55fd..925fb60 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
@@ -40,6 +40,7 @@
 
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/fs_pd.h>
 
 #include <linux/serial_core.h>
 #include <linux/kernel.h>
@@ -145,7 +146,7 @@
 		/* was hostalloc but changed cause it blows away the */
 		/* large tlb mapping when pinning the kernel area    */
 		mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8));
-		dma_addr = (u32)mem_addr;
+		dma_addr = (u32)cpm_dpram_phys(mem_addr);
 	} else
 		mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
 					      GFP_KERNEL);
@@ -205,7 +206,7 @@
 	    (unsigned long)&cpmp->cp_smc[0];
 	cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
 	cpm_uart_ports[UART_SMC1].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
-	cpm_uart_ports[UART_SMC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+	cpm_uart_ports[UART_SMC1].port.uartclk = uart_clock();
 	cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1;
 #endif
 
@@ -217,7 +218,7 @@
 	    (unsigned long)&cpmp->cp_smc[1];
 	cpm_uart_ports[UART_SMC2].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
 	cpm_uart_ports[UART_SMC2].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
-	cpm_uart_ports[UART_SMC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+	cpm_uart_ports[UART_SMC2].port.uartclk = uart_clock();
 	cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2;
 #endif
 
@@ -231,7 +232,7 @@
 	    ~(UART_SCCM_TX | UART_SCCM_RX);
 	cpm_uart_ports[UART_SCC1].sccp->scc_gsmrl &=
 	    ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-	cpm_uart_ports[UART_SCC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+	cpm_uart_ports[UART_SCC1].port.uartclk = uart_clock();
 	cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1;
 #endif
 
@@ -245,7 +246,7 @@
 	    ~(UART_SCCM_TX | UART_SCCM_RX);
 	cpm_uart_ports[UART_SCC2].sccp->scc_gsmrl &=
 	    ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-	cpm_uart_ports[UART_SCC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+	cpm_uart_ports[UART_SCC2].port.uartclk = uart_clock();
 	cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2;
 #endif
 
@@ -259,7 +260,7 @@
 	    ~(UART_SCCM_TX | UART_SCCM_RX);
 	cpm_uart_ports[UART_SCC3].sccp->scc_gsmrl &=
 	    ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-	cpm_uart_ports[UART_SCC3].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+	cpm_uart_ports[UART_SCC3].port.uartclk = uart_clock();
 	cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3;
 #endif
 
@@ -273,7 +274,7 @@
 	    ~(UART_SCCM_TX | UART_SCCM_RX);
 	cpm_uart_ports[UART_SCC4].sccp->scc_gsmrl &=
 	    ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-	cpm_uart_ports[UART_SCC4].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+	cpm_uart_ports[UART_SCC4].port.uartclk = uart_clock();
 	cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4;
 #endif
 	return 0;
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
index 5eb49ea..a99e45e 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
@@ -20,9 +20,6 @@
 #define SCC3_IRQ	(CPM_IRQ_OFFSET + CPMVEC_SCC3)
 #define SCC4_IRQ	(CPM_IRQ_OFFSET + CPMVEC_SCC4)
 
-/* the CPM address */
-#define CPM_ADDR	IMAP_ADDR
-
 static inline void cpm_set_brg(int brg, int baud)
 {
 	cpm_setbrg(brg, baud);
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
index 4b77911..1b3219f 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.h
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
@@ -20,9 +20,6 @@
 #define SCC3_IRQ	SIU_INT_SCC3
 #define SCC4_IRQ	SIU_INT_SCC4
 
-/* the CPM address */
-#define CPM_ADDR	CPM_MAP_ADDR
-
 static inline void cpm_set_brg(int brg, int baud)
 {
 	cpm_setbrg(brg, baud);
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
index db8607e..f5051cf 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/serial/uartlite.c
@@ -256,7 +256,7 @@
 {
 	release_mem_region(port->mapbase, ULITE_REGION);
 	iounmap(port->membase);
-	port->membase = 0;
+	port->membase = NULL;
 }
 
 static int ulite_request_port(struct uart_port *port)
@@ -438,7 +438,7 @@
 	port->iotype	= UPIO_MEM;
 	port->iobase	= 1; /* mark port in use */
 	port->mapbase	= res->start;
-	port->membase	= 0;
+	port->membase	= NULL;
 	port->ops	= &ulite_ops;
 	port->irq	= res2->start;
 	port->flags	= UPF_BOOT_AUTOCONF;
@@ -462,7 +462,7 @@
 		uart_remove_one_port(&ulite_uart_driver, port);
 
 	/* mark port as free */
-	port->membase = 0;
+	port->membase = NULL;
 
 	return 0;
 }
diff --git a/drivers/tc/Makefile b/drivers/tc/Makefile
index 83b5bd7..9673426 100644
--- a/drivers/tc/Makefile
+++ b/drivers/tc/Makefile
@@ -4,7 +4,7 @@
 
 # Object file lists.
 
-obj-$(CONFIG_TC) += tc.o
+obj-$(CONFIG_TC) += tc.o tc-driver.o
 obj-$(CONFIG_ZS) += zs.o
 obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o
 
diff --git a/drivers/tc/tc-driver.c b/drivers/tc/tc-driver.c
new file mode 100644
index 0000000..16b5bae
--- /dev/null
+++ b/drivers/tc/tc-driver.c
@@ -0,0 +1,110 @@
+/*
+ *	TURBOchannel driver services.
+ *
+ *	Copyright (c) 2005  James Simmons
+ *	Copyright (c) 2006  Maciej W. Rozycki
+ *
+ *	Loosely based on drivers/dio/dio-driver.c and
+ *	drivers/pci/pci-driver.c.
+ *
+ *	This file is subject to the terms and conditions of the GNU
+ *	General Public License.  See the file "COPYING" in the main
+ *	directory of this archive for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/tc.h>
+
+/**
+ * tc_register_driver - register a new TC driver
+ * @drv: the driver structure to register
+ *
+ * Adds the driver structure to the list of registered drivers
+ * Returns a negative value on error, otherwise 0.
+ * If no error occurred, the driver remains registered even if
+ * no device was claimed during registration.
+ */
+int tc_register_driver(struct tc_driver *tdrv)
+{
+	return driver_register(&tdrv->driver);
+}
+EXPORT_SYMBOL(tc_register_driver);
+
+/**
+ * tc_unregister_driver - unregister a TC driver
+ * @drv: the driver structure to unregister
+ *
+ * Deletes the driver structure from the list of registered TC drivers,
+ * gives it a chance to clean up by calling its remove() function for
+ * each device it was responsible for, and marks those devices as
+ * driverless.
+ */
+void tc_unregister_driver(struct tc_driver *tdrv)
+{
+	driver_unregister(&tdrv->driver);
+}
+EXPORT_SYMBOL(tc_unregister_driver);
+
+/**
+ * tc_match_device - tell if a TC device structure has a matching
+ *                   TC device ID structure
+ * @tdrv: the TC driver to earch for matching TC device ID strings
+ * @tdev: the TC device structure to match against
+ *
+ * Used by a driver to check whether a TC device present in the
+ * system is in its list of supported devices.  Returns the matching
+ * tc_device_id structure or %NULL if there is no match.
+ */
+const struct tc_device_id *tc_match_device(struct tc_driver *tdrv,
+					   struct tc_dev *tdev)
+{
+	const struct tc_device_id *id = tdrv->id_table;
+
+	if (id) {
+		while (id->name[0] || id->vendor[0]) {
+			if (strcmp(tdev->name, id->name) == 0 &&
+			    strcmp(tdev->vendor, id->vendor) == 0)
+				return id;
+			id++;
+		}
+	}
+	return NULL;
+}
+EXPORT_SYMBOL(tc_match_device);
+
+/**
+ * tc_bus_match - Tell if a device structure has a matching
+ *                TC device ID structure
+ * @dev: the device structure to match against
+ * @drv: the device driver to search for matching TC device ID strings
+ *
+ * Used by a driver to check whether a TC device present in the
+ * system is in its list of supported devices.  Returns 1 if there
+ * is a match or 0 otherwise.
+ */
+static int tc_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct tc_dev *tdev = to_tc_dev(dev);
+	struct tc_driver *tdrv = to_tc_driver(drv);
+	const struct tc_device_id *id;
+
+	id = tc_match_device(tdrv, tdev);
+	if (id)
+		return 1;
+
+	return 0;
+}
+
+struct bus_type tc_bus_type = {
+	.name	= "tc",
+	.match	= tc_bus_match,
+};
+EXPORT_SYMBOL(tc_bus_type);
+
+static int __init tc_driver_init(void)
+{
+	return bus_register(&tc_bus_type);
+}
+
+postcore_initcall(tc_driver_init);
diff --git a/drivers/tc/tc.c b/drivers/tc/tc.c
index 4a51e56..f77f62a 100644
--- a/drivers/tc/tc.c
+++ b/drivers/tc/tc.c
@@ -1,254 +1,193 @@
 /*
- * tc-init: We assume the TURBOchannel to be up and running so
- * just probe for Modules and fill in the global data structure
- * tc_bus.
+ *	TURBOchannel bus services.
  *
- * 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.
+ *	Copyright (c) Harald Koerfgen, 1998
+ *	Copyright (c) 2001, 2003, 2005, 2006  Maciej W. Rozycki
+ *	Copyright (c) 2005  James Simmons
  *
- * Copyright (c) Harald Koerfgen, 1998
- * Copyright (c) 2001, 2003, 2005  Maciej W. Rozycki
+ *	This file is subject to the terms and conditions of the GNU
+ *	General Public License.  See the file "COPYING" in the main
+ *	directory of this archive for more details.
  */
+#include <linux/compiler.h>
+#include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/ioport.h>
 #include <linux/kernel.h>
+#include <linux/list.h>
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/tc.h>
 #include <linux/types.h>
 
-#include <asm/addrspace.h>
-#include <asm/errno.h>
 #include <asm/io.h>
-#include <asm/paccess.h>
 
-#include <asm/dec/machtype.h>
-#include <asm/dec/prom.h>
-#include <asm/dec/tcinfo.h>
-#include <asm/dec/tcmodule.h>
-#include <asm/dec/interrupts.h>
-
-MODULE_LICENSE("GPL");
-slot_info tc_bus[MAX_SLOT];
-static int num_tcslots;
-static tcinfo *info;
+static struct tc_bus tc_bus = {
+	.name = "TURBOchannel",
+};
 
 /*
- * Interface to the world. Read comment in include/asm-mips/tc.h.
+ * Probing for TURBOchannel modules.
  */
-
-int search_tc_card(const char *name)
+static void __init tc_bus_add_devices(struct tc_bus *tbus)
 {
-	int slot;
-	slot_info *sip;
-
-	for (slot = 0; slot < num_tcslots; slot++) {
-		sip = &tc_bus[slot];
-		if ((sip->flags & FREE) &&
-		    (strncmp(sip->name, name, strlen(name)) == 0)) {
-			return slot;
-		}
-	}
-
-	return -ENODEV;
-}
-
-void claim_tc_card(int slot)
-{
-	if (tc_bus[slot].flags & IN_USE) {
-		printk("claim_tc_card: attempting to claim a card already in use\n");
-		return;
-	}
-	tc_bus[slot].flags &= ~FREE;
-	tc_bus[slot].flags |= IN_USE;
-}
-
-void release_tc_card(int slot)
-{
-	if (tc_bus[slot].flags & FREE) {
-		printk("release_tc_card: "
-		       "attempting to release a card already free\n");
-		return;
-	}
-	tc_bus[slot].flags &= ~IN_USE;
-	tc_bus[slot].flags |= FREE;
-}
-
-unsigned long get_tc_base_addr(int slot)
-{
-	return tc_bus[slot].base_addr;
-}
-
-unsigned long get_tc_irq_nr(int slot)
-{
-	return tc_bus[slot].interrupt;
-}
-
-unsigned long get_tc_speed(void)
-{
-	return 100000 * (10000 / (unsigned long)info->clk_period);
-}
-
-/*
- * Probing for TURBOchannel modules
- */
-static void __init tc_probe(unsigned long startaddr, unsigned long size,
-			    int slots)
-{
-	unsigned long slotaddr;
+	resource_size_t slotsize = tbus->info.slot_size << 20;
+	resource_size_t extslotsize = tbus->ext_slot_size;
+	resource_size_t slotaddr;
+	resource_size_t extslotaddr;
+	resource_size_t devsize;
+	void __iomem *module;
+	struct tc_dev *tdev;
 	int i, slot, err;
-	long offset;
 	u8 pattern[4];
-	volatile u8 *module;
+	long offset;
 
-	for (slot = 0; slot < slots; slot++) {
-		slotaddr = startaddr + slot * size;
-		module = ioremap_nocache(slotaddr, size);
+	for (slot = 0; slot < tbus->num_tcslots; slot++) {
+		slotaddr = tbus->slot_base + slot * slotsize;
+		extslotaddr = tbus->ext_slot_base + slot * extslotsize;
+		module = ioremap_nocache(slotaddr, slotsize);
 		BUG_ON(!module);
 
-		offset = OLDCARD;
+		offset = TC_OLDCARD;
 
 		err = 0;
-		err |= get_dbe(pattern[0], module + OLDCARD + TC_PATTERN0);
-		err |= get_dbe(pattern[1], module + OLDCARD + TC_PATTERN1);
-		err |= get_dbe(pattern[2], module + OLDCARD + TC_PATTERN2);
-		err |= get_dbe(pattern[3], module + OLDCARD + TC_PATTERN3);
-		if (err) {
-			iounmap(module);
-			continue;
-		}
+		err |= tc_preadb(pattern + 0, module + offset + TC_PATTERN0);
+		err |= tc_preadb(pattern + 1, module + offset + TC_PATTERN1);
+		err |= tc_preadb(pattern + 2, module + offset + TC_PATTERN2);
+		err |= tc_preadb(pattern + 3, module + offset + TC_PATTERN3);
+		if (err)
+			goto out_err;
 
 		if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
 		    pattern[2] != 0xaa || pattern[3] != 0xff) {
-			offset = NEWCARD;
+			offset = TC_NEWCARD;
 
 			err = 0;
-			err |= get_dbe(pattern[0], module + TC_PATTERN0);
-			err |= get_dbe(pattern[1], module + TC_PATTERN1);
-			err |= get_dbe(pattern[2], module + TC_PATTERN2);
-			err |= get_dbe(pattern[3], module + TC_PATTERN3);
-			if (err) {
-				iounmap(module);
-				continue;
-			}
+			err |= tc_preadb(pattern + 0,
+					 module + offset + TC_PATTERN0);
+			err |= tc_preadb(pattern + 1,
+					 module + offset + TC_PATTERN1);
+			err |= tc_preadb(pattern + 2,
+					 module + offset + TC_PATTERN2);
+			err |= tc_preadb(pattern + 3,
+					 module + offset + TC_PATTERN3);
+			if (err)
+				goto out_err;
 		}
 
 		if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
-		    pattern[2] != 0xaa || pattern[3] != 0xff) {
-			iounmap(module);
-			continue;
-		}
+		    pattern[2] != 0xaa || pattern[3] != 0xff)
+			goto out_err;
 
-		tc_bus[slot].base_addr = slotaddr;
+		/* Found a board, allocate it an entry in the list */
+		tdev = kzalloc(sizeof(*tdev), GFP_KERNEL);
+		if (!tdev) {
+			printk(KERN_ERR "tc%x: unable to allocate tc_dev\n",
+			       slot);
+			goto out_err;
+		}
+		sprintf(tdev->dev.bus_id, "tc%x", slot);
+		tdev->bus = tbus;
+		tdev->dev.parent = &tbus->dev;
+		tdev->dev.bus = &tc_bus_type;
+		tdev->slot = slot;
+
 		for (i = 0; i < 8; i++) {
-			tc_bus[slot].firmware[i] =
-				module[TC_FIRM_VER + offset + 4 * i];
-			tc_bus[slot].vendor[i] =
-				module[TC_VENDOR + offset + 4 * i];
-			tc_bus[slot].name[i] =
-				module[TC_MODULE + offset + 4 * i];
+			tdev->firmware[i] =
+				readb(module + offset + TC_FIRM_VER + 4 * i);
+			tdev->vendor[i] =
+				readb(module + offset + TC_VENDOR + 4 * i);
+			tdev->name[i] =
+				readb(module + offset + TC_MODULE + 4 * i);
 		}
-		tc_bus[slot].firmware[8] = 0;
-		tc_bus[slot].vendor[8] = 0;
-		tc_bus[slot].name[8] = 0;
-		/*
-		 * Looks unneccesary, but we may change
-		 * TC? in the future
-		 */
-		switch (slot) {
-		case 0:
-			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC0];
-			break;
-		case 1:
-			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC1];
-			break;
-		case 2:
-			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC2];
-			break;
-		/*
-		 * Yuck! DS5000/200 onboard devices
-		 */
-		case 5:
-			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC5];
-			break;
-		case 6:
-			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC6];
-			break;
-		default:
-			tc_bus[slot].interrupt = -1;
-			break;
-		}
+		tdev->firmware[8] = 0;
+		tdev->vendor[8] = 0;
+		tdev->name[8] = 0;
 
+		pr_info("%s: %s %s %s\n", tdev->dev.bus_id, tdev->vendor,
+			tdev->name, tdev->firmware);
+
+		devsize = readb(module + offset + TC_SLOT_SIZE);
+		devsize <<= 22;
+		if (devsize <= slotsize) {
+			tdev->resource.start = slotaddr;
+			tdev->resource.end = slotaddr + devsize - 1;
+		} else if (devsize <= extslotsize) {
+			tdev->resource.start = extslotaddr;
+			tdev->resource.end = extslotaddr + devsize - 1;
+		} else {
+			printk(KERN_ERR "%s: Cannot provide slot space "
+			       "(%dMiB required, up to %dMiB supported)\n",
+			       tdev->dev.bus_id, devsize >> 20,
+			       max(slotsize, extslotsize) >> 20);
+			kfree(tdev);
+			goto out_err;
+		}
+		tdev->resource.name = tdev->name;
+		tdev->resource.flags = IORESOURCE_MEM;
+
+		tc_device_get_irq(tdev);
+
+		device_register(&tdev->dev);
+		list_add_tail(&tdev->node, &tbus->devices);
+
+out_err:
 		iounmap(module);
 	}
 }
 
 /*
- * the main entry
+ * The main entry.
  */
 static int __init tc_init(void)
 {
-	int tc_clock;
-	int i;
-	unsigned long slot0addr;
-	unsigned long slot_size;
-
-	if (!TURBOCHANNEL)
+	/* Initialize the TURBOchannel bus */
+	if (tc_bus_get_info(&tc_bus))
 		return 0;
 
-	for (i = 0; i < MAX_SLOT; i++) {
-		tc_bus[i].base_addr = 0;
-		tc_bus[i].name[0] = 0;
-		tc_bus[i].vendor[0] = 0;
-		tc_bus[i].firmware[0] = 0;
-		tc_bus[i].interrupt = -1;
-		tc_bus[i].flags = FREE;
-	}
+	INIT_LIST_HEAD(&tc_bus.devices);
+	strcpy(tc_bus.dev.bus_id, "tc");
+	device_register(&tc_bus.dev);
 
-	info = rex_gettcinfo();
-	slot0addr = CPHYSADDR((long)rex_slot_address(0));
+	if (tc_bus.info.slot_size) {
+		unsigned int tc_clock = tc_get_speed(&tc_bus) / 100000;
 
-	switch (mips_machtype) {
-	case MACH_DS5000_200:
-		num_tcslots = 7;
-		break;
-	case MACH_DS5000_1XX:
-	case MACH_DS5000_2X0:
-	case MACH_DS5900:
-		num_tcslots = 3;
-		break;
-	case MACH_DS5000_XX:
-	default:
-		num_tcslots = 2;
-		break;
-	}
+		pr_info("tc: TURBOchannel rev. %d at %d.%d MHz "
+			"(with%s parity)\n", tc_bus.info.revision,
+			tc_clock / 10, tc_clock % 10,
+			tc_bus.info.parity ? "" : "out");
 
-	tc_clock = 10000 / info->clk_period;
-
-	if (info->slot_size && slot0addr) {
-		pr_info("TURBOchannel rev. %d at %d.%d MHz (with%s parity)\n",
-			info->revision, tc_clock / 10, tc_clock % 10,
-			info->parity ? "" : "out");
-
-		slot_size = info->slot_size << 20;
-
-		tc_probe(slot0addr, slot_size, num_tcslots);
-
-		for (i = 0; i < num_tcslots; i++) {
-			if (!tc_bus[i].base_addr)
-				continue;
-			pr_info("    slot %d: %s %s %s\n", i, tc_bus[i].vendor,
-				tc_bus[i].name, tc_bus[i].firmware);
+		tc_bus.resource[0].start = tc_bus.slot_base;
+		tc_bus.resource[0].end = tc_bus.slot_base +
+					 (tc_bus.info.slot_size << 20) *
+					 tc_bus.num_tcslots - 1;
+		tc_bus.resource[0].name = tc_bus.name;
+		tc_bus.resource[0].flags = IORESOURCE_MEM;
+		if (request_resource(&iomem_resource,
+				     &tc_bus.resource[0]) < 0) {
+			printk(KERN_ERR "tc: Cannot reserve resource\n");
+			return 0;
 		}
+		if (tc_bus.ext_slot_size) {
+			tc_bus.resource[1].start = tc_bus.ext_slot_base;
+			tc_bus.resource[1].end = tc_bus.ext_slot_base +
+						 tc_bus.ext_slot_size *
+						 tc_bus.num_tcslots - 1;
+			tc_bus.resource[1].name = tc_bus.name;
+			tc_bus.resource[1].flags = IORESOURCE_MEM;
+			if (request_resource(&iomem_resource,
+					     &tc_bus.resource[1]) < 0) {
+				printk(KERN_ERR
+				       "tc: Cannot reserve resource\n");
+				release_resource(&tc_bus.resource[0]);
+				return 0;
+			}
+		}
+
+		tc_bus_add_devices(&tc_bus);
 	}
 
 	return 0;
 }
 
 subsys_initcall(tc_init);
-
-EXPORT_SYMBOL(search_tc_card);
-EXPORT_SYMBOL(claim_tc_card);
-EXPORT_SYMBOL(release_tc_card);
-EXPORT_SYMBOL(get_tc_base_addr);
-EXPORT_SYMBOL(get_tc_irq_nr);
-EXPORT_SYMBOL(get_tc_speed);
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 8ed6c75..638b800 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -36,7 +36,7 @@
 #include <linux/stat.h>
 #include <linux/timer.h>
 #include <linux/types.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/workqueue.h>
 
 #include "usbatm.h"
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 6377db1..63e50a1 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -398,6 +398,9 @@
 	retval = 0;
 #endif
 
+	retval = usb_autopm_get_interface(intf);
+	if (retval < 0)
+		goto out;
 	usblp->used = 1;
 	file->private_data = usblp;
 
@@ -442,6 +445,7 @@
 	usblp->used = 0;
 	if (usblp->present) {
 		usblp_unlink_urbs(usblp);
+		usb_autopm_put_interface(usblp->intf);
 	} else 		/* finish cleanup from disconnect */
 		usblp_cleanup (usblp);
 	mutex_unlock (&usblp_mutex);
@@ -1203,14 +1207,9 @@
 {
 	struct usblp *usblp = usb_get_intfdata (intf);
 
-	/* this races against normal access and open */
-	mutex_lock (&usblp_mutex);
-	mutex_lock (&usblp->mut);
 	/* we take no more IO */
 	usblp->sleeping = 1;
 	usblp_unlink_urbs(usblp);
-	mutex_unlock (&usblp->mut);
-	mutex_unlock (&usblp_mutex);
 
 	return 0;
 }
@@ -1220,15 +1219,9 @@
 	struct usblp *usblp = usb_get_intfdata (intf);
 	int r;
 
-	mutex_lock (&usblp_mutex);
-	mutex_lock (&usblp->mut);
-
 	usblp->sleeping = 0;
 	r = handle_bidir (usblp);
 
-	mutex_unlock (&usblp->mut);
-	mutex_unlock (&usblp_mutex);
-
 	return r;
 }
 
@@ -1251,6 +1244,7 @@
 	.suspend =	usblp_suspend,
 	.resume =	usblp_resume,
 	.id_table =	usblp_ids,
+	.supports_autosuspend =	1,
 };
 
 static int __init usblp_init(void)
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index 3e66b2a..2fc0f88 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -33,19 +33,6 @@
 
 	  Most users want to say Y here.
 
-config USB_BANDWIDTH
-	bool "Enforce USB bandwidth allocation (EXPERIMENTAL)"
-	depends on USB && EXPERIMENTAL
-	help
-	  If you say Y here, the USB subsystem enforces USB bandwidth
-	  allocation and will prevent some device opens from succeeding
-	  if they would cause USB bandwidth usage to go above 90% of
-	  the bus bandwidth.
-
-	  If you say N here, these conditions will cause warning messages
-	  about USB bandwidth usage to be logged and some devices or
-	  drivers may not work correctly.
-
 config USB_DYNAMIC_MINORS
 	bool "Dynamic USB minor allocation (EXPERIMENTAL)"
 	depends on USB && EXPERIMENTAL
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index c3915dc..ead2475 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -49,9 +49,9 @@
  *
  * Call hcd_buffer_destroy() to clean up after using those pools.
  */
-int hcd_buffer_create (struct usb_hcd *hcd)
+int hcd_buffer_create(struct usb_hcd *hcd)
 {
-	char		name [16];
+	char		name[16];
 	int 		i, size;
 
 	if (!hcd->self.controller->dma_mask)
@@ -60,11 +60,11 @@
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
 		if (!(size = pool_max [i]))
 			continue;
-		snprintf (name, sizeof name, "buffer-%d", size);
-		hcd->pool [i] = dma_pool_create (name, hcd->self.controller,
+		snprintf(name, sizeof name, "buffer-%d", size);
+		hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
 				size, size, 0);
 		if (!hcd->pool [i]) {
-			hcd_buffer_destroy (hcd);
+			hcd_buffer_destroy(hcd);
 			return -ENOMEM;
 		}
 	}
@@ -79,14 +79,14 @@
  *
  * This frees the buffer pools created by hcd_buffer_create().
  */
-void hcd_buffer_destroy (struct usb_hcd *hcd)
+void hcd_buffer_destroy(struct usb_hcd *hcd)
 {
 	int		i;
 
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
-		struct dma_pool		*pool = hcd->pool [i];
+		struct dma_pool		*pool = hcd->pool[i];
 		if (pool) {
-			dma_pool_destroy (pool);
+			dma_pool_destroy(pool);
 			hcd->pool[i] = NULL;
 		}
 	}
@@ -97,8 +97,8 @@
  * better sharing and to leverage mm/slab.c intelligence.
  */
 
-void *hcd_buffer_alloc (
-	struct usb_bus 		*bus,
+void *hcd_buffer_alloc(
+	struct usb_bus 	*bus,
 	size_t			size,
 	gfp_t			mem_flags,
 	dma_addr_t		*dma
@@ -110,18 +110,18 @@
 	/* some USB hosts just use PIO */
 	if (!bus->controller->dma_mask) {
 		*dma = ~(dma_addr_t) 0;
-		return kmalloc (size, mem_flags);
+		return kmalloc(size, mem_flags);
 	}
 
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
 		if (size <= pool_max [i])
-			return dma_pool_alloc (hcd->pool [i], mem_flags, dma);
+			return dma_pool_alloc(hcd->pool [i], mem_flags, dma);
 	}
-	return dma_alloc_coherent (hcd->self.controller, size, dma, 0);
+	return dma_alloc_coherent(hcd->self.controller, size, dma, 0);
 }
 
-void hcd_buffer_free (
-	struct usb_bus 		*bus,
+void hcd_buffer_free(
+	struct usb_bus 	*bus,
 	size_t			size,
 	void 			*addr,
 	dma_addr_t		dma
@@ -134,15 +134,15 @@
 		return;
 
 	if (!bus->controller->dma_mask) {
-		kfree (addr);
+		kfree(addr);
 		return;
 	}
 
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
 		if (size <= pool_max [i]) {
-			dma_pool_free (hcd->pool [i], addr, dma);
+			dma_pool_free(hcd->pool [i], addr, dma);
 			return;
 		}
 	}
-	dma_free_coherent (hcd->self.controller, size, addr, dma);
+	dma_free_coherent(hcd->self.controller, size, addr, dma);
 }
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index ea398e5..a47c30b 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -104,7 +104,7 @@
   
 static const char *format_iface =
 /* I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
-  "I:  If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
+  "I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
 
 static const char *format_endpt =
 /* E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
@@ -164,10 +164,10 @@
 	for (ix = 0; clas_info[ix].class != -1; ix++)
 		if (clas_info[ix].class == class)
 			break;
-	return (clas_info[ix].class_name);
+	return clas_info[ix].class_name;
 }
 
-static char *usb_dump_endpoint_descriptor (
+static char *usb_dump_endpoint_descriptor(
 	int speed,
 	char *start,
 	char *end,
@@ -212,9 +212,9 @@
 		break;
 	case USB_ENDPOINT_XFER_INT:
 		type = "Int.";
-		if (speed == USB_SPEED_HIGH) {
+		if (speed == USB_SPEED_HIGH)
 			interval = 1 << (desc->bInterval - 1);
-		} else
+		else
 			interval = desc->bInterval;
 		break;
 	default:	/* "can't happen" */
@@ -242,15 +242,19 @@
 {
 	const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc;
 	const char *driver_name = "";
+	int active = 0;
 
 	if (start > end)
 		return start;
 	down_read(&usb_bus_type.subsys.rwsem);
-	if (iface)
+	if (iface) {
 		driver_name = (iface->dev.driver
 				? iface->dev.driver->name
 				: "(none)");
+		active = (desc == &iface->cur_altsetting->desc);
+	}
 	start += sprintf(start, format_iface,
+			 active ? '*' : ' ',	/* mark active altsetting */
 			 desc->bInterfaceNumber,
 			 desc->bAlternateSetting,
 			 desc->bNumEndpoints,
@@ -343,7 +347,7 @@
 
 	if (start > end)
 		return start;
-	start += sprintf (start, format_device1,
+	start += sprintf(start, format_device1,
 			  bcdUSB >> 8, bcdUSB & 0xff,
 			  desc->bDeviceClass,
 			  class_decode (desc->bDeviceClass),
@@ -363,7 +367,7 @@
 /*
  * Dump the different strings that this device holds.
  */
-static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev)
+static char *usb_dump_device_strings(char *start, char *end, struct usb_device *dev)
 {
 	if (start > end)
 		return start;
@@ -395,7 +399,7 @@
 	if (start > end)
 		return start;
 	
-	start = usb_dump_device_strings (start, end, dev);
+	start = usb_dump_device_strings(start, end, dev);
 
 	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
 		if (start > end)
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 4b3a6ab..2087766 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -522,19 +522,19 @@
 
 static struct usb_device *usbdev_lookup_minor(int minor)
 {
-	struct class_device *class_dev;
-	struct usb_device *dev = NULL;
+	struct device *device;
+	struct usb_device *udev = NULL;
 
 	down(&usb_device_class->sem);
-	list_for_each_entry(class_dev, &usb_device_class->children, node) {
-		if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
-			dev = class_dev->class_data;
+	list_for_each_entry(device, &usb_device_class->devices, node) {
+		if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
+			udev = device->platform_data;
 			break;
 		}
 	}
 	up(&usb_device_class->sem);
 
-	return dev;
+	return udev;
 };
 
 /*
@@ -570,6 +570,7 @@
 	ps->dev = dev;
 	ps->file = file;
 	spin_lock_init(&ps->lock);
+	INIT_LIST_HEAD(&ps->list);
 	INIT_LIST_HEAD(&ps->async_pending);
 	INIT_LIST_HEAD(&ps->async_completed);
 	init_waitqueue_head(&ps->wait);
@@ -1596,19 +1597,19 @@
 {
 	int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
 
-	dev->class_dev = class_device_create(usb_device_class, NULL,
-				MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
+	dev->usbfs_dev = device_create(usb_device_class, &dev->dev,
+				MKDEV(USB_DEVICE_MAJOR, minor),
 				"usbdev%d.%d", dev->bus->busnum, dev->devnum);
-	if (IS_ERR(dev->class_dev))
-		return PTR_ERR(dev->class_dev);
+	if (IS_ERR(dev->usbfs_dev))
+		return PTR_ERR(dev->usbfs_dev);
 
-	dev->class_dev->class_data = dev;
+	dev->usbfs_dev->platform_data = dev;
 	return 0;
 }
 
 static void usbdev_remove(struct usb_device *dev)
 {
-	class_device_unregister(dev->class_dev);
+	device_unregister(dev->usbfs_dev);
 }
 
 static int usbdev_notify(struct notifier_block *self, unsigned long action,
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index d6eb5ce..600d1bc 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -28,24 +28,16 @@
 #include "hcd.h"
 #include "usb.h"
 
-static int usb_match_one_id(struct usb_interface *interface,
-			    const struct usb_device_id *id);
-
-struct usb_dynid {
-	struct list_head node;
-	struct usb_device_id id;
-};
-
 #ifdef CONFIG_HOTPLUG
 
 /*
  * Adds a new dynamic USBdevice ID to this driver,
  * and cause the driver to probe for all devices again.
  */
-static ssize_t store_new_id(struct device_driver *driver,
-			    const char *buf, size_t count)
+ssize_t usb_store_new_id(struct usb_dynids *dynids,
+			 struct device_driver *driver,
+			 const char *buf, size_t count)
 {
-	struct usb_driver *usb_drv = to_usb_driver(driver);
 	struct usb_dynid *dynid;
 	u32 idVendor = 0;
 	u32 idProduct = 0;
@@ -65,9 +57,9 @@
 	dynid->id.idProduct = idProduct;
 	dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
 
-	spin_lock(&usb_drv->dynids.lock);
-	list_add_tail(&usb_drv->dynids.list, &dynid->node);
-	spin_unlock(&usb_drv->dynids.lock);
+	spin_lock(&dynids->lock);
+	list_add_tail(&dynids->list, &dynid->node);
+	spin_unlock(&dynids->lock);
 
 	if (get_driver(driver)) {
 		retval = driver_attach(driver);
@@ -78,6 +70,15 @@
 		return retval;
 	return count;
 }
+EXPORT_SYMBOL_GPL(usb_store_new_id);
+
+static ssize_t store_new_id(struct device_driver *driver,
+			    const char *buf, size_t count)
+{
+	struct usb_driver *usb_drv = to_usb_driver(driver);
+
+	return usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+}
 static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
 
 static int usb_create_newid_file(struct usb_driver *usb_drv)
@@ -365,8 +366,8 @@
 EXPORT_SYMBOL(usb_driver_release_interface);
 
 /* returns 0 if no match, 1 if match */
-static int usb_match_one_id(struct usb_interface *interface,
-			    const struct usb_device_id *id)
+int usb_match_one_id(struct usb_interface *interface,
+		     const struct usb_device_id *id)
 {
 	struct usb_host_interface *intf;
 	struct usb_device *dev;
@@ -432,6 +433,8 @@
 
 	return 1;
 }
+EXPORT_SYMBOL_GPL(usb_match_one_id);
+
 /**
  * usb_match_id - find first usb_device_id matching device or interface
  * @interface: the interface of interest
@@ -750,7 +753,8 @@
  * usb_register_dev() to enable that functionality.  This function no longer
  * takes care of that.
  */
-int usb_register_driver(struct usb_driver *new_driver, struct module *owner)
+int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
+			const char *mod_name)
 {
 	int retval = 0;
 
@@ -763,6 +767,7 @@
 	new_driver->drvwrap.driver.probe = usb_probe_interface;
 	new_driver->drvwrap.driver.remove = usb_unbind_interface;
 	new_driver->drvwrap.driver.owner = owner;
+	new_driver->drvwrap.driver.mod_name = mod_name;
 	spin_lock_init(&new_driver->dynids.lock);
 	INIT_LIST_HEAD(&new_driver->dynids.list);
 
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index f794f07..01c857a 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -194,14 +194,13 @@
 		++temp;
 	else
 		temp = name;
-	intf->class_dev = class_device_create(usb_class->class, NULL,
-					      MKDEV(USB_MAJOR, minor),
-					      &intf->dev, "%s", temp);
-	if (IS_ERR(intf->class_dev)) {
+	intf->usb_dev = device_create(usb_class->class, &intf->dev,
+				      MKDEV(USB_MAJOR, minor), "%s", temp);
+	if (IS_ERR(intf->usb_dev)) {
 		spin_lock (&minor_lock);
 		usb_minors[intf->minor] = NULL;
 		spin_unlock (&minor_lock);
-		retval = PTR_ERR(intf->class_dev);
+		retval = PTR_ERR(intf->usb_dev);
 	}
 exit:
 	return retval;
@@ -242,8 +241,8 @@
 	spin_unlock (&minor_lock);
 
 	snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
-	class_device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
-	intf->class_dev = NULL;
+	device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
+	intf->usb_dev = NULL;
 	intf->minor = -1;
 	destroy_usb_class();
 }
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index ebb20ff..b531a4f 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -25,6 +25,20 @@
 	return (n == 1 ? "" : "s");
 }
 
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+	return desc->bInterfaceClass == USB_CLASS_COMM
+		&& desc->bInterfaceSubClass == 2
+		&& desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+	return desc->bInterfaceClass == USB_CLASS_MISC
+		&& desc->bInterfaceSubClass == 1
+		&& desc->bInterfaceProtocol == 1;
+}
+
 static int choose_configuration(struct usb_device *udev)
 {
 	int i;
@@ -87,14 +101,12 @@
 			continue;
 		}
 
-		/* If the first config's first interface is COMM/2/0xff
-		 * (MSFT RNDIS), rule it out unless Linux has host-side
-		 * RNDIS support. */
-		if (i == 0 && desc
-				&& desc->bInterfaceClass == USB_CLASS_COMM
-				&& desc->bInterfaceSubClass == 2
-				&& desc->bInterfaceProtocol == 0xff) {
-#ifndef CONFIG_USB_NET_RNDIS_HOST
+		/* When the first config's first interface is one of Microsoft's
+		 * pet nonstandard Ethernet-over-USB protocols, ignore it unless
+		 * this kernel has enabled the necessary host side driver.
+		 */
+		if (i == 0 && desc && (is_rndis(desc) || is_activesync(desc))) {
+#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
 			continue;
 #else
 			best = c;
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 10064af..b26c19e 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -45,8 +45,6 @@
 #include "hub.h"
 
 
-// #define USB_BANDWIDTH_MESSAGES
-
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -891,136 +889,6 @@
 }
 EXPORT_SYMBOL (usb_calc_bus_time);
 
-/*
- * usb_check_bandwidth():
- *
- * old_alloc is from host_controller->bandwidth_allocated in microseconds;
- * bustime is from calc_bus_time(), but converted to microseconds.
- *
- * returns <bustime in us> if successful,
- * or -ENOSPC if bandwidth request fails.
- *
- * FIXME:
- * This initial implementation does not use Endpoint.bInterval
- * in managing bandwidth allocation.
- * It probably needs to be expanded to use Endpoint.bInterval.
- * This can be done as a later enhancement (correction).
- *
- * This will also probably require some kind of
- * frame allocation tracking...meaning, for example,
- * that if multiple drivers request interrupts every 10 USB frames,
- * they don't all have to be allocated at
- * frame numbers N, N+10, N+20, etc.  Some of them could be at
- * N+11, N+21, N+31, etc., and others at
- * N+12, N+22, N+32, etc.
- *
- * Similarly for isochronous transfers...
- *
- * Individual HCDs can schedule more directly ... this logic
- * is not correct for high speed transfers.
- */
-int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
-{
-	unsigned int	pipe = urb->pipe;
-	long		bustime;
-	int		is_in = usb_pipein (pipe);
-	int		is_iso = usb_pipeisoc (pipe);
-	int		old_alloc = dev->bus->bandwidth_allocated;
-	int		new_alloc;
-
-
-	bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso,
-			usb_maxpacket (dev, pipe, !is_in)));
-	if (is_iso)
-		bustime /= urb->number_of_packets;
-
-	new_alloc = old_alloc + (int) bustime;
-	if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) {
-#ifdef	DEBUG
-		char	*mode = 
-#ifdef CONFIG_USB_BANDWIDTH
-			"";
-#else
-			"would have ";
-#endif
-		dev_dbg (&dev->dev, "usb_check_bandwidth %sFAILED: %d + %ld = %d usec\n",
-			mode, old_alloc, bustime, new_alloc);
-#endif
-#ifdef CONFIG_USB_BANDWIDTH
-		bustime = -ENOSPC;	/* report error */
-#endif
-	}
-
-	return bustime;
-}
-EXPORT_SYMBOL (usb_check_bandwidth);
-
-
-/**
- * usb_claim_bandwidth - records bandwidth for a periodic transfer
- * @dev: source/target of request
- * @urb: request (urb->dev == dev)
- * @bustime: bandwidth consumed, in (average) microseconds per frame
- * @isoc: true iff the request is isochronous
- *
- * Bus bandwidth reservations are recorded purely for diagnostic purposes.
- * HCDs are expected not to overcommit periodic bandwidth, and to record such
- * reservations whenever endpoints are added to the periodic schedule.
- *
- * FIXME averaging per-frame is suboptimal.  Better to sum over the HCD's
- * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable
- * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how
- * large its periodic schedule is.
- */
-void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc)
-{
-	dev->bus->bandwidth_allocated += bustime;
-	if (isoc)
-		dev->bus->bandwidth_isoc_reqs++;
-	else
-		dev->bus->bandwidth_int_reqs++;
-	urb->bandwidth = bustime;
-
-#ifdef USB_BANDWIDTH_MESSAGES
-	dev_dbg (&dev->dev, "bandwidth alloc increased by %d (%s) to %d for %d requesters\n",
-		bustime,
-		isoc ? "ISOC" : "INTR",
-		dev->bus->bandwidth_allocated,
-		dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
-}
-EXPORT_SYMBOL (usb_claim_bandwidth);
-
-
-/**
- * usb_release_bandwidth - reverses effect of usb_claim_bandwidth()
- * @dev: source/target of request
- * @urb: request (urb->dev == dev)
- * @isoc: true iff the request is isochronous
- *
- * This records that previously allocated bandwidth has been released.
- * Bandwidth is released when endpoints are removed from the host controller's
- * periodic schedule.
- */
-void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc)
-{
-	dev->bus->bandwidth_allocated -= urb->bandwidth;
-	if (isoc)
-		dev->bus->bandwidth_isoc_reqs--;
-	else
-		dev->bus->bandwidth_int_reqs--;
-
-#ifdef USB_BANDWIDTH_MESSAGES
-	dev_dbg (&dev->dev, "bandwidth alloc reduced by %d (%s) to %d for %d requesters\n",
-		urb->bandwidth,
-		isoc ? "ISOC" : "INTR",
-		dev->bus->bandwidth_allocated,
-		dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
-	urb->bandwidth = 0;
-}
-EXPORT_SYMBOL (usb_release_bandwidth);
-
 
 /*-------------------------------------------------------------------------*/
 
@@ -1034,11 +902,6 @@
 {
 	unsigned long		flags;
 
-	/* Release any periodic transfer bandwidth */
-	if (urb->bandwidth)
-		usb_release_bandwidth (urb->dev, urb,
-			usb_pipeisoc (urb->pipe));
-
 	/* clear all state linking urb to this dev (and hcd) */
 
 	spin_lock_irqsave (&hcd_data_lock, flags);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 8f8df0d..2a269ca 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -308,10 +308,6 @@
 #define NS_TO_US(ns)	((ns + 500L) / 1000L)
 			/* convert & round nanoseconds to microseconds */
 
-extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb,
-		int bustime, int isoc);
-extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
-		int isoc);
 
 /*
  * Full/low speed bandwidth allocation constants/support.
@@ -324,8 +320,6 @@
 #define FRAME_TIME_MAX_BITS_ALLOC	(90L * FRAME_TIME_BITS / 100L)
 #define FRAME_TIME_MAX_USECS_ALLOC	(90L * FRAME_TIME_USECS / 100L)
 
-extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
-
 /*
  * Ceiling [nano/micro]seconds (typical) for that many bytes at high speed
  * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 1988224..590ec82 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -87,9 +87,6 @@
 
 static struct task_struct *khubd_task;
 
-/* multithreaded probe logic */
-static int multithread_probe = 0;
-
 /* cycle leds on hubs that aren't blinking for attention */
 static int blinkenlights = 0;
 module_param (blinkenlights, bool, S_IRUGO);
@@ -1256,9 +1253,28 @@
 static int __usb_port_suspend(struct usb_device *, int port1);
 #endif
 
-static int __usb_new_device(void *void_data)
+/**
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is called with devices which have been enumerated, but not yet
+ * configured.  The device descriptor is available, but not descriptors
+ * for any device configuration.  The caller must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * It will return if the device is configured properly or not.  Zero if
+ * the interface was registered with the driver core; else a negative
+ * errno value.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
+ */
+int usb_new_device(struct usb_device *udev)
 {
-	struct usb_device *udev = void_data;
 	int err;
 
 	/* Lock ourself into memory in order to keep a probe sequence
@@ -1375,44 +1391,6 @@
 	goto exit;
 }
 
-/**
- * usb_new_device - perform initial device setup (usbcore-internal)
- * @udev: newly addressed device (in ADDRESS state)
- *
- * This is called with devices which have been enumerated, but not yet
- * configured.  The device descriptor is available, but not descriptors
- * for any device configuration.  The caller must have locked either
- * the parent hub (if udev is a normal device) or else the
- * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
- * udev has already been installed, but udev is not yet visible through
- * sysfs or other filesystem code.
- *
- * The return value for this function depends on if the
- * multithread_probe variable is set or not.  If it's set, it will
- * return a if the probe thread was successfully created or not.  If the
- * variable is not set, it will return if the device is configured
- * properly or not.  interfaces, in sysfs); else a negative errno value.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver or root-hub registrar should ever call this.
- */
-int usb_new_device(struct usb_device *udev)
-{
-	struct task_struct *probe_task;
-	int ret = 0;
-
-	if (multithread_probe) {
-		probe_task = kthread_run(__usb_new_device, udev,
-					 "usb-probe-%s", udev->devnum);
-		if (IS_ERR(probe_task))
-			ret = PTR_ERR(probe_task);
-	} else
-		ret = __usb_new_device(udev);
-
-	return ret;
-}
-
 static int hub_port_status(struct usb_hub *hub, int port1,
 			       u16 *status, u16 *change)
 {
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 149aa8b..8aca357 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1545,11 +1545,7 @@
 	INIT_WORK(&req->work, driver_set_config_work);
 
 	usb_get_dev(udev);
-	if (!schedule_work(&req->work)) {
-		usb_put_dev(udev);
-		kfree(req);
-		return -EINVAL;
-	}
+	schedule_work(&req->work);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 55d8f57..4eaa0ee 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -16,16 +16,16 @@
 
 /* Active configuration fields */
 #define usb_actconfig_show(field, multiplier, format_string)		\
-static ssize_t  show_##field (struct device *dev,			\
+static ssize_t  show_##field(struct device *dev,			\
 		struct device_attribute *attr, char *buf)		\
 {									\
 	struct usb_device *udev;					\
 	struct usb_host_config *actconfig;				\
 									\
-	udev = to_usb_device (dev);					\
+	udev = to_usb_device(dev);					\
 	actconfig = udev->actconfig;					\
 	if (actconfig)							\
-		return sprintf (buf, format_string,			\
+		return sprintf(buf, format_string,			\
 				actconfig->desc.field * multiplier);	\
 	else								\
 		return 0;						\
@@ -35,9 +35,9 @@
 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")
+usb_actconfig_attr(bNumInterfaces, 1, "%2d\n")
+usb_actconfig_attr(bmAttributes, 1, "%2x\n")
+usb_actconfig_attr(bMaxPower, 2, "%3dmA\n")
 
 static ssize_t show_configuration_string(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -45,7 +45,7 @@
 	struct usb_device *udev;
 	struct usb_host_config *actconfig;
 
-	udev = to_usb_device (dev);
+	udev = to_usb_device(dev);
 	actconfig = udev->actconfig;
 	if ((!actconfig) || (!actconfig->string))
 		return 0;
@@ -57,16 +57,16 @@
 usb_actconfig_show(bConfigurationValue, 1, "%u\n");
 
 static ssize_t
-set_bConfigurationValue (struct device *dev, struct device_attribute *attr,
+set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
 		const char *buf, size_t count)
 {
-	struct usb_device	*udev = to_usb_device (dev);
+	struct usb_device	*udev = to_usb_device(dev);
 	int			config, value;
 
-	if (sscanf (buf, "%u", &config) != 1 || config > 255)
+	if (sscanf(buf, "%u", &config) != 1 || config > 255)
 		return -EINVAL;
 	usb_lock_device(udev);
-	value = usb_set_configuration (udev, config);
+	value = usb_set_configuration(udev, config);
 	usb_unlock_device(udev);
 	return (value < 0) ? value : count;
 }
@@ -81,7 +81,7 @@
 {									\
 	struct usb_device *udev;					\
 									\
-	udev = to_usb_device (dev);					\
+	udev = to_usb_device(dev);					\
 	return sprintf(buf, "%s\n", udev->name);			\
 }									\
 static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
@@ -91,12 +91,12 @@
 usb_string_attr(serial);
 
 static ssize_t
-show_speed (struct device *dev, struct device_attribute *attr, char *buf)
+show_speed(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev;
 	char *speed;
 
-	udev = to_usb_device (dev);
+	udev = to_usb_device(dev);
 
 	switch (udev->speed) {
 	case USB_SPEED_LOW:
@@ -112,22 +112,22 @@
 	default:
 		speed = "unknown";
 	}
-	return sprintf (buf, "%s\n", speed);
+	return sprintf(buf, "%s\n", speed);
 }
 static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
 
 static ssize_t
-show_devnum (struct device *dev, struct device_attribute *attr, char *buf)
+show_devnum(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev;
 
-	udev = to_usb_device (dev);
-	return sprintf (buf, "%d\n", udev->devnum);
+	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, struct device_attribute *attr, char *buf)
+show_version(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev;
 	u16 bcdUSB;
@@ -139,25 +139,25 @@
 static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
 
 static ssize_t
-show_maxchild (struct device *dev, struct device_attribute *attr, char *buf)
+show_maxchild(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev;
 
-	udev = to_usb_device (dev);
-	return sprintf (buf, "%d\n", udev->maxchild);
+	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_le16(field, format_string)			\
 static ssize_t								\
-show_##field (struct device *dev, struct device_attribute *attr,	\
+show_##field(struct device *dev, struct device_attribute *attr,	\
 		char *buf)						\
 {									\
 	struct usb_device *udev;					\
 									\
-	udev = to_usb_device (dev);					\
-	return sprintf (buf, format_string, 				\
+	udev = to_usb_device(dev);					\
+	return sprintf(buf, format_string, 				\
 			le16_to_cpu(udev->descriptor.field));		\
 }									\
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
@@ -168,21 +168,21 @@
 
 #define usb_descriptor_attr(field, format_string)			\
 static ssize_t								\
-show_##field (struct device *dev, struct device_attribute *attr,	\
+show_##field(struct device *dev, struct device_attribute *attr,	\
 		char *buf)						\
 {									\
 	struct usb_device *udev;					\
 									\
-	udev = to_usb_device (dev);					\
-	return sprintf (buf, format_string, udev->descriptor.field);	\
+	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 (bDeviceClass, "%02x\n")
-usb_descriptor_attr (bDeviceSubClass, "%02x\n")
-usb_descriptor_attr (bDeviceProtocol, "%02x\n")
-usb_descriptor_attr (bNumConfigurations, "%d\n")
-usb_descriptor_attr (bMaxPacketSize0, "%d\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")
+usb_descriptor_attr(bMaxPacketSize0, "%d\n")
 
 static struct attribute *dev_attrs[] = {
 	/* current configuration's attributes */
@@ -220,17 +220,17 @@
 		return retval;
 
 	if (udev->manufacturer) {
-		retval = device_create_file (dev, &dev_attr_manufacturer);
+		retval = device_create_file(dev, &dev_attr_manufacturer);
 		if (retval)
 			goto error;
 	}
 	if (udev->product) {
-		retval = device_create_file (dev, &dev_attr_product);
+		retval = device_create_file(dev, &dev_attr_product);
 		if (retval)
 			goto error;
 	}
 	if (udev->serial) {
-		retval = device_create_file (dev, &dev_attr_serial);
+		retval = device_create_file(dev, &dev_attr_serial);
 		if (retval)
 			goto error;
 	}
@@ -246,7 +246,7 @@
 	return retval;
 }
 
-void usb_remove_sysfs_dev_files (struct usb_device *udev)
+void usb_remove_sysfs_dev_files(struct usb_device *udev)
 {
 	struct device *dev = &udev->dev;
 
@@ -264,22 +264,22 @@
 /* Interface fields */
 #define usb_intf_attr(field, format_string)				\
 static ssize_t								\
-show_##field (struct device *dev, struct device_attribute *attr,	\
+show_##field(struct device *dev, struct device_attribute *attr,	\
 		char *buf)						\
 {									\
-	struct usb_interface *intf = to_usb_interface (dev);		\
+	struct usb_interface *intf = to_usb_interface(dev);		\
 									\
-	return sprintf (buf, format_string,				\
+	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(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")
 
 static ssize_t show_interface_string(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -288,8 +288,8 @@
 	struct usb_device *udev;
 	int len;
 
-	intf = to_usb_interface (dev);
-	udev = interface_to_usbdev (intf);
+	intf = to_usb_interface(dev);
+	udev = interface_to_usbdev(intf);
 	len = snprintf(buf, 256, "%s", intf->cur_altsetting->string);
 	if (len < 0)
 		return 0;
@@ -384,7 +384,7 @@
 	return retval;
 }
 
-void usb_remove_sysfs_intf_files (struct usb_interface *intf)
+void usb_remove_sysfs_intf_files(struct usb_interface *intf)
 {
 	usb_remove_intf_ep_files(intf);
 	sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 9801d08..94ea972 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -235,16 +235,15 @@
 
 	urb->status = -EINPROGRESS;
 	urb->actual_length = 0;
-	urb->bandwidth = 0;
 
 	/* Lots of sanity checks, so HCDs can rely on clean data
 	 * and don't need to duplicate tests
 	 */
 	pipe = urb->pipe;
-	temp = usb_pipetype (pipe);
-	is_out = usb_pipeout (pipe);
+	temp = usb_pipetype(pipe);
+	is_out = usb_pipeout(pipe);
 
-	if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED)
+	if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
 		return -ENODEV;
 
 	/* FIXME there should be a sharable lock protecting us against
@@ -253,11 +252,11 @@
 	 * checks get made.)
 	 */
 
-	max = usb_maxpacket (dev, pipe, is_out);
+	max = usb_maxpacket(dev, pipe, is_out);
 	if (max <= 0) {
 		dev_dbg(&dev->dev,
 			"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
-			usb_pipeendpoint (pipe), is_out ? "out" : "in",
+			usb_pipeendpoint(pipe), is_out ? "out" : "in",
 			__FUNCTION__, max);
 		return -EMSGSIZE;
 	}
@@ -279,11 +278,11 @@
 		if (urb->number_of_packets <= 0)		    
 			return -EINVAL;
 		for (n = 0; n < urb->number_of_packets; n++) {
-			len = urb->iso_frame_desc [n].length;
+			len = urb->iso_frame_desc[n].length;
 			if (len < 0 || len > max) 
 				return -EMSGSIZE;
-			urb->iso_frame_desc [n].status = -EXDEV;
-			urb->iso_frame_desc [n].actual_length = 0;
+			urb->iso_frame_desc[n].status = -EXDEV;
+			urb->iso_frame_desc[n].actual_length = 0;
 		}
 	}
 
@@ -322,7 +321,7 @@
 
 	/* fail if submitter gave bogus flags */
 	if (urb->transfer_flags != orig_flags) {
-		err ("BOGUS urb flags, %x --> %x",
+		err("BOGUS urb flags, %x --> %x",
 			orig_flags, urb->transfer_flags);
 		return -EINVAL;
 	}
@@ -373,7 +372,7 @@
 		urb->interval = temp;
 	}
 
-	return usb_hcd_submit_urb (urb, mem_flags);
+	return usb_hcd_submit_urb(urb, mem_flags);
 }
 
 /*-------------------------------------------------------------------*/
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 02426d0..3db721c 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -233,7 +233,7 @@
  * @parent: hub to which device is connected; null to allocate a root hub
  * @bus: bus used to access the device
  * @port1: one-based index of port; ignored for root hubs
- * Context: !in_interrupt ()
+ * Context: !in_interrupt()
  *
  * Only hub drivers (including virtual root hub drivers for host
  * controllers) should ever call this.
@@ -277,22 +277,22 @@
 	 * as stable:  bus->busnum changes easily from modprobe order,
 	 * cardbus or pci hotplugging, and so on.
 	 */
-	if (unlikely (!parent)) {
-		dev->devpath [0] = '0';
+	if (unlikely(!parent)) {
+		dev->devpath[0] = '0';
 
 		dev->dev.parent = bus->controller;
-		sprintf (&dev->dev.bus_id[0], "usb%d", bus->busnum);
+		sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
 	} else {
 		/* match any labeling on the hubs; it's one-based */
-		if (parent->devpath [0] == '0')
-			snprintf (dev->devpath, sizeof dev->devpath,
+		if (parent->devpath[0] == '0')
+			snprintf(dev->devpath, sizeof dev->devpath,
 				"%d", port1);
 		else
-			snprintf (dev->devpath, sizeof dev->devpath,
+			snprintf(dev->devpath, sizeof dev->devpath,
 				"%s.%d", parent->devpath, port1);
 
 		dev->dev.parent = &parent->dev;
-		sprintf (&dev->dev.bus_id[0], "%d-%s",
+		sprintf(&dev->dev.bus_id[0], "%d-%s",
 			bus->busnum, dev->devpath);
 
 		/* hub driver sets up TT records */
@@ -463,7 +463,7 @@
 	/* see if this device matches */
 	if ((vendor_id == le16_to_cpu(dev->descriptor.idVendor)) &&
 	    (product_id == le16_to_cpu(dev->descriptor.idProduct))) {
-		dev_dbg (&dev->dev, "matched this device!\n");
+		dev_dbg(&dev->dev, "matched this device!\n");
 		ret_dev = usb_get_dev(dev);
 		goto exit;
 	}
@@ -535,7 +535,7 @@
  */
 int usb_get_current_frame_number(struct usb_device *dev)
 {
-	return usb_hcd_get_frame_number (dev);
+	return usb_hcd_get_frame_number(dev);
 }
 
 /*-------------------------------------------------------------------*/
@@ -593,7 +593,7 @@
  *
  * When the buffer is no longer used, free it with usb_buffer_free().
  */
-void *usb_buffer_alloc (
+void *usb_buffer_alloc(
 	struct usb_device *dev,
 	size_t size,
 	gfp_t mem_flags,
@@ -602,7 +602,7 @@
 {
 	if (!dev || !dev->bus)
 		return NULL;
-	return hcd_buffer_alloc (dev->bus, size, mem_flags, dma);
+	return hcd_buffer_alloc(dev->bus, size, mem_flags, dma);
 }
 
 /**
@@ -616,7 +616,7 @@
  * been allocated using usb_buffer_alloc(), and the parameters must match
  * those provided in that allocation request. 
  */
-void usb_buffer_free (
+void usb_buffer_free(
 	struct usb_device *dev,
 	size_t size,
 	void *addr,
@@ -627,7 +627,7 @@
 		return;
 	if (!addr)
 		return;
-	hcd_buffer_free (dev->bus, size, addr, dma);
+	hcd_buffer_free(dev->bus, size, addr, dma);
 }
 
 /**
@@ -647,7 +647,7 @@
  * Reverse the effect of this call with usb_buffer_unmap().
  */
 #if 0
-struct urb *usb_buffer_map (struct urb *urb)
+struct urb *usb_buffer_map(struct urb *urb)
 {
 	struct usb_bus		*bus;
 	struct device		*controller;
@@ -659,14 +659,14 @@
 		return NULL;
 
 	if (controller->dma_mask) {
-		urb->transfer_dma = dma_map_single (controller,
+		urb->transfer_dma = dma_map_single(controller,
 			urb->transfer_buffer, urb->transfer_buffer_length,
-			usb_pipein (urb->pipe)
+			usb_pipein(urb->pipe)
 				? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-		if (usb_pipecontrol (urb->pipe))
-			urb->setup_dma = dma_map_single (controller,
+		if (usb_pipecontrol(urb->pipe))
+			urb->setup_dma = dma_map_single(controller,
 					urb->setup_packet,
-					sizeof (struct usb_ctrlrequest),
+					sizeof(struct usb_ctrlrequest),
 					DMA_TO_DEVICE);
 	// FIXME generic api broken like pci, can't report errors
 	// if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
@@ -689,7 +689,7 @@
  * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s)
  * @urb: urb whose transfer_buffer/setup_packet will be synchronized
  */
-void usb_buffer_dmasync (struct urb *urb)
+void usb_buffer_dmasync(struct urb *urb)
 {
 	struct usb_bus		*bus;
 	struct device		*controller;
@@ -702,14 +702,14 @@
 		return;
 
 	if (controller->dma_mask) {
-		dma_sync_single (controller,
+		dma_sync_single(controller,
 			urb->transfer_dma, urb->transfer_buffer_length,
-			usb_pipein (urb->pipe)
+			usb_pipein(urb->pipe)
 				? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-		if (usb_pipecontrol (urb->pipe))
-			dma_sync_single (controller,
+		if (usb_pipecontrol(urb->pipe))
+			dma_sync_single(controller,
 					urb->setup_dma,
-					sizeof (struct usb_ctrlrequest),
+					sizeof(struct usb_ctrlrequest),
 					DMA_TO_DEVICE);
 	}
 }
@@ -722,7 +722,7 @@
  * Reverses the effect of usb_buffer_map().
  */
 #if 0
-void usb_buffer_unmap (struct urb *urb)
+void usb_buffer_unmap(struct urb *urb)
 {
 	struct usb_bus		*bus;
 	struct device		*controller;
@@ -735,14 +735,14 @@
 		return;
 
 	if (controller->dma_mask) {
-		dma_unmap_single (controller,
+		dma_unmap_single(controller,
 			urb->transfer_dma, urb->transfer_buffer_length,
-			usb_pipein (urb->pipe)
+			usb_pipein(urb->pipe)
 				? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-		if (usb_pipecontrol (urb->pipe))
-			dma_unmap_single (controller,
+		if (usb_pipecontrol(urb->pipe))
+			dma_unmap_single(controller,
 					urb->setup_dma,
-					sizeof (struct usb_ctrlrequest),
+					sizeof(struct usb_ctrlrequest),
 					DMA_TO_DEVICE);
 	}
 	urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
@@ -783,15 +783,15 @@
 	struct device		*controller;
 
 	if (!dev
-			|| usb_pipecontrol (pipe)
+			|| usb_pipecontrol(pipe)
 			|| !(bus = dev->bus)
 			|| !(controller = bus->controller)
 			|| !controller->dma_mask)
 		return -1;
 
 	// FIXME generic api broken like pci, can't report errors
-	return dma_map_sg (controller, sg, nents,
-			usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+	return dma_map_sg(controller, sg, nents,
+			usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /* XXX DISABLED, no users currently.  If you wish to re-enable this
@@ -823,8 +823,8 @@
 			|| !controller->dma_mask)
 		return;
 
-	dma_sync_sg (controller, sg, n_hw_ents,
-			usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+	dma_sync_sg(controller, sg, n_hw_ents,
+			usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 #endif
 
@@ -849,8 +849,8 @@
 			|| !controller->dma_mask)
 		return;
 
-	dma_unmap_sg (controller, sg, n_hw_ents,
-			usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+	dma_unmap_sg(controller, sg, n_hw_ents,
+			usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /* format to disable USB on kernel command line is: nousb */
@@ -871,7 +871,7 @@
 {
 	int retval;
 	if (nousb) {
-		pr_info ("%s: USB support disabled\n", usbcore_name);
+		pr_info("%s: USB support disabled\n", usbcore_name);
 		return 0;
 	}
 
@@ -971,19 +971,19 @@
 EXPORT_SYMBOL(usb_find_device);
 EXPORT_SYMBOL(usb_get_current_frame_number);
 
-EXPORT_SYMBOL (usb_buffer_alloc);
-EXPORT_SYMBOL (usb_buffer_free);
+EXPORT_SYMBOL(usb_buffer_alloc);
+EXPORT_SYMBOL(usb_buffer_free);
 
 #if 0
-EXPORT_SYMBOL (usb_buffer_map);
-EXPORT_SYMBOL (usb_buffer_dmasync);
-EXPORT_SYMBOL (usb_buffer_unmap);
+EXPORT_SYMBOL(usb_buffer_map);
+EXPORT_SYMBOL(usb_buffer_dmasync);
+EXPORT_SYMBOL(usb_buffer_unmap);
 #endif
 
-EXPORT_SYMBOL (usb_buffer_map_sg);
+EXPORT_SYMBOL(usb_buffer_map_sg);
 #if 0
-EXPORT_SYMBOL (usb_buffer_dmasync_sg);
+EXPORT_SYMBOL(usb_buffer_dmasync_sg);
 #endif
-EXPORT_SYMBOL (usb_buffer_unmap_sg);
+EXPORT_SYMBOL(usb_buffer_unmap_sg);
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 812c733..f390501 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -39,7 +39,7 @@
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
 #include <linux/clk.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/byteorder.h>
@@ -1807,16 +1807,13 @@
 			|| !wake
 			|| at91_suspend_entering_slow_clock()) {
 		pullup(udc, 0);
-		disable_irq_wake(udc->udp_irq);
+		wake = 0;
 	} else
 		enable_irq_wake(udc->udp_irq);
 
-	if (udc->board.vbus_pin > 0) {
-		if (wake)
-			enable_irq_wake(udc->board.vbus_pin);
-		else
-			disable_irq_wake(udc->board.vbus_pin);
-	}
+	udc->active_suspend = wake;
+	if (udc->board.vbus_pin > 0 && wake)
+		enable_irq_wake(udc->board.vbus_pin);
 	return 0;
 }
 
@@ -1824,8 +1821,14 @@
 {
 	struct at91_udc *udc = platform_get_drvdata(pdev);
 
+	if (udc->board.vbus_pin > 0 && udc->active_suspend)
+		disable_irq_wake(udc->board.vbus_pin);
+
 	/* maybe reconnect to host; if so, clocks on */
-	pullup(udc, 1);
+	if (udc->active_suspend)
+		disable_irq_wake(udc->udp_irq);
+	else
+		pullup(udc, 1);
 	return 0;
 }
 #else
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
index 677089b..7e34e2f 100644
--- a/drivers/usb/gadget/at91_udc.h
+++ b/drivers/usb/gadget/at91_udc.h
@@ -136,6 +136,7 @@
 	unsigned			wait_for_addr_ack:1;
 	unsigned			wait_for_config_ack:1;
 	unsigned			selfpowered:1;
+	unsigned			active_suspend:1;
 	u8				addr;
 	struct at91_udc_data		board;
 	struct clk			*iclk, *fclk;
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index 83b4866..d18901b 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -24,7 +24,7 @@
 #include <linux/string.h>
 #include <linux/device.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 53d5845..f28af06 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -27,7 +27,7 @@
 #include <linux/ctype.h>
 #include <linux/string.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include "gadget_chips.h"
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index d15bf22..22e3c94 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -47,7 +47,7 @@
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb_gadget.h>
 
@@ -72,9 +72,18 @@
  *
  * There's some hardware that can't talk CDC.  We make that hardware
  * implement a "minimalist" vendor-agnostic CDC core:  same framing, but
- * link-level setup only requires activating the configuration.
- * Linux supports it, but other host operating systems may not.
- * (This is a subset of CDC Ethernet.)
+ * link-level setup only requires activating the configuration.  Only the
+ * endpoint descriptors, and product/vendor IDs, are relevant; no control
+ * operations are available.  Linux supports it, but other host operating
+ * systems may not.  (This is a subset of CDC Ethernet.)
+ *
+ * It turns out that if you add a few descriptors to that "CDC Subset",
+ * (Windows) host side drivers from MCCI can treat it as one submode of
+ * a proprietary scheme called "SAFE" ... without needing to know about
+ * specific product/vendor IDs.  So we do that, making it easier to use
+ * those MS-Windows drivers.  Those added descriptors make it resemble a
+ * CDC MDLM device, but they don't change device behavior at all.  (See
+ * MCCI Engineering report 950198 "SAFE Networking Functions".)
  *
  * A third option is also in use.  Rather than CDC Ethernet, or something
  * simpler, Microsoft pushes their own approach: RNDIS.  The published
@@ -254,6 +263,10 @@
 #define DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_S3C2410
+#define DEV_CONFIG_CDC
+#endif
+
 #ifdef CONFIG_USB_GADGET_AT91
 #define DEV_CONFIG_CDC
 #endif
@@ -266,6 +279,10 @@
 #define DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#define DEV_CONFIG_CDC
+#endif
+
 
 /* For CDC-incapable hardware, choose the simple cdc subset.
  * Anything that talks bulk (without notable bugs) can do this.
@@ -283,9 +300,6 @@
 #define	DEV_CONFIG_SUBSET
 #endif
 
-#ifdef CONFIG_USB_GADGET_S3C2410
-#define DEV_CONFIG_CDC
-#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -487,8 +501,17 @@
  * endpoint.  Both have a "data" interface and two bulk endpoints.
  * There are also differences in how control requests are handled.
  *
- * RNDIS shares a lot with CDC-Ethernet, since it's a variant of
- * the CDC-ACM (modem) spec.
+ * RNDIS shares a lot with CDC-Ethernet, since it's a variant of the
+ * CDC-ACM (modem) spec.  Unfortunately MSFT's RNDIS driver is buggy; it
+ * may hang or oops.  Since bugfixes (or accurate specs, letting Linux
+ * work around those bugs) are unlikely to ever come from MSFT, you may
+ * wish to avoid using RNDIS.
+ *
+ * MCCI offers an alternative to RNDIS if you need to connect to Windows
+ * but have hardware that can't support CDC Ethernet.   We add descriptors
+ * to present the CDC Subset as a (nonconformant) CDC MDLM variant called
+ * "SAFE".  That borrows from both CDC Ethernet and CDC MDLM.  You can
+ * get those drivers from MCCI, or bundled with various products.
  */
 
 #ifdef	DEV_CONFIG_CDC
@@ -522,8 +545,6 @@
 };
 #endif
 
-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-
 static const struct usb_cdc_header_desc header_desc = {
 	.bLength =		sizeof header_desc,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
@@ -532,6 +553,8 @@
 	.bcdCDC =		__constant_cpu_to_le16 (0x0110),
 };
 
+#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+
 static const struct usb_cdc_union_desc union_desc = {
 	.bLength =		sizeof union_desc,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
@@ -564,7 +587,40 @@
 
 #endif
 
-#ifdef	DEV_CONFIG_CDC
+#ifndef DEV_CONFIG_CDC
+
+/* "SAFE" loosely follows CDC WMC MDLM, violating the spec in various
+ * ways:  data endpoints live in the control interface, there's no data
+ * interface, and it's not used to talk to a cell phone radio.
+ */
+
+static const struct usb_cdc_mdlm_desc mdlm_desc = {
+	.bLength =		sizeof mdlm_desc,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_MDLM_TYPE,
+
+	.bcdVersion =		__constant_cpu_to_le16(0x0100),
+	.bGUID = {
+		0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
+		0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
+	},
+};
+
+/* since "usb_cdc_mdlm_detail_desc" is a variable length structure, we
+ * can't really use its struct.  All we do here is say that we're using
+ * the submode of "SAFE" which directly matches the CDC Subset.
+ */
+static const u8 mdlm_detail_desc[] = {
+	6,
+	USB_DT_CS_INTERFACE,
+	USB_CDC_MDLM_DETAIL_TYPE,
+
+	0,	/* "SAFE" */
+	0,	/* network control capabilities (none) */
+	0,	/* network data capabilities ("raw" encapsulation) */
+};
+
+#endif
 
 static const struct usb_cdc_ether_desc ether_desc = {
 	.bLength =		sizeof ether_desc,
@@ -579,7 +635,6 @@
 	.bNumberPowerFilters =	0,
 };
 
-#endif
 
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
 
@@ -672,6 +727,9 @@
 /*
  * "Simple" CDC-subset option is a simple vendor-neutral model that most
  * full speed controllers can handle:  one interface, two bulk endpoints.
+ *
+ * To assist host side drivers, we fancy it up a bit, and add descriptors
+ * so some host side drivers will understand it as a "SAFE" variant.
  */
 
 static const struct usb_interface_descriptor
@@ -682,8 +740,8 @@
 	.bInterfaceNumber =	0,
 	.bAlternateSetting =	0,
 	.bNumEndpoints =	2,
-	.bInterfaceClass =	USB_CLASS_VENDOR_SPEC,
-	.bInterfaceSubClass =	0,
+	.bInterfaceClass =      USB_CLASS_COMM,
+	.bInterfaceSubClass =	USB_CDC_SUBCLASS_MDLM,
 	.bInterfaceProtocol =	0,
 	.iInterface =		STRING_DATA,
 };
@@ -731,10 +789,15 @@
 static inline void __init fs_subset_descriptors(void)
 {
 #ifdef DEV_CONFIG_SUBSET
+	/* behavior is "CDC Subset"; extra descriptors say "SAFE" */
 	fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
-	fs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
-	fs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
-	fs_eth_function[4] = NULL;
+	fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+	fs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+	fs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+	fs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+	fs_eth_function[6] = (struct usb_descriptor_header *) &fs_source_desc;
+	fs_eth_function[7] = (struct usb_descriptor_header *) &fs_sink_desc;
+	fs_eth_function[8] = NULL;
 #else
 	fs_eth_function[1] = NULL;
 #endif
@@ -828,10 +891,15 @@
 static inline void __init hs_subset_descriptors(void)
 {
 #ifdef DEV_CONFIG_SUBSET
+	/* behavior is "CDC Subset"; extra descriptors say "SAFE" */
 	hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
-	hs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
-	hs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
-	hs_eth_function[4] = NULL;
+	hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+	hs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+	hs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+	hs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+	hs_eth_function[6] = (struct usb_descriptor_header *) &hs_source_desc;
+	hs_eth_function[7] = (struct usb_descriptor_header *) &hs_sink_desc;
+	hs_eth_function[8] = NULL;
 #else
 	hs_eth_function[1] = NULL;
 #endif
@@ -878,10 +946,8 @@
 static char				product_desc [40] = DRIVER_DESC;
 static char				serial_number [20];
 
-#ifdef	DEV_CONFIG_CDC
 /* address that the host will use ... usually assigned at random */
 static char				ethaddr [2 * ETH_ALEN + 1];
-#endif
 
 /* static strings, in UTF-8 */
 static struct usb_string		strings [] = {
@@ -889,9 +955,9 @@
 	{ STRING_PRODUCT,	product_desc, },
 	{ STRING_SERIALNUMBER,	serial_number, },
 	{ STRING_DATA,		"Ethernet Data", },
+	{ STRING_ETHADDR,	ethaddr, },
 #ifdef	DEV_CONFIG_CDC
 	{ STRING_CDC,		"CDC Ethernet", },
-	{ STRING_ETHADDR,	ethaddr, },
 	{ STRING_CONTROL,	"CDC Communications Control", },
 #endif
 #ifdef	DEV_CONFIG_SUBSET
@@ -986,10 +1052,10 @@
 	}
 #endif
 
-	dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
+	dev->in = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
 	dev->in_ep->driver_data = dev;
 
-	dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
+	dev->out = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
 	dev->out_ep->driver_data = dev;
 
 	/* With CDC,  the host isn't allowed to use these two data
@@ -2278,10 +2344,10 @@
 			"RNDIS/%s", driver_desc);
 
 	/* CDC subset ... recognized by Linux since 2.4.10, but Windows
-	 * drivers aren't widely available.
+	 * drivers aren't widely available.  (That may be improved by
+	 * supporting one submode of the "SAFE" variant of MDLM.)
 	 */
 	} else if (!cdc) {
-		device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
 		device_desc.idVendor =
 			__constant_cpu_to_le16(SIMPLE_VENDOR_NUM);
 		device_desc.idProduct =
@@ -2352,6 +2418,10 @@
 	if (!cdc) {
 		eth_config.bNumInterfaces = 1;
 		eth_config.iConfiguration = STRING_SUBSET;
+
+		/* use functions to set these up, in case we're built to work
+		 * with multiple controllers and must override CDC Ethernet.
+		 */
 		fs_subset_descriptors();
 		hs_subset_descriptors();
 	}
@@ -2415,22 +2485,20 @@
 
 	/* Module params for these addresses should come from ID proms.
 	 * The host side address is used with CDC and RNDIS, and commonly
-	 * ends up in a persistent config database.
+	 * ends up in a persistent config database.  It's not clear if
+	 * host side code for the SAFE thing cares -- its original BLAN
+	 * thing didn't, Sharp never assigned those addresses on Zaurii.
 	 */
 	if (get_ether_addr(dev_addr, net->dev_addr))
 		dev_warn(&gadget->dev,
 			"using random %s ethernet address\n", "self");
-	if (cdc || rndis) {
-		if (get_ether_addr(host_addr, dev->host_mac))
-			dev_warn(&gadget->dev,
-				"using random %s ethernet address\n", "host");
-#ifdef	DEV_CONFIG_CDC
-		snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
-			dev->host_mac [0], dev->host_mac [1],
-			dev->host_mac [2], dev->host_mac [3],
-			dev->host_mac [4], dev->host_mac [5]);
-#endif
-	}
+	if (get_ether_addr(host_addr, dev->host_mac))
+		dev_warn(&gadget->dev,
+			"using random %s ethernet address\n", "host");
+	snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
+		dev->host_mac [0], dev->host_mac [1],
+		dev->host_mac [2], dev->host_mac [3],
+		dev->host_mac [4], dev->host_mac [5]);
 
 	if (rndis) {
 		status = rndis_init();
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 72f2ae9..f04a29a 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -253,7 +253,7 @@
 #include <linux/freezer.h>
 #include <linux/utsname.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include "gadget_chips.h"
@@ -1148,7 +1148,7 @@
 
 static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
 {
-	struct fsg_dev		*fsg = (struct fsg_dev *) ep->driver_data;
+	struct fsg_dev		*fsg = ep->driver_data;
 
 	if (req->actual > 0)
 		dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
@@ -1170,8 +1170,8 @@
 
 static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
 {
-	struct fsg_dev		*fsg = (struct fsg_dev *) ep->driver_data;
-	struct fsg_buffhd	*bh = (struct fsg_buffhd *) req->context;
+	struct fsg_dev		*fsg = ep->driver_data;
+	struct fsg_buffhd	*bh = req->context;
 
 	if (req->status || req->actual != req->length)
 		DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
@@ -1190,8 +1190,8 @@
 
 static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
 {
-	struct fsg_dev		*fsg = (struct fsg_dev *) ep->driver_data;
-	struct fsg_buffhd	*bh = (struct fsg_buffhd *) req->context;
+	struct fsg_dev		*fsg = ep->driver_data;
+	struct fsg_buffhd	*bh = req->context;
 
 	dump_msg(fsg, "bulk-out", req->buf, req->actual);
 	if (req->status || req->actual != bh->bulk_out_intended_length)
@@ -1214,8 +1214,8 @@
 #ifdef CONFIG_USB_FILE_STORAGE_TEST
 static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
 {
-	struct fsg_dev		*fsg = (struct fsg_dev *) ep->driver_data;
-	struct fsg_buffhd	*bh = (struct fsg_buffhd *) req->context;
+	struct fsg_dev		*fsg = ep->driver_data;
+	struct fsg_buffhd	*bh = req->context;
 
 	if (req->status || req->actual != req->length)
 		DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
@@ -2577,7 +2577,7 @@
 	}
 
 	if (transport_is_bbb()) {
-		struct bulk_cs_wrap	*csw = (struct bulk_cs_wrap *) bh->buf;
+		struct bulk_cs_wrap	*csw = bh->buf;
 
 		/* Store and send the Bulk-only CSW */
 		csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG);
@@ -2596,8 +2596,7 @@
 		return 0;
 
 	} else {			// USB_PR_CBI
-		struct interrupt_data	*buf = (struct interrupt_data *)
-						bh->buf;
+		struct interrupt_data	*buf = bh->buf;
 
 		/* Store and send the Interrupt data.  UFI sends the ASC
 		 * and ASCQ bytes.  Everything else sends a Type (which
@@ -2982,7 +2981,7 @@
 static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
 {
 	struct usb_request	*req = bh->outreq;
-	struct bulk_cb_wrap	*cbw = (struct bulk_cb_wrap *) req->buf;
+	struct bulk_cb_wrap	*cbw = req->buf;
 
 	/* Was this a real packet? */
 	if (req->status)
@@ -3428,7 +3427,7 @@
 
 static int fsg_main_thread(void *fsg_)
 {
-	struct fsg_dev		*fsg = (struct fsg_dev *) fsg_;
+	struct fsg_dev		*fsg = fsg_;
 
 	/* Allow the thread to be killed by a signal, but set the signal mask
 	 * to block everything but INT, TERM, KILL, and USR1. */
@@ -3600,7 +3599,7 @@
 static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct lun	*curlun = dev_to_lun(dev);
-	struct fsg_dev	*fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+	struct fsg_dev	*fsg = dev_get_drvdata(dev);
 	char		*p;
 	ssize_t		rc;
 
@@ -3629,7 +3628,7 @@
 {
 	ssize_t		rc = count;
 	struct lun	*curlun = dev_to_lun(dev);
-	struct fsg_dev	*fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+	struct fsg_dev	*fsg = dev_get_drvdata(dev);
 	int		i;
 
 	if (sscanf(buf, "%d", &i) != 1)
@@ -3652,7 +3651,7 @@
 static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct lun	*curlun = dev_to_lun(dev);
-	struct fsg_dev	*fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+	struct fsg_dev	*fsg = dev_get_drvdata(dev);
 	int		rc = 0;
 
 	if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) {
@@ -3700,7 +3699,7 @@
 
 static void lun_release(struct device *dev)
 {
-	struct fsg_dev	*fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+	struct fsg_dev	*fsg = dev_get_drvdata(dev);
 
 	kref_put(&fsg->ref, fsg_release);
 }
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index aa80f09..2e3d662 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -75,6 +75,12 @@
 #define	gadget_is_pxa27x(g)	0
 #endif
 
+#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#define gadget_is_husb2dev(g)	!strcmp("husb2_udc", (g)->name)
+#else
+#define gadget_is_husb2dev(g)	0
+#endif
+
 #ifdef CONFIG_USB_GADGET_S3C2410
 #define gadget_is_s3c2410(g)    !strcmp("s3c2410_udc", (g)->name)
 #else
@@ -169,5 +175,7 @@
 		return 0x16;
 	else if (gadget_is_mpc8272(gadget))
 		return 0x17;
+	else if (gadget_is_husb2dev(gadget))
+		return 0x18;
 	return -ENOENT;
 }
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index f1a67965..d08a8d0 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -35,7 +35,7 @@
 #include <sound/initval.h>
 #include <sound/rawmidi.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb/audio.h>
 #include <linux/usb/midi.h>
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index d0ef1d6..e873cf4 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -39,7 +39,7 @@
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
 #include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/byteorder.h>
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 3fb1044a..34296e7 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -20,7 +20,7 @@
  */
 
 
-// #define	DEBUG 			/* data to help fault diagnosis */
+// #define	DEBUG			/* data to help fault diagnosis */
 // #define	VERBOSE		/* extra debug messages (success too) */
 
 #include <linux/init.h>
@@ -59,11 +59,11 @@
  *   may serve as a source of device events, used to handle all control
  *   requests other than basic enumeration.
  *
- * - Then either immediately, or after a SET_CONFIGURATION control request,
- *   ep_config() is called when each /dev/gadget/ep* file is configured
- *   (by writing endpoint descriptors).  Afterwards these files are used
- *   to write() IN data or to read() OUT data.  To halt the endpoint, a
- *   "wrong direction" request is issued (like reading an IN endpoint).
+ * - Then, after a SET_CONFIGURATION control request, ep_config() is
+ *   called when each /dev/gadget/ep* file is configured (by writing
+ *   endpoint descriptors).  Afterwards these files are used to write()
+ *   IN data or to read() OUT data.  To halt the endpoint, a "wrong
+ *   direction" request is issued (like reading an IN endpoint).
  *
  * Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe
  * not possible on all hardware.  For example, precise fault handling with
@@ -98,16 +98,16 @@
 	 * must always write descriptors to initialize the device, then
 	 * the device becomes UNCONNECTED until enumeration.
 	 */
-	STATE_OPENED,
+	STATE_DEV_OPENED,
 
 	/* From then on, ep0 fd is in either of two basic modes:
 	 * - (UN)CONNECTED: read usb_gadgetfs_event(s) from it
 	 * - SETUP: read/write will transfer control data and succeed;
 	 *   or if "wrong direction", performs protocol stall
 	 */
-	STATE_UNCONNECTED,
-	STATE_CONNECTED,
-	STATE_SETUP,
+	STATE_DEV_UNCONNECTED,
+	STATE_DEV_CONNECTED,
+	STATE_DEV_SETUP,
 
 	/* UNBOUND means the driver closed ep0, so the device won't be
 	 * accessible again (DEV_DISABLED) until all fds are closed.
@@ -121,7 +121,7 @@
 struct dev_data {
 	spinlock_t			lock;
 	atomic_t			count;
-	enum ep0_state			state;
+	enum ep0_state			state;		/* P: lock */
 	struct usb_gadgetfs_event	event [N_EVENT];
 	unsigned			ev_next;
 	struct fasync_struct		*fasync;
@@ -188,7 +188,6 @@
 enum ep_state {
 	STATE_EP_DISABLED = 0,
 	STATE_EP_READY,
-	STATE_EP_DEFER_ENABLE,
 	STATE_EP_ENABLED,
 	STATE_EP_UNBOUND,
 };
@@ -313,18 +312,10 @@
 
 	if ((val = down_interruptible (&epdata->lock)) < 0)
 		return val;
-newstate:
+
 	switch (epdata->state) {
 	case STATE_EP_ENABLED:
 		break;
-	case STATE_EP_DEFER_ENABLE:
-		DBG (epdata->dev, "%s wait for host\n", epdata->name);
-		if ((val = wait_event_interruptible (epdata->wait, 
-				epdata->state != STATE_EP_DEFER_ENABLE
-				|| epdata->dev->state == STATE_DEV_UNBOUND
-				)) < 0)
-			goto fail;
-		goto newstate;
 	// case STATE_EP_DISABLED:		/* "can't happen" */
 	// case STATE_EP_READY:			/* "can't happen" */
 	default:				/* error! */
@@ -333,7 +324,6 @@
 		// FALLTHROUGH
 	case STATE_EP_UNBOUND:			/* clean disconnect */
 		val = -ENODEV;
-fail:
 		up (&epdata->lock);
 	}
 	return val;
@@ -565,29 +555,28 @@
 	ssize_t			len, total;
 	int			i;
 
-  	/* we "retry" to get the right mm context for this: */
+	/* we "retry" to get the right mm context for this: */
 
- 	/* copy stuff into user buffers */
- 	total = priv->actual;
- 	len = 0;
- 	for (i=0; i < priv->nr_segs; i++) {
- 		ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
+	/* copy stuff into user buffers */
+	total = priv->actual;
+	len = 0;
+	for (i=0; i < priv->nr_segs; i++) {
+		ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
 
- 		if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
- 			if (len == 0)
- 				len = -EFAULT;
- 			break;
- 		}
+		if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
+			if (len == 0)
+				len = -EFAULT;
+			break;
+		}
 
- 		total -= this;
- 		len += this;
- 		if (total == 0)
- 			break;
- 	}
-  	kfree(priv->buf);
-  	kfree(priv);
-  	aio_put_req(iocb);
- 	return len;
+		total -= this;
+		len += this;
+		if (total == 0)
+			break;
+	}
+	kfree(priv->buf);
+	kfree(priv);
+	return len;
 }
 
 static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
@@ -600,18 +589,17 @@
 	spin_lock(&epdata->dev->lock);
 	priv->req = NULL;
 	priv->epdata = NULL;
-	if (priv->iv == NULL
-			|| unlikely(req->actual == 0)
-			|| unlikely(kiocbIsCancelled(iocb))) {
+
+	/* if this was a write or a read returning no data then we
+	 * don't need to copy anything to userspace, so we can
+	 * complete the aio request immediately.
+	 */
+	if (priv->iv == NULL || unlikely(req->actual == 0)) {
 		kfree(req->buf);
 		kfree(priv);
 		iocb->private = NULL;
 		/* aio_complete() reports bytes-transferred _and_ faults */
-		if (unlikely(kiocbIsCancelled(iocb)))
-			aio_put_req(iocb);
-		else
-			aio_complete(iocb,
-				req->actual ? req->actual : req->status,
+		aio_complete(iocb, req->actual ? req->actual : req->status,
 				req->status);
 	} else {
 		/* retry() won't report both; so we hide some faults */
@@ -636,7 +624,7 @@
 	size_t		len,
 	struct ep_data	*epdata,
 	const struct iovec *iv,
-	unsigned long 	nr_segs
+	unsigned long	nr_segs
 )
 {
 	struct kiocb_priv	*priv;
@@ -852,9 +840,9 @@
 		break;
 #endif
 	default:
-		DBG (data->dev, "unconnected, %s init deferred\n",
+		DBG(data->dev, "unconnected, %s init abandoned\n",
 				data->name);
-		data->state = STATE_EP_DEFER_ENABLE;
+		value = -EINVAL;
 	}
 	if (value == 0) {
 		fd->f_op = &ep_io_operations;
@@ -943,22 +931,24 @@
 static void ep0_complete (struct usb_ep *ep, struct usb_request *req)
 {
 	struct dev_data		*dev = ep->driver_data;
+	unsigned long		flags;
 	int			free = 1;
 
 	/* for control OUT, data must still get to userspace */
+	spin_lock_irqsave(&dev->lock, flags);
 	if (!dev->setup_in) {
 		dev->setup_out_error = (req->status != 0);
 		if (!dev->setup_out_error)
 			free = 0;
 		dev->setup_out_ready = 1;
 		ep0_readable (dev);
-	} else if (dev->state == STATE_SETUP)
-		dev->state = STATE_CONNECTED;
+	}
 
 	/* clean up as appropriate */
 	if (free && req->buf != &dev->rbuf)
 		clean_req (ep, req);
 	req->complete = epio_complete;
+	spin_unlock_irqrestore(&dev->lock, flags);
 }
 
 static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
@@ -998,13 +988,13 @@
 	}
 
 	/* control DATA stage */
-	if ((state = dev->state) == STATE_SETUP) {
+	if ((state = dev->state) == STATE_DEV_SETUP) {
 
 		if (dev->setup_in) {		/* stall IN */
 			VDEBUG(dev, "ep0in stall\n");
 			(void) usb_ep_set_halt (dev->gadget->ep0);
 			retval = -EL2HLT;
-			dev->state = STATE_CONNECTED;
+			dev->state = STATE_DEV_CONNECTED;
 
 		} else if (len == 0) {		/* ack SET_CONFIGURATION etc */
 			struct usb_ep		*ep = dev->gadget->ep0;
@@ -1012,7 +1002,7 @@
 
 			if ((retval = setup_req (ep, req, 0)) == 0)
 				retval = usb_ep_queue (ep, req, GFP_ATOMIC);
-			dev->state = STATE_CONNECTED;
+			dev->state = STATE_DEV_CONNECTED;
 
 			/* assume that was SET_CONFIGURATION */
 			if (dev->current_config) {
@@ -1040,6 +1030,13 @@
 			spin_lock_irq (&dev->lock);
 			if (retval)
 				goto done;
+
+			if (dev->state != STATE_DEV_SETUP) {
+				retval = -ECANCELED;
+				goto done;
+			}
+			dev->state = STATE_DEV_CONNECTED;
+
 			if (dev->setup_out_error)
 				retval = -EIO;
 			else {
@@ -1066,39 +1063,36 @@
 	/* return queued events right away */
 	if (dev->ev_next != 0) {
 		unsigned		i, n;
-		int			tmp = dev->ev_next;
 
-		len = min (len, tmp * sizeof (struct usb_gadgetfs_event));
 		n = len / sizeof (struct usb_gadgetfs_event);
+		if (dev->ev_next < n)
+			n = dev->ev_next;
 
-		/* ep0 can't deliver events when STATE_SETUP */
+		/* ep0 i/o has special semantics during STATE_DEV_SETUP */
 		for (i = 0; i < n; i++) {
 			if (dev->event [i].type == GADGETFS_SETUP) {
-				len = i + 1;
-				len *= sizeof (struct usb_gadgetfs_event);
-				n = 0;
+				dev->state = STATE_DEV_SETUP;
+				n = i + 1;
 				break;
 			}
 		}
 		spin_unlock_irq (&dev->lock);
+		len = n * sizeof (struct usb_gadgetfs_event);
 		if (copy_to_user (buf, &dev->event, len))
 			retval = -EFAULT;
 		else
 			retval = len;
 		if (len > 0) {
-			len /= sizeof (struct usb_gadgetfs_event);
-
 			/* NOTE this doesn't guard against broken drivers;
 			 * concurrent ep0 readers may lose events.
 			 */
 			spin_lock_irq (&dev->lock);
-			dev->ev_next -= len;
-			if (dev->ev_next != 0)
-				memmove (&dev->event, &dev->event [len],
+			if (dev->ev_next > n) {
+				memmove(&dev->event[0], &dev->event[n],
 					sizeof (struct usb_gadgetfs_event)
-						* (tmp - len));
-			if (n == 0)
-				dev->state = STATE_SETUP;
+						* (dev->ev_next - n));
+			}
+			dev->ev_next -= n;
 			spin_unlock_irq (&dev->lock);
 		}
 		return retval;
@@ -1113,8 +1107,8 @@
 		DBG (dev, "fail %s, state %d\n", __FUNCTION__, state);
 		retval = -ESRCH;
 		break;
-	case STATE_UNCONNECTED:
-	case STATE_CONNECTED:
+	case STATE_DEV_UNCONNECTED:
+	case STATE_DEV_CONNECTED:
 		spin_unlock_irq (&dev->lock);
 		DBG (dev, "%s wait\n", __FUNCTION__);
 
@@ -1141,7 +1135,7 @@
 	switch (type) {
 	/* these events purge the queue */
 	case GADGETFS_DISCONNECT:
-		if (dev->state == STATE_SETUP)
+		if (dev->state == STATE_DEV_SETUP)
 			dev->setup_abort = 1;
 		// FALL THROUGH
 	case GADGETFS_CONNECT:
@@ -1153,7 +1147,7 @@
 		for (i = 0; i != dev->ev_next; i++) {
 			if (dev->event [i].type != type)
 				continue;
-			DBG (dev, "discard old event %d\n", type);
+			DBG(dev, "discard old event[%d] %d\n", i, type);
 			dev->ev_next--;
 			if (i == dev->ev_next)
 				break;
@@ -1166,9 +1160,9 @@
 	default:
 		BUG ();
 	}
+	VDEBUG(dev, "event[%d] = %d\n", dev->ev_next, type);
 	event = &dev->event [dev->ev_next++];
 	BUG_ON (dev->ev_next > N_EVENT);
-	VDEBUG (dev, "ev %d, next %d\n", type, dev->ev_next);
 	memset (event, 0, sizeof *event);
 	event->type = type;
 	return event;
@@ -1188,12 +1182,13 @@
 		retval = -EIDRM;
 
 	/* data and/or status stage for control request */
-	} else if (dev->state == STATE_SETUP) {
+	} else if (dev->state == STATE_DEV_SETUP) {
 
 		/* IN DATA+STATUS caller makes len <= wLength */
 		if (dev->setup_in) {
 			retval = setup_req (dev->gadget->ep0, dev->req, len);
 			if (retval == 0) {
+				dev->state = STATE_DEV_CONNECTED;
 				spin_unlock_irq (&dev->lock);
 				if (copy_from_user (dev->req->buf, buf, len))
 					retval = -EFAULT;
@@ -1219,7 +1214,7 @@
 			VDEBUG(dev, "ep0out stall\n");
 			(void) usb_ep_set_halt (dev->gadget->ep0);
 			retval = -EL2HLT;
-			dev->state = STATE_CONNECTED;
+			dev->state = STATE_DEV_CONNECTED;
 		} else {
 			DBG(dev, "bogus ep0out stall!\n");
 		}
@@ -1261,7 +1256,9 @@
 	put_dev (dev);
 
 	/* other endpoints were all decoupled from this device */
+	spin_lock_irq(&dev->lock);
 	dev->state = STATE_DEV_DISABLED;
+	spin_unlock_irq(&dev->lock);
 	return 0;
 }
 
@@ -1282,7 +1279,7 @@
                goto out;
        }
 
-       if (dev->state == STATE_SETUP) {
+       if (dev->state == STATE_DEV_SETUP) {
                if (dev->setup_in || dev->setup_can_stall)
                        mask = POLLOUT;
        } else {
@@ -1392,52 +1389,29 @@
 
 	spin_lock (&dev->lock);
 	dev->setup_abort = 0;
-	if (dev->state == STATE_UNCONNECTED) {
-		struct usb_ep	*ep;
-		struct ep_data	*data;
-
-		dev->state = STATE_CONNECTED;
-		dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
-
+	if (dev->state == STATE_DEV_UNCONNECTED) {
 #ifdef	CONFIG_USB_GADGET_DUALSPEED
 		if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) {
+			spin_unlock(&dev->lock);
 			ERROR (dev, "no high speed config??\n");
 			return -EINVAL;
 		}
 #endif	/* CONFIG_USB_GADGET_DUALSPEED */
 
+		dev->state = STATE_DEV_CONNECTED;
+		dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
+
 		INFO (dev, "connected\n");
 		event = next_event (dev, GADGETFS_CONNECT);
 		event->u.speed = gadget->speed;
 		ep0_readable (dev);
 
-		list_for_each_entry (ep, &gadget->ep_list, ep_list) {
-			data = ep->driver_data;
-			/* ... down_trylock (&data->lock) ... */
-			if (data->state != STATE_EP_DEFER_ENABLE)
-				continue;
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-			if (gadget->speed == USB_SPEED_HIGH)
-				value = usb_ep_enable (ep, &data->hs_desc);
-			else
-#endif	/* CONFIG_USB_GADGET_DUALSPEED */
-				value = usb_ep_enable (ep, &data->desc);
-			if (value) {
-				ERROR (dev, "deferred %s enable --> %d\n",
-					data->name, value);
-				continue;
-			}
-			data->state = STATE_EP_ENABLED;
-			wake_up (&data->wait);
-			DBG (dev, "woke up %s waiters\n", data->name);
-		}
-
 	/* host may have given up waiting for response.  we can miss control
 	 * requests handled lower down (device/endpoint status and features);
 	 * then ep0_{read,write} will report the wrong status. controller
 	 * driver will have aborted pending i/o.
 	 */
-	} else if (dev->state == STATE_SETUP)
+	} else if (dev->state == STATE_DEV_SETUP)
 		dev->setup_abort = 1;
 
 	req->buf = dev->rbuf;
@@ -1583,7 +1557,7 @@
 	}
 
 	/* proceed with data transfer and status phases? */
-	if (value >= 0 && dev->state != STATE_SETUP) {
+	if (value >= 0 && dev->state != STATE_DEV_SETUP) {
 		req->length = value;
 		req->zero = value < w_length;
 		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
@@ -1747,7 +1721,9 @@
 		goto enomem;
 
 	INFO (dev, "bound to %s driver\n", gadget->name);
-	dev->state = STATE_UNCONNECTED;
+	spin_lock_irq(&dev->lock);
+	dev->state = STATE_DEV_UNCONNECTED;
+	spin_unlock_irq(&dev->lock);
 	get_dev (dev);
 	return 0;
 
@@ -1762,11 +1738,9 @@
 	struct dev_data		*dev = get_gadget_data (gadget);
 
 	spin_lock (&dev->lock);
-	if (dev->state == STATE_UNCONNECTED) {
-		DBG (dev, "already unconnected\n");
+	if (dev->state == STATE_DEV_UNCONNECTED)
 		goto exit;
-	}
-	dev->state = STATE_UNCONNECTED;
+	dev->state = STATE_DEV_UNCONNECTED;
 
 	INFO (dev, "disconnected\n");
 	next_event (dev, GADGETFS_DISCONNECT);
@@ -1783,9 +1757,9 @@
 	INFO (dev, "suspended from state %d\n", dev->state);
 	spin_lock (&dev->lock);
 	switch (dev->state) {
-	case STATE_SETUP:		// VERY odd... host died??
-	case STATE_CONNECTED:
-	case STATE_UNCONNECTED:
+	case STATE_DEV_SETUP:		// VERY odd... host died??
+	case STATE_DEV_CONNECTED:
+	case STATE_DEV_UNCONNECTED:
 		next_event (dev, GADGETFS_SUSPEND);
 		ep0_readable (dev);
 		/* FALLTHROUGH */
@@ -1808,7 +1782,7 @@
 	.disconnect	= gadgetfs_disconnect,
 	.suspend	= gadgetfs_suspend,
 
-	.driver 	= {
+	.driver	= {
 		.name		= (char *) shortname,
 	},
 };
@@ -1829,7 +1803,7 @@
 	.unbind		= gadgetfs_nop,
 	.setup		= (void *)gadgetfs_nop,
 	.disconnect	= gadgetfs_nop,
-	.driver 	= {
+	.driver	= {
 		.name		= "nop",
 	},
 };
@@ -1849,19 +1823,16 @@
  * . full/low speed config ... all wTotalLength bytes (with interface,
  *	class, altsetting, endpoint, and other descriptors)
  * . high speed config ... all descriptors, for high speed operation;
- * 	this one's optional except for high-speed hardware
+ *	this one's optional except for high-speed hardware
  * . device descriptor
  *
- * Endpoints are not yet enabled. Drivers may want to immediately
- * initialize them, using the /dev/gadget/ep* files that are available
- * as soon as the kernel sees the configuration, or they can wait
- * until device configuration and interface altsetting changes create
+ * Endpoints are not yet enabled. Drivers must wait until device
+ * configuration and interface altsetting changes create
  * the need to configure (or unconfigure) them.
  *
  * After initialization, the device stays active for as long as that
- * $CHIP file is open.  Events may then be read from that descriptor,
- * such as configuration notifications.  More complex drivers will handle
- * some control requests in user space.
+ * $CHIP file is open.  Events must then be read from that descriptor,
+ * such as configuration notifications.
  */
 
 static int is_valid_config (struct usb_config_descriptor *config)
@@ -1884,9 +1855,6 @@
 	u32			tag;
 	char			*kbuf;
 
-	if (dev->state != STATE_OPENED)
-		return -EEXIST;
-
 	if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4))
 		return -EINVAL;
 
@@ -1978,13 +1946,15 @@
 	struct dev_data		*dev = inode->i_private;
 	int			value = -EBUSY;
 
+	spin_lock_irq(&dev->lock);
 	if (dev->state == STATE_DEV_DISABLED) {
 		dev->ev_next = 0;
-		dev->state = STATE_OPENED;
+		dev->state = STATE_DEV_OPENED;
 		fd->private_data = dev;
 		get_dev (dev);
 		value = 0;
 	}
+	spin_unlock_irq(&dev->lock);
 	return value;
 }
 
diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h
index e3bb785..b3fe197 100644
--- a/drivers/usb/gadget/lh7a40x_udc.h
+++ b/drivers/usb/gadget/lh7a40x_udc.h
@@ -49,7 +49,7 @@
 #include <asm/unaligned.h>
 #include <asm/hardware.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 /*
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 569eb8c..7617ff7 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -63,7 +63,7 @@
 #include <linux/interrupt.h>
 #include <linux/moduleparam.h>
 #include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/byteorder.h>
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index cdcfd42..1401043 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -38,7 +38,7 @@
 #include <linux/mm.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index b78de96..0d22536 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -56,7 +56,7 @@
 #include <asm/arch/pxa-regs.h>
 #endif
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/arch/udc.h>
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index f8a3ec6..6c742a9 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -43,7 +43,7 @@
 #include <asm/unaligned.h>
 #include <asm/uaccess.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb_gadget.h>
 
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index b173576..3459ea6 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -14,7 +14,7 @@
 #include <linux/device.h>
 #include <linux/init.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/unaligned.h>
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 40710ea..ebe04e0 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -84,7 +84,7 @@
 #include <asm/system.h>
 #include <asm/unaligned.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include "gadget_chips.h"
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index cc60759..6271187 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -67,6 +67,11 @@
 
 	  If unsure, say N.
 
+config USB_EHCI_BIG_ENDIAN_MMIO
+	bool
+	depends on USB_EHCI_HCD
+	default n
+
 config USB_ISP116X_HCD
 	tristate "ISP116X HCD support"
 	depends on USB
@@ -101,21 +106,48 @@
 	bool "OHCI support for on-chip PPC USB controller"
 	depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
 	default y
-	select USB_OHCI_BIG_ENDIAN
+	select USB_OHCI_BIG_ENDIAN_DESC
+	select USB_OHCI_BIG_ENDIAN_MMIO
 	---help---
 	  Enables support for the USB controller on the MPC52xx or
 	  STB03xxx processor chip.  If unsure, say Y.
 
+config USB_OHCI_HCD_PPC_OF
+	bool "OHCI support for PPC USB controller on OF platform bus"
+	depends on USB_OHCI_HCD && PPC_OF
+	default y
+	---help---
+	  Enables support for the USB controller PowerPC present on the
+	  OpenFirmware platform bus.
+
+config USB_OHCI_HCD_PPC_OF_BE
+	bool "Support big endian HC"
+	depends on USB_OHCI_HCD_PPC_OF
+	default y
+	select USB_OHCI_BIG_ENDIAN_DESC
+	select USB_OHCI_BIG_ENDIAN_MMIO
+
+config USB_OHCI_HCD_PPC_OF_LE
+	bool "Support little endian HC"
+	depends on USB_OHCI_HCD_PPC_OF
+	default n
+	select USB_OHCI_LITTLE_ENDIAN
+
 config USB_OHCI_HCD_PCI
 	bool "OHCI support for PCI-bus USB controllers"
-	depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx)
+	depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF)
 	default y
 	select USB_OHCI_LITTLE_ENDIAN
 	---help---
 	  Enables support for PCI-bus plug-in USB controller cards.
 	  If unsure, say Y.
 
-config USB_OHCI_BIG_ENDIAN
+config USB_OHCI_BIG_ENDIAN_DESC
+	bool
+	depends on USB_OHCI_HCD
+	default n
+
+config USB_OHCI_BIG_ENDIAN_MMIO
 	bool
 	depends on USB_OHCI_HCD
 	default n
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 56349d2..246afea 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -43,7 +43,7 @@
  */
 static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
 {
-	u32	params = readl (&ehci->caps->hcs_params);
+	u32	params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
 	ehci_dbg (ehci,
 		"%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n",
@@ -87,7 +87,7 @@
  * */
 static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
 {
-	u32	params = readl (&ehci->caps->hcc_params);
+	u32	params = ehci_readl(ehci, &ehci->caps->hcc_params);
 
 	if (HCC_ISOC_CACHE (params)) {
 		ehci_dbg (ehci,
@@ -653,7 +653,7 @@
 	}
 
 	/* Capability Registers */
-	i = HC_VERSION(readl (&ehci->caps->hc_capbase));
+	i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
 	temp = scnprintf (next, size,
 		"bus %s, device %s (driver " DRIVER_VERSION ")\n"
 		"%s\n"
@@ -673,7 +673,7 @@
 		unsigned	count = 256/4;
 
 		pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
-		offset = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
+		offset = HCC_EXT_CAPS (ehci_readl(ehci, &ehci->caps->hcc_params));
 		while (offset && count--) {
 			pci_read_config_dword (pdev, offset, &cap);
 			switch (cap & 0xff) {
@@ -704,50 +704,50 @@
 #endif
 
 	// FIXME interpret both types of params
-	i = readl (&ehci->caps->hcs_params);
+	i = ehci_readl(ehci, &ehci->caps->hcs_params);
 	temp = scnprintf (next, size, "structural params 0x%08x\n", i);
 	size -= temp;
 	next += temp;
 
-	i = readl (&ehci->caps->hcc_params);
+	i = ehci_readl(ehci, &ehci->caps->hcc_params);
 	temp = scnprintf (next, size, "capability params 0x%08x\n", i);
 	size -= temp;
 	next += temp;
 
 	/* Operational Registers */
 	temp = dbg_status_buf (scratch, sizeof scratch, label,
-			readl (&ehci->regs->status));
+			ehci_readl(ehci, &ehci->regs->status));
 	temp = scnprintf (next, size, fmt, temp, scratch);
 	size -= temp;
 	next += temp;
 
 	temp = dbg_command_buf (scratch, sizeof scratch, label,
-			readl (&ehci->regs->command));
+			ehci_readl(ehci, &ehci->regs->command));
 	temp = scnprintf (next, size, fmt, temp, scratch);
 	size -= temp;
 	next += temp;
 
 	temp = dbg_intr_buf (scratch, sizeof scratch, label,
-			readl (&ehci->regs->intr_enable));
+			ehci_readl(ehci, &ehci->regs->intr_enable));
 	temp = scnprintf (next, size, fmt, temp, scratch);
 	size -= temp;
 	next += temp;
 
 	temp = scnprintf (next, size, "uframe %04x\n",
-			readl (&ehci->regs->frame_index));
+			ehci_readl(ehci, &ehci->regs->frame_index));
 	size -= temp;
 	next += temp;
 
 	for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
 		temp = dbg_port_buf (scratch, sizeof scratch, label, i,
-				readl (&ehci->regs->port_status [i - 1]));
+				ehci_readl(ehci, &ehci->regs->port_status [i - 1]));
 		temp = scnprintf (next, size, fmt, temp, scratch);
 		size -= temp;
 		next += temp;
 		if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
 			temp = scnprintf (next, size,
 					"    debug control %08x\n",
-					readl (&ehci->debug->control));
+					ehci_readl(ehci, &ehci->debug->control));
 			size -= temp;
 			next += temp;
 		}
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 1a915e9..a524805 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -177,7 +177,7 @@
 	case FSL_USB2_PHY_NONE:
 		break;
 	}
-	writel(portsc, &ehci->regs->port_status[port_offset]);
+	ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
 }
 
 static void mpc83xx_usb_setup(struct usb_hcd *hcd)
@@ -214,7 +214,7 @@
 	}
 
 	/* put controller in host mode. */
-	writel(0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
+	ehci_writel(ehci, 0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
 	out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
 	out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
 	out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
@@ -238,12 +238,12 @@
 	/* EHCI registers start at offset 0x100 */
 	ehci->caps = hcd->regs + 0x100;
 	ehci->regs = hcd->regs + 0x100 +
-	    HC_LENGTH(readl(&ehci->caps->hc_capbase));
+	    HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
 	dbg_hcs_params(ehci, "reset");
 	dbg_hcc_params(ehci, "reset");
 
 	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = readl(&ehci->caps->hcs_params);
+	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
 	retval = ehci_halt(ehci);
 	if (retval)
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 025d333..185721d 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -157,12 +157,13 @@
  * before driver shutdown. But it also seems to be caused by bugs in cardbus
  * bridge shutdown:  shutting down the bridge before the devices using it.
  */
-static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
+static int handshake (struct ehci_hcd *ehci, void __iomem *ptr,
+		      u32 mask, u32 done, int usec)
 {
 	u32	result;
 
 	do {
-		result = readl (ptr);
+		result = ehci_readl(ehci, ptr);
 		if (result == ~(u32)0)		/* card removed */
 			return -ENODEV;
 		result &= mask;
@@ -177,18 +178,19 @@
 /* force HC to halt state from unknown (EHCI spec section 2.3) */
 static int ehci_halt (struct ehci_hcd *ehci)
 {
-	u32	temp = readl (&ehci->regs->status);
+	u32	temp = ehci_readl(ehci, &ehci->regs->status);
 
 	/* disable any irqs left enabled by previous code */
-	writel (0, &ehci->regs->intr_enable);
+	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 
 	if ((temp & STS_HALT) != 0)
 		return 0;
 
-	temp = readl (&ehci->regs->command);
+	temp = ehci_readl(ehci, &ehci->regs->command);
 	temp &= ~CMD_RUN;
-	writel (temp, &ehci->regs->command);
-	return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125);
+	ehci_writel(ehci, temp, &ehci->regs->command);
+	return handshake (ehci, &ehci->regs->status,
+			  STS_HALT, STS_HALT, 16 * 125);
 }
 
 /* put TDI/ARC silicon into EHCI mode */
@@ -198,23 +200,24 @@
 	u32		tmp;
 
 	reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68);
-	tmp = readl (reg_ptr);
+	tmp = ehci_readl(ehci, reg_ptr);
 	tmp |= 0x3;
-	writel (tmp, reg_ptr);
+	ehci_writel(ehci, tmp, reg_ptr);
 }
 
 /* reset a non-running (STS_HALT == 1) controller */
 static int ehci_reset (struct ehci_hcd *ehci)
 {
 	int	retval;
-	u32	command = readl (&ehci->regs->command);
+	u32	command = ehci_readl(ehci, &ehci->regs->command);
 
 	command |= CMD_RESET;
 	dbg_cmd (ehci, "reset", command);
-	writel (command, &ehci->regs->command);
+	ehci_writel(ehci, command, &ehci->regs->command);
 	ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 	ehci->next_statechange = jiffies;
-	retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
+	retval = handshake (ehci, &ehci->regs->command,
+			    CMD_RESET, 0, 250 * 1000);
 
 	if (retval)
 		return retval;
@@ -236,21 +239,21 @@
 #endif
 
 	/* wait for any schedule enables/disables to take effect */
-	temp = readl (&ehci->regs->command) << 10;
+	temp = ehci_readl(ehci, &ehci->regs->command) << 10;
 	temp &= STS_ASS | STS_PSS;
-	if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+	if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
 				temp, 16 * 125) != 0) {
 		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		return;
 	}
 
 	/* then disable anything that's still active */
-	temp = readl (&ehci->regs->command);
+	temp = ehci_readl(ehci, &ehci->regs->command);
 	temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
-	writel (temp, &ehci->regs->command);
+	ehci_writel(ehci, temp, &ehci->regs->command);
 
 	/* hardware can take 16 microframes to turn off ... */
-	if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+	if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
 				0, 16 * 125) != 0) {
 		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		return;
@@ -277,11 +280,11 @@
 
 	/* lost IAA irqs wedge things badly; seen with a vt8235 */
 	if (ehci->reclaim) {
-		u32		status = readl (&ehci->regs->status);
+		u32		status = ehci_readl(ehci, &ehci->regs->status);
 		if (status & STS_IAA) {
 			ehci_vdbg (ehci, "lost IAA\n");
 			COUNT (ehci->stats.lost_iaa);
-			writel (STS_IAA, &ehci->regs->status);
+			ehci_writel(ehci, STS_IAA, &ehci->regs->status);
 			ehci->reclaim_ready = 1;
 		}
 	}
@@ -309,7 +312,7 @@
 	(void) ehci_halt (ehci);
 
 	/* make BIOS/etc use companion controller during reboot */
-	writel (0, &ehci->regs->configured_flag);
+	ehci_writel(ehci, 0, &ehci->regs->configured_flag);
 }
 
 static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
@@ -379,12 +382,13 @@
 		ehci_quiesce (ehci);
 
 	ehci_reset (ehci);
-	writel (0, &ehci->regs->intr_enable);
+	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 	spin_unlock_irq(&ehci->lock);
 
 	/* let companion controllers work when we aren't */
-	writel (0, &ehci->regs->configured_flag);
+	ehci_writel(ehci, 0, &ehci->regs->configured_flag);
 
+	remove_companion_file(ehci);
 	remove_debug_files (ehci);
 
 	/* root hub is shut down separately (first, when possible) */
@@ -402,7 +406,8 @@
 		ehci->stats.complete, ehci->stats.unlink);
 #endif
 
-	dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
+	dbg_status (ehci, "ehci_stop completed",
+		    ehci_readl(ehci, &ehci->regs->status));
 }
 
 /* one-time init, only for memory state */
@@ -428,7 +433,7 @@
 		return retval;
 
 	/* controllers may cache some of the periodic schedule ... */
-	hcc_params = readl(&ehci->caps->hcc_params);
+	hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
 	if (HCC_ISOC_CACHE(hcc_params))		// full frame cache
 		ehci->i_thresh = 8;
 	else					// N microframes cached
@@ -496,13 +501,16 @@
 	u32			temp;
 	u32			hcc_params;
 
+	hcd->uses_new_polling = 1;
+	hcd->poll_rh = 0;
+
 	/* EHCI spec section 4.1 */
 	if ((retval = ehci_reset(ehci)) != 0) {
 		ehci_mem_cleanup(ehci);
 		return retval;
 	}
-	writel(ehci->periodic_dma, &ehci->regs->frame_list);
-	writel((u32)ehci->async->qh_dma, &ehci->regs->async_next);
+	ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+	ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
 
 	/*
 	 * hcc_params controls whether ehci->regs->segment must (!!!)
@@ -516,9 +524,9 @@
 	 * Scsi_Host.highmem_io, and so forth.  It's readonly to all
 	 * host side drivers though.
 	 */
-	hcc_params = readl(&ehci->caps->hcc_params);
+	hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
 	if (HCC_64BIT_ADDR(hcc_params)) {
-		writel(0, &ehci->regs->segment);
+		ehci_writel(ehci, 0, &ehci->regs->segment);
 #if 0
 // this is deeply broken on almost all architectures
 		if (!dma_set_mask(hcd->self.controller, DMA_64BIT_MASK))
@@ -531,7 +539,7 @@
 	// root hub will detect new devices (why?); NEC doesn't
 	ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
 	ehci->command |= CMD_RUN;
-	writel (ehci->command, &ehci->regs->command);
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
 	dbg_cmd (ehci, "init", ehci->command);
 
 	/*
@@ -541,23 +549,25 @@
 	 * and there's no companion controller unless maybe for USB OTG.)
 	 */
 	hcd->state = HC_STATE_RUNNING;
-	writel (FLAG_CF, &ehci->regs->configured_flag);
-	readl (&ehci->regs->command);	/* unblock posted writes */
+	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
 
-	temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
+	temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
 	ehci_info (ehci,
 		"USB %x.%x started, EHCI %x.%02x, driver %s%s\n",
 		((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
 		temp >> 8, temp & 0xff, DRIVER_VERSION,
 		ignore_oc ? ", overcurrent ignored" : "");
 
-	writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
+	ehci_writel(ehci, INTR_MASK,
+		    &ehci->regs->intr_enable); /* Turn On Interrupts */
 
 	/* GRR this is run-once init(), being done every time the HC starts.
 	 * So long as they're part of class devices, we can't do it init()
 	 * since the class device isn't created that early.
 	 */
 	create_debug_files(ehci);
+	create_companion_file(ehci);
 
 	return 0;
 }
@@ -567,12 +577,12 @@
 static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	u32			status;
+	u32			status, pcd_status = 0;
 	int			bh;
 
 	spin_lock (&ehci->lock);
 
-	status = readl (&ehci->regs->status);
+	status = ehci_readl(ehci, &ehci->regs->status);
 
 	/* e.g. cardbus physical eject */
 	if (status == ~(u32) 0) {
@@ -587,8 +597,8 @@
 	}
 
 	/* clear (just) interrupts */
-	writel (status, &ehci->regs->status);
-	readl (&ehci->regs->command);	/* unblock posted write */
+	ehci_writel(ehci, status, &ehci->regs->status);
+	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted write */
 	bh = 0;
 
 #ifdef	EHCI_VERBOSE_DEBUG
@@ -617,13 +627,15 @@
 	/* remote wakeup [4.3.1] */
 	if (status & STS_PCD) {
 		unsigned	i = HCS_N_PORTS (ehci->hcs_params);
+		pcd_status = status;
 
 		/* resume root hub? */
-		if (!(readl(&ehci->regs->command) & CMD_RUN))
+		if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN))
 			usb_hcd_resume_root_hub(hcd);
 
 		while (i--) {
-			int pstatus = readl (&ehci->regs->port_status [i]);
+			int pstatus = ehci_readl(ehci,
+						 &ehci->regs->port_status [i]);
 
 			if (pstatus & PORT_OWNER)
 				continue;
@@ -643,14 +655,15 @@
 	/* PCI errors [4.15.2.4] */
 	if (unlikely ((status & STS_FATAL) != 0)) {
 		/* bogus "fatal" IRQs appear on some chips... why?  */
-		status = readl (&ehci->regs->status);
-		dbg_cmd (ehci, "fatal", readl (&ehci->regs->command));
+		status = ehci_readl(ehci, &ehci->regs->status);
+		dbg_cmd (ehci, "fatal", ehci_readl(ehci,
+						   &ehci->regs->command));
 		dbg_status (ehci, "fatal", status);
 		if (status & STS_HALT) {
 			ehci_err (ehci, "fatal error\n");
 dead:
 			ehci_reset (ehci);
-			writel (0, &ehci->regs->configured_flag);
+			ehci_writel(ehci, 0, &ehci->regs->configured_flag);
 			/* generic layer kills/unlinks all urbs, then
 			 * uses ehci_stop to clean up the rest
 			 */
@@ -661,6 +674,8 @@
 	if (bh)
 		ehci_work (ehci);
 	spin_unlock (&ehci->lock);
+	if (pcd_status & STS_PCD)
+		usb_hcd_poll_rh_status(hcd);
 	return IRQ_HANDLED;
 }
 
@@ -873,7 +888,8 @@
 static int ehci_get_frame (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size;
+	return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) %
+		ehci->periodic_size;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -899,7 +915,13 @@
 #define	PLATFORM_DRIVER		ehci_hcd_au1xxx_driver
 #endif
 
-#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER)
+#ifdef CONFIG_PPC_PS3
+#include "ehci-ps3.c"
+#define	PS3_SYSTEM_BUS_DRIVER	ps3_ehci_sb_driver
+#endif
+
+#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
+    !defined(PS3_SYSTEM_BUS_DRIVER)
 #error "missing bus glue for ehci-hcd"
 #endif
 
@@ -924,6 +946,20 @@
 #ifdef PLATFORM_DRIVER
 		platform_driver_unregister(&PLATFORM_DRIVER);
 #endif
+		return retval;
+	}
+#endif
+
+#ifdef PS3_SYSTEM_BUS_DRIVER
+	retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+	if (retval < 0) {
+#ifdef PLATFORM_DRIVER
+		platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef PCI_DRIVER
+		pci_unregister_driver(&PCI_DRIVER);
+#endif
+		return retval;
 	}
 #endif
 
@@ -939,6 +975,9 @@
 #ifdef PCI_DRIVER
 	pci_unregister_driver(&PCI_DRIVER);
 #endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+	ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+#endif
 }
 module_exit(ehci_hcd_cleanup);
 
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index bfe5f30..0d83c6d 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -47,7 +47,7 @@
 		ehci_quiesce (ehci);
 		hcd->state = HC_STATE_QUIESCING;
 	}
-	ehci->command = readl (&ehci->regs->command);
+	ehci->command = ehci_readl(ehci, &ehci->regs->command);
 	if (ehci->reclaim)
 		ehci->reclaim_ready = 1;
 	ehci_work(ehci);
@@ -60,7 +60,7 @@
 	ehci->bus_suspended = 0;
 	while (port--) {
 		u32 __iomem	*reg = &ehci->regs->port_status [port];
-		u32		t1 = readl (reg) & ~PORT_RWC_BITS;
+		u32		t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
 		u32		t2 = t1;
 
 		/* keep track of which ports we suspend */
@@ -79,7 +79,7 @@
 		if (t1 != t2) {
 			ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
 				port + 1, t1, t2);
-			writel (t2, reg);
+			ehci_writel(ehci, t2, reg);
 		}
 	}
 
@@ -92,8 +92,8 @@
 	mask = INTR_MASK;
 	if (!device_may_wakeup(&hcd->self.root_hub->dev))
 		mask &= ~STS_PCD;
-	writel(mask, &ehci->regs->intr_enable);
-	readl(&ehci->regs->intr_enable);
+	ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+	ehci_readl(ehci, &ehci->regs->intr_enable);
 
 	ehci->next_statechange = jiffies + msecs_to_jiffies(10);
 	spin_unlock_irq (&ehci->lock);
@@ -118,26 +118,26 @@
 	 * the last user of the controller, not reset/pm hardware keeping
 	 * state we gave to it.
 	 */
-	temp = readl(&ehci->regs->intr_enable);
+	temp = ehci_readl(ehci, &ehci->regs->intr_enable);
 	ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss");
 
 	/* at least some APM implementations will try to deliver
 	 * IRQs right away, so delay them until we're ready.
 	 */
-	writel(0, &ehci->regs->intr_enable);
+	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 
 	/* re-init operational registers */
-	writel(0, &ehci->regs->segment);
-	writel(ehci->periodic_dma, &ehci->regs->frame_list);
-	writel((u32) ehci->async->qh_dma, &ehci->regs->async_next);
+	ehci_writel(ehci, 0, &ehci->regs->segment);
+	ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+	ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next);
 
 	/* restore CMD_RUN, framelist size, and irq threshold */
-	writel (ehci->command, &ehci->regs->command);
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
 
 	/* manually resume the ports we suspended during bus_suspend() */
 	i = HCS_N_PORTS (ehci->hcs_params);
 	while (i--) {
-		temp = readl (&ehci->regs->port_status [i]);
+		temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
 		temp &= ~(PORT_RWC_BITS
 			| PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
 		if (test_bit(i, &ehci->bus_suspended) &&
@@ -145,20 +145,20 @@
 			ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
 			temp |= PORT_RESUME;
 		}
-		writel (temp, &ehci->regs->port_status [i]);
+		ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
 	}
 	i = HCS_N_PORTS (ehci->hcs_params);
 	mdelay (20);
 	while (i--) {
-		temp = readl (&ehci->regs->port_status [i]);
+		temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
 		if (test_bit(i, &ehci->bus_suspended) &&
 				(temp & PORT_SUSPEND)) {
 			temp &= ~(PORT_RWC_BITS | PORT_RESUME);
-			writel (temp, &ehci->regs->port_status [i]);
+			ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
 			ehci_vdbg (ehci, "resumed port %d\n", i + 1);
 		}
 	}
-	(void) readl (&ehci->regs->command);
+	(void) ehci_readl(ehci, &ehci->regs->command);
 
 	/* maybe re-activate the schedule(s) */
 	temp = 0;
@@ -168,14 +168,14 @@
 		temp |= CMD_PSE;
 	if (temp) {
 		ehci->command |= temp;
-		writel (ehci->command, &ehci->regs->command);
+		ehci_writel(ehci, ehci->command, &ehci->regs->command);
 	}
 
 	ehci->next_statechange = jiffies + msecs_to_jiffies(5);
 	hcd->state = HC_STATE_RUNNING;
 
 	/* Now we can safely re-enable irqs */
-	writel(INTR_MASK, &ehci->regs->intr_enable);
+	ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
 
 	spin_unlock_irq (&ehci->lock);
 	return 0;
@@ -190,9 +190,107 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* Display the ports dedicated to the companion controller */
+static ssize_t show_companion(struct class_device *class_dev, char *buf)
+{
+	struct ehci_hcd		*ehci;
+	int			nports, index, n;
+	int			count = PAGE_SIZE;
+	char			*ptr = buf;
+
+	ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+	nports = HCS_N_PORTS(ehci->hcs_params);
+
+	for (index = 0; index < nports; ++index) {
+		if (test_bit(index, &ehci->companion_ports)) {
+			n = scnprintf(ptr, count, "%d\n", index + 1);
+			ptr += n;
+			count -= n;
+		}
+	}
+	return ptr - buf;
+}
+
+/*
+ * Dedicate or undedicate a port to the companion controller.
+ * Syntax is "[-]portnum", where a leading '-' sign means
+ * return control of the port to the EHCI controller.
+ */
+static ssize_t store_companion(struct class_device *class_dev,
+		const char *buf, size_t count)
+{
+	struct ehci_hcd		*ehci;
+	int			portnum, new_owner, try;
+	u32 __iomem		*status_reg;
+	u32			port_status;
+
+	ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+	new_owner = PORT_OWNER;		/* Owned by companion */
+	if (sscanf(buf, "%d", &portnum) != 1)
+		return -EINVAL;
+	if (portnum < 0) {
+		portnum = - portnum;
+		new_owner = 0;		/* Owned by EHCI */
+	}
+	if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
+		return -ENOENT;
+	status_reg = &ehci->regs->port_status[--portnum];
+	if (new_owner)
+		set_bit(portnum, &ehci->companion_ports);
+	else
+		clear_bit(portnum, &ehci->companion_ports);
+
+	/*
+	 * The controller won't set the OWNER bit if the port is
+	 * enabled, so this loop will sometimes require at least two
+	 * iterations: one to disable the port and one to set OWNER.
+	 */
+
+	for (try = 4; try > 0; --try) {
+		spin_lock_irq(&ehci->lock);
+		port_status = ehci_readl(ehci, status_reg);
+		if ((port_status & PORT_OWNER) == new_owner
+				|| (port_status & (PORT_OWNER | PORT_CONNECT))
+					== 0)
+			try = 0;
+		else {
+			port_status ^= PORT_OWNER;
+			port_status &= ~(PORT_PE | PORT_RWC_BITS);
+			ehci_writel(ehci, port_status, status_reg);
+		}
+		spin_unlock_irq(&ehci->lock);
+		if (try > 1)
+			msleep(5);
+	}
+	return count;
+}
+static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion);
+
+static inline void create_companion_file(struct ehci_hcd *ehci)
+{
+	int	i;
+
+	/* with integrated TT there is no companion! */
+	if (!ehci_is_TDI(ehci))
+		i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev,
+				&class_device_attr_companion);
+}
+
+static inline void remove_companion_file(struct ehci_hcd *ehci)
+{
+	/* with integrated TT there is no companion! */
+	if (!ehci_is_TDI(ehci))
+		class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev,
+				&class_device_attr_companion);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
 static int check_reset_complete (
 	struct ehci_hcd	*ehci,
 	int		index,
+	u32 __iomem	*status_reg,
 	int		port_status
 ) {
 	if (!(port_status & PORT_CONNECT)) {
@@ -217,7 +315,7 @@
 		// what happens if HCS_N_CC(params) == 0 ?
 		port_status |= PORT_OWNER;
 		port_status &= ~PORT_RWC_BITS;
-		writel (port_status, &ehci->regs->port_status [index]);
+		ehci_writel(ehci, port_status, status_reg);
 
 	} else
 		ehci_dbg (ehci, "port %d high speed\n", index + 1);
@@ -268,22 +366,21 @@
 	/* port N changes (bit N)? */
 	spin_lock_irqsave (&ehci->lock, flags);
 	for (i = 0; i < ports; i++) {
-		temp = readl (&ehci->regs->port_status [i]);
-		if (temp & PORT_OWNER) {
-			/* don't report this in GetPortStatus */
-			if (temp & PORT_CSC) {
-				temp &= ~PORT_RWC_BITS;
-				temp |= PORT_CSC;
-				writel (temp, &ehci->regs->port_status [i]);
-			}
-			continue;
-		}
+		temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
+
+		/*
+		 * Return status information even for ports with OWNER set.
+		 * Otherwise khubd wouldn't see the disconnect event when a
+		 * high-speed device is switched over to the companion
+		 * controller by the user.
+		 */
+
 		if (!(temp & PORT_CONNECT))
 			ehci->reset_done [i] = 0;
 		if ((temp & mask) != 0
 				|| ((temp & PORT_RESUME) != 0
-					&& time_after (jiffies,
-						ehci->reset_done [i]))) {
+					&& time_after_eq(jiffies,
+						ehci->reset_done[i]))) {
 			if (i < 7)
 			    buf [0] |= 1 << (i + 1);
 			else
@@ -345,6 +442,7 @@
 ) {
 	struct ehci_hcd	*ehci = hcd_to_ehci (hcd);
 	int		ports = HCS_N_PORTS (ehci->hcs_params);
+	u32 __iomem	*status_reg = &ehci->regs->port_status[wIndex - 1];
 	u32		temp, status;
 	unsigned long	flags;
 	int		retval = 0;
@@ -373,18 +471,22 @@
 		if (!wIndex || wIndex > ports)
 			goto error;
 		wIndex--;
-		temp = readl (&ehci->regs->port_status [wIndex]);
-		if (temp & PORT_OWNER)
-			break;
+		temp = ehci_readl(ehci, status_reg);
+
+		/*
+		 * Even if OWNER is set, so the port is owned by the
+		 * companion controller, khubd needs to be able to clear
+		 * the port-change status bits (especially
+		 * USB_PORT_FEAT_C_CONNECTION).
+		 */
 
 		switch (wValue) {
 		case USB_PORT_FEAT_ENABLE:
-			writel (temp & ~PORT_PE,
-				&ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, temp & ~PORT_PE, status_reg);
 			break;
 		case USB_PORT_FEAT_C_ENABLE:
-			writel((temp & ~PORT_RWC_BITS) | PORT_PEC,
-				&ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC,
+					status_reg);
 			break;
 		case USB_PORT_FEAT_SUSPEND:
 			if (temp & PORT_RESET)
@@ -396,8 +498,8 @@
 					goto error;
 				/* resume signaling for 20 msec */
 				temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
-				writel (temp | PORT_RESUME,
-					&ehci->regs->port_status [wIndex]);
+				ehci_writel(ehci, temp | PORT_RESUME,
+						status_reg);
 				ehci->reset_done [wIndex] = jiffies
 						+ msecs_to_jiffies (20);
 			}
@@ -407,16 +509,17 @@
 			break;
 		case USB_PORT_FEAT_POWER:
 			if (HCS_PPC (ehci->hcs_params))
-				writel (temp & ~(PORT_RWC_BITS | PORT_POWER),
-					&ehci->regs->port_status [wIndex]);
+				ehci_writel(ehci,
+					  temp & ~(PORT_RWC_BITS | PORT_POWER),
+					  status_reg);
 			break;
 		case USB_PORT_FEAT_C_CONNECTION:
-			writel((temp & ~PORT_RWC_BITS) | PORT_CSC,
-				&ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC,
+					status_reg);
 			break;
 		case USB_PORT_FEAT_C_OVER_CURRENT:
-			writel((temp & ~PORT_RWC_BITS) | PORT_OCC,
-				&ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC,
+					status_reg);
 			break;
 		case USB_PORT_FEAT_C_RESET:
 			/* GetPortStatus clears reset */
@@ -424,7 +527,7 @@
 		default:
 			goto error;
 		}
-		readl (&ehci->regs->command);	/* unblock posted write */
+		ehci_readl(ehci, &ehci->regs->command);	/* unblock posted write */
 		break;
 	case GetHubDescriptor:
 		ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
@@ -440,7 +543,7 @@
 			goto error;
 		wIndex--;
 		status = 0;
-		temp = readl (&ehci->regs->port_status [wIndex]);
+		temp = ehci_readl(ehci, status_reg);
 
 		// wPortChange bits
 		if (temp & PORT_CSC)
@@ -451,42 +554,55 @@
 			status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
 
 		/* whoever resumes must GetPortStatus to complete it!! */
-		if ((temp & PORT_RESUME)
-				&& time_after (jiffies,
-					ehci->reset_done [wIndex])) {
-			status |= 1 << USB_PORT_FEAT_C_SUSPEND;
-			ehci->reset_done [wIndex] = 0;
+		if (temp & PORT_RESUME) {
 
-			/* stop resume signaling */
-			temp = readl (&ehci->regs->port_status [wIndex]);
-			writel (temp & ~(PORT_RWC_BITS | PORT_RESUME),
-				&ehci->regs->port_status [wIndex]);
-			retval = handshake (
-					&ehci->regs->port_status [wIndex],
-					PORT_RESUME, 0, 2000 /* 2msec */);
-			if (retval != 0) {
-				ehci_err (ehci, "port %d resume error %d\n",
-					wIndex + 1, retval);
-				goto error;
+			/* Remote Wakeup received? */
+			if (!ehci->reset_done[wIndex]) {
+				/* resume signaling for 20 msec */
+				ehci->reset_done[wIndex] = jiffies
+						+ msecs_to_jiffies(20);
+				/* check the port again */
+				mod_timer(&ehci_to_hcd(ehci)->rh_timer,
+						ehci->reset_done[wIndex]);
 			}
-			temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+
+			/* resume completed? */
+			else if (time_after_eq(jiffies,
+					ehci->reset_done[wIndex])) {
+				status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+				ehci->reset_done[wIndex] = 0;
+
+				/* stop resume signaling */
+				temp = ehci_readl(ehci, status_reg);
+				ehci_writel(ehci,
+					temp & ~(PORT_RWC_BITS | PORT_RESUME),
+					status_reg);
+				retval = handshake(ehci, status_reg,
+					   PORT_RESUME, 0, 2000 /* 2msec */);
+				if (retval != 0) {
+					ehci_err(ehci,
+						"port %d resume error %d\n",
+						wIndex + 1, retval);
+					goto error;
+				}
+				temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+			}
 		}
 
 		/* whoever resets must GetPortStatus to complete it!! */
 		if ((temp & PORT_RESET)
-				&& time_after (jiffies,
-					ehci->reset_done [wIndex])) {
+				&& time_after_eq(jiffies,
+					ehci->reset_done[wIndex])) {
 			status |= 1 << USB_PORT_FEAT_C_RESET;
 			ehci->reset_done [wIndex] = 0;
 
 			/* force reset to complete */
-			writel (temp & ~(PORT_RWC_BITS | PORT_RESET),
-					&ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),
+					status_reg);
 			/* REVISIT:  some hardware needs 550+ usec to clear
 			 * this bit; seems too long to spin routinely...
 			 */
-			retval = handshake (
-					&ehci->regs->port_status [wIndex],
+			retval = handshake(ehci, status_reg,
 					PORT_RESET, 0, 750);
 			if (retval != 0) {
 				ehci_err (ehci, "port %d reset error %d\n",
@@ -495,29 +611,42 @@
 			}
 
 			/* see what we found out */
-			temp = check_reset_complete (ehci, wIndex,
-				readl (&ehci->regs->port_status [wIndex]));
+			temp = check_reset_complete (ehci, wIndex, status_reg,
+					ehci_readl(ehci, status_reg));
 		}
 
-		// don't show wPortStatus if it's owned by a companion hc
-		if (!(temp & PORT_OWNER)) {
-			if (temp & PORT_CONNECT) {
-				status |= 1 << USB_PORT_FEAT_CONNECTION;
-				// status may be from integrated TT
-				status |= ehci_port_speed(ehci, temp);
-			}
-			if (temp & PORT_PE)
-				status |= 1 << USB_PORT_FEAT_ENABLE;
-			if (temp & (PORT_SUSPEND|PORT_RESUME))
-				status |= 1 << USB_PORT_FEAT_SUSPEND;
-			if (temp & PORT_OC)
-				status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
-			if (temp & PORT_RESET)
-				status |= 1 << USB_PORT_FEAT_RESET;
-			if (temp & PORT_POWER)
-				status |= 1 << USB_PORT_FEAT_POWER;
+		/* transfer dedicated ports to the companion hc */
+		if ((temp & PORT_CONNECT) &&
+				test_bit(wIndex, &ehci->companion_ports)) {
+			temp &= ~PORT_RWC_BITS;
+			temp |= PORT_OWNER;
+			ehci_writel(ehci, temp, status_reg);
+			ehci_dbg(ehci, "port %d --> companion\n", wIndex + 1);
+			temp = ehci_readl(ehci, status_reg);
 		}
 
+		/*
+		 * Even if OWNER is set, there's no harm letting khubd
+		 * see the wPortStatus values (they should all be 0 except
+		 * for PORT_POWER anyway).
+		 */
+
+		if (temp & PORT_CONNECT) {
+			status |= 1 << USB_PORT_FEAT_CONNECTION;
+			// status may be from integrated TT
+			status |= ehci_port_speed(ehci, temp);
+		}
+		if (temp & PORT_PE)
+			status |= 1 << USB_PORT_FEAT_ENABLE;
+		if (temp & (PORT_SUSPEND|PORT_RESUME))
+			status |= 1 << USB_PORT_FEAT_SUSPEND;
+		if (temp & PORT_OC)
+			status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
+		if (temp & PORT_RESET)
+			status |= 1 << USB_PORT_FEAT_RESET;
+		if (temp & PORT_POWER)
+			status |= 1 << USB_PORT_FEAT_POWER;
+
 #ifndef	EHCI_VERBOSE_DEBUG
 	if (status & ~0xffff)	/* only if wPortChange is interesting */
 #endif
@@ -541,7 +670,7 @@
 		if (!wIndex || wIndex > ports)
 			goto error;
 		wIndex--;
-		temp = readl (&ehci->regs->port_status [wIndex]);
+		temp = ehci_readl(ehci, status_reg);
 		if (temp & PORT_OWNER)
 			break;
 
@@ -555,13 +684,12 @@
 				goto error;
 			if (device_may_wakeup(&hcd->self.root_hub->dev))
 				temp |= PORT_WAKE_BITS;
-			writel (temp | PORT_SUSPEND,
-				&ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
 			break;
 		case USB_PORT_FEAT_POWER:
 			if (HCS_PPC (ehci->hcs_params))
-				writel (temp | PORT_POWER,
-					&ehci->regs->port_status [wIndex]);
+				ehci_writel(ehci, temp | PORT_POWER,
+						status_reg);
 			break;
 		case USB_PORT_FEAT_RESET:
 			if (temp & PORT_RESUME)
@@ -589,7 +717,7 @@
 				ehci->reset_done [wIndex] = jiffies
 						+ msecs_to_jiffies (50);
 			}
-			writel (temp, &ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, temp, status_reg);
 			break;
 
 		/* For downstream facing ports (these):  one hub port is put
@@ -604,13 +732,13 @@
 			ehci_quiesce(ehci);
 			ehci_halt(ehci);
 			temp |= selector << 16;
-			writel (temp, &ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, temp, status_reg);
 			break;
 
 		default:
 			goto error;
 		}
-		readl (&ehci->regs->command);	/* unblock posted writes */
+		ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
 		break;
 
 	default:
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 4bc7970..12edc72 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -38,7 +38,7 @@
 		if ((temp & (3 << 13)) == (1 << 13)) {
 			temp &= 0x1fff;
 			ehci->debug = ehci_to_hcd(ehci)->regs + temp;
-			temp = readl(&ehci->debug->control);
+			temp = ehci_readl(ehci, &ehci->debug->control);
 			ehci_info(ehci, "debug port %d%s\n",
 				HCS_DEBUG_PORT(ehci->hcs_params),
 				(temp & DBGP_ENABLED)
@@ -71,8 +71,24 @@
 	u32			temp;
 	int			retval;
 
+	switch (pdev->vendor) {
+	case PCI_VENDOR_ID_TOSHIBA_2:
+		/* celleb's companion chip */
+		if (pdev->device == 0x01b5) {
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+			ehci->big_endian_mmio = 1;
+#else
+			ehci_warn(ehci,
+				  "unsupported big endian Toshiba quirk\n");
+#endif
+		}
+		break;
+	}
+
 	ehci->caps = hcd->regs;
-	ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+	ehci->regs = hcd->regs +
+		HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+
 	dbg_hcs_params(ehci, "reset");
 	dbg_hcc_params(ehci, "reset");
 
@@ -101,7 +117,7 @@
 	}
 
 	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = readl(&ehci->caps->hcs_params);
+	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
 	retval = ehci_halt(ehci);
 	if (retval)
@@ -235,8 +251,8 @@
 		rc = -EINVAL;
 		goto bail;
 	}
-	writel (0, &ehci->regs->intr_enable);
-	(void)readl(&ehci->regs->intr_enable);
+	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+	(void)ehci_readl(ehci, &ehci->regs->intr_enable);
 
 	/* make sure snapshot being resumed re-enumerates everything */
 	if (message.event == PM_EVENT_PRETHAW) {
@@ -270,13 +286,13 @@
 	/* If CF is still set, we maintained PCI Vaux power.
 	 * Just undo the effect of ehci_pci_suspend().
 	 */
-	if (readl(&ehci->regs->configured_flag) == FLAG_CF) {
+	if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
 		int	mask = INTR_MASK;
 
 		if (!device_may_wakeup(&hcd->self.root_hub->dev))
 			mask &= ~STS_PCD;
-		writel(mask, &ehci->regs->intr_enable);
-		readl(&ehci->regs->intr_enable);
+		ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+		ehci_readl(ehci, &ehci->regs->intr_enable);
 		return 0;
 	}
 
@@ -300,9 +316,9 @@
 	/* here we "know" root ports should always stay powered */
 	ehci_port_power(ehci, 1);
 
-	writel(ehci->command, &ehci->regs->command);
-	writel(FLAG_CF, &ehci->regs->configured_flag);
-	readl(&ehci->regs->command);	/* unblock posted writes */
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
+	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
 
 	hcd->state = HC_STATE_SUSPENDED;
 	return 0;
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
new file mode 100644
index 0000000..4d781a2
--- /dev/null
+++ b/drivers/usb/host/ehci-ps3.c
@@ -0,0 +1,193 @@
+/*
+ *  PS3 EHCI Host Controller driver
+ *
+ *  Copyright (C) 2006 Sony Computer Entertainment Inc.
+ *  Copyright 2006 Sony Corp.
+ *
+ *  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.
+ *
+ *  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 <asm/ps3.h>
+
+static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
+{
+	int result;
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+	ehci->big_endian_mmio = 1;
+
+	ehci->caps = hcd->regs;
+	ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
+		&ehci->caps->hc_capbase));
+
+	dbg_hcs_params(ehci, "reset");
+	dbg_hcc_params(ehci, "reset");
+
+	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+	result = ehci_halt(ehci);
+
+	if (result)
+		return result;
+
+	result = ehci_init(hcd);
+
+	if (result)
+		return result;
+
+	ehci_port_power(ehci, 0);
+
+	return result;
+}
+
+static const struct hc_driver ps3_ehci_hc_driver = {
+	.description		= hcd_name,
+	.product_desc		= "PS3 EHCI Host Controller",
+	.hcd_priv_size		= sizeof(struct ehci_hcd),
+	.irq			= ehci_irq,
+	.flags			= HCD_MEMORY | HCD_USB2,
+	.reset			= ps3_ehci_hc_reset,
+	.start			= ehci_run,
+	.stop			= ehci_stop,
+	.shutdown		= ehci_shutdown,
+	.urb_enqueue		= ehci_urb_enqueue,
+	.urb_dequeue		= ehci_urb_dequeue,
+	.endpoint_disable	= ehci_endpoint_disable,
+	.get_frame_number	= ehci_get_frame,
+	.hub_status_data	= ehci_hub_status_data,
+	.hub_control		= ehci_hub_control,
+#if defined(CONFIG_PM)
+	.bus_suspend		= ehci_bus_suspend,
+	.bus_resume		= ehci_bus_resume,
+#endif
+};
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+	const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+
+static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
+{
+	int result;
+	struct usb_hcd *hcd;
+	unsigned int virq;
+	static u64 dummy_mask = DMA_32BIT_MASK;
+
+	if (usb_disabled()) {
+		result = -ENODEV;
+		goto fail_start;
+	}
+
+	result = ps3_mmio_region_create(dev->m_region);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
+			__func__, __LINE__);
+		result = -EPERM;
+		goto fail_mmio;
+	}
+
+	dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+		__LINE__, dev->m_region->lpar_addr);
+
+	result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
+			__func__, __LINE__, virq);
+		result = -EPERM;
+		goto fail_irq;
+	}
+
+	dev->core.power.power_state = PMSG_ON;
+	dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
+
+	hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev->core.bus_id);
+
+	if (!hcd) {
+		dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
+			__LINE__);
+		result = -ENOMEM;
+		goto fail_create_hcd;
+	}
+
+	hcd->rsrc_start = dev->m_region->lpar_addr;
+	hcd->rsrc_len = dev->m_region->len;
+	hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
+
+	if (!hcd->regs) {
+		dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
+			__LINE__);
+		result = -EPERM;
+		goto fail_ioremap;
+	}
+
+	dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
+		(unsigned long)hcd->rsrc_start);
+	dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len   %lxh\n", __func__, __LINE__,
+		(unsigned long)hcd->rsrc_len);
+	dev_dbg(&dev->core, "%s:%d: hcd->regs       %lxh\n", __func__, __LINE__,
+		(unsigned long)hcd->regs);
+	dev_dbg(&dev->core, "%s:%d: virq            %lu\n", __func__, __LINE__,
+		(unsigned long)virq);
+
+	ps3_system_bus_set_driver_data(dev, hcd);
+
+	result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
+			__func__, __LINE__, result);
+		goto fail_add_hcd;
+	}
+
+	return result;
+
+fail_add_hcd:
+	iounmap(hcd->regs);
+fail_ioremap:
+	usb_put_hcd(hcd);
+fail_create_hcd:
+	ps3_free_io_irq(virq);
+fail_irq:
+	ps3_free_mmio_region(dev->m_region);
+fail_mmio:
+fail_start:
+	return result;
+}
+
+static int ps3_ehci_sb_remove(struct ps3_system_bus_device *dev)
+{
+	struct usb_hcd *hcd =
+		(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+
+	usb_put_hcd(hcd);
+	ps3_system_bus_set_driver_data(dev, NULL);
+
+	return 0;
+}
+
+MODULE_ALIAS("ps3-ehci");
+
+static struct ps3_system_bus_driver ps3_ehci_sb_driver = {
+	.match_id = PS3_MATCH_ID_EHCI,
+	.core = {
+		.name = "ps3-ehci-driver",
+	},
+	.probe = ps3_ehci_sb_probe,
+	.remove = ps3_ehci_sb_remove,
+};
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 62e46dc..e7fbbd0 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -789,13 +789,14 @@
 	head = ehci->async;
 	timer_action_done (ehci, TIMER_ASYNC_OFF);
 	if (!head->qh_next.qh) {
-		u32	cmd = readl (&ehci->regs->command);
+		u32	cmd = ehci_readl(ehci, &ehci->regs->command);
 
 		if (!(cmd & CMD_ASE)) {
 			/* in case a clear of CMD_ASE didn't take yet */
-			(void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
+			(void)handshake(ehci, &ehci->regs->status,
+					STS_ASS, 0, 150);
 			cmd |= CMD_ASE | CMD_RUN;
-			writel (cmd, &ehci->regs->command);
+			ehci_writel(ehci, cmd, &ehci->regs->command);
 			ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
 			/* posted write need not be known to HC yet ... */
 		}
@@ -1007,7 +1008,7 @@
 
 static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
-	int		cmd = readl (&ehci->regs->command);
+	int		cmd = ehci_readl(ehci, &ehci->regs->command);
 	struct ehci_qh	*prev;
 
 #ifdef DEBUG
@@ -1025,7 +1026,8 @@
 		if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
 				&& !ehci->reclaim) {
 			/* ... and CMD_IAAD clear */
-			writel (cmd & ~CMD_ASE, &ehci->regs->command);
+			ehci_writel(ehci, cmd & ~CMD_ASE,
+				    &ehci->regs->command);
 			wmb ();
 			// handshake later, if we need to
 			timer_action_done (ehci, TIMER_ASYNC_OFF);
@@ -1054,8 +1056,8 @@
 
 	ehci->reclaim_ready = 0;
 	cmd |= CMD_IAAD;
-	writel (cmd, &ehci->regs->command);
-	(void) readl (&ehci->regs->command);
+	ehci_writel(ehci, cmd, &ehci->regs->command);
+	(void)ehci_readl(ehci, &ehci->regs->command);
 	timer_action (ehci, TIMER_IAA_WATCHDOG);
 }
 
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 65c402a..7b5ae71 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -433,20 +433,20 @@
 	/* did clearing PSE did take effect yet?
 	 * takes effect only at frame boundaries...
 	 */
-	status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125);
+	status = handshake(ehci, &ehci->regs->status, STS_PSS, 0, 9 * 125);
 	if (status != 0) {
 		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		return status;
 	}
 
-	cmd = readl (&ehci->regs->command) | CMD_PSE;
-	writel (cmd, &ehci->regs->command);
+	cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
+	ehci_writel(ehci, cmd, &ehci->regs->command);
 	/* posted write ... PSS happens later */
 	ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
 
 	/* make sure ehci_work scans these */
-	ehci->next_uframe = readl (&ehci->regs->frame_index)
-				% (ehci->periodic_size << 3);
+	ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
+		% (ehci->periodic_size << 3);
 	return 0;
 }
 
@@ -458,14 +458,14 @@
 	/* did setting PSE not take effect yet?
 	 * takes effect only at frame boundaries...
 	 */
-	status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
+	status = handshake(ehci, &ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
 	if (status != 0) {
 		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		return status;
 	}
 
-	cmd = readl (&ehci->regs->command) & ~CMD_PSE;
-	writel (cmd, &ehci->regs->command);
+	cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
+	ehci_writel(ehci, cmd, &ehci->regs->command);
 	/* posted write ... */
 
 	ehci->next_uframe = -1;
@@ -1336,7 +1336,7 @@
 		goto fail;
 	}
 
-	now = readl (&ehci->regs->frame_index) % mod;
+	now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
 
 	/* when's the last uframe this urb could start? */
 	max = now + mod;
@@ -2088,7 +2088,7 @@
 	 */
 	now_uframe = ehci->next_uframe;
 	if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
-		clock = readl (&ehci->regs->frame_index);
+		clock = ehci_readl(ehci, &ehci->regs->frame_index);
 	else
 		clock = now_uframe + mod - 1;
 	clock %= mod;
@@ -2213,7 +2213,7 @@
 			if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
 				break;
 			ehci->next_uframe = now_uframe;
-			now = readl (&ehci->regs->frame_index) % mod;
+			now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
 			if (now_uframe == now)
 				break;
 
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 74dbc6c..46fa57a 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -74,7 +74,11 @@
 
 	/* per root hub port */
 	unsigned long		reset_done [EHCI_MAX_ROOT_PORTS];
-	unsigned long		bus_suspended;
+	/* bit vectors (one bit per port) */
+	unsigned long		bus_suspended;		/* which ports were
+			already suspended at the start of a bus suspend */
+	unsigned long		companion_ports;	/* which ports are
+			dedicated to the companion controller */
 
 	/* per-HC memory pools (could be per-bus, but ...) */
 	struct dma_pool		*qh_pool;	/* qh per active urb */
@@ -92,6 +96,7 @@
 	unsigned		is_tdi_rh_tt:1;	/* TDI roothub with TT */
 	unsigned		no_selective_suspend:1;
 	unsigned		has_fsl_port_bug:1; /* FreeScale */
+	unsigned		big_endian_mmio:1;
 
 	u8			sbrn;		/* packed release number */
 
@@ -651,6 +656,45 @@
 #define	ehci_has_fsl_portno_bug(e)		(0)
 #endif
 
+/*
+ * While most USB host controllers implement their registers in
+ * little-endian format, a minority (celleb companion chip) implement
+ * them in big endian format.
+ *
+ * This attempts to support either format at compile time without a
+ * runtime penalty, or both formats with the additional overhead
+ * of checking a flag bit.
+ */
+
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+#define ehci_big_endian_mmio(e)		((e)->big_endian_mmio)
+#else
+#define ehci_big_endian_mmio(e)		0
+#endif
+
+static inline unsigned int ehci_readl (const struct ehci_hcd *ehci,
+				       __u32 __iomem * regs)
+{
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+	return ehci_big_endian_mmio(ehci) ?
+		readl_be(regs) :
+		readl(regs);
+#else
+	return readl(regs);
+#endif
+}
+
+static inline void ehci_writel (const struct ehci_hcd *ehci,
+				const unsigned int val, __u32 __iomem *regs)
+{
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+	ehci_big_endian_mmio(ehci) ?
+		writel_be(val, regs) :
+		writel(val, regs);
+#else
+	writel(val, regs);
+#endif
+}
 
 /*-------------------------------------------------------------------------*/
 
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index cc40551..9303464 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -170,7 +170,6 @@
 	at91_stop_hc(pdev);
 	iounmap(hcd->regs);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-	disable_irq_wake(hcd->irq);
 
 	clk_put(fclk);
 	clk_put(iclk);
@@ -271,8 +270,6 @@
 
 	if (device_may_wakeup(&pdev->dev))
 		enable_irq_wake(hcd->irq);
-	else
-		disable_irq_wake(hcd->irq);
 
 	/*
 	 * The integrated transceivers seem unable to notice disconnect,
@@ -293,6 +290,11 @@
 
 static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
 {
+	struct usb_hcd	*hcd = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(&pdev->dev))
+		disable_irq_wake(hcd->irq);
+
 	if (!clocked) {
 		clk_enable(iclk);
 		clk_enable(fclk);
@@ -320,18 +322,3 @@
 	},
 };
 
-static int __init ohci_hcd_at91_init (void)
-{
-	if (usb_disabled())
-		return -ENODEV;
-
-	return platform_driver_register(&ohci_hcd_at91_driver);
-}
-
-static void __exit ohci_hcd_at91_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_at91_driver);
-}
-
-module_init (ohci_hcd_at91_init);
-module_exit (ohci_hcd_at91_cleanup);
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index e70b243..663a060 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -345,19 +345,3 @@
 	},
 };
 
-static int __init ohci_hcd_au1xxx_init (void)
-{
-	pr_debug (DRIVER_INFO " (Au1xxx)");
-	pr_debug ("block sizes: ed %d td %d\n",
-		sizeof (struct ed), sizeof (struct td));
-
-	return platform_driver_register(&ohci_hcd_au1xxx_driver);
-}
-
-static void __exit ohci_hcd_au1xxx_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_au1xxx_driver);
-}
-
-module_init (ohci_hcd_au1xxx_init);
-module_exit (ohci_hcd_au1xxx_cleanup);
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index 3348b07..44c60fb 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -214,15 +214,3 @@
 	},
 };
 
-static int __init ohci_hcd_ep93xx_init(void)
-{
-	return platform_driver_register(&ohci_hcd_ep93xx_driver);
-}
-
-static void __exit ohci_hcd_ep93xx_cleanup(void)
-{
-	platform_driver_unregister(&ohci_hcd_ep93xx_driver);
-}
-
-module_init(ohci_hcd_ep93xx_init);
-module_exit(ohci_hcd_ep93xx_cleanup);
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index c1c1d87..fa6a7ce 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -855,63 +855,167 @@
 
 #ifdef CONFIG_PCI
 #include "ohci-pci.c"
+#define PCI_DRIVER		ohci_pci_driver
 #endif
 
 #ifdef CONFIG_SA1111
 #include "ohci-sa1111.c"
+#define SA1111_DRIVER		ohci_hcd_sa1111_driver
 #endif
 
 #ifdef CONFIG_ARCH_S3C2410
 #include "ohci-s3c2410.c"
+#define PLATFORM_DRIVER		ohci_hcd_s3c2410_driver
 #endif
 
 #ifdef CONFIG_ARCH_OMAP
 #include "ohci-omap.c"
+#define PLATFORM_DRIVER		ohci_hcd_omap_driver
 #endif
 
 #ifdef CONFIG_ARCH_LH7A404
 #include "ohci-lh7a404.c"
+#define PLATFORM_DRIVER		ohci_hcd_lh7a404_driver
 #endif
 
 #ifdef CONFIG_PXA27x
 #include "ohci-pxa27x.c"
+#define PLATFORM_DRIVER		ohci_hcd_pxa27x_driver
 #endif
 
 #ifdef CONFIG_ARCH_EP93XX
 #include "ohci-ep93xx.c"
+#define PLATFORM_DRIVER		ohci_hcd_ep93xx_driver
 #endif
 
 #ifdef CONFIG_SOC_AU1X00
 #include "ohci-au1xxx.c"
+#define PLATFORM_DRIVER		ohci_hcd_au1xxx_driver
 #endif
 
 #ifdef CONFIG_PNX8550
 #include "ohci-pnx8550.c"
+#define PLATFORM_DRIVER		ohci_hcd_pnx8550_driver
 #endif
 
 #ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
 #include "ohci-ppc-soc.c"
+#define PLATFORM_DRIVER		ohci_hcd_ppc_soc_driver
 #endif
 
 #ifdef CONFIG_ARCH_AT91
 #include "ohci-at91.c"
+#define PLATFORM_DRIVER		ohci_hcd_at91_driver
 #endif
 
 #ifdef CONFIG_ARCH_PNX4008
 #include "ohci-pnx4008.c"
+#define PLATFORM_DRIVER		usb_hcd_pnx4008_driver
 #endif
 
-#if !(defined(CONFIG_PCI) \
-      || defined(CONFIG_SA1111) \
-      || defined(CONFIG_ARCH_S3C2410) \
-      || defined(CONFIG_ARCH_OMAP) \
-      || defined (CONFIG_ARCH_LH7A404) \
-      || defined (CONFIG_PXA27x) \
-      || defined (CONFIG_ARCH_EP93XX) \
-      || defined (CONFIG_SOC_AU1X00) \
-      || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
-      || defined (CONFIG_ARCH_AT91) \
-      || defined (CONFIG_ARCH_PNX4008) \
-	)
+
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF
+#include "ohci-ppc-of.c"
+#define OF_PLATFORM_DRIVER	ohci_hcd_ppc_of_driver
+#endif
+
+#ifdef CONFIG_PPC_PS3
+#include "ohci-ps3.c"
+#define PS3_SYSTEM_BUS_DRIVER	ps3_ohci_sb_driver
+#endif
+
+#if	!defined(PCI_DRIVER) &&		\
+	!defined(PLATFORM_DRIVER) &&	\
+	!defined(OF_PLATFORM_DRIVER) &&	\
+	!defined(SA1111_DRIVER) &&	\
+	!defined(PS3_SYSTEM_BUS_DRIVER)
 #error "missing bus glue for ohci-hcd"
 #endif
+
+static int __init ohci_hcd_mod_init(void)
+{
+	int retval = 0;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name);
+	pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
+		sizeof (struct ed), sizeof (struct td));
+
+#ifdef PS3_SYSTEM_BUS_DRIVER
+	retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+	if (retval < 0)
+		goto error_ps3;
+#endif
+
+#ifdef PLATFORM_DRIVER
+	retval = platform_driver_register(&PLATFORM_DRIVER);
+	if (retval < 0)
+		goto error_platform;
+#endif
+
+#ifdef OF_PLATFORM_DRIVER
+	retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
+	if (retval < 0)
+		goto error_of_platform;
+#endif
+
+#ifdef SA1111_DRIVER
+	retval = sa1111_driver_register(&SA1111_DRIVER);
+	if (retval < 0)
+		goto error_sa1111;
+#endif
+
+#ifdef PCI_DRIVER
+	retval = pci_register_driver(&PCI_DRIVER);
+	if (retval < 0)
+		goto error_pci;
+#endif
+
+	return retval;
+
+	/* Error path */
+#ifdef PCI_DRIVER
+ error_pci:
+#endif
+#ifdef SA1111_DRIVER
+	sa1111_driver_unregister(&SA1111_DRIVER);
+ error_sa1111:
+#endif
+#ifdef OF_PLATFORM_DRIVER
+	of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+ error_of_platform:
+#endif
+#ifdef PLATFORM_DRIVER
+	platform_driver_unregister(&PLATFORM_DRIVER);
+ error_platform:
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+	ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+ error_ps3:
+#endif
+	return retval;
+}
+module_init(ohci_hcd_mod_init);
+
+static void __exit ohci_hcd_mod_exit(void)
+{
+#ifdef PCI_DRIVER
+	pci_unregister_driver(&PCI_DRIVER);
+#endif
+#ifdef SA1111_DRIVER
+	sa1111_driver_unregister(&SA1111_DRIVER);
+#endif
+#ifdef OF_PLATFORM_DRIVER
+	of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+#endif
+#ifdef PLATFORM_DRIVER
+	platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+	ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+#endif
+}
+module_exit(ohci_hcd_mod_exit);
+
diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
index e9807cf..4a043ab 100644
--- a/drivers/usb/host/ohci-lh7a404.c
+++ b/drivers/usb/host/ohci-lh7a404.c
@@ -251,19 +251,3 @@
 	},
 };
 
-static int __init ohci_hcd_lh7a404_init (void)
-{
-	pr_debug (DRIVER_INFO " (LH7A404)");
-	pr_debug ("block sizes: ed %d td %d\n",
-		sizeof (struct ed), sizeof (struct td));
-
-	return platform_driver_register(&ohci_hcd_lh7a404_driver);
-}
-
-static void __exit ohci_hcd_lh7a404_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_lh7a404_driver);
-}
-
-module_init (ohci_hcd_lh7a404_init);
-module_exit (ohci_hcd_lh7a404_cleanup);
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 27be1f9..5cfa3d1 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -544,22 +544,3 @@
 	},
 };
 
-static int __init ohci_hcd_omap_init (void)
-{
-	printk (KERN_DEBUG "%s: " DRIVER_INFO " (OMAP)\n", hcd_name);
-	if (usb_disabled())
-		return -ENODEV;
-
-	pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
-		sizeof (struct ed), sizeof (struct td));
-
-	return platform_driver_register(&ohci_hcd_omap_driver);
-}
-
-static void __exit ohci_hcd_omap_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_omap_driver);
-}
-
-module_init (ohci_hcd_omap_init);
-module_exit (ohci_hcd_omap_cleanup);
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 596e0b4..b331ac4 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -20,80 +20,155 @@
 
 /*-------------------------------------------------------------------------*/
 
-static int
-ohci_pci_reset (struct usb_hcd *hcd)
+/* AMD 756, for most chips (early revs), corrupts register
+ * values on read ... so enable the vendor workaround.
+ */
+static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd)
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 
-	ohci_hcd_init (ohci);
-	return ohci_init (ohci);
+	ohci->flags = OHCI_QUIRK_AMD756;
+	ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
+
+	/* also erratum 10 (suspend/resume issues) */
+	device_init_wakeup(&hcd->self.root_hub->dev, 0);
+
+	return 0;
 }
 
-static int __devinit
-ohci_pci_start (struct usb_hcd *hcd)
+/* Apple's OHCI driver has a lot of bizarre workarounds
+ * for this chip.  Evidently control and bulk lists
+ * can get confused.  (B&W G3 models, and ...)
+ */
+static int __devinit ohci_quirk_opti(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+
+	ohci_dbg (ohci, "WARNING: OPTi workarounds unavailable\n");
+
+	return 0;
+}
+
+/* Check for NSC87560. We have to look at the bridge (fn1) to
+ * identify the USB (fn2). This quirk might apply to more or
+ * even all NSC stuff.
+ */
+static int __devinit ohci_quirk_ns(struct usb_hcd *hcd)
+{
+	struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+	struct pci_dev	*b;
+
+	b  = pci_get_slot (pdev->bus, PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
+	if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
+	    && b->vendor == PCI_VENDOR_ID_NS) {
+		struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+
+		ohci->flags |= OHCI_QUIRK_SUPERIO;
+		ohci_dbg (ohci, "Using NSC SuperIO setup\n");
+	}
+	pci_dev_put(b);
+
+	return 0;
+}
+
+/* Check for Compaq's ZFMicro chipset, which needs short
+ * delays before control or bulk queues get re-activated
+ * in finish_unlinks()
+ */
+static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+
+	ohci->flags |= OHCI_QUIRK_ZFMICRO;
+	ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
+
+	return 0;
+}
+
+/* Check for Toshiba SCC OHCI which has big endian registers
+ * and little endian in memory data structures
+ */
+static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+
+	/* That chip is only present in the southbridge of some
+	 * cell based platforms which are supposed to select
+	 * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO. We verify here if
+	 * that was the case though.
+	 */
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+	ohci->flags |= OHCI_QUIRK_BE_MMIO;
+	ohci_dbg (ohci, "enabled big endian Toshiba quirk\n");
+	return 0;
+#else
+	ohci_err (ohci, "unsupported big endian Toshiba quirk\n");
+	return -ENXIO;
+#endif
+}
+
+/* List of quirks for OHCI */
+static const struct pci_device_id ohci_pci_quirks[] = {
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x740c),
+		.driver_data = (unsigned long)ohci_quirk_amd756,
+	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_OPTI, 0xc861),
+		.driver_data = (unsigned long)ohci_quirk_opti,
+	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_ANY_ID),
+		.driver_data = (unsigned long)ohci_quirk_ns,
+	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8),
+		.driver_data = (unsigned long)ohci_quirk_zfmicro,
+	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6),
+		.driver_data = (unsigned long)ohci_quirk_toshiba_scc,
+	},
+	/* FIXME for some of the early AMD 760 southbridges, OHCI
+	 * won't work at all.  blacklist them.
+	 */
+
+	{},
+};
+
+static int ohci_pci_reset (struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int ret = 0;
+
+	if (hcd->self.controller) {
+		struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+		const struct pci_device_id *quirk_id;
+
+		quirk_id = pci_match_id(ohci_pci_quirks, pdev);
+		if (quirk_id != NULL) {
+			int (*quirk)(struct usb_hcd *ohci);
+			quirk = (void *)quirk_id->driver_data;
+			ret = quirk(hcd);
+		}
+	}
+	if (ret == 0) {
+		ohci_hcd_init (ohci);
+		return ohci_init (ohci);
+	}
+	return ret;
+}
+
+
+static int __devinit ohci_pci_start (struct usb_hcd *hcd)
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 	int		ret;
 
-	/* REVISIT this whole block should move to reset(), which handles
-	 * all the other one-time init.
-	 */
+#ifdef CONFIG_PM /* avoid warnings about unused pdev */
 	if (hcd->self.controller) {
 		struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 
-		/* AMD 756, for most chips (early revs), corrupts register
-		 * values on read ... so enable the vendor workaround.
-		 */
-		if (pdev->vendor == PCI_VENDOR_ID_AMD
-				&& pdev->device == 0x740c) {
-			ohci->flags = OHCI_QUIRK_AMD756;
-			ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
-			/* also erratum 10 (suspend/resume issues) */
-			device_init_wakeup(&hcd->self.root_hub->dev, 0);
-		}
-
-		/* FIXME for some of the early AMD 760 southbridges, OHCI
-		 * won't work at all.  blacklist them.
-		 */
-
-		/* Apple's OHCI driver has a lot of bizarre workarounds
-		 * for this chip.  Evidently control and bulk lists
-		 * can get confused.  (B&W G3 models, and ...)
-		 */
-		else if (pdev->vendor == PCI_VENDOR_ID_OPTI
-				&& pdev->device == 0xc861) {
-			ohci_dbg (ohci,
-				"WARNING: OPTi workarounds unavailable\n");
-		}
-
-		/* Check for NSC87560. We have to look at the bridge (fn1) to
-		 * identify the USB (fn2). This quirk might apply to more or
-		 * even all NSC stuff.
-		 */
-		else if (pdev->vendor == PCI_VENDOR_ID_NS) {
-			struct pci_dev	*b;
-
-			b  = pci_get_slot (pdev->bus,
-					PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
-			if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
-					&& b->vendor == PCI_VENDOR_ID_NS) {
-				ohci->flags |= OHCI_QUIRK_SUPERIO;
-				ohci_dbg (ohci, "Using NSC SuperIO setup\n");
-			}
-			pci_dev_put(b);
-		}
-
-		/* Check for Compaq's ZFMicro chipset, which needs short
-		 * delays before control or bulk queues get re-activated
-		 * in finish_unlinks()
-		 */
-		else if (pdev->vendor == PCI_VENDOR_ID_COMPAQ
-				&& pdev->device  == 0xa0f8) {
-			ohci->flags |= OHCI_QUIRK_ZFMICRO;
-			ohci_dbg (ohci,
-				"enabled Compaq ZFMicro chipset quirk\n");
-		}
-
 		/* RWC may not be set for add-in PCI cards, since boot
 		 * firmware probably ignored them.  This transfers PCI
 		 * PM wakeup capabilities (once the PCI layer is fixed).
@@ -101,16 +176,14 @@
 		if (device_may_wakeup(&pdev->dev))
 			ohci->hc_control |= OHCI_CTRL_RWC;
 	}
+#endif /* CONFIG_PM */
 
-	/* NOTE: there may have already been a first reset, to
-	 * keep bios/smm irqs from making trouble
-	 */
-	if ((ret = ohci_run (ohci)) < 0) {
+	ret = ohci_run (ohci);
+	if (ret < 0) {
 		ohci_err (ohci, "can't start\n");
 		ohci_stop (hcd);
-		return ret;
 	}
-	return 0;
+	return ret;
 }
 
 #ifdef	CONFIG_PM
@@ -238,23 +311,3 @@
 	.shutdown =	usb_hcd_pci_shutdown,
 };
 
-
-static int __init ohci_hcd_pci_init (void)
-{
-	printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);
-	if (usb_disabled())
-		return -ENODEV;
-
-	pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
-		sizeof (struct ed), sizeof (struct td));
-	return pci_register_driver (&ohci_pci_driver);
-}
-module_init (ohci_hcd_pci_init);
-
-/*-------------------------------------------------------------------------*/
-
-static void __exit ohci_hcd_pci_cleanup (void)
-{
-	pci_unregister_driver (&ohci_pci_driver);
-}
-module_exit (ohci_hcd_pci_cleanup);
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
index 3a8cbfb..893b172 100644
--- a/drivers/usb/host/ohci-pnx4008.c
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -465,15 +465,3 @@
 	.remove = usb_hcd_pnx4008_remove,
 };
 
-static int __init usb_hcd_pnx4008_init(void)
-{
-	return platform_driver_register(&usb_hcd_pnx4008_driver);
-}
-
-static void __exit usb_hcd_pnx4008_cleanup(void)
-{
-	return platform_driver_unregister(&usb_hcd_pnx4008_driver);
-}
-
-module_init(usb_hcd_pnx4008_init);
-module_exit(usb_hcd_pnx4008_cleanup);
diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c
index 6922b91..de45eb0 100644
--- a/drivers/usb/host/ohci-pnx8550.c
+++ b/drivers/usb/host/ohci-pnx8550.c
@@ -240,19 +240,3 @@
 	.remove		= ohci_hcd_pnx8550_drv_remove,
 };
 
-static int __init ohci_hcd_pnx8550_init (void)
-{
-	pr_debug (DRIVER_INFO " (pnx8550)");
-	pr_debug ("block sizes: ed %d td %d\n",
-		sizeof (struct ed), sizeof (struct td));
-
-	return platform_driver_register(&ohci_hcd_pnx8550_driver);
-}
-
-static void __exit ohci_hcd_pnx8550_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_pnx8550_driver);
-}
-
-module_init (ohci_hcd_pnx8550_init);
-module_exit (ohci_hcd_pnx8550_cleanup);
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
new file mode 100644
index 0000000..08e237c
--- /dev/null
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -0,0 +1,232 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ * (C) Copyright 2006 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Bus glue for OHCI HC on the of_platform bus
+ *
+ * Modified for of_platform bus from ohci-sa1111.c
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/signal.h>
+
+#include <asm/of_platform.h>
+#include <asm/prom.h>
+
+
+static int __devinit
+ohci_ppc_of_start(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
+	int		ret;
+
+	if ((ret = ohci_init(ohci)) < 0)
+		return ret;
+
+	if ((ret = ohci_run(ohci)) < 0) {
+		err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+		ohci_stop(hcd);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct hc_driver ohci_ppc_of_hc_driver = {
+	.description =		hcd_name,
+	.product_desc =		"OF OHCI",
+	.hcd_priv_size =	sizeof(struct ohci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ohci_irq,
+	.flags =		HCD_USB11 | HCD_MEMORY,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.start =		ohci_ppc_of_start,
+	.stop =			ohci_stop,
+	.shutdown = 		ohci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ohci_hub_status_data,
+	.hub_control =		ohci_hub_control,
+	.hub_irq_enable =	ohci_rhsc_enable,
+#ifdef	CONFIG_PM
+	.bus_suspend =		ohci_bus_suspend,
+	.bus_resume =		ohci_bus_resume,
+#endif
+	.start_port_reset =	ohci_start_port_reset,
+};
+
+
+static int __devinit
+ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+	struct device_node *dn = op->node;
+	struct usb_hcd *hcd;
+	struct ohci_hcd	*ohci;
+	struct resource res;
+	int irq;
+
+	int rv;
+	int is_bigendian;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	is_bigendian =
+		device_is_compatible(dn, "ohci-bigendian") ||
+		device_is_compatible(dn, "ohci-be");
+
+	dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
+
+	rv = of_address_to_resource(dn, 0, &res);
+	if (rv)
+		return rv;
+
+	hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
+	if (!hcd)
+		return -ENOMEM;
+
+	hcd->rsrc_start = res.start;
+	hcd->rsrc_len = res.end - res.start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
+		rv = -EBUSY;
+		goto err_rmr;
+	}
+
+	irq = irq_of_parse_and_map(dn, 0);
+	if (irq == NO_IRQ) {
+		printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+		rv = -EBUSY;
+		goto err_irq;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		printk(KERN_ERR __FILE__ ": ioremap failed\n");
+		rv = -ENOMEM;
+		goto err_ioremap;
+	}
+
+	ohci = hcd_to_ohci(hcd);
+	if (is_bigendian)
+		ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+
+	ohci_hcd_init(ohci);
+
+	rv = usb_add_hcd(hcd, irq, 0);
+	if (rv == 0)
+		return 0;
+
+	iounmap(hcd->regs);
+err_ioremap:
+	irq_dispose_mapping(irq);
+err_irq:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_rmr:
+ 	usb_put_hcd(hcd);
+
+	return rv;
+}
+
+static int ohci_hcd_ppc_of_remove(struct of_device *op)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+	dev_set_drvdata(&op->dev, NULL);
+
+	dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
+
+	usb_remove_hcd(hcd);
+
+	iounmap(hcd->regs);
+	irq_dispose_mapping(hcd->irq);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+	usb_put_hcd(hcd);
+
+	return 0;
+}
+
+static int ohci_hcd_ppc_of_shutdown(struct of_device *op)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+        if (hcd->driver->shutdown)
+                hcd->driver->shutdown(hcd);
+
+	return 0;
+}
+
+
+static struct of_device_id ohci_hcd_ppc_of_match[] = {
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
+	{
+		.name = "usb",
+		.compatible = "ohci-bigendian",
+	},
+	{
+		.name = "usb",
+		.compatible = "ohci-be",
+	},
+#endif
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE
+	{
+		.name = "usb",
+		.compatible = "ohci-littledian",
+	},
+	{
+		.name = "usb",
+		.compatible = "ohci-le",
+	},
+#endif
+	{},
+};
+MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
+
+#if	!defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
+	!defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
+#error "No endianess selected for ppc-of-ohci"
+#endif
+
+
+static struct of_platform_driver ohci_hcd_ppc_of_driver = {
+	.name		= "ppc-of-ohci",
+	.match_table	= ohci_hcd_ppc_of_match,
+	.probe		= ohci_hcd_ppc_of_probe,
+	.remove		= ohci_hcd_ppc_of_remove,
+	.shutdown 	= ohci_hcd_ppc_of_shutdown,
+#ifdef CONFIG_PM
+	/*.suspend	= ohci_hcd_ppc_soc_drv_suspend,*/
+	/*.resume	= ohci_hcd_ppc_soc_drv_resume,*/
+#endif
+	.driver		= {
+		.name	= "ppc-of-ohci",
+		.owner	= THIS_MODULE,
+	},
+};
+
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index e1a7eb8..1a2e177 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -72,7 +72,7 @@
 	}
 
 	ohci = hcd_to_ohci(hcd);
-	ohci->flags |= OHCI_BIG_ENDIAN;
+	ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
 	ohci_hcd_init(ohci);
 
 	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
@@ -208,19 +208,3 @@
 	},
 };
 
-static int __init ohci_hcd_ppc_soc_init(void)
-{
-	pr_debug(DRIVER_INFO " (PPC SOC)\n");
-	pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed),
-							sizeof(struct td));
-
-	return platform_driver_register(&ohci_hcd_ppc_soc_driver);
-}
-
-static void __exit ohci_hcd_ppc_soc_cleanup(void)
-{
-	platform_driver_unregister(&ohci_hcd_ppc_soc_driver);
-}
-
-module_init(ohci_hcd_ppc_soc_init);
-module_exit(ohci_hcd_ppc_soc_cleanup);
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
new file mode 100644
index 0000000..62283a3
--- /dev/null
+++ b/drivers/usb/host/ohci-ps3.c
@@ -0,0 +1,196 @@
+/*
+ *  PS3 OHCI Host Controller driver
+ *
+ *  Copyright (C) 2006 Sony Computer Entertainment Inc.
+ *  Copyright 2006 Sony Corp.
+ *
+ *  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.
+ *
+ *  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 <asm/ps3.h>
+
+static int ps3_ohci_hc_reset(struct usb_hcd *hcd)
+{
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+	ohci->flags |= OHCI_QUIRK_BE_MMIO;
+	ohci_hcd_init(ohci);
+	return ohci_init(ohci);
+}
+
+static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd)
+{
+	int result;
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+	/* Handle root hub init quirk in spider south bridge. */
+	/* Also set PwrOn2PwrGood to 0x7f (254ms). */
+
+	ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM,
+		&ohci->regs->roothub.a);
+	ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b);
+
+	result = ohci_run(ohci);
+
+	if (result < 0) {
+		err("can't start %s", hcd->self.bus_name);
+		ohci_stop(hcd);
+	}
+
+	return result;
+}
+
+static const struct hc_driver ps3_ohci_hc_driver = {
+	.description		= hcd_name,
+	.product_desc		= "PS3 OHCI Host Controller",
+	.hcd_priv_size		= sizeof(struct ohci_hcd),
+	.irq			= ohci_irq,
+	.flags			= HCD_MEMORY | HCD_USB11,
+	.reset			= ps3_ohci_hc_reset,
+	.start			= ps3_ohci_hc_start,
+	.stop			= ohci_stop,
+	.shutdown		= ohci_shutdown,
+	.urb_enqueue		= ohci_urb_enqueue,
+	.urb_dequeue		= ohci_urb_dequeue,
+	.endpoint_disable	= ohci_endpoint_disable,
+	.get_frame_number	= ohci_get_frame,
+	.hub_status_data	= ohci_hub_status_data,
+	.hub_control		= ohci_hub_control,
+	.hub_irq_enable		= ohci_rhsc_enable,
+	.start_port_reset	= ohci_start_port_reset,
+#if defined(CONFIG_PM)
+	.bus_suspend 		= ohci_bus_suspend,
+	.bus_resume 		= ohci_bus_resume,
+#endif
+};
+
+/* redefine dev_dbg to do a syntax check */
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+	const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
+{
+	int result;
+	struct usb_hcd *hcd;
+	unsigned int virq;
+	static u64 dummy_mask = DMA_32BIT_MASK;
+
+	if (usb_disabled()) {
+		result = -ENODEV;
+		goto fail_start;
+	}
+
+	result = ps3_mmio_region_create(dev->m_region);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
+			__func__, __LINE__);
+		result = -EPERM;
+		goto fail_mmio;
+	}
+
+	dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+		__LINE__, dev->m_region->lpar_addr);
+
+	result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
+			__func__, __LINE__, virq);
+		result = -EPERM;
+		goto fail_irq;
+	}
+
+	dev->core.power.power_state = PMSG_ON;
+	dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
+
+	hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev->core.bus_id);
+
+	if (!hcd) {
+		dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
+			__LINE__);
+		result = -ENOMEM;
+		goto fail_create_hcd;
+	}
+
+	hcd->rsrc_start = dev->m_region->lpar_addr;
+	hcd->rsrc_len = dev->m_region->len;
+	hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
+
+	if (!hcd->regs) {
+		dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
+			__LINE__);
+		result = -EPERM;
+		goto fail_ioremap;
+	}
+
+	dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
+		(unsigned long)hcd->rsrc_start);
+	dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len   %lxh\n", __func__, __LINE__,
+		(unsigned long)hcd->rsrc_len);
+	dev_dbg(&dev->core, "%s:%d: hcd->regs       %lxh\n", __func__, __LINE__,
+		(unsigned long)hcd->regs);
+	dev_dbg(&dev->core, "%s:%d: virq            %lu\n", __func__, __LINE__,
+		(unsigned long)virq);
+
+	ps3_system_bus_set_driver_data(dev, hcd);
+
+	result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
+			__func__, __LINE__, result);
+		goto fail_add_hcd;
+	}
+
+	return result;
+
+fail_add_hcd:
+	iounmap(hcd->regs);
+fail_ioremap:
+	usb_put_hcd(hcd);
+fail_create_hcd:
+	ps3_free_io_irq(virq);
+fail_irq:
+	ps3_free_mmio_region(dev->m_region);
+fail_mmio:
+fail_start:
+	return result;
+}
+
+static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev)
+{
+	struct usb_hcd *hcd =
+		(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+
+	usb_put_hcd(hcd);
+	ps3_system_bus_set_driver_data(dev, NULL);
+
+	return 0;
+}
+
+MODULE_ALIAS("ps3-ohci");
+
+static struct ps3_system_bus_driver ps3_ohci_sb_driver = {
+	.match_id = PS3_MATCH_ID_OHCI,
+	.core = {
+		.name = "ps3-ohci-driver",
+	},
+	.probe = ps3_ohci_sb_probe,
+	.remove = ps3_ohci_sb_remove,
+};
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 3bbea84..f1563dc 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -369,19 +369,3 @@
 	},
 };
 
-static int __init ohci_hcd_pxa27x_init (void)
-{
-	pr_debug (DRIVER_INFO " (pxa27x)");
-	pr_debug ("block sizes: ed %d td %d\n",
-		sizeof (struct ed), sizeof (struct td));
-
-	return platform_driver_register(&ohci_hcd_pxa27x_driver);
-}
-
-static void __exit ohci_hcd_pxa27x_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_pxa27x_driver);
-}
-
-module_init (ohci_hcd_pxa27x_init);
-module_exit (ohci_hcd_pxa27x_cleanup);
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index b350d45..6829814 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -501,15 +501,3 @@
 	},
 };
 
-static int __init ohci_hcd_s3c2410_init (void)
-{
-	return platform_driver_register(&ohci_hcd_s3c2410_driver);
-}
-
-static void __exit ohci_hcd_s3c2410_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_s3c2410_driver);
-}
-
-module_init (ohci_hcd_s3c2410_init);
-module_exit (ohci_hcd_s3c2410_cleanup);
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index fe0090e..0f48f2d 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -269,19 +269,3 @@
 	.remove		= ohci_hcd_sa1111_drv_remove,
 };
 
-static int __init ohci_hcd_sa1111_init (void)
-{
-	dbg (DRIVER_INFO " (SA-1111)");
-	dbg ("block sizes: ed %d td %d",
-		sizeof (struct ed), sizeof (struct td));
-
-	return sa1111_driver_register(&ohci_hcd_sa1111_driver);
-}
-
-static void __exit ohci_hcd_sa1111_cleanup (void)
-{
-	sa1111_driver_unregister(&ohci_hcd_sa1111_driver);
-}
-
-module_init (ohci_hcd_sa1111_init);
-module_exit (ohci_hcd_sa1111_cleanup);
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 405257f..c2b5ecf 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -394,8 +394,9 @@
 #define	OHCI_QUIRK_AMD756	0x01			/* erratum #4 */
 #define	OHCI_QUIRK_SUPERIO	0x02			/* natsemi */
 #define	OHCI_QUIRK_INITRESET	0x04			/* SiS, OPTi, ... */
-#define	OHCI_BIG_ENDIAN		0x08			/* big endian HC */
-#define	OHCI_QUIRK_ZFMICRO	0x10			/* Compaq ZFMicro chipset*/
+#define	OHCI_QUIRK_BE_DESC	0x08			/* BE descriptors */
+#define	OHCI_QUIRK_BE_MMIO	0x10			/* BE registers */
+#define	OHCI_QUIRK_ZFMICRO	0x20			/* Compaq ZFMicro chipset*/
 	// there are also chip quirks/bugs in init logic
 
 };
@@ -439,117 +440,164 @@
  * a minority (notably the IBM STB04XXX and the Motorola MPC5200
  * processors) implement them in big endian format.
  *
+ * In addition some more exotic implementations like the Toshiba
+ * Spider (aka SCC) cell southbridge are "mixed" endian, that is,
+ * they have a different endianness for registers vs. in-memory
+ * descriptors.
+ *
  * This attempts to support either format at compile time without a
  * runtime penalty, or both formats with the additional overhead
  * of checking a flag bit.
+ *
+ * That leads to some tricky Kconfig rules howevber. There are
+ * different defaults based on some arch/ppc platforms, though
+ * the basic rules are:
+ *
+ * Controller type              Kconfig options needed
+ * ---------------              ----------------------
+ * little endian                CONFIG_USB_OHCI_LITTLE_ENDIAN
+ *
+ * fully big endian             CONFIG_USB_OHCI_BIG_ENDIAN_DESC _and_
+ *                              CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ *
+ * mixed endian                 CONFIG_USB_OHCI_LITTLE_ENDIAN _and_
+ *                              CONFIG_USB_OHCI_BIG_ENDIAN_{MMIO,DESC}
+ *
+ * (If you have a mixed endian controller, you -must- also define
+ * CONFIG_USB_OHCI_LITTLE_ENDIAN or things will not work when building
+ * both your mixed endian and a fully big endian controller support in
+ * the same kernel image).
  */
 
-#ifdef CONFIG_USB_OHCI_BIG_ENDIAN
-
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_DESC
 #ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
-#define big_endian(ohci)	(ohci->flags & OHCI_BIG_ENDIAN) /* either */
+#define big_endian_desc(ohci)	(ohci->flags & OHCI_QUIRK_BE_DESC)
 #else
-#define big_endian(ohci)	1		/* only big endian */
+#define big_endian_desc(ohci)	1		/* only big endian */
+#endif
+#else
+#define big_endian_desc(ohci)	0		/* only little endian */
+#endif
+
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
+#define big_endian_mmio(ohci)	(ohci->flags & OHCI_QUIRK_BE_MMIO)
+#else
+#define big_endian_mmio(ohci)	1		/* only big endian */
+#endif
+#else
+#define big_endian_mmio(ohci)	0		/* only little endian */
 #endif
 
 /*
  * Big-endian read/write functions are arch-specific.
  * Other arches can be added if/when they're needed.
+ *
+ * REVISIT: arch/powerpc now has readl/writel_be, so the
+ * definition below can die once the STB04xxx support is
+ * finally ported over.
  */
-#if defined(CONFIG_PPC)
+#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE)
 #define readl_be(addr)		in_be32((__force unsigned *)addr)
 #define writel_be(val, addr)	out_be32((__force unsigned *)addr, val)
 #endif
 
-static inline unsigned int ohci_readl (const struct ohci_hcd *ohci,
-							__hc32 __iomem * regs)
+static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci,
+					__hc32 __iomem * regs)
 {
-	return big_endian(ohci) ? readl_be (regs) : readl ((__force u32 *)regs);
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+	return big_endian_mmio(ohci) ?
+		readl_be (regs) :
+		readl (regs);
+#else
+	return readl (regs);
+#endif
 }
 
-static inline void ohci_writel (const struct ohci_hcd *ohci,
-				const unsigned int val, __hc32 __iomem *regs)
+static inline void _ohci_writel (const struct ohci_hcd *ohci,
+				 const unsigned int val, __hc32 __iomem *regs)
 {
-	big_endian(ohci) ? writel_be (val, regs) :
-			   writel (val, (__force u32 *)regs);
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+	big_endian_mmio(ohci) ?
+		writel_be (val, regs) :
+		writel (val, regs);
+#else
+		writel (val, regs);
+#endif
 }
 
-#else	/* !CONFIG_USB_OHCI_BIG_ENDIAN */
-
-#define big_endian(ohci)	0		/* only little endian */
-
 #ifdef CONFIG_ARCH_LH7A404
-	/* Marc Singer: at the time this code was written, the LH7A404
-	 * had a problem reading the USB host registers.  This
-	 * implementation of the ohci_readl function performs the read
-	 * twice as a work-around.
-	 */
-static inline unsigned int
-ohci_readl (const struct ohci_hcd *ohci, const __hc32 *regs)
-{
-	*(volatile __force unsigned int*) regs;
-	return *(volatile __force unsigned int*) regs;
-}
+/* Marc Singer: at the time this code was written, the LH7A404
+ * had a problem reading the USB host registers.  This
+ * implementation of the ohci_readl function performs the read
+ * twice as a work-around.
+ */
+#define ohci_readl(o,r)		(_ohci_readl(o,r),_ohci_readl(o,r))
+#define ohci_writel(o,v,r)	_ohci_writel(o,v,r)
 #else
-	/* Standard version of ohci_readl uses standard, platform
-	 * specific implementation. */
-static inline unsigned int
-ohci_readl (const struct ohci_hcd *ohci, __hc32 __iomem * regs)
-{
-	return readl(regs);
-}
+#define ohci_readl(o,r)		_ohci_readl(o,r)
+#define ohci_writel(o,v,r)	_ohci_writel(o,v,r)
 #endif
 
-static inline void ohci_writel (const struct ohci_hcd *ohci,
-				const unsigned int val, __hc32 __iomem *regs)
-{
-	writel (val, regs);
-}
-
-#endif	/* !CONFIG_USB_OHCI_BIG_ENDIAN */
 
 /*-------------------------------------------------------------------------*/
 
 /* cpu to ohci */
 static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x)
 {
-	return big_endian(ohci) ? (__force __hc16)cpu_to_be16(x) : (__force __hc16)cpu_to_le16(x);
+	return big_endian_desc(ohci) ?
+		(__force __hc16)cpu_to_be16(x) :
+		(__force __hc16)cpu_to_le16(x);
 }
 
 static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x)
 {
-	return big_endian(ohci) ? cpu_to_be16p(x) : cpu_to_le16p(x);
+	return big_endian_desc(ohci) ?
+		cpu_to_be16p(x) :
+		cpu_to_le16p(x);
 }
 
 static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x)
 {
-	return big_endian(ohci) ? (__force __hc32)cpu_to_be32(x) : (__force __hc32)cpu_to_le32(x);
+	return big_endian_desc(ohci) ?
+		(__force __hc32)cpu_to_be32(x) :
+		(__force __hc32)cpu_to_le32(x);
 }
 
 static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x)
 {
-	return big_endian(ohci) ? cpu_to_be32p(x) : cpu_to_le32p(x);
+	return big_endian_desc(ohci) ?
+		cpu_to_be32p(x) :
+		cpu_to_le32p(x);
 }
 
 /* ohci to cpu */
 static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x)
 {
-	return big_endian(ohci) ? be16_to_cpu((__force __be16)x) : le16_to_cpu((__force __le16)x);
+	return big_endian_desc(ohci) ?
+		be16_to_cpu((__force __be16)x) :
+		le16_to_cpu((__force __le16)x);
 }
 
 static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x)
 {
-	return big_endian(ohci) ? be16_to_cpup((__force __be16 *)x) : le16_to_cpup((__force __le16 *)x);
+	return big_endian_desc(ohci) ?
+		be16_to_cpup((__force __be16 *)x) :
+		le16_to_cpup((__force __le16 *)x);
 }
 
 static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x)
 {
-	return big_endian(ohci) ? be32_to_cpu((__force __be32)x) : le32_to_cpu((__force __le32)x);
+	return big_endian_desc(ohci) ?
+		be32_to_cpu((__force __be32)x) :
+		le32_to_cpu((__force __le32)x);
 }
 
 static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
 {
-	return big_endian(ohci) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x);
+	return big_endian_desc(ohci) ?
+		be32_to_cpup((__force __be32 *)x) :
+		le32_to_cpup((__force __le32 *)x);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -557,6 +605,9 @@
 /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
  * hardware handles 16 bit reads.  That creates a different confusion on
  * some big-endian SOC implementations.  Same thing happens with PSW access.
+ *
+ * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
+ * to arch/powerpc
  */
 
 #ifdef CONFIG_STB03xxx
@@ -568,7 +619,7 @@
 static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
 {
 	u32 tmp;
-	if (big_endian(ohci)) {
+	if (big_endian_desc(ohci)) {
 		tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
 		tmp >>= OHCI_BE_FRAME_NO_SHIFT;
 	} else
@@ -580,7 +631,7 @@
 static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci,
                                  const struct td *td, int index)
 {
-	return (__hc16 *)(big_endian(ohci) ?
+	return (__hc16 *)(big_endian_desc(ohci) ?
 			&td->hwPSW[index ^ 1] : &td->hwPSW[index]);
 }
 
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index e345f15..5d6c06b 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -168,9 +168,13 @@
 			space, "", qh, qtype,
 			le32_to_cpu(qh->link), le32_to_cpu(element));
 	if (qh->type == USB_ENDPOINT_XFER_ISOC)
-		out += sprintf(out, "%*s    period %d frame %x desc [%p]\n",
-				space, "", qh->period, qh->iso_frame,
-				qh->iso_packet_desc);
+		out += sprintf(out, "%*s    period %d phase %d load %d us, "
+				"frame %x desc [%p]\n",
+				space, "", qh->period, qh->phase, qh->load,
+				qh->iso_frame, qh->iso_packet_desc);
+	else if (qh->type == USB_ENDPOINT_XFER_INT)
+		out += sprintf(out, "%*s    period %d phase %d load %d us\n",
+				space, "", qh->period, qh->phase, qh->load);
 
 	if (element & UHCI_PTR_QH)
 		out += sprintf(out, "%*s  Element points to QH (bug?)\n", space, "");
@@ -208,7 +212,7 @@
 					space, "", nurbs);
 	}
 
-	if (qh->udev) {
+	if (qh->dummy_td) {
 		out += sprintf(out, "%*s  Dummy TD\n", space, "");
 		out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
 	}
@@ -347,31 +351,80 @@
 	struct uhci_qh *qh;
 	struct uhci_td *td;
 	struct list_head *tmp, *head;
+	int nframes, nerrs;
 
 	out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
 	out += sprintf(out, "HC status\n");
 	out += uhci_show_status(uhci, out, len - (out - buf));
+
+	out += sprintf(out, "Periodic load table\n");
+	for (i = 0; i < MAX_PHASE; ++i) {
+		out += sprintf(out, "\t%d", uhci->load[i]);
+		if (i % 8 == 7)
+			*out++ = '\n';
+	}
+	out += sprintf(out, "Total: %d, #INT: %d, #ISO: %d\n",
+			uhci->total_load,
+			uhci_to_hcd(uhci)->self.bandwidth_int_reqs,
+			uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs);
 	if (debug <= 1)
 		return out - buf;
 
 	out += sprintf(out, "Frame List\n");
+	nframes = 10;
+	nerrs = 0;
 	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
-		td = uhci->frame_cpu[i];
-		if (!td)
-			continue;
+		__le32 link, qh_dma;
 
-		out += sprintf(out, "- Frame %d\n", i); \
-		if (td->dma_handle != (dma_addr_t)uhci->frame[i])
-			out += sprintf(out, "    frame list does not match td->dma_handle!\n");
+		j = 0;
+		td = uhci->frame_cpu[i];
+		link = uhci->frame[i];
+		if (!td)
+			goto check_link;
+
+		if (nframes > 0) {
+			out += sprintf(out, "- Frame %d -> (%08x)\n",
+					i, le32_to_cpu(link));
+			j = 1;
+		}
 
 		head = &td->fl_list;
 		tmp = head;
 		do {
 			td = list_entry(tmp, struct uhci_td, fl_list);
 			tmp = tmp->next;
-			out += uhci_show_td(td, out, len - (out - buf), 4);
+			if (cpu_to_le32(td->dma_handle) != link) {
+				if (nframes > 0)
+					out += sprintf(out, "    link does "
+						"not match list entry!\n");
+				else
+					++nerrs;
+			}
+			if (nframes > 0)
+				out += uhci_show_td(td, out,
+						len - (out - buf), 4);
+			link = td->link;
 		} while (tmp != head);
+
+check_link:
+		qh_dma = uhci_frame_skel_link(uhci, i);
+		if (link != qh_dma) {
+			if (nframes > 0) {
+				if (!j) {
+					out += sprintf(out,
+						"- Frame %d -> (%08x)\n",
+						i, le32_to_cpu(link));
+					j = 1;
+				}
+				out += sprintf(out, "   link does not match "
+					"QH (%08x)!\n", le32_to_cpu(qh_dma));
+			} else
+				++nerrs;
+		}
+		nframes -= j;
 	}
+	if (nerrs > 0)
+		out += sprintf(out, "Skipped %d bad links\n", nerrs);
 
 	out += sprintf(out, "Skeleton QHs\n");
 
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index e0d4c23..49b9d39 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -92,6 +92,34 @@
 static void wakeup_rh(struct uhci_hcd *uhci);
 static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
 
+/*
+ * Calculate the link pointer DMA value for the first Skeleton QH in a frame.
+ */
+static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
+{
+	int skelnum;
+
+	/*
+	 * The interrupt queues will be interleaved as evenly as possible.
+	 * There's not much to be done about period-1 interrupts; they have
+	 * to occur in every frame.  But we can schedule period-2 interrupts
+	 * in odd-numbered frames, period-4 interrupts in frames congruent
+	 * to 2 (mod 4), and so on.  This way each frame only has two
+	 * interrupt QHs, which will help spread out bandwidth utilization.
+	 *
+	 * ffs (Find First bit Set) does exactly what we need:
+	 * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[8],
+	 * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
+	 * ffs >= 7 => not on any high-period queue, so use
+	 *	skel_int1_qh = skelqh[9].
+	 * Add in UHCI_NUMFRAMES to insure at least one bit is set.
+	 */
+	skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES);
+	if (skelnum <= 1)
+		skelnum = 9;
+	return UHCI_PTR_QH | cpu_to_le32(uhci->skelqh[skelnum]->dma_handle);
+}
+
 #include "uhci-debug.c"
 #include "uhci-q.c"
 #include "uhci-hub.c"
@@ -631,32 +659,11 @@
 	/*
 	 * Fill the frame list: make all entries point to the proper
 	 * interrupt queue.
-	 *
-	 * The interrupt queues will be interleaved as evenly as possible.
-	 * There's not much to be done about period-1 interrupts; they have
-	 * to occur in every frame.  But we can schedule period-2 interrupts
-	 * in odd-numbered frames, period-4 interrupts in frames congruent
-	 * to 2 (mod 4), and so on.  This way each frame only has two
-	 * interrupt QHs, which will help spread out bandwidth utilization.
 	 */
 	for (i = 0; i < UHCI_NUMFRAMES; i++) {
-		int irq;
-
-		/*
-		 * ffs (Find First bit Set) does exactly what we need:
-		 * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[8],
-		 * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
-		 * ffs >= 7 => not on any high-period queue, so use
-		 *	skel_int1_qh = skelqh[9].
-		 * Add UHCI_NUMFRAMES to insure at least one bit is set.
-		 */
-		irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES);
-		if (irq <= 1)
-			irq = 9;
 
 		/* Only place we don't use the frame list routines */
-		uhci->frame[i] = UHCI_PTR_QH |
-				cpu_to_le32(uhci->skelqh[irq]->dma_handle);
+		uhci->frame[i] = uhci_frame_skel_link(uhci, i);
 	}
 
 	/*
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 108e3de..74469b5 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -83,6 +83,7 @@
 #define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
 #define CAN_SCHEDULE_FRAMES	1000	/* how far in the future frames
 					 * can be scheduled */
+#define MAX_PHASE		32	/* Periodic scheduling length */
 
 /* When no queues need Full-Speed Bandwidth Reclamation,
  * delay this long before turning FSBR off */
@@ -141,6 +142,8 @@
 	unsigned long advance_jiffies;	/* Time of last queue advance */
 	unsigned int unlink_frame;	/* When the QH was unlinked */
 	unsigned int period;		/* For Interrupt and Isochronous QHs */
+	short phase;			/* Between 0 and period-1 */
+	short load;			/* Periodic time requirement, in us */
 	unsigned int iso_frame;		/* Frame # for iso_packet_desc */
 	int iso_status;			/* Status for Isochronous URBs */
 
@@ -153,6 +156,8 @@
 	unsigned int needs_fixup:1;	/* Must fix the TD toggle values */
 	unsigned int is_stopped:1;	/* Queue was stopped by error/unlink */
 	unsigned int wait_expired:1;	/* QH_WAIT_TIMEOUT has expired */
+	unsigned int bandwidth_reserved:1;	/* Periodic bandwidth has
+						 * been allocated */
 } __attribute__((aligned(16)));
 
 /*
@@ -414,6 +419,9 @@
 
 	wait_queue_head_t waitqh;		/* endpoint_disable waiters */
 	int num_waiting;			/* Number of waiters */
+
+	int total_load;				/* Sum of array values */
+	short load[MAX_PHASE];			/* Periodic allocations */
 };
 
 /* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 30b8845..2cbb239 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -248,16 +248,26 @@
 	INIT_LIST_HEAD(&qh->node);
 
 	if (udev) {		/* Normal QH */
-		qh->dummy_td = uhci_alloc_td(uhci);
-		if (!qh->dummy_td) {
-			dma_pool_free(uhci->qh_pool, qh, dma_handle);
-			return NULL;
+		qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+		if (qh->type != USB_ENDPOINT_XFER_ISOC) {
+			qh->dummy_td = uhci_alloc_td(uhci);
+			if (!qh->dummy_td) {
+				dma_pool_free(uhci->qh_pool, qh, dma_handle);
+				return NULL;
+			}
 		}
 		qh->state = QH_STATE_IDLE;
 		qh->hep = hep;
 		qh->udev = udev;
 		hep->hcpriv = qh;
-		qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+		if (qh->type == USB_ENDPOINT_XFER_INT ||
+				qh->type == USB_ENDPOINT_XFER_ISOC)
+			qh->load = usb_calc_bus_time(udev->speed,
+					usb_endpoint_dir_in(&hep->desc),
+					qh->type == USB_ENDPOINT_XFER_ISOC,
+					le16_to_cpu(hep->desc.wMaxPacketSize))
+				/ 1000 + 1;
 
 	} else {		/* Skeleton QH */
 		qh->state = QH_STATE_ACTIVE;
@@ -275,7 +285,8 @@
 	list_del(&qh->node);
 	if (qh->udev) {
 		qh->hep->hcpriv = NULL;
-		uhci_free_td(uhci, qh->dummy_td);
+		if (qh->dummy_td)
+			uhci_free_td(uhci, qh->dummy_td);
 	}
 	dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
 }
@@ -327,7 +338,7 @@
 		goto done;
 	qh->element = UHCI_PTR_TERM;
 
-	/* Control pipes have to worry about toggles */
+	/* Control pipes don't have to worry about toggles */
 	if (qh->type == USB_ENDPOINT_XFER_CONTROL)
 		goto done;
 
@@ -493,6 +504,121 @@
 		wake_up_all(&uhci->waitqh);
 }
 
+/*
+ * Find the highest existing bandwidth load for a given phase and period.
+ */
+static int uhci_highest_load(struct uhci_hcd *uhci, int phase, int period)
+{
+	int highest_load = uhci->load[phase];
+
+	for (phase += period; phase < MAX_PHASE; phase += period)
+		highest_load = max_t(int, highest_load, uhci->load[phase]);
+	return highest_load;
+}
+
+/*
+ * Set qh->phase to the optimal phase for a periodic transfer and
+ * check whether the bandwidth requirement is acceptable.
+ */
+static int uhci_check_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+	int minimax_load;
+
+	/* Find the optimal phase (unless it is already set) and get
+	 * its load value. */
+	if (qh->phase >= 0)
+		minimax_load = uhci_highest_load(uhci, qh->phase, qh->period);
+	else {
+		int phase, load;
+		int max_phase = min_t(int, MAX_PHASE, qh->period);
+
+		qh->phase = 0;
+		minimax_load = uhci_highest_load(uhci, qh->phase, qh->period);
+		for (phase = 1; phase < max_phase; ++phase) {
+			load = uhci_highest_load(uhci, phase, qh->period);
+			if (load < minimax_load) {
+				minimax_load = load;
+				qh->phase = phase;
+			}
+		}
+	}
+
+	/* Maximum allowable periodic bandwidth is 90%, or 900 us per frame */
+	if (minimax_load + qh->load > 900) {
+		dev_dbg(uhci_dev(uhci), "bandwidth allocation failed: "
+				"period %d, phase %d, %d + %d us\n",
+				qh->period, qh->phase, minimax_load, qh->load);
+		return -ENOSPC;
+	}
+	return 0;
+}
+
+/*
+ * Reserve a periodic QH's bandwidth in the schedule
+ */
+static void uhci_reserve_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+	int i;
+	int load = qh->load;
+	char *p = "??";
+
+	for (i = qh->phase; i < MAX_PHASE; i += qh->period) {
+		uhci->load[i] += load;
+		uhci->total_load += load;
+	}
+	uhci_to_hcd(uhci)->self.bandwidth_allocated =
+			uhci->total_load / MAX_PHASE;
+	switch (qh->type) {
+	case USB_ENDPOINT_XFER_INT:
+		++uhci_to_hcd(uhci)->self.bandwidth_int_reqs;
+		p = "INT";
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		++uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs;
+		p = "ISO";
+		break;
+	}
+	qh->bandwidth_reserved = 1;
+	dev_dbg(uhci_dev(uhci),
+			"%s dev %d ep%02x-%s, period %d, phase %d, %d us\n",
+			"reserve", qh->udev->devnum,
+			qh->hep->desc.bEndpointAddress, p,
+			qh->period, qh->phase, load);
+}
+
+/*
+ * Release a periodic QH's bandwidth reservation
+ */
+static void uhci_release_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+	int i;
+	int load = qh->load;
+	char *p = "??";
+
+	for (i = qh->phase; i < MAX_PHASE; i += qh->period) {
+		uhci->load[i] -= load;
+		uhci->total_load -= load;
+	}
+	uhci_to_hcd(uhci)->self.bandwidth_allocated =
+			uhci->total_load / MAX_PHASE;
+	switch (qh->type) {
+	case USB_ENDPOINT_XFER_INT:
+		--uhci_to_hcd(uhci)->self.bandwidth_int_reqs;
+		p = "INT";
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		--uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs;
+		p = "ISO";
+		break;
+	}
+	qh->bandwidth_reserved = 0;
+	dev_dbg(uhci_dev(uhci),
+			"%s dev %d ep%02x-%s, period %d, phase %d, %d us\n",
+			"release", qh->udev->devnum,
+			qh->hep->desc.bEndpointAddress, p,
+			qh->period, qh->phase, load);
+}
+
 static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci,
 		struct urb *urb)
 {
@@ -796,7 +922,6 @@
 	wmb();
 	qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
 	qh->dummy_td = td;
-	qh->period = urb->interval;
 
 	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
 			usb_pipeout(urb->pipe), toggle);
@@ -827,28 +952,42 @@
 static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
 		struct uhci_qh *qh)
 {
-	int exponent;
+	int ret;
 
 	/* USB 1.1 interrupt transfers only involve one packet per interval.
 	 * Drivers can submit URBs of any length, but longer ones will need
 	 * multiple intervals to complete.
 	 */
 
-	/* Figure out which power-of-two queue to use */
-	for (exponent = 7; exponent >= 0; --exponent) {
-		if ((1 << exponent) <= urb->interval)
-			break;
-	}
-	if (exponent < 0)
-		return -EINVAL;
-	urb->interval = 1 << exponent;
+	if (!qh->bandwidth_reserved) {
+		int exponent;
 
-	if (qh->period == 0)
+		/* Figure out which power-of-two queue to use */
+		for (exponent = 7; exponent >= 0; --exponent) {
+			if ((1 << exponent) <= urb->interval)
+				break;
+		}
+		if (exponent < 0)
+			return -EINVAL;
+		qh->period = 1 << exponent;
 		qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)];
-	else if (qh->period != urb->interval)
-		return -EINVAL;		/* Can't change the period */
 
-	return uhci_submit_common(uhci, urb, qh);
+		/* For now, interrupt phase is fixed by the layout
+		 * of the QH lists. */
+		qh->phase = (qh->period / 2) & (MAX_PHASE - 1);
+		ret = uhci_check_bandwidth(uhci, qh);
+		if (ret)
+			return ret;
+	} else if (qh->period > urb->interval)
+		return -EINVAL;		/* Can't decrease the period */
+
+	ret = uhci_submit_common(uhci, urb, qh);
+	if (ret == 0) {
+		urb->interval = qh->period;
+		if (!qh->bandwidth_reserved)
+			uhci_reserve_bandwidth(uhci, qh);
+	}
+	return ret;
 }
 
 /*
@@ -995,15 +1134,32 @@
 		return -EFBIG;
 
 	/* Check the period and figure out the starting frame number */
-	if (qh->period == 0) {
+	if (!qh->bandwidth_reserved) {
+		qh->period = urb->interval;
 		if (urb->transfer_flags & URB_ISO_ASAP) {
+			qh->phase = -1;		/* Find the best phase */
+			i = uhci_check_bandwidth(uhci, qh);
+			if (i)
+				return i;
+
+			/* Allow a little time to allocate the TDs */
 			uhci_get_current_frame_number(uhci);
-			urb->start_frame = uhci->frame_number + 10;
+			frame = uhci->frame_number + 10;
+
+			/* Move forward to the first frame having the
+			 * correct phase */
+			urb->start_frame = frame + ((qh->phase - frame) &
+					(qh->period - 1));
 		} else {
 			i = urb->start_frame - uhci->last_iso_frame;
 			if (i <= 0 || i >= UHCI_NUMFRAMES)
 				return -EINVAL;
+			qh->phase = urb->start_frame & (qh->period - 1);
+			i = uhci_check_bandwidth(uhci, qh);
+			if (i)
+				return i;
 		}
+
 	} else if (qh->period != urb->interval) {
 		return -EINVAL;		/* Can't change the period */
 
@@ -1049,9 +1205,6 @@
 	/* Set the interrupt-on-completion flag on the last packet. */
 	td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
 
-	qh->skel = uhci->skel_iso_qh;
-	qh->period = urb->interval;
-
 	/* Add the TDs to the frame list */
 	frame = urb->start_frame;
 	list_for_each_entry(td, &urbp->td_list, list) {
@@ -1065,6 +1218,9 @@
 		qh->iso_status = 0;
 	}
 
+	qh->skel = uhci->skel_iso_qh;
+	if (!qh->bandwidth_reserved)
+		uhci_reserve_bandwidth(uhci, qh);
 	return 0;
 }
 
@@ -1119,7 +1275,6 @@
 	unsigned long flags;
 	struct urb_priv *urbp;
 	struct uhci_qh *qh;
-	int bustime;
 
 	spin_lock_irqsave(&uhci->lock, flags);
 
@@ -1149,35 +1304,11 @@
 		ret = uhci_submit_bulk(uhci, urb, qh);
 		break;
 	case USB_ENDPOINT_XFER_INT:
-		if (list_empty(&qh->queue)) {
-			bustime = usb_check_bandwidth(urb->dev, urb);
-			if (bustime < 0)
-				ret = bustime;
-			else {
-				ret = uhci_submit_interrupt(uhci, urb, qh);
-				if (ret == 0)
-					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
-			}
-		} else {	/* inherit from parent */
-			struct urb_priv *eurbp;
-
-			eurbp = list_entry(qh->queue.prev, struct urb_priv,
-					node);
-			urb->bandwidth = eurbp->urb->bandwidth;
-			ret = uhci_submit_interrupt(uhci, urb, qh);
-		}
+		ret = uhci_submit_interrupt(uhci, urb, qh);
 		break;
 	case USB_ENDPOINT_XFER_ISOC:
 		urb->error_count = 0;
-		bustime = usb_check_bandwidth(urb->dev, urb);
-		if (bustime < 0) {
-			ret = bustime;
-			break;
-		}
-
 		ret = uhci_submit_isochronous(uhci, urb, qh);
-		if (ret == 0)
-			usb_claim_bandwidth(urb->dev, urb, bustime, 1);
 		break;
 	}
 	if (ret != 0)
@@ -1274,24 +1405,6 @@
 
 	uhci_free_urb_priv(uhci, urbp);
 
-	switch (qh->type) {
-	case USB_ENDPOINT_XFER_ISOC:
-		/* Release bandwidth for Interrupt or Isoc. transfers */
-		if (urb->bandwidth)
-			usb_release_bandwidth(urb->dev, urb, 1);
-		break;
-	case USB_ENDPOINT_XFER_INT:
-		/* Release bandwidth for Interrupt or Isoc. transfers */
-		/* Make sure we don't release if we have a queued URB */
-		if (list_empty(&qh->queue) && urb->bandwidth)
-			usb_release_bandwidth(urb->dev, urb, 0);
-		else
-			/* bandwidth was passed on to queued URB, */
-			/* so don't let usb_unlink_urb() release it */
-			urb->bandwidth = 0;
-		break;
-	}
-
 	spin_unlock(&uhci->lock);
 	usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
 	spin_lock(&uhci->lock);
@@ -1300,9 +1413,8 @@
 	 * reserved bandwidth. */
 	if (list_empty(&qh->queue)) {
 		uhci_unlink_qh(uhci, qh);
-
-		/* Bandwidth stuff not yet implemented */
-		qh->period = 0;
+		if (qh->bandwidth_reserved)
+			uhci_release_bandwidth(uhci, qh);
 	}
 }
 
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 63a84bb..d308afd 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -565,11 +565,15 @@
 
 		usb_deregister_dev(intf, &mdc800_class);
 
+		/* must be under lock to make sure no URB
+		   is submitted after usb_kill_urb() */
+		mutex_lock(&mdc800->io_lock);
 		mdc800->state=NOT_CONNECTED;
 
 		usb_kill_urb(mdc800->irq_urb);
 		usb_kill_urb(mdc800->write_urb);
 		usb_kill_urb(mdc800->download_urb);
+		mutex_unlock(&mdc800->io_lock);
 
 		mdc800->dev = NULL;
 		usb_set_intfdata(intf, NULL);
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
index c7d8875..2e71d3c 100644
--- a/drivers/usb/input/Kconfig
+++ b/drivers/usb/input/Kconfig
@@ -69,6 +69,14 @@
 	  Note: if you say N here, this device will still be supported, but without
 	  force feedback.
 
+config PANTHERLORD_FF
+	bool "PantherLord USB/PS2 2in1 Adapter support"
+	depends on HID_FF
+	select INPUT_FF_MEMLESS if USB_HID
+	help
+	  Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want
+	  to enable force feedback support for it.
+
 config THRUSTMASTER_FF
 	bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)"
 	depends on HID_FF && EXPERIMENTAL
@@ -344,3 +352,15 @@
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called appletouch.
+
+config USB_GTCO
+        tristate "GTCO CalComp/InterWrite USB Support"
+        depends on USB && INPUT
+        ---help---
+          Say Y here if you want to use the USB version of the GTCO
+          CalComp/InterWrite Tablet.  Make sure to say Y to "Mouse support"
+          (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+          (CONFIG_INPUT_EVDEV) as well.
+
+          To compile this driver as a module, choose M here: the
+          module will be called gtco.
diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile
index 1a24b5b..a9d206c 100644
--- a/drivers/usb/input/Makefile
+++ b/drivers/usb/input/Makefile
@@ -17,6 +17,9 @@
 ifeq ($(CONFIG_LOGITECH_FF),y)
 	usbhid-objs	+= hid-lgff.o
 endif
+ifeq ($(CONFIG_PANTHERLORD_FF),y)
+	usbhid-objs	+= hid-plff.o
+endif
 ifeq ($(CONFIG_THRUSTMASTER_FF),y)
 	usbhid-objs	+= hid-tmff.o
 endif
@@ -45,6 +48,7 @@
 obj-$(CONFIG_USB_YEALINK)	+= yealink.o
 obj-$(CONFIG_USB_XPAD)		+= xpad.o
 obj-$(CONFIG_USB_APPLETOUCH)	+= appletouch.o
+obj-$(CONFIG_USB_GTCO)         += gtco.o
 
 ifeq ($(CONFIG_USB_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/usb/input/gtco.c b/drivers/usb/input/gtco.c
new file mode 100644
index 0000000..203cdc1bb
--- /dev/null
+++ b/drivers/usb/input/gtco.c
@@ -0,0 +1,1104 @@
+/*    -*- linux-c -*-
+
+GTCO digitizer USB driver
+
+Use the err(), dbg() and info() macros from usb.h for system logging
+
+TO CHECK:  Is pressure done right on report 5?
+
+Copyright (C) 2006  GTCO CalComp
+
+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.
+
+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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of GTCO-CalComp not be used in advertising
+or publicity pertaining to distribution of the software without specific,
+written prior permission. GTCO-CalComp makes no representations about the
+suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+
+GTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+GTCO CalComp, Inc.
+7125 Riverwood Drive
+Columbia, MD 21046
+
+Jeremy Roberson jroberson@gtcocalcomp.com
+Scott Hill shill@gtcocalcomp.com
+*/
+
+
+
+/*#define DEBUG*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+
+#include <linux/version.h>
+#include <linux/usb/input.h>
+
+/* Version with a Major number of 2 is for kernel inclusion only. */
+#define  GTCO_VERSION   "2.00.0006"
+
+
+/*   MACROS  */
+
+#define VENDOR_ID_GTCO	      0x078C
+#define PID_400               0x400
+#define PID_401               0x401
+#define PID_1000              0x1000
+#define PID_1001              0x1001
+#define PID_1002              0x1002
+
+/* Max size of a single report */
+#define REPORT_MAX_SIZE       10
+
+
+/* Bitmask whether pen is in range */
+#define MASK_INRANGE 0x20
+#define MASK_BUTTON  0x01F
+
+#define  PATHLENGTH     64
+
+/* DATA STRUCTURES */
+
+/* Device table */
+static struct usb_device_id gtco_usbid_table [] = {
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_400) },
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_401) },
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_1000) },
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_1001) },
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_1002) },
+	{ }
+};
+MODULE_DEVICE_TABLE (usb, gtco_usbid_table);
+
+
+/* Structure to hold all of our device specific stuff */
+struct gtco {
+
+	struct input_dev  *inputdevice; /* input device struct pointer  */
+	struct usb_device *usbdev; /* the usb device for this device */
+	struct urb        *urbinfo;	 /* urb for incoming reports      */
+	dma_addr_t        buf_dma;  /* dma addr of the data buffer*/
+	unsigned char *   buffer;   /* databuffer for reports */
+
+	char  usbpath[PATHLENGTH];
+	int   openCount;
+
+	/* Information pulled from Report Descriptor */
+	u32  usage;
+	u32  min_X;
+	u32  max_X;
+	u32  min_Y;
+	u32  max_Y;
+	s8   mintilt_X;
+	s8   maxtilt_X;
+	s8   mintilt_Y;
+	s8   maxtilt_Y;
+	u32  maxpressure;
+	u32  minpressure;
+};
+
+
+
+/*   Code for parsing the HID REPORT DESCRIPTOR          */
+
+/* From HID1.11 spec */
+struct hid_descriptor
+{
+	struct usb_descriptor_header header;
+	__le16   bcdHID;
+	u8       bCountryCode;
+	u8       bNumDescriptors;
+	u8       bDescriptorType;
+	__le16   wDescriptorLength;
+} __attribute__ ((packed));
+
+
+#define HID_DESCRIPTOR_SIZE   9
+#define HID_DEVICE_TYPE       33
+#define REPORT_DEVICE_TYPE    34
+
+
+#define PREF_TAG(x)     ((x)>>4)
+#define PREF_TYPE(x)    ((x>>2)&0x03)
+#define PREF_SIZE(x)    ((x)&0x03)
+
+#define TYPE_MAIN       0
+#define TYPE_GLOBAL     1
+#define TYPE_LOCAL      2
+#define TYPE_RESERVED   3
+
+#define TAG_MAIN_INPUT        0x8
+#define TAG_MAIN_OUTPUT       0x9
+#define TAG_MAIN_FEATURE      0xB
+#define TAG_MAIN_COL_START    0xA
+#define TAG_MAIN_COL_END      0xC
+
+#define TAG_GLOB_USAGE        0
+#define TAG_GLOB_LOG_MIN      1
+#define TAG_GLOB_LOG_MAX      2
+#define TAG_GLOB_PHYS_MIN     3
+#define TAG_GLOB_PHYS_MAX     4
+#define TAG_GLOB_UNIT_EXP     5
+#define TAG_GLOB_UNIT         6
+#define TAG_GLOB_REPORT_SZ    7
+#define TAG_GLOB_REPORT_ID    8
+#define TAG_GLOB_REPORT_CNT   9
+#define TAG_GLOB_PUSH         10
+#define TAG_GLOB_POP          11
+
+#define TAG_GLOB_MAX          12
+
+#define DIGITIZER_USAGE_TIP_PRESSURE   0x30
+#define DIGITIZER_USAGE_TILT_X         0x3D
+#define DIGITIZER_USAGE_TILT_Y         0x3E
+
+
+/*
+ *
+ *   This is an abbreviated parser for the HID Report Descriptor.  We
+ *   know what devices we are talking to, so this is by no means meant
+ *   to be generic.  We can make some safe assumptions:
+ *
+ *   - We know there are no LONG tags, all short
+ *   - We know that we have no MAIN Feature and MAIN Output items
+ *   - We know what the IRQ reports are supposed to look like.
+ *
+ *   The main purpose of this is to use the HID report desc to figure
+ *   out the mins and maxs of the fields in the IRQ reports.  The IRQ
+ *   reports for 400/401 change slightly if the max X is bigger than 64K.
+ *
+ */
+static void parse_hid_report_descriptor(struct gtco *device, char * report,
+					int length)
+{
+	int   x,i=0;
+
+	/* Tag primitive vars */
+	__u8   prefix;
+	__u8   size;
+	__u8   tag;
+	__u8   type;
+	__u8   data   = 0;
+	__u16  data16 = 0;
+	__u32  data32 = 0;
+
+
+	/* For parsing logic */
+	int   inputnum = 0;
+	__u32 usage = 0;
+
+	/* Global Values, indexed by TAG */
+	__u32 globalval[TAG_GLOB_MAX];
+	__u32 oldval[TAG_GLOB_MAX];
+
+	/* Debug stuff */
+	char  maintype='x';
+	char  globtype[12];
+	int   indent=0;
+	char  indentstr[10]="";
+
+
+
+	dbg("======>>>>>>PARSE<<<<<<======");
+
+	/* Walk  this report and pull out the info we need */
+	while (i<length){
+		prefix=report[i];
+
+		/* Skip over prefix */
+		i++;
+
+		/* Determine data size and save the data in the proper variable */
+		size = PREF_SIZE(prefix);
+		switch(size){
+		case 1:
+			data = report[i];
+			break;
+		case 2:
+			data16 = le16_to_cpu(get_unaligned((__le16*)(&(report[i]))));
+			break;
+		case 3:
+			size = 4;
+			data32 = le32_to_cpu(get_unaligned((__le32*)(&(report[i]))));
+		}
+
+		/* Skip size of data */
+		i+=size;
+
+		/* What we do depends on the tag type */
+		tag  = PREF_TAG(prefix);
+		type = PREF_TYPE(prefix);
+		switch(type){
+		case TYPE_MAIN:
+			strcpy(globtype,"");
+			switch(tag){
+
+			case TAG_MAIN_INPUT:
+				/*
+				 * The INPUT MAIN tag signifies this is
+				 * information from a report.  We need to
+				 * figure out what it is and store the
+				 * min/max values
+				 */
+
+				maintype='I';
+				if (data==2){
+					strcpy(globtype,"Variable");
+				}
+				if (data==3){
+					strcpy(globtype,"Var|Const");
+				}
+
+				dbg("::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits",
+				    globalval[TAG_GLOB_REPORT_ID],inputnum,
+				    globalval[TAG_GLOB_LOG_MAX],globalval[TAG_GLOB_LOG_MAX],
+				    globalval[TAG_GLOB_LOG_MIN],globalval[TAG_GLOB_LOG_MIN],
+				    (globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]));
+
+
+				/*
+				  We can assume that the first two input items
+				  are always the X and Y coordinates.  After
+				  that, we look for everything else by
+				  local usage value
+				 */
+				switch (inputnum){
+				case 0:  /* X coord */
+					dbg("GER: X Usage: 0x%x",usage);
+					if (device->max_X == 0){
+						device->max_X = globalval[TAG_GLOB_LOG_MAX];
+						device->min_X = globalval[TAG_GLOB_LOG_MIN];
+					}
+
+					break;
+				case 1:  /* Y coord */
+					dbg("GER: Y Usage: 0x%x",usage);
+					if (device->max_Y == 0){
+						device->max_Y = globalval[TAG_GLOB_LOG_MAX];
+						device->min_Y = globalval[TAG_GLOB_LOG_MIN];
+					}
+					break;
+				default:
+					/* Tilt X */
+					if (usage == DIGITIZER_USAGE_TILT_X){
+						if (device->maxtilt_X == 0){
+							device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX];
+							device->mintilt_X = globalval[TAG_GLOB_LOG_MIN];
+						}
+					}
+
+					/* Tilt Y */
+					if (usage == DIGITIZER_USAGE_TILT_Y){
+						if (device->maxtilt_Y == 0){
+							device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX];
+							device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN];
+						}
+					}
+
+
+					/* Pressure */
+					if (usage == DIGITIZER_USAGE_TIP_PRESSURE){
+						if (device->maxpressure == 0){
+							device->maxpressure = globalval[TAG_GLOB_LOG_MAX];
+							device->minpressure = globalval[TAG_GLOB_LOG_MIN];
+						}
+					}
+
+					break;
+				}
+
+				inputnum++;
+
+
+				break;
+			case TAG_MAIN_OUTPUT:
+				maintype='O';
+				break;
+			case TAG_MAIN_FEATURE:
+				maintype='F';
+				break;
+			case TAG_MAIN_COL_START:
+				maintype='S';
+
+				if (data==0){
+					dbg("======>>>>>> Physical");
+					strcpy(globtype,"Physical");
+				}else{
+					dbg("======>>>>>>");
+				}
+
+				/* Indent the debug output */
+				indent++;
+				for (x=0;x<indent;x++){
+					indentstr[x]='-';
+				}
+				indentstr[x]=0;
+
+				/* Save global tags */
+				for (x=0;x<TAG_GLOB_MAX;x++){
+					oldval[x] = globalval[x];
+				}
+
+				break;
+			case TAG_MAIN_COL_END:
+				dbg("<<<<<<======");
+				maintype='E';
+				indent--;
+				for (x=0;x<indent;x++){
+					indentstr[x]='-';
+				}
+				indentstr[x]=0;
+
+				/* Copy global tags back */
+				for (x=0;x<TAG_GLOB_MAX;x++){
+					globalval[x] = oldval[x];
+				}
+
+				break;
+			}
+
+			switch (size){
+			case 1:
+				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+				    indentstr,tag,maintype,size,globtype,data);
+				break;
+			case 2:
+				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+				    indentstr,tag,maintype,size,globtype, data16);
+				break;
+			case 4:
+				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+				    indentstr,tag,maintype,size,globtype,data32);
+				break;
+			}
+			break;
+		case TYPE_GLOBAL:
+			switch(tag){
+			case TAG_GLOB_USAGE:
+				/*
+				 * First time we hit the global usage tag,
+				 * it should tell us the type of device
+				 */
+				if (device->usage == 0){
+					device->usage = data;
+				}
+				strcpy(globtype,"USAGE");
+				break;
+			case TAG_GLOB_LOG_MIN   :
+				strcpy(globtype,"LOG_MIN");
+				break;
+			case TAG_GLOB_LOG_MAX   :
+				strcpy(globtype,"LOG_MAX");
+				break;
+			case TAG_GLOB_PHYS_MIN  :
+				strcpy(globtype,"PHYS_MIN");
+				break;
+			case TAG_GLOB_PHYS_MAX  :
+				strcpy(globtype,"PHYS_MAX");
+				break;
+			case TAG_GLOB_UNIT_EXP  :
+				strcpy(globtype,"EXP");
+				break;
+			case TAG_GLOB_UNIT      :
+				strcpy(globtype,"UNIT");
+				break;
+			case TAG_GLOB_REPORT_SZ :
+				strcpy(globtype,"REPORT_SZ");
+				break;
+			case TAG_GLOB_REPORT_ID :
+				strcpy(globtype,"REPORT_ID");
+				/* New report, restart numbering */
+				inputnum=0;
+				break;
+			case TAG_GLOB_REPORT_CNT:
+				strcpy(globtype,"REPORT_CNT");
+				break;
+			case TAG_GLOB_PUSH :
+				strcpy(globtype,"PUSH");
+				break;
+			case TAG_GLOB_POP:
+				strcpy(globtype,"POP");
+				break;
+			}
+
+
+			/* Check to make sure we have a good tag number
+			   so we don't overflow array */
+			if (tag < TAG_GLOB_MAX){
+				switch (size){
+				case 1:
+					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data);
+					globalval[tag]=data;
+					break;
+				case 2:
+					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data16);
+					globalval[tag]=data16;
+					break;
+				case 4:
+					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data32);
+					globalval[tag]=data32;
+					break;
+				}
+			}else{
+				dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ",
+				    indentstr,tag,size);
+			}
+
+
+			break;
+
+		case TYPE_LOCAL:
+			switch(tag){
+			case TAG_GLOB_USAGE:
+				strcpy(globtype,"USAGE");
+				/* Always 1 byte */
+				usage = data;
+				break;
+			case TAG_GLOB_LOG_MIN   :
+				strcpy(globtype,"MIN");
+				break;
+			case TAG_GLOB_LOG_MAX   :
+				strcpy(globtype,"MAX");
+				break;
+			default:
+				strcpy(globtype,"UNKNOWN");
+			}
+
+			switch (size){
+			case 1:
+				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+				    indentstr,tag,globtype,size,data);
+				break;
+			case 2:
+				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+				    indentstr,tag,globtype,size,data16);
+				break;
+			case 4:
+				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+				    indentstr,tag,globtype,size,data32);
+				break;
+			}
+
+			break;
+		}
+
+	}
+
+}
+
+
+
+/*   INPUT DRIVER Routines                               */
+
+
+/*
+ *    Called when opening the input device.  This will submit the URB to
+ *    the usb system so we start getting reports
+ */
+static int gtco_input_open(struct input_dev *inputdev)
+{
+	struct gtco *device;
+	device = inputdev->private;
+
+	device->urbinfo->dev = device->usbdev;
+	if (usb_submit_urb(device->urbinfo, GFP_KERNEL)) {
+		return -EIO;
+	}
+	return 0;
+}
+
+/**
+    Called when closing the input device.  This will unlink the URB
+*/
+static void gtco_input_close(struct input_dev *inputdev)
+{
+	struct gtco *device = inputdev->private;
+
+	usb_kill_urb(device->urbinfo);
+
+}
+
+
+/*
+ *  Setup input device capabilities.  Tell the input system what this
+ *  device is capable of generating.
+ *
+ *  This information is based on what is read from the HID report and
+ *  placed in the struct gtco structure
+ *
+ */
+static void  gtco_setup_caps(struct input_dev  *inputdev)
+{
+	struct gtco *device = inputdev->private;
+
+
+	/* Which events */
+	inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
+
+
+	/* Misc event menu block */
+	inputdev->mscbit[0] = BIT(MSC_SCAN)|BIT(MSC_SERIAL)|BIT(MSC_RAW) ;
+
+
+	/* Absolute values based on HID report info */
+	input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X,
+			     0, 0);
+	input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y,
+			     0, 0);
+
+	/* Proximity */
+	input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0);
+
+	/* Tilt & pressure */
+	input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X,
+			     device->maxtilt_X, 0, 0);
+	input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y,
+			     device->maxtilt_Y, 0, 0);
+	input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure,
+			     device->maxpressure, 0, 0);
+
+
+	/* Transducer */
+	input_set_abs_params(inputdev, ABS_MISC, 0,0xFF, 0, 0);
+
+}
+
+
+
+/*   USB Routines  */
+
+
+/*
+ * URB callback routine.  Called when we get IRQ reports from the
+ *  digitizer.
+ *
+ *  This bridges the USB and input device worlds.  It generates events
+ *  on the input device based on the USB reports.
+ */
+static void gtco_urb_callback(struct urb *urbinfo)
+{
+
+
+	struct gtco     *device = urbinfo->context;
+	struct input_dev  *inputdev;
+	int               rc;
+	u32               val = 0;
+	s8                valsigned = 0;
+	char              le_buffer[2];
+
+	inputdev = device->inputdevice;
+
+
+	/* Was callback OK? */
+	if ((urbinfo->status == -ECONNRESET ) ||
+	    (urbinfo->status == -ENOENT ) ||
+	    (urbinfo->status == -ESHUTDOWN )){
+
+		/* Shutdown is occurring. Return and don't queue up any more */
+		return;
+	}
+
+	if (urbinfo->status != 0 ) {
+		/* Some unknown error.  Hopefully temporary.  Just go and */
+		/* requeue an URB */
+		goto resubmit;
+	}
+
+	/*
+	 * Good URB, now process
+	 */
+
+	/* PID dependent when we interpret the report */
+	if ((inputdev->id.product == PID_1000 )||
+	    (inputdev->id.product == PID_1001 )||
+	    (inputdev->id.product == PID_1002 ))
+	{
+
+		/*
+		 * Switch on the report ID
+		 * Conveniently, the reports have more information, the higher
+		 * the report number.  We can just fall through the case
+		 * statements if we start with the highest number report
+		 */
+		switch(device->buffer[0]){
+		case 5:
+			/* Pressure is 9 bits */
+			val =  ((u16)(device->buffer[8]) << 1);
+			val |= (u16)(device->buffer[7] >> 7);
+			input_report_abs(inputdev, ABS_PRESSURE,
+					 device->buffer[8]);
+
+			/* Mask out the Y tilt value used for pressure */
+			device->buffer[7] = (u8)((device->buffer[7]) & 0x7F);
+
+
+			/* Fall thru */
+		case 4:
+			/* Tilt */
+
+			/* Sign extend these 7 bit numbers.  */
+			if (device->buffer[6] & 0x40)
+				device->buffer[6] |= 0x80;
+
+			if (device->buffer[7] & 0x40)
+				device->buffer[7] |= 0x80;
+
+
+			valsigned = (device->buffer[6]);
+			input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned);
+
+			valsigned = (device->buffer[7]);
+			input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned);
+
+			/* Fall thru */
+
+		case 2:
+		case 3:
+			/* Convert buttons, only 5 bits possible */
+			val = (device->buffer[5])&MASK_BUTTON;
+
+			/* We don't apply any meaning to the bitmask,
+			   just report */
+			input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+
+			/*  Fall thru */
+		case 1:
+
+			/* All reports have X and Y coords in the same place */
+			val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[1])));
+			input_report_abs(inputdev, ABS_X, val);
+
+			val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[3])));
+			input_report_abs(inputdev, ABS_Y, val);
+
+
+			/* Ditto for proximity bit */
+			if (device->buffer[5]& MASK_INRANGE){
+				val = 1;
+			}else{
+				val=0;
+			}
+			input_report_abs(inputdev, ABS_DISTANCE, val);
+
+
+			/* Report 1 is an exception to how we handle buttons */
+			/* Buttons are an index, not a bitmask */
+			if (device->buffer[0] == 1){
+
+				/* Convert buttons, 5 bit index */
+				/* Report value of index set as one,
+				   the rest as 0 */
+				val = device->buffer[5]& MASK_BUTTON;
+				dbg("======>>>>>>REPORT 1: val 0x%X(%d)",
+				    val,val);
+
+				/*
+				 * We don't apply any meaning to the button
+				 * index, just report it
+				 */
+				input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+
+
+			}
+
+			break;
+		case 7:
+			/* Menu blocks */
+			input_event(inputdev, EV_MSC, MSC_SCAN,
+				    device->buffer[1]);
+
+
+			break;
+
+		}
+
+
+	}
+	/* Other pid class */
+	if ((inputdev->id.product == PID_400 )||
+	    (inputdev->id.product == PID_401 ))
+	{
+
+		/* Report 2 */
+		if (device->buffer[0] == 2){
+			/* Menu blocks */
+			input_event(inputdev, EV_MSC, MSC_SCAN,
+				    device->buffer[1]);
+		}
+
+		/*  Report 1 */
+		if (device->buffer[0] == 1){
+			char buttonbyte;
+
+
+			/*  IF X max > 64K, we still a bit from the y report */
+			if (device->max_X > 0x10000){
+
+				val = (u16)(((u16)(device->buffer[2]<<8))|((u8)(device->buffer[1])));
+				val |= (u32)(((u8)device->buffer[3]&0x1)<< 16);
+
+				input_report_abs(inputdev, ABS_X, val);
+
+				le_buffer[0]  = (u8)((u8)(device->buffer[3])>>1);
+				le_buffer[0] |= (u8)((device->buffer[3]&0x1)<<7);
+
+				le_buffer[1]  = (u8)(device->buffer[4]>>1);
+				le_buffer[1] |= (u8)((device->buffer[5]&0x1)<<7);
+
+				val = le16_to_cpu(get_unaligned((__le16 *)(le_buffer)));
+
+				input_report_abs(inputdev, ABS_Y, val);
+
+
+				/*
+				 * Shift the button byte right by one to
+				 * make it look like the standard report
+				 */
+				buttonbyte = (device->buffer[5])>>1;
+			}else{
+
+				val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[1]))));
+				input_report_abs(inputdev, ABS_X, val);
+
+				val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[3]))));
+				input_report_abs(inputdev, ABS_Y, val);
+
+				buttonbyte = device->buffer[5];
+
+			}
+
+
+			/* BUTTONS and PROXIMITY */
+			if (buttonbyte& MASK_INRANGE){
+				val = 1;
+			}else{
+				val=0;
+			}
+			input_report_abs(inputdev, ABS_DISTANCE, val);
+
+			/* Convert buttons, only 4 bits possible */
+			val = buttonbyte&0x0F;
+#ifdef USE_BUTTONS
+			for ( i=0;i<5;i++){
+				input_report_key(inputdev, BTN_DIGI+i,val&(1<<i));
+			}
+#else
+			/* We don't apply any meaning to the bitmask, just report */
+			input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+#endif
+			/* TRANSDUCER */
+			input_report_abs(inputdev, ABS_MISC, device->buffer[6]);
+
+		}
+	}
+
+	/* Everybody gets report ID's */
+	input_event(inputdev, EV_MSC, MSC_RAW,  device->buffer[0]);
+
+	/* Sync it up */
+	input_sync(inputdev);
+
+ resubmit:
+	rc = usb_submit_urb(urbinfo, GFP_ATOMIC);
+	if (rc != 0) {
+		err("usb_submit_urb failed rc=0x%x",rc);
+	}
+
+}
+
+/*
+ *  The probe routine.  This is called when the kernel find the matching USB
+ *   vendor/product.  We do the following:
+ *
+ *    - Allocate mem for a local structure to manage the device
+ *    - Request a HID Report Descriptor from the device and parse it to
+ *      find out the device parameters
+ *    - Create an input device and assign it attributes
+ *   - Allocate an URB so the device can talk to us when the input
+ *      queue is open
+ */
+static int gtco_probe(struct usb_interface *usbinterface,
+		      const struct usb_device_id *id)
+{
+
+	struct gtco             *device = NULL;
+	char                    path[PATHLENGTH];
+	struct input_dev        *inputdev;
+	struct hid_descriptor   *hid_desc;
+	char                    *report;
+	int                     result=0, retry;
+	struct usb_endpoint_descriptor *endpoint;
+
+	/* Allocate memory for device structure */
+	device = kzalloc(sizeof(struct gtco), GFP_KERNEL);
+	if (device == NULL) {
+		err("No more memory");
+		return -ENOMEM;
+	}
+
+
+	device->inputdevice = input_allocate_device();
+	if (!device->inputdevice){
+		kfree(device);
+		err("No more memory");
+		return -ENOMEM;
+	}
+
+	/* Get pointer to the input device */
+	inputdev = device->inputdevice;
+
+	/* Save interface information */
+	device->usbdev     = usb_get_dev(interface_to_usbdev(usbinterface));
+
+
+	/* Allocate some data for incoming reports */
+	device->buffer = usb_buffer_alloc(device->usbdev, REPORT_MAX_SIZE,
+					   GFP_KERNEL, &(device->buf_dma));
+	if (!device->buffer){
+		input_free_device(device->inputdevice);
+		kfree(device);
+		err("No more memory");
+		return -ENOMEM;
+	}
+
+	/* Allocate URB for reports */
+	device->urbinfo = usb_alloc_urb(0, GFP_KERNEL);
+	if (!device->urbinfo) {
+		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+				device->buffer, device->buf_dma);
+		input_free_device(device->inputdevice);
+		kfree(device);
+		err("No more memory");
+		return -ENOMEM;
+	}
+
+
+	/*
+	 * The endpoint is always altsetting 0, we know this since we know
+	 * this device only has one interrupt endpoint
+	 */
+	endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+	/* Some debug */
+	dbg("gtco # interfaces: %d",usbinterface->num_altsetting);
+	dbg("num endpoints:     %d",usbinterface->cur_altsetting->desc.bNumEndpoints);
+	dbg("interface class:   %d",usbinterface->cur_altsetting->desc.bInterfaceClass);
+	dbg("endpoint: attribute:0x%x type:0x%x",endpoint->bmAttributes,endpoint->bDescriptorType);
+	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+		dbg("endpoint: we have interrupt endpoint\n");
+
+	dbg("endpoint extra len:%d ",usbinterface->altsetting[0].extralen);
+
+
+
+	/*
+	 * Find the HID descriptor so we can find out the size of the
+	 * HID report descriptor
+	 */
+	if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
+				     HID_DEVICE_TYPE,&hid_desc) != 0){
+		err("Can't retrieve exta USB descriptor to get hid report descriptor length");
+		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+				device->buffer, device->buf_dma);
+		input_free_device(device->inputdevice);
+		kfree(device);
+		return -EIO;
+	}
+
+	dbg("Extra descriptor success: type:%d  len:%d",
+	    hid_desc->bDescriptorType,  hid_desc->wDescriptorLength);
+
+	if (!(report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL))) {
+		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+				device->buffer, device->buf_dma);
+
+		input_free_device(device->inputdevice);
+		kfree(device);
+		err("No more memory");
+		return -ENOMEM;
+	}
+
+	/* Couple of tries to get reply */
+	for (retry=0;retry<3;retry++) {
+		result = usb_control_msg(device->usbdev,
+					 usb_rcvctrlpipe(device->usbdev, 0),
+					 USB_REQ_GET_DESCRIPTOR,
+					 USB_RECIP_INTERFACE | USB_DIR_IN,
+					 (REPORT_DEVICE_TYPE << 8),
+					 0, /* interface */
+					 report,
+					 hid_desc->wDescriptorLength,
+					 5000); /* 5 secs */
+
+		if (result == hid_desc->wDescriptorLength)
+			break;
+	}
+
+	/* If we didn't get the report, fail */
+	dbg("usb_control_msg result: :%d", result);
+	if (result != hid_desc->wDescriptorLength){
+		kfree(report);
+		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+				device->buffer, device->buf_dma);
+		input_free_device(device->inputdevice);
+		kfree(device);
+		err("Failed to get HID Report Descriptor of size: %d",
+		    hid_desc->wDescriptorLength);
+		return -EIO;
+	}
+
+
+	/* Now we parse the report */
+	parse_hid_report_descriptor(device,report,result);
+
+	/* Now we delete it */
+	kfree(report);
+
+	/* Create a device file node */
+	usb_make_path(device->usbdev, path, PATHLENGTH);
+	sprintf(device->usbpath, "%s/input0", path);
+
+
+	/* Set Input device functions */
+	inputdev->open     = gtco_input_open;
+	inputdev->close    = gtco_input_close;
+
+	/* Set input device information */
+	inputdev->name     = "GTCO_CalComp";
+	inputdev->phys     = device->usbpath;
+	inputdev->private  = device;
+
+
+	/* Now set up all the input device capabilities */
+	gtco_setup_caps(inputdev);
+
+	/* Set input device required ID information */
+	usb_to_input_id(device->usbdev, &device->inputdevice->id);
+	inputdev->cdev.dev = &usbinterface->dev;
+
+	/* Setup the URB, it will be posted later on open of input device */
+	endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+	usb_fill_int_urb(device->urbinfo,
+			 device->usbdev,
+			 usb_rcvintpipe(device->usbdev,
+					endpoint->bEndpointAddress),
+			 device->buffer,
+			 REPORT_MAX_SIZE,
+			 gtco_urb_callback,
+			 device,
+			 endpoint->bInterval);
+
+	device->urbinfo->transfer_dma = device->buf_dma;
+	device->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+
+	/* Save device pointer in USB interface device */
+	usb_set_intfdata(usbinterface, device);
+
+	/* All done, now register the input device */
+	input_register_device(inputdev);
+
+	info( "gtco driver created usb:  %s\n",  path);
+	return 0;
+
+}
+
+/*
+ *  This function is a standard USB function called when the USB device
+ *  is disconnected.  We will get rid of the URV, de-register the input
+ *  device, and free up allocated memory
+ */
+static void gtco_disconnect(struct usb_interface *interface)
+{
+
+	/* Grab private device ptr */
+	struct gtco    *device = usb_get_intfdata (interface);
+	struct input_dev *inputdev;
+
+	inputdev = device->inputdevice;
+
+	/* Now reverse all the registration stuff */
+	if (device) {
+		input_unregister_device(inputdev);
+		usb_kill_urb(device->urbinfo);
+		usb_free_urb(device->urbinfo);
+		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+				device->buffer, device->buf_dma);
+		kfree(device);
+	}
+
+	info("gtco driver disconnected");
+}
+
+
+/*   STANDARD MODULE LOAD ROUTINES  */
+
+static struct usb_driver gtco_driverinfo_table = {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
+	.owner      = THIS_MODULE,
+#endif
+	.name       = "gtco",
+	.id_table   = gtco_usbid_table,
+	.probe      = gtco_probe,
+	.disconnect = gtco_disconnect,
+};
+/*
+ *  Register this module with the USB subsystem
+ */
+static int __init gtco_init(void)
+{
+	int rc;
+	rc = usb_register(&gtco_driverinfo_table);
+	if (rc) {
+		err("usb_register() failed rc=0x%x", rc);
+	}
+	printk("GTCO usb driver version: %s",GTCO_VERSION);
+	return rc;
+}
+
+/*
+ *   Deregister this module with the USB subsystem
+ */
+static void __exit gtco_exit(void)
+{
+	usb_deregister(&gtco_driverinfo_table);
+}
+
+module_init (gtco_init);
+module_exit (gtco_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index c6c9e72..84983d1 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -35,6 +35,7 @@
 
 #include <linux/hid.h>
 #include <linux/hiddev.h>
+#include <linux/hid-debug.h>
 #include "usbhid.h"
 
 /*
@@ -220,23 +221,6 @@
 	}
 }
 
-/*
- * Find a report field with a specified HID usage.
- */
-#if 0
-struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type)
-{
-	struct hid_report *report;
-	int i;
-
-	list_for_each_entry(report, &hid->report_enum[type].report_list, list)
-		for (i = 0; i < report->maxfield; i++)
-			if (report->field[i]->logical == wanted_usage)
-				return report->field[i];
-	return NULL;
-}
-#endif  /*  0  */
-
 static int hid_submit_out(struct hid_device *hid)
 {
 	struct hid_report *report;
@@ -501,7 +485,7 @@
 {
 	int result, retries = 4;
 
-	memset(buf,0,size);	// Make sure we parse really received data
+	memset(buf, 0, size);
 
 	do {
 		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
@@ -528,18 +512,6 @@
 		usb_kill_urb(usbhid->urbin);
 }
 
-static int hidinput_open(struct input_dev *dev)
-{
-	struct hid_device *hid = dev->private;
-	return usbhid_open(hid);
-}
-
-static void hidinput_close(struct input_dev *dev)
-{
-	struct hid_device *hid = dev->private;
-	usbhid_close(hid);
-}
-
 #define USB_VENDOR_ID_PANJIT		0x134c
 
 #define USB_VENDOR_ID_TURBOX		0x062a
@@ -770,6 +742,7 @@
 #define USB_DEVICE_ID_APPLE_GEYSER4_JIS	0x021c
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY	0x030a
 #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY	0x030b
+#define USB_DEVICE_ID_APPLE_IR		0x8240
 
 #define USB_VENDOR_ID_CHERRY		0x046a
 #define USB_DEVICE_ID_CHERRY_CYMOTION	0x0023
@@ -792,6 +765,12 @@
 #define USB_VENDOR_ID_IMATION		0x0718
 #define USB_DEVICE_ID_DISC_STAKKA	0xd000
 
+#define USB_VENDOR_ID_PANTHERLORD	0x0810
+#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK	0x0001
+
+#define USB_VENDOR_ID_SONY			0x054c
+#define USB_DEVICE_ID_SONY_PS3_CONTROLLER	0x0268
+
 /*
  * Alphabetically sorted blacklist by quirk type.
  */
@@ -946,19 +925,21 @@
 
 	{ USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION },
 
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR, HID_QUIRK_IGNORE },
 
 	{ USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE },
@@ -969,6 +950,10 @@
 
 	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
 
+	{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
+
+	{ USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER },
+
 	{ 0, 0 }
 };
 
@@ -1033,6 +1018,32 @@
 	}
 }
 
+/*
+ * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
+ * to "operational".  Without this, the ps3 controller will not report any
+ * events.
+ */
+static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
+{
+	int result;
+	char *buf = kmalloc(18, GFP_KERNEL);
+
+	if (!buf)
+		return;
+
+	result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+				 HID_REQ_GET_REPORT,
+				 USB_DIR_IN | USB_TYPE_CLASS |
+				 USB_RECIP_INTERFACE,
+				 (3 << 8) | 0xf2, ifnum, buf, 17,
+				 USB_CTRL_GET_TIMEOUT);
+
+	if (result < 0)
+		err("%s failed: %d\n", __func__, result);
+
+	kfree(buf);
+}
+
 static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 {
 	struct usb_host_interface *interface = intf->cur_altsetting;
@@ -1064,6 +1075,11 @@
 	if (quirks & HID_QUIRK_IGNORE)
 		return NULL;
 
+	if ((quirks & HID_QUIRK_IGNORE_MOUSE) &&
+		(interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE))
+			return NULL;
+
+
 	if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&
 	    (!interface->desc.bNumEndpoints ||
 	     usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {
@@ -1235,8 +1251,8 @@
 	usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
 	usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
 	hid->hidinput_input_event = usb_hidinput_input_event;
-	hid->hidinput_open = hidinput_open;
-	hid->hidinput_close = hidinput_close;
+	hid->hid_open = usbhid_open;
+	hid->hid_close = usbhid_close;
 #ifdef CONFIG_USB_HIDDEV
 	hid->hiddev_hid_event = hiddev_hid_event;
 	hid->hiddev_report_event = hiddev_report_event;
@@ -1315,13 +1331,13 @@
 		return -ENODEV;
 	}
 
-	/* This only gets called when we are a single-input (most of the
-	 * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is
-	 * only useful in this case, and not for multi-input quirks. */
-	if ((hid->claimed & HID_CLAIMED_INPUT) &&
-			!(hid->quirks & HID_QUIRK_MULTI_INPUT))
+	if ((hid->claimed & HID_CLAIMED_INPUT))
 		hid_ff_init(hid);
 
+	if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
+		hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
+			intf->cur_altsetting->desc.bInterfaceNumber);
+
 	printk(KERN_INFO);
 
 	if (hid->claimed & HID_CLAIMED_INPUT)
diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c
index 59ed65e..5d14505 100644
--- a/drivers/usb/input/hid-ff.c
+++ b/drivers/usb/input/hid-ff.c
@@ -58,6 +58,9 @@
 	{ 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
 	{ 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
 #endif
+#ifdef CONFIG_PANTHERLORD_FF
+	{ 0x810, 0x0001, hid_plff_init },
+#endif
 #ifdef CONFIG_THRUSTMASTER_FF
 	{ 0x44f, 0xb304, hid_tmff_init },
 #endif
diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c
index e474662..4f4fc3b 100644
--- a/drivers/usb/input/hid-lgff.c
+++ b/drivers/usb/input/hid-lgff.c
@@ -32,7 +32,7 @@
 #include <linux/hid.h>
 #include "usbhid.h"
 
-struct device_type {
+struct dev_type {
 	u16 idVendor;
 	u16 idProduct;
 	const signed short *ff;
@@ -48,7 +48,7 @@
 	-1
 };
 
-static const struct device_type devices[] = {
+static const struct dev_type devices[] = {
 	{ 0x046d, 0xc211, ff_rumble },
 	{ 0x046d, 0xc219, ff_rumble },
 	{ 0x046d, 0xc283, ff_joystick },
diff --git a/drivers/usb/input/hid-plff.c b/drivers/usb/input/hid-plff.c
new file mode 100644
index 0000000..76d2e6e
--- /dev/null
+++ b/drivers/usb/input/hid-plff.c
@@ -0,0 +1,129 @@
+/*
+ *  Force feedback support for PantherLord USB/PS2 2in1 Adapter devices
+ *
+ *  Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* #define DEBUG */
+
+#define debug(format, arg...) pr_debug("hid-plff: " format "\n" , ## arg)
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include "usbhid.h"
+
+struct plff_device {
+	struct hid_report *report;
+};
+
+static int hid_plff_play(struct input_dev *dev, void *data,
+			 struct ff_effect *effect)
+{
+	struct hid_device *hid = dev->private;
+	struct plff_device *plff = data;
+	int left, right;
+
+	left = effect->u.rumble.strong_magnitude;
+	right = effect->u.rumble.weak_magnitude;
+	debug("called with 0x%04x 0x%04x", left, right);
+
+	left = left * 0x7f / 0xffff;
+	right = right * 0x7f / 0xffff;
+
+	plff->report->field[0]->value[2] = left;
+	plff->report->field[0]->value[3] = right;
+	debug("running with 0x%02x 0x%02x", left, right);
+	usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
+
+	return 0;
+}
+
+int hid_plff_init(struct hid_device *hid)
+{
+	struct plff_device *plff;
+	struct hid_report *report;
+	struct hid_input *hidinput;
+	struct list_head *report_list =
+			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	struct list_head *report_ptr = report_list;
+	struct input_dev *dev;
+	int error;
+
+	/* The device contains 2 output reports (one for each
+	   HID_QUIRK_MULTI_INPUT device), both containing 1 field, which
+	   contains 4 ff00.0002 usages and 4 16bit absolute values.
+
+	   The 2 input reports also contain a field which contains
+	   8 ff00.0001 usages and 8 boolean values. Their meaning is
+	   currently unknown. */
+
+	if (list_empty(report_list)) {
+		printk(KERN_ERR "hid-plff: no output reports found\n");
+		return -ENODEV;
+	}
+
+	list_for_each_entry(hidinput, &hid->inputs, list) {
+
+		report_ptr = report_ptr->next;
+
+		if (report_ptr == report_list) {
+			printk(KERN_ERR "hid-plff: required output report is missing\n");
+			return -ENODEV;
+		}
+
+		report = list_entry(report_ptr, struct hid_report, list);
+		if (report->maxfield < 1) {
+			printk(KERN_ERR "hid-plff: no fields in the report\n");
+			return -ENODEV;
+		}
+
+		if (report->field[0]->report_count < 4) {
+			printk(KERN_ERR "hid-plff: not enough values in the field\n");
+			return -ENODEV;
+		}
+
+		plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL);
+		if (!plff)
+			return -ENOMEM;
+
+		dev = hidinput->input;
+
+		set_bit(FF_RUMBLE, dev->ffbit);
+
+		error = input_ff_create_memless(dev, plff, hid_plff_play);
+		if (error) {
+			kfree(plff);
+			return error;
+		}
+
+		plff->report = report;
+		plff->report->field[0]->value[0] = 0x00;
+		plff->report->field[0]->value[1] = 0x00;
+		plff->report->field[0]->value[2] = 0x00;
+		plff->report->field[0]->value[3] = 0x00;
+		usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
+	}
+
+	printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 "
+	       "2in1 Adapters by Anssi Hannula <anssi.hannula@gmail.com>\n");
+
+	return 0;
+}
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index c941853..15c70bd 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -269,7 +269,7 @@
 	/* prevent a race condition with open() */
 	mutex_lock(&disconnect_mutex);
 
-	dev = (struct usb_idmouse *) file->private_data;
+	dev = file->private_data;
 
 	if (dev == NULL) {
 		mutex_unlock(&disconnect_mutex);
@@ -304,17 +304,15 @@
 static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count,
 				loff_t * ppos)
 {
-	struct usb_idmouse *dev;
+	struct usb_idmouse *dev = file->private_data;
 	int result;
 
-	dev = (struct usb_idmouse *) file->private_data;
-
 	/* lock this object */
-	down (&dev->sem);
+	down(&dev->sem);
 
 	/* verify that the device wasn't unplugged */
 	if (!dev->present) {
-		up (&dev->sem);
+		up(&dev->sem);
 		return -ENODEV;
 	}
 
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index 384fa37..fdf6847 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -69,7 +69,7 @@
         char *obuf, *ibuf;              /* transfer buffers */
         char bulk_in_ep, bulk_out_ep;   /* Endpoint assignments */
         wait_queue_head_t wait_q;       /* for timeouts */
-	struct semaphore lock;          /* general race avoidance */
+	struct mutex lock;          /* general race avoidance */
 };
 
 static struct rio_usb_data rio_instance;
@@ -78,17 +78,17 @@
 {
 	struct rio_usb_data *rio = &rio_instance;
 
-	down(&(rio->lock));
+	mutex_lock(&(rio->lock));
 
 	if (rio->isopen || !rio->present) {
-		up(&(rio->lock));
+		mutex_unlock(&(rio->lock));
 		return -EBUSY;
 	}
 	rio->isopen = 1;
 
 	init_waitqueue_head(&rio->wait_q);
 
-	up(&(rio->lock));
+	mutex_unlock(&(rio->lock));
 
 	info("Rio opened.");
 
@@ -117,7 +117,7 @@
 	int retries;
 	int retval=0;
 
-	down(&(rio->lock));
+	mutex_lock(&(rio->lock));
         /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
              rio->present == 0 ||
@@ -257,7 +257,7 @@
 
 
 err_out:
-	up(&(rio->lock));
+	mutex_unlock(&(rio->lock));
 	return retval;
 }
 
@@ -275,14 +275,17 @@
 	int result = 0;
 	int maxretry;
 	int errn = 0;
+	int intr;
 
-	down(&(rio->lock));
+	intr = mutex_lock_interruptible(&(rio->lock));
+	if (intr)
+		return -EINTR;
         /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
              rio->present == 0 ||
              rio->rio_dev == NULL )
 	{
-		up(&(rio->lock));
+		mutex_unlock(&(rio->lock));
 		return -ENODEV;
 	}
 
@@ -305,7 +308,7 @@
 				goto error;
 			}
 			if (signal_pending(current)) {
-				up(&(rio->lock));
+				mutex_unlock(&(rio->lock));
 				return bytes_written ? bytes_written : -EINTR;
 			}
 
@@ -341,12 +344,12 @@
 		buffer += copy_size;
 	} while (count > 0);
 
-	up(&(rio->lock));
+	mutex_unlock(&(rio->lock));
 
 	return bytes_written ? bytes_written : -EIO;
 
 error:
-	up(&(rio->lock));
+	mutex_unlock(&(rio->lock));
 	return errn;
 }
 
@@ -361,14 +364,17 @@
 	int result;
 	int maxretry = 10;
 	char *ibuf;
+	int intr;
 
-	down(&(rio->lock));
+	intr = mutex_lock_interruptible(&(rio->lock));
+	if (intr)
+		return -EINTR;
 	/* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
              rio->present == 0 ||
              rio->rio_dev == NULL )
 	{
-		up(&(rio->lock));
+		mutex_unlock(&(rio->lock));
 		return -ENODEV;
 	}
 
@@ -379,11 +385,11 @@
 
 	while (count > 0) {
 		if (signal_pending(current)) {
-			up(&(rio->lock));
+			mutex_unlock(&(rio->lock));
 			return read_count ? read_count : -EINTR;
 		}
 		if (!rio->rio_dev) {
-			up(&(rio->lock));
+			mutex_unlock(&(rio->lock));
 			return -ENODEV;
 		}
 		this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
@@ -400,7 +406,7 @@
 			count = this_read = partial;
 		} else if (result == -ETIMEDOUT || result == 15) {	/* FIXME: 15 ??? */
 			if (!maxretry--) {
-				up(&(rio->lock));
+				mutex_unlock(&(rio->lock));
 				err("read_rio: maxretry timeout");
 				return -ETIME;
 			}
@@ -409,18 +415,18 @@
 			finish_wait(&rio->wait_q, &wait);
 			continue;
 		} else if (result != -EREMOTEIO) {
-			up(&(rio->lock));
+			mutex_unlock(&(rio->lock));
 			err("Read Whoops - result:%u partial:%u this_read:%u",
 			     result, partial, this_read);
 			return -EIO;
 		} else {
-			up(&(rio->lock));
+			mutex_unlock(&(rio->lock));
 			return (0);
 		}
 
 		if (this_read) {
 			if (copy_to_user(buffer, ibuf, this_read)) {
-				up(&(rio->lock));
+				mutex_unlock(&(rio->lock));
 				return -EFAULT;
 			}
 			count -= this_read;
@@ -428,7 +434,7 @@
 			buffer += this_read;
 		}
 	}
-	up(&(rio->lock));
+	mutex_unlock(&(rio->lock));
 	return read_count;
 }
 
@@ -480,7 +486,7 @@
 	}
 	dbg("probe_rio: ibuf address:%p", rio->ibuf);
 
-	init_MUTEX(&(rio->lock));
+	mutex_init(&(rio->lock));
 
 	usb_set_intfdata (intf, rio);
 	rio->present = 1;
@@ -496,12 +502,12 @@
 	if (rio) {
 		usb_deregister_dev(intf, &usb_rio_class);
 
-		down(&(rio->lock));
+		mutex_lock(&(rio->lock));
 		if (rio->isopen) {
 			rio->isopen = 0;
 			/* better let it finish - the release will do whats needed */
 			rio->rio_dev = NULL;
-			up(&(rio->lock));
+			mutex_unlock(&(rio->lock));
 			return;
 		}
 		kfree(rio->ibuf);
@@ -510,7 +516,7 @@
 		info("USB Rio disconnected.");
 
 		rio->present = 0;
-		up(&(rio->lock));
+		mutex_unlock(&(rio->lock));
 	}
 }
 
diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile
index 3cf3ea3a..90c5953 100644
--- a/drivers/usb/mon/Makefile
+++ b/drivers/usb/mon/Makefile
@@ -2,7 +2,7 @@
 # Makefile for USB Core files and filesystem
 #
 
-usbmon-objs	:= mon_main.o mon_stat.o mon_text.o mon_dma.o
+usbmon-objs	:= mon_main.o mon_stat.o mon_text.o mon_bin.o mon_dma.o
 
 # This does not use CONFIG_USB_MON because we want this to use a tristate.
 obj-$(CONFIG_USB)	+= usbmon.o
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
new file mode 100644
index 0000000..c01dfe6
--- /dev/null
+++ b/drivers/usb/mon/mon_bin.c
@@ -0,0 +1,1172 @@
+/*
+ * The USB Monitor, inspired by Dave Harding's USBMon.
+ *
+ * This is a binary format reader.
+ *
+ * Copyright (C) 2006 Paolo Abeni (paolo.abeni@email.it)
+ * Copyright (C) 2006 Pete Zaitcev (zaitcev@redhat.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/usb.h>
+#include <linux/poll.h>
+#include <linux/compat.h>
+#include <linux/mm.h>
+
+#include <asm/uaccess.h>
+
+#include "usb_mon.h"
+
+/*
+ * Defined by USB 2.0 clause 9.3, table 9.2.
+ */
+#define SETUP_LEN  8
+
+/* ioctl macros */
+#define MON_IOC_MAGIC 0x92
+
+#define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1)
+/* #2 used to be MON_IOCX_URB, removed before it got into Linus tree */
+#define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
+#define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4)
+#define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5)
+#define MON_IOCX_GET   _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get)
+#define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch)
+#define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8)
+#ifdef CONFIG_COMPAT
+#define MON_IOCX_GET32 _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get32)
+#define MON_IOCX_MFETCH32 _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch32)
+#endif
+
+/*
+ * Some architectures have enormous basic pages (16KB for ia64, 64KB for ppc).
+ * But it's all right. Just use a simple way to make sure the chunk is never
+ * smaller than a page.
+ *
+ * N.B. An application does not know our chunk size.
+ *
+ * Woops, get_zeroed_page() returns a single page. I guess we're stuck with
+ * page-sized chunks for the time being.
+ */
+#define CHUNK_SIZE   PAGE_SIZE
+#define CHUNK_ALIGN(x)   (((x)+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1))
+
+/*
+ * The magic limit was calculated so that it allows the monitoring
+ * application to pick data once in two ticks. This way, another application,
+ * which presumably drives the bus, gets to hog CPU, yet we collect our data.
+ * If HZ is 100, a 480 mbit/s bus drives 614 KB every jiffy. USB has an
+ * enormous overhead built into the bus protocol, so we need about 1000 KB.
+ *
+ * This is still too much for most cases, where we just snoop a few
+ * descriptor fetches for enumeration. So, the default is a "reasonable"
+ * amount for systems with HZ=250 and incomplete bus saturation.
+ *
+ * XXX What about multi-megabyte URBs which take minutes to transfer?
+ */
+#define BUFF_MAX  CHUNK_ALIGN(1200*1024)
+#define BUFF_DFL   CHUNK_ALIGN(300*1024)
+#define BUFF_MIN     CHUNK_ALIGN(8*1024)
+
+/*
+ * The per-event API header (2 per URB).
+ *
+ * This structure is seen in userland as defined by the documentation.
+ */
+struct mon_bin_hdr {
+	u64 id;			/* URB ID - from submission to callback */
+	unsigned char type;	/* Same as in text API; extensible. */
+	unsigned char xfer_type;	/* ISO, Intr, Control, Bulk */
+	unsigned char epnum;	/* Endpoint number and transfer direction */
+	unsigned char devnum;	/* Device address */
+	unsigned short busnum;	/* Bus number */
+	char flag_setup;
+	char flag_data;
+	s64 ts_sec;		/* gettimeofday */
+	s32 ts_usec;		/* gettimeofday */
+	int status;
+	unsigned int len_urb;	/* Length of data (submitted or actual) */
+	unsigned int len_cap;	/* Delivered length */
+	unsigned char setup[SETUP_LEN];	/* Only for Control S-type */
+};
+
+/* per file statistic */
+struct mon_bin_stats {
+	u32 queued;
+	u32 dropped;
+};
+
+struct mon_bin_get {
+	struct mon_bin_hdr __user *hdr;	/* Only 48 bytes, not 64. */
+	void __user *data;
+	size_t alloc;		/* Length of data (can be zero) */
+};
+
+struct mon_bin_mfetch {
+	u32 __user *offvec;	/* Vector of events fetched */
+	u32 nfetch;		/* Number of events to fetch (out: fetched) */
+	u32 nflush;		/* Number of events to flush */
+};
+
+#ifdef CONFIG_COMPAT
+struct mon_bin_get32 {
+	u32 hdr32;
+	u32 data32;
+	u32 alloc32;
+};
+
+struct mon_bin_mfetch32 {
+        u32 offvec32;
+        u32 nfetch32;
+        u32 nflush32;
+};
+#endif
+
+/* Having these two values same prevents wrapping of the mon_bin_hdr */
+#define PKT_ALIGN   64
+#define PKT_SIZE    64
+
+/* max number of USB bus supported */
+#define MON_BIN_MAX_MINOR 128
+
+/*
+ * The buffer: map of used pages.
+ */
+struct mon_pgmap {
+	struct page *pg;
+	unsigned char *ptr;	/* XXX just use page_to_virt everywhere? */
+};
+
+/*
+ * This gets associated with an open file struct.
+ */
+struct mon_reader_bin {
+	/* The buffer: one per open. */
+	spinlock_t b_lock;		/* Protect b_cnt, b_in */
+	unsigned int b_size;		/* Current size of the buffer - bytes */
+	unsigned int b_cnt;		/* Bytes used */
+	unsigned int b_in, b_out;	/* Offsets into buffer - bytes */
+	unsigned int b_read;		/* Amount of read data in curr. pkt. */
+	struct mon_pgmap *b_vec;	/* The map array */
+	wait_queue_head_t b_wait;	/* Wait for data here */
+
+	struct mutex fetch_lock;	/* Protect b_read, b_out */
+	int mmap_active;
+
+	/* A list of these is needed for "bus 0". Some time later. */
+	struct mon_reader r;
+
+	/* Stats */
+	unsigned int cnt_lost;
+};
+
+static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp,
+    unsigned int offset)
+{
+	return (struct mon_bin_hdr *)
+	    (rp->b_vec[offset / CHUNK_SIZE].ptr + offset % CHUNK_SIZE);
+}
+
+#define MON_RING_EMPTY(rp)	((rp)->b_cnt == 0)
+
+static dev_t mon_bin_dev0;
+static struct cdev mon_bin_cdev;
+
+static void mon_buff_area_fill(const struct mon_reader_bin *rp,
+    unsigned int offset, unsigned int size);
+static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp);
+static int mon_alloc_buff(struct mon_pgmap *map, int npages);
+static void mon_free_buff(struct mon_pgmap *map, int npages);
+
+/*
+ * This is a "chunked memcpy". It does not manipulate any counters.
+ * But it returns the new offset for repeated application.
+ */
+unsigned int mon_copy_to_buff(const struct mon_reader_bin *this,
+    unsigned int off, const unsigned char *from, unsigned int length)
+{
+	unsigned int step_len;
+	unsigned char *buf;
+	unsigned int in_page;
+
+	while (length) {
+		/*
+		 * Determine step_len.
+		 */
+		step_len = length;
+		in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1));
+		if (in_page < step_len)
+			step_len = in_page;
+
+		/*
+		 * Copy data and advance pointers.
+		 */
+		buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE;
+		memcpy(buf, from, step_len);
+		if ((off += step_len) >= this->b_size) off = 0;
+		from += step_len;
+		length -= step_len;
+	}
+	return off;
+}
+
+/*
+ * This is a little worse than the above because it's "chunked copy_to_user".
+ * The return value is an error code, not an offset.
+ */
+static int copy_from_buf(const struct mon_reader_bin *this, unsigned int off,
+    char __user *to, int length)
+{
+	unsigned int step_len;
+	unsigned char *buf;
+	unsigned int in_page;
+
+	while (length) {
+		/*
+		 * Determine step_len.
+		 */
+		step_len = length;
+		in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1));
+		if (in_page < step_len)
+			step_len = in_page;
+
+		/*
+		 * Copy data and advance pointers.
+		 */
+		buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE;
+		if (copy_to_user(to, buf, step_len))
+			return -EINVAL;
+		if ((off += step_len) >= this->b_size) off = 0;
+		to += step_len;
+		length -= step_len;
+	}
+	return 0;
+}
+
+/*
+ * Allocate an (aligned) area in the buffer.
+ * This is called under b_lock.
+ * Returns ~0 on failure.
+ */
+static unsigned int mon_buff_area_alloc(struct mon_reader_bin *rp,
+    unsigned int size)
+{
+	unsigned int offset;
+
+	size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+	if (rp->b_cnt + size > rp->b_size)
+		return ~0;
+	offset = rp->b_in;
+	rp->b_cnt += size;
+	if ((rp->b_in += size) >= rp->b_size)
+		rp->b_in -= rp->b_size;
+	return offset;
+}
+
+/*
+ * This is the same thing as mon_buff_area_alloc, only it does not allow
+ * buffers to wrap. This is needed by applications which pass references
+ * into mmap-ed buffers up their stacks (libpcap can do that).
+ *
+ * Currently, we always have the header stuck with the data, although
+ * it is not strictly speaking necessary.
+ *
+ * When a buffer would wrap, we place a filler packet to mark the space.
+ */
+static unsigned int mon_buff_area_alloc_contiguous(struct mon_reader_bin *rp,
+    unsigned int size)
+{
+	unsigned int offset;
+	unsigned int fill_size;
+
+	size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+	if (rp->b_cnt + size > rp->b_size)
+		return ~0;
+	if (rp->b_in + size > rp->b_size) {
+		/*
+		 * This would wrap. Find if we still have space after
+		 * skipping to the end of the buffer. If we do, place
+		 * a filler packet and allocate a new packet.
+		 */
+		fill_size = rp->b_size - rp->b_in;
+		if (rp->b_cnt + size + fill_size > rp->b_size)
+			return ~0;
+		mon_buff_area_fill(rp, rp->b_in, fill_size);
+
+		offset = 0;
+		rp->b_in = size;
+		rp->b_cnt += size + fill_size;
+	} else if (rp->b_in + size == rp->b_size) {
+		offset = rp->b_in;
+		rp->b_in = 0;
+		rp->b_cnt += size;
+	} else {
+		offset = rp->b_in;
+		rp->b_in += size;
+		rp->b_cnt += size;
+	}
+	return offset;
+}
+
+/*
+ * Return a few (kilo-)bytes to the head of the buffer.
+ * This is used if a DMA fetch fails.
+ */
+static void mon_buff_area_shrink(struct mon_reader_bin *rp, unsigned int size)
+{
+
+	size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+	rp->b_cnt -= size;
+	if (rp->b_in < size)
+		rp->b_in += rp->b_size;
+	rp->b_in -= size;
+}
+
+/*
+ * This has to be called under both b_lock and fetch_lock, because
+ * it accesses both b_cnt and b_out.
+ */
+static void mon_buff_area_free(struct mon_reader_bin *rp, unsigned int size)
+{
+
+	size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+	rp->b_cnt -= size;
+	if ((rp->b_out += size) >= rp->b_size)
+		rp->b_out -= rp->b_size;
+}
+
+static void mon_buff_area_fill(const struct mon_reader_bin *rp,
+    unsigned int offset, unsigned int size)
+{
+	struct mon_bin_hdr *ep;
+
+	ep = MON_OFF2HDR(rp, offset);
+	memset(ep, 0, PKT_SIZE);
+	ep->type = '@';
+	ep->len_cap = size - PKT_SIZE;
+}
+
+static inline char mon_bin_get_setup(unsigned char *setupb,
+    const struct urb *urb, char ev_type)
+{
+
+	if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+		return '-';
+
+	if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
+		return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
+	if (urb->setup_packet == NULL)
+		return 'Z';
+
+	memcpy(setupb, urb->setup_packet, SETUP_LEN);
+	return 0;
+}
+
+static char mon_bin_get_data(const struct mon_reader_bin *rp,
+    unsigned int offset, struct urb *urb, unsigned int length)
+{
+
+	if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) {
+		mon_dmapeek_vec(rp, offset, urb->transfer_dma, length);
+		return 0;
+	}
+
+	if (urb->transfer_buffer == NULL)
+		return 'Z';
+
+	mon_copy_to_buff(rp, offset, urb->transfer_buffer, length);
+	return 0;
+}
+
+static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
+    char ev_type)
+{
+	unsigned long flags;
+	struct timeval ts;
+	unsigned int urb_length;
+	unsigned int offset;
+	unsigned int length;
+	struct mon_bin_hdr *ep;
+	char data_tag = 0;
+
+	do_gettimeofday(&ts);
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+
+	/*
+	 * Find the maximum allowable length, then allocate space.
+	 */
+	urb_length = (ev_type == 'S') ?
+	    urb->transfer_buffer_length : urb->actual_length;
+	length = urb_length;
+
+	if (length >= rp->b_size/5)
+		length = rp->b_size/5;
+
+	if (usb_pipein(urb->pipe)) {
+		if (ev_type == 'S') {
+			length = 0;
+			data_tag = '<';
+		}
+	} else {
+		if (ev_type == 'C') {
+			length = 0;
+			data_tag = '>';
+		}
+	}
+
+	if (rp->mmap_active)
+		offset = mon_buff_area_alloc_contiguous(rp, length + PKT_SIZE);
+	else
+		offset = mon_buff_area_alloc(rp, length + PKT_SIZE);
+	if (offset == ~0) {
+		rp->cnt_lost++;
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+		return;
+	}
+
+	ep = MON_OFF2HDR(rp, offset);
+	if ((offset += PKT_SIZE) >= rp->b_size) offset = 0;
+
+	/*
+	 * Fill the allocated area.
+	 */
+	memset(ep, 0, PKT_SIZE);
+	ep->type = ev_type;
+	ep->xfer_type = usb_pipetype(urb->pipe);
+	/* We use the fact that usb_pipein() returns 0x80 */
+	ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
+	ep->devnum = usb_pipedevice(urb->pipe);
+	ep->busnum = rp->r.m_bus->u_bus->busnum;
+	ep->id = (unsigned long) urb;
+	ep->ts_sec = ts.tv_sec;
+	ep->ts_usec = ts.tv_usec;
+	ep->status = urb->status;
+	ep->len_urb = urb_length;
+	ep->len_cap = length;
+
+	ep->flag_setup = mon_bin_get_setup(ep->setup, urb, ev_type);
+	if (length != 0) {
+		ep->flag_data = mon_bin_get_data(rp, offset, urb, length);
+		if (ep->flag_data != 0) {	/* Yes, it's 0x00, not '0' */
+			ep->len_cap = 0;
+			mon_buff_area_shrink(rp, length);
+		}
+	} else {
+		ep->flag_data = data_tag;
+	}
+
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+
+	wake_up(&rp->b_wait);
+}
+
+static void mon_bin_submit(void *data, struct urb *urb)
+{
+	struct mon_reader_bin *rp = data;
+	mon_bin_event(rp, urb, 'S');
+}
+
+static void mon_bin_complete(void *data, struct urb *urb)
+{
+	struct mon_reader_bin *rp = data;
+	mon_bin_event(rp, urb, 'C');
+}
+
+static void mon_bin_error(void *data, struct urb *urb, int error)
+{
+	struct mon_reader_bin *rp = data;
+	unsigned long flags;
+	unsigned int offset;
+	struct mon_bin_hdr *ep;
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+
+	offset = mon_buff_area_alloc(rp, PKT_SIZE);
+	if (offset == ~0) {
+		/* Not incrementing cnt_lost. Just because. */
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+		return;
+	}
+
+	ep = MON_OFF2HDR(rp, offset);
+
+	memset(ep, 0, PKT_SIZE);
+	ep->type = 'E';
+	ep->xfer_type = usb_pipetype(urb->pipe);
+	/* We use the fact that usb_pipein() returns 0x80 */
+	ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
+	ep->devnum = usb_pipedevice(urb->pipe);
+	ep->busnum = rp->r.m_bus->u_bus->busnum;
+	ep->id = (unsigned long) urb;
+	ep->status = error;
+
+	ep->flag_setup = '-';
+	ep->flag_data = 'E';
+
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+
+	wake_up(&rp->b_wait);
+}
+
+static int mon_bin_open(struct inode *inode, struct file *file)
+{
+	struct mon_bus *mbus;
+	struct usb_bus *ubus;
+	struct mon_reader_bin *rp;
+	size_t size;
+	int rc;
+
+	mutex_lock(&mon_lock);
+	if ((mbus = mon_bus_lookup(iminor(inode))) == NULL) {
+		mutex_unlock(&mon_lock);
+		return -ENODEV;
+	}
+	if ((ubus = mbus->u_bus) == NULL) {
+		printk(KERN_ERR TAG ": consistency error on open\n");
+		mutex_unlock(&mon_lock);
+		return -ENODEV;
+	}
+
+	rp = kzalloc(sizeof(struct mon_reader_bin), GFP_KERNEL);
+	if (rp == NULL) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	spin_lock_init(&rp->b_lock);
+	init_waitqueue_head(&rp->b_wait);
+	mutex_init(&rp->fetch_lock);
+
+	rp->b_size = BUFF_DFL;
+
+	size = sizeof(struct mon_pgmap) * (rp->b_size/CHUNK_SIZE);
+	if ((rp->b_vec = kzalloc(size, GFP_KERNEL)) == NULL) {
+		rc = -ENOMEM;
+		goto err_allocvec;
+	}
+
+	if ((rc = mon_alloc_buff(rp->b_vec, rp->b_size/CHUNK_SIZE)) < 0)
+		goto err_allocbuff;
+
+	rp->r.m_bus = mbus;
+	rp->r.r_data = rp;
+	rp->r.rnf_submit = mon_bin_submit;
+	rp->r.rnf_error = mon_bin_error;
+	rp->r.rnf_complete = mon_bin_complete;
+
+	mon_reader_add(mbus, &rp->r);
+
+	file->private_data = rp;
+	mutex_unlock(&mon_lock);
+	return 0;
+
+err_allocbuff:
+	kfree(rp->b_vec);
+err_allocvec:
+	kfree(rp);
+err_alloc:
+	mutex_unlock(&mon_lock);
+	return rc;
+}
+
+/*
+ * Extract an event from buffer and copy it to user space.
+ * Wait if there is no event ready.
+ * Returns zero or error.
+ */
+static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp,
+    struct mon_bin_hdr __user *hdr, void __user *data, unsigned int nbytes)
+{
+	unsigned long flags;
+	struct mon_bin_hdr *ep;
+	size_t step_len;
+	unsigned int offset;
+	int rc;
+
+	mutex_lock(&rp->fetch_lock);
+
+	if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+		mutex_unlock(&rp->fetch_lock);
+		return rc;
+	}
+
+	ep = MON_OFF2HDR(rp, rp->b_out);
+
+	if (copy_to_user(hdr, ep, sizeof(struct mon_bin_hdr))) {
+		mutex_unlock(&rp->fetch_lock);
+		return -EFAULT;
+	}
+
+	step_len = min(ep->len_cap, nbytes);
+	if ((offset = rp->b_out + PKT_SIZE) >= rp->b_size) offset = 0;
+
+	if (copy_from_buf(rp, offset, data, step_len)) {
+		mutex_unlock(&rp->fetch_lock);
+		return -EFAULT;
+	}
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+	mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+	rp->b_read = 0;
+
+	mutex_unlock(&rp->fetch_lock);
+	return 0;
+}
+
+static int mon_bin_release(struct inode *inode, struct file *file)
+{
+	struct mon_reader_bin *rp = file->private_data;
+	struct mon_bus* mbus = rp->r.m_bus;
+
+	mutex_lock(&mon_lock);
+
+	if (mbus->nreaders <= 0) {
+		printk(KERN_ERR TAG ": consistency error on close\n");
+		mutex_unlock(&mon_lock);
+		return 0;
+	}
+	mon_reader_del(mbus, &rp->r);
+
+	mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE);
+	kfree(rp->b_vec);
+	kfree(rp);
+
+	mutex_unlock(&mon_lock);
+	return 0;
+}
+
+static ssize_t mon_bin_read(struct file *file, char __user *buf,
+    size_t nbytes, loff_t *ppos)
+{
+	struct mon_reader_bin *rp = file->private_data;
+	unsigned long flags;
+	struct mon_bin_hdr *ep;
+	unsigned int offset;
+	size_t step_len;
+	char *ptr;
+	ssize_t done = 0;
+	int rc;
+
+	mutex_lock(&rp->fetch_lock);
+
+	if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+		mutex_unlock(&rp->fetch_lock);
+		return rc;
+	}
+
+	ep = MON_OFF2HDR(rp, rp->b_out);
+
+	if (rp->b_read < sizeof(struct mon_bin_hdr)) {
+		step_len = min(nbytes, sizeof(struct mon_bin_hdr) - rp->b_read);
+		ptr = ((char *)ep) + rp->b_read;
+		if (step_len && copy_to_user(buf, ptr, step_len)) {
+			mutex_unlock(&rp->fetch_lock);
+			return -EFAULT;
+		}
+		nbytes -= step_len;
+		buf += step_len;
+		rp->b_read += step_len;
+		done += step_len;
+	}
+
+	if (rp->b_read >= sizeof(struct mon_bin_hdr)) {
+		step_len = min(nbytes, (size_t)ep->len_cap);
+		offset = rp->b_out + PKT_SIZE;
+		offset += rp->b_read - sizeof(struct mon_bin_hdr);
+		if (offset >= rp->b_size)
+			offset -= rp->b_size;
+		if (copy_from_buf(rp, offset, buf, step_len)) {
+			mutex_unlock(&rp->fetch_lock);
+			return -EFAULT;
+		}
+		nbytes -= step_len;
+		buf += step_len;
+		rp->b_read += step_len;
+		done += step_len;
+	}
+
+	/*
+	 * Check if whole packet was read, and if so, jump to the next one.
+	 */
+	if (rp->b_read >= sizeof(struct mon_bin_hdr) + ep->len_cap) {
+		spin_lock_irqsave(&rp->b_lock, flags);
+		mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+		rp->b_read = 0;
+	}
+
+	mutex_unlock(&rp->fetch_lock);
+	return done;
+}
+
+/*
+ * Remove at most nevents from chunked buffer.
+ * Returns the number of removed events.
+ */
+static int mon_bin_flush(struct mon_reader_bin *rp, unsigned nevents)
+{
+	unsigned long flags;
+	struct mon_bin_hdr *ep;
+	int i;
+
+	mutex_lock(&rp->fetch_lock);
+	spin_lock_irqsave(&rp->b_lock, flags);
+	for (i = 0; i < nevents; ++i) {
+		if (MON_RING_EMPTY(rp))
+			break;
+
+		ep = MON_OFF2HDR(rp, rp->b_out);
+		mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+	}
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+	rp->b_read = 0;
+	mutex_unlock(&rp->fetch_lock);
+	return i;
+}
+
+/*
+ * Fetch at most max event offsets into the buffer and put them into vec.
+ * The events are usually freed later with mon_bin_flush.
+ * Return the effective number of events fetched.
+ */
+static int mon_bin_fetch(struct file *file, struct mon_reader_bin *rp,
+    u32 __user *vec, unsigned int max)
+{
+	unsigned int cur_out;
+	unsigned int bytes, avail;
+	unsigned int size;
+	unsigned int nevents;
+	struct mon_bin_hdr *ep;
+	unsigned long flags;
+	int rc;
+
+	mutex_lock(&rp->fetch_lock);
+
+	if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+		mutex_unlock(&rp->fetch_lock);
+		return rc;
+	}
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+	avail = rp->b_cnt;
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+
+	cur_out = rp->b_out;
+	nevents = 0;
+	bytes = 0;
+	while (bytes < avail) {
+		if (nevents >= max)
+			break;
+
+		ep = MON_OFF2HDR(rp, cur_out);
+		if (put_user(cur_out, &vec[nevents])) {
+			mutex_unlock(&rp->fetch_lock);
+			return -EFAULT;
+		}
+
+		nevents++;
+		size = ep->len_cap + PKT_SIZE;
+		size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+		if ((cur_out += size) >= rp->b_size)
+			cur_out -= rp->b_size;
+		bytes += size;
+	}
+
+	mutex_unlock(&rp->fetch_lock);
+	return nevents;
+}
+
+/*
+ * Count events. This is almost the same as the above mon_bin_fetch,
+ * only we do not store offsets into user vector, and we have no limit.
+ */
+static int mon_bin_queued(struct mon_reader_bin *rp)
+{
+	unsigned int cur_out;
+	unsigned int bytes, avail;
+	unsigned int size;
+	unsigned int nevents;
+	struct mon_bin_hdr *ep;
+	unsigned long flags;
+
+	mutex_lock(&rp->fetch_lock);
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+	avail = rp->b_cnt;
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+
+	cur_out = rp->b_out;
+	nevents = 0;
+	bytes = 0;
+	while (bytes < avail) {
+		ep = MON_OFF2HDR(rp, cur_out);
+
+		nevents++;
+		size = ep->len_cap + PKT_SIZE;
+		size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+		if ((cur_out += size) >= rp->b_size)
+			cur_out -= rp->b_size;
+		bytes += size;
+	}
+
+	mutex_unlock(&rp->fetch_lock);
+	return nevents;
+}
+
+/*
+ */
+static int mon_bin_ioctl(struct inode *inode, struct file *file,
+    unsigned int cmd, unsigned long arg)
+{
+	struct mon_reader_bin *rp = file->private_data;
+	// struct mon_bus* mbus = rp->r.m_bus;
+	int ret = 0;
+	struct mon_bin_hdr *ep;
+	unsigned long flags;
+
+	switch (cmd) {
+
+	case MON_IOCQ_URB_LEN:
+		/*
+		 * N.B. This only returns the size of data, without the header.
+		 */
+		spin_lock_irqsave(&rp->b_lock, flags);
+		if (!MON_RING_EMPTY(rp)) {
+			ep = MON_OFF2HDR(rp, rp->b_out);
+			ret = ep->len_cap;
+		}
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+		break;
+
+	case MON_IOCQ_RING_SIZE:
+		ret = rp->b_size;
+		break;
+
+	case MON_IOCT_RING_SIZE:
+		/*
+		 * Changing the buffer size will flush it's contents; the new
+		 * buffer is allocated before releasing the old one to be sure
+		 * the device will stay functional also in case of memory
+		 * pressure.
+		 */
+		{
+		int size;
+		struct mon_pgmap *vec;
+
+		if (arg < BUFF_MIN || arg > BUFF_MAX)
+			return -EINVAL;
+
+		size = CHUNK_ALIGN(arg);
+		if ((vec = kzalloc(sizeof(struct mon_pgmap) * (size/CHUNK_SIZE),
+		    GFP_KERNEL)) == NULL) {
+			ret = -ENOMEM;
+			break;
+		}
+
+		ret = mon_alloc_buff(vec, size/CHUNK_SIZE);
+		if (ret < 0) {
+			kfree(vec);
+			break;
+		}
+
+		mutex_lock(&rp->fetch_lock);
+		spin_lock_irqsave(&rp->b_lock, flags);
+		mon_free_buff(rp->b_vec, size/CHUNK_SIZE);
+		kfree(rp->b_vec);
+		rp->b_vec  = vec;
+		rp->b_size = size;
+		rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0;
+		rp->cnt_lost = 0;
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+		mutex_unlock(&rp->fetch_lock);
+		}
+		break;
+
+	case MON_IOCH_MFLUSH:
+		ret = mon_bin_flush(rp, arg);
+		break;
+
+	case MON_IOCX_GET:
+		{
+		struct mon_bin_get getb;
+
+		if (copy_from_user(&getb, (void __user *)arg,
+					    sizeof(struct mon_bin_get)))
+			return -EFAULT;
+
+		if (getb.alloc > 0x10000000)	/* Want to cast to u32 */
+			return -EINVAL;
+		ret = mon_bin_get_event(file, rp,
+			  getb.hdr, getb.data, (unsigned int)getb.alloc);
+		}
+		break;
+
+#ifdef CONFIG_COMPAT
+	case MON_IOCX_GET32: {
+		struct mon_bin_get32 getb;
+
+		if (copy_from_user(&getb, (void __user *)arg,
+					    sizeof(struct mon_bin_get32)))
+			return -EFAULT;
+
+		ret = mon_bin_get_event(file, rp,
+		    compat_ptr(getb.hdr32), compat_ptr(getb.data32),
+		    getb.alloc32);
+		}
+		break;
+#endif
+
+	case MON_IOCX_MFETCH:
+		{
+		struct mon_bin_mfetch mfetch;
+		struct mon_bin_mfetch __user *uptr;
+
+		uptr = (struct mon_bin_mfetch __user *)arg;
+
+		if (copy_from_user(&mfetch, uptr, sizeof(mfetch)))
+			return -EFAULT;
+
+		if (mfetch.nflush) {
+			ret = mon_bin_flush(rp, mfetch.nflush);
+			if (ret < 0)
+				return ret;
+			if (put_user(ret, &uptr->nflush))
+				return -EFAULT;
+		}
+		ret = mon_bin_fetch(file, rp, mfetch.offvec, mfetch.nfetch);
+		if (ret < 0)
+			return ret;
+		if (put_user(ret, &uptr->nfetch))
+			return -EFAULT;
+		ret = 0;
+		}
+		break;
+
+#ifdef CONFIG_COMPAT
+	case MON_IOCX_MFETCH32:
+		{
+		struct mon_bin_mfetch32 mfetch;
+		struct mon_bin_mfetch32 __user *uptr;
+
+		uptr = (struct mon_bin_mfetch32 __user *) compat_ptr(arg);
+
+		if (copy_from_user(&mfetch, uptr, sizeof(mfetch)))
+			return -EFAULT;
+
+		if (mfetch.nflush32) {
+			ret = mon_bin_flush(rp, mfetch.nflush32);
+			if (ret < 0)
+				return ret;
+			if (put_user(ret, &uptr->nflush32))
+				return -EFAULT;
+		}
+		ret = mon_bin_fetch(file, rp, compat_ptr(mfetch.offvec32),
+		    mfetch.nfetch32);
+		if (ret < 0)
+			return ret;
+		if (put_user(ret, &uptr->nfetch32))
+			return -EFAULT;
+		ret = 0;
+		}
+		break;
+#endif
+
+	case MON_IOCG_STATS: {
+		struct mon_bin_stats __user *sp;
+		unsigned int nevents;
+		unsigned int ndropped;
+
+		spin_lock_irqsave(&rp->b_lock, flags);
+		ndropped = rp->cnt_lost;
+		rp->cnt_lost = 0;
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+		nevents = mon_bin_queued(rp);
+
+		sp = (struct mon_bin_stats __user *)arg;
+		if (put_user(rp->cnt_lost, &sp->dropped))
+			return -EFAULT;
+		if (put_user(nevents, &sp->queued))
+			return -EFAULT;
+
+		}
+		break;
+
+	default:
+		return -ENOTTY;
+	}
+
+	return ret;
+}
+
+static unsigned int
+mon_bin_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct mon_reader_bin *rp = file->private_data;
+	unsigned int mask = 0;
+	unsigned long flags;
+
+	if (file->f_mode & FMODE_READ)
+		poll_wait(file, &rp->b_wait, wait);
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+	if (!MON_RING_EMPTY(rp))
+		mask |= POLLIN | POLLRDNORM;    /* readable */
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+	return mask;
+}
+
+/*
+ * open and close: just keep track of how many times the device is
+ * mapped, to use the proper memory allocation function.
+ */
+static void mon_bin_vma_open(struct vm_area_struct *vma)
+{
+	struct mon_reader_bin *rp = vma->vm_private_data;
+	rp->mmap_active++;
+}
+
+static void mon_bin_vma_close(struct vm_area_struct *vma)
+{
+	struct mon_reader_bin *rp = vma->vm_private_data;
+	rp->mmap_active--;
+}
+
+/*
+ * Map ring pages to user space.
+ */
+struct page *mon_bin_vma_nopage(struct vm_area_struct *vma,
+                                unsigned long address, int *type)
+{
+	struct mon_reader_bin *rp = vma->vm_private_data;
+	unsigned long offset, chunk_idx;
+	struct page *pageptr;
+
+	offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+	if (offset >= rp->b_size)
+		return NOPAGE_SIGBUS;
+	chunk_idx = offset / CHUNK_SIZE;
+	pageptr = rp->b_vec[chunk_idx].pg;
+	get_page(pageptr);
+	if (type)
+		*type = VM_FAULT_MINOR;
+	return pageptr;
+}
+
+struct vm_operations_struct mon_bin_vm_ops = {
+	.open =     mon_bin_vma_open,
+	.close =    mon_bin_vma_close,
+	.nopage =   mon_bin_vma_nopage,
+};
+
+int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	/* don't do anything here: "nopage" will set up page table entries */
+	vma->vm_ops = &mon_bin_vm_ops;
+	vma->vm_flags |= VM_RESERVED;
+	vma->vm_private_data = filp->private_data;
+	mon_bin_vma_open(vma);
+	return 0;
+}
+
+struct file_operations mon_fops_binary = {
+	.owner =	THIS_MODULE,
+	.open =		mon_bin_open,
+	.llseek =	no_llseek,
+	.read =		mon_bin_read,
+	/* .write =	mon_text_write, */
+	.poll =		mon_bin_poll,
+	.ioctl =	mon_bin_ioctl,
+	.release =	mon_bin_release,
+};
+
+static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp)
+{
+	DECLARE_WAITQUEUE(waita, current);
+	unsigned long flags;
+
+	add_wait_queue(&rp->b_wait, &waita);
+	set_current_state(TASK_INTERRUPTIBLE);
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+	while (MON_RING_EMPTY(rp)) {
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+
+		if (file->f_flags & O_NONBLOCK) {
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue(&rp->b_wait, &waita);
+			return -EWOULDBLOCK; /* Same as EAGAIN in Linux */
+		}
+		schedule();
+		if (signal_pending(current)) {
+			remove_wait_queue(&rp->b_wait, &waita);
+			return -EINTR;
+		}
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		spin_lock_irqsave(&rp->b_lock, flags);
+	}
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&rp->b_wait, &waita);
+	return 0;
+}
+
+static int mon_alloc_buff(struct mon_pgmap *map, int npages)
+{
+	int n;
+	unsigned long vaddr;
+
+	for (n = 0; n < npages; n++) {
+		vaddr = get_zeroed_page(GFP_KERNEL);
+		if (vaddr == 0) {
+			while (n-- != 0)
+				free_page((unsigned long) map[n].ptr);
+			return -ENOMEM;
+		}
+		map[n].ptr = (unsigned char *) vaddr;
+		map[n].pg = virt_to_page(vaddr);
+	}
+	return 0;
+}
+
+static void mon_free_buff(struct mon_pgmap *map, int npages)
+{
+	int n;
+
+	for (n = 0; n < npages; n++)
+		free_page((unsigned long) map[n].ptr);
+}
+
+int __init mon_bin_init(void)
+{
+	int rc;
+
+	rc = alloc_chrdev_region(&mon_bin_dev0, 0, MON_BIN_MAX_MINOR, "usbmon");
+	if (rc < 0)
+		goto err_dev;
+
+	cdev_init(&mon_bin_cdev, &mon_fops_binary);
+	mon_bin_cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&mon_bin_cdev, mon_bin_dev0, MON_BIN_MAX_MINOR);
+	if (rc < 0)
+		goto err_add;
+
+	return 0;
+
+err_add:
+	unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+err_dev:
+	return rc;
+}
+
+void __exit mon_bin_exit(void)
+{
+	cdev_del(&mon_bin_cdev);
+	unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+}
diff --git a/drivers/usb/mon/mon_dma.c b/drivers/usb/mon/mon_dma.c
index ddcfc01..140cc80 100644
--- a/drivers/usb/mon/mon_dma.c
+++ b/drivers/usb/mon/mon_dma.c
@@ -48,6 +48,36 @@
 	local_irq_restore(flags);
 	return 0;
 }
+
+void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+    unsigned int offset, dma_addr_t dma_addr, unsigned int length)
+{
+	unsigned long flags;
+	unsigned int step_len;
+	struct page *pg;
+	unsigned char *map;
+	unsigned long page_off, page_len;
+
+	local_irq_save(flags);
+	while (length) {
+		/* compute number of bytes we are going to copy in this page */
+		step_len = length;
+		page_off = dma_addr & (PAGE_SIZE-1);
+		page_len = PAGE_SIZE - page_off;
+		if (page_len < step_len)
+			step_len = page_len;
+
+		/* copy data and advance pointers */
+		pg = phys_to_page(dma_addr);
+		map = kmap_atomic(pg, KM_IRQ0);
+		offset = mon_copy_to_buff(rp, offset, map + page_off, step_len);
+		kunmap_atomic(map, KM_IRQ0);
+		dma_addr += step_len;
+		length -= step_len;
+	}
+	local_irq_restore(flags);
+}
+
 #endif /* __i386__ */
 
 #ifndef MON_HAS_UNMAP
@@ -55,4 +85,11 @@
 {
 	return 'D';
 }
-#endif
+
+void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+    unsigned int offset, dma_addr_t dma_addr, unsigned int length)
+{
+	;
+}
+
+#endif /* MON_HAS_UNMAP */
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index 394bbf2..c9739e7 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -9,7 +9,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/usb.h>
-#include <linux/debugfs.h>
 #include <linux/smp_lock.h>
 #include <linux/notifier.h>
 #include <linux/mutex.h>
@@ -22,11 +21,10 @@
 static void mon_stop(struct mon_bus *mbus);
 static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
 static void mon_bus_drop(struct kref *r);
-static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus);
+static void mon_bus_init(struct usb_bus *ubus);
 
 DEFINE_MUTEX(mon_lock);
 
-static struct dentry *mon_dir;		/* /dbg/usbmon */
 static LIST_HEAD(mon_buses);		/* All buses we know: struct mon_bus */
 
 /*
@@ -200,7 +198,7 @@
  */
 static void mon_bus_add(struct usb_bus *ubus)
 {
-	mon_bus_init(mon_dir, ubus);
+	mon_bus_init(ubus);
 }
 
 /*
@@ -212,8 +210,8 @@
 
 	mutex_lock(&mon_lock);
 	list_del(&mbus->bus_link);
-	debugfs_remove(mbus->dent_t);
-	debugfs_remove(mbus->dent_s);
+	if (mbus->text_inited)
+		mon_text_del(mbus);
 
 	mon_dissolve(mbus, ubus);
 	kref_put(&mbus->ref, mon_bus_drop);
@@ -281,13 +279,9 @@
  *  - refcount USB bus struct
  *  - link
  */
-static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
+static void mon_bus_init(struct usb_bus *ubus)
 {
-	struct dentry *d;
 	struct mon_bus *mbus;
-	enum { NAMESZ = 10 };
-	char name[NAMESZ];
-	int rc;
 
 	if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
 		goto err_alloc;
@@ -303,57 +297,54 @@
 	ubus->mon_bus = mbus;
 	mbus->uses_dma = ubus->uses_dma;
 
-	rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
-	if (rc <= 0 || rc >= NAMESZ)
-		goto err_print_t;
-	d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_text);
-	if (d == NULL)
-		goto err_create_t;
-	mbus->dent_t = d;
-
-	rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
-	if (rc <= 0 || rc >= NAMESZ)
-		goto err_print_s;
-	d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_stat);
-	if (d == NULL)
-		goto err_create_s;
-	mbus->dent_s = d;
+	mbus->text_inited = mon_text_add(mbus, ubus);
+	// mon_bin_add(...)
 
 	mutex_lock(&mon_lock);
 	list_add_tail(&mbus->bus_link, &mon_buses);
 	mutex_unlock(&mon_lock);
 	return;
 
-err_create_s:
-err_print_s:
-	debugfs_remove(mbus->dent_t);
-err_create_t:
-err_print_t:
-	kfree(mbus);
 err_alloc:
 	return;
 }
 
+/*
+ * Search a USB bus by number. Notice that USB bus numbers start from one,
+ * which we may later use to identify "all" with zero.
+ *
+ * This function must be called with mon_lock held.
+ *
+ * This is obviously inefficient and may be revised in the future.
+ */
+struct mon_bus *mon_bus_lookup(unsigned int num)
+{
+	struct list_head *p;
+	struct mon_bus *mbus;
+
+	list_for_each (p, &mon_buses) {
+		mbus = list_entry(p, struct mon_bus, bus_link);
+		if (mbus->u_bus->busnum == num) {
+			return mbus;
+		}
+	}
+	return NULL;
+}
+
 static int __init mon_init(void)
 {
 	struct usb_bus *ubus;
-	struct dentry *mondir;
+	int rc;
 
-	mondir = debugfs_create_dir("usbmon", NULL);
-	if (IS_ERR(mondir)) {
-		printk(KERN_NOTICE TAG ": debugfs is not available\n");
-		return -ENODEV;
-	}
-	if (mondir == NULL) {
-		printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
-		return -ENODEV;
-	}
-	mon_dir = mondir;
+	if ((rc = mon_text_init()) != 0)
+		goto err_text;
+	if ((rc = mon_bin_init()) != 0)
+		goto err_bin;
 
 	if (usb_mon_register(&mon_ops_0) != 0) {
 		printk(KERN_NOTICE TAG ": unable to register with the core\n");
-		debugfs_remove(mondir);
-		return -ENODEV;
+		rc = -ENODEV;
+		goto err_reg;
 	}
 	// MOD_INC_USE_COUNT(which_module?);
 
@@ -361,10 +352,17 @@
 
 	mutex_lock(&usb_bus_list_lock);
 	list_for_each_entry (ubus, &usb_bus_list, bus_list) {
-		mon_bus_init(mondir, ubus);
+		mon_bus_init(ubus);
 	}
 	mutex_unlock(&usb_bus_list_lock);
 	return 0;
+
+err_reg:
+	mon_bin_exit();
+err_bin:
+	mon_text_exit();
+err_text:
+	return rc;
 }
 
 static void __exit mon_exit(void)
@@ -381,8 +379,8 @@
 		mbus = list_entry(p, struct mon_bus, bus_link);
 		list_del(p);
 
-		debugfs_remove(mbus->dent_t);
-		debugfs_remove(mbus->dent_s);
+		if (mbus->text_inited)
+			mon_text_del(mbus);
 
 		/*
 		 * This never happens, because the open/close paths in
@@ -401,7 +399,8 @@
 	}
 	mutex_unlock(&mon_lock);
 
-	debugfs_remove(mon_dir);
+	mon_text_exit();
+	mon_bin_exit();
 }
 
 module_init(mon_init);
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index 05cf2c9..d38a127 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -9,6 +9,7 @@
 #include <linux/usb.h>
 #include <linux/time.h>
 #include <linux/mutex.h>
+#include <linux/debugfs.h>
 #include <asm/uaccess.h>
 
 #include "usb_mon.h"
@@ -63,6 +64,8 @@
 	char slab_name[SLAB_NAME_SZ];
 };
 
+static struct dentry *mon_dir;		/* Usually /sys/kernel/debug/usbmon */
+
 static void mon_text_ctor(void *, struct kmem_cache *, unsigned long);
 
 /*
@@ -436,7 +439,7 @@
 	return 0;
 }
 
-const struct file_operations mon_fops_text = {
+static const struct file_operations mon_fops_text = {
 	.owner =	THIS_MODULE,
 	.open =		mon_text_open,
 	.llseek =	no_llseek,
@@ -447,6 +450,47 @@
 	.release =	mon_text_release,
 };
 
+int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
+{
+	struct dentry *d;
+	enum { NAMESZ = 10 };
+	char name[NAMESZ];
+	int rc;
+
+	rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
+	if (rc <= 0 || rc >= NAMESZ)
+		goto err_print_t;
+	d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text);
+	if (d == NULL)
+		goto err_create_t;
+	mbus->dent_t = d;
+
+	/* XXX The stats do not belong to here (text API), but oh well... */
+	rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
+	if (rc <= 0 || rc >= NAMESZ)
+		goto err_print_s;
+	d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat);
+	if (d == NULL)
+		goto err_create_s;
+	mbus->dent_s = d;
+
+	return 1;
+
+err_create_s:
+err_print_s:
+	debugfs_remove(mbus->dent_t);
+	mbus->dent_t = NULL;
+err_create_t:
+err_print_t:
+	return 0;
+}
+
+void mon_text_del(struct mon_bus *mbus)
+{
+	debugfs_remove(mbus->dent_t);
+	debugfs_remove(mbus->dent_s);
+}
+
 /*
  * Slab interface: constructor.
  */
@@ -459,3 +503,24 @@
 	memset(mem, 0xe5, sizeof(struct mon_event_text));
 }
 
+int __init mon_text_init(void)
+{
+	struct dentry *mondir;
+
+	mondir = debugfs_create_dir("usbmon", NULL);
+	if (IS_ERR(mondir)) {
+		printk(KERN_NOTICE TAG ": debugfs is not available\n");
+		return -ENODEV;
+	}
+	if (mondir == NULL) {
+		printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
+		return -ENODEV;
+	}
+	mon_dir = mondir;
+	return 0;
+}
+
+void __exit mon_text_exit(void)
+{
+	debugfs_remove(mon_dir);
+}
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
index ab9d02d..4f949ce 100644
--- a/drivers/usb/mon/usb_mon.h
+++ b/drivers/usb/mon/usb_mon.h
@@ -17,9 +17,11 @@
 struct mon_bus {
 	struct list_head bus_link;
 	spinlock_t lock;
+	struct usb_bus *u_bus;
+
+	int text_inited;
 	struct dentry *dent_s;		/* Debugging file */
 	struct dentry *dent_t;		/* Text interface file */
-	struct usb_bus *u_bus;
 	int uses_dma;
 
 	/* Ref */
@@ -48,13 +50,35 @@
 void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
 void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
 
+struct mon_bus *mon_bus_lookup(unsigned int num);
+
+int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus);
+void mon_text_del(struct mon_bus *mbus);
+// void mon_bin_add(struct mon_bus *);
+
+int __init mon_text_init(void);
+void __exit mon_text_exit(void);
+int __init mon_bin_init(void);
+void __exit mon_bin_exit(void);
+
 /*
- */
+ * DMA interface.
+ *
+ * XXX The vectored side needs a serious re-thinking. Abstracting vectors,
+ * like in Paolo's original patch, produces a double pkmap. We need an idea.
+*/
 extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len);
 
+struct mon_reader_bin;
+extern void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+    unsigned int offset, dma_addr_t dma_addr, unsigned int len);
+extern unsigned int mon_copy_to_buff(const struct mon_reader_bin *rp,
+    unsigned int offset, const unsigned char *from, unsigned int len);
+
+/*
+ */
 extern struct mutex mon_lock;
 
-extern const struct file_operations mon_fops_text;
 extern const struct file_operations mon_fops_stat;
 
 #endif /* __USB_MON_H */
diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig
index e081836..a2b94ef5 100644
--- a/drivers/usb/net/Kconfig
+++ b/drivers/usb/net/Kconfig
@@ -222,13 +222,15 @@
 	  adapters marketed under the DeLOCK brand.
 
 config USB_NET_RNDIS_HOST
-	tristate "Host for RNDIS devices (EXPERIMENTAL)"
+	tristate "Host for RNDIS and ActiveSync devices (EXPERIMENTAL)"
 	depends on USB_USBNET && EXPERIMENTAL
 	select USB_NET_CDCETHER
 	help
 	  This option enables hosting "Remote NDIS" USB networking links,
 	  as encouraged by Microsoft (instead of CDC Ethernet!) for use in
-	  various devices that may only support this protocol.
+	  various devices that may only support this protocol.  A variant
+	  of this protocol (with even less public documentation) seems to
+	  be at the root of Microsoft's "ActiveSync" too.
 
 	  Avoid using this protocol unless you have no better options.
 	  The protocol specification is incomplete, and is controlled by
diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c
index 896449f..4206df2 100644
--- a/drivers/usb/net/asix.c
+++ b/drivers/usb/net/asix.c
@@ -1449,6 +1449,10 @@
 	// Linksys USB1000
 	USB_DEVICE (0x1737, 0x0039),
 	.driver_info = (unsigned long) &ax88178_info,
+}, {
+	// IO-DATA ETG-US2
+	USB_DEVICE (0x04bb, 0x0930),
+	.driver_info = (unsigned long) &ax88178_info,
 },
 	{ },		// END
 };
diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c
index 44a9154..e5cdafa 100644
--- a/drivers/usb/net/cdc_ether.c
+++ b/drivers/usb/net/cdc_ether.c
@@ -1,6 +1,7 @@
 /*
  * CDC Ethernet based networking peripherals
  * Copyright (C) 2003-2005 by David Brownell
+ * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync)
  *
  * 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
@@ -35,6 +36,29 @@
 #include "usbnet.h"
 
 
+#if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
+
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+	return desc->bInterfaceClass == USB_CLASS_COMM
+		&& desc->bInterfaceSubClass == 2
+		&& desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+	return desc->bInterfaceClass == USB_CLASS_MISC
+		&& desc->bInterfaceSubClass == 1
+		&& desc->bInterfaceProtocol == 1;
+}
+
+#else
+
+#define is_rndis(desc)		0
+#define is_activesync(desc)	0
+
+#endif
+
 /*
  * probes control interface, claims data interface, collects the bulk
  * endpoints, activates data interface (if needed), maybe sets MTU.
@@ -71,7 +95,8 @@
 	/* this assumes that if there's a non-RNDIS vendor variant
 	 * of cdc-acm, it'll fail RNDIS requests cleanly.
 	 */
-	rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff);
+	rndis = is_rndis(&intf->cur_altsetting->desc)
+		|| is_activesync(&intf->cur_altsetting->desc);
 
 	memset(info, 0, sizeof *info);
 	info->control = intf;
@@ -99,6 +124,23 @@
 				goto bad_desc;
 			}
 			break;
+		case USB_CDC_ACM_TYPE:
+			/* paranoia:  disambiguate a "real" vendor-specific
+			 * modem interface from an RNDIS non-modem.
+			 */
+			if (rndis) {
+				struct usb_cdc_acm_descriptor *d;
+
+				d = (void *) buf;
+				if (d->bmCapabilities) {
+					dev_dbg(&intf->dev,
+						"ACM capabilities %02x, "
+						"not really RNDIS?\n",
+						d->bmCapabilities);
+					goto bad_desc;
+				}
+			}
+			break;
 		case USB_CDC_UNION_TYPE:
 			if (info->u) {
 				dev_dbg(&intf->dev, "extra CDC union\n");
@@ -171,7 +213,21 @@
 		buf += buf [0];
 	}
 
-	if (!info->header || !info->u || (!rndis && !info->ether)) {
+	/* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors,
+	 * so we'll hard-wire the interfaces and not check for descriptors.
+	 */
+	if (is_activesync(&intf->cur_altsetting->desc) && !info->u) {
+		info->control = usb_ifnum_to_if(dev->udev, 0);
+		info->data = usb_ifnum_to_if(dev->udev, 1);
+		if (!info->control || !info->data) {
+			dev_dbg(&intf->dev,
+				"activesync: master #0/%p slave #1/%p\n",
+				info->control,
+				info->data);
+			goto bad_desc;
+		}
+
+	} else if (!info->header || !info->u || (!rndis && !info->ether)) {
 		dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
 			info->header ? "" : "header ",
 			info->u ? "" : "union ",
diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c
index a6f0f4d..31e5fe3 100644
--- a/drivers/usb/net/gl620a.c
+++ b/drivers/usb/net/gl620a.c
@@ -70,12 +70,12 @@
 	(((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4)
 
 struct gl_packet {
-	u32		packet_length;
+	__le32		packet_length;
 	char		packet_data [1];
 };
 
 struct gl_header {
-	u32			packet_count;
+	__le32			packet_count;
 	struct gl_packet	packets;
 };
 
@@ -85,15 +85,14 @@
 	struct gl_packet	*packet;
 	struct sk_buff		*gl_skb;
 	u32			size;
+	u32			count;
 
 	header = (struct gl_header *) skb->data;
 
 	// get the packet count of the received skb
-	le32_to_cpus(&header->packet_count);
-	if ((header->packet_count > GL_MAX_TRANSMIT_PACKETS)
-			|| (header->packet_count < 0)) {
-		dbg("genelink: invalid received packet count %d",
-			header->packet_count);
+	count = le32_to_cpu(header->packet_count);
+	if (count > GL_MAX_TRANSMIT_PACKETS) {
+		dbg("genelink: invalid received packet count %u", count);
 		return 0;
 	}
 
@@ -103,7 +102,7 @@
 	// decrement the length for the packet count size 4 bytes
 	skb_pull(skb, 4);
 
-	while (header->packet_count > 1) {
+	while (count > 1) {
 		// get the packet length
 		size = le32_to_cpu(packet->packet_length);
 
@@ -124,9 +123,8 @@
 		}
 
 		// advance to the next packet
-		packet = (struct gl_packet *)
-			&packet->packet_data [size];
-		header->packet_count--;
+		packet = (struct gl_packet *)&packet->packet_data[size];
+		count--;
 
 		// shift the data pointer to the next gl_packet
 		skb_pull(skb, size + 4);
@@ -149,8 +147,8 @@
 	int	length = skb->len;
 	int	headroom = skb_headroom(skb);
 	int	tailroom = skb_tailroom(skb);
-	u32	*packet_count;
-	u32	*packet_len;
+	__le32	*packet_count;
+	__le32	*packet_len;
 
 	// FIXME:  magic numbers, bleech
 	padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1;
@@ -172,7 +170,7 @@
 	}
 
 	// attach the packet count to the header
-	packet_count = (u32 *) skb_push(skb, (4 + 4*1));
+	packet_count = (__le32 *) skb_push(skb, (4 + 4*1));
 	packet_len = packet_count + 1;
 
 	*packet_count = cpu_to_le32(1);
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
index fa78326..36a9891 100644
--- a/drivers/usb/net/kaweth.c
+++ b/drivers/usb/net/kaweth.c
@@ -179,6 +179,7 @@
 	.suspend =	kaweth_suspend,
 	.resume =	kaweth_resume,
 	.id_table =     usb_klsi_table,
+	.supports_autosuspend =	1,
 };
 
 typedef __u8 eth_addr_t[6];
@@ -225,6 +226,7 @@
 	struct delayed_work lowmem_work;
 
 	struct usb_device *dev;
+	struct usb_interface *intf;
 	struct net_device *net;
 	wait_queue_head_t term_wait;
 
@@ -662,9 +664,14 @@
 
 	dbg("Opening network device.");
 
+	res = usb_autopm_get_interface(kaweth->intf);
+	if (res) {
+		err("Interface cannot be resumed.");
+		return -EIO;
+	}
 	res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
 	if (res)
-		return -EIO;
+		goto err_out;
 
 	usb_fill_int_urb(
 		kaweth->irq_urb,
@@ -681,7 +688,7 @@
 	res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL);
 	if (res) {
 		usb_kill_urb(kaweth->rx_urb);
-		return -EIO;
+		goto err_out;
 	}
 	kaweth->opened = 1;
 
@@ -689,10 +696,14 @@
 
 	kaweth_async_set_rx_mode(kaweth);
 	return 0;
+
+err_out:
+	usb_autopm_enable(kaweth->intf);
+	return -EIO;
 }
 
 /****************************************************************
- *     kaweth_close
+ *     kaweth_kill_urbs
  ****************************************************************/
 static void kaweth_kill_urbs(struct kaweth_device *kaweth)
 {
@@ -724,17 +735,29 @@
 
 	kaweth->status &= ~KAWETH_STATUS_CLOSING;
 
+	usb_autopm_enable(kaweth->intf);
+
 	return 0;
 }
 
 static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
+	struct kaweth_device *kaweth = netdev_priv(dev);
 
 	strlcpy(info->driver, driver_name, sizeof(info->driver));
+	usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info));
+}
+
+static u32 kaweth_get_link(struct net_device *dev)
+{
+	struct kaweth_device *kaweth = netdev_priv(dev);
+
+	return kaweth->linkstate;
 }
 
 static struct ethtool_ops ops = {
-	.get_drvinfo = kaweth_get_drvinfo
+	.get_drvinfo	= kaweth_get_drvinfo,
+	.get_link	= kaweth_get_link
 };
 
 /****************************************************************
@@ -908,6 +931,7 @@
 	struct kaweth_device *kaweth = usb_get_intfdata(intf);
 	unsigned long flags;
 
+	dbg("Suspending device");
 	spin_lock_irqsave(&kaweth->device_lock, flags);
 	kaweth->status |= KAWETH_STATUS_SUSPENDING;
 	spin_unlock_irqrestore(&kaweth->device_lock, flags);
@@ -924,6 +948,7 @@
 	struct kaweth_device *kaweth = usb_get_intfdata(intf);
 	unsigned long flags;
 
+	dbg("Resuming device");
 	spin_lock_irqsave(&kaweth->device_lock, flags);
 	kaweth->status &= ~KAWETH_STATUS_SUSPENDING;
 	spin_unlock_irqrestore(&kaweth->device_lock, flags);
@@ -1086,6 +1111,8 @@
 
 	dbg("Initializing net device.");
 
+	kaweth->intf = intf;
+
 	kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!kaweth->tx_urb)
 		goto err_free_netdev;
@@ -1265,7 +1292,7 @@
 {
         struct urb *urb;
         int retv;
-        int length;
+        int length = 0; /* shut up GCC */
 
         urb = usb_alloc_urb(0, GFP_NOIO);
         if (!urb)
diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h
index 98f6898..c746782 100644
--- a/drivers/usb/net/pegasus.h
+++ b/drivers/usb/net/pegasus.h
@@ -214,9 +214,9 @@
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004,
+PEGASUS_DEV( "Corega FEther USB-TX", VENDOR_COREGA, 0x0004,
 		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Corega FEter USB-TXS", VENDOR_COREGA, 0x000d,
+PEGASUS_DEV( "Corega FEther USB-TXS", VENDOR_COREGA, 0x000d,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
 		DEFAULT_GPIO_RESET )
diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c
index a322a16..be888d2 100644
--- a/drivers/usb/net/rndis_host.c
+++ b/drivers/usb/net/rndis_host.c
@@ -49,6 +49,8 @@
  *    - In some cases, MS-Windows will emit undocumented requests; this
  *	matters more to peripheral implementations than host ones.
  *
+ * Moreover there's a no-open-specs variant of RNDIS called "ActiveSync".
+ *
  * For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in
  * favor of such non-proprietary alternatives as CDC Ethernet or the newer (and
  * currently rare) "Ethernet Emulation Model" (EEM).
@@ -61,6 +63,9 @@
  *  - control-in:  GET_ENCAPSULATED
  *
  * We'll try to ignore the RESPONSE_AVAILABLE notifications.
+ *
+ * REVISIT some RNDIS implementations seem to have curious issues still
+ * to be resolved.
  */
 struct rndis_msg_hdr {
 	__le32	msg_type;			/* RNDIS_MSG_* */
@@ -71,8 +76,14 @@
 	// ... and more
 } __attribute__ ((packed));
 
-/* RNDIS defines this (absurdly huge) control timeout */
-#define	RNDIS_CONTROL_TIMEOUT_MS	(10 * 1000)
+/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
+#define	CONTROL_BUFFER_SIZE		1025
+
+/* RNDIS defines an (absurdly huge) 10 second control timeout,
+ * but ActiveSync seems to use a more usual 5 second timeout
+ * (which matches the USB 2.0 spec).
+ */
+#define	RNDIS_CONTROL_TIMEOUT_MS	(5 * 1000)
 
 
 #define ccpu2 __constant_cpu_to_le32
@@ -270,6 +281,7 @@
 static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
 {
 	struct cdc_state	*info = (void *) &dev->data;
+	int			master_ifnum;
 	int			retval;
 	unsigned		count;
 	__le32			rsp;
@@ -279,7 +291,7 @@
 	 * disconnect(): either serialize, or dispatch responses on xid
 	 */
 
-	/* Issue the request; don't bother byteswapping our xid */
+	/* Issue the request; xid is unique, don't bother byteswapping it */
 	if (likely(buf->msg_type != RNDIS_MSG_HALT
 			&& buf->msg_type != RNDIS_MSG_RESET)) {
 		xid = dev->xid++;
@@ -287,11 +299,12 @@
 			xid = dev->xid++;
 		buf->request_id = (__force __le32) xid;
 	}
+	master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber;
 	retval = usb_control_msg(dev->udev,
 		usb_sndctrlpipe(dev->udev, 0),
 		USB_CDC_SEND_ENCAPSULATED_COMMAND,
 		USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-		0, info->u->bMasterInterface0,
+		0, master_ifnum,
 		buf, le32_to_cpu(buf->msg_len),
 		RNDIS_CONTROL_TIMEOUT_MS);
 	if (unlikely(retval < 0 || xid == 0))
@@ -306,13 +319,13 @@
 	 */
 	rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
 	for (count = 0; count < 10; count++) {
-		memset(buf, 0, 1024);
+		memset(buf, 0, CONTROL_BUFFER_SIZE);
 		retval = usb_control_msg(dev->udev,
 			usb_rcvctrlpipe(dev->udev, 0),
 			USB_CDC_GET_ENCAPSULATED_RESPONSE,
 			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-			0, info->u->bMasterInterface0,
-			buf, 1024,
+			0, master_ifnum,
+			buf, CONTROL_BUFFER_SIZE,
 			RNDIS_CONTROL_TIMEOUT_MS);
 		if (likely(retval >= 8)) {
 			msg_len = le32_to_cpu(buf->msg_len);
@@ -350,7 +363,7 @@
 					usb_sndctrlpipe(dev->udev, 0),
 					USB_CDC_SEND_ENCAPSULATED_COMMAND,
 					USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-					0, info->u->bMasterInterface0,
+					0, master_ifnum,
 					msg, sizeof *msg,
 					RNDIS_CONTROL_TIMEOUT_MS);
 				if (unlikely(retval < 0))
@@ -393,38 +406,64 @@
 	u32			tmp;
 
 	/* we can't rely on i/o from stack working, or stack allocation */
-	u.buf = kmalloc(1024, GFP_KERNEL);
+	u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
 	if (!u.buf)
 		return -ENOMEM;
 	retval = usbnet_generic_cdc_bind(dev, intf);
 	if (retval < 0)
 		goto fail;
 
-	net->hard_header_len += sizeof (struct rndis_data_hdr);
-
-	/* initialize; max transfer is 16KB at full speed */
 	u.init->msg_type = RNDIS_MSG_INIT;
 	u.init->msg_len = ccpu2(sizeof *u.init);
 	u.init->major_version = ccpu2(1);
 	u.init->minor_version = ccpu2(0);
-	u.init->max_transfer_size = ccpu2(net->mtu + net->hard_header_len);
 
+	/* max transfer (in spec) is 0x4000 at full speed, but for
+	 * TX we'll stick to one Ethernet packet plus RNDIS framing.
+	 * For RX we handle drivers that zero-pad to end-of-packet.
+	 * Don't let userspace change these settings.
+	 */
+	net->hard_header_len += sizeof (struct rndis_data_hdr);
+	dev->hard_mtu = net->mtu + net->hard_header_len;
+
+	dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1);
+	dev->rx_urb_size &= ~(dev->maxpacket - 1);
+	u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size);
+
+	net->change_mtu = NULL;
 	retval = rndis_command(dev, u.header);
 	if (unlikely(retval < 0)) {
 		/* it might not even be an RNDIS device!! */
 		dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
+ 		goto fail_and_release;
+	}
+	tmp = le32_to_cpu(u.init_c->max_transfer_size);
+	if (tmp < dev->hard_mtu) {
+		dev_err(&intf->dev,
+			"dev can't take %u byte packets (max %u)\n",
+			dev->hard_mtu, tmp);
 		goto fail_and_release;
 	}
-	dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size);
+
 	/* REVISIT:  peripheral "alignment" request is ignored ... */
-	dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu,
+	dev_dbg(&intf->dev,
+		"hard mtu %u (%u from dev), rx buflen %Zu, align %d\n",
+		dev->hard_mtu, tmp, dev->rx_urb_size,
 		1 << le32_to_cpu(u.init_c->packet_alignment));
 
-	/* get designated host ethernet address */
-	memset(u.get, 0, sizeof *u.get);
+	/* Get designated host ethernet address.
+	 *
+	 * Adding a payload exactly the same size as the expected response
+	 * payload is an evident requirement MSFT added for ActiveSync.
+	 * This undocumented (and nonsensical) issue was found by sniffing
+	 * protocol requests from the ActiveSync 4.1 Windows driver.
+	 */
+	memset(u.get, 0, sizeof *u.get + 48);
 	u.get->msg_type = RNDIS_MSG_QUERY;
-	u.get->msg_len = ccpu2(sizeof *u.get);
+	u.get->msg_len = ccpu2(sizeof *u.get + 48);
 	u.get->oid = OID_802_3_PERMANENT_ADDRESS;
+	u.get->len = ccpu2(48);
+	u.get->offset = ccpu2(20);
 
 	retval = rndis_command(dev, u.header);
 	if (unlikely(retval < 0)) {
@@ -432,7 +471,7 @@
 		goto fail_and_release;
 	}
 	tmp = le32_to_cpu(u.get_c->offset);
-	if (unlikely((tmp + 8) > (1024 - ETH_ALEN)
+	if (unlikely((tmp + 8) > (CONTROL_BUFFER_SIZE - ETH_ALEN)
 			|| u.get_c->len != ccpu2(ETH_ALEN))) {
 		dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n",
 			tmp, le32_to_cpu(u.get_c->len));
@@ -598,6 +637,10 @@
 	/* RNDIS is MSFT's un-official variant of CDC ACM */
 	USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
 	.driver_info = (unsigned long) &rndis_info,
+}, {
+	/* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
+	USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
+	.driver_info = (unsigned long) &rndis_info,
 },
 	{ },		// END
 };
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index 86bcf63..11dad42 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -572,8 +572,20 @@
 		schedule_work(&priv->rx_work);
 }
 
+static struct usb_driver aircable_driver = {
+	.name =		"aircable",
+	.probe =	usb_serial_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	id_table,
+	.no_dynamic_id =	1,
+};
+
 static struct usb_serial_driver aircable_device = {
-	.description =		"aircable",
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"aircable",
+	},
+	.usb_driver = 		&aircable_driver,
 	.id_table = 		id_table,
 	.num_ports =		1,
 	.attach =		aircable_attach,
@@ -587,13 +599,6 @@
 	.unthrottle =		aircable_unthrottle,
 };
 
-static struct usb_driver aircable_driver = {
-	.name =		"aircable",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 static int __init aircable_init (void)
 {
 	int retval;
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index f2ca76a..0af42e3 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -277,6 +277,7 @@
 		.owner =	THIS_MODULE,
 		.name =		"airprime",
 	},
+	.usb_driver =		&airprime_driver,
 	.id_table =		id_table,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 5261cd2..edd6857 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -444,6 +444,7 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
+	.no_dynamic_id =	1,
 };
 
 static struct usb_serial_driver ark3116_device = {
@@ -452,6 +453,7 @@
 		.name =		"ark3116",
 	},
 	.id_table =		id_table,
+	.usb_driver =		&ark3116_driver,
 	.num_interrupt_in =	1,
 	.num_bulk_in =		1,
 	.num_bulk_out =		1,
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 38b4dae..3b800d2 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -126,6 +126,7 @@
 		.name =		"belkin",
 	},
 	.description =		"Belkin / Peracom / GoHubs USB Serial Adapter",
+	.usb_driver =		&belkin_driver,
 	.id_table =		id_table_combined,
 	.num_interrupt_in =	1,
 	.num_bulk_in =		1,
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index 6542f22..c08a384 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -103,11 +103,52 @@
 	return retval;
 }
 
+#ifdef CONFIG_HOTPLUG
+static ssize_t store_new_id(struct device_driver *driver,
+			    const char *buf, size_t count)
+{
+	struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
+	ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+
+	if (retval >= 0 && usb_drv->usb_driver != NULL)
+		retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
+					  &usb_drv->usb_driver->drvwrap.driver,
+					  buf, count);
+	return retval;
+}
+
+static struct driver_attribute drv_attrs[] = {
+	__ATTR(new_id, S_IWUSR, NULL, store_new_id),
+	__ATTR_NULL,
+};
+
+static void free_dynids(struct usb_serial_driver *drv)
+{
+	struct usb_dynid *dynid, *n;
+
+	spin_lock(&drv->dynids.lock);
+	list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
+		list_del(&dynid->node);
+		kfree(dynid);
+	}
+	spin_unlock(&drv->dynids.lock);
+}
+
+#else
+static struct driver_attribute drv_attrs[] = {
+	__ATTR_NULL,
+};
+static inline void free_dynids(struct usb_driver *drv)
+{
+}
+#endif
+
 struct bus_type usb_serial_bus_type = {
 	.name =		"usb-serial",
 	.match =	usb_serial_device_match,
 	.probe =	usb_serial_device_probe,
 	.remove =	usb_serial_device_remove,
+	.drv_attrs = 	drv_attrs,
 };
 
 int usb_serial_bus_register(struct usb_serial_driver *driver)
@@ -115,6 +156,9 @@
 	int retval;
 
 	driver->driver.bus = &usb_serial_bus_type;
+	spin_lock_init(&driver->dynids.lock);
+	INIT_LIST_HEAD(&driver->dynids.list);
+
 	retval = driver_register(&driver->driver);
 
 	return retval;
@@ -122,6 +166,7 @@
 
 void usb_serial_bus_deregister(struct usb_serial_driver *driver)
 {
+	free_dynids(driver);
 	driver_unregister(&driver->driver);
 }
 
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index 7ebaffd..3ec2487 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -89,6 +89,7 @@
 		.owner =	THIS_MODULE,
 		.name = 	"cp2101",
 	},
+	.usb_driver		= &cp2101_driver,
 	.id_table		= id_table,
 	.num_interrupt_in	= 0,
 	.num_bulk_in		= 0,
@@ -169,13 +170,13 @@
 		unsigned int *data, int size)
 {
 	struct usb_serial *serial = port->serial;
-	u32 *buf;
+	__le32 *buf;
 	int result, i, length;
 
 	/* Number of integers required to contain the array */
 	length = (((size - 1) | 3) + 1)/4;
 
-	buf = kcalloc(length, sizeof(u32), GFP_KERNEL);
+	buf = kcalloc(length, sizeof(__le32), GFP_KERNEL);
 	if (!buf) {
 		dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
 		return -ENOMEM;
@@ -215,13 +216,13 @@
 		unsigned int *data, int size)
 {
 	struct usb_serial *serial = port->serial;
-	u32 *buf;
+	__le32 *buf;
 	int result, i, length;
 
 	/* Number of integers required to contain the array */
 	length = (((size - 1) | 3) + 1)/4;
 
-	buf = kmalloc(length * sizeof(u32), GFP_KERNEL);
+	buf = kmalloc(length * sizeof(__le32), GFP_KERNEL);
 	if (!buf) {
 		dev_err(&port->dev, "%s - out of memory.\n",
 				__FUNCTION__);
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index a63c328..4167753 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -88,6 +88,7 @@
 		.name =		"cyberjack",
 	},
 	.description =		"Reiner SCT Cyberjack USB card reader",
+	.usb_driver = 		&cyberjack_driver,
 	.id_table =		id_table,
 	.num_interrupt_in =	1,
 	.num_bulk_in =		1,
@@ -98,7 +99,7 @@
 	.open =			cyberjack_open,
 	.close =		cyberjack_close,
 	.write =		cyberjack_write,
-	.write_room =	cyberjack_write_room,
+	.write_room =		cyberjack_write_room,
 	.read_int_callback =	cyberjack_read_int_callback,
 	.read_bulk_callback =	cyberjack_read_bulk_callback,
 	.write_bulk_callback =	cyberjack_write_bulk_callback,
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 6bc1f40..57b8e27 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -193,6 +193,7 @@
 		.name =			"earthmate",
 	},
 	.description =			"DeLorme Earthmate USB",
+	.usb_driver = 			&cypress_driver,
 	.id_table =			id_table_earthmate,
 	.num_interrupt_in = 		1,
 	.num_interrupt_out =		1,
@@ -222,6 +223,7 @@
 		.name =			"cyphidcom",
 	},
 	.description =			"HID->COM RS232 Adapter",
+	.usb_driver = 			&cypress_driver,
 	.id_table =			id_table_cyphidcomrs232,
 	.num_interrupt_in =		1,
 	.num_interrupt_out =		1,
@@ -251,6 +253,7 @@
                 .name =			"nokiaca42v2",
 	},
 	.description =			"Nokia CA-42 V2 Adapter",
+	.usb_driver = 			&cypress_driver,
 	.id_table =			id_table_nokiaca42v2,
 	.num_interrupt_in =		1,
 	.num_interrupt_out =		1,
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index efd9ce3..0b0fb51 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -509,6 +509,7 @@
 		.name =			"digi_2",
 	},
 	.description =			"Digi 2 port USB adapter",
+	.usb_driver = 			&digi_driver,
 	.id_table =			id_table_2,
 	.num_interrupt_in =		0,
 	.num_bulk_in =			4,
@@ -538,6 +539,7 @@
 		.name =			"digi_4",
 	},
 	.description =			"Digi 4 port USB adapter",
+	.usb_driver = 			&digi_driver,
 	.id_table =			id_table_4,
 	.num_interrupt_in =		0,
 	.num_bulk_in =			5,
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 92beeb1..4703c8f 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -117,6 +117,7 @@
 		.name =		"empeg",
 	},
 	.id_table =		id_table,
+	.usb_driver = 		&empeg_driver,
 	.num_interrupt_in =	0,
 	.num_bulk_in =		1,
 	.num_bulk_out =		1,
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 6986e75..4695952 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -464,7 +464,6 @@
 	{ USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
 	{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
 	{ USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) },
-	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
 	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
@@ -615,6 +614,7 @@
 		.name =		"ftdi_sio",
 	},
 	.description =		"FTDI USB Serial Device",
+	.usb_driver = 		&ftdi_driver ,
 	.id_table =		id_table_combined,
 	.num_interrupt_in =	0,
 	.num_bulk_in =		1,
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 40dd394..7eff1c0 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -364,7 +364,6 @@
  * USB-TTY activ, USB-TTY passiv.  Some PIDs are used by several devices
  * and I'm not entirely sure which are used by which.
  */
-#define FTDI_4N_GALAXY_DE_0_PID	0x8372
 #define FTDI_4N_GALAXY_DE_1_PID	0xF3C0
 #define FTDI_4N_GALAXY_DE_2_PID	0xF3C1
 
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index 2bebd63..4092f6d 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -58,6 +58,7 @@
 		.name =		"funsoft",
 	},
 	.id_table =		id_table,
+	.usb_driver = 		&funsoft_driver,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 6530d39..74660a3 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1566,6 +1566,7 @@
 		.name        = "garmin_gps",
 	},
 	.description         = "Garmin GPS usb/tty",
+	.usb_driver          = &garmin_driver,
 	.id_table            = id_table,
 	.num_interrupt_in    = 1,
 	.num_bulk_in         = 1,
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 3604293..601e064 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -20,6 +20,10 @@
 #include <linux/usb/serial.h>
 #include <asm/uaccess.h>
 
+static int generic_probe(struct usb_interface *interface,
+			 const struct usb_device_id *id);
+
+
 static int debug;
 
 #ifdef CONFIG_USB_SERIAL_GENERIC
@@ -34,6 +38,21 @@
 
 static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */
 
+/* we want to look at all devices, as the vendor/product id can change
+ * depending on the command line argument */
+static struct usb_device_id generic_serial_ids[] = {
+	{.driver_info = 42},
+	{}
+};
+
+static struct usb_driver generic_driver = {
+	.name =		"usbserial_generic",
+	.probe =	generic_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	generic_serial_ids,
+	.no_dynamic_id =	1,
+};
+
 /* All of the device info needed for the Generic Serial Converter */
 struct usb_serial_driver usb_serial_generic_device = {
 	.driver = {
@@ -41,6 +60,7 @@
 		.name =		"generic",
 	},
 	.id_table =		generic_device_ids,
+	.usb_driver = 		&generic_driver,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
@@ -48,13 +68,6 @@
 	.shutdown =		usb_serial_generic_shutdown,
 };
 
-/* we want to look at all devices, as the vendor/product id can change
- * depending on the command line argument */
-static struct usb_device_id generic_serial_ids[] = {
-	{.driver_info = 42},
-	{}
-};
-
 static int generic_probe(struct usb_interface *interface,
 			       const struct usb_device_id *id)
 {
@@ -65,14 +78,6 @@
 		return usb_serial_probe(interface, id);
 	return -ENODEV;
 }
-
-static struct usb_driver generic_driver = {
-	.name =		"usbserial_generic",
-	.probe =	generic_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	generic_serial_ids,
-	.no_dynamic_id = 	1,
-};
 #endif
 
 int usb_serial_generic_register (int _debug)
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
index ebcac70..6c6ebae 100644
--- a/drivers/usb/serial/hp4x.c
+++ b/drivers/usb/serial/hp4x.c
@@ -49,6 +49,7 @@
 		.name =		"hp4X",
 	},
 	.id_table =		id_table,
+	.usb_driver = 		&hp49gp_driver,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index f623d58..6a26a2e 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -146,6 +146,8 @@
 	struct edge_manuf_descriptor	manuf_descriptor;	/* the manufacturer descriptor */
 	struct edge_boot_descriptor	boot_descriptor;	/* the boot firmware descriptor */
 	struct edgeport_product_info	product_info;		/* Product Info */
+	struct edge_compatibility_descriptor epic_descriptor;	/* Edgeport compatible descriptor */
+	int			is_epic;			/* flag if EPiC device or not */
 
 	__u8			interrupt_in_endpoint;		/* the interrupt endpoint handle */
 	unsigned char *		interrupt_in_buffer;		/* the buffer we use for the interrupt endpoint */
@@ -240,14 +242,6 @@
 
 #include "io_tables.h"	/* all of the devices that this driver supports */
 
-static struct usb_driver io_driver = {
-	.name =		"io_edgeport",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table_combined,
-	.no_dynamic_id = 	1,
-};
-
 /* function prototypes for all of our local functions */
 static void  process_rcvd_data		(struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength);
 static void process_rcvd_status		(struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3);
@@ -397,6 +391,7 @@
 	unicode_to_ascii(string, buflen, pStringDesc->wData, pStringDesc->bLength/2);
 
 	kfree(pStringDesc);
+	dbg("%s - USB String %s", __FUNCTION__, string);
 	return strlen(string);
 }
 
@@ -434,6 +429,34 @@
 }
 #endif
 
+static void dump_product_info(struct edgeport_product_info *product_info)
+{
+	// Dump Product Info structure
+	dbg("**Product Information:");
+	dbg("  ProductId             %x", product_info->ProductId );
+	dbg("  NumPorts              %d", product_info->NumPorts );
+	dbg("  ProdInfoVer           %d", product_info->ProdInfoVer );
+	dbg("  IsServer              %d", product_info->IsServer);
+	dbg("  IsRS232               %d", product_info->IsRS232 );
+	dbg("  IsRS422               %d", product_info->IsRS422 );
+	dbg("  IsRS485               %d", product_info->IsRS485 );
+	dbg("  RomSize               %d", product_info->RomSize );
+	dbg("  RamSize               %d", product_info->RamSize );
+	dbg("  CpuRev                %x", product_info->CpuRev  );
+	dbg("  BoardRev              %x", product_info->BoardRev);
+	dbg("  BootMajorVersion      %d.%d.%d", product_info->BootMajorVersion,
+	    product_info->BootMinorVersion,
+	    le16_to_cpu(product_info->BootBuildNumber));
+	dbg("  FirmwareMajorVersion  %d.%d.%d", product_info->FirmwareMajorVersion,
+	    product_info->FirmwareMinorVersion,
+	    le16_to_cpu(product_info->FirmwareBuildNumber));
+	dbg("  ManufactureDescDate   %d/%d/%d", product_info->ManufactureDescDate[0],
+	    product_info->ManufactureDescDate[1],
+	    product_info->ManufactureDescDate[2]+1900);
+	dbg("  iDownloadFile         0x%x", product_info->iDownloadFile);
+	dbg("  EpicVer               %d", product_info->EpicVer);
+}
+
 static void get_product_info(struct edgeport_serial *edge_serial)
 {
 	struct edgeport_product_info *product_info = &edge_serial->product_info;
@@ -495,30 +518,60 @@
 			break;
 	}
 
-	// Dump Product Info structure
-	dbg("**Product Information:");
-	dbg("  ProductId             %x", product_info->ProductId );
-	dbg("  NumPorts              %d", product_info->NumPorts );
-	dbg("  ProdInfoVer           %d", product_info->ProdInfoVer );
-	dbg("  IsServer              %d", product_info->IsServer);
-	dbg("  IsRS232               %d", product_info->IsRS232 );
-	dbg("  IsRS422               %d", product_info->IsRS422 );
-	dbg("  IsRS485               %d", product_info->IsRS485 );
-	dbg("  RomSize               %d", product_info->RomSize );
-	dbg("  RamSize               %d", product_info->RamSize );
-	dbg("  CpuRev                %x", product_info->CpuRev  );
-	dbg("  BoardRev              %x", product_info->BoardRev);
-	dbg("  BootMajorVersion      %d.%d.%d", product_info->BootMajorVersion,
-	    product_info->BootMinorVersion,
-	    le16_to_cpu(product_info->BootBuildNumber));
-	dbg("  FirmwareMajorVersion  %d.%d.%d", product_info->FirmwareMajorVersion,
-	    product_info->FirmwareMinorVersion,
-	    le16_to_cpu(product_info->FirmwareBuildNumber));
-	dbg("  ManufactureDescDate   %d/%d/%d", product_info->ManufactureDescDate[0],
-	    product_info->ManufactureDescDate[1],
-	    product_info->ManufactureDescDate[2]+1900);
-	dbg("  iDownloadFile         0x%x",     product_info->iDownloadFile);
+	dump_product_info(product_info);
+}
 
+static int get_epic_descriptor(struct edgeport_serial *ep)
+{
+	int result;
+	struct usb_serial *serial = ep->serial;
+	struct edgeport_product_info *product_info = &ep->product_info;
+	struct edge_compatibility_descriptor *epic = &ep->epic_descriptor;
+	struct edge_compatibility_bits *bits;
+
+	ep->is_epic = 0;
+	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+				 USB_REQUEST_ION_GET_EPIC_DESC,
+				 0xC0, 0x00, 0x00,
+				 &ep->epic_descriptor,
+				 sizeof(struct edge_compatibility_descriptor),
+				 300);
+
+	dbg("%s result = %d", __FUNCTION__, result);
+
+	if (result > 0) {
+		ep->is_epic = 1;
+		memset(product_info, 0, sizeof(struct edgeport_product_info));
+
+		product_info->NumPorts			= epic->NumPorts;
+		product_info->ProdInfoVer		= 0;
+		product_info->FirmwareMajorVersion	= epic->MajorVersion;
+		product_info->FirmwareMinorVersion	= epic->MinorVersion;
+		product_info->FirmwareBuildNumber	= epic->BuildNumber;
+		product_info->iDownloadFile		= epic->iDownloadFile;
+		product_info->EpicVer			= epic->EpicVer;
+		product_info->Epic			= epic->Supports;
+		product_info->ProductId			= ION_DEVICE_ID_EDGEPORT_COMPATIBLE;
+		dump_product_info(product_info);
+
+		bits = &ep->epic_descriptor.Supports;
+		dbg("**EPIC descriptor:");
+		dbg("  VendEnableSuspend: %s", bits->VendEnableSuspend	? "TRUE": "FALSE");
+		dbg("  IOSPOpen         : %s", bits->IOSPOpen		? "TRUE": "FALSE" );
+		dbg("  IOSPClose        : %s", bits->IOSPClose		? "TRUE": "FALSE" );
+		dbg("  IOSPChase        : %s", bits->IOSPChase		? "TRUE": "FALSE" );
+		dbg("  IOSPSetRxFlow    : %s", bits->IOSPSetRxFlow	? "TRUE": "FALSE" );
+		dbg("  IOSPSetTxFlow    : %s", bits->IOSPSetTxFlow	? "TRUE": "FALSE" );
+		dbg("  IOSPSetXChar     : %s", bits->IOSPSetXChar	? "TRUE": "FALSE" );
+		dbg("  IOSPRxCheck      : %s", bits->IOSPRxCheck	? "TRUE": "FALSE" );
+		dbg("  IOSPSetClrBreak  : %s", bits->IOSPSetClrBreak	? "TRUE": "FALSE" );
+		dbg("  IOSPWriteMCR     : %s", bits->IOSPWriteMCR	? "TRUE": "FALSE" );
+		dbg("  IOSPWriteLCR     : %s", bits->IOSPWriteLCR	? "TRUE": "FALSE" );
+		dbg("  IOSPSetBaudRate  : %s", bits->IOSPSetBaudRate	? "TRUE": "FALSE" );
+		dbg("  TrueEdgeport     : %s", bits->TrueEdgeport	? "TRUE": "FALSE" );
+	}
+
+	return result;
 }
 
 
@@ -1017,21 +1070,29 @@
 
 	edge_port->closePending = TRUE;
 
-	/* flush and chase */
-	edge_port->chaseResponsePending = TRUE;
+	if ((!edge_serial->is_epic) ||
+	    ((edge_serial->is_epic) &&
+	     (edge_serial->epic_descriptor.Supports.IOSPChase))) {
+		/* flush and chase */
+		edge_port->chaseResponsePending = TRUE;
 
-	dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
-	status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
-	if (status == 0) {
-		// block until chase finished
-		block_until_chase_response(edge_port);
-	} else {
-		edge_port->chaseResponsePending = FALSE;
+		dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
+		status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+		if (status == 0) {
+			// block until chase finished
+			block_until_chase_response(edge_port);
+		} else {
+			edge_port->chaseResponsePending = FALSE;
+		}
 	}
 
-	/* close the port */
-	dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__);
-	send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
+	if ((!edge_serial->is_epic) ||
+	    ((edge_serial->is_epic) &&
+	     (edge_serial->epic_descriptor.Supports.IOSPClose))) {
+	       /* close the port */
+		dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__);
+		send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
+	}
 
 	//port->close = TRUE;
 	edge_port->closePending = FALSE;
@@ -1694,29 +1755,38 @@
 static void edge_break (struct usb_serial_port *port, int break_state)
 {
 	struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+	struct edgeport_serial *edge_serial = usb_get_serial_data(port->serial);
 	int status;
 
-	/* flush and chase */
-	edge_port->chaseResponsePending = TRUE;
+	if ((!edge_serial->is_epic) ||
+	    ((edge_serial->is_epic) &&
+	     (edge_serial->epic_descriptor.Supports.IOSPChase))) {
+		/* flush and chase */
+		edge_port->chaseResponsePending = TRUE;
 
-	dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
-	status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
-	if (status == 0) {
-		// block until chase finished
-		block_until_chase_response(edge_port);
-	} else {
-		edge_port->chaseResponsePending = FALSE;
+		dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
+		status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+		if (status == 0) {
+			// block until chase finished
+			block_until_chase_response(edge_port);
+		} else {
+			edge_port->chaseResponsePending = FALSE;
+		}
 	}
 
-	if (break_state == -1) {
-		dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__);
-		status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0);
-	} else {
-		dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__);
-		status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0);
-	}
-	if (status) {
-		dbg("%s - error sending break set/clear command.", __FUNCTION__);
+	if ((!edge_serial->is_epic) ||
+	    ((edge_serial->is_epic) &&
+	     (edge_serial->epic_descriptor.Supports.IOSPSetClrBreak))) {
+		if (break_state == -1) {
+			dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__);
+			status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0);
+		} else {
+			dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__);
+			status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0);
+		}
+		if (status) {
+			dbg("%s - error sending break set/clear command.", __FUNCTION__);
+		}
 	}
 
 	return;
@@ -2288,6 +2358,7 @@
  *****************************************************************************/
 static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate)
 {
+	struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
 	unsigned char *cmdBuffer;
 	unsigned char *currCmd;
 	int cmdLen = 0;
@@ -2295,6 +2366,14 @@
 	int status;
 	unsigned char number = edge_port->port->number - edge_port->port->serial->minor;
 
+	if ((!edge_serial->is_epic) ||
+	    ((edge_serial->is_epic) &&
+	     (!edge_serial->epic_descriptor.Supports.IOSPSetBaudRate))) {
+		dbg("SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d",
+		    edge_port->port->number, baudRate);
+		return 0;
+	}
+
 	dbg("%s - port = %d, baud = %d", __FUNCTION__, edge_port->port->number, baudRate);
 
 	status = calc_baud_rate_divisor (baudRate, &divisor);
@@ -2374,6 +2453,7 @@
  *****************************************************************************/
 static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue)
 {
+	struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
 	unsigned char *cmdBuffer;
 	unsigned char *currCmd;
 	unsigned long cmdLen = 0;
@@ -2381,6 +2461,22 @@
 
 	dbg("%s - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", __FUNCTION__, regValue);
 
+	if ((!edge_serial->is_epic) ||
+	    ((edge_serial->is_epic) &&
+	     (!edge_serial->epic_descriptor.Supports.IOSPWriteMCR) &&
+	     (regNum == MCR))) {
+		dbg("SendCmdWriteUartReg - Not writting to MCR Register");
+		return 0;
+	}
+
+	if ((!edge_serial->is_epic) ||
+	    ((edge_serial->is_epic) &&
+	     (!edge_serial->epic_descriptor.Supports.IOSPWriteLCR) &&
+	     (regNum == LCR))) {
+		dbg ("SendCmdWriteUartReg - Not writting to LCR Register");
+		return 0;
+	}
+
 	// Alloc memory for the string of commands.
 	cmdBuffer = kmalloc (0x10, GFP_ATOMIC);
 	if (cmdBuffer == NULL ) {
@@ -2414,6 +2510,7 @@
 #endif
 static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios)
 {
+	struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
 	struct tty_struct *tty;
 	int baud;
 	unsigned cflag;
@@ -2494,8 +2591,12 @@
 		unsigned char stop_char  = STOP_CHAR(tty);
 		unsigned char start_char = START_CHAR(tty);
 
-		send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
-		send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
+		if ((!edge_serial->is_epic) ||
+		    ((edge_serial->is_epic) &&
+		     (edge_serial->epic_descriptor.Supports.IOSPSetXChar))) {
+			send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
+			send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
+		}
 
 		/* if we are implementing INBOUND XON/XOFF */
 		if (I_IXOFF(tty)) {
@@ -2515,8 +2616,14 @@
 	}
 
 	/* Set flow control to the configured value */
-	send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow);
-	send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_TX_FLOW, txFlow);
+	if ((!edge_serial->is_epic) ||
+	    ((edge_serial->is_epic) &&
+	     (edge_serial->epic_descriptor.Supports.IOSPSetRxFlow)))
+		send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow);
+	if ((!edge_serial->is_epic) ||
+	    ((edge_serial->is_epic) &&
+	     (edge_serial->epic_descriptor.Supports.IOSPSetTxFlow)))
+		send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_TX_FLOW, txFlow);
 
 
 	edge_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
@@ -2728,6 +2835,13 @@
 	struct edgeport_port *edge_port;
 	struct usb_device *dev;
 	int i, j;
+	int response;
+	int interrupt_in_found;
+	int bulk_in_found;
+	int bulk_out_found;
+	static __u32 descriptor[3] = {	EDGE_COMPATIBILITY_MASK0,
+					EDGE_COMPATIBILITY_MASK1,
+					EDGE_COMPATIBILITY_MASK2 };
 
 	dev = serial->dev;
 
@@ -2750,38 +2864,50 @@
 
 	dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name);
 
-	/* get the manufacturing descriptor for this device */
-	get_manufacturing_desc (edge_serial);
+	/* Read the epic descriptor */
+	if (get_epic_descriptor(edge_serial) <= 0) {
+		/* memcpy descriptor to Supports structures */
+		memcpy(&edge_serial->epic_descriptor.Supports, descriptor,
+		       sizeof(struct edge_compatibility_bits));
 
-	/* get the boot descriptor */
-	get_boot_desc (edge_serial);
+		/* get the manufacturing descriptor for this device */
+		get_manufacturing_desc (edge_serial);
 
-	get_product_info(edge_serial);
+		/* get the boot descriptor */
+		get_boot_desc (edge_serial);
+
+		get_product_info(edge_serial);
+	}
 
 	/* set the number of ports from the manufacturing description */
 	/* serial->num_ports = serial->product_info.NumPorts; */
-	if (edge_serial->product_info.NumPorts != serial->num_ports) {
-		warn("%s - Device Reported %d serial ports vs core "
-		     "thinking we have %d ports, email greg@kroah.com this info.",
-		     __FUNCTION__, edge_serial->product_info.NumPorts, 
-		     serial->num_ports);
+	if ((!edge_serial->is_epic) &&
+	    (edge_serial->product_info.NumPorts != serial->num_ports)) {
+		dev_warn(&serial->dev->dev, "Device Reported %d serial ports "
+			 "vs. core thinking we have %d ports, email "
+			 "greg@kroah.com this information.",
+			 edge_serial->product_info.NumPorts,
+			 serial->num_ports);
 	}
 
 	dbg("%s - time 1 %ld", __FUNCTION__, jiffies);
 
-	/* now load the application firmware into this device */
-	load_application_firmware (edge_serial);
+	/* If not an EPiC device */
+	if (!edge_serial->is_epic) {
+		/* now load the application firmware into this device */
+		load_application_firmware (edge_serial);
 
-	dbg("%s - time 2 %ld", __FUNCTION__, jiffies);
+		dbg("%s - time 2 %ld", __FUNCTION__, jiffies);
 
-	/* Check current Edgeport EEPROM and update if necessary */
-	update_edgeport_E2PROM (edge_serial);
-	
-	dbg("%s - time 3 %ld", __FUNCTION__, jiffies);
+		/* Check current Edgeport EEPROM and update if necessary */
+		update_edgeport_E2PROM (edge_serial);
 
-	/* set the configuration to use #1 */
-//	dbg("set_configuration 1");
-//	usb_set_configuration (dev, 1);
+		dbg("%s - time 3 %ld", __FUNCTION__, jiffies);
+
+		/* set the configuration to use #1 */
+//		dbg("set_configuration 1");
+//		usb_set_configuration (dev, 1);
+	}
 
 	/* we set up the pointers to the endpoints in the edge_open function, 
 	 * as the structures aren't created yet. */
@@ -2804,8 +2930,101 @@
 		edge_port->port = serial->port[i];
 		usb_set_serial_port_data(serial->port[i], edge_port);
 	}
-	
-	return 0;
+
+	response = 0;
+
+	if (edge_serial->is_epic) {
+		/* EPIC thing, set up our interrupt polling now and our read urb, so
+		 * that the device knows it really is connected. */
+		interrupt_in_found = bulk_in_found = bulk_out_found = FALSE;
+		for (i = 0; i < serial->interface->altsetting[0].desc.bNumEndpoints; ++i) {
+			struct usb_endpoint_descriptor *endpoint;
+			int buffer_size;
+
+			endpoint = &serial->interface->altsetting[0].endpoint[i].desc;
+			buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+			if ((!interrupt_in_found) &&
+			    (usb_endpoint_is_int_in(endpoint))) {
+				/* we found a interrupt in endpoint */
+				dbg("found interrupt in");
+
+				/* not set up yet, so do it now */
+				edge_serial->interrupt_read_urb = usb_alloc_urb(0, GFP_KERNEL);
+				if (!edge_serial->interrupt_read_urb) {
+					err("out of memory");
+					return -ENOMEM;
+				}
+				edge_serial->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+				if (!edge_serial->interrupt_in_buffer) {
+					err("out of memory");
+					usb_free_urb(edge_serial->interrupt_read_urb);
+					return -ENOMEM;
+				}
+				edge_serial->interrupt_in_endpoint = endpoint->bEndpointAddress;
+
+				/* set up our interrupt urb */
+				usb_fill_int_urb(edge_serial->interrupt_read_urb,
+						 dev,
+						 usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+						 edge_serial->interrupt_in_buffer,
+						 buffer_size,
+						 edge_interrupt_callback,
+						 edge_serial,
+						 endpoint->bInterval);
+
+				interrupt_in_found = TRUE;
+			}
+
+			if ((!bulk_in_found) &&
+			    (usb_endpoint_is_bulk_in(endpoint))) {
+				/* we found a bulk in endpoint */
+				dbg("found bulk in");
+
+				/* not set up yet, so do it now */
+				edge_serial->read_urb = usb_alloc_urb(0, GFP_KERNEL);
+				if (!edge_serial->read_urb) {
+					err("out of memory");
+					return -ENOMEM;
+				}
+				edge_serial->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+				if (!edge_serial->bulk_in_buffer) {
+					err ("out of memory");
+					usb_free_urb(edge_serial->read_urb);
+					return -ENOMEM;
+				}
+				edge_serial->bulk_in_endpoint = endpoint->bEndpointAddress;
+
+				/* set up our bulk in urb */
+				usb_fill_bulk_urb(edge_serial->read_urb, dev,
+						  usb_rcvbulkpipe(dev, endpoint->bEndpointAddress),
+						  edge_serial->bulk_in_buffer,
+						  endpoint->wMaxPacketSize,
+						  edge_bulk_in_callback,
+						  edge_serial);
+				bulk_in_found = TRUE;
+			}
+
+			if ((!bulk_out_found) &&
+			    (usb_endpoint_is_bulk_out(endpoint))) {
+				/* we found a bulk out endpoint */
+				dbg("found bulk out");
+				edge_serial->bulk_out_endpoint = endpoint->bEndpointAddress;
+				bulk_out_found = TRUE;
+			}
+		}
+
+		if ((!interrupt_in_found) || (!bulk_in_found) || (!bulk_out_found)) {
+			err ("Error - the proper endpoints were not found!");
+			return -ENODEV;
+		}
+
+		/* start interrupt read for this edgeport this interrupt will
+		 * continue as long as the edgeport is connected */
+		response = usb_submit_urb(edge_serial->interrupt_read_urb, GFP_KERNEL);
+		if (response)
+			err("%s - Error %d submitting control urb", __FUNCTION__, response);
+	}
+	return response;
 }
 
 
@@ -2815,6 +3034,7 @@
  ****************************************************************************/
 static void edge_shutdown (struct usb_serial *serial)
 {
+	struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
 	int i;
 
 	dbg("%s", __FUNCTION__);
@@ -2824,7 +3044,18 @@
 		kfree (usb_get_serial_port_data(serial->port[i]));
 		usb_set_serial_port_data(serial->port[i],  NULL);
 	}
-	kfree (usb_get_serial_data(serial));
+	/* free up our endpoint stuff */
+	if (edge_serial->is_epic) {
+		usb_unlink_urb(edge_serial->interrupt_read_urb);
+		usb_free_urb(edge_serial->interrupt_read_urb);
+		kfree(edge_serial->interrupt_in_buffer);
+
+		usb_unlink_urb(edge_serial->read_urb);
+		usb_free_urb(edge_serial->read_urb);
+		kfree(edge_serial->bulk_in_buffer);
+	}
+
+	kfree(edge_serial);
 	usb_set_serial_data(serial, NULL);
 }
 
@@ -2846,6 +3077,9 @@
 	retval = usb_serial_register(&edgeport_8port_device);
 	if (retval)
 		goto failed_8port_device_register;
+	retval = usb_serial_register(&epic_device);
+	if (retval)
+		goto failed_epic_device_register;
 	retval = usb_register(&io_driver);
 	if (retval) 
 		goto failed_usb_register;
@@ -2853,6 +3087,8 @@
 	return 0;
 
 failed_usb_register:
+	usb_serial_deregister(&epic_device);
+failed_epic_device_register:
 	usb_serial_deregister(&edgeport_8port_device);
 failed_8port_device_register:
 	usb_serial_deregister(&edgeport_4port_device);
@@ -2873,6 +3109,7 @@
 	usb_serial_deregister (&edgeport_2port_device);
 	usb_serial_deregister (&edgeport_4port_device);
 	usb_serial_deregister (&edgeport_8port_device);
+	usb_serial_deregister (&epic_device);
 }
 
 module_init(edgeport_init);
diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h
index 123fa8a..29a913a 100644
--- a/drivers/usb/serial/io_edgeport.h
+++ b/drivers/usb/serial/io_edgeport.h
@@ -111,10 +111,12 @@
 	__le16	FirmwareBuildNumber;		/*				zzzz (LE format) */
 
 	__u8	ManufactureDescDate[3];		/* MM/DD/YY when descriptor template was compiled */
-	__u8	Unused1[1];			/* Available */
+	__u8	HardwareType;
 
 	__u8	iDownloadFile;			/* What to download to EPiC device */
-	__u8	Unused2[2];			/* Available */
+	__u8	EpicVer;			/* What version of EPiC spec this device supports */
+
+	struct edge_compatibility_bits Epic;
 };
 
 /*
diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h
index fad561c..6d30087 100644
--- a/drivers/usb/serial/io_tables.h
+++ b/drivers/usb/serial/io_tables.h
@@ -47,6 +47,18 @@
 	{ }
 };
 
+static struct usb_device_id Epic_port_id_table [] = {
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) },
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) },
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) },
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) },
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) },
+	{ USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) },
+	{ USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) },
+	{ USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) },
+	{ }
+};
+
 /* Devices that this driver supports */
 static struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_4) },
@@ -70,17 +82,34 @@
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) },
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) },
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) },
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) },
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) },
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) },
+	{ USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) },
+	{ USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) },
+	{ USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) },
 	{ }							/* Terminating entry */
 };
 
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
+static struct usb_driver io_driver = {
+	.name =		"io_edgeport",
+	.probe =	usb_serial_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	id_table_combined,
+	.no_dynamic_id = 	1,
+};
+
 static struct usb_serial_driver edgeport_2port_device = {
 	.driver = {
 		.owner		= THIS_MODULE,
 		.name		= "edgeport_2",
 	},
 	.description		= "Edgeport 2 port adapter",
+	.usb_driver		= &io_driver,
 	.id_table		= edgeport_2port_id_table,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 1,
@@ -111,6 +140,7 @@
 		.name		= "edgeport_4",
 	},
 	.description		= "Edgeport 4 port adapter",
+	.usb_driver		= &io_driver,
 	.id_table		= edgeport_4port_id_table,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 1,
@@ -141,6 +171,7 @@
 		.name		= "edgeport_8",
 	},
 	.description		= "Edgeport 8 port adapter",
+	.usb_driver		= &io_driver,
 	.id_table		= edgeport_8port_id_table,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 1,
@@ -165,5 +196,35 @@
 	.write_bulk_callback	= edge_bulk_out_data_callback,
 };
 
+static struct usb_serial_driver epic_device = {
+	.driver = {
+		.owner		= THIS_MODULE,
+		.name		= "epic",
+	},
+	.description		= "EPiC device",
+	.id_table		= Epic_port_id_table,
+	.num_interrupt_in	= 1,
+	.num_bulk_in		= 1,
+	.num_bulk_out		= 1,
+	.num_ports		= 1,
+	.open			= edge_open,
+	.close			= edge_close,
+	.throttle		= edge_throttle,
+	.unthrottle		= edge_unthrottle,
+	.attach			= edge_startup,
+	.shutdown		= edge_shutdown,
+	.ioctl			= edge_ioctl,
+	.set_termios		= edge_set_termios,
+	.tiocmget		= edge_tiocmget,
+	.tiocmset		= edge_tiocmset,
+	.write			= edge_write,
+	.write_room		= edge_write_room,
+	.chars_in_buffer	= edge_chars_in_buffer,
+	.break_ctl		= edge_break,
+	.read_int_callback	= edge_interrupt_callback,
+	.read_bulk_callback	= edge_bulk_in_callback,
+	.write_bulk_callback	= edge_bulk_out_data_callback,
+};
+
 #endif
 
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 980285c..544098d 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -2979,6 +2979,7 @@
 		.name		= "edgeport_ti_1",
 	},
 	.description		= "Edgeport TI 1 port adapter",
+	.usb_driver		= &io_driver,
 	.id_table		= edgeport_1port_id_table,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 1,
@@ -3009,6 +3010,7 @@
 		.name		= "edgeport_ti_2",
 	},
 	.description		= "Edgeport TI 2 port adapter",
+	.usb_driver		= &io_driver,
 	.id_table		= edgeport_2port_id_table,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 2,
diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h
index f1804fd..e57fa11 100644
--- a/drivers/usb/serial/io_usbvend.h
+++ b/drivers/usb/serial/io_usbvend.h
@@ -30,6 +30,7 @@
 
 #define	USB_VENDOR_ID_ION	0x1608		// Our VID
 #define	USB_VENDOR_ID_TI	0x0451		// TI VID
+#define USB_VENDOR_ID_AXIOHM	0x05D9		/* Axiohm VID */
 
 //
 // Definitions of USB product IDs (PID)
@@ -334,6 +335,10 @@
 
 };
 
+#define EDGE_COMPATIBILITY_MASK0	0x0001
+#define EDGE_COMPATIBILITY_MASK1	0x3FFF
+#define EDGE_COMPATIBILITY_MASK2	0x0001
+
 struct edge_compatibility_descriptor
 {
 	__u8	Length;				// Descriptor Length (per USB spec)
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 42f757a..a408184 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -563,6 +563,7 @@
 		.name =		"ipaq",
 	},
 	.description =		"PocketPC PDA",
+	.usb_driver = 		&ipaq_driver,
 	.id_table =		ipaq_id_table,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		1,
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index d3b9a35..1bc5860 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -442,6 +442,7 @@
 		.name =		"ipw",
 	},
 	.description =		"IPWireless converter",
+	.usb_driver = 		&usb_ipw_driver,
 	.id_table =		usb_ipw_ids,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		1,
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 8fdf486..9d847f6 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -138,6 +138,7 @@
 		.name =		"ir-usb",
 	},
 	.description =		"IR Dongle",
+	.usb_driver = 		&ir_driver,
 	.id_table =		id_table,
 	.num_interrupt_in =	1,
 	.num_bulk_in =		1,
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 9d2fdfd..e6966f1 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -1275,11 +1275,31 @@
 }
 
 /* Helper functions used by keyspan_setup_urbs */
+static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
+						     int endpoint)
+{
+	struct usb_host_interface *iface_desc;
+	struct usb_endpoint_descriptor *ep;
+	int i;
+
+	iface_desc = serial->interface->cur_altsetting;
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+		ep = &iface_desc->endpoint[i].desc;
+		if (ep->bEndpointAddress == endpoint)
+			return ep;
+	}
+	dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
+		 "endpoint %x\n", endpoint);
+	return NULL;
+}
+
 static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
 				      int dir, void *ctx, char *buf, int len,
 				      void (*callback)(struct urb *))
 {
 	struct urb *urb;
+	struct usb_endpoint_descriptor const *ep_desc;
+	char const *ep_type_name;
 
 	if (endpoint == -1)
 		return NULL;		/* endpoint not needed */
@@ -1291,11 +1311,32 @@
 		return NULL;
 	}
 
-		/* Fill URB using supplied data. */
-	usb_fill_bulk_urb(urb, serial->dev,
-		      usb_sndbulkpipe(serial->dev, endpoint) | dir,
-		      buf, len, callback, ctx);
+	ep_desc = find_ep(serial, endpoint);
+	if (!ep_desc) {
+		/* leak the urb, something's wrong and the callers don't care */
+		return urb;
+	}
+	if (usb_endpoint_xfer_int(ep_desc)) {
+		ep_type_name = "INT";
+		usb_fill_int_urb(urb, serial->dev,
+				 usb_sndintpipe(serial->dev, endpoint) | dir,
+				 buf, len, callback, ctx,
+				 ep_desc->bInterval);
+	} else if (usb_endpoint_xfer_bulk(ep_desc)) {
+		ep_type_name = "BULK";
+		usb_fill_bulk_urb(urb, serial->dev,
+				  usb_sndbulkpipe(serial->dev, endpoint) | dir,
+				  buf, len, callback, ctx);
+	} else {
+		dev_warn(&serial->interface->dev,
+			 "unsupported endpoint type %x\n",
+			 ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+		usb_free_urb(urb);
+		return NULL;
+	}
 
+	dbg("%s - using urb %p for %s endpoint %x",
+	    __func__, urb, ep_type_name, endpoint);
 	return urb;
 }
 
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index 6413d73..c6830cb 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -229,7 +229,6 @@
 #define	keyspan_usa28_product_id		0x010f
 #define	keyspan_usa28x_product_id		0x0110
 #define	keyspan_usa28xa_product_id		0x0115
-#define	keyspan_usa28xb_product_id		0x0110
 #define	keyspan_usa49w_product_id		0x010a
 #define	keyspan_usa49wlc_product_id		0x012a
 
@@ -511,7 +510,6 @@
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
-	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)},
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
 	{ } /* Terminating entry */
@@ -559,7 +557,6 @@
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
-	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
 	{ } /* Terminating entry */
 };
 
@@ -576,6 +573,7 @@
 		.name		= "keyspan_no_firm",
 	},
 	.description		= "Keyspan - (without firmware)",
+	.usb_driver		= &keyspan_driver,
 	.id_table		= keyspan_pre_ids,
 	.num_interrupt_in	= NUM_DONT_CARE,
 	.num_bulk_in		= NUM_DONT_CARE,
@@ -590,6 +588,7 @@
 		.name		= "keyspan_1",
 	},
 	.description		= "Keyspan 1 port adapter",
+	.usb_driver		= &keyspan_driver,
 	.id_table		= keyspan_1port_ids,
 	.num_interrupt_in	= NUM_DONT_CARE,
 	.num_bulk_in		= NUM_DONT_CARE,
@@ -617,6 +616,7 @@
 		.name		= "keyspan_2",
 	},
 	.description		= "Keyspan 2 port adapter",
+	.usb_driver		= &keyspan_driver,
 	.id_table		= keyspan_2port_ids,
 	.num_interrupt_in	= NUM_DONT_CARE,
 	.num_bulk_in		= NUM_DONT_CARE,
@@ -644,6 +644,7 @@
 		.name		= "keyspan_4",
 	},
 	.description		= "Keyspan 4 port adapter",
+	.usb_driver		= &keyspan_driver,
 	.id_table		= keyspan_4port_ids,
 	.num_interrupt_in	= NUM_DONT_CARE,
 	.num_bulk_in		= 5,
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 126b970..da514cb 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -793,6 +793,7 @@
 		.name =		"keyspan_pda_pre",
 	},
 	.description =		"Keyspan PDA - (prerenumeration)",
+	.usb_driver = 		&keyspan_pda_driver,
 	.id_table =		id_table_fake,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
@@ -809,6 +810,7 @@
 		.name =		"xircom_no_firm",
 	},
 	.description =		"Xircom / Entregra PGS - (prerenumeration)",
+	.usb_driver = 		&keyspan_pda_driver,
 	.id_table =		id_table_fake_xircom,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
@@ -824,6 +826,7 @@
 		.name =		"keyspan_pda",
 	},
 	.description =		"Keyspan PDA",
+	.usb_driver = 		&keyspan_pda_driver,
 	.id_table =		id_table_std,
 	.num_interrupt_in =	1,
 	.num_bulk_in =		0,
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 5c4b06a..b2097c4 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -124,6 +124,7 @@
 		.name =		"kl5kusb105d",
 	},
 	.description =	     "KL5KUSB105D / PalmConnect",
+	.usb_driver =	     &kl5kusb105d_driver,
 	.id_table =	     id_table,
 	.num_interrupt_in =  1,
 	.num_bulk_in =	     1,
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 62bea0c..0683b51 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -110,6 +110,7 @@
 		.name =		"kobil",
 	},
 	.description =		"KOBIL USB smart card terminal",
+	.usb_driver = 		&kobil_driver,
 	.id_table =		id_table,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		0,
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 38b1d17..4cd839b 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -137,6 +137,7 @@
 		.name =		"mct_u232",
 	},
 	.description =	     "MCT U232",
+	.usb_driver = 	     &mct_u232_driver,
 	.id_table =	     id_table_combined,
 	.num_interrupt_in =  2,
 	.num_bulk_in =	     0,
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index e55f4ed..6109c67 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -1605,12 +1605,21 @@
 	usb_set_serial_data(serial, NULL);
 }
 
+static struct usb_driver usb_driver = {
+	.name =		"moschip7720",
+	.probe =	usb_serial_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	moschip_port_id_table,
+	.no_dynamic_id =	1,
+};
+
 static struct usb_serial_driver moschip7720_2port_driver = {
 	.driver = {
 		.owner =	THIS_MODULE,
 		.name =		"moschip7720",
 	},
 	.description		= "Moschip 2 port adapter",
+	.usb_driver		= &usb_driver,
 	.id_table		= moschip_port_id_table,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 2,
@@ -1631,13 +1640,6 @@
 	.read_bulk_callback	= mos7720_bulk_in_callback,
 };
 
-static struct usb_driver usb_driver = {
-	.name =		"moschip7720",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	moschip_port_id_table,
-};
-
 static int __init moschip7720_init(void)
 {
 	int retval;
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 83f6614..b2264a8 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -2834,12 +2834,21 @@
 
 }
 
+static struct usb_driver io_driver = {
+	.name = "mos7840",
+	.probe = usb_serial_probe,
+	.disconnect = usb_serial_disconnect,
+	.id_table = moschip_id_table_combined,
+	.no_dynamic_id = 1,
+};
+
 static struct usb_serial_driver moschip7840_4port_device = {
 	.driver = {
 		   .owner = THIS_MODULE,
 		   .name = "mos7840",
 		   },
 	.description = DRIVER_DESC,
+	.usb_driver = &io_driver,
 	.id_table = moschip_port_id_table,
 	.num_interrupt_in = 1,	//NUM_DONT_CARE,//1,
 #ifdef check
@@ -2869,13 +2878,6 @@
 	.read_int_callback = mos7840_interrupt_callback,
 };
 
-static struct usb_driver io_driver = {
-	.name = "mos7840",
-	.probe = usb_serial_probe,
-	.disconnect = usb_serial_disconnect,
-	.id_table = moschip_id_table_combined,
-};
-
 /****************************************************************************
  * moschip7840_init
  *	This is called by the module subsystem, or on startup to initialize us
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index 054abee..9070111 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -119,6 +119,7 @@
 		.name =		"navman",
 	},
 	.id_table =		id_table,
+	.usb_driver =		&navman_driver,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index bc91d3b..0216ac1 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -93,6 +93,7 @@
 		.name =		"omninet",
 	},
 	.description =		"ZyXEL - omni.net lcd plus usb",
+	.usb_driver =		&omninet_driver,
 	.id_table =		id_table,
 	.num_interrupt_in =	1,
 	.num_bulk_in =		1,
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 0fed43a..ced9f32 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -135,6 +135,7 @@
 		.name =		"option1",
 	},
 	.description       = "GSM modem (1-port)",
+	.usb_driver        = &option_driver,
 	.id_table          = option_ids1,
 	.num_interrupt_in  = NUM_DONT_CARE,
 	.num_bulk_in       = NUM_DONT_CARE,
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 5dc2ac9..6c083d4 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -1118,6 +1118,7 @@
 		.name =		"pl2303",
 	},
 	.id_table =		id_table,
+	.usb_driver = 		&pl2303_driver,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		1,
 	.num_bulk_out =		1,
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 30b7ebc..5a03a3f 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -402,6 +402,7 @@
 		.name =		"safe_serial",
 	},
 	.id_table =		id_table,
+	.usb_driver =		&safe_driver,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 6d8e91e..ecedd83 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -13,10 +13,9 @@
   Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
   Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
 
-  History:
 */
 
-#define DRIVER_VERSION "v.1.0.5"
+#define DRIVER_VERSION "v.1.0.6"
 #define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
 #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
 
@@ -31,14 +30,15 @@
 
 
 static struct usb_device_id id_table [] = {
-	{ USB_DEVICE(0x1199, 0x0018) },	/* Sierra Wireless MC5720 */
-	{ USB_DEVICE(0x1199, 0x0020) },	/* Sierra Wireless MC5725 */
 	{ USB_DEVICE(0x1199, 0x0017) },	/* Sierra Wireless EM5625 */
-	{ USB_DEVICE(0x1199, 0x0019) },	/* Sierra Wireless AirCard 595 */
+	{ USB_DEVICE(0x1199, 0x0018) },	/* Sierra Wireless MC5720 */
 	{ USB_DEVICE(0x1199, 0x0218) },	/* Sierra Wireless MC5720 */
+	{ USB_DEVICE(0x1199, 0x0020) },	/* Sierra Wireless MC5725 */
+	{ USB_DEVICE(0x1199, 0x0019) },	/* Sierra Wireless AirCard 595 */
+	{ USB_DEVICE(0x1199, 0x0021) },	/* Sierra Wireless AirCard 597E */
 	{ USB_DEVICE(0x1199, 0x6802) },	/* Sierra Wireless MC8755 */
+	{ USB_DEVICE(0x1199, 0x6804) },	/* Sierra Wireless MC8755 */
 	{ USB_DEVICE(0x1199, 0x6803) },	/* Sierra Wireless MC8765 */
-	{ USB_DEVICE(0x1199, 0x6804) },	/* Sierra Wireless MC8755 for Europe */
 	{ USB_DEVICE(0x1199, 0x6812) },	/* Sierra Wireless MC8775 */
 	{ USB_DEVICE(0x1199, 0x6820) },	/* Sierra Wireless AirCard 875 */
 
@@ -55,14 +55,15 @@
 };
 
 static struct usb_device_id id_table_3port [] = {
-	{ USB_DEVICE(0x1199, 0x0018) },	/* Sierra Wireless MC5720 */
-	{ USB_DEVICE(0x1199, 0x0020) },	/* Sierra Wireless MC5725 */
 	{ USB_DEVICE(0x1199, 0x0017) },	/* Sierra Wireless EM5625 */
-	{ USB_DEVICE(0x1199, 0x0019) },	/* Sierra Wireless AirCard 595 */
+	{ USB_DEVICE(0x1199, 0x0018) },	/* Sierra Wireless MC5720 */
 	{ USB_DEVICE(0x1199, 0x0218) },	/* Sierra Wireless MC5720 */
+	{ USB_DEVICE(0x1199, 0x0020) },	/* Sierra Wireless MC5725 */
+	{ USB_DEVICE(0x1199, 0x0019) },	/* Sierra Wireless AirCard 595 */
+	{ USB_DEVICE(0x1199, 0x0021) },	/* Sierra Wireless AirCard 597E */
 	{ USB_DEVICE(0x1199, 0x6802) },	/* Sierra Wireless MC8755 */
+	{ USB_DEVICE(0x1199, 0x6804) },	/* Sierra Wireless MC8755 */
 	{ USB_DEVICE(0x1199, 0x6803) },	/* Sierra Wireless MC8765 */
-	{ USB_DEVICE(0x1199, 0x6804) },	/* Sierra Wireless MC8755 for Europe */
 	{ USB_DEVICE(0x1199, 0x6812) },	/* Sierra Wireless MC8775 */
 	{ USB_DEVICE(0x1199, 0x6820) },	/* Sierra Wireless AirCard 875 */
 	{ }
@@ -81,7 +82,7 @@
 
 /* per port private data */
 #define N_IN_URB	4
-#define N_OUT_URB	1
+#define N_OUT_URB	4
 #define IN_BUFLEN	4096
 #define OUT_BUFLEN	128
 
@@ -396,6 +397,8 @@
 	struct usb_serial *serial = port->serial;
 	int i, err;
 	struct urb *urb;
+	int result;
+	__u16 set_mode_dzero = 0x0000;
 
 	portdata = usb_get_serial_port_data(port);
 
@@ -442,6 +445,12 @@
 
 	port->tty->low_latency = 1;
 
+	/* set mode to D0 */
+	result = usb_control_msg(serial->dev,
+				 usb_rcvctrlpipe(serial->dev, 0),
+				 0x00, 0x40, set_mode_dzero, 0, NULL,
+				 0, USB_CTRL_SET_TIMEOUT);
+
 	sierra_send_setup(port);
 
 	return (0);
@@ -614,6 +623,7 @@
 	},
 	.description       = "Sierra USB modem (1 port)",
 	.id_table          = id_table_1port,
+	.usb_driver        = &sierra_driver,
 	.num_interrupt_in  = NUM_DONT_CARE,
 	.num_bulk_in       = 1,
 	.num_bulk_out      = 1,
@@ -642,6 +652,7 @@
 	},
 	.description       = "Sierra USB modem (3 port)",
 	.id_table          = id_table_3port,
+	.usb_driver        = &sierra_driver,
 	.num_interrupt_in  = NUM_DONT_CARE,
 	.num_bulk_in       = 3,
 	.num_bulk_out      = 3,
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 8318900..4203e2b 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -262,6 +262,7 @@
 		.name		= "ti_usb_3410_5052_1",
 	},
 	.description		= "TI USB 3410 1 port adapter",
+	.usb_driver		= &ti_usb_driver,
 	.id_table		= ti_id_table_3410,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 1,
@@ -292,6 +293,7 @@
 		.name		= "ti_usb_3410_5052_2",
 	},
 	.description		= "TI USB 5052 2 port adapter",
+	.usb_driver		= &ti_usb_driver,
 	.id_table		= ti_id_table_5052,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 2,
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 716f680..6bf22a2 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -59,14 +59,19 @@
 
 static int debug;
 static struct usb_serial *serial_table[SERIAL_TTY_MINORS];	/* initially all NULL */
+static spinlock_t table_lock;
 static LIST_HEAD(usb_serial_driver_list);
 
 struct usb_serial *usb_serial_get_by_index(unsigned index)
 {
-	struct usb_serial *serial = serial_table[index];
+	struct usb_serial *serial;
+
+	spin_lock(&table_lock);
+	serial = serial_table[index];
 
 	if (serial)
 		kref_get(&serial->kref);
+	spin_unlock(&table_lock);
 	return serial;
 }
 
@@ -78,6 +83,7 @@
 	dbg("%s %d", __FUNCTION__, num_ports);
 
 	*minor = 0;
+	spin_lock(&table_lock);
 	for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
 		if (serial_table[i])
 			continue;
@@ -96,8 +102,10 @@
 		dbg("%s - minor base = %d", __FUNCTION__, *minor);
 		for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
 			serial_table[i] = serial;
+		spin_unlock(&table_lock);
 		return serial;
 	}
+	spin_unlock(&table_lock);
 	return NULL;
 }
 
@@ -110,9 +118,11 @@
 	if (serial == NULL)
 		return;
 
+	spin_lock(&table_lock);
 	for (i = 0; i < serial->num_ports; ++i) {
 		serial_table[serial->minor + i] = NULL;
 	}
+	spin_unlock(&table_lock);
 }
 
 static void destroy_serial(struct kref *kref)
@@ -271,7 +281,7 @@
 static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	int retval = -EINVAL;
+	int retval = -ENODEV;
 
 	if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
 		goto exit;
@@ -279,6 +289,7 @@
 	dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
 
 	if (!port->open_count) {
+		retval = -EINVAL;
 		dbg("%s - port not opened", __FUNCTION__);
 		goto exit;
 	}
@@ -559,15 +570,20 @@
 	port_free(port);
 }
 
-static void port_free(struct usb_serial_port *port)
+static void kill_traffic(struct usb_serial_port *port)
 {
 	usb_kill_urb(port->read_urb);
-	usb_free_urb(port->read_urb);
 	usb_kill_urb(port->write_urb);
-	usb_free_urb(port->write_urb);
 	usb_kill_urb(port->interrupt_in_urb);
-	usb_free_urb(port->interrupt_in_urb);
 	usb_kill_urb(port->interrupt_out_urb);
+}
+
+static void port_free(struct usb_serial_port *port)
+{
+	kill_traffic(port);
+	usb_free_urb(port->read_urb);
+	usb_free_urb(port->write_urb);
+	usb_free_urb(port->interrupt_in_urb);
 	usb_free_urb(port->interrupt_out_urb);
 	kfree(port->bulk_in_buffer);
 	kfree(port->bulk_out_buffer);
@@ -596,6 +612,39 @@
 	return serial;
 }
 
+static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
+						    struct usb_serial_driver *drv)
+{
+	struct usb_dynid *dynid;
+
+	spin_lock(&drv->dynids.lock);
+	list_for_each_entry(dynid, &drv->dynids.list, node) {
+		if (usb_match_one_id(intf, &dynid->id)) {
+			spin_unlock(&drv->dynids.lock);
+			return &dynid->id;
+		}
+	}
+	spin_unlock(&drv->dynids.lock);
+	return NULL;
+}
+
+static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
+						struct usb_interface *intf)
+{
+	const struct usb_device_id *id;
+
+	id = usb_match_id(intf, drv->id_table);
+	if (id) {
+		dbg("static descriptor matches");
+		goto exit;
+	}
+	id = match_dynamic_id(intf, drv);
+	if (id)
+		dbg("dynamic descriptor matches");
+exit:
+	return id;
+}
+
 static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
 {
 	struct list_head *p;
@@ -605,11 +654,9 @@
 	/* Check if the usb id matches a known device */
 	list_for_each(p, &usb_serial_driver_list) {
 		t = list_entry(p, struct usb_serial_driver, driver_list);
-		id = usb_match_id(iface, t->id_table);
-		if (id != NULL) {
-			dbg("descriptor matches");
+		id = get_iface_id(t, iface);
+		if (id)
 			return t;
-		}
 	}
 
 	return NULL;
@@ -639,14 +686,17 @@
 	int num_ports = 0;
 	int max_endpoints;
 
+	lock_kernel(); /* guard against unloading a serial driver module */
 	type = search_serial_device(interface);
 	if (!type) {
+		unlock_kernel();
 		dbg("none matched");
 		return -ENODEV;
 	}
 
 	serial = create_serial (dev, interface, type);
 	if (!serial) {
+		unlock_kernel();
 		dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
 		return -ENOMEM;
 	}
@@ -656,16 +706,18 @@
 		const struct usb_device_id *id;
 
 		if (!try_module_get(type->driver.owner)) {
+			unlock_kernel();
 			dev_err(&interface->dev, "module get failed, exiting\n");
 			kfree (serial);
 			return -EIO;
 		}
 
-		id = usb_match_id(interface, type->id_table);
+		id = get_iface_id(type, interface);
 		retval = type->probe(serial, id);
 		module_put(type->driver.owner);
 
 		if (retval) {
+			unlock_kernel();
 			dbg ("sub driver rejected device");
 			kfree (serial);
 			return retval;
@@ -735,6 +787,7 @@
 		 * properly during a later invocation of usb_serial_probe
 		 */
 		if (num_bulk_in == 0 || num_bulk_out == 0) {
+			unlock_kernel();
 			dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
 			kfree (serial);
 			return -ENODEV;
@@ -750,6 +803,7 @@
 	if (type == &usb_serial_generic_device) {
 		num_ports = num_bulk_out;
 		if (num_ports == 0) {
+			unlock_kernel();
 			dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n");
 			kfree (serial);
 			return -EIO;
@@ -760,6 +814,7 @@
 		/* if this device type has a calc_num_ports function, call it */
 		if (type->calc_num_ports) {
 			if (!try_module_get(type->driver.owner)) {
+				unlock_kernel();
 				dev_err(&interface->dev, "module get failed, exiting\n");
 				kfree (serial);
 				return -EIO;
@@ -771,12 +826,6 @@
 			num_ports = type->num_ports;
 	}
 
-	if (get_free_serial (serial, num_ports, &minor) == NULL) {
-		dev_err(&interface->dev, "No more free serial devices\n");
-		kfree (serial);
-		return -ENOMEM;
-	}
-
 	serial->minor = minor;
 	serial->num_ports = num_ports;
 	serial->num_bulk_in = num_bulk_in;
@@ -791,6 +840,8 @@
 	max_endpoints = max(max_endpoints, num_interrupt_out);
 	max_endpoints = max(max_endpoints, (int)serial->num_ports);
 	serial->num_port_pointers = max_endpoints;
+	unlock_kernel();
+
 	dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
 	for (i = 0; i < max_endpoints; ++i) {
 		port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
@@ -925,6 +976,11 @@
 		}
 	}
 
+	if (get_free_serial (serial, num_ports, &minor) == NULL) {
+		dev_err(&interface->dev, "No more free serial devices\n");
+		goto probe_error;
+	}
+
 	/* register all of the individual ports with the driver core */
 	for (i = 0; i < num_ports; ++i) {
 		port = serial->port[i];
@@ -1002,8 +1058,11 @@
 	if (serial) {
 		for (i = 0; i < serial->num_ports; ++i) {
 			port = serial->port[i];
-			if (port && port->tty)
-				tty_hangup(port->tty);
+			if (port) {
+				if (port->tty)
+					tty_hangup(port->tty);
+				kill_traffic(port);
+			}
 		}
 		/* let the last holder of this object 
 		 * cause it to be cleaned up */
@@ -1040,6 +1099,7 @@
 		return -ENOMEM;
 
 	/* Initialize our global data */
+	spin_lock_init(&table_lock);
 	for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
 		serial_table[i] = NULL;
 	}
@@ -1138,7 +1198,7 @@
 	set_to_generic_if_null(device, shutdown);
 }
 
-int usb_serial_register(struct usb_serial_driver *driver)
+int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */
 {
 	int retval;
 
@@ -1162,7 +1222,7 @@
 }
 
 
-void usb_serial_deregister(struct usb_serial_driver *device)
+void usb_serial_deregister(struct usb_serial_driver *device) /* must be called with BKL held */
 {
 	info("USB Serial deregistering driver %s", device->description);
 	list_del(&device->driver_list);
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index b09f060..2f59ff2 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -90,8 +90,6 @@
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID),
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
-	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID),
-		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID),
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID),
@@ -151,7 +149,6 @@
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
-	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
@@ -189,6 +186,7 @@
 		.name =		"visor",
 	},
 	.description =		"Handspring Visor / Palm OS",
+	.usb_driver =		&visor_driver,
 	.id_table =		id_table,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		2,
@@ -219,6 +217,7 @@
 		.name =		"clie_5",
 	},
 	.description =		"Sony Clie 5.0",
+	.usb_driver =		&visor_driver,
 	.id_table =		clie_id_5_table,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		2,
@@ -249,6 +248,7 @@
 		.name =		"clie_3.5",
 	},
 	.description =		"Sony Clie 3.5",
+	.usb_driver =		&visor_driver,
 	.id_table =		clie_id_3_5_table,
 	.num_interrupt_in =	0,
 	.num_bulk_in =		1,
diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
index 765118d..4ce6f62 100644
--- a/drivers/usb/serial/visor.h
+++ b/drivers/usb/serial/visor.h
@@ -32,7 +32,6 @@
 #define PALM_TUNGSTEN_T_ID		0x0060
 #define PALM_TREO_650			0x0061
 #define PALM_TUNGSTEN_Z_ID		0x0031
-#define PALM_ZIRE31_ID			0x0061
 #define PALM_ZIRE_ID			0x0070
 #define PALM_M100_ID			0x0080
 
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 5483d85..bf16e9e 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -161,6 +161,7 @@
 		.name =		"whiteheatnofirm",
 	},
 	.description =		"Connect Tech - WhiteHEAT - (prerenumeration)",
+	.usb_driver =		&whiteheat_driver,
 	.id_table =		id_table_prerenumeration,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
@@ -176,6 +177,7 @@
 		.name =		"whiteheat",
 	},
 	.description =		"Connect Tech - WhiteHEAT",
+	.usb_driver =		&whiteheat_driver,
 	.id_table =		id_table_std,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index e565d3d..6d3dad3 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -33,7 +33,6 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/usb_ch9.h>
 #include <linux/usb/input.h>
 #include "usb.h"
 #include "onetouch.h"
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index e1072d5..70234f5 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -110,23 +110,6 @@
 	 * the end, scatter-gather buffers follow page boundaries. */
 	blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
 
-	/* Set the SCSI level to at least 2.  We'll leave it at 3 if that's
-	 * what is originally reported.  We need this to avoid confusing
-	 * the SCSI layer with devices that report 0 or 1, but need 10-byte
-	 * commands (ala ATAPI devices behind certain bridges, or devices
-	 * which simply have broken INQUIRY data).
-	 *
-	 * NOTE: This means /dev/sg programs (ala cdrecord) will get the
-	 * actual information.  This seems to be the preference for
-	 * programs like that.
-	 *
-	 * NOTE: This also means that /proc/scsi/scsi and sysfs may report
-	 * the actual value or the modified one, depending on where the
-	 * data comes from.
-	 */
-	if (sdev->scsi_level < SCSI_2)
-		sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2;
-
 	/* Many devices have trouble transfering more than 32KB at a time,
 	 * while others have trouble with more than 64K. At this time we
 	 * are limiting both to 32K (64 sectores).
@@ -176,7 +159,9 @@
 		 * a Get-Max-LUN request, we won't lose much by setting the
 		 * revision level down to 2.  The only devices that would be
 		 * affected are those with sparse LUNs. */
-		sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2;
+		if (sdev->scsi_level > SCSI_2)
+			sdev->sdev_target->scsi_level =
+					sdev->scsi_level = SCSI_2;
 
 		/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
 		 * Hardware Error) when any low-level error occurs,
@@ -194,6 +179,16 @@
 		sdev->use_10_for_ms = 1;
 	}
 
+	/* The CB and CBI transports have no way to pass LUN values
+	 * other than the bits in the second byte of a CDB.  But those
+	 * bits don't get set to the LUN value if the device reports
+	 * scsi_level == 0 (UNKNOWN).  Hence such devices must necessarily
+	 * be single-LUN.
+	 */
+	if ((us->protocol == US_PR_CB || us->protocol == US_PR_CBI) &&
+			sdev->scsi_level == SCSI_UNKNOWN)
+		us->max_lun = 0;
+
 	/* Some devices choke when they receive a PREVENT-ALLOW MEDIUM
 	 * REMOVAL command, so suppress those commands. */
 	if (us->flags & US_FL_NOT_LOCKABLE)
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index b49f2a7..f49a62f 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -573,7 +573,7 @@
 #endif
 
 /* Submitted by Olaf Hering, <olh@suse.de> SuSE Bugzilla #49049 */
-UNUSUAL_DEV(  0x054c, 0x002c, 0x0501, 0x0501,
+UNUSUAL_DEV(  0x054c, 0x002c, 0x0501, 0x2000,
 		"Sony",
 		"USB Floppy Drive",
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -1325,13 +1325,6 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_CAPACITY ),
 
-/* Reported by Jan Mate <mate@fiit.stuba.sk> */
-UNUSUAL_DEV(  0x0fce, 0xe030, 0x0000, 0x0000,
-		"Sony Ericsson",
-		"P990i",
-		US_SC_DEVICE, US_PR_DEVICE, NULL,
-		US_FL_FIX_CAPACITY ),
-
 /* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
  * Tested on hardware version 1.10.
  * Entry is needed only for the initializer function override.
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 7064450..7e7ec29 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -731,26 +731,27 @@
 	struct usb_endpoint_descriptor *ep_int = NULL;
 
 	/*
-	 * Find the endpoints we need.
+	 * Find the first endpoint of each type we need.
 	 * We are expecting a minimum of 2 endpoints - in and out (bulk).
-	 * An optional interrupt is OK (necessary for CBI protocol).
+	 * An optional interrupt-in is OK (necessary for CBI protocol).
 	 * We will ignore any others.
 	 */
 	for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
 		ep = &altsetting->endpoint[i].desc;
 
-		/* Is it a BULK endpoint? */
 		if (usb_endpoint_xfer_bulk(ep)) {
-			/* BULK in or out? */
-			if (usb_endpoint_dir_in(ep))
-				ep_in = ep;
-			else
-				ep_out = ep;
+			if (usb_endpoint_dir_in(ep)) {
+				if (!ep_in)
+					ep_in = ep;
+			} else {
+				if (!ep_out)
+					ep_out = ep;
+			}
 		}
 
-		/* Is it an interrupt endpoint? */
-		else if (usb_endpoint_xfer_int(ep)) {
-			ep_int = ep;
+		else if (usb_endpoint_is_int_in(ep)) {
+			if (!ep_int)
+				ep_int = ep;
 		}
 	}
 
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 4e83f01..45fe65d 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1444,8 +1444,8 @@
 	  used mainly in the MIPS-based DECstation series.
 
 config FB_PMAG_BA
-	bool "PMAG-BA TURBOchannel framebuffer support"
-	depends on (FB = y) && TC
+	tristate "PMAG-BA TURBOchannel framebuffer support"
+	depends on FB && TC
  	select FB_CFB_FILLRECT
  	select FB_CFB_COPYAREA
  	select FB_CFB_IMAGEBLIT
@@ -1454,8 +1454,8 @@
 	  used mainly in the MIPS-based DECstation series.
 
 config FB_PMAGB_B
-	bool "PMAGB-B TURBOchannel framebuffer support"
-	depends on (FB = y) && TC
+	tristate "PMAGB-B TURBOchannel framebuffer support"
+	depends on TC
  	select FB_CFB_FILLRECT
  	select FB_CFB_COPYAREA
  	select FB_CFB_IMAGEBLIT
diff --git a/drivers/video/output.c b/drivers/video/output.c
new file mode 100644
index 0000000..1473f2c
--- /dev/null
+++ b/drivers/video/output.c
@@ -0,0 +1,129 @@
+/*
+ *  output.c - Display Output Switch driver
+ *
+ *  Copyright (C) 2006 Luming Yu <luming.yu@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or (at
+ *  your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/module.h>
+#include <linux/video_output.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+
+
+MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Luming Yu <luming.yu@intel.com>");
+
+static ssize_t video_output_show_state(struct class_device *dev,char *buf)
+{
+	ssize_t ret_size = 0;
+	struct output_device *od = to_output_device(dev);
+	if (od->props)
+		ret_size = sprintf(buf,"%.8x\n",od->props->get_status(od));
+	return ret_size;
+}
+
+static ssize_t video_output_store_state(struct class_device *dev,
+	const char *buf,size_t count)
+{
+	char *endp;
+	struct output_device *od = to_output_device(dev);
+	int request_state = simple_strtoul(buf,&endp,0);
+	size_t size = endp - buf;
+
+	if (*endp && isspace(*endp))
+		size++;
+	if (size != count)
+		return -EINVAL;
+
+	if (od->props) {
+		od->request_state = request_state;
+		od->props->set_state(od);
+	}
+	return count;
+}
+
+static void video_output_class_release(struct class_device *dev)
+{
+	struct output_device *od = to_output_device(dev);
+	kfree(od);
+}
+
+static struct class_device_attribute video_output_attributes[] = {
+	__ATTR(state, 0644, video_output_show_state, video_output_store_state),
+	__ATTR_NULL,
+};
+
+static struct class video_output_class = {
+	.name = "video_output",
+	.release = video_output_class_release,
+	.class_dev_attrs = video_output_attributes,
+};
+
+struct output_device *video_output_register(const char *name,
+	struct device *dev,
+	void *devdata,
+	struct output_properties *op)
+{
+	struct output_device *new_dev;
+	int ret_code = 0;
+
+	new_dev = kzalloc(sizeof(struct output_device),GFP_KERNEL);
+	if (!new_dev) {
+		ret_code = -ENOMEM;
+		goto error_return;
+	}
+	new_dev->props = op;
+	new_dev->class_dev.class = &video_output_class;
+	new_dev->class_dev.dev = dev;
+	strlcpy(new_dev->class_dev.class_id,name,KOBJ_NAME_LEN);
+	class_set_devdata(&new_dev->class_dev,devdata);
+	ret_code = class_device_register(&new_dev->class_dev);
+	if (ret_code) {
+		kfree(new_dev);
+		goto error_return;
+	}
+	return new_dev;
+
+error_return:
+	return ERR_PTR(ret_code);
+}
+EXPORT_SYMBOL(video_output_register);
+
+void video_output_unregister(struct output_device *dev)
+{
+	if (!dev)
+		return;
+	class_device_unregister(&dev->class_dev);
+}
+EXPORT_SYMBOL(video_output_unregister);
+
+static void __exit video_output_class_exit(void)
+{
+	class_unregister(&video_output_class);
+}
+
+static int __init video_output_class_init(void)
+{
+	return class_register(&video_output_class);
+}
+
+postcore_initcall(video_output_class_init);
+module_exit(video_output_class_exit);
diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c
index f5361cd..264d372 100644
--- a/drivers/video/pmag-ba-fb.c
+++ b/drivers/video/pmag-ba-fb.c
@@ -15,7 +15,8 @@
  *	Michael Engel <engel@unix-ag.org>,
  *	Karsten Merker <merker@linuxtag.org> and
  *	Harald Koerfgen.
- *	Copyright (c) 2005  Maciej W. Rozycki
+ *	Copyright (c) 2005, 2006  Maciej W. Rozycki
+ *	Copyright (c) 2005  James Simmons
  *
  *	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
@@ -28,26 +29,21 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/tc.h>
 #include <linux/types.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <asm/dec/tc.h>
-
 #include <video/pmag-ba-fb.h>
 
 
 struct pmagbafb_par {
-	struct fb_info *next;
 	volatile void __iomem *mmio;
 	volatile u32 __iomem *dac;
-	int slot;
 };
 
 
-static struct fb_info *root_pmagbafb_dev;
-
 static struct fb_var_screeninfo pmagbafb_defined __initdata = {
 	.xres		= 1024,
 	.yres		= 864,
@@ -145,24 +141,19 @@
 }
 
 
-static int __init pmagbafb_init_one(int slot)
+static int __init pmagbafb_probe(struct device *dev)
 {
+	struct tc_dev *tdev = to_tc_dev(dev);
+	resource_size_t start, len;
 	struct fb_info *info;
 	struct pmagbafb_par *par;
-	unsigned long base_addr;
 
-	info = framebuffer_alloc(sizeof(struct pmagbafb_par), NULL);
+	info = framebuffer_alloc(sizeof(struct pmagbafb_par), dev);
 	if (!info)
 		return -ENOMEM;
 
 	par = info->par;
-	par->slot = slot;
-	claim_tc_card(par->slot);
-
-	base_addr = get_tc_base_addr(par->slot);
-
-	par->next = root_pmagbafb_dev;
-	root_pmagbafb_dev = info;
+	dev_set_drvdata(dev, info);
 
 	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
 		goto err_alloc;
@@ -172,15 +163,21 @@
 	info->var = pmagbafb_defined;
 	info->flags = FBINFO_DEFAULT;
 
+	/* Request the I/O MEM resource.  */
+	start = tdev->resource.start;
+	len = tdev->resource.end - start + 1;
+	if (!request_mem_region(start, len, dev->bus_id))
+		goto err_cmap;
+
 	/* MMIO mapping setup.  */
-	info->fix.mmio_start = base_addr;
+	info->fix.mmio_start = start;
 	par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
 	if (!par->mmio)
-		goto err_cmap;
+		goto err_resource;
 	par->dac = par->mmio + PMAG_BA_BT459;
 
 	/* Frame buffer mapping setup.  */
-	info->fix.smem_start = base_addr + PMAG_BA_FBMEM;
+	info->fix.smem_start = start + PMAG_BA_FBMEM;
 	info->screen_base = ioremap_nocache(info->fix.smem_start,
 					    info->fix.smem_len);
 	if (!info->screen_base)
@@ -192,8 +189,10 @@
 	if (register_framebuffer(info) < 0)
 		goto err_smem_map;
 
-	pr_info("fb%d: %s frame buffer device in slot %d\n",
-		info->node, info->fix.id, par->slot);
+	get_device(dev);
+
+	pr_info("fb%d: %s frame buffer device at %s\n",
+		info->node, info->fix.id, dev->bus_id);
 
 	return 0;
 
@@ -204,54 +203,68 @@
 err_mmio_map:
 	iounmap(par->mmio);
 
+err_resource:
+	release_mem_region(start, len);
+
 err_cmap:
 	fb_dealloc_cmap(&info->cmap);
 
 err_alloc:
-	root_pmagbafb_dev = par->next;
-	release_tc_card(par->slot);
 	framebuffer_release(info);
 	return -ENXIO;
 }
 
-static void __exit pmagbafb_exit_one(void)
+static int __exit pmagbafb_remove(struct device *dev)
 {
-	struct fb_info *info = root_pmagbafb_dev;
+	struct tc_dev *tdev = to_tc_dev(dev);
+	struct fb_info *info = dev_get_drvdata(dev);
 	struct pmagbafb_par *par = info->par;
+	resource_size_t start, len;
 
+	put_device(dev);
 	unregister_framebuffer(info);
 	iounmap(info->screen_base);
 	iounmap(par->mmio);
+	start = tdev->resource.start;
+	len = tdev->resource.end - start + 1;
+	release_mem_region(start, len);
 	fb_dealloc_cmap(&info->cmap);
-	root_pmagbafb_dev = par->next;
-	release_tc_card(par->slot);
 	framebuffer_release(info);
+	return 0;
 }
 
 
 /*
- * Initialise the framebuffer.
+ * Initialize the framebuffer.
  */
+static const struct tc_device_id pmagbafb_tc_table[] = {
+	{ "DEC     ", "PMAG-BA " },
+	{ }
+};
+MODULE_DEVICE_TABLE(tc, pmagbafb_tc_table);
+
+static struct tc_driver pmagbafb_driver = {
+	.id_table	= pmagbafb_tc_table,
+	.driver		= {
+		.name	= "pmagbafb",
+		.bus	= &tc_bus_type,
+		.probe	= pmagbafb_probe,
+		.remove	= __exit_p(pmagbafb_remove),
+	},
+};
+
 static int __init pmagbafb_init(void)
 {
-	int count = 0;
-	int slot;
-
+#ifndef MODULE
 	if (fb_get_options("pmagbafb", NULL))
 		return -ENXIO;
-
-	while ((slot = search_tc_card("PMAG-BA")) >= 0) {
-		if (pmagbafb_init_one(slot) < 0)
-			break;
-		count++;
-	}
-	return (count > 0) ? 0 : -ENXIO;
+#endif
+	return tc_register_driver(&pmagbafb_driver);
 }
 
 static void __exit pmagbafb_exit(void)
 {
-	while (root_pmagbafb_dev)
-		pmagbafb_exit_one();
+	tc_unregister_driver(&pmagbafb_driver);
 }
 
 
diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c
index a06a064..7a0ce7d 100644
--- a/drivers/video/pmagb-b-fb.c
+++ b/drivers/video/pmagb-b-fb.c
@@ -11,7 +11,7 @@
  *	Michael Engel <engel@unix-ag.org>,
  *	Karsten Merker <merker@linuxtag.org> and
  *	Harald Koerfgen.
- *	Copyright (c) 2005  Maciej W. Rozycki
+ *	Copyright (c) 2005, 2006  Maciej W. Rozycki
  *
  *	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
@@ -25,18 +25,16 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/tc.h>
 #include <linux/types.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <asm/dec/tc.h>
-
 #include <video/pmagb-b-fb.h>
 
 
 struct pmagbbfb_par {
-	struct fb_info *next;
 	volatile void __iomem *mmio;
 	volatile void __iomem *smem;
 	volatile u32 __iomem *sfb;
@@ -47,8 +45,6 @@
 };
 
 
-static struct fb_info *root_pmagbbfb_dev;
-
 static struct fb_var_screeninfo pmagbbfb_defined __initdata = {
 	.bits_per_pixel	= 8,
 	.red.length	= 8,
@@ -190,8 +186,9 @@
 		69197, 66000, 65000, 50350, 36000, 32000, 25175
 	};
 	struct pmagbbfb_par *par = info->par;
+	struct tc_bus *tbus = to_tc_dev(info->device)->bus;
 	u32 count0 = 8, count1 = 8, counttc = 16 * 256 + 8;
-	u32 freq0, freq1, freqtc = get_tc_speed() / 250;
+	u32 freq0, freq1, freqtc = tc_get_speed(tbus) / 250;
 	int i, j;
 
 	gp0_write(par, 0);				/* select Osc0 */
@@ -249,26 +246,21 @@
 };
 
 
-static int __init pmagbbfb_init_one(int slot)
+static int __init pmagbbfb_probe(struct device *dev)
 {
-	char freq0[12], freq1[12];
+	struct tc_dev *tdev = to_tc_dev(dev);
+	resource_size_t start, len;
 	struct fb_info *info;
 	struct pmagbbfb_par *par;
-	unsigned long base_addr;
+	char freq0[12], freq1[12];
 	u32 vid_base;
 
-	info = framebuffer_alloc(sizeof(struct pmagbbfb_par), NULL);
+	info = framebuffer_alloc(sizeof(struct pmagbbfb_par), dev);
 	if (!info)
 		return -ENOMEM;
 
 	par = info->par;
-	par->slot = slot;
-	claim_tc_card(par->slot);
-
-	base_addr = get_tc_base_addr(par->slot);
-
-	par->next = root_pmagbbfb_dev;
-	root_pmagbbfb_dev = info;
+	dev_set_drvdata(dev, info);
 
 	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
 		goto err_alloc;
@@ -278,16 +270,22 @@
 	info->var = pmagbbfb_defined;
 	info->flags = FBINFO_DEFAULT;
 
+	/* Request the I/O MEM resource.  */
+	start = tdev->resource.start;
+	len = tdev->resource.end - start + 1;
+	if (!request_mem_region(start, len, dev->bus_id))
+		goto err_cmap;
+
 	/* MMIO mapping setup.  */
-	info->fix.mmio_start = base_addr;
+	info->fix.mmio_start = start;
 	par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
 	if (!par->mmio)
-		goto err_cmap;
+		goto err_resource;
 	par->sfb = par->mmio + PMAGB_B_SFB;
 	par->dac = par->mmio + PMAGB_B_BT459;
 
 	/* Frame buffer mapping setup.  */
-	info->fix.smem_start = base_addr + PMAGB_B_FBMEM;
+	info->fix.smem_start = start + PMAGB_B_FBMEM;
 	par->smem = ioremap_nocache(info->fix.smem_start, info->fix.smem_len);
 	if (!par->smem)
 		goto err_mmio_map;
@@ -302,13 +300,15 @@
 	if (register_framebuffer(info) < 0)
 		goto err_smem_map;
 
+	get_device(dev);
+
 	snprintf(freq0, sizeof(freq0), "%u.%03uMHz",
 		 par->osc0 / 1000, par->osc0 % 1000);
 	snprintf(freq1, sizeof(freq1), "%u.%03uMHz",
 		 par->osc1 / 1000, par->osc1 % 1000);
 
-	pr_info("fb%d: %s frame buffer device in slot %d\n",
-		info->node, info->fix.id, par->slot);
+	pr_info("fb%d: %s frame buffer device at %s\n",
+		info->node, info->fix.id, dev->bus_id);
 	pr_info("fb%d: Osc0: %s, Osc1: %s, Osc%u selected\n",
 		info->node, freq0, par->osc1 ? freq1 : "disabled",
 		par->osc1 != 0);
@@ -322,54 +322,68 @@
 err_mmio_map:
 	iounmap(par->mmio);
 
+err_resource:
+	release_mem_region(start, len);
+
 err_cmap:
 	fb_dealloc_cmap(&info->cmap);
 
 err_alloc:
-	root_pmagbbfb_dev = par->next;
-	release_tc_card(par->slot);
 	framebuffer_release(info);
 	return -ENXIO;
 }
 
-static void __exit pmagbbfb_exit_one(void)
+static int __exit pmagbbfb_remove(struct device *dev)
 {
-	struct fb_info *info = root_pmagbbfb_dev;
+	struct tc_dev *tdev = to_tc_dev(dev);
+	struct fb_info *info = dev_get_drvdata(dev);
 	struct pmagbbfb_par *par = info->par;
+	resource_size_t start, len;
 
+	put_device(dev);
 	unregister_framebuffer(info);
 	iounmap(par->smem);
 	iounmap(par->mmio);
+	start = tdev->resource.start;
+	len = tdev->resource.end - start + 1;
+	release_mem_region(start, len);
 	fb_dealloc_cmap(&info->cmap);
-	root_pmagbbfb_dev = par->next;
-	release_tc_card(par->slot);
 	framebuffer_release(info);
+	return 0;
 }
 
 
 /*
- * Initialise the framebuffer.
+ * Initialize the framebuffer.
  */
+static const struct tc_device_id pmagbbfb_tc_table[] = {
+	{ "DEC     ", "PMAGB-BA" },
+	{ }
+};
+MODULE_DEVICE_TABLE(tc, pmagbbfb_tc_table);
+
+static struct tc_driver pmagbbfb_driver = {
+	.id_table	= pmagbbfb_tc_table,
+	.driver		= {
+		.name	= "pmagbbfb",
+		.bus	= &tc_bus_type,
+		.probe	= pmagbbfb_probe,
+		.remove	= __exit_p(pmagbbfb_remove),
+	},
+};
+
 static int __init pmagbbfb_init(void)
 {
-	int count = 0;
-	int slot;
-
+#ifndef MODULE
 	if (fb_get_options("pmagbbfb", NULL))
 		return -ENXIO;
-
-	while ((slot = search_tc_card("PMAGB-BA")) >= 0) {
-		if (pmagbbfb_init_one(slot) < 0)
-			break;
-		count++;
-	}
-	return (count > 0) ? 0 : -ENXIO;
+#endif
+	return tc_register_driver(&pmagbbfb_driver);
 }
 
 static void __exit pmagbbfb_exit(void)
 {
-	while (root_pmagbbfb_dev)
-		pmagbbfb_exit_one();
+	tc_unregister_driver(&pmagbbfb_driver);
 }
 
 
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 9109ba1..378767c 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -585,17 +585,14 @@
 	if (IS_ERR(inode)) {
 		err = PTR_ERR(inode);
 		inode = NULL;
-		goto clean_up_fids;
+		v9fs_fid_destroy(vfid);
+		goto error;
 	}
 
 	dentry->d_op = &v9fs_dentry_operations;
 	d_instantiate(dentry, inode);
 	return 0;
 
-clean_up_fids:
-	if (vfid)
-		v9fs_fid_destroy(vfid);
-
 clean_up_dfid:
 	v9fs_fid_clunk(v9ses, dfid);
 
diff --git a/fs/Kconfig b/fs/Kconfig
index 8cd2417..5e8e9d9 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -426,7 +426,6 @@
 	select CONFIGFS_FS
 	select JBD
 	select CRC32
-	select INET
 	help
 	  OCFS2 is a general purpose extent based shared disk cluster file
 	  system with many similarities to ext3. It supports 64 bit inode
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index ae8595d..7b0265d 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -419,7 +419,7 @@
 	unsigned long textpos = 0, datapos = 0, result;
 	unsigned long realdatastart = 0;
 	unsigned long text_len, data_len, bss_len, stack_len, flags;
-	unsigned long memp = 0; /* for finding the brk area */
+	unsigned long len, reallen, memp = 0;
 	unsigned long extra, rlim;
 	unsigned long *reloc = 0, *rp;
 	struct inode *inode;
@@ -540,10 +540,18 @@
 			goto err;
 		}
 
+		len = data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
 		down_write(&current->mm->mmap_sem);
-		realdatastart = do_mmap(0, 0, data_len + extra +
-				MAX_SHARED_LIBS * sizeof(unsigned long),
-				PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0);
+		realdatastart = do_mmap(0, 0, len,
+			PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0);
+		/* Remap to use all availabe slack region space */
+		if (realdatastart && (realdatastart < (unsigned long)-4096)) {
+			reallen = ksize(realdatastart);
+			if (reallen > len) {
+				realdatastart = do_mremap(realdatastart, len,
+					reallen, MREMAP_FIXED, realdatastart);
+			}
+		}
 		up_write(&current->mm->mmap_sem);
 
 		if (realdatastart == 0 || realdatastart >= (unsigned long)-4096) {
@@ -584,11 +592,20 @@
 
 	} else {
 
+		len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
 		down_write(&current->mm->mmap_sem);
-		textpos = do_mmap(0, 0, text_len + data_len + extra +
-					MAX_SHARED_LIBS * sizeof(unsigned long),
-				PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
+		textpos = do_mmap(0, 0, len,
+			PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
+		/* Remap to use all availabe slack region space */
+		if (textpos && (textpos < (unsigned long) -4096)) {
+			reallen = ksize(textpos);
+			if (reallen > len) {
+				textpos = do_mremap(textpos, len, reallen,
+					MREMAP_FIXED, textpos);
+			}
+		}
 		up_write(&current->mm->mmap_sem);
+
 		if (!textpos  || textpos >= (unsigned long) -4096) {
 			if (!textpos)
 				textpos = (unsigned long) -ENOMEM;
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index d04d2f7..85e3850 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,6 +1,8 @@
 Version 1.47
 ------------
 Fix oops in list_del during mount caused by unaligned string.
+Seek to SEEK_END forces check for update of file size for non-cached
+files.
 
 Version 1.46
 ------------
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 10c9029..93ef099 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -511,7 +511,15 @@
 {
 	/* origin == SEEK_END => we must revalidate the cached file length */
 	if (origin == SEEK_END) {
-		int retval = cifs_revalidate(file->f_path.dentry);
+		int retval;
+
+		/* some applications poll for the file length in this strange
+		   way so we must seek to end on non-oplocked files by
+		   setting the revalidate time to zero */
+		if(file->f_path.dentry->d_inode)		
+			CIFS_I(file->f_path.dentry->d_inode)->time = 0;
+
+		retval = cifs_revalidate(file->f_path.dentry);
 		if (retval < 0)
 			return (loff_t)retval;
 	}
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 8a49b2e..e9dcf5e 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1146,7 +1146,7 @@
 	pgoff_t end;
 	pgoff_t index;
  	int range_whole = 0;
-	struct kvec iov[32];
+	struct kvec * iov;
 	int len;
 	int n_iov = 0;
 	pgoff_t next;
@@ -1171,15 +1171,21 @@
 	if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
 		if(cifs_sb->tcon->ses->server->secMode &
                           (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-			if(!experimEnabled)
+			if(!experimEnabled) 
 				return generic_writepages(mapping, wbc);
 
+	iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
+	if(iov == NULL)
+		return generic_writepages(mapping, wbc);
+
+
 	/*
 	 * BB: Is this meaningful for a non-block-device file system?
 	 * If it is, we should test it again after we do I/O
 	 */
 	if (wbc->nonblocking && bdi_write_congested(bdi)) {
 		wbc->encountered_congestion = 1;
+		kfree(iov);
 		return 0;
 	}
 
@@ -1345,7 +1351,7 @@
 		mapping->writeback_index = index;
 
 	FreeXid(xid);
-
+	kfree(iov);
 	return rc;
 }
 
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 99dfb53..782940b 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -156,9 +156,9 @@
 		tmp_inode->i_atime = cnvrtDosUnixTm(
 				le16_to_cpu(pfindData->LastAccessDate),
 				le16_to_cpu(pfindData->LastAccessTime));
-                tmp_inode->i_ctime = cnvrtDosUnixTm(
-                                le16_to_cpu(pfindData->LastWriteDate),
-                                le16_to_cpu(pfindData->LastWriteTime));
+		tmp_inode->i_ctime = cnvrtDosUnixTm(
+				le16_to_cpu(pfindData->LastWriteDate),
+				le16_to_cpu(pfindData->LastWriteTime));
 		AdjustForTZ(cifs_sb->tcon, tmp_inode);
 		attr = le16_to_cpu(pfindData->Attributes);
 		allocation_size = le32_to_cpu(pfindData->AllocationSize);
diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c
index 7a1b2b9..1b1daf6 100644
--- a/fs/cifs/smbdes.c
+++ b/fs/cifs/smbdes.c
@@ -196,7 +196,7 @@
 	char c[28];
 	char d[28];
 	char *cd;
-	char ki[16][48];
+	char (*ki)[48];
 	char *pd1;
 	char l[32], r[32];
 	char *rl;
@@ -206,6 +206,12 @@
 	if(pk1 == NULL)
 		return;
 
+	ki = kmalloc(16*48, GFP_KERNEL);
+	if(ki == NULL) {
+		kfree(pk1);
+		return;
+	}
+
 	cd = pk1 + 56;
 	pd1= cd  + 56;
 	rl = pd1 + 64;
@@ -243,6 +249,7 @@
 		er = kmalloc(48+48+32+32+32, GFP_KERNEL);
 		if(er == NULL) {
 			kfree(pk1);
+			kfree(ki);
 			return;
 		}
 		erk = er+48;
@@ -290,6 +297,7 @@
 
 	permute(out, rl, perm6, 64);
 	kfree(pk1);
+	kfree(ki);
 }
 
 static void
diff --git a/fs/configfs/file.c b/fs/configfs/file.c
index 2a7cb08..d98be5e 100644
--- a/fs/configfs/file.c
+++ b/fs/configfs/file.c
@@ -162,14 +162,17 @@
 	int error;
 
 	if (!buffer->page)
-		buffer->page = (char *)get_zeroed_page(GFP_KERNEL);
+		buffer->page = (char *)__get_free_pages(GFP_KERNEL, 0);
 	if (!buffer->page)
 		return -ENOMEM;
 
-	if (count > PAGE_SIZE)
-		count = PAGE_SIZE;
+	if (count >= PAGE_SIZE)
+		count = PAGE_SIZE - 1;
 	error = copy_from_user(buffer->page,buf,count);
 	buffer->needs_read_fill = 1;
+	/* if buf is assumed to contain a string, terminate it by \0,
+	 * so e.g. sscanf() can scan the string easily */
+	buffer->page[count] = 0;
 	return error ? -EFAULT : count;
 }
 
diff --git a/fs/dlm/Kconfig b/fs/dlm/Kconfig
index b5654a2..6fa7b0d 100644
--- a/fs/dlm/Kconfig
+++ b/fs/dlm/Kconfig
@@ -3,21 +3,21 @@
 
 config DLM
 	tristate "Distributed Lock Manager (DLM)"
-	depends on IPV6 || IPV6=n
+	depends on SYSFS && (IPV6 || IPV6=n)
 	select CONFIGFS_FS
 	select IP_SCTP if DLM_SCTP
 	help
-	A general purpose distributed lock manager for kernel or userspace
-	applications.
+	  A general purpose distributed lock manager for kernel or userspace
+	  applications.
 
 choice
 	prompt "Select DLM communications protocol"
 	depends on DLM
 	default DLM_TCP
 	help
-	The DLM Can use TCP or SCTP for it's network communications.
-	SCTP supports multi-homed operations whereas TCP doesn't.
-	However, SCTP seems to have stability problems at the moment.
+	  The DLM Can use TCP or SCTP for it's network communications.
+	  SCTP supports multi-homed operations whereas TCP doesn't.
+	  However, SCTP seems to have stability problems at the moment.
 
 config DLM_TCP
 	bool "TCP/IP"
@@ -31,8 +31,8 @@
 	bool "DLM debugging"
 	depends on DLM
 	help
-	Under the debugfs mount point, the name of each lockspace will
-	appear as a file in the "dlm" directory.  The output is the
-	list of resource and locks the local node knows about.
+	  Under the debugfs mount point, the name of each lockspace will
+	  appear as a file in the "dlm" directory.  The output is the
+	  list of resource and locks the local node knows about.
 
 endmenu
diff --git a/fs/dlm/config.c b/fs/dlm/config.c
index 88553054..8665c88 100644
--- a/fs/dlm/config.c
+++ b/fs/dlm/config.c
@@ -54,6 +54,11 @@
 static void drop_node(struct config_group *, struct config_item *);
 static void release_node(struct config_item *);
 
+static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a,
+			    char *buf);
+static ssize_t store_cluster(struct config_item *i,
+			     struct configfs_attribute *a,
+			     const char *buf, size_t len);
 static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,
 			 char *buf);
 static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a,
@@ -73,6 +78,101 @@
 static ssize_t node_weight_read(struct node *nd, char *buf);
 static ssize_t node_weight_write(struct node *nd, const char *buf, size_t len);
 
+struct cluster {
+	struct config_group group;
+	unsigned int cl_tcp_port;
+	unsigned int cl_buffer_size;
+	unsigned int cl_rsbtbl_size;
+	unsigned int cl_lkbtbl_size;
+	unsigned int cl_dirtbl_size;
+	unsigned int cl_recover_timer;
+	unsigned int cl_toss_secs;
+	unsigned int cl_scan_secs;
+	unsigned int cl_log_debug;
+};
+
+enum {
+	CLUSTER_ATTR_TCP_PORT = 0,
+	CLUSTER_ATTR_BUFFER_SIZE,
+	CLUSTER_ATTR_RSBTBL_SIZE,
+	CLUSTER_ATTR_LKBTBL_SIZE,
+	CLUSTER_ATTR_DIRTBL_SIZE,
+	CLUSTER_ATTR_RECOVER_TIMER,
+	CLUSTER_ATTR_TOSS_SECS,
+	CLUSTER_ATTR_SCAN_SECS,
+	CLUSTER_ATTR_LOG_DEBUG,
+};
+
+struct cluster_attribute {
+	struct configfs_attribute attr;
+	ssize_t (*show)(struct cluster *, char *);
+	ssize_t (*store)(struct cluster *, const char *, size_t);
+};
+
+static ssize_t cluster_set(struct cluster *cl, unsigned int *cl_field,
+			   unsigned int *info_field, int check_zero,
+			   const char *buf, size_t len)
+{
+	unsigned int x;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	x = simple_strtoul(buf, NULL, 0);
+
+	if (check_zero && !x)
+		return -EINVAL;
+
+	*cl_field = x;
+	*info_field = x;
+
+	return len;
+}
+
+#define __CONFIGFS_ATTR(_name,_mode,_read,_write) {                           \
+	.attr   = { .ca_name = __stringify(_name),                            \
+		    .ca_mode = _mode,                                         \
+		    .ca_owner = THIS_MODULE },                                \
+	.show   = _read,                                                      \
+	.store  = _write,                                                     \
+}
+
+#define CLUSTER_ATTR(name, check_zero)                                        \
+static ssize_t name##_write(struct cluster *cl, const char *buf, size_t len)  \
+{                                                                             \
+	return cluster_set(cl, &cl->cl_##name, &dlm_config.ci_##name,         \
+			   check_zero, buf, len);                             \
+}                                                                             \
+static ssize_t name##_read(struct cluster *cl, char *buf)                     \
+{                                                                             \
+	return snprintf(buf, PAGE_SIZE, "%u\n", cl->cl_##name);               \
+}                                                                             \
+static struct cluster_attribute cluster_attr_##name =                         \
+__CONFIGFS_ATTR(name, 0644, name##_read, name##_write)
+
+CLUSTER_ATTR(tcp_port, 1);
+CLUSTER_ATTR(buffer_size, 1);
+CLUSTER_ATTR(rsbtbl_size, 1);
+CLUSTER_ATTR(lkbtbl_size, 1);
+CLUSTER_ATTR(dirtbl_size, 1);
+CLUSTER_ATTR(recover_timer, 1);
+CLUSTER_ATTR(toss_secs, 1);
+CLUSTER_ATTR(scan_secs, 1);
+CLUSTER_ATTR(log_debug, 0);
+
+static struct configfs_attribute *cluster_attrs[] = {
+	[CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port.attr,
+	[CLUSTER_ATTR_BUFFER_SIZE] = &cluster_attr_buffer_size.attr,
+	[CLUSTER_ATTR_RSBTBL_SIZE] = &cluster_attr_rsbtbl_size.attr,
+	[CLUSTER_ATTR_LKBTBL_SIZE] = &cluster_attr_lkbtbl_size.attr,
+	[CLUSTER_ATTR_DIRTBL_SIZE] = &cluster_attr_dirtbl_size.attr,
+	[CLUSTER_ATTR_RECOVER_TIMER] = &cluster_attr_recover_timer.attr,
+	[CLUSTER_ATTR_TOSS_SECS] = &cluster_attr_toss_secs.attr,
+	[CLUSTER_ATTR_SCAN_SECS] = &cluster_attr_scan_secs.attr,
+	[CLUSTER_ATTR_LOG_DEBUG] = &cluster_attr_log_debug.attr,
+	NULL,
+};
+
 enum {
 	COMM_ATTR_NODEID = 0,
 	COMM_ATTR_LOCAL,
@@ -152,10 +252,6 @@
 	struct configfs_subsystem subsys;
 };
 
-struct cluster {
-	struct config_group group;
-};
-
 struct spaces {
 	struct config_group ss_group;
 };
@@ -197,6 +293,8 @@
 
 static struct configfs_item_operations cluster_ops = {
 	.release = release_cluster,
+	.show_attribute = show_cluster,
+	.store_attribute = store_cluster,
 };
 
 static struct configfs_group_operations spaces_ops = {
@@ -237,6 +335,7 @@
 
 static struct config_item_type cluster_type = {
 	.ct_item_ops = &cluster_ops,
+	.ct_attrs = cluster_attrs,
 	.ct_owner = THIS_MODULE,
 };
 
@@ -317,6 +416,16 @@
 	cl->group.default_groups[1] = &cms->cs_group;
 	cl->group.default_groups[2] = NULL;
 
+	cl->cl_tcp_port = dlm_config.ci_tcp_port;
+	cl->cl_buffer_size = dlm_config.ci_buffer_size;
+	cl->cl_rsbtbl_size = dlm_config.ci_rsbtbl_size;
+	cl->cl_lkbtbl_size = dlm_config.ci_lkbtbl_size;
+	cl->cl_dirtbl_size = dlm_config.ci_dirtbl_size;
+	cl->cl_recover_timer = dlm_config.ci_recover_timer;
+	cl->cl_toss_secs = dlm_config.ci_toss_secs;
+	cl->cl_scan_secs = dlm_config.ci_scan_secs;
+	cl->cl_log_debug = dlm_config.ci_log_debug;
+
 	space_list = &sps->ss_group;
 	comm_list = &cms->cs_group;
 	return &cl->group;
@@ -509,6 +618,25 @@
  * Functions for user space to read/write attributes
  */
 
+static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a,
+			    char *buf)
+{
+	struct cluster *cl = to_cluster(i);
+	struct cluster_attribute *cla =
+			container_of(a, struct cluster_attribute, attr);
+	return cla->show ? cla->show(cl, buf) : 0;
+}
+
+static ssize_t store_cluster(struct config_item *i,
+			     struct configfs_attribute *a,
+			     const char *buf, size_t len)
+{
+	struct cluster *cl = to_cluster(i);
+	struct cluster_attribute *cla =
+		container_of(a, struct cluster_attribute, attr);
+	return cla->store ? cla->store(cl, buf, len) : -EINVAL;
+}
+
 static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,
 			 char *buf)
 {
@@ -775,15 +903,17 @@
 #define DEFAULT_RECOVER_TIMER      5
 #define DEFAULT_TOSS_SECS         10
 #define DEFAULT_SCAN_SECS          5
+#define DEFAULT_LOG_DEBUG          0
 
 struct dlm_config_info dlm_config = {
-	.tcp_port = DEFAULT_TCP_PORT,
-	.buffer_size = DEFAULT_BUFFER_SIZE,
-	.rsbtbl_size = DEFAULT_RSBTBL_SIZE,
-	.lkbtbl_size = DEFAULT_LKBTBL_SIZE,
-	.dirtbl_size = DEFAULT_DIRTBL_SIZE,
-	.recover_timer = DEFAULT_RECOVER_TIMER,
-	.toss_secs = DEFAULT_TOSS_SECS,
-	.scan_secs = DEFAULT_SCAN_SECS
+	.ci_tcp_port = DEFAULT_TCP_PORT,
+	.ci_buffer_size = DEFAULT_BUFFER_SIZE,
+	.ci_rsbtbl_size = DEFAULT_RSBTBL_SIZE,
+	.ci_lkbtbl_size = DEFAULT_LKBTBL_SIZE,
+	.ci_dirtbl_size = DEFAULT_DIRTBL_SIZE,
+	.ci_recover_timer = DEFAULT_RECOVER_TIMER,
+	.ci_toss_secs = DEFAULT_TOSS_SECS,
+	.ci_scan_secs = DEFAULT_SCAN_SECS,
+	.ci_log_debug = DEFAULT_LOG_DEBUG
 };
 
diff --git a/fs/dlm/config.h b/fs/dlm/config.h
index 9da7839..1e97861 100644
--- a/fs/dlm/config.h
+++ b/fs/dlm/config.h
@@ -17,14 +17,15 @@
 #define DLM_MAX_ADDR_COUNT 3
 
 struct dlm_config_info {
-	int tcp_port;
-	int buffer_size;
-	int rsbtbl_size;
-	int lkbtbl_size;
-	int dirtbl_size;
-	int recover_timer;
-	int toss_secs;
-	int scan_secs;
+	int ci_tcp_port;
+	int ci_buffer_size;
+	int ci_rsbtbl_size;
+	int ci_lkbtbl_size;
+	int ci_dirtbl_size;
+	int ci_recover_timer;
+	int ci_toss_secs;
+	int ci_scan_secs;
+	int ci_log_debug;
 };
 
 extern struct dlm_config_info dlm_config;
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
index 1ee8195..61d9320 100644
--- a/fs/dlm/dlm_internal.h
+++ b/fs/dlm/dlm_internal.h
@@ -41,6 +41,7 @@
 #include <asm/uaccess.h>
 
 #include <linux/dlm.h>
+#include "config.h"
 
 #define DLM_LOCKSPACE_LEN	64
 
@@ -69,12 +70,12 @@
 #define log_error(ls, fmt, args...) \
 	printk(KERN_ERR "dlm: %s: " fmt "\n", (ls)->ls_name , ##args)
 
-#define DLM_LOG_DEBUG
-#ifdef DLM_LOG_DEBUG
-#define log_debug(ls, fmt, args...) log_error(ls, fmt, ##args)
-#else
-#define log_debug(ls, fmt, args...)
-#endif
+#define log_debug(ls, fmt, args...) \
+do { \
+	if (dlm_config.ci_log_debug) \
+		printk(KERN_DEBUG "dlm: %s: " fmt "\n", \
+		       (ls)->ls_name , ##args); \
+} while (0)
 
 #define DLM_ASSERT(x, do) \
 { \
@@ -309,8 +310,8 @@
 
 /* dlm_header is first element of all structs sent between nodes */
 
-#define DLM_HEADER_MAJOR	0x00020000
-#define DLM_HEADER_MINOR	0x00000001
+#define DLM_HEADER_MAJOR	0x00030000
+#define DLM_HEADER_MINOR	0x00000000
 
 #define DLM_MSG			1
 #define DLM_RCOM		2
@@ -386,6 +387,8 @@
 	uint32_t		rc_type;	/* DLM_RCOM_ */
 	int			rc_result;	/* multi-purpose */
 	uint64_t		rc_id;		/* match reply with request */
+	uint64_t		rc_seq;		/* sender's ls_recover_seq */
+	uint64_t		rc_seq_reply;	/* remote ls_recover_seq */
 	char			rc_buf[0];
 };
 
@@ -523,6 +526,7 @@
 	spinlock_t		asts_spin;
 	struct list_head	locks;
 	spinlock_t		locks_spin;
+	struct list_head	unlocking;
 	wait_queue_head_t	wait;
 };
 
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
index 30878de..e725005 100644
--- a/fs/dlm/lock.c
+++ b/fs/dlm/lock.c
@@ -754,6 +754,11 @@
 	mutex_unlock(&ls->ls_waiters_mutex);
 }
 
+/* We clear the RESEND flag because we might be taking an lkb off the waiters
+   list as part of process_requestqueue (e.g. a lookup that has an optimized
+   request reply on the requestqueue) between dlm_recover_waiters_pre() which
+   set RESEND and dlm_recover_waiters_post() */
+
 static int _remove_from_waiters(struct dlm_lkb *lkb)
 {
 	int error = 0;
@@ -764,6 +769,7 @@
 		goto out;
 	}
 	lkb->lkb_wait_type = 0;
+	lkb->lkb_flags &= ~DLM_IFL_RESEND;
 	list_del(&lkb->lkb_wait_reply);
 	unhold_lkb(lkb);
  out:
@@ -810,7 +816,7 @@
 		list_for_each_entry_reverse(r, &ls->ls_rsbtbl[b].toss,
 					    res_hashchain) {
 			if (!time_after_eq(jiffies, r->res_toss_time +
-					   dlm_config.toss_secs * HZ))
+					   dlm_config.ci_toss_secs * HZ))
 				continue;
 			found = 1;
 			break;
@@ -2144,12 +2150,24 @@
 	if (lkb->lkb_astaddr)
 		ms->m_asts |= AST_COMP;
 
-	if (ms->m_type == DLM_MSG_REQUEST || ms->m_type == DLM_MSG_LOOKUP)
+	/* compare with switch in create_message; send_remove() doesn't
+	   use send_args() */
+
+	switch (ms->m_type) {
+	case DLM_MSG_REQUEST:
+	case DLM_MSG_LOOKUP:
 		memcpy(ms->m_extra, r->res_name, r->res_length);
-
-	else if (lkb->lkb_lvbptr)
+		break;
+	case DLM_MSG_CONVERT:
+	case DLM_MSG_UNLOCK:
+	case DLM_MSG_REQUEST_REPLY:
+	case DLM_MSG_CONVERT_REPLY:
+	case DLM_MSG_GRANT:
+		if (!lkb->lkb_lvbptr)
+			break;
 		memcpy(ms->m_extra, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);
-
+		break;
+	}
 }
 
 static int send_common(struct dlm_rsb *r, struct dlm_lkb *lkb, int mstype)
@@ -2418,8 +2436,12 @@
 
 	DLM_ASSERT(is_master_copy(lkb), dlm_print_lkb(lkb););
 
-	if (receive_lvb(ls, lkb, ms))
-		return -ENOMEM;
+	if (lkb->lkb_exflags & DLM_LKF_VALBLK) {
+		/* lkb was just created so there won't be an lvb yet */
+		lkb->lkb_lvbptr = allocate_lvb(ls);
+		if (!lkb->lkb_lvbptr)
+			return -ENOMEM;
+	}
 
 	return 0;
 }
@@ -3002,7 +3024,7 @@
 {
 	struct dlm_message *ms = (struct dlm_message *) hd;
 	struct dlm_ls *ls;
-	int error;
+	int error = 0;
 
 	if (!recovery)
 		dlm_message_in(ms);
@@ -3119,7 +3141,7 @@
  out:
 	dlm_put_lockspace(ls);
 	dlm_astd_wake();
-	return 0;
+	return error;
 }
 
 
@@ -3132,6 +3154,7 @@
 	if (middle_conversion(lkb)) {
 		hold_lkb(lkb);
 		ls->ls_stub_ms.m_result = -EINPROGRESS;
+		ls->ls_stub_ms.m_flags = lkb->lkb_flags;
 		_remove_from_waiters(lkb);
 		_receive_convert_reply(lkb, &ls->ls_stub_ms);
 
@@ -3205,6 +3228,7 @@
 		case DLM_MSG_UNLOCK:
 			hold_lkb(lkb);
 			ls->ls_stub_ms.m_result = -DLM_EUNLOCK;
+			ls->ls_stub_ms.m_flags = lkb->lkb_flags;
 			_remove_from_waiters(lkb);
 			_receive_unlock_reply(lkb, &ls->ls_stub_ms);
 			dlm_put_lkb(lkb);
@@ -3213,6 +3237,7 @@
 		case DLM_MSG_CANCEL:
 			hold_lkb(lkb);
 			ls->ls_stub_ms.m_result = -DLM_ECANCEL;
+			ls->ls_stub_ms.m_flags = lkb->lkb_flags;
 			_remove_from_waiters(lkb);
 			_receive_cancel_reply(lkb, &ls->ls_stub_ms);
 			dlm_put_lkb(lkb);
@@ -3571,6 +3596,14 @@
 	lock_rsb(r);
 
 	switch (error) {
+	case -EBADR:
+		/* There's a chance the new master received our lock before
+		   dlm_recover_master_reply(), this wouldn't happen if we did
+		   a barrier between recover_masters and recover_locks. */
+		log_debug(ls, "master copy not ready %x r %lx %s", lkb->lkb_id,
+			  (unsigned long)r, r->res_name);
+		dlm_send_rcom_lock(r, lkb);
+		goto out;
 	case -EEXIST:
 		log_debug(ls, "master copy exists %x", lkb->lkb_id);
 		/* fall through */
@@ -3585,7 +3618,7 @@
 	/* an ack for dlm_recover_locks() which waits for replies from
 	   all the locks it sends to new masters */
 	dlm_recovered_lock(r);
-
+ out:
 	unlock_rsb(r);
 	put_rsb(r);
 	dlm_put_lkb(lkb);
@@ -3610,7 +3643,7 @@
 	}
 
 	if (flags & DLM_LKF_VALBLK) {
-		ua->lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
+		ua->lksb.sb_lvbptr = kzalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
 		if (!ua->lksb.sb_lvbptr) {
 			kfree(ua);
 			__put_lkb(ls, lkb);
@@ -3679,7 +3712,7 @@
 	ua = (struct dlm_user_args *)lkb->lkb_astparam;
 
 	if (flags & DLM_LKF_VALBLK && !ua->lksb.sb_lvbptr) {
-		ua->lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
+		ua->lksb.sb_lvbptr = kzalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
 		if (!ua->lksb.sb_lvbptr) {
 			error = -ENOMEM;
 			goto out_put;
@@ -3745,12 +3778,10 @@
 		goto out_put;
 
 	spin_lock(&ua->proc->locks_spin);
-	list_del_init(&lkb->lkb_ownqueue);
+	/* dlm_user_add_ast() may have already taken lkb off the proc list */
+	if (!list_empty(&lkb->lkb_ownqueue))
+		list_move(&lkb->lkb_ownqueue, &ua->proc->unlocking);
 	spin_unlock(&ua->proc->locks_spin);
-
-	/* this removes the reference for the proc->locks list added by
-	   dlm_user_request */
-	unhold_lkb(lkb);
  out_put:
 	dlm_put_lkb(lkb);
  out:
@@ -3790,9 +3821,8 @@
 	/* this lkb was removed from the WAITING queue */
 	if (lkb->lkb_grmode == DLM_LOCK_IV) {
 		spin_lock(&ua->proc->locks_spin);
-		list_del_init(&lkb->lkb_ownqueue);
+		list_move(&lkb->lkb_ownqueue, &ua->proc->unlocking);
 		spin_unlock(&ua->proc->locks_spin);
-		unhold_lkb(lkb);
 	}
  out_put:
 	dlm_put_lkb(lkb);
@@ -3853,11 +3883,6 @@
 	mutex_lock(&ls->ls_clear_proc_locks);
 
 	list_for_each_entry_safe(lkb, safe, &proc->locks, lkb_ownqueue) {
-		if (lkb->lkb_ast_type) {
-			list_del(&lkb->lkb_astqueue);
-			unhold_lkb(lkb);
-		}
-
 		list_del_init(&lkb->lkb_ownqueue);
 
 		if (lkb->lkb_exflags & DLM_LKF_PERSISTENT) {
@@ -3874,6 +3899,20 @@
 
 		dlm_put_lkb(lkb);
 	}
+
+	/* in-progress unlocks */
+	list_for_each_entry_safe(lkb, safe, &proc->unlocking, lkb_ownqueue) {
+		list_del_init(&lkb->lkb_ownqueue);
+		lkb->lkb_flags |= DLM_IFL_DEAD;
+		dlm_put_lkb(lkb);
+	}
+
+	list_for_each_entry_safe(lkb, safe, &proc->asts, lkb_astqueue) {
+		list_del(&lkb->lkb_astqueue);
+		dlm_put_lkb(lkb);
+	}
+
 	mutex_unlock(&ls->ls_clear_proc_locks);
 	unlock_recovery(ls);
 }
+
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
index 59012b0..f40817b 100644
--- a/fs/dlm/lockspace.c
+++ b/fs/dlm/lockspace.c
@@ -236,7 +236,7 @@
 	while (!kthread_should_stop()) {
 		list_for_each_entry(ls, &lslist, ls_list)
 			dlm_scan_rsbs(ls);
-		schedule_timeout_interruptible(dlm_config.scan_secs * HZ);
+		schedule_timeout_interruptible(dlm_config.ci_scan_secs * HZ);
 	}
 	return 0;
 }
@@ -422,7 +422,7 @@
 	ls->ls_count = 0;
 	ls->ls_flags = 0;
 
-	size = dlm_config.rsbtbl_size;
+	size = dlm_config.ci_rsbtbl_size;
 	ls->ls_rsbtbl_size = size;
 
 	ls->ls_rsbtbl = kmalloc(sizeof(struct dlm_rsbtable) * size, GFP_KERNEL);
@@ -434,7 +434,7 @@
 		rwlock_init(&ls->ls_rsbtbl[i].lock);
 	}
 
-	size = dlm_config.lkbtbl_size;
+	size = dlm_config.ci_lkbtbl_size;
 	ls->ls_lkbtbl_size = size;
 
 	ls->ls_lkbtbl = kmalloc(sizeof(struct dlm_lkbtable) * size, GFP_KERNEL);
@@ -446,7 +446,7 @@
 		ls->ls_lkbtbl[i].counter = 1;
 	}
 
-	size = dlm_config.dirtbl_size;
+	size = dlm_config.ci_dirtbl_size;
 	ls->ls_dirtbl_size = size;
 
 	ls->ls_dirtbl = kmalloc(sizeof(struct dlm_dirtable) * size, GFP_KERNEL);
@@ -489,7 +489,7 @@
 	mutex_init(&ls->ls_requestqueue_mutex);
 	mutex_init(&ls->ls_clear_proc_locks);
 
-	ls->ls_recover_buf = kmalloc(dlm_config.buffer_size, GFP_KERNEL);
+	ls->ls_recover_buf = kmalloc(dlm_config.ci_buffer_size, GFP_KERNEL);
 	if (!ls->ls_recover_buf)
 		goto out_dirfree;
 
diff --git a/fs/dlm/lowcomms-sctp.c b/fs/dlm/lowcomms-sctp.c
index fe158d7..dc83a9d 100644
--- a/fs/dlm/lowcomms-sctp.c
+++ b/fs/dlm/lowcomms-sctp.c
@@ -72,6 +72,8 @@
 	struct list_head	writequeue; /* outgoing writequeue_entries */
 	spinlock_t		writequeue_lock;
 	int			nodeid;
+	struct work_struct      swork; /* Send workqueue */
+	struct work_struct      lwork; /* Locking workqueue */
 };
 
 static DEFINE_IDR(nodeinfo_idr);
@@ -96,6 +98,7 @@
 	atomic_t		waiting_requests;
 	struct cbuf		cb;
 	int                     eagain_flag;
+	struct work_struct      work; /* Send workqueue */
 };
 
 /* An entry waiting to be sent */
@@ -137,19 +140,23 @@
 static LIST_HEAD(write_nodes);
 static DEFINE_SPINLOCK(write_nodes_lock);
 
+
 /* Maximum number of incoming messages to process before
  * doing a schedule()
  */
 #define MAX_RX_MSG_COUNT 25
 
-/* Manage daemons */
-static struct task_struct *recv_task;
-static struct task_struct *send_task;
-static DECLARE_WAIT_QUEUE_HEAD(lowcomms_recv_wait);
+/* Work queues */
+static struct workqueue_struct *recv_workqueue;
+static struct workqueue_struct *send_workqueue;
+static struct workqueue_struct *lock_workqueue;
 
 /* The SCTP connection */
 static struct connection sctp_con;
 
+static void process_send_sockets(struct work_struct *work);
+static void process_recv_sockets(struct work_struct *work);
+static void process_lock_request(struct work_struct *work);
 
 static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr)
 {
@@ -222,6 +229,8 @@
 	spin_lock_init(&ni->lock);
 	INIT_LIST_HEAD(&ni->writequeue);
 	spin_lock_init(&ni->writequeue_lock);
+	INIT_WORK(&ni->lwork, process_lock_request);
+	INIT_WORK(&ni->swork, process_send_sockets);
 	ni->nodeid = nodeid;
 
 	if (nodeid > max_nodeid)
@@ -249,11 +258,8 @@
 /* Data or notification available on socket */
 static void lowcomms_data_ready(struct sock *sk, int count_unused)
 {
-	atomic_inc(&sctp_con.waiting_requests);
 	if (test_and_set_bit(CF_READ_PENDING, &sctp_con.flags))
-		return;
-
-	wake_up_interruptible(&lowcomms_recv_wait);
+		queue_work(recv_workqueue, &sctp_con.work);
 }
 
 
@@ -361,10 +367,10 @@
 				spin_lock_bh(&write_nodes_lock);
 				list_add_tail(&ni->write_list, &write_nodes);
 				spin_unlock_bh(&write_nodes_lock);
+				queue_work(send_workqueue, &ni->swork);
 			}
 		}
 	}
-	wake_up_process(send_task);
 }
 
 /* Something happened to an association */
@@ -446,8 +452,8 @@
 				spin_lock_bh(&write_nodes_lock);
 				list_add_tail(&ni->write_list, &write_nodes);
 				spin_unlock_bh(&write_nodes_lock);
+				queue_work(send_workqueue, &ni->swork);
 			}
-			wake_up_process(send_task);
 		}
 		break;
 
@@ -580,8 +586,8 @@
 				spin_lock_bh(&write_nodes_lock);
 				list_add_tail(&ni->write_list, &write_nodes);
 				spin_unlock_bh(&write_nodes_lock);
+				queue_work(send_workqueue, &ni->swork);
 			}
-			wake_up_process(send_task);
 		}
 	}
 
@@ -590,6 +596,7 @@
 		return 0;
 
 	cbuf_add(&sctp_con.cb, ret);
+	// PJC: TODO: Add to node's workqueue....can we ??
 	ret = dlm_process_incoming_buffer(cpu_to_le32(sinfo->sinfo_ppid),
 					  page_address(sctp_con.rx_page),
 					  sctp_con.cb.base, sctp_con.cb.len,
@@ -635,7 +642,7 @@
 
 	if (result < 0)
 		log_print("Can't bind to port %d addr number %d",
-			  dlm_config.tcp_port, num);
+			  dlm_config.ci_tcp_port, num);
 
 	return result;
 }
@@ -711,7 +718,7 @@
 	/* Bind to all interfaces. */
 	for (i = 0; i < dlm_local_count; i++) {
 		memcpy(&localaddr, dlm_local_addr[i], sizeof(localaddr));
-		make_sockaddr(&localaddr, dlm_config.tcp_port, &addr_len);
+		make_sockaddr(&localaddr, dlm_config.ci_tcp_port, &addr_len);
 
 		result = add_bind_addr(&localaddr, addr_len, num);
 		if (result)
@@ -820,7 +827,8 @@
 		spin_lock_bh(&write_nodes_lock);
 		list_add_tail(&ni->write_list, &write_nodes);
 		spin_unlock_bh(&write_nodes_lock);
-		wake_up_process(send_task);
+
+		queue_work(send_workqueue, &ni->swork);
 	}
 	return;
 
@@ -863,7 +871,7 @@
 		return;
 	}
 
-	make_sockaddr(&rem_addr, dlm_config.tcp_port, &addrlen);
+	make_sockaddr(&rem_addr, dlm_config.ci_tcp_port, &addrlen);
 
 	outmessage.msg_name = &rem_addr;
 	outmessage.msg_namelen = addrlen;
@@ -1088,101 +1096,75 @@
 	return 0;
 }
 
-static int write_list_empty(void)
+// PJC: The work queue function for receiving.
+static void process_recv_sockets(struct work_struct *work)
 {
-	int status;
-
-	spin_lock_bh(&write_nodes_lock);
-	status = list_empty(&write_nodes);
-	spin_unlock_bh(&write_nodes_lock);
-
-	return status;
-}
-
-static int dlm_recvd(void *data)
-{
-	DECLARE_WAITQUEUE(wait, current);
-
-	while (!kthread_should_stop()) {
+	if (test_and_clear_bit(CF_READ_PENDING, &sctp_con.flags)) {
+		int ret;
 		int count = 0;
 
-		set_current_state(TASK_INTERRUPTIBLE);
-		add_wait_queue(&lowcomms_recv_wait, &wait);
-		if (!test_bit(CF_READ_PENDING, &sctp_con.flags))
-			cond_resched();
-		remove_wait_queue(&lowcomms_recv_wait, &wait);
-		set_current_state(TASK_RUNNING);
+		do {
+			ret = receive_from_sock();
 
-		if (test_and_clear_bit(CF_READ_PENDING, &sctp_con.flags)) {
-			int ret;
-
-			do {
-				ret = receive_from_sock();
-
-				/* Don't starve out everyone else */
-				if (++count >= MAX_RX_MSG_COUNT) {
-					cond_resched();
-					count = 0;
-				}
-			} while (!kthread_should_stop() && ret >=0);
-		}
-		cond_resched();
+			/* Don't starve out everyone else */
+			if (++count >= MAX_RX_MSG_COUNT) {
+				cond_resched();
+				count = 0;
+			}
+		} while (!kthread_should_stop() && ret >=0);
 	}
-
-	return 0;
+	cond_resched();
 }
 
-static int dlm_sendd(void *data)
+// PJC: the work queue function for sending
+static void process_send_sockets(struct work_struct *work)
 {
-	DECLARE_WAITQUEUE(wait, current);
-
-	add_wait_queue(sctp_con.sock->sk->sk_sleep, &wait);
-
-	while (!kthread_should_stop()) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (write_list_empty())
-			cond_resched();
-		set_current_state(TASK_RUNNING);
-
-		if (sctp_con.eagain_flag) {
-			sctp_con.eagain_flag = 0;
-			refill_write_queue();
-		}
-		process_output_queue();
+	if (sctp_con.eagain_flag) {
+		sctp_con.eagain_flag = 0;
+		refill_write_queue();
 	}
+	process_output_queue();
+}
 
-	remove_wait_queue(sctp_con.sock->sk->sk_sleep, &wait);
-
-	return 0;
+// PJC: Process lock requests from a particular node.
+// TODO: can we optimise this out on UP ??
+static void process_lock_request(struct work_struct *work)
+{
 }
 
 static void daemons_stop(void)
 {
-	kthread_stop(recv_task);
-	kthread_stop(send_task);
+	destroy_workqueue(recv_workqueue);
+	destroy_workqueue(send_workqueue);
+	destroy_workqueue(lock_workqueue);
 }
 
 static int daemons_start(void)
 {
-	struct task_struct *p;
 	int error;
-
-	p = kthread_run(dlm_recvd, NULL, "dlm_recvd");
-	error = IS_ERR(p);
+	recv_workqueue = create_workqueue("dlm_recv");
+	error = IS_ERR(recv_workqueue);
 	if (error) {
-		log_print("can't start dlm_recvd %d", error);
+		log_print("can't start dlm_recv %d", error);
 		return error;
 	}
-	recv_task = p;
 
-	p = kthread_run(dlm_sendd, NULL, "dlm_sendd");
-	error = IS_ERR(p);
+	send_workqueue = create_singlethread_workqueue("dlm_send");
+	error = IS_ERR(send_workqueue);
 	if (error) {
-		log_print("can't start dlm_sendd %d", error);
-		kthread_stop(recv_task);
+		log_print("can't start dlm_send %d", error);
+		destroy_workqueue(recv_workqueue);
 		return error;
 	}
-	send_task = p;
+
+	lock_workqueue = create_workqueue("dlm_rlock");
+	error = IS_ERR(lock_workqueue);
+	if (error) {
+		log_print("can't start dlm_rlock %d", error);
+		destroy_workqueue(send_workqueue);
+		destroy_workqueue(recv_workqueue);
+		return error;
+	}
 
 	return 0;
 }
@@ -1194,6 +1176,8 @@
 {
 	int error;
 
+	INIT_WORK(&sctp_con.work, process_recv_sockets);
+
 	error = init_sock();
 	if (error)
 		goto fail_sock;
@@ -1224,4 +1208,3 @@
 	for (i = 0; i < dlm_local_count; i++)
 		kfree(dlm_local_addr[i]);
 }
-
diff --git a/fs/dlm/lowcomms-tcp.c b/fs/dlm/lowcomms-tcp.c
index 9be3a44..07e0a12 100644
--- a/fs/dlm/lowcomms-tcp.c
+++ b/fs/dlm/lowcomms-tcp.c
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -96,10 +96,7 @@
 struct connection {
 	struct socket *sock;	/* NULL if not connected */
 	uint32_t nodeid;	/* So we know who we are in the list */
-	struct rw_semaphore sock_sem; /* Stop connect races */
-	struct list_head read_list;   /* On this list when ready for reading */
-	struct list_head write_list;  /* On this list when ready for writing */
-	struct list_head state_list;  /* On this list when ready to connect */
+	struct mutex sock_mutex;
 	unsigned long flags;	/* bit 1,2 = We are on the read/write lists */
 #define CF_READ_PENDING 1
 #define CF_WRITE_PENDING 2
@@ -112,9 +109,10 @@
 	struct page *rx_page;
 	struct cbuf cb;
 	int retries;
-	atomic_t waiting_requests;
 #define MAX_CONNECT_RETRIES 3
 	struct connection *othercon;
+	struct work_struct rwork; /* Receive workqueue */
+	struct work_struct swork; /* Send workqueue */
 };
 #define sock2con(x) ((struct connection *)(x)->sk_user_data)
 
@@ -131,14 +129,9 @@
 
 static struct sockaddr_storage dlm_local_addr;
 
-/* Manage daemons */
-static struct task_struct *recv_task;
-static struct task_struct *send_task;
-
-static wait_queue_t lowcomms_send_waitq_head;
-static DECLARE_WAIT_QUEUE_HEAD(lowcomms_send_waitq);
-static wait_queue_t lowcomms_recv_waitq_head;
-static DECLARE_WAIT_QUEUE_HEAD(lowcomms_recv_waitq);
+/* Work queues */
+static struct workqueue_struct *recv_workqueue;
+static struct workqueue_struct *send_workqueue;
 
 /* An array of pointers to connections, indexed by NODEID */
 static struct connection **connections;
@@ -146,17 +139,8 @@
 static struct kmem_cache *con_cache;
 static int conn_array_size;
 
-/* List of sockets that have reads pending */
-static LIST_HEAD(read_sockets);
-static DEFINE_SPINLOCK(read_sockets_lock);
-
-/* List of sockets which have writes pending */
-static LIST_HEAD(write_sockets);
-static DEFINE_SPINLOCK(write_sockets_lock);
-
-/* List of sockets which have connects pending */
-static LIST_HEAD(state_sockets);
-static DEFINE_SPINLOCK(state_sockets_lock);
+static void process_recv_sockets(struct work_struct *work);
+static void process_send_sockets(struct work_struct *work);
 
 static struct connection *nodeid2con(int nodeid, gfp_t allocation)
 {
@@ -186,9 +170,11 @@
 			goto finish;
 
 		con->nodeid = nodeid;
-		init_rwsem(&con->sock_sem);
+		mutex_init(&con->sock_mutex);
 		INIT_LIST_HEAD(&con->writequeue);
 		spin_lock_init(&con->writequeue_lock);
+		INIT_WORK(&con->swork, process_send_sockets);
+		INIT_WORK(&con->rwork, process_recv_sockets);
 
 		connections[nodeid] = con;
 	}
@@ -203,41 +189,22 @@
 {
 	struct connection *con = sock2con(sk);
 
-	atomic_inc(&con->waiting_requests);
-	if (test_and_set_bit(CF_READ_PENDING, &con->flags))
-		return;
-
-	spin_lock_bh(&read_sockets_lock);
-	list_add_tail(&con->read_list, &read_sockets);
-	spin_unlock_bh(&read_sockets_lock);
-
-	wake_up_interruptible(&lowcomms_recv_waitq);
+	if (!test_and_set_bit(CF_READ_PENDING, &con->flags))
+		queue_work(recv_workqueue, &con->rwork);
 }
 
 static void lowcomms_write_space(struct sock *sk)
 {
 	struct connection *con = sock2con(sk);
 
-	if (test_and_set_bit(CF_WRITE_PENDING, &con->flags))
-		return;
-
-	spin_lock_bh(&write_sockets_lock);
-	list_add_tail(&con->write_list, &write_sockets);
-	spin_unlock_bh(&write_sockets_lock);
-
-	wake_up_interruptible(&lowcomms_send_waitq);
+	if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags))
+		queue_work(send_workqueue, &con->swork);
 }
 
 static inline void lowcomms_connect_sock(struct connection *con)
 {
-	if (test_and_set_bit(CF_CONNECT_PENDING, &con->flags))
-		return;
-
-	spin_lock_bh(&state_sockets_lock);
-	list_add_tail(&con->state_list, &state_sockets);
-	spin_unlock_bh(&state_sockets_lock);
-
-	wake_up_interruptible(&lowcomms_send_waitq);
+	if (!test_and_set_bit(CF_CONNECT_PENDING, &con->flags))
+		queue_work(send_workqueue, &con->swork);
 }
 
 static void lowcomms_state_change(struct sock *sk)
@@ -279,7 +246,7 @@
 /* Close a remote connection and tidy up */
 static void close_connection(struct connection *con, bool and_other)
 {
-	down_write(&con->sock_sem);
+	mutex_lock(&con->sock_mutex);
 
 	if (con->sock) {
 		sock_release(con->sock);
@@ -294,24 +261,27 @@
 		con->rx_page = NULL;
 	}
 	con->retries = 0;
-	up_write(&con->sock_sem);
+	mutex_unlock(&con->sock_mutex);
 }
 
 /* Data received from remote end */
 static int receive_from_sock(struct connection *con)
 {
 	int ret = 0;
-	struct msghdr msg;
-	struct iovec iov[2];
-	mm_segment_t fs;
+	struct msghdr msg = {};
+	struct kvec iov[2];
 	unsigned len;
 	int r;
 	int call_again_soon = 0;
+	int nvec;
 
-	down_read(&con->sock_sem);
+	mutex_lock(&con->sock_mutex);
 
-	if (con->sock == NULL)
-		goto out;
+	if (con->sock == NULL) {
+		ret = -EAGAIN;
+		goto out_close;
+	}
+
 	if (con->rx_page == NULL) {
 		/*
 		 * This doesn't need to be atomic, but I think it should
@@ -323,21 +293,13 @@
 		cbuf_init(&con->cb, PAGE_CACHE_SIZE);
 	}
 
-	msg.msg_control = NULL;
-	msg.msg_controllen = 0;
-	msg.msg_iovlen = 1;
-	msg.msg_iov = iov;
-	msg.msg_name = NULL;
-	msg.msg_namelen = 0;
-	msg.msg_flags = 0;
-
 	/*
 	 * iov[0] is the bit of the circular buffer between the current end
 	 * point (cb.base + cb.len) and the end of the buffer.
 	 */
 	iov[0].iov_len = con->cb.base - cbuf_data(&con->cb);
 	iov[0].iov_base = page_address(con->rx_page) + cbuf_data(&con->cb);
-	iov[1].iov_len = 0;
+	nvec = 1;
 
 	/*
 	 * iov[1] is the bit of the circular buffer between the start of the
@@ -347,18 +309,18 @@
 		iov[0].iov_len = PAGE_CACHE_SIZE - cbuf_data(&con->cb);
 		iov[1].iov_len = con->cb.base;
 		iov[1].iov_base = page_address(con->rx_page);
-		msg.msg_iovlen = 2;
+		nvec = 2;
 	}
 	len = iov[0].iov_len + iov[1].iov_len;
 
-	fs = get_fs();
-	set_fs(get_ds());
-	r = ret = sock_recvmsg(con->sock, &msg, len,
+	r = ret = kernel_recvmsg(con->sock, &msg, iov, nvec, len,
 			       MSG_DONTWAIT | MSG_NOSIGNAL);
-	set_fs(fs);
 
 	if (ret <= 0)
 		goto out_close;
+	if (ret == -EAGAIN)
+		goto out_resched;
+
 	if (ret == len)
 		call_again_soon = 1;
 	cbuf_add(&con->cb, ret);
@@ -381,24 +343,26 @@
 		con->rx_page = NULL;
 	}
 
-out:
 	if (call_again_soon)
 		goto out_resched;
-	up_read(&con->sock_sem);
+	mutex_unlock(&con->sock_mutex);
 	return 0;
 
 out_resched:
-	lowcomms_data_ready(con->sock->sk, 0);
-	up_read(&con->sock_sem);
-	cond_resched();
-	return 0;
+	if (!test_and_set_bit(CF_READ_PENDING, &con->flags))
+		queue_work(recv_workqueue, &con->rwork);
+	mutex_unlock(&con->sock_mutex);
+	return -EAGAIN;
 
 out_close:
-	up_read(&con->sock_sem);
+	mutex_unlock(&con->sock_mutex);
 	if (ret != -EAGAIN && !test_bit(CF_IS_OTHERCON, &con->flags)) {
 		close_connection(con, false);
 		/* Reconnect when there is something to send */
 	}
+	/* Don't return success if we really got EOF */
+	if (ret == 0)
+		ret = -EAGAIN;
 
 	return ret;
 }
@@ -412,6 +376,7 @@
 	int len;
 	int nodeid;
 	struct connection *newcon;
+	struct connection *addcon;
 
 	memset(&peeraddr, 0, sizeof(peeraddr));
 	result = sock_create_kern(dlm_local_addr.ss_family, SOCK_STREAM,
@@ -419,7 +384,7 @@
 	if (result < 0)
 		return -ENOMEM;
 
-	down_read(&con->sock_sem);
+	mutex_lock_nested(&con->sock_mutex, 0);
 
 	result = -ENOTCONN;
 	if (con->sock == NULL)
@@ -445,7 +410,7 @@
 	if (dlm_addr_to_nodeid(&peeraddr, &nodeid)) {
 		printk("dlm: connect from non cluster node\n");
 		sock_release(newsock);
-		up_read(&con->sock_sem);
+		mutex_unlock(&con->sock_mutex);
 		return -1;
 	}
 
@@ -462,7 +427,7 @@
 		result = -ENOMEM;
 		goto accept_err;
 	}
-	down_write(&newcon->sock_sem);
+	mutex_lock_nested(&newcon->sock_mutex, 1);
 	if (newcon->sock) {
 		struct connection *othercon = newcon->othercon;
 
@@ -470,41 +435,45 @@
 			othercon = kmem_cache_zalloc(con_cache, GFP_KERNEL);
 			if (!othercon) {
 				printk("dlm: failed to allocate incoming socket\n");
-				up_write(&newcon->sock_sem);
+				mutex_unlock(&newcon->sock_mutex);
 				result = -ENOMEM;
 				goto accept_err;
 			}
 			othercon->nodeid = nodeid;
 			othercon->rx_action = receive_from_sock;
-			init_rwsem(&othercon->sock_sem);
+			mutex_init(&othercon->sock_mutex);
+			INIT_WORK(&othercon->swork, process_send_sockets);
+			INIT_WORK(&othercon->rwork, process_recv_sockets);
 			set_bit(CF_IS_OTHERCON, &othercon->flags);
 			newcon->othercon = othercon;
 		}
 		othercon->sock = newsock;
 		newsock->sk->sk_user_data = othercon;
 		add_sock(newsock, othercon);
+		addcon = othercon;
 	}
 	else {
 		newsock->sk->sk_user_data = newcon;
 		newcon->rx_action = receive_from_sock;
 		add_sock(newsock, newcon);
-
+		addcon = newcon;
 	}
 
-	up_write(&newcon->sock_sem);
+	mutex_unlock(&newcon->sock_mutex);
 
 	/*
 	 * Add it to the active queue in case we got data
 	 * beween processing the accept adding the socket
 	 * to the read_sockets list
 	 */
-	lowcomms_data_ready(newsock->sk, 0);
-	up_read(&con->sock_sem);
+	if (!test_and_set_bit(CF_READ_PENDING, &addcon->flags))
+		queue_work(recv_workqueue, &addcon->rwork);
+	mutex_unlock(&con->sock_mutex);
 
 	return 0;
 
 accept_err:
-	up_read(&con->sock_sem);
+	mutex_unlock(&con->sock_mutex);
 	sock_release(newsock);
 
 	if (result != -EAGAIN)
@@ -525,7 +494,7 @@
 		return;
 	}
 
-	down_write(&con->sock_sem);
+	mutex_lock(&con->sock_mutex);
 	if (con->retries++ > MAX_CONNECT_RETRIES)
 		goto out;
 
@@ -548,7 +517,7 @@
 	sock->sk->sk_user_data = con;
 	con->rx_action = receive_from_sock;
 
-	make_sockaddr(&saddr, dlm_config.tcp_port, &addr_len);
+	make_sockaddr(&saddr, dlm_config.ci_tcp_port, &addr_len);
 
 	add_sock(sock, con);
 
@@ -577,7 +546,7 @@
 		result = 0;
 	}
 out:
-	up_write(&con->sock_sem);
+	mutex_unlock(&con->sock_mutex);
 	return;
 }
 
@@ -616,10 +585,10 @@
 	con->sock = sock;
 
 	/* Bind to our port */
-	make_sockaddr(saddr, dlm_config.tcp_port, &addr_len);
+	make_sockaddr(saddr, dlm_config.ci_tcp_port, &addr_len);
 	result = sock->ops->bind(sock, (struct sockaddr *) saddr, addr_len);
 	if (result < 0) {
-		printk("dlm: Can't bind to port %d\n", dlm_config.tcp_port);
+		printk("dlm: Can't bind to port %d\n", dlm_config.ci_tcp_port);
 		sock_release(sock);
 		sock = NULL;
 		con->sock = NULL;
@@ -638,7 +607,7 @@
 
 	result = sock->ops->listen(sock, 5);
 	if (result < 0) {
-		printk("dlm: Can't listen on port %d\n", dlm_config.tcp_port);
+		printk("dlm: Can't listen on port %d\n", dlm_config.ci_tcp_port);
 		sock_release(sock);
 		sock = NULL;
 		goto create_out;
@@ -709,6 +678,7 @@
 	if (!con)
 		return NULL;
 
+	spin_lock(&con->writequeue_lock);
 	e = list_entry(con->writequeue.prev, struct writequeue_entry, list);
 	if ((&e->list == &con->writequeue) ||
 	    (PAGE_CACHE_SIZE - e->end < len)) {
@@ -747,6 +717,7 @@
 	struct connection *con = e->con;
 	int users;
 
+	spin_lock(&con->writequeue_lock);
 	users = --e->users;
 	if (users)
 		goto out;
@@ -754,12 +725,8 @@
 	kunmap(e->page);
 	spin_unlock(&con->writequeue_lock);
 
-	if (test_and_set_bit(CF_WRITE_PENDING, &con->flags) == 0) {
-		spin_lock_bh(&write_sockets_lock);
-		list_add_tail(&con->write_list, &write_sockets);
-		spin_unlock_bh(&write_sockets_lock);
-
-		wake_up_interruptible(&lowcomms_send_waitq);
+	if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) {
+		queue_work(send_workqueue, &con->swork);
 	}
 	return;
 
@@ -783,7 +750,7 @@
 	struct writequeue_entry *e;
 	int len, offset;
 
-	down_read(&con->sock_sem);
+	mutex_lock(&con->sock_mutex);
 	if (con->sock == NULL)
 		goto out_connect;
 
@@ -800,6 +767,7 @@
 		offset = e->offset;
 		BUG_ON(len == 0 && e->users == 0);
 		spin_unlock(&con->writequeue_lock);
+		kmap(e->page);
 
 		ret = 0;
 		if (len) {
@@ -828,18 +796,18 @@
 	}
 	spin_unlock(&con->writequeue_lock);
 out:
-	up_read(&con->sock_sem);
+	mutex_unlock(&con->sock_mutex);
 	return;
 
 send_error:
-	up_read(&con->sock_sem);
+	mutex_unlock(&con->sock_mutex);
 	close_connection(con, false);
 	lowcomms_connect_sock(con);
 	return;
 
 out_connect:
-	up_read(&con->sock_sem);
-	lowcomms_connect_sock(con);
+	mutex_unlock(&con->sock_mutex);
+	connect_to_sock(con);
 	return;
 }
 
@@ -872,7 +840,6 @@
 	if (con) {
 		clean_one_writequeue(con);
 		close_connection(con, true);
-		atomic_set(&con->waiting_requests, 0);
 	}
 	return 0;
 
@@ -880,102 +847,29 @@
 	return -1;
 }
 
-/* API send message call, may queue the request */
-/* N.B. This is the old interface - use the new one for new calls */
-int lowcomms_send_message(int nodeid, char *buf, int len, gfp_t allocation)
-{
-	struct writequeue_entry *e;
-	char *b;
-
-	e = dlm_lowcomms_get_buffer(nodeid, len, allocation, &b);
-	if (e) {
-		memcpy(b, buf, len);
-		dlm_lowcomms_commit_buffer(e);
-		return 0;
-	}
-	return -ENOBUFS;
-}
-
 /* Look for activity on active sockets */
-static void process_sockets(void)
+static void process_recv_sockets(struct work_struct *work)
 {
-	struct list_head *list;
-	struct list_head *temp;
-	int count = 0;
+	struct connection *con = container_of(work, struct connection, rwork);
+	int err;
 
-	spin_lock_bh(&read_sockets_lock);
-	list_for_each_safe(list, temp, &read_sockets) {
-
-		struct connection *con =
-			list_entry(list, struct connection, read_list);
-		list_del(&con->read_list);
-		clear_bit(CF_READ_PENDING, &con->flags);
-
-		spin_unlock_bh(&read_sockets_lock);
-
-		/* This can reach zero if we are processing requests
-		 * as they come in.
-		 */
-		if (atomic_read(&con->waiting_requests) == 0) {
-			spin_lock_bh(&read_sockets_lock);
-			continue;
-		}
-
-		do {
-			con->rx_action(con);
-
-			/* Don't starve out everyone else */
-			if (++count >= MAX_RX_MSG_COUNT) {
-				cond_resched();
-				count = 0;
-			}
-
-		} while (!atomic_dec_and_test(&con->waiting_requests) &&
-			 !kthread_should_stop());
-
-		spin_lock_bh(&read_sockets_lock);
-	}
-	spin_unlock_bh(&read_sockets_lock);
+	clear_bit(CF_READ_PENDING, &con->flags);
+	do {
+		err = con->rx_action(con);
+	} while (!err);
 }
 
-/* Try to send any messages that are pending
- */
-static void process_output_queue(void)
+
+static void process_send_sockets(struct work_struct *work)
 {
-	struct list_head *list;
-	struct list_head *temp;
+	struct connection *con = container_of(work, struct connection, swork);
 
-	spin_lock_bh(&write_sockets_lock);
-	list_for_each_safe(list, temp, &write_sockets) {
-		struct connection *con =
-			list_entry(list, struct connection, write_list);
-		clear_bit(CF_WRITE_PENDING, &con->flags);
-		list_del(&con->write_list);
-
-		spin_unlock_bh(&write_sockets_lock);
-		send_to_sock(con);
-		spin_lock_bh(&write_sockets_lock);
-	}
-	spin_unlock_bh(&write_sockets_lock);
-}
-
-static void process_state_queue(void)
-{
-	struct list_head *list;
-	struct list_head *temp;
-
-	spin_lock_bh(&state_sockets_lock);
-	list_for_each_safe(list, temp, &state_sockets) {
-		struct connection *con =
-			list_entry(list, struct connection, state_list);
-		list_del(&con->state_list);
-		clear_bit(CF_CONNECT_PENDING, &con->flags);
-		spin_unlock_bh(&state_sockets_lock);
-
+	if (test_and_clear_bit(CF_CONNECT_PENDING, &con->flags)) {
 		connect_to_sock(con);
-		spin_lock_bh(&state_sockets_lock);
 	}
-	spin_unlock_bh(&state_sockets_lock);
+
+	clear_bit(CF_WRITE_PENDING, &con->flags);
+	send_to_sock(con);
 }
 
 
@@ -992,109 +886,33 @@
 	}
 }
 
-static int read_list_empty(void)
+static void work_stop(void)
 {
-	int status;
-
-	spin_lock_bh(&read_sockets_lock);
-	status = list_empty(&read_sockets);
-	spin_unlock_bh(&read_sockets_lock);
-
-	return status;
+	destroy_workqueue(recv_workqueue);
+	destroy_workqueue(send_workqueue);
 }
 
-/* DLM Transport comms receive daemon */
-static int dlm_recvd(void *data)
+static int work_start(void)
 {
-	init_waitqueue_entry(&lowcomms_recv_waitq_head, current);
-	add_wait_queue(&lowcomms_recv_waitq, &lowcomms_recv_waitq_head);
-
-	while (!kthread_should_stop()) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (read_list_empty())
-			cond_resched();
-		set_current_state(TASK_RUNNING);
-
-		process_sockets();
-	}
-
-	return 0;
-}
-
-static int write_and_state_lists_empty(void)
-{
-	int status;
-
-	spin_lock_bh(&write_sockets_lock);
-	status = list_empty(&write_sockets);
-	spin_unlock_bh(&write_sockets_lock);
-
-	spin_lock_bh(&state_sockets_lock);
-	if (list_empty(&state_sockets) == 0)
-		status = 0;
-	spin_unlock_bh(&state_sockets_lock);
-
-	return status;
-}
-
-/* DLM Transport send daemon */
-static int dlm_sendd(void *data)
-{
-	init_waitqueue_entry(&lowcomms_send_waitq_head, current);
-	add_wait_queue(&lowcomms_send_waitq, &lowcomms_send_waitq_head);
-
-	while (!kthread_should_stop()) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (write_and_state_lists_empty())
-			cond_resched();
-		set_current_state(TASK_RUNNING);
-
-		process_state_queue();
-		process_output_queue();
-	}
-
-	return 0;
-}
-
-static void daemons_stop(void)
-{
-	kthread_stop(recv_task);
-	kthread_stop(send_task);
-}
-
-static int daemons_start(void)
-{
-	struct task_struct *p;
 	int error;
-
-	p = kthread_run(dlm_recvd, NULL, "dlm_recvd");
-	error = IS_ERR(p);
+	recv_workqueue = create_workqueue("dlm_recv");
+	error = IS_ERR(recv_workqueue);
 	if (error) {
-		log_print("can't start dlm_recvd %d", error);
+		log_print("can't start dlm_recv %d", error);
 		return error;
 	}
-	recv_task = p;
 
-	p = kthread_run(dlm_sendd, NULL, "dlm_sendd");
-	error = IS_ERR(p);
+	send_workqueue = create_singlethread_workqueue("dlm_send");
+	error = IS_ERR(send_workqueue);
 	if (error) {
-		log_print("can't start dlm_sendd %d", error);
-		kthread_stop(recv_task);
+		log_print("can't start dlm_send %d", error);
+		destroy_workqueue(recv_workqueue);
 		return error;
 	}
-	send_task = p;
 
 	return 0;
 }
 
-/*
- * Return the largest buffer size we can cope with.
- */
-int lowcomms_max_buffer_size(void)
-{
-	return PAGE_CACHE_SIZE;
-}
-
 void dlm_lowcomms_stop(void)
 {
 	int i;
@@ -1107,7 +925,7 @@
 			connections[i]->flags |= 0xFF;
 	}
 
-	daemons_stop();
+	work_stop();
 	clean_writequeues();
 
 	for (i = 0; i < conn_array_size; i++) {
@@ -1159,7 +977,7 @@
 	if (error)
 		goto fail_unlisten;
 
-	error = daemons_start();
+	error = work_start();
 	if (error)
 		goto fail_unlisten;
 
diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c
index c9b1c3d..a5126e0 100644
--- a/fs/dlm/midcomms.c
+++ b/fs/dlm/midcomms.c
@@ -82,7 +82,7 @@
 		if (msglen < sizeof(struct dlm_header))
 			break;
 		err = -E2BIG;
-		if (msglen > dlm_config.buffer_size) {
+		if (msglen > dlm_config.ci_buffer_size) {
 			log_print("message size %d from %d too big, buf len %d",
 				  msglen, nodeid, len);
 			break;
@@ -103,7 +103,7 @@
 
 		if (msglen > sizeof(__tmp) &&
 		    msg == (struct dlm_header *) __tmp) {
-			msg = kmalloc(dlm_config.buffer_size, GFP_KERNEL);
+			msg = kmalloc(dlm_config.ci_buffer_size, GFP_KERNEL);
 			if (msg == NULL)
 				return ret;
 		}
diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c
index 4cc31be..6bfbd61 100644
--- a/fs/dlm/rcom.c
+++ b/fs/dlm/rcom.c
@@ -56,6 +56,10 @@
 
 	rc->rc_type = type;
 
+	spin_lock(&ls->ls_recover_lock);
+	rc->rc_seq = ls->ls_recover_seq;
+	spin_unlock(&ls->ls_recover_lock);
+
 	*mh_ret = mh;
 	*rc_ret = rc;
 	return 0;
@@ -78,8 +82,17 @@
 	rf->rf_lsflags = ls->ls_exflags;
 }
 
-static int check_config(struct dlm_ls *ls, struct rcom_config *rf, int nodeid)
+static int check_config(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid)
 {
+	struct rcom_config *rf = (struct rcom_config *) rc->rc_buf;
+
+	if ((rc->rc_header.h_version & 0xFFFF0000) != DLM_HEADER_MAJOR) {
+		log_error(ls, "version mismatch: %x nodeid %d: %x",
+			  DLM_HEADER_MAJOR | DLM_HEADER_MINOR, nodeid,
+			  rc->rc_header.h_version);
+		return -EINVAL;
+	}
+
 	if (rf->rf_lvblen != ls->ls_lvblen ||
 	    rf->rf_lsflags != ls->ls_exflags) {
 		log_error(ls, "config mismatch: %d,%x nodeid %d: %d,%x",
@@ -125,7 +138,7 @@
 		goto out;
 
 	allow_sync_reply(ls, &rc->rc_id);
-	memset(ls->ls_recover_buf, 0, dlm_config.buffer_size);
+	memset(ls->ls_recover_buf, 0, dlm_config.ci_buffer_size);
 
 	send_rcom(ls, mh, rc);
 
@@ -141,8 +154,7 @@
 		log_debug(ls, "remote node %d not ready", nodeid);
 		rc->rc_result = 0;
 	} else
-		error = check_config(ls, (struct rcom_config *) rc->rc_buf,
-				     nodeid);
+		error = check_config(ls, rc, nodeid);
 	/* the caller looks at rc_result for the remote recovery status */
  out:
 	return error;
@@ -159,6 +171,7 @@
 	if (error)
 		return;
 	rc->rc_id = rc_in->rc_id;
+	rc->rc_seq_reply = rc_in->rc_seq;
 	rc->rc_result = dlm_recover_status(ls);
 	make_config(ls, (struct rcom_config *) rc->rc_buf);
 
@@ -200,7 +213,7 @@
 	if (nodeid == dlm_our_nodeid()) {
 		dlm_copy_master_names(ls, last_name, last_len,
 		                      ls->ls_recover_buf + len,
-		                      dlm_config.buffer_size - len, nodeid);
+		                      dlm_config.ci_buffer_size - len, nodeid);
 		goto out;
 	}
 
@@ -210,7 +223,7 @@
 	memcpy(rc->rc_buf, last_name, last_len);
 
 	allow_sync_reply(ls, &rc->rc_id);
-	memset(ls->ls_recover_buf, 0, dlm_config.buffer_size);
+	memset(ls->ls_recover_buf, 0, dlm_config.ci_buffer_size);
 
 	send_rcom(ls, mh, rc);
 
@@ -224,30 +237,17 @@
 {
 	struct dlm_rcom *rc;
 	struct dlm_mhandle *mh;
-	int error, inlen, outlen;
-	int nodeid = rc_in->rc_header.h_nodeid;
-	uint32_t status = dlm_recover_status(ls);
-
-	/*
-	 * We can't run dlm_dir_rebuild_send (which uses ls_nodes) while
-	 * dlm_recoverd is running ls_nodes_reconfig (which changes ls_nodes).
-	 * It could only happen in rare cases where we get a late NAMES
-	 * message from a previous instance of recovery.
-	 */
-
-	if (!(status & DLM_RS_NODES)) {
-		log_debug(ls, "ignoring RCOM_NAMES from %u", nodeid);
-		return;
-	}
+	int error, inlen, outlen, nodeid;
 
 	nodeid = rc_in->rc_header.h_nodeid;
 	inlen = rc_in->rc_header.h_length - sizeof(struct dlm_rcom);
-	outlen = dlm_config.buffer_size - sizeof(struct dlm_rcom);
+	outlen = dlm_config.ci_buffer_size - sizeof(struct dlm_rcom);
 
 	error = create_rcom(ls, nodeid, DLM_RCOM_NAMES_REPLY, outlen, &rc, &mh);
 	if (error)
 		return;
 	rc->rc_id = rc_in->rc_id;
+	rc->rc_seq_reply = rc_in->rc_seq;
 
 	dlm_copy_master_names(ls, rc_in->rc_buf, inlen, rc->rc_buf, outlen,
 			      nodeid);
@@ -294,6 +294,7 @@
 		ret_nodeid = error;
 	rc->rc_result = ret_nodeid;
 	rc->rc_id = rc_in->rc_id;
+	rc->rc_seq_reply = rc_in->rc_seq;
 
 	send_rcom(ls, mh, rc);
 }
@@ -375,20 +376,13 @@
 
 	memcpy(rc->rc_buf, rc_in->rc_buf, sizeof(struct rcom_lock));
 	rc->rc_id = rc_in->rc_id;
+	rc->rc_seq_reply = rc_in->rc_seq;
 
 	send_rcom(ls, mh, rc);
 }
 
 static void receive_rcom_lock_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
 {
-	uint32_t status = dlm_recover_status(ls);
-
-	if (!(status & DLM_RS_DIR)) {
-		log_debug(ls, "ignoring RCOM_LOCK_REPLY from %u",
-			  rc_in->rc_header.h_nodeid);
-		return;
-	}
-
 	dlm_recover_process_copy(ls, rc_in);
 }
 
@@ -415,6 +409,7 @@
 
 	rc->rc_type = DLM_RCOM_STATUS_REPLY;
 	rc->rc_id = rc_in->rc_id;
+	rc->rc_seq_reply = rc_in->rc_seq;
 	rc->rc_result = -ESRCH;
 
 	rf = (struct rcom_config *) rc->rc_buf;
@@ -426,6 +421,31 @@
 	return 0;
 }
 
+static int is_old_reply(struct dlm_ls *ls, struct dlm_rcom *rc)
+{
+	uint64_t seq;
+	int rv = 0;
+
+	switch (rc->rc_type) {
+	case DLM_RCOM_STATUS_REPLY:
+	case DLM_RCOM_NAMES_REPLY:
+	case DLM_RCOM_LOOKUP_REPLY:
+	case DLM_RCOM_LOCK_REPLY:
+		spin_lock(&ls->ls_recover_lock);
+		seq = ls->ls_recover_seq;
+		spin_unlock(&ls->ls_recover_lock);
+		if (rc->rc_seq_reply != seq) {
+			log_debug(ls, "ignoring old reply %x from %d "
+				      "seq_reply %llx expect %llx",
+				      rc->rc_type, rc->rc_header.h_nodeid,
+				      (unsigned long long)rc->rc_seq_reply,
+				      (unsigned long long)seq);
+			rv = 1;
+		}
+	}
+	return rv;
+}
+
 /* Called by dlm_recvd; corresponds to dlm_receive_message() but special
    recovery-only comms are sent through here. */
 
@@ -449,11 +469,14 @@
 	}
 
 	if (dlm_recovery_stopped(ls) && (rc->rc_type != DLM_RCOM_STATUS)) {
-		log_error(ls, "ignoring recovery message %x from %d",
+		log_debug(ls, "ignoring recovery message %x from %d",
 			  rc->rc_type, nodeid);
 		goto out;
 	}
 
+	if (is_old_reply(ls, rc))
+		goto out;
+
 	if (nodeid != rc->rc_header.h_nodeid) {
 		log_error(ls, "bad rcom nodeid %d from %d",
 			  rc->rc_header.h_nodeid, nodeid);
diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c
index cf9f683..c2cc769 100644
--- a/fs/dlm/recover.c
+++ b/fs/dlm/recover.c
@@ -44,7 +44,7 @@
 static void dlm_wait_timer_fn(unsigned long data)
 {
 	struct dlm_ls *ls = (struct dlm_ls *) data;
-	mod_timer(&ls->ls_timer, jiffies + (dlm_config.recover_timer * HZ));
+	mod_timer(&ls->ls_timer, jiffies + (dlm_config.ci_recover_timer * HZ));
 	wake_up(&ls->ls_wait_general);
 }
 
@@ -55,7 +55,7 @@
 	init_timer(&ls->ls_timer);
 	ls->ls_timer.function = dlm_wait_timer_fn;
 	ls->ls_timer.data = (long) ls;
-	ls->ls_timer.expires = jiffies + (dlm_config.recover_timer * HZ);
+	ls->ls_timer.expires = jiffies + (dlm_config.ci_recover_timer * HZ);
 	add_timer(&ls->ls_timer);
 
 	wait_event(ls->ls_wait_general, testfn(ls) || dlm_recovery_stopped(ls));
@@ -397,7 +397,9 @@
 
 		if (dlm_no_directory(ls))
 			count += recover_master_static(r);
-		else if (!is_master(r) && dlm_is_removed(ls, r->res_nodeid)) {
+		else if (!is_master(r) &&
+			 (dlm_is_removed(ls, r->res_nodeid) ||
+			  rsb_flag(r, RSB_NEW_MASTER))) {
 			recover_master(r);
 			count++;
 		}
diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c
index 650536aa..3cb636d 100644
--- a/fs/dlm/recoverd.c
+++ b/fs/dlm/recoverd.c
@@ -77,7 +77,7 @@
 
 	error = dlm_recover_members(ls, rv, &neg);
 	if (error) {
-		log_error(ls, "recover_members failed %d", error);
+		log_debug(ls, "recover_members failed %d", error);
 		goto fail;
 	}
 	start = jiffies;
@@ -89,7 +89,7 @@
 
 	error = dlm_recover_directory(ls);
 	if (error) {
-		log_error(ls, "recover_directory failed %d", error);
+		log_debug(ls, "recover_directory failed %d", error);
 		goto fail;
 	}
 
@@ -99,7 +99,7 @@
 
 	error = dlm_recover_directory_wait(ls);
 	if (error) {
-		log_error(ls, "recover_directory_wait failed %d", error);
+		log_debug(ls, "recover_directory_wait failed %d", error);
 		goto fail;
 	}
 
@@ -129,7 +129,7 @@
 
 		error = dlm_recover_masters(ls);
 		if (error) {
-			log_error(ls, "recover_masters failed %d", error);
+			log_debug(ls, "recover_masters failed %d", error);
 			goto fail;
 		}
 
@@ -139,13 +139,13 @@
 
 		error = dlm_recover_locks(ls);
 		if (error) {
-			log_error(ls, "recover_locks failed %d", error);
+			log_debug(ls, "recover_locks failed %d", error);
 			goto fail;
 		}
 
 		error = dlm_recover_locks_wait(ls);
 		if (error) {
-			log_error(ls, "recover_locks_wait failed %d", error);
+			log_debug(ls, "recover_locks_wait failed %d", error);
 			goto fail;
 		}
 
@@ -166,7 +166,7 @@
 
 		error = dlm_recover_locks_wait(ls);
 		if (error) {
-			log_error(ls, "recover_locks_wait failed %d", error);
+			log_debug(ls, "recover_locks_wait failed %d", error);
 			goto fail;
 		}
 	}
@@ -184,7 +184,7 @@
 	dlm_set_recover_status(ls, DLM_RS_DONE);
 	error = dlm_recover_done_wait(ls);
 	if (error) {
-		log_error(ls, "recover_done_wait failed %d", error);
+		log_debug(ls, "recover_done_wait failed %d", error);
 		goto fail;
 	}
 
@@ -192,19 +192,19 @@
 
 	error = enable_locking(ls, rv->seq);
 	if (error) {
-		log_error(ls, "enable_locking failed %d", error);
+		log_debug(ls, "enable_locking failed %d", error);
 		goto fail;
 	}
 
 	error = dlm_process_requestqueue(ls);
 	if (error) {
-		log_error(ls, "process_requestqueue failed %d", error);
+		log_debug(ls, "process_requestqueue failed %d", error);
 		goto fail;
 	}
 
 	error = dlm_recover_waiters_post(ls);
 	if (error) {
-		log_error(ls, "recover_waiters_post failed %d", error);
+		log_debug(ls, "recover_waiters_post failed %d", error);
 		goto fail;
 	}
 
diff --git a/fs/dlm/user.c b/fs/dlm/user.c
index c37e93e..d378b7f 100644
--- a/fs/dlm/user.c
+++ b/fs/dlm/user.c
@@ -180,6 +180,14 @@
 	    ua->lksb.sb_status == -EAGAIN && !list_empty(&lkb->lkb_ownqueue))
 		remove_ownqueue = 1;
 
+	/* unlocks or cancels of waiting requests need to be removed from the
+	   proc's unlocking list, again there must be a better way...  */
+
+	if (ua->lksb.sb_status == -DLM_EUNLOCK ||
+	    (ua->lksb.sb_status == -DLM_ECANCEL &&
+	     lkb->lkb_grmode == DLM_LOCK_IV))
+		remove_ownqueue = 1;
+
 	/* We want to copy the lvb to userspace when the completion
 	   ast is read if the status is 0, the lock has an lvb and
 	   lvb_ops says we should.  We could probably have set_lvb_lock()
@@ -523,6 +531,7 @@
 	proc->lockspace = ls->ls_local_handle;
 	INIT_LIST_HEAD(&proc->asts);
 	INIT_LIST_HEAD(&proc->locks);
+	INIT_LIST_HEAD(&proc->unlocking);
 	spin_lock_init(&proc->asts_spin);
 	spin_lock_init(&proc->locks_spin);
 	init_waitqueue_head(&proc->wait);
diff --git a/fs/dlm/util.c b/fs/dlm/util.c
index 767197d..963889c 100644
--- a/fs/dlm/util.c
+++ b/fs/dlm/util.c
@@ -134,6 +134,8 @@
 	rc->rc_type		= cpu_to_le32(rc->rc_type);
 	rc->rc_result		= cpu_to_le32(rc->rc_result);
 	rc->rc_id		= cpu_to_le64(rc->rc_id);
+	rc->rc_seq		= cpu_to_le64(rc->rc_seq);
+	rc->rc_seq_reply	= cpu_to_le64(rc->rc_seq_reply);
 
 	if (type == DLM_RCOM_LOCK)
 		rcom_lock_out((struct rcom_lock *) rc->rc_buf);
@@ -151,6 +153,8 @@
 	rc->rc_type		= le32_to_cpu(rc->rc_type);
 	rc->rc_result		= le32_to_cpu(rc->rc_result);
 	rc->rc_id		= le64_to_cpu(rc->rc_id);
+	rc->rc_seq		= le64_to_cpu(rc->rc_seq);
+	rc->rc_seq_reply	= le64_to_cpu(rc->rc_seq_reply);
 
 	if (rc->rc_type == DLM_RCOM_LOCK)
 		rcom_lock_in((struct rcom_lock *) rc->rc_buf);
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 7196f50..a86a55c 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -828,9 +828,7 @@
 		mutex_unlock(&crypt_stat->cs_tfm_mutex);
 		goto out;
 	}
-	crypto_blkcipher_set_flags(crypt_stat->tfm,
-				   (ECRYPTFS_DEFAULT_CHAINING_MODE
-				    | CRYPTO_TFM_REQ_WEAK_KEY));
+	crypto_blkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY);
 	mutex_unlock(&crypt_stat->cs_tfm_mutex);
 	rc = 0;
 out:
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index afb64bd..0f89710 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -176,7 +176,6 @@
 #define ECRYPTFS_FILE_SIZE_BYTES 8
 #define ECRYPTFS_DEFAULT_CIPHER "aes"
 #define ECRYPTFS_DEFAULT_KEY_BYTES 16
-#define ECRYPTFS_DEFAULT_CHAINING_MODE CRYPTO_TFM_MODE_CBC
 #define ECRYPTFS_DEFAULT_HASH "md5"
 #define ECRYPTFS_TAG_3_PACKET_TYPE 0x8C
 #define ECRYPTFS_TAG_11_PACKET_TYPE 0xED
diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig
index 6a2ffa2..de8e64c 100644
--- a/fs/gfs2/Kconfig
+++ b/fs/gfs2/Kconfig
@@ -4,44 +4,43 @@
 	select FS_POSIX_ACL
 	select CRC32
 	help
-	A cluster filesystem.
+	  A cluster filesystem.
 
-	Allows a cluster of computers to simultaneously use a block device
-	that is shared between them (with FC, iSCSI, NBD, etc...).  GFS reads
-	and writes to the block device like a local filesystem, but also uses
-	a lock module to allow the computers coordinate their I/O so
-	filesystem consistency is maintained.  One of the nifty features of
-	GFS is perfect consistency -- changes made to the filesystem on one
-	machine show up immediately on all other machines in the cluster.
+	  Allows a cluster of computers to simultaneously use a block device
+	  that is shared between them (with FC, iSCSI, NBD, etc...).  GFS reads
+	  and writes to the block device like a local filesystem, but also uses
+	  a lock module to allow the computers coordinate their I/O so
+	  filesystem consistency is maintained.  One of the nifty features of
+	  GFS is perfect consistency -- changes made to the filesystem on one
+	  machine show up immediately on all other machines in the cluster.
 
-	To use the GFS2 filesystem, you will need to enable one or more of
-	the below locking modules. Documentation and utilities for GFS2 can
-	be found here: http://sources.redhat.com/cluster
+	  To use the GFS2 filesystem, you will need to enable one or more of
+	  the below locking modules. Documentation and utilities for GFS2 can
+	  be found here: http://sources.redhat.com/cluster
 
 config GFS2_FS_LOCKING_NOLOCK
 	tristate "GFS2 \"nolock\" locking module"
 	depends on GFS2_FS
 	help
-	Single node locking module for GFS2.
+	  Single node locking module for GFS2.
 
-	Use this module if you want to use GFS2 on a single node without
-	its clustering features. You can still take advantage of the
-	large file support, and upgrade to running a full cluster later on
-	if required.
+	  Use this module if you want to use GFS2 on a single node without
+	  its clustering features. You can still take advantage of the
+	  large file support, and upgrade to running a full cluster later on
+	  if required.
 
-	If you will only be using GFS2 in cluster mode, you do not need this
-	module.
+	  If you will only be using GFS2 in cluster mode, you do not need this
+	  module.
 
 config GFS2_FS_LOCKING_DLM
 	tristate "GFS2 DLM locking module"
-	depends on GFS2_FS && NET && INET && (IPV6 || IPV6=n)
+	depends on GFS2_FS && SYSFS && NET && INET && (IPV6 || IPV6=n)
 	select IP_SCTP if DLM_SCTP
 	select CONFIGFS_FS
 	select DLM
 	help
-	Multiple node locking module for GFS2
+	  Multiple node locking module for GFS2
 
-	Most users of GFS2 will require this module. It provides the locking
-	interface between GFS2 and the DLM, which is required to use GFS2
-	in a cluster environment.
-
+	  Most users of GFS2 will require this module. It provides the locking
+	  interface between GFS2 and the DLM, which is required to use GFS2
+	  in a cluster environment.
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 8240c1f..113f6c9 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -773,7 +773,7 @@
 			gfs2_free_data(ip, bstart, blen);
 	}
 
-	ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+	ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 
 	gfs2_dinode_out(ip, dibh->b_data);
 
@@ -848,7 +848,7 @@
 	}
 
 	ip->i_di.di_size = size;
-	ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+	ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 
 	error = gfs2_meta_inode_buffer(ip, &dibh);
 	if (error)
@@ -963,7 +963,7 @@
 
 	if (gfs2_is_stuffed(ip)) {
 		ip->i_di.di_size = size;
-		ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+		ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
 		gfs2_dinode_out(ip, dibh->b_data);
 		gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + size);
@@ -975,7 +975,7 @@
 
 		if (!error) {
 			ip->i_di.di_size = size;
-			ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+			ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 			ip->i_di.di_flags |= GFS2_DIF_TRUNC_IN_PROG;
 			gfs2_trans_add_bh(ip->i_gl, dibh, 1);
 			gfs2_dinode_out(ip, dibh->b_data);
@@ -1048,7 +1048,7 @@
 			ip->i_num.no_addr;
 		gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
 	}
-	ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+	ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 	ip->i_di.di_flags &= ~GFS2_DIF_TRUNC_IN_PROG;
 
 	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index 0fdcb77..c93ca8f 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -131,7 +131,7 @@
 	memcpy(dibh->b_data + offset + sizeof(struct gfs2_dinode), buf, size);
 	if (ip->i_di.di_size < offset + size)
 		ip->i_di.di_size = offset + size;
-	ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+	ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 	gfs2_dinode_out(ip, dibh->b_data);
 
 	brelse(dibh);
@@ -229,7 +229,7 @@
 
 	if (ip->i_di.di_size < offset + copied)
 		ip->i_di.di_size = offset + copied;
-	ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+	ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 
 	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
 	gfs2_dinode_out(ip, dibh->b_data);
@@ -1198,12 +1198,11 @@
  */
 
 static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
-			   void *opaque, gfs2_filldir_t filldir,
+			   void *opaque, filldir_t filldir,
 			   const struct gfs2_dirent **darr, u32 entries,
 			   int *copied)
 {
 	const struct gfs2_dirent *dent, *dent_next;
-	struct gfs2_inum_host inum;
 	u64 off, off_next;
 	unsigned int x, y;
 	int run = 0;
@@ -1240,11 +1239,9 @@
 			*offset = off;
 		}
 
-		gfs2_inum_in(&inum, (char *)&dent->de_inum);
-
 		error = filldir(opaque, (const char *)(dent + 1),
 				be16_to_cpu(dent->de_name_len),
-				off, &inum,
+				off, be64_to_cpu(dent->de_inum.no_addr),
 				be16_to_cpu(dent->de_type));
 		if (error)
 			return 1;
@@ -1262,8 +1259,8 @@
 }
 
 static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
-			      gfs2_filldir_t filldir, int *copied,
-			      unsigned *depth, u64 leaf_no)
+			      filldir_t filldir, int *copied, unsigned *depth,
+			      u64 leaf_no)
 {
 	struct gfs2_inode *ip = GFS2_I(inode);
 	struct buffer_head *bh;
@@ -1343,7 +1340,7 @@
  */
 
 static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
-		      gfs2_filldir_t filldir)
+		      filldir_t filldir)
 {
 	struct gfs2_inode *dip = GFS2_I(inode);
 	struct gfs2_sbd *sdp = GFS2_SB(inode);
@@ -1402,7 +1399,7 @@
 }
 
 int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
-		  gfs2_filldir_t filldir)
+		  filldir_t filldir)
 {
 	struct gfs2_inode *dip = GFS2_I(inode);
 	struct dirent_gather g;
@@ -1568,7 +1565,7 @@
 				break;
 			gfs2_trans_add_bh(ip->i_gl, bh, 1);
 			ip->i_di.di_entries++;
-			ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+			ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 			gfs2_dinode_out(ip, bh->b_data);
 			brelse(bh);
 			error = 0;
@@ -1654,7 +1651,7 @@
 		gfs2_consist_inode(dip);
 	gfs2_trans_add_bh(dip->i_gl, bh, 1);
 	dip->i_di.di_entries--;
-	dip->i_inode.i_mtime.tv_sec = dip->i_inode.i_ctime.tv_sec = get_seconds();
+	dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME_SEC;
 	gfs2_dinode_out(dip, bh->b_data);
 	brelse(bh);
 	mark_inode_dirty(&dip->i_inode);
@@ -1702,7 +1699,7 @@
 		gfs2_trans_add_bh(dip->i_gl, bh, 1);
 	}
 
-	dip->i_inode.i_mtime.tv_sec = dip->i_inode.i_ctime.tv_sec = get_seconds();
+	dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME_SEC;
 	gfs2_dinode_out(dip, bh->b_data);
 	brelse(bh);
 	return 0;
diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h
index b21b336..48fe890 100644
--- a/fs/gfs2/dir.h
+++ b/fs/gfs2/dir.h
@@ -16,30 +16,13 @@
 struct gfs2_inode;
 struct gfs2_inum;
 
-/**
- * gfs2_filldir_t - Report a directory entry to the caller of gfs2_dir_read()
- * @opaque: opaque data used by the function
- * @name: the name of the directory entry
- * @length: the length of the name
- * @offset: the entry's offset in the directory
- * @inum: the inode number the entry points to
- * @type: the type of inode the entry points to
- *
- * Returns: 0 on success, 1 if buffer full
- */
-
-typedef int (*gfs2_filldir_t) (void *opaque,
-			      const char *name, unsigned int length,
-			      u64 offset,
-			      struct gfs2_inum_host *inum, unsigned int type);
-
 int gfs2_dir_search(struct inode *dir, const struct qstr *filename,
 		    struct gfs2_inum_host *inum, unsigned int *type);
 int gfs2_dir_add(struct inode *inode, const struct qstr *filename,
 		 const struct gfs2_inum_host *inum, unsigned int type);
 int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *filename);
-int gfs2_dir_read(struct inode *inode, u64 * offset, void *opaque,
-		  gfs2_filldir_t filldir);
+int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
+		  filldir_t filldir);
 int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
 		   struct gfs2_inum_host *new_inum, unsigned int new_type);
 
diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c
index ebebbdc..0c83c7f 100644
--- a/fs/gfs2/eattr.c
+++ b/fs/gfs2/eattr.c
@@ -301,7 +301,7 @@
 
 	error = gfs2_meta_inode_buffer(ip, &dibh);
 	if (!error) {
-		ip->i_inode.i_ctime.tv_sec = get_seconds();
+		ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
 		gfs2_dinode_out(ip, dibh->b_data);
 		brelse(dibh);
@@ -718,7 +718,7 @@
 					    (er->er_mode & S_IFMT));
 			ip->i_inode.i_mode = er->er_mode;
 		}
-		ip->i_inode.i_ctime.tv_sec = get_seconds();
+		ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
 		gfs2_dinode_out(ip, dibh->b_data);
 		brelse(dibh);
@@ -853,7 +853,7 @@
 			(ip->i_inode.i_mode & S_IFMT) == (er->er_mode & S_IFMT));
 		ip->i_inode.i_mode = er->er_mode;
 	}
-	ip->i_inode.i_ctime.tv_sec = get_seconds();
+	ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
 	gfs2_dinode_out(ip, dibh->b_data);
 	brelse(dibh);
@@ -1134,7 +1134,7 @@
 
 	error = gfs2_meta_inode_buffer(ip, &dibh);
 	if (!error) {
-		ip->i_inode.i_ctime.tv_sec = get_seconds();
+		ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
 		gfs2_dinode_out(ip, dibh->b_data);
 		brelse(dibh);
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 4381469..6618c11 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -19,6 +19,8 @@
 #include <linux/gfs2_ondisk.h>
 #include <linux/list.h>
 #include <linux/lm_interface.h>
+#include <linux/wait.h>
+#include <linux/rwsem.h>
 #include <asm/uaccess.h>
 
 #include "gfs2.h"
@@ -33,11 +35,6 @@
 #include "super.h"
 #include "util.h"
 
-struct greedy {
-	struct gfs2_holder gr_gh;
-	struct delayed_work gr_work;
-};
-
 struct gfs2_gl_hash_bucket {
         struct hlist_head hb_list;
 };
@@ -47,6 +44,9 @@
 static int gfs2_dump_lockstate(struct gfs2_sbd *sdp);
 static int dump_glock(struct gfs2_glock *gl);
 static int dump_inode(struct gfs2_inode *ip);
+static void gfs2_glock_xmote_th(struct gfs2_holder *gh);
+static void gfs2_glock_drop_th(struct gfs2_glock *gl);
+static DECLARE_RWSEM(gfs2_umount_flush_sem);
 
 #define GFS2_GL_HASH_SHIFT      15
 #define GFS2_GL_HASH_SIZE       (1 << GFS2_GL_HASH_SHIFT)
@@ -213,30 +213,6 @@
 }
 
 /**
- * queue_empty - check to see if a glock's queue is empty
- * @gl: the glock
- * @head: the head of the queue to check
- *
- * This function protects the list in the event that a process already
- * has a holder on the list and is adding a second holder for itself.
- * The glmutex lock is what generally prevents processes from working
- * on the same glock at once, but the special case of adding a second
- * holder for yourself ("recursive" locking) doesn't involve locking
- * glmutex, making the spin lock necessary.
- *
- * Returns: 1 if the queue is empty
- */
-
-static inline int queue_empty(struct gfs2_glock *gl, struct list_head *head)
-{
-	int empty;
-	spin_lock(&gl->gl_spin);
-	empty = list_empty(head);
-	spin_unlock(&gl->gl_spin);
-	return empty;
-}
-
-/**
  * search_bucket() - Find struct gfs2_glock by lock number
  * @bucket: the bucket to search
  * @name: The lock name
@@ -395,11 +371,6 @@
 	gh->gh_flags = flags;
 	gh->gh_error = 0;
 	gh->gh_iflags = 0;
-	init_completion(&gh->gh_wait);
-
-	if (gh->gh_state == LM_ST_EXCLUSIVE)
-		gh->gh_flags |= GL_LOCAL_EXCL;
-
 	gfs2_glock_hold(gl);
 }
 
@@ -417,9 +388,6 @@
 {
 	gh->gh_state = state;
 	gh->gh_flags = flags;
-	if (gh->gh_state == LM_ST_EXCLUSIVE)
-		gh->gh_flags |= GL_LOCAL_EXCL;
-
 	gh->gh_iflags &= 1 << HIF_ALLOCED;
 	gh->gh_ip = (unsigned long)__builtin_return_address(0);
 }
@@ -479,6 +447,29 @@
 	kfree(gh);
 }
 
+static void gfs2_holder_dispose_or_wake(struct gfs2_holder *gh)
+{
+	if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) {
+		gfs2_holder_put(gh);
+		return;
+	}
+	clear_bit(HIF_WAIT, &gh->gh_iflags);
+	smp_mb();
+	wake_up_bit(&gh->gh_iflags, HIF_WAIT);
+}
+
+static int holder_wait(void *word)
+{
+        schedule();
+        return 0;
+}
+
+static void wait_on_holder(struct gfs2_holder *gh)
+{
+	might_sleep();
+	wait_on_bit(&gh->gh_iflags, HIF_WAIT, holder_wait, TASK_UNINTERRUPTIBLE);
+}
+
 /**
  * rq_mutex - process a mutex request in the queue
  * @gh: the glock holder
@@ -493,7 +484,9 @@
 	list_del_init(&gh->gh_list);
 	/*  gh->gh_error never examined.  */
 	set_bit(GLF_LOCK, &gl->gl_flags);
-	complete(&gh->gh_wait);
+	clear_bit(HIF_WAIT, &gh->gh_iflags);
+	smp_mb();
+	wake_up_bit(&gh->gh_iflags, HIF_WAIT);
 
 	return 1;
 }
@@ -511,7 +504,6 @@
 {
 	struct gfs2_glock *gl = gh->gh_gl;
 	struct gfs2_sbd *sdp = gl->gl_sbd;
-	const struct gfs2_glock_operations *glops = gl->gl_ops;
 
 	if (!relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) {
 		if (list_empty(&gl->gl_holders)) {
@@ -526,7 +518,7 @@
 				gfs2_reclaim_glock(sdp);
 			}
 
-			glops->go_xmote_th(gl, gh->gh_state, gh->gh_flags);
+			gfs2_glock_xmote_th(gh);
 			spin_lock(&gl->gl_spin);
 		}
 		return 1;
@@ -537,11 +529,11 @@
 		set_bit(GLF_LOCK, &gl->gl_flags);
 	} else {
 		struct gfs2_holder *next_gh;
-		if (gh->gh_flags & GL_LOCAL_EXCL)
+		if (gh->gh_state == LM_ST_EXCLUSIVE)
 			return 1;
 		next_gh = list_entry(gl->gl_holders.next, struct gfs2_holder,
 				     gh_list);
-		if (next_gh->gh_flags & GL_LOCAL_EXCL)
+		if (next_gh->gh_state == LM_ST_EXCLUSIVE)
 			 return 1;
 	}
 
@@ -549,7 +541,7 @@
 	gh->gh_error = 0;
 	set_bit(HIF_HOLDER, &gh->gh_iflags);
 
-	complete(&gh->gh_wait);
+	gfs2_holder_dispose_or_wake(gh);
 
 	return 0;
 }
@@ -564,7 +556,6 @@
 static int rq_demote(struct gfs2_holder *gh)
 {
 	struct gfs2_glock *gl = gh->gh_gl;
-	const struct gfs2_glock_operations *glops = gl->gl_ops;
 
 	if (!list_empty(&gl->gl_holders))
 		return 1;
@@ -573,10 +564,7 @@
 		list_del_init(&gh->gh_list);
 		gh->gh_error = 0;
 		spin_unlock(&gl->gl_spin);
-		if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
-			gfs2_holder_put(gh);
-		else
-			complete(&gh->gh_wait);
+		gfs2_holder_dispose_or_wake(gh);
 		spin_lock(&gl->gl_spin);
 	} else {
 		gl->gl_req_gh = gh;
@@ -585,9 +573,9 @@
 
 		if (gh->gh_state == LM_ST_UNLOCKED ||
 		    gl->gl_state != LM_ST_EXCLUSIVE)
-			glops->go_drop_th(gl);
+			gfs2_glock_drop_th(gl);
 		else
-			glops->go_xmote_th(gl, gh->gh_state, gh->gh_flags);
+			gfs2_glock_xmote_th(gh);
 
 		spin_lock(&gl->gl_spin);
 	}
@@ -596,30 +584,6 @@
 }
 
 /**
- * rq_greedy - process a queued request to drop greedy status
- * @gh: the glock holder
- *
- * Returns: 1 if the queue is blocked
- */
-
-static int rq_greedy(struct gfs2_holder *gh)
-{
-	struct gfs2_glock *gl = gh->gh_gl;
-
-	list_del_init(&gh->gh_list);
-	/*  gh->gh_error never examined.  */
-	clear_bit(GLF_GREEDY, &gl->gl_flags);
-	spin_unlock(&gl->gl_spin);
-
-	gfs2_holder_uninit(gh);
-	kfree(container_of(gh, struct greedy, gr_gh));
-
-	spin_lock(&gl->gl_spin);
-
-	return 0;
-}
-
-/**
  * run_queue - process holder structures on a glock
  * @gl: the glock
  *
@@ -649,8 +613,6 @@
 
 			if (test_bit(HIF_DEMOTE, &gh->gh_iflags))
 				blocked = rq_demote(gh);
-			else if (test_bit(HIF_GREEDY, &gh->gh_iflags))
-				blocked = rq_greedy(gh);
 			else
 				gfs2_assert_warn(gl->gl_sbd, 0);
 
@@ -684,6 +646,8 @@
 
 	gfs2_holder_init(gl, 0, 0, &gh);
 	set_bit(HIF_MUTEX, &gh.gh_iflags);
+	if (test_and_set_bit(HIF_WAIT, &gh.gh_iflags))
+		BUG();
 
 	spin_lock(&gl->gl_spin);
 	if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
@@ -691,11 +655,13 @@
 	} else {
 		gl->gl_owner = current;
 		gl->gl_ip = (unsigned long)__builtin_return_address(0);
-		complete(&gh.gh_wait);
+		clear_bit(HIF_WAIT, &gh.gh_iflags);
+		smp_mb();
+		wake_up_bit(&gh.gh_iflags, HIF_WAIT);
 	}
 	spin_unlock(&gl->gl_spin);
 
-	wait_for_completion(&gh.gh_wait);
+	wait_on_holder(&gh);
 	gfs2_holder_uninit(&gh);
 }
 
@@ -774,6 +740,7 @@
 			return;
 		set_bit(HIF_DEMOTE, &new_gh->gh_iflags);
 		set_bit(HIF_DEALLOC, &new_gh->gh_iflags);
+		set_bit(HIF_WAIT, &new_gh->gh_iflags);
 
 		goto restart;
 	}
@@ -825,7 +792,7 @@
 	int op_done = 1;
 
 	gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
-	gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
+	gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
 	gfs2_assert_warn(sdp, !(ret & LM_OUT_ASYNC));
 
 	state_change(gl, ret & LM_OUT_ST_MASK);
@@ -908,12 +875,8 @@
 
 	gfs2_glock_put(gl);
 
-	if (gh) {
-		if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
-			gfs2_holder_put(gh);
-		else
-			complete(&gh->gh_wait);
-	}
+	if (gh)
+		gfs2_holder_dispose_or_wake(gh);
 }
 
 /**
@@ -924,23 +887,26 @@
  *
  */
 
-void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags)
+void gfs2_glock_xmote_th(struct gfs2_holder *gh)
 {
+	struct gfs2_glock *gl = gh->gh_gl;
 	struct gfs2_sbd *sdp = gl->gl_sbd;
+	int flags = gh->gh_flags;
+	unsigned state = gh->gh_state;
 	const struct gfs2_glock_operations *glops = gl->gl_ops;
 	int lck_flags = flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB |
 				 LM_FLAG_NOEXP | LM_FLAG_ANY |
 				 LM_FLAG_PRIORITY);
 	unsigned int lck_ret;
 
+	if (glops->go_xmote_th)
+		glops->go_xmote_th(gl);
+
 	gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
-	gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
+	gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
 	gfs2_assert_warn(sdp, state != LM_ST_UNLOCKED);
 	gfs2_assert_warn(sdp, state != gl->gl_state);
 
-	if (gl->gl_state == LM_ST_EXCLUSIVE && glops->go_sync)
-		glops->go_sync(gl);
-
 	gfs2_glock_hold(gl);
 	gl->gl_req_bh = xmote_bh;
 
@@ -971,10 +937,8 @@
 	const struct gfs2_glock_operations *glops = gl->gl_ops;
 	struct gfs2_holder *gh = gl->gl_req_gh;
 
-	clear_bit(GLF_PREFETCH, &gl->gl_flags);
-
 	gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
-	gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
+	gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
 	gfs2_assert_warn(sdp, !ret);
 
 	state_change(gl, LM_ST_UNLOCKED);
@@ -1001,12 +965,8 @@
 
 	gfs2_glock_put(gl);
 
-	if (gh) {
-		if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
-			gfs2_holder_put(gh);
-		else
-			complete(&gh->gh_wait);
-	}
+	if (gh)
+		gfs2_holder_dispose_or_wake(gh);
 }
 
 /**
@@ -1015,18 +975,18 @@
  *
  */
 
-void gfs2_glock_drop_th(struct gfs2_glock *gl)
+static void gfs2_glock_drop_th(struct gfs2_glock *gl)
 {
 	struct gfs2_sbd *sdp = gl->gl_sbd;
 	const struct gfs2_glock_operations *glops = gl->gl_ops;
 	unsigned int ret;
 
-	gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
-	gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
-	gfs2_assert_warn(sdp, gl->gl_state != LM_ST_UNLOCKED);
+	if (glops->go_drop_th)
+		glops->go_drop_th(gl);
 
-	if (gl->gl_state == LM_ST_EXCLUSIVE && glops->go_sync)
-		glops->go_sync(gl);
+	gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
+	gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
+	gfs2_assert_warn(sdp, gl->gl_state != LM_ST_UNLOCKED);
 
 	gfs2_glock_hold(gl);
 	gl->gl_req_bh = drop_bh;
@@ -1107,8 +1067,7 @@
 	if (gh->gh_flags & LM_FLAG_PRIORITY)
 		do_cancels(gh);
 
-	wait_for_completion(&gh->gh_wait);
-
+	wait_on_holder(gh);
 	if (gh->gh_error)
 		return gh->gh_error;
 
@@ -1164,6 +1123,8 @@
 	struct gfs2_holder *existing;
 
 	BUG_ON(!gh->gh_owner);
+	if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags))
+		BUG();
 
 	existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner);
 	if (existing) {
@@ -1227,8 +1188,6 @@
 		}
 	}
 
-	clear_bit(GLF_PREFETCH, &gl->gl_flags);
-
 	return error;
 }
 
@@ -1321,98 +1280,6 @@
 }
 
 /**
- * gfs2_glock_prefetch - Try to prefetch a glock
- * @gl: the glock
- * @state: the state to prefetch in
- * @flags: flags passed to go_xmote_th()
- *
- */
-
-static void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state,
-				int flags)
-{
-	const struct gfs2_glock_operations *glops = gl->gl_ops;
-
-	spin_lock(&gl->gl_spin);
-
-	if (test_bit(GLF_LOCK, &gl->gl_flags) || !list_empty(&gl->gl_holders) ||
-	    !list_empty(&gl->gl_waiters1) || !list_empty(&gl->gl_waiters2) ||
-	    !list_empty(&gl->gl_waiters3) ||
-	    relaxed_state_ok(gl->gl_state, state, flags)) {
-		spin_unlock(&gl->gl_spin);
-		return;
-	}
-
-	set_bit(GLF_PREFETCH, &gl->gl_flags);
-	set_bit(GLF_LOCK, &gl->gl_flags);
-	spin_unlock(&gl->gl_spin);
-
-	glops->go_xmote_th(gl, state, flags);
-}
-
-static void greedy_work(struct work_struct *work)
-{
-	struct greedy *gr = container_of(work, struct greedy, gr_work.work);
-	struct gfs2_holder *gh = &gr->gr_gh;
-	struct gfs2_glock *gl = gh->gh_gl;
-	const struct gfs2_glock_operations *glops = gl->gl_ops;
-
-	clear_bit(GLF_SKIP_WAITERS2, &gl->gl_flags);
-
-	if (glops->go_greedy)
-		glops->go_greedy(gl);
-
-	spin_lock(&gl->gl_spin);
-
-	if (list_empty(&gl->gl_waiters2)) {
-		clear_bit(GLF_GREEDY, &gl->gl_flags);
-		spin_unlock(&gl->gl_spin);
-		gfs2_holder_uninit(gh);
-		kfree(gr);
-	} else {
-		gfs2_glock_hold(gl);
-		list_add_tail(&gh->gh_list, &gl->gl_waiters2);
-		run_queue(gl);
-		spin_unlock(&gl->gl_spin);
-		gfs2_glock_put(gl);
-	}
-}
-
-/**
- * gfs2_glock_be_greedy -
- * @gl:
- * @time:
- *
- * Returns: 0 if go_greedy will be called, 1 otherwise
- */
-
-int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time)
-{
-	struct greedy *gr;
-	struct gfs2_holder *gh;
-
-	if (!time || gl->gl_sbd->sd_args.ar_localcaching ||
-	    test_and_set_bit(GLF_GREEDY, &gl->gl_flags))
-		return 1;
-
-	gr = kmalloc(sizeof(struct greedy), GFP_KERNEL);
-	if (!gr) {
-		clear_bit(GLF_GREEDY, &gl->gl_flags);
-		return 1;
-	}
-	gh = &gr->gr_gh;
-
-	gfs2_holder_init(gl, 0, 0, gh);
-	set_bit(HIF_GREEDY, &gh->gh_iflags);
-	INIT_DELAYED_WORK(&gr->gr_work, greedy_work);
-
-	set_bit(GLF_SKIP_WAITERS2, &gl->gl_flags);
-	schedule_delayed_work(&gr->gr_work, time);
-
-	return 0;
-}
-
-/**
  * gfs2_glock_dq_uninit - dequeue a holder from a glock and initialize it
  * @gh: the holder structure
  *
@@ -1470,10 +1337,7 @@
 		return 1;
 	if (a->ln_number < b->ln_number)
 		return -1;
-	if (gh_a->gh_state == LM_ST_SHARED && gh_b->gh_state == LM_ST_EXCLUSIVE)
-		return 1;
-	if (!(gh_a->gh_flags & GL_LOCAL_EXCL) && (gh_b->gh_flags & GL_LOCAL_EXCL))
-		return 1;
+	BUG_ON(gh_a->gh_gl->gl_ops->go_type == gh_b->gh_gl->gl_ops->go_type);
 	return 0;
 }
 
@@ -1618,34 +1482,6 @@
 }
 
 /**
- * gfs2_glock_prefetch_num - prefetch a glock based on lock number
- * @sdp: the filesystem
- * @number: the lock number
- * @glops: the glock operations for the type of glock
- * @state: the state to acquire the glock in
- * @flags: modifier flags for the aquisition
- *
- * Returns: errno
- */
-
-void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, u64 number,
-			     const struct gfs2_glock_operations *glops,
-			     unsigned int state, int flags)
-{
-	struct gfs2_glock *gl;
-	int error;
-
-	if (atomic_read(&sdp->sd_reclaim_count) <
-	    gfs2_tune_get(sdp, gt_reclaim_limit)) {
-		error = gfs2_glock_get(sdp, number, glops, CREATE, &gl);
-		if (!error) {
-			gfs2_glock_prefetch(gl, state, flags);
-			gfs2_glock_put(gl);
-		}
-	}
-}
-
-/**
  * gfs2_lvb_hold - attach a LVB from a glock
  * @gl: The glock in question
  *
@@ -1703,8 +1539,6 @@
 	if (!gl)
 		return;
 
-	if (gl->gl_ops->go_callback)
-		gl->gl_ops->go_callback(gl, state);
 	handle_callback(gl, state);
 
 	spin_lock(&gl->gl_spin);
@@ -1746,12 +1580,14 @@
 		struct lm_async_cb *async = data;
 		struct gfs2_glock *gl;
 
+		down_read(&gfs2_umount_flush_sem);
 		gl = gfs2_glock_find(sdp, &async->lc_name);
 		if (gfs2_assert_warn(sdp, gl))
 			return;
 		if (!gfs2_assert_warn(sdp, gl->gl_req_bh))
 			gl->gl_req_bh(gl, async->lc_ret);
 		gfs2_glock_put(gl);
+		up_read(&gfs2_umount_flush_sem);
 		return;
 	}
 
@@ -1781,15 +1617,11 @@
 
 static int demote_ok(struct gfs2_glock *gl)
 {
-	struct gfs2_sbd *sdp = gl->gl_sbd;
 	const struct gfs2_glock_operations *glops = gl->gl_ops;
 	int demote = 1;
 
 	if (test_bit(GLF_STICKY, &gl->gl_flags))
 		demote = 0;
-	else if (test_bit(GLF_PREFETCH, &gl->gl_flags))
-		demote = time_after_eq(jiffies, gl->gl_stamp +
-				    gfs2_tune_get(sdp, gt_prefetch_secs) * HZ);
 	else if (glops->go_demote_ok)
 		demote = glops->go_demote_ok(gl);
 
@@ -1845,7 +1677,7 @@
 	atomic_inc(&sdp->sd_reclaimed);
 
 	if (gfs2_glmutex_trylock(gl)) {
-		if (queue_empty(gl, &gl->gl_holders) &&
+		if (list_empty(&gl->gl_holders) &&
 		    gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl))
 			handle_callback(gl, LM_ST_UNLOCKED);
 		gfs2_glmutex_unlock(gl);
@@ -1909,7 +1741,7 @@
 		return;
 
 	if (gfs2_glmutex_trylock(gl)) {
-		if (queue_empty(gl, &gl->gl_holders) &&
+		if (list_empty(&gl->gl_holders) &&
 		    gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl))
 			goto out_schedule;
 		gfs2_glmutex_unlock(gl);
@@ -1958,7 +1790,7 @@
 	}
 
 	if (gfs2_glmutex_trylock(gl)) {
-		if (queue_empty(gl, &gl->gl_holders) &&
+		if (list_empty(&gl->gl_holders) &&
 		    gl->gl_state != LM_ST_UNLOCKED)
 			handle_callback(gl, LM_ST_UNLOCKED);
 		gfs2_glmutex_unlock(gl);
@@ -2000,7 +1832,9 @@
 			t = jiffies;
 		}
 
+		down_write(&gfs2_umount_flush_sem);
 		invalidate_inodes(sdp->sd_vfs);
+		up_write(&gfs2_umount_flush_sem);
 		msleep(10);
 	}
 }
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
index fb39108..f50e40c 100644
--- a/fs/gfs2/glock.h
+++ b/fs/gfs2/glock.h
@@ -20,7 +20,6 @@
 #define LM_FLAG_ANY		0x00000008
 #define LM_FLAG_PRIORITY	0x00000010 */
 
-#define GL_LOCAL_EXCL		0x00000020
 #define GL_ASYNC		0x00000040
 #define GL_EXACT		0x00000080
 #define GL_SKIP			0x00000100
@@ -83,17 +82,11 @@
 void gfs2_holder_reinit(unsigned int state, unsigned flags,
 			struct gfs2_holder *gh);
 void gfs2_holder_uninit(struct gfs2_holder *gh);
-
-void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags);
-void gfs2_glock_drop_th(struct gfs2_glock *gl);
-
 int gfs2_glock_nq(struct gfs2_holder *gh);
 int gfs2_glock_poll(struct gfs2_holder *gh);
 int gfs2_glock_wait(struct gfs2_holder *gh);
 void gfs2_glock_dq(struct gfs2_holder *gh);
 
-int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time);
-
 void gfs2_glock_dq_uninit(struct gfs2_holder *gh);
 int gfs2_glock_nq_num(struct gfs2_sbd *sdp,
 		      u64 number, const struct gfs2_glock_operations *glops,
@@ -103,10 +96,6 @@
 void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs);
 void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs);
 
-void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, u64 number,
-			     const struct gfs2_glock_operations *glops,
-			     unsigned int state, int flags);
-
 /**
  * gfs2_glock_nq_init - intialize a holder and enqueue it on a glock
  * @gl: the glock
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index b068d10..c4b0391 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -117,12 +117,14 @@
 
 static void meta_go_sync(struct gfs2_glock *gl)
 {
+	if (gl->gl_state != LM_ST_EXCLUSIVE)
+		return;
+
 	if (test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) {
 		gfs2_log_flush(gl->gl_sbd, gl);
 		gfs2_meta_sync(gl);
 		gfs2_ail_empty_gl(gl);
 	}
-
 }
 
 /**
@@ -142,6 +144,37 @@
 }
 
 /**
+ * inode_go_sync - Sync the dirty data and/or metadata for an inode glock
+ * @gl: the glock protecting the inode
+ *
+ */
+
+static void inode_go_sync(struct gfs2_glock *gl)
+{
+	struct gfs2_inode *ip = gl->gl_object;
+
+	if (ip && !S_ISREG(ip->i_inode.i_mode))
+		ip = NULL;
+
+	if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
+		gfs2_log_flush(gl->gl_sbd, gl);
+		if (ip)
+			filemap_fdatawrite(ip->i_inode.i_mapping);
+		gfs2_meta_sync(gl);
+		if (ip) {
+			struct address_space *mapping = ip->i_inode.i_mapping;
+			int error = filemap_fdatawait(mapping);
+			if (error == -ENOSPC)
+				set_bit(AS_ENOSPC, &mapping->flags);
+			else if (error)
+				set_bit(AS_EIO, &mapping->flags);
+		}
+		clear_bit(GLF_DIRTY, &gl->gl_flags);
+		gfs2_ail_empty_gl(gl);
+	}
+}
+
+/**
  * inode_go_xmote_th - promote/demote a glock
  * @gl: the glock
  * @state: the requested state
@@ -149,12 +182,12 @@
  *
  */
 
-static void inode_go_xmote_th(struct gfs2_glock *gl, unsigned int state,
-			      int flags)
+static void inode_go_xmote_th(struct gfs2_glock *gl)
 {
 	if (gl->gl_state != LM_ST_UNLOCKED)
 		gfs2_pte_inval(gl);
-	gfs2_glock_xmote_th(gl, state, flags);
+	if (gl->gl_state == LM_ST_EXCLUSIVE)
+		inode_go_sync(gl);
 }
 
 /**
@@ -189,38 +222,8 @@
 static void inode_go_drop_th(struct gfs2_glock *gl)
 {
 	gfs2_pte_inval(gl);
-	gfs2_glock_drop_th(gl);
-}
-
-/**
- * inode_go_sync - Sync the dirty data and/or metadata for an inode glock
- * @gl: the glock protecting the inode
- *
- */
-
-static void inode_go_sync(struct gfs2_glock *gl)
-{
-	struct gfs2_inode *ip = gl->gl_object;
-
-	if (ip && !S_ISREG(ip->i_inode.i_mode))
-		ip = NULL;
-
-	if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
-		gfs2_log_flush(gl->gl_sbd, gl);
-		if (ip)
-			filemap_fdatawrite(ip->i_inode.i_mapping);
-		gfs2_meta_sync(gl);
-		if (ip) {
-			struct address_space *mapping = ip->i_inode.i_mapping;
-			int error = filemap_fdatawait(mapping);
-			if (error == -ENOSPC)
-				set_bit(AS_ENOSPC, &mapping->flags);
-			else if (error)
-				set_bit(AS_EIO, &mapping->flags);
-		}
-		clear_bit(GLF_DIRTY, &gl->gl_flags);
-		gfs2_ail_empty_gl(gl);
-	}
+	if (gl->gl_state == LM_ST_EXCLUSIVE)
+		inode_go_sync(gl);
 }
 
 /**
@@ -295,7 +298,7 @@
 
 	if ((ip->i_di.di_flags & GFS2_DIF_TRUNC_IN_PROG) &&
 	    (gl->gl_state == LM_ST_EXCLUSIVE) &&
-	    (gh->gh_flags & GL_LOCAL_EXCL))
+	    (gh->gh_state == LM_ST_EXCLUSIVE))
 		error = gfs2_truncatei_resume(ip);
 
 	return error;
@@ -319,39 +322,6 @@
 }
 
 /**
- * inode_greedy -
- * @gl: the glock
- *
- */
-
-static void inode_greedy(struct gfs2_glock *gl)
-{
-	struct gfs2_sbd *sdp = gl->gl_sbd;
-	struct gfs2_inode *ip = gl->gl_object;
-	unsigned int quantum = gfs2_tune_get(sdp, gt_greedy_quantum);
-	unsigned int max = gfs2_tune_get(sdp, gt_greedy_max);
-	unsigned int new_time;
-
-	spin_lock(&ip->i_spin);
-
-	if (time_after(ip->i_last_pfault + quantum, jiffies)) {
-		new_time = ip->i_greedy + quantum;
-		if (new_time > max)
-			new_time = max;
-	} else {
-		new_time = ip->i_greedy - quantum;
-		if (!new_time || new_time > max)
-			new_time = 1;
-	}
-
-	ip->i_greedy = new_time;
-
-	spin_unlock(&ip->i_spin);
-
-	iput(&ip->i_inode);
-}
-
-/**
  * rgrp_go_demote_ok - Check to see if it's ok to unlock a RG's glock
  * @gl: the glock
  *
@@ -398,8 +368,7 @@
  *
  */
 
-static void trans_go_xmote_th(struct gfs2_glock *gl, unsigned int state,
-			      int flags)
+static void trans_go_xmote_th(struct gfs2_glock *gl)
 {
 	struct gfs2_sbd *sdp = gl->gl_sbd;
 
@@ -408,8 +377,6 @@
 		gfs2_meta_syncfs(sdp);
 		gfs2_log_shutdown(sdp);
 	}
-
-	gfs2_glock_xmote_th(gl, state, flags);
 }
 
 /**
@@ -461,8 +428,6 @@
 		gfs2_meta_syncfs(sdp);
 		gfs2_log_shutdown(sdp);
 	}
-
-	gfs2_glock_drop_th(gl);
 }
 
 /**
@@ -478,8 +443,8 @@
 }
 
 const struct gfs2_glock_operations gfs2_meta_glops = {
-	.go_xmote_th = gfs2_glock_xmote_th,
-	.go_drop_th = gfs2_glock_drop_th,
+	.go_xmote_th = meta_go_sync,
+	.go_drop_th = meta_go_sync,
 	.go_type = LM_TYPE_META,
 };
 
@@ -487,19 +452,14 @@
 	.go_xmote_th = inode_go_xmote_th,
 	.go_xmote_bh = inode_go_xmote_bh,
 	.go_drop_th = inode_go_drop_th,
-	.go_sync = inode_go_sync,
 	.go_inval = inode_go_inval,
 	.go_demote_ok = inode_go_demote_ok,
 	.go_lock = inode_go_lock,
 	.go_unlock = inode_go_unlock,
-	.go_greedy = inode_greedy,
 	.go_type = LM_TYPE_INODE,
 };
 
 const struct gfs2_glock_operations gfs2_rgrp_glops = {
-	.go_xmote_th = gfs2_glock_xmote_th,
-	.go_drop_th = gfs2_glock_drop_th,
-	.go_sync = meta_go_sync,
 	.go_inval = meta_go_inval,
 	.go_demote_ok = rgrp_go_demote_ok,
 	.go_lock = rgrp_go_lock,
@@ -515,33 +475,23 @@
 };
 
 const struct gfs2_glock_operations gfs2_iopen_glops = {
-	.go_xmote_th = gfs2_glock_xmote_th,
-	.go_drop_th = gfs2_glock_drop_th,
 	.go_type = LM_TYPE_IOPEN,
 };
 
 const struct gfs2_glock_operations gfs2_flock_glops = {
-	.go_xmote_th = gfs2_glock_xmote_th,
-	.go_drop_th = gfs2_glock_drop_th,
 	.go_type = LM_TYPE_FLOCK,
 };
 
 const struct gfs2_glock_operations gfs2_nondisk_glops = {
-	.go_xmote_th = gfs2_glock_xmote_th,
-	.go_drop_th = gfs2_glock_drop_th,
 	.go_type = LM_TYPE_NONDISK,
 };
 
 const struct gfs2_glock_operations gfs2_quota_glops = {
-	.go_xmote_th = gfs2_glock_xmote_th,
-	.go_drop_th = gfs2_glock_drop_th,
 	.go_demote_ok = quota_go_demote_ok,
 	.go_type = LM_TYPE_QUOTA,
 };
 
 const struct gfs2_glock_operations gfs2_journal_glops = {
-	.go_xmote_th = gfs2_glock_xmote_th,
-	.go_drop_th = gfs2_glock_drop_th,
 	.go_type = LM_TYPE_JOURNAL,
 };
 
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 734421e..12c80fd 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -101,17 +101,14 @@
 };
 
 struct gfs2_glock_operations {
-	void (*go_xmote_th) (struct gfs2_glock *gl, unsigned int state, int flags);
+	void (*go_xmote_th) (struct gfs2_glock *gl);
 	void (*go_xmote_bh) (struct gfs2_glock *gl);
 	void (*go_drop_th) (struct gfs2_glock *gl);
 	void (*go_drop_bh) (struct gfs2_glock *gl);
-	void (*go_sync) (struct gfs2_glock *gl);
 	void (*go_inval) (struct gfs2_glock *gl, int flags);
 	int (*go_demote_ok) (struct gfs2_glock *gl);
 	int (*go_lock) (struct gfs2_holder *gh);
 	void (*go_unlock) (struct gfs2_holder *gh);
-	void (*go_callback) (struct gfs2_glock *gl, unsigned int state);
-	void (*go_greedy) (struct gfs2_glock *gl);
 	const int go_type;
 };
 
@@ -120,7 +117,6 @@
 	HIF_MUTEX		= 0,
 	HIF_PROMOTE		= 1,
 	HIF_DEMOTE		= 2,
-	HIF_GREEDY		= 3,
 
 	/* States */
 	HIF_ALLOCED		= 4,
@@ -128,6 +124,7 @@
 	HIF_HOLDER		= 6,
 	HIF_FIRST		= 7,
 	HIF_ABORTED		= 9,
+	HIF_WAIT		= 10,
 };
 
 struct gfs2_holder {
@@ -140,17 +137,14 @@
 
 	int gh_error;
 	unsigned long gh_iflags;
-	struct completion gh_wait;
 	unsigned long gh_ip;
 };
 
 enum {
 	GLF_LOCK		= 1,
 	GLF_STICKY		= 2,
-	GLF_PREFETCH		= 3,
 	GLF_DIRTY		= 5,
 	GLF_SKIP_WAITERS2	= 6,
-	GLF_GREEDY		= 7,
 };
 
 struct gfs2_glock {
@@ -167,7 +161,7 @@
 	unsigned long gl_ip;
 	struct list_head gl_holders;
 	struct list_head gl_waiters1;	/* HIF_MUTEX */
-	struct list_head gl_waiters2;	/* HIF_DEMOTE, HIF_GREEDY */
+	struct list_head gl_waiters2;	/* HIF_DEMOTE */
 	struct list_head gl_waiters3;	/* HIF_PROMOTE */
 
 	const struct gfs2_glock_operations *gl_ops;
@@ -236,7 +230,6 @@
 
 	spinlock_t i_spin;
 	struct rw_semaphore i_rw_mutex;
-	unsigned int i_greedy;
 	unsigned long i_last_pfault;
 
 	struct buffer_head *i_cache[GFS2_MAX_META_HEIGHT];
@@ -418,17 +411,12 @@
 	unsigned int gt_atime_quantum; /* Min secs between atime updates */
 	unsigned int gt_new_files_jdata;
 	unsigned int gt_new_files_directio;
-	unsigned int gt_max_atomic_write; /* Split big writes into this size */
 	unsigned int gt_max_readahead; /* Max bytes to read-ahead from disk */
 	unsigned int gt_lockdump_size;
 	unsigned int gt_stall_secs; /* Detects trouble! */
 	unsigned int gt_complain_secs;
 	unsigned int gt_reclaim_limit; /* Max num of glocks in reclaim list */
 	unsigned int gt_entries_per_readdir;
-	unsigned int gt_prefetch_secs; /* Usage window for prefetched glocks */
-	unsigned int gt_greedy_default;
-	unsigned int gt_greedy_quantum;
-	unsigned int gt_greedy_max;
 	unsigned int gt_statfs_quantum;
 	unsigned int gt_statfs_slow;
 };
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index d122074c..0d6831a 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -287,10 +287,8 @@
  *
  * Returns: errno
  */
-
 int gfs2_change_nlink(struct gfs2_inode *ip, int diff)
 {
-	struct gfs2_sbd *sdp = ip->i_inode.i_sb->s_fs_info;
 	struct buffer_head *dibh;
 	u32 nlink;
 	int error;
@@ -315,42 +313,34 @@
 	else
 		drop_nlink(&ip->i_inode);
 
-	ip->i_inode.i_ctime.tv_sec = get_seconds();
+	ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 
 	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
 	gfs2_dinode_out(ip, dibh->b_data);
 	brelse(dibh);
 	mark_inode_dirty(&ip->i_inode);
 
-	if (ip->i_inode.i_nlink == 0) {
-		struct gfs2_rgrpd *rgd;
-		struct gfs2_holder ri_gh, rg_gh;
-
-		error = gfs2_rindex_hold(sdp, &ri_gh);
-		if (error)
-			goto out;
-		error = -EIO;
-		rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
-		if (!rgd)
-			goto out_norgrp;
-		error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh);
-		if (error)
-			goto out_norgrp;
-
+	if (ip->i_inode.i_nlink == 0)
 		gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */
-		gfs2_glock_dq_uninit(&rg_gh);
-out_norgrp:
-		gfs2_glock_dq_uninit(&ri_gh);
-	}
-out:
+
 	return error;
 }
 
 struct inode *gfs2_lookup_simple(struct inode *dip, const char *name)
 {
 	struct qstr qstr;
+	struct inode *inode;
 	gfs2_str2qstr(&qstr, name);
-	return gfs2_lookupi(dip, &qstr, 1, NULL);
+	inode = gfs2_lookupi(dip, &qstr, 1, NULL);
+	/* gfs2_lookupi has inconsistent callers: vfs
+	 * related routines expect NULL for no entry found,
+	 * gfs2_lookup_simple callers expect ENOENT
+	 * and do not check for NULL.
+	 */
+	if (inode == NULL)
+		return ERR_PTR(-ENOENT);
+	else
+		return inode;
 }
 
 
@@ -361,8 +351,10 @@
  * @is_root: If 1, ignore the caller's permissions
  * @i_gh: An uninitialized holder for the new inode glock
  *
- * There will always be a vnode (Linux VFS inode) for the d_gh inode unless
- * @is_root is true.
+ * This can be called via the VFS filldir function when NFS is doing
+ * a readdirplus and the inode which its intending to stat isn't
+ * already in cache. In this case we must not take the directory glock
+ * again, since the readdir call will have already taken that lock.
  *
  * Returns: errno
  */
@@ -375,8 +367,9 @@
 	struct gfs2_holder d_gh;
 	struct gfs2_inum_host inum;
 	unsigned int type;
-	int error = 0;
+	int error;
 	struct inode *inode = NULL;
+	int unlock = 0;
 
 	if (!name->len || name->len > GFS2_FNAMESIZE)
 		return ERR_PTR(-ENAMETOOLONG);
@@ -388,9 +381,12 @@
 		return dir;
 	}
 
-	error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
-	if (error)
-		return ERR_PTR(error);
+	if (gfs2_glock_is_locked_by_me(dip->i_gl) == 0) {
+		error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
+		if (error)
+			return ERR_PTR(error);
+		unlock = 1;
+	}
 
 	if (!is_root) {
 		error = permission(dir, MAY_EXEC, NULL);
@@ -405,10 +401,11 @@
 	inode = gfs2_inode_lookup(sb, &inum, type);
 
 out:
-	gfs2_glock_dq_uninit(&d_gh);
+	if (unlock)
+		gfs2_glock_dq_uninit(&d_gh);
 	if (error == -ENOENT)
 		return NULL;
-	return inode;
+	return inode ? inode : ERR_PTR(error);
 }
 
 static int pick_formal_ino_1(struct gfs2_sbd *sdp, u64 *formal_ino)
diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c
index effe4a3..e30673d 100644
--- a/fs/gfs2/lm.c
+++ b/fs/gfs2/lm.c
@@ -104,15 +104,9 @@
 	vprintk(fmt, args);
 	va_end(args);
 
-	fs_err(sdp, "about to withdraw from the cluster\n");
+	fs_err(sdp, "about to withdraw this file system\n");
 	BUG_ON(sdp->sd_args.ar_debug);
 
-
-	fs_err(sdp, "waiting for outstanding I/O\n");
-
-	/* FIXME: suspend dm device so oustanding bio's complete
-	   and all further io requests fail */
-
 	fs_err(sdp, "telling LM to withdraw\n");
 	gfs2_withdraw_lockproto(&sdp->sd_lockstruct);
 	fs_err(sdp, "withdrawn\n");
diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h
index 33af707..a87c7bf 100644
--- a/fs/gfs2/locking/dlm/lock_dlm.h
+++ b/fs/gfs2/locking/dlm/lock_dlm.h
@@ -36,7 +36,7 @@
 
 #define GDLM_STRNAME_BYTES	24
 #define GDLM_LVB_SIZE		32
-#define GDLM_DROP_COUNT		50000
+#define GDLM_DROP_COUNT		200000
 #define GDLM_DROP_PERIOD	60
 #define GDLM_NAME_LEN		128
 
diff --git a/fs/gfs2/locking/dlm/main.c b/fs/gfs2/locking/dlm/main.c
index 2194b1d..a0e7eda 100644
--- a/fs/gfs2/locking/dlm/main.c
+++ b/fs/gfs2/locking/dlm/main.c
@@ -11,9 +11,6 @@
 
 #include "lock_dlm.h"
 
-extern int gdlm_drop_count;
-extern int gdlm_drop_period;
-
 extern struct lm_lockops gdlm_ops;
 
 static int __init init_lock_dlm(void)
@@ -40,9 +37,6 @@
 		return error;
 	}
 
-	gdlm_drop_count = GDLM_DROP_COUNT;
-	gdlm_drop_period = GDLM_DROP_PERIOD;
-
 	printk(KERN_INFO
 	       "Lock_DLM (built %s %s) installed\n", __DATE__, __TIME__);
 	return 0;
diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c
index cdd1694..1d8faa3 100644
--- a/fs/gfs2/locking/dlm/mount.c
+++ b/fs/gfs2/locking/dlm/mount.c
@@ -9,8 +9,6 @@
 
 #include "lock_dlm.h"
 
-int gdlm_drop_count;
-int gdlm_drop_period;
 const struct lm_lockops gdlm_ops;
 
 
@@ -24,8 +22,8 @@
 	if (!ls)
 		return NULL;
 
-	ls->drop_locks_count = gdlm_drop_count;
-	ls->drop_locks_period = gdlm_drop_period;
+	ls->drop_locks_count = GDLM_DROP_COUNT;
+	ls->drop_locks_period = GDLM_DROP_PERIOD;
 	ls->fscb = cb;
 	ls->sdp = sdp;
 	ls->fsflags = flags;
diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c
index 29ae06f..4746b88 100644
--- a/fs/gfs2/locking/dlm/sysfs.c
+++ b/fs/gfs2/locking/dlm/sysfs.c
@@ -116,6 +116,17 @@
 	return sprintf(buf, "%d\n", ls->recover_jid_status);
 }
 
+static ssize_t drop_count_show(struct gdlm_ls *ls, char *buf)
+{
+	return sprintf(buf, "%d\n", ls->drop_locks_count);
+}
+
+static ssize_t drop_count_store(struct gdlm_ls *ls, const char *buf, size_t len)
+{
+	ls->drop_locks_count = simple_strtol(buf, NULL, 0);
+	return len;
+}
+
 struct gdlm_attr {
 	struct attribute attr;
 	ssize_t (*show)(struct gdlm_ls *, char *);
@@ -135,6 +146,7 @@
 GDLM_ATTR(recover,        0644, recover_show,        recover_store);
 GDLM_ATTR(recover_done,   0444, recover_done_show,   NULL);
 GDLM_ATTR(recover_status, 0444, recover_status_show, NULL);
+GDLM_ATTR(drop_count,     0644, drop_count_show,     drop_count_store);
 
 static struct attribute *gdlm_attrs[] = {
 	&gdlm_attr_proto_name.attr,
@@ -147,6 +159,7 @@
 	&gdlm_attr_recover.attr,
 	&gdlm_attr_recover_done.attr,
 	&gdlm_attr_recover_status.attr,
+	&gdlm_attr_drop_count.attr,
 	NULL,
 };
 
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 4d7f94d..16bb4b4 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -69,13 +69,16 @@
 	struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le);
 	struct gfs2_trans *tr;
 
-	if (!list_empty(&bd->bd_list_tr))
+	gfs2_log_lock(sdp);
+	if (!list_empty(&bd->bd_list_tr)) {
+		gfs2_log_unlock(sdp);
 		return;
-
+	}
 	tr = current->journal_info;
 	tr->tr_touched = 1;
 	tr->tr_num_buf++;
 	list_add(&bd->bd_list_tr, &tr->tr_list_buf);
+	gfs2_log_unlock(sdp);
 
 	if (!list_empty(&le->le_list))
 		return;
@@ -84,7 +87,6 @@
 
 	gfs2_meta_check(sdp, bd->bd_bh);
 	gfs2_pin(sdp, bd->bd_bh);
-
 	gfs2_log_lock(sdp);
 	sdp->sd_log_num_buf++;
 	list_add(&le->le_list, &sdp->sd_log_le_buf);
@@ -98,11 +100,13 @@
 	struct list_head *head = &tr->tr_list_buf;
 	struct gfs2_bufdata *bd;
 
+	gfs2_log_lock(sdp);
 	while (!list_empty(head)) {
 		bd = list_entry(head->next, struct gfs2_bufdata, bd_list_tr);
 		list_del_init(&bd->bd_list_tr);
 		tr->tr_num_buf--;
 	}
+	gfs2_log_unlock(sdp);
 	gfs2_assert_warn(sdp, !tr->tr_num_buf);
 }
 
@@ -462,13 +466,17 @@
 	struct address_space *mapping = bd->bd_bh->b_page->mapping;
 	struct gfs2_inode *ip = GFS2_I(mapping->host);
 
+	gfs2_log_lock(sdp);
 	tr->tr_touched = 1;
 	if (list_empty(&bd->bd_list_tr) &&
 	    (ip->i_di.di_flags & GFS2_DIF_JDATA)) {
 		tr->tr_num_buf++;
 		list_add(&bd->bd_list_tr, &tr->tr_list_buf);
+		gfs2_log_unlock(sdp);
 		gfs2_pin(sdp, bd->bd_bh);
 		tr->tr_num_buf_new++;
+	} else {
+		gfs2_log_unlock(sdp);
 	}
 	gfs2_trans_add_gl(bd->bd_gl);
 	gfs2_log_lock(sdp);
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index d8d69a7..56e3359 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -16,6 +16,7 @@
 #include <linux/pagevec.h>
 #include <linux/mpage.h>
 #include <linux/fs.h>
+#include <linux/writeback.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/lm_interface.h>
 
@@ -157,6 +158,32 @@
 }
 
 /**
+ * gfs2_writepages - Write a bunch of dirty pages back to disk
+ * @mapping: The mapping to write
+ * @wbc: Write-back control
+ *
+ * For journaled files and/or ordered writes this just falls back to the
+ * kernel's default writepages path for now. We will probably want to change
+ * that eventually (i.e. when we look at allocate on flush).
+ *
+ * For the data=writeback case though we can already ignore buffer heads
+ * and write whole extents at once. This is a big reduction in the
+ * number of I/O requests we send and the bmap calls we make in this case.
+ */
+static int gfs2_writepages(struct address_space *mapping,
+			   struct writeback_control *wbc)
+{
+	struct inode *inode = mapping->host;
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
+
+	if (sdp->sd_args.ar_data == GFS2_DATA_WRITEBACK && !gfs2_is_jdata(ip))
+		return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc);
+
+	return generic_writepages(mapping, wbc);
+}
+
+/**
  * stuffed_readpage - Fill in a Linux page with stuffed file data
  * @ip: the inode
  * @page: the page
@@ -256,7 +283,7 @@
  *    the page lock and the glock) and return having done no I/O. Its
  *    obviously not something we'd want to do on too regular a basis.
  *    Any I/O we ignore at this time will be done via readpage later.
- * 2. We have to handle stuffed files here too.
+ * 2. We don't handle stuffed files here we let readpage do the honours.
  * 3. mpage_readpages() does most of the heavy lifting in the common case.
  * 4. gfs2_get_block() is relied upon to set BH_Boundary in the right places.
  * 5. We use LM_FLAG_TRY_1CB here, effectively we then have lock-ahead as
@@ -269,8 +296,7 @@
 	struct gfs2_inode *ip = GFS2_I(inode);
 	struct gfs2_sbd *sdp = GFS2_SB(inode);
 	struct gfs2_holder gh;
-	unsigned page_idx;
-	int ret;
+	int ret = 0;
 	int do_unlock = 0;
 
 	if (likely(file != &gfs2_internal_file_sentinel)) {
@@ -289,29 +315,8 @@
 			goto out_unlock;
 	}
 skip_lock:
-	if (gfs2_is_stuffed(ip)) {
-		struct pagevec lru_pvec;
-		pagevec_init(&lru_pvec, 0);
-		for (page_idx = 0; page_idx < nr_pages; page_idx++) {
-			struct page *page = list_entry(pages->prev, struct page, lru);
-			prefetchw(&page->flags);
-			list_del(&page->lru);
-			if (!add_to_page_cache(page, mapping,
-					       page->index, GFP_KERNEL)) {
-				ret = stuffed_readpage(ip, page);
-				unlock_page(page);
-				if (!pagevec_add(&lru_pvec, page))
-					 __pagevec_lru_add(&lru_pvec);
-			} else {
-				page_cache_release(page);
-			}
-		}
-		pagevec_lru_add(&lru_pvec);
-		ret = 0;
-	} else {
-		/* What we really want to do .... */
+	if (!gfs2_is_stuffed(ip))
 		ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block);
-	}
 
 	if (do_unlock) {
 		gfs2_glock_dq_m(1, &gh);
@@ -356,8 +361,10 @@
 	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME|LM_FLAG_TRY_1CB, &ip->i_gh);
 	error = gfs2_glock_nq_atime(&ip->i_gh);
 	if (unlikely(error)) {
-		if (error == GLR_TRYFAILED)
+		if (error == GLR_TRYFAILED) {
+			unlock_page(page);
 			error = AOP_TRUNCATED_PAGE;
+		}
 		goto out_uninit;
 	}
 
@@ -594,6 +601,36 @@
 	return;
 }
 
+/**
+ * gfs2_ok_for_dio - check that dio is valid on this file
+ * @ip: The inode
+ * @rw: READ or WRITE
+ * @offset: The offset at which we are reading or writing
+ *
+ * Returns: 0 (to ignore the i/o request and thus fall back to buffered i/o)
+ *          1 (to accept the i/o request)
+ */
+static int gfs2_ok_for_dio(struct gfs2_inode *ip, int rw, loff_t offset)
+{
+	/*
+	 * Should we return an error here? I can't see that O_DIRECT for
+	 * a journaled file makes any sense. For now we'll silently fall
+	 * back to buffered I/O, likewise we do the same for stuffed
+	 * files since they are (a) small and (b) unaligned.
+	 */
+	if (gfs2_is_jdata(ip))
+		return 0;
+
+	if (gfs2_is_stuffed(ip))
+		return 0;
+
+	if (offset > i_size_read(&ip->i_inode))
+		return 0;
+	return 1;
+}
+
+
+
 static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
 			      const struct iovec *iov, loff_t offset,
 			      unsigned long nr_segs)
@@ -604,42 +641,28 @@
 	struct gfs2_holder gh;
 	int rv;
 
-	if (rw == READ)
-		mutex_lock(&inode->i_mutex);
 	/*
-	 * Shared lock, even if its a write, since we do no allocation
-	 * on this path. All we need change is atime.
+	 * Deferred lock, even if its a write, since we do no allocation
+	 * on this path. All we need change is atime, and this lock mode
+	 * ensures that other nodes have flushed their buffered read caches
+	 * (i.e. their page cache entries for this inode). We do not,
+	 * unfortunately have the option of only flushing a range like
+	 * the VFS does.
 	 */
-	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
+	gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, GL_ATIME, &gh);
 	rv = gfs2_glock_nq_atime(&gh);
 	if (rv)
-		goto out;
+		return rv;
+	rv = gfs2_ok_for_dio(ip, rw, offset);
+	if (rv != 1)
+		goto out; /* dio not valid, fall back to buffered i/o */
 
-	if (offset > i_size_read(inode))
-		goto out;
-
-	/*
-	 * Should we return an error here? I can't see that O_DIRECT for
-	 * a journaled file makes any sense. For now we'll silently fall
-	 * back to buffered I/O, likewise we do the same for stuffed
-	 * files since they are (a) small and (b) unaligned.
-	 */
-	if (gfs2_is_jdata(ip))
-		goto out;
-
-	if (gfs2_is_stuffed(ip))
-		goto out;
-
-	rv = blockdev_direct_IO_own_locking(rw, iocb, inode,
-					    inode->i_sb->s_bdev,
-					    iov, offset, nr_segs,
-					    gfs2_get_block_direct, NULL);
+	rv = blockdev_direct_IO_no_locking(rw, iocb, inode, inode->i_sb->s_bdev,
+					   iov, offset, nr_segs,
+					   gfs2_get_block_direct, NULL);
 out:
 	gfs2_glock_dq_m(1, &gh);
 	gfs2_holder_uninit(&gh);
-	if (rw == READ)
-		mutex_unlock(&inode->i_mutex);
-
 	return rv;
 }
 
@@ -763,6 +786,7 @@
 
 const struct address_space_operations gfs2_file_aops = {
 	.writepage = gfs2_writepage,
+	.writepages = gfs2_writepages,
 	.readpage = gfs2_readpage,
 	.readpages = gfs2_readpages,
 	.sync_page = block_sync_page,
diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c
index d355899..9187eb1 100644
--- a/fs/gfs2/ops_dentry.c
+++ b/fs/gfs2/ops_dentry.c
@@ -46,6 +46,7 @@
 	struct gfs2_inum_host inum;
 	unsigned int type;
 	int error;
+	int had_lock=0;
 
 	if (inode && is_bad_inode(inode))
 		goto invalid;
@@ -53,9 +54,12 @@
 	if (sdp->sd_args.ar_localcaching)
 		goto valid;
 
-	error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
-	if (error)
-		goto fail;
+	had_lock = gfs2_glock_is_locked_by_me(dip->i_gl);
+	if (!had_lock) {
+		error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
+		if (error)
+			goto fail;
+	} 
 
 	error = gfs2_dir_search(parent->d_inode, &dentry->d_name, &inum, &type);
 	switch (error) {
@@ -82,13 +86,15 @@
 	}
 
 valid_gunlock:
-	gfs2_glock_dq_uninit(&d_gh);
+	if (!had_lock)
+		gfs2_glock_dq_uninit(&d_gh);
 valid:
 	dput(parent);
 	return 1;
 
 invalid_gunlock:
-	gfs2_glock_dq_uninit(&d_gh);
+	if (!had_lock)
+		gfs2_glock_dq_uninit(&d_gh);
 invalid:
 	if (inode && S_ISDIR(inode->i_mode)) {
 		if (have_submounts(dentry))
diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c
index b4e7b87..4855e8c 100644
--- a/fs/gfs2/ops_export.c
+++ b/fs/gfs2/ops_export.c
@@ -22,6 +22,7 @@
 #include "glock.h"
 #include "glops.h"
 #include "inode.h"
+#include "ops_dentry.h"
 #include "ops_export.h"
 #include "rgrp.h"
 #include "util.h"
@@ -112,13 +113,12 @@
 	char *name;
 };
 
-static int get_name_filldir(void *opaque, const char *name, unsigned int length,
-			    u64 offset, struct gfs2_inum_host *inum,
-			    unsigned int type)
+static int get_name_filldir(void *opaque, const char *name, int length,
+			    loff_t offset, u64 inum, unsigned int type)
 {
-	struct get_name_filldir *gnfd = (struct get_name_filldir *)opaque;
+	struct get_name_filldir *gnfd = opaque;
 
-	if (!gfs2_inum_equal(inum, &gnfd->inum))
+	if (inum != gnfd->inum.no_addr)
 		return 0;
 
 	memcpy(gnfd->name, name, length);
@@ -189,6 +189,7 @@
 		return ERR_PTR(-ENOMEM);
 	}
 
+	dentry->d_op = &gfs2_dops;
 	return dentry;
 }
 
@@ -215,8 +216,7 @@
 	}
 
 	error = gfs2_glock_nq_num(sdp, inum->no_addr, &gfs2_inode_glops,
-				  LM_ST_SHARED, LM_FLAG_ANY | GL_LOCAL_EXCL,
-				  &i_gh);
+				  LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
 	if (error)
 		return ERR_PTR(error);
 
@@ -269,6 +269,7 @@
 		return ERR_PTR(-ENOMEM);
 	}
 
+	dentry->d_op = &gfs2_dops;
 	return dentry;
 
 fail_rgd:
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
index faa07e4..c996aa7 100644
--- a/fs/gfs2/ops_file.c
+++ b/fs/gfs2/ops_file.c
@@ -43,15 +43,6 @@
 #include "util.h"
 #include "eaops.h"
 
-/* For regular, non-NFS */
-struct filldir_reg {
-	struct gfs2_sbd *fdr_sbd;
-	int fdr_prefetch;
-
-	filldir_t fdr_filldir;
-	void *fdr_opaque;
-};
-
 /*
  * Most fields left uninitialised to catch anybody who tries to
  * use them. f_flags set to prevent file_accessed() from touching
@@ -128,41 +119,6 @@
 }
 
 /**
- * filldir_func - Report a directory entry to the caller of gfs2_dir_read()
- * @opaque: opaque data used by the function
- * @name: the name of the directory entry
- * @length: the length of the name
- * @offset: the entry's offset in the directory
- * @inum: the inode number the entry points to
- * @type: the type of inode the entry points to
- *
- * Returns: 0 on success, 1 if buffer full
- */
-
-static int filldir_func(void *opaque, const char *name, unsigned int length,
-			u64 offset, struct gfs2_inum_host *inum,
-			unsigned int type)
-{
-	struct filldir_reg *fdr = (struct filldir_reg *)opaque;
-	struct gfs2_sbd *sdp = fdr->fdr_sbd;
-	int error;
-
-	error = fdr->fdr_filldir(fdr->fdr_opaque, name, length, offset,
-				 inum->no_addr, type);
-	if (error)
-		return 1;
-
-	if (fdr->fdr_prefetch && !(length == 1 && *name == '.')) {
-		gfs2_glock_prefetch_num(sdp, inum->no_addr, &gfs2_inode_glops,
-				       LM_ST_SHARED, LM_FLAG_TRY | LM_FLAG_ANY);
-		gfs2_glock_prefetch_num(sdp, inum->no_addr, &gfs2_iopen_glops,
-				       LM_ST_SHARED, LM_FLAG_TRY);
-	}
-
-	return 0;
-}
-
-/**
  * gfs2_readdir - Read directory entries from a directory
  * @file: The directory to read from
  * @dirent: Buffer for dirents
@@ -175,16 +131,10 @@
 {
 	struct inode *dir = file->f_mapping->host;
 	struct gfs2_inode *dip = GFS2_I(dir);
-	struct filldir_reg fdr;
 	struct gfs2_holder d_gh;
 	u64 offset = file->f_pos;
 	int error;
 
-	fdr.fdr_sbd = GFS2_SB(dir);
-	fdr.fdr_prefetch = 1;
-	fdr.fdr_filldir = filldir;
-	fdr.fdr_opaque = dirent;
-
 	gfs2_holder_init(dip->i_gl, LM_ST_SHARED, GL_ATIME, &d_gh);
 	error = gfs2_glock_nq_atime(&d_gh);
 	if (error) {
@@ -192,7 +142,7 @@
 		return error;
 	}
 
-	error = gfs2_dir_read(dir, &offset, &fdr, filldir_func);
+	error = gfs2_dir_read(dir, &offset, dirent, filldir);
 
 	gfs2_glock_dq_uninit(&d_gh);
 
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
index 636dda4..f40a848 100644
--- a/fs/gfs2/ops_inode.c
+++ b/fs/gfs2/ops_inode.c
@@ -264,13 +264,23 @@
 	struct gfs2_inode *dip = GFS2_I(dir);
 	struct gfs2_sbd *sdp = GFS2_SB(dir);
 	struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
-	struct gfs2_holder ghs[2];
+	struct gfs2_holder ghs[3];
+	struct gfs2_rgrpd *rgd;
+	struct gfs2_holder ri_gh;
 	int error;
 
-	gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
-	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
+	error = gfs2_rindex_hold(sdp, &ri_gh);
+	if (error)
+		return error;
 
-	error = gfs2_glock_nq_m(2, ghs);
+	gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
+	gfs2_holder_init(ip->i_gl,  LM_ST_EXCLUSIVE, 0, ghs + 1);
+
+	rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
+	gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2);
+
+
+	error = gfs2_glock_nq_m(3, ghs);
 	if (error)
 		goto out;
 
@@ -291,10 +301,12 @@
 out_end_trans:
 	gfs2_trans_end(sdp);
 out_gunlock:
-	gfs2_glock_dq_m(2, ghs);
+	gfs2_glock_dq_m(3, ghs);
 out:
 	gfs2_holder_uninit(ghs);
 	gfs2_holder_uninit(ghs + 1);
+	gfs2_holder_uninit(ghs + 2);
+	gfs2_glock_dq_uninit(&ri_gh);
 	return error;
 }
 
@@ -449,13 +461,22 @@
 	struct gfs2_inode *dip = GFS2_I(dir);
 	struct gfs2_sbd *sdp = GFS2_SB(dir);
 	struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
-	struct gfs2_holder ghs[2];
+	struct gfs2_holder ghs[3];
+	struct gfs2_rgrpd *rgd;
+	struct gfs2_holder ri_gh;
 	int error;
 
+
+	error = gfs2_rindex_hold(sdp, &ri_gh);
+	if (error)
+		return error;
 	gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
 	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
 
-	error = gfs2_glock_nq_m(2, ghs);
+	rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
+	gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2);
+
+	error = gfs2_glock_nq_m(3, ghs);
 	if (error)
 		goto out;
 
@@ -483,10 +504,12 @@
 	gfs2_trans_end(sdp);
 
 out_gunlock:
-	gfs2_glock_dq_m(2, ghs);
+	gfs2_glock_dq_m(3, ghs);
 out:
 	gfs2_holder_uninit(ghs);
 	gfs2_holder_uninit(ghs + 1);
+	gfs2_holder_uninit(ghs + 2);
+	gfs2_glock_dq_uninit(&ri_gh);
 	return error;
 }
 
@@ -547,7 +570,8 @@
 	struct gfs2_inode *ip = GFS2_I(odentry->d_inode);
 	struct gfs2_inode *nip = NULL;
 	struct gfs2_sbd *sdp = GFS2_SB(odir);
-	struct gfs2_holder ghs[4], r_gh;
+	struct gfs2_holder ghs[5], r_gh;
+	struct gfs2_rgrpd *nrgd;
 	unsigned int num_gh;
 	int dir_rename = 0;
 	int alloc_required;
@@ -587,6 +611,13 @@
 	if (nip) {
 		gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);
 		num_gh++;
+		/* grab the resource lock for unlink flag twiddling 
+		 * this is the case of the target file already existing
+		 * so we unlink before doing the rename
+		 */
+		nrgd = gfs2_blk2rgrpd(sdp, nip->i_num.no_addr);
+		if (nrgd)
+			gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++);
 	}
 
 	error = gfs2_glock_nq_m(num_gh, ghs);
@@ -684,12 +715,12 @@
 		error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
 					 al->al_rgd->rd_ri.ri_length +
 					 4 * RES_DINODE + 4 * RES_LEAF +
-					 RES_STATFS + RES_QUOTA, 0);
+					 RES_STATFS + RES_QUOTA + 4, 0);
 		if (error)
 			goto out_ipreserv;
 	} else {
 		error = gfs2_trans_begin(sdp, 4 * RES_DINODE +
-					 5 * RES_LEAF, 0);
+					 5 * RES_LEAF + 4, 0);
 		if (error)
 			goto out_gunlock;
 	}
@@ -728,7 +759,7 @@
 		error = gfs2_meta_inode_buffer(ip, &dibh);
 		if (error)
 			goto out_end_trans;
-		ip->i_inode.i_ctime.tv_sec = get_seconds();
+		ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
 		gfs2_dinode_out(ip, dibh->b_data);
 		brelse(dibh);
@@ -1018,7 +1049,7 @@
 	}
 
 	generic_fillattr(inode, stat);
-	if (unlock);
+	if (unlock)
 		gfs2_glock_dq_uninit(&gh);
 
 	return 0;
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c
index 7685b46..47369d0 100644
--- a/fs/gfs2/ops_super.c
+++ b/fs/gfs2/ops_super.c
@@ -173,6 +173,9 @@
 	struct gfs2_sbd *sdp = sb->s_fs_info;
 	int error;
 
+	if (test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
+		return;
+
 	for (;;) {
 		error = gfs2_freeze_fs(sdp);
 		if (!error)
@@ -426,6 +429,12 @@
 	}
 
 	error = gfs2_dinode_dealloc(ip);
+	/*
+	 * Must do this before unlock to avoid trying to write back
+	 * potentially dirty data now that inode no longer exists
+	 * on disk.
+	 */
+	truncate_inode_pages(&inode->i_data, 0);
 
 out_unlock:
 	gfs2_glock_dq(&ip->i_iopen_gh);
@@ -443,14 +452,12 @@
 
 static struct inode *gfs2_alloc_inode(struct super_block *sb)
 {
-	struct gfs2_sbd *sdp = sb->s_fs_info;
 	struct gfs2_inode *ip;
 
 	ip = kmem_cache_alloc(gfs2_inode_cachep, GFP_KERNEL);
 	if (ip) {
 		ip->i_flags = 0;
 		ip->i_gl = NULL;
-		ip->i_greedy = gfs2_tune_get(sdp, gt_greedy_default);
 		ip->i_last_pfault = jiffies;
 	}
 	return &ip->i_inode;
diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c
index 45a5f11..14b380f 100644
--- a/fs/gfs2/ops_vm.c
+++ b/fs/gfs2/ops_vm.c
@@ -28,34 +28,13 @@
 #include "trans.h"
 #include "util.h"
 
-static void pfault_be_greedy(struct gfs2_inode *ip)
-{
-	unsigned int time;
-
-	spin_lock(&ip->i_spin);
-	time = ip->i_greedy;
-	ip->i_last_pfault = jiffies;
-	spin_unlock(&ip->i_spin);
-
-	igrab(&ip->i_inode);
-	if (gfs2_glock_be_greedy(ip->i_gl, time))
-		iput(&ip->i_inode);
-}
-
 static struct page *gfs2_private_nopage(struct vm_area_struct *area,
 					unsigned long address, int *type)
 {
 	struct gfs2_inode *ip = GFS2_I(area->vm_file->f_mapping->host);
-	struct page *result;
 
 	set_bit(GIF_PAGED, &ip->i_flags);
-
-	result = filemap_nopage(area, address, type);
-
-	if (result && result != NOPAGE_OOM)
-		pfault_be_greedy(ip);
-
-	return result;
+	return filemap_nopage(area, address, type);
 }
 
 static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
@@ -167,7 +146,6 @@
 		set_page_dirty(result);
 	}
 
-	pfault_be_greedy(ip);
 out:
 	gfs2_glock_dq_uninit(&i_gh);
 
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 43a24f2..70f424f 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -71,17 +71,12 @@
 	gt->gt_atime_quantum = 3600;
 	gt->gt_new_files_jdata = 0;
 	gt->gt_new_files_directio = 0;
-	gt->gt_max_atomic_write = 4 << 20;
 	gt->gt_max_readahead = 1 << 18;
 	gt->gt_lockdump_size = 131072;
 	gt->gt_stall_secs = 600;
 	gt->gt_complain_secs = 10;
 	gt->gt_reclaim_limit = 5000;
 	gt->gt_entries_per_readdir = 32;
-	gt->gt_prefetch_secs = 10;
-	gt->gt_greedy_default = HZ / 10;
-	gt->gt_greedy_quantum = HZ / 40;
-	gt->gt_greedy_max = HZ / 4;
 	gt->gt_statfs_quantum = 30;
 	gt->gt_statfs_slow = 0;
 }
@@ -359,8 +354,7 @@
 	mutex_lock(&sdp->sd_jindex_mutex);
 
 	for (;;) {
-		error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED,
-					   GL_LOCAL_EXCL, ji_gh);
+		error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, ji_gh);
 		if (error)
 			break;
 
@@ -529,8 +523,7 @@
 	struct gfs2_log_header_host head;
 	int error;
 
-	error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED,
-				   GL_LOCAL_EXCL, &t_gh);
+	error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, 0, &t_gh);
 	if (error)
 		return error;
 
@@ -583,9 +576,8 @@
 	gfs2_quota_sync(sdp);
 	gfs2_statfs_sync(sdp);
 
-	error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED,
-				GL_LOCAL_EXCL | GL_NOCACHE,
-				&t_gh);
+	error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, GL_NOCACHE,
+				   &t_gh);
 	if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
 		return error;
 
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
index 983eaf1..d01f9f0 100644
--- a/fs/gfs2/sys.c
+++ b/fs/gfs2/sys.c
@@ -436,17 +436,12 @@
 TUNE_ATTR(max_readahead, 0);
 TUNE_ATTR(complain_secs, 0);
 TUNE_ATTR(reclaim_limit, 0);
-TUNE_ATTR(prefetch_secs, 0);
 TUNE_ATTR(statfs_slow, 0);
 TUNE_ATTR(new_files_jdata, 0);
 TUNE_ATTR(new_files_directio, 0);
 TUNE_ATTR(quota_simul_sync, 1);
 TUNE_ATTR(quota_cache_secs, 1);
-TUNE_ATTR(max_atomic_write, 1);
 TUNE_ATTR(stall_secs, 1);
-TUNE_ATTR(greedy_default, 1);
-TUNE_ATTR(greedy_quantum, 1);
-TUNE_ATTR(greedy_max, 1);
 TUNE_ATTR(statfs_quantum, 1);
 TUNE_ATTR_DAEMON(scand_secs, scand_process);
 TUNE_ATTR_DAEMON(recoverd_secs, recoverd_process);
@@ -465,15 +460,10 @@
 	&tune_attr_max_readahead.attr,
 	&tune_attr_complain_secs.attr,
 	&tune_attr_reclaim_limit.attr,
-	&tune_attr_prefetch_secs.attr,
 	&tune_attr_statfs_slow.attr,
 	&tune_attr_quota_simul_sync.attr,
 	&tune_attr_quota_cache_secs.attr,
-	&tune_attr_max_atomic_write.attr,
 	&tune_attr_stall_secs.attr,
-	&tune_attr_greedy_default.attr,
-	&tune_attr_greedy_quantum.attr,
-	&tune_attr_greedy_max.attr,
 	&tune_attr_statfs_quantum.attr,
 	&tune_attr_scand_secs.attr,
 	&tune_attr_recoverd_secs.attr,
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 4f4cd13..e6bd553 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -449,10 +449,13 @@
 }
 
 /*
- * For direct-IO reads into hugetlb pages
+ * mark the head page dirty
  */
 static int hugetlbfs_set_page_dirty(struct page *page)
 {
+	struct page *head = (struct page *)page_private(page);
+
+	SetPageDirty(head);
 	return 0;
 }
 
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
index f571911..e285022 100644
--- a/fs/jfs/inode.c
+++ b/fs/jfs/inode.c
@@ -182,9 +182,9 @@
 	 * Take appropriate lock on inode
 	 */
 	if (create)
-		IWRITE_LOCK(ip);
+		IWRITE_LOCK(ip, RDWRLOCK_NORMAL);
 	else
-		IREAD_LOCK(ip);
+		IREAD_LOCK(ip, RDWRLOCK_NORMAL);
 
 	if (((lblock64 << ip->i_sb->s_blocksize_bits) < ip->i_size) &&
 	    (!xtLookup(ip, lblock64, xlen, &xflag, &xaddr, &xlen, 0)) &&
@@ -359,7 +359,7 @@
 
 	nobh_truncate_page(ip->i_mapping, ip->i_size);
 
-	IWRITE_LOCK(ip);
+	IWRITE_LOCK(ip, RDWRLOCK_NORMAL);
 	jfs_truncate_nolock(ip, ip->i_size);
 	IWRITE_UNLOCK(ip);
 }
diff --git a/fs/jfs/jfs_debug.h b/fs/jfs/jfs_debug.h
index ddffbbd..7378798 100644
--- a/fs/jfs/jfs_debug.h
+++ b/fs/jfs/jfs_debug.h
@@ -39,10 +39,6 @@
 /*
  *	assert with traditional printf/panic
  */
-#ifdef CONFIG_KERNEL_ASSERTS
-/* kgdb stuff */
-#define assert(p) KERNEL_ASSERT(#p, p)
-#else
 #define assert(p) do {	\
 	if (!(p)) {	\
 		printk(KERN_CRIT "BUG at %s:%d assert(%s)\n",	\
@@ -50,7 +46,6 @@
 		BUG();	\
 	}		\
 } while (0)
-#endif
 
 /*
  *	debug ON
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
index 23546c8..82b0544 100644
--- a/fs/jfs/jfs_dmap.c
+++ b/fs/jfs/jfs_dmap.c
@@ -337,7 +337,7 @@
 	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
 	struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
 
-	IREAD_LOCK(ipbmap);
+	IREAD_LOCK(ipbmap, RDWRLOCK_DMAP);
 
 	/* block to be freed better be within the mapsize. */
 	if (unlikely((blkno == 0) || (blkno + nblocks > bmp->db_mapsize))) {
@@ -733,7 +733,7 @@
 	 * allocation group size, try to allocate anywhere.
 	 */
 	if (l2nb > bmp->db_agl2size) {
-		IWRITE_LOCK(ipbmap);
+		IWRITE_LOCK(ipbmap, RDWRLOCK_DMAP);
 
 		rc = dbAllocAny(bmp, nblocks, l2nb, results);
 
@@ -774,7 +774,7 @@
 	 * the hint using a tiered strategy.
 	 */
 	if (nblocks <= BPERDMAP) {
-		IREAD_LOCK(ipbmap);
+		IREAD_LOCK(ipbmap, RDWRLOCK_DMAP);
 
 		/* get the buffer for the dmap containing the hint.
 		 */
@@ -844,7 +844,7 @@
 	/* try to satisfy the allocation request with blocks within
 	 * the same allocation group as the hint.
 	 */
-	IWRITE_LOCK(ipbmap);
+	IWRITE_LOCK(ipbmap, RDWRLOCK_DMAP);
 	if ((rc = dbAllocAG(bmp, agno, nblocks, l2nb, results)) != -ENOSPC)
 		goto write_unlock;
 
@@ -856,7 +856,7 @@
 	 * Let dbNextAG recommend a preferred allocation group
 	 */
 	agno = dbNextAG(ipbmap);
-	IWRITE_LOCK(ipbmap);
+	IWRITE_LOCK(ipbmap, RDWRLOCK_DMAP);
 
 	/* Try to allocate within this allocation group.  if that fails, try to
 	 * allocate anywhere in the map.
@@ -900,7 +900,7 @@
 	s64 lblkno;
 	struct metapage *mp;
 
-	IREAD_LOCK(ipbmap);
+	IREAD_LOCK(ipbmap, RDWRLOCK_DMAP);
 
 	/*
 	 * validate extent request:
@@ -1050,7 +1050,7 @@
 	 */
 	extblkno = lastblkno + 1;
 
-	IREAD_LOCK(ipbmap);
+	IREAD_LOCK(ipbmap, RDWRLOCK_DMAP);
 
 	/* better be within the file system */
 	bmp = sbi->bmap;
@@ -3116,7 +3116,7 @@
 	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
 	struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
 
-	IREAD_LOCK(ipbmap);
+	IREAD_LOCK(ipbmap, RDWRLOCK_DMAP);
 
 	/* block to be allocated better be within the mapsize. */
 	ASSERT(nblocks <= bmp->db_mapsize - blkno);
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
index 53f63b4..aa5124b 100644
--- a/fs/jfs/jfs_imap.c
+++ b/fs/jfs/jfs_imap.c
@@ -331,7 +331,7 @@
 
 	/* read the iag */
 	imap = JFS_IP(ipimap)->i_imap;
-	IREAD_LOCK(ipimap);
+	IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
 	rc = diIAGRead(imap, iagno, &mp);
 	IREAD_UNLOCK(ipimap);
 	if (rc) {
@@ -920,7 +920,7 @@
 	/* Obtain read lock in imap inode.  Don't release it until we have
 	 * read all of the IAG's that we are going to.
 	 */
-	IREAD_LOCK(ipimap);
+	IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
 
 	/* read the iag.
 	 */
@@ -1415,7 +1415,7 @@
 	AG_LOCK(imap, agno);
 
 	/* Get read lock on imap inode */
-	IREAD_LOCK(ipimap);
+	IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
 
 	/* get the iag number and read the iag */
 	iagno = INOTOIAG(inum);
@@ -1808,7 +1808,7 @@
 		return -ENOSPC;
 
 	/* obtain read lock on imap inode */
-	IREAD_LOCK(imap->im_ipimap);
+	IREAD_LOCK(imap->im_ipimap, RDWRLOCK_IMAP);
 
 	/* read the iag at the head of the list.
 	 */
@@ -1946,7 +1946,7 @@
 	} else {
 		/* read the iag.
 		 */
-		IREAD_LOCK(imap->im_ipimap);
+		IREAD_LOCK(imap->im_ipimap, RDWRLOCK_IMAP);
 		if ((rc = diIAGRead(imap, iagno, &mp))) {
 			IREAD_UNLOCK(imap->im_ipimap);
 			jfs_error(ip->i_sb, "diAllocExt: error reading iag");
@@ -2509,7 +2509,7 @@
 		 */
 
 		/* acquire inode map lock */
-		IWRITE_LOCK(ipimap);
+		IWRITE_LOCK(ipimap, RDWRLOCK_IMAP);
 
 		if (ipimap->i_size >> L2PSIZE != imap->im_nextiag + 1) {
 			IWRITE_UNLOCK(ipimap);
@@ -2648,7 +2648,7 @@
 	}
 
 	/* obtain read lock on map */
-	IREAD_LOCK(ipimap);
+	IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
 
 	/* read the iag */
 	if ((rc = diIAGRead(imap, iagno, &mp))) {
@@ -2779,7 +2779,7 @@
 		return -EIO;
 	}
 	/* read the iag */
-	IREAD_LOCK(ipimap);
+	IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
 	rc = diIAGRead(imap, iagno, &mp);
 	IREAD_UNLOCK(ipimap);
 	if (rc)
diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h
index 9400558..8f453ef 100644
--- a/fs/jfs/jfs_incore.h
+++ b/fs/jfs/jfs_incore.h
@@ -109,9 +109,11 @@
 
 #define JFS_ACL_NOT_CACHED ((void *)-1)
 
-#define IREAD_LOCK(ip)		down_read(&JFS_IP(ip)->rdwrlock)
+#define IREAD_LOCK(ip, subclass) \
+	down_read_nested(&JFS_IP(ip)->rdwrlock, subclass)
 #define IREAD_UNLOCK(ip)	up_read(&JFS_IP(ip)->rdwrlock)
-#define IWRITE_LOCK(ip)		down_write(&JFS_IP(ip)->rdwrlock)
+#define IWRITE_LOCK(ip, subclass) \
+	down_write_nested(&JFS_IP(ip)->rdwrlock, subclass)
 #define IWRITE_UNLOCK(ip)	up_write(&JFS_IP(ip)->rdwrlock)
 
 /*
@@ -127,6 +129,29 @@
 	COMMIT_Synclist,	/* metadata pages on group commit synclist */
 };
 
+/*
+ * commit_mutex nesting subclasses:
+ */
+enum commit_mutex_class
+{
+	COMMIT_MUTEX_PARENT,
+	COMMIT_MUTEX_CHILD,
+	COMMIT_MUTEX_SECOND_PARENT,	/* Renaming */
+	COMMIT_MUTEX_VICTIM		/* Inode being unlinked due to rename */
+};
+
+/*
+ * rdwrlock subclasses:
+ * The dmap inode may be locked while a normal inode or the imap inode are
+ * locked.
+ */
+enum rdwrlock_class
+{
+	RDWRLOCK_NORMAL,
+	RDWRLOCK_IMAP,
+	RDWRLOCK_DMAP
+};
+
 #define set_cflag(flag, ip)	set_bit(flag, &(JFS_IP(ip)->cflag))
 #define clear_cflag(flag, ip)	clear_bit(flag, &(JFS_IP(ip)->cflag))
 #define test_cflag(flag, ip)	test_bit(flag, &(JFS_IP(ip)->cflag))
diff --git a/fs/jfs/jfs_lock.h b/fs/jfs/jfs_lock.h
index 7d78e83..df48ece 100644
--- a/fs/jfs/jfs_lock.h
+++ b/fs/jfs/jfs_lock.h
@@ -42,7 +42,7 @@
 		if (cond)				\
 			break;				\
 		unlock_cmd;				\
-		schedule();				\
+		io_schedule();				\
 		lock_cmd;				\
 	}						\
 	current->state = TASK_RUNNING;			\
diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
index ceaf03b..58deae0 100644
--- a/fs/jfs/jfs_metapage.c
+++ b/fs/jfs/jfs_metapage.c
@@ -56,7 +56,7 @@
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		if (metapage_locked(mp)) {
 			unlock_page(mp->page);
-			schedule();
+			io_schedule();
 			lock_page(mp->page);
 		}
 	} while (trylock_metapage(mp));
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index d558e51..6988a10 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -135,7 +135,7 @@
 	add_wait_queue(event, &wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	TXN_UNLOCK();
-	schedule();
+	io_schedule();
 	current->state = TASK_RUNNING;
 	remove_wait_queue(event, &wait);
 }
diff --git a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c
index e98eb03..acc97c4 100644
--- a/fs/jfs/jfs_xtree.c
+++ b/fs/jfs/jfs_xtree.c
@@ -757,6 +757,11 @@
 			nsplit = 0;
 
 		/* push (bn, index) of the parent page/entry */
+		if (BT_STACK_FULL(btstack)) {
+			jfs_error(ip->i_sb, "stack overrun in xtSearch!");
+			XT_PUTPAGE(mp);
+			return -EIO;
+		}
 		BT_PUSH(btstack, bn, index);
 
 		/* get the child page block number */
@@ -3915,6 +3920,11 @@
 	 */
       getChild:
 	/* save current parent entry for the child page */
+	if (BT_STACK_FULL(&btstack)) {
+		jfs_error(ip->i_sb, "stack overrun in xtTruncate!");
+		XT_PUTPAGE(mp);
+		return -EIO;
+	}
 	BT_PUSH(&btstack, bn, index);
 
 	/* get child page */
@@ -4112,6 +4122,11 @@
 	 */
       getChild:
 	/* save current parent entry for the child page */
+	if (BT_STACK_FULL(&btstack)) {
+		jfs_error(ip->i_sb, "stack overrun in xtTruncate_pmap!");
+		XT_PUTPAGE(mp);
+		return -EIO;
+	}
 	BT_PUSH(&btstack, bn, index);
 
 	/* get child page */
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index a6a8c16..7ab4756 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -104,8 +104,8 @@
 
 	tid = txBegin(dip->i_sb, 0);
 
-	mutex_lock(&JFS_IP(dip)->commit_mutex);
-	mutex_lock(&JFS_IP(ip)->commit_mutex);
+	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
 	rc = jfs_init_acl(tid, ip, dip);
 	if (rc)
@@ -238,8 +238,8 @@
 
 	tid = txBegin(dip->i_sb, 0);
 
-	mutex_lock(&JFS_IP(dip)->commit_mutex);
-	mutex_lock(&JFS_IP(ip)->commit_mutex);
+	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
 	rc = jfs_init_acl(tid, ip, dip);
 	if (rc)
@@ -365,8 +365,8 @@
 
 	tid = txBegin(dip->i_sb, 0);
 
-	mutex_lock(&JFS_IP(dip)->commit_mutex);
-	mutex_lock(&JFS_IP(ip)->commit_mutex);
+	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
 	iplist[0] = dip;
 	iplist[1] = ip;
@@ -483,12 +483,12 @@
 	if ((rc = get_UCSname(&dname, dentry)))
 		goto out;
 
-	IWRITE_LOCK(ip);
+	IWRITE_LOCK(ip, RDWRLOCK_NORMAL);
 
 	tid = txBegin(dip->i_sb, 0);
 
-	mutex_lock(&JFS_IP(dip)->commit_mutex);
-	mutex_lock(&JFS_IP(ip)->commit_mutex);
+	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
 	iplist[0] = dip;
 	iplist[1] = ip;
@@ -802,8 +802,8 @@
 
 	tid = txBegin(ip->i_sb, 0);
 
-	mutex_lock(&JFS_IP(dir)->commit_mutex);
-	mutex_lock(&JFS_IP(ip)->commit_mutex);
+	mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT);
+	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
 	/*
 	 * scan parent directory for entry/freespace
@@ -913,8 +913,8 @@
 
 	tid = txBegin(dip->i_sb, 0);
 
-	mutex_lock(&JFS_IP(dip)->commit_mutex);
-	mutex_lock(&JFS_IP(ip)->commit_mutex);
+	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
 	rc = jfs_init_security(tid, ip, dip);
 	if (rc)
@@ -1127,7 +1127,7 @@
 			goto out3;
 		}
 	} else if (new_ip) {
-		IWRITE_LOCK(new_ip);
+		IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL);
 		/* Init inode for quota operations. */
 		DQUOT_INIT(new_ip);
 	}
@@ -1137,13 +1137,21 @@
 	 */
 	tid = txBegin(new_dir->i_sb, 0);
 
-	mutex_lock(&JFS_IP(new_dir)->commit_mutex);
-	mutex_lock(&JFS_IP(old_ip)->commit_mutex);
+	/*
+	 * How do we know the locking is safe from deadlocks?
+	 * The vfs does the hard part for us.  Any time we are taking nested
+	 * commit_mutexes, the vfs already has i_mutex held on the parent.
+	 * Here, the vfs has already taken i_mutex on both old_dir and new_dir.
+	 */
+	mutex_lock_nested(&JFS_IP(new_dir)->commit_mutex, COMMIT_MUTEX_PARENT);
+	mutex_lock_nested(&JFS_IP(old_ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 	if (old_dir != new_dir)
-		mutex_lock(&JFS_IP(old_dir)->commit_mutex);
+		mutex_lock_nested(&JFS_IP(old_dir)->commit_mutex,
+				  COMMIT_MUTEX_SECOND_PARENT);
 
 	if (new_ip) {
-		mutex_lock(&JFS_IP(new_ip)->commit_mutex);
+		mutex_lock_nested(&JFS_IP(new_ip)->commit_mutex,
+				  COMMIT_MUTEX_VICTIM);
 		/*
 		 * Change existing directory entry to new inode number
 		 */
@@ -1357,8 +1365,8 @@
 
 	tid = txBegin(dir->i_sb, 0);
 
-	mutex_lock(&JFS_IP(dir)->commit_mutex);
-	mutex_lock(&JFS_IP(ip)->commit_mutex);
+	mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT);
+	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
 	rc = jfs_init_acl(tid, ip, dir);
 	if (rc)
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
index 277ca67..5a9779b 100644
--- a/fs/ocfs2/cluster/heartbeat.c
+++ b/fs/ocfs2/cluster/heartbeat.c
@@ -184,10 +184,9 @@
 	flush_scheduled_work();
 }
 
-static inline void o2hb_bio_wait_init(struct o2hb_bio_wait_ctxt *wc,
-				      unsigned int num_ios)
+static inline void o2hb_bio_wait_init(struct o2hb_bio_wait_ctxt *wc)
 {
-	atomic_set(&wc->wc_num_reqs, num_ios);
+	atomic_set(&wc->wc_num_reqs, 1);
 	init_completion(&wc->wc_io_complete);
 	wc->wc_error = 0;
 }
@@ -212,6 +211,7 @@
 	struct address_space *mapping = reg->hr_bdev->bd_inode->i_mapping;
 
 	blk_run_address_space(mapping);
+	o2hb_bio_wait_dec(wc, 1);
 
 	wait_for_completion(&wc->wc_io_complete);
 }
@@ -231,6 +231,7 @@
 		return 1;
 
 	o2hb_bio_wait_dec(wc, 1);
+	bio_put(bio);
 	return 0;
 }
 
@@ -238,23 +239,22 @@
  * start_slot. */
 static struct bio *o2hb_setup_one_bio(struct o2hb_region *reg,
 				      struct o2hb_bio_wait_ctxt *wc,
-				      unsigned int start_slot,
-				      unsigned int num_slots)
+				      unsigned int *current_slot,
+				      unsigned int max_slots)
 {
-	int i, nr_vecs, len, first_page, last_page;
+	int len, current_page;
 	unsigned int vec_len, vec_start;
 	unsigned int bits = reg->hr_block_bits;
 	unsigned int spp = reg->hr_slots_per_page;
+	unsigned int cs = *current_slot;
 	struct bio *bio;
 	struct page *page;
 
-	nr_vecs = (num_slots + spp - 1) / spp;
-
 	/* Testing has shown this allocation to take long enough under
 	 * GFP_KERNEL that the local node can get fenced. It would be
 	 * nicest if we could pre-allocate these bios and avoid this
 	 * all together. */
-	bio = bio_alloc(GFP_ATOMIC, nr_vecs);
+	bio = bio_alloc(GFP_ATOMIC, 16);
 	if (!bio) {
 		mlog(ML_ERROR, "Could not alloc slots BIO!\n");
 		bio = ERR_PTR(-ENOMEM);
@@ -262,137 +262,53 @@
 	}
 
 	/* Must put everything in 512 byte sectors for the bio... */
-	bio->bi_sector = (reg->hr_start_block + start_slot) << (bits - 9);
+	bio->bi_sector = (reg->hr_start_block + cs) << (bits - 9);
 	bio->bi_bdev = reg->hr_bdev;
 	bio->bi_private = wc;
 	bio->bi_end_io = o2hb_bio_end_io;
 
-	first_page = start_slot / spp;
-	last_page = first_page + nr_vecs;
-	vec_start = (start_slot << bits) % PAGE_CACHE_SIZE;
-	for(i = first_page; i < last_page; i++) {
-		page = reg->hr_slot_data[i];
+	vec_start = (cs << bits) % PAGE_CACHE_SIZE;
+	while(cs < max_slots) {
+		current_page = cs / spp;
+		page = reg->hr_slot_data[current_page];
 
-		vec_len = PAGE_CACHE_SIZE;
-		/* last page might be short */
-		if (((i + 1) * spp) > (start_slot + num_slots))
-			vec_len = ((num_slots + start_slot) % spp) << bits;
-		vec_len -=  vec_start;
+		vec_len = min(PAGE_CACHE_SIZE,
+			      (max_slots-cs) * (PAGE_CACHE_SIZE/spp) );
 
 		mlog(ML_HB_BIO, "page %d, vec_len = %u, vec_start = %u\n",
-		     i, vec_len, vec_start);
+		     current_page, vec_len, vec_start);
 
 		len = bio_add_page(bio, page, vec_len, vec_start);
-		if (len != vec_len) {
-			bio_put(bio);
-			bio = ERR_PTR(-EIO);
+		if (len != vec_len) break;
 
-			mlog(ML_ERROR, "Error adding page to bio i = %d, "
-			     "vec_len = %u, len = %d\n, start = %u\n",
-			     i, vec_len, len, vec_start);
-			goto bail;
-		}
-
+		cs += vec_len / (PAGE_CACHE_SIZE/spp);
 		vec_start = 0;
 	}
 
 bail:
+	*current_slot = cs;
 	return bio;
 }
 
-/*
- * Compute the maximum number of sectors the bdev can handle in one bio,
- * as a power of two.
- *
- * Stolen from oracleasm, thanks Joel!
- */
-static int compute_max_sectors(struct block_device *bdev)
-{
-	int max_pages, max_sectors, pow_two_sectors;
-
-	struct request_queue *q;
-
-	q = bdev_get_queue(bdev);
-	max_pages = q->max_sectors >> (PAGE_SHIFT - 9);
-	if (max_pages > BIO_MAX_PAGES)
-		max_pages = BIO_MAX_PAGES;
-	if (max_pages > q->max_phys_segments)
-		max_pages = q->max_phys_segments;
-	if (max_pages > q->max_hw_segments)
-		max_pages = q->max_hw_segments;
-	max_pages--; /* Handle I/Os that straddle a page */
-
-	if (max_pages) {
-		max_sectors = max_pages << (PAGE_SHIFT - 9);
-	} else {
-		/* If BIO contains 1 or less than 1 page. */
-		max_sectors = q->max_sectors;
-	}
-	/* Why is fls() 1-based???? */
-	pow_two_sectors = 1 << (fls(max_sectors) - 1);
-
-	return pow_two_sectors;
-}
-
-static inline void o2hb_compute_request_limits(struct o2hb_region *reg,
-					       unsigned int num_slots,
-					       unsigned int *num_bios,
-					       unsigned int *slots_per_bio)
-{
-	unsigned int max_sectors, io_sectors;
-
-	max_sectors = compute_max_sectors(reg->hr_bdev);
-
-	io_sectors = num_slots << (reg->hr_block_bits - 9);
-
-	*num_bios = (io_sectors + max_sectors - 1) / max_sectors;
-	*slots_per_bio = max_sectors >> (reg->hr_block_bits - 9);
-
-	mlog(ML_HB_BIO, "My io size is %u sectors for %u slots. This "
-	     "device can handle %u sectors of I/O\n", io_sectors, num_slots,
-	     max_sectors);
-	mlog(ML_HB_BIO, "Will need %u bios holding %u slots each\n",
-	     *num_bios, *slots_per_bio);
-}
-
 static int o2hb_read_slots(struct o2hb_region *reg,
 			   unsigned int max_slots)
 {
-	unsigned int num_bios, slots_per_bio, start_slot, num_slots;
-	int i, status;
+	unsigned int current_slot=0;
+	int status;
 	struct o2hb_bio_wait_ctxt wc;
-	struct bio **bios;
 	struct bio *bio;
 
-	o2hb_compute_request_limits(reg, max_slots, &num_bios, &slots_per_bio);
+	o2hb_bio_wait_init(&wc);
 
-	bios = kcalloc(num_bios, sizeof(struct bio *), GFP_KERNEL);
-	if (!bios) {
-		status = -ENOMEM;
-		mlog_errno(status);
-		return status;
-	}
-
-	o2hb_bio_wait_init(&wc, num_bios);
-
-	num_slots = slots_per_bio;
-	for(i = 0; i < num_bios; i++) {
-		start_slot = i * slots_per_bio;
-
-		/* adjust num_slots at last bio */
-		if (max_slots < (start_slot + num_slots))
-			num_slots = max_slots - start_slot;
-
-		bio = o2hb_setup_one_bio(reg, &wc, start_slot, num_slots);
+	while(current_slot < max_slots) {
+		bio = o2hb_setup_one_bio(reg, &wc, &current_slot, max_slots);
 		if (IS_ERR(bio)) {
-			o2hb_bio_wait_dec(&wc, num_bios - i);
-
 			status = PTR_ERR(bio);
 			mlog_errno(status);
 			goto bail_and_wait;
 		}
-		bios[i] = bio;
 
+		atomic_inc(&wc.wc_num_reqs);
 		submit_bio(READ, bio);
 	}
 
@@ -403,38 +319,30 @@
 	if (wc.wc_error && !status)
 		status = wc.wc_error;
 
-	if (bios) {
-		for(i = 0; i < num_bios; i++)
-			if (bios[i])
-				bio_put(bios[i]);
-		kfree(bios);
-	}
-
 	return status;
 }
 
 static int o2hb_issue_node_write(struct o2hb_region *reg,
-				 struct bio **write_bio,
 				 struct o2hb_bio_wait_ctxt *write_wc)
 {
 	int status;
 	unsigned int slot;
 	struct bio *bio;
 
-	o2hb_bio_wait_init(write_wc, 1);
+	o2hb_bio_wait_init(write_wc);
 
 	slot = o2nm_this_node();
 
-	bio = o2hb_setup_one_bio(reg, write_wc, slot, 1);
+	bio = o2hb_setup_one_bio(reg, write_wc, &slot, slot+1);
 	if (IS_ERR(bio)) {
 		status = PTR_ERR(bio);
 		mlog_errno(status);
 		goto bail;
 	}
 
+	atomic_inc(&write_wc->wc_num_reqs);
 	submit_bio(WRITE, bio);
 
-	*write_bio = bio;
 	status = 0;
 bail:
 	return status;
@@ -826,7 +734,6 @@
 {
 	int i, ret, highest_node, change = 0;
 	unsigned long configured_nodes[BITS_TO_LONGS(O2NM_MAX_NODES)];
-	struct bio *write_bio;
 	struct o2hb_bio_wait_ctxt write_wc;
 
 	ret = o2nm_configured_node_map(configured_nodes,
@@ -864,7 +771,7 @@
 
 	/* And fire off the write. Note that we don't wait on this I/O
 	 * until later. */
-	ret = o2hb_issue_node_write(reg, &write_bio, &write_wc);
+	ret = o2hb_issue_node_write(reg, &write_wc);
 	if (ret < 0) {
 		mlog_errno(ret);
 		return ret;
@@ -882,7 +789,6 @@
 	 * people we find in our steady state have seen us.
 	 */
 	o2hb_wait_on_io(reg, &write_wc);
-	bio_put(write_bio);
 	if (write_wc.wc_error) {
 		/* Do not re-arm the write timeout on I/O error - we
 		 * can't be sure that the new block ever made it to
@@ -943,7 +849,6 @@
 {
 	int i, ret;
 	struct o2hb_region *reg = data;
-	struct bio *write_bio;
 	struct o2hb_bio_wait_ctxt write_wc;
 	struct timeval before_hb, after_hb;
 	unsigned int elapsed_msec;
@@ -993,10 +898,9 @@
 	 *
 	 * XXX: Should we skip this on unclean_stop? */
 	o2hb_prepare_block(reg, 0);
-	ret = o2hb_issue_node_write(reg, &write_bio, &write_wc);
+	ret = o2hb_issue_node_write(reg, &write_wc);
 	if (ret == 0) {
 		o2hb_wait_on_io(reg, &write_wc);
-		bio_put(write_bio);
 	} else {
 		mlog_errno(ret);
 	}
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index ae4ff4a..1718215 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -556,6 +556,8 @@
 	sk->sk_data_ready = o2net_data_ready;
 	sk->sk_state_change = o2net_state_change;
 
+	mutex_init(&sc->sc_send_lock);
+
 	write_unlock_bh(&sk->sk_callback_lock);
 }
 
@@ -688,6 +690,7 @@
  * be given to the handler if their payload is longer than the max. */
 int o2net_register_handler(u32 msg_type, u32 key, u32 max_len,
 			   o2net_msg_handler_func *func, void *data,
+			   o2net_post_msg_handler_func *post_func,
 			   struct list_head *unreg_list)
 {
 	struct o2net_msg_handler *nmh = NULL;
@@ -722,6 +725,7 @@
 
 	nmh->nh_func = func;
 	nmh->nh_func_data = data;
+	nmh->nh_post_func = post_func;
 	nmh->nh_msg_type = msg_type;
 	nmh->nh_max_len = max_len;
 	nmh->nh_key = key;
@@ -856,10 +860,12 @@
 	ssize_t ret;
 
 
+	mutex_lock(&sc->sc_send_lock);
 	ret = sc->sc_sock->ops->sendpage(sc->sc_sock,
 					 virt_to_page(kmalloced_virt),
 					 (long)kmalloced_virt & ~PAGE_MASK,
 					 size, MSG_DONTWAIT);
+	mutex_unlock(&sc->sc_send_lock);
 	if (ret != size) {
 		mlog(ML_ERROR, "sendpage of size %zu to " SC_NODEF_FMT 
 		     " failed with %zd\n", size, SC_NODEF_ARGS(sc), ret);
@@ -974,8 +980,10 @@
 
 	/* finally, convert the message header to network byte-order
 	 * and send */
+	mutex_lock(&sc->sc_send_lock);
 	ret = o2net_send_tcp_msg(sc->sc_sock, vec, veclen,
 				 sizeof(struct o2net_msg) + caller_bytes);
+	mutex_unlock(&sc->sc_send_lock);
 	msglog(msg, "sending returned %d\n", ret);
 	if (ret < 0) {
 		mlog(0, "error returned from o2net_send_tcp_msg=%d\n", ret);
@@ -1049,6 +1057,7 @@
 	int ret = 0, handler_status;
 	enum  o2net_system_error syserr;
 	struct o2net_msg_handler *nmh = NULL;
+	void *ret_data = NULL;
 
 	msglog(hdr, "processing message\n");
 
@@ -1101,17 +1110,26 @@
 	sc->sc_msg_type = be16_to_cpu(hdr->msg_type);
 	handler_status = (nmh->nh_func)(hdr, sizeof(struct o2net_msg) +
 					     be16_to_cpu(hdr->data_len),
-					nmh->nh_func_data);
+					nmh->nh_func_data, &ret_data);
 	do_gettimeofday(&sc->sc_tv_func_stop);
 
 out_respond:
 	/* this destroys the hdr, so don't use it after this */
+	mutex_lock(&sc->sc_send_lock);
 	ret = o2net_send_status_magic(sc->sc_sock, hdr, syserr,
 				      handler_status);
+	mutex_unlock(&sc->sc_send_lock);
 	hdr = NULL;
 	mlog(0, "sending handler status %d, syserr %d returned %d\n",
 	     handler_status, syserr, ret);
 
+	if (nmh) {
+		BUG_ON(ret_data != NULL && nmh->nh_post_func == NULL);
+		if (nmh->nh_post_func)
+			(nmh->nh_post_func)(handler_status, nmh->nh_func_data,
+					    ret_data);
+	}
+
 out:
 	if (nmh)
 		o2net_handler_put(nmh);
@@ -1795,13 +1813,13 @@
 	ready(sk, bytes);
 }
 
-static int o2net_open_listening_sock(__be16 port)
+static int o2net_open_listening_sock(__be32 addr, __be16 port)
 {
 	struct socket *sock = NULL;
 	int ret;
 	struct sockaddr_in sin = {
 		.sin_family = PF_INET,
-		.sin_addr = { .s_addr = (__force u32)htonl(INADDR_ANY) },
+		.sin_addr = { .s_addr = (__force u32)addr },
 		.sin_port = (__force u16)port,
 	};
 
@@ -1824,15 +1842,15 @@
 	sock->sk->sk_reuse = 1;
 	ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin));
 	if (ret < 0) {
-		mlog(ML_ERROR, "unable to bind socket to port %d, ret=%d\n",
-		     ntohs(port), ret);
+		mlog(ML_ERROR, "unable to bind socket at %u.%u.%u.%u:%u, "
+		     "ret=%d\n", NIPQUAD(addr), ntohs(port), ret);
 		goto out;
 	}
 
 	ret = sock->ops->listen(sock, 64);
 	if (ret < 0) {
-		mlog(ML_ERROR, "unable to listen on port %d, ret=%d\n",
-		     ntohs(port), ret);
+		mlog(ML_ERROR, "unable to listen on %u.%u.%u.%u:%u, ret=%d\n",
+		     NIPQUAD(addr), ntohs(port), ret);
 	}
 
 out:
@@ -1865,7 +1883,8 @@
 		return -ENOMEM; /* ? */
 	}
 
-	ret = o2net_open_listening_sock(node->nd_ipv4_port);
+	ret = o2net_open_listening_sock(node->nd_ipv4_address,
+					node->nd_ipv4_port);
 	if (ret) {
 		destroy_workqueue(o2net_wq);
 		o2net_wq = NULL;
diff --git a/fs/ocfs2/cluster/tcp.h b/fs/ocfs2/cluster/tcp.h
index 21a4e43..da880fc 100644
--- a/fs/ocfs2/cluster/tcp.h
+++ b/fs/ocfs2/cluster/tcp.h
@@ -50,7 +50,10 @@
 	__u8  buf[0];
 };
 
-typedef int (o2net_msg_handler_func)(struct o2net_msg *msg, u32 len, void *data);
+typedef int (o2net_msg_handler_func)(struct o2net_msg *msg, u32 len, void *data,
+				     void **ret_data);
+typedef void (o2net_post_msg_handler_func)(int status, void *data,
+					   void *ret_data);
 
 #define O2NET_MAX_PAYLOAD_BYTES  (4096 - sizeof(struct o2net_msg))
 
@@ -99,6 +102,7 @@
 
 int o2net_register_handler(u32 msg_type, u32 key, u32 max_len,
 			   o2net_msg_handler_func *func, void *data,
+			   o2net_post_msg_handler_func *post_func,
 			   struct list_head *unreg_list);
 void o2net_unregister_handler_list(struct list_head *list);
 
diff --git a/fs/ocfs2/cluster/tcp_internal.h b/fs/ocfs2/cluster/tcp_internal.h
index b700dc9..4dae5df 100644
--- a/fs/ocfs2/cluster/tcp_internal.h
+++ b/fs/ocfs2/cluster/tcp_internal.h
@@ -38,6 +38,12 @@
  * locking semantics of the file system using the protocol.  It should 
  * be somewhere else, I'm sure, but right now it isn't.
  *
+ * New in version 7:
+ * 	- DLM join domain includes the live nodemap
+ *
+ * New in version 6:
+ * 	- DLM lockres remote refcount fixes.
+ *
  * New in version 5:
  * 	- Network timeout checking protocol
  *
@@ -51,7 +57,7 @@
  * 	- full 64 bit i_size in the metadata lock lvbs
  * 	- introduction of "rw" lock and pushing meta/data locking down
  */
-#define O2NET_PROTOCOL_VERSION 5ULL
+#define O2NET_PROTOCOL_VERSION 7ULL
 struct o2net_handshake {
 	__be64	protocol_version;
 	__be64	connector_id;
@@ -149,6 +155,8 @@
 	struct timeval 		sc_tv_func_stop;
 	u32			sc_msg_key;
 	u16			sc_msg_type;
+
+	struct mutex		sc_send_lock;
 };
 
 struct o2net_msg_handler {
@@ -158,6 +166,8 @@
 	u32			nh_key;
 	o2net_msg_handler_func	*nh_func;
 	o2net_msg_handler_func	*nh_func_data;
+	o2net_post_msg_handler_func
+				*nh_post_func;
 	struct kref		nh_kref;
 	struct list_head	nh_unregister_item;
 };
diff --git a/fs/ocfs2/dlm/dlmast.c b/fs/ocfs2/dlm/dlmast.c
index 681046d..241cad3 100644
--- a/fs/ocfs2/dlm/dlmast.c
+++ b/fs/ocfs2/dlm/dlmast.c
@@ -263,7 +263,8 @@
 
 
 
-int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data,
+			  void **ret_data)
 {
 	int ret;
 	unsigned int locklen;
@@ -311,8 +312,8 @@
 	    past->type != DLM_BAST) {
 		mlog(ML_ERROR, "Unknown ast type! %d, cookie=%u:%llu"
 		     "name=%.*s\n", past->type, 
-		     dlm_get_lock_cookie_node(cookie),
-		     dlm_get_lock_cookie_seq(cookie),
+		     dlm_get_lock_cookie_node(be64_to_cpu(cookie)),
+		     dlm_get_lock_cookie_seq(be64_to_cpu(cookie)),
 		     locklen, name);
 		ret = DLM_IVLOCKID;
 		goto leave;
@@ -323,8 +324,8 @@
 		mlog(0, "got %sast for unknown lockres! "
 		     "cookie=%u:%llu, name=%.*s, namelen=%u\n",
 		     past->type == DLM_AST ? "" : "b",
-		     dlm_get_lock_cookie_node(cookie),
-		     dlm_get_lock_cookie_seq(cookie),
+		     dlm_get_lock_cookie_node(be64_to_cpu(cookie)),
+		     dlm_get_lock_cookie_seq(be64_to_cpu(cookie)),
 		     locklen, name, locklen);
 		ret = DLM_IVLOCKID;
 		goto leave;
@@ -369,7 +370,8 @@
 
 	mlog(0, "got %sast for unknown lock!  cookie=%u:%llu, "
 	     "name=%.*s, namelen=%u\n", past->type == DLM_AST ? "" : "b", 
-	     dlm_get_lock_cookie_node(cookie), dlm_get_lock_cookie_seq(cookie),
+	     dlm_get_lock_cookie_node(be64_to_cpu(cookie)),
+	     dlm_get_lock_cookie_seq(be64_to_cpu(cookie)),
 	     locklen, name, locklen);
 
 	ret = DLM_NORMAL;
diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h
index 6b6ff76..e90b92f 100644
--- a/fs/ocfs2/dlm/dlmcommon.h
+++ b/fs/ocfs2/dlm/dlmcommon.h
@@ -180,6 +180,11 @@
 	unsigned ignore_higher:1;
 };
 
+struct dlm_deref_lockres_priv
+{
+	struct dlm_lock_resource *deref_res;
+	u8 deref_node;
+};
 
 struct dlm_work_item
 {
@@ -191,6 +196,7 @@
 		struct dlm_request_all_locks_priv ral;
 		struct dlm_mig_lockres_priv ml;
 		struct dlm_assert_master_priv am;
+		struct dlm_deref_lockres_priv dl;
 	} u;
 };
 
@@ -222,6 +228,9 @@
 #define DLM_LOCK_RES_DIRTY                0x00000008
 #define DLM_LOCK_RES_IN_PROGRESS          0x00000010
 #define DLM_LOCK_RES_MIGRATING            0x00000020
+#define DLM_LOCK_RES_DROPPING_REF         0x00000040
+#define DLM_LOCK_RES_BLOCK_DIRTY          0x00001000
+#define DLM_LOCK_RES_SETREF_INPROG        0x00002000
 
 /* max milliseconds to wait to sync up a network failure with a node death */
 #define DLM_NODE_DEATH_WAIT_MAX (5 * 1000)
@@ -265,6 +274,8 @@
 	u8  owner;              //node which owns the lock resource, or unknown
 	u16 state;
 	char lvb[DLM_LVB_LEN];
+	unsigned int inflight_locks;
+	unsigned long refmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
 };
 
 struct dlm_migratable_lock
@@ -367,7 +378,7 @@
 	DLM_CONVERT_LOCK_MSG,	 /* 504 */
 	DLM_PROXY_AST_MSG,	 /* 505 */
 	DLM_UNLOCK_LOCK_MSG,	 /* 506 */
-	DLM_UNUSED_MSG2,	 /* 507 */
+	DLM_DEREF_LOCKRES_MSG,	 /* 507 */
 	DLM_MIGRATE_REQUEST_MSG, /* 508 */
 	DLM_MIG_LOCKRES_MSG, 	 /* 509 */
 	DLM_QUERY_JOIN_MSG,	 /* 510 */
@@ -417,6 +428,9 @@
 	u8 name[O2NM_MAX_NAME_LEN];
 };
 
+#define DLM_ASSERT_RESPONSE_REASSERT       0x00000001
+#define DLM_ASSERT_RESPONSE_MASTERY_REF    0x00000002
+
 #define DLM_ASSERT_MASTER_MLE_CLEANUP      0x00000001
 #define DLM_ASSERT_MASTER_REQUERY          0x00000002
 #define DLM_ASSERT_MASTER_FINISH_MIGRATION 0x00000004
@@ -430,6 +444,8 @@
 	u8 name[O2NM_MAX_NAME_LEN];
 };
 
+#define DLM_MIGRATE_RESPONSE_MASTERY_REF   0x00000001
+
 struct dlm_migrate_request
 {
 	u8 master;
@@ -609,12 +625,16 @@
 };
 
 
+#define BITS_PER_BYTE 8
+#define BITS_TO_BYTES(bits) (((bits)+BITS_PER_BYTE-1)/BITS_PER_BYTE)
+
 struct dlm_query_join_request
 {
 	u8 node_idx;
 	u8 pad1[2];
 	u8 name_len;
 	u8 domain[O2NM_MAX_NAME_LEN];
+	u8 node_map[BITS_TO_BYTES(O2NM_MAX_NODES)];
 };
 
 struct dlm_assert_joined
@@ -648,6 +668,16 @@
 	__be32 pad2;
 };
 
+struct dlm_deref_lockres
+{
+	u32 pad1;
+	u16 pad2;
+	u8 node_idx;
+	u8 namelen;
+
+	u8 name[O2NM_MAX_NAME_LEN];
+};
+
 static inline enum dlm_status
 __dlm_lockres_state_to_status(struct dlm_lock_resource *res)
 {
@@ -688,16 +718,20 @@
 void dlm_lock_attach_lockres(struct dlm_lock *lock,
 			     struct dlm_lock_resource *res);
 
-int dlm_create_lock_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data);
+int dlm_create_lock_handler(struct o2net_msg *msg, u32 len, void *data,
+			    void **ret_data);
+int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data,
+			     void **ret_data);
+int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data,
+			  void **ret_data);
 
 void dlm_revert_pending_convert(struct dlm_lock_resource *res,
 				struct dlm_lock *lock);
 void dlm_revert_pending_lock(struct dlm_lock_resource *res,
 			     struct dlm_lock *lock);
 
-int dlm_unlock_lock_handler(struct o2net_msg *msg, u32 len, void *data);
+int dlm_unlock_lock_handler(struct o2net_msg *msg, u32 len, void *data,
+			    void **ret_data);
 void dlm_commit_pending_cancel(struct dlm_lock_resource *res,
 			       struct dlm_lock *lock);
 void dlm_commit_pending_unlock(struct dlm_lock_resource *res,
@@ -721,8 +755,6 @@
 			      struct dlm_lock_resource *res);
 void dlm_lockres_calc_usage(struct dlm_ctxt *dlm,
 			    struct dlm_lock_resource *res);
-void dlm_purge_lockres(struct dlm_ctxt *dlm,
-		       struct dlm_lock_resource *lockres);
 static inline void dlm_lockres_get(struct dlm_lock_resource *res)
 {
 	/* This is called on every lookup, so it might be worth
@@ -733,6 +765,10 @@
 void __dlm_unhash_lockres(struct dlm_lock_resource *res);
 void __dlm_insert_lockres(struct dlm_ctxt *dlm,
 			  struct dlm_lock_resource *res);
+struct dlm_lock_resource * __dlm_lookup_lockres_full(struct dlm_ctxt *dlm,
+						     const char *name,
+						     unsigned int len,
+						     unsigned int hash);
 struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm,
 						const char *name,
 						unsigned int len,
@@ -753,6 +789,47 @@
 					  const char *name,
 					  unsigned int namelen);
 
+#define dlm_lockres_set_refmap_bit(bit,res)  \
+	__dlm_lockres_set_refmap_bit(bit,res,__FILE__,__LINE__)
+#define dlm_lockres_clear_refmap_bit(bit,res)  \
+	__dlm_lockres_clear_refmap_bit(bit,res,__FILE__,__LINE__)
+
+static inline void __dlm_lockres_set_refmap_bit(int bit,
+						struct dlm_lock_resource *res,
+						const char *file,
+						int line)
+{
+	//printk("%s:%d:%.*s: setting bit %d\n", file, line,
+	//     res->lockname.len, res->lockname.name, bit);
+	set_bit(bit, res->refmap);
+}
+
+static inline void __dlm_lockres_clear_refmap_bit(int bit,
+						  struct dlm_lock_resource *res,
+						  const char *file,
+						  int line)
+{
+	//printk("%s:%d:%.*s: clearing bit %d\n", file, line,
+	//     res->lockname.len, res->lockname.name, bit);
+	clear_bit(bit, res->refmap);
+}
+
+void __dlm_lockres_drop_inflight_ref(struct dlm_ctxt *dlm,
+				   struct dlm_lock_resource *res,
+				   const char *file,
+				   int line);
+void __dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm,
+				   struct dlm_lock_resource *res,
+				   int new_lockres,
+				   const char *file,
+				   int line);
+#define dlm_lockres_drop_inflight_ref(d,r)  \
+	__dlm_lockres_drop_inflight_ref(d,r,__FILE__,__LINE__)
+#define dlm_lockres_grab_inflight_ref(d,r)  \
+	__dlm_lockres_grab_inflight_ref(d,r,0,__FILE__,__LINE__)
+#define dlm_lockres_grab_inflight_ref_new(d,r)  \
+	__dlm_lockres_grab_inflight_ref(d,r,1,__FILE__,__LINE__)
+
 void dlm_queue_ast(struct dlm_ctxt *dlm, struct dlm_lock *lock);
 void dlm_queue_bast(struct dlm_ctxt *dlm, struct dlm_lock *lock);
 void dlm_do_local_ast(struct dlm_ctxt *dlm,
@@ -801,10 +878,7 @@
 void dlm_hb_node_down_cb(struct o2nm_node *node, int idx, void *data);
 void dlm_hb_node_up_cb(struct o2nm_node *node, int idx, void *data);
 
-int dlm_lockres_is_dirty(struct dlm_ctxt *dlm, struct dlm_lock_resource *res);
-int dlm_migrate_lockres(struct dlm_ctxt *dlm,
-			struct dlm_lock_resource *res,
-			u8 target);
+int dlm_empty_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res);
 int dlm_finish_migration(struct dlm_ctxt *dlm,
 			 struct dlm_lock_resource *res,
 			 u8 old_master);
@@ -812,15 +886,27 @@
 			     struct dlm_lock_resource *res);
 void __dlm_lockres_reserve_ast(struct dlm_lock_resource *res);
 
-int dlm_master_request_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_assert_master_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_migrate_request_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_request_all_locks_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_reco_data_done_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_begin_reco_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data);
+int dlm_master_request_handler(struct o2net_msg *msg, u32 len, void *data,
+			       void **ret_data);
+int dlm_assert_master_handler(struct o2net_msg *msg, u32 len, void *data,
+			      void **ret_data);
+void dlm_assert_master_post_handler(int status, void *data, void *ret_data);
+int dlm_deref_lockres_handler(struct o2net_msg *msg, u32 len, void *data,
+			      void **ret_data);
+int dlm_migrate_request_handler(struct o2net_msg *msg, u32 len, void *data,
+				void **ret_data);
+int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data,
+			    void **ret_data);
+int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data,
+			       void **ret_data);
+int dlm_request_all_locks_handler(struct o2net_msg *msg, u32 len, void *data,
+				  void **ret_data);
+int dlm_reco_data_done_handler(struct o2net_msg *msg, u32 len, void *data,
+			       void **ret_data);
+int dlm_begin_reco_handler(struct o2net_msg *msg, u32 len, void *data,
+			   void **ret_data);
+int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data,
+			      void **ret_data);
 int dlm_do_master_requery(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
 			  u8 nodenum, u8 *real_master);
 
@@ -856,10 +942,12 @@
 int dlm_init_mle_cache(void);
 void dlm_destroy_mle_cache(void);
 void dlm_hb_event_notify_attached(struct dlm_ctxt *dlm, int idx, int node_up);
+int dlm_drop_lockres_ref(struct dlm_ctxt *dlm,
+			 struct dlm_lock_resource *res);
 void dlm_clean_master_list(struct dlm_ctxt *dlm,
 			   u8 dead_node);
 int dlm_lock_basts_flushed(struct dlm_ctxt *dlm, struct dlm_lock *lock);
-
+int __dlm_lockres_has_locks(struct dlm_lock_resource *res);
 int __dlm_lockres_unused(struct dlm_lock_resource *res);
 
 static inline const char * dlm_lock_mode_name(int mode)
diff --git a/fs/ocfs2/dlm/dlmconvert.c b/fs/ocfs2/dlm/dlmconvert.c
index c764dc8..ecb4d99 100644
--- a/fs/ocfs2/dlm/dlmconvert.c
+++ b/fs/ocfs2/dlm/dlmconvert.c
@@ -286,8 +286,8 @@
 		__dlm_print_one_lock_resource(res);
 		mlog(ML_ERROR, "converting a remote lock that is already "
 		     "converting! (cookie=%u:%llu, conv=%d)\n",
-		     dlm_get_lock_cookie_node(lock->ml.cookie),
-		     dlm_get_lock_cookie_seq(lock->ml.cookie),
+		     dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
+		     dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
 		     lock->ml.convert_type);
 		status = DLM_DENIED;
 		goto bail;
@@ -418,7 +418,8 @@
  * returns: DLM_NORMAL, DLM_IVLOCKID, DLM_BADARGS,
  *          status from __dlmconvert_master
  */
-int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data,
+			     void **ret_data)
 {
 	struct dlm_ctxt *dlm = data;
 	struct dlm_convert_lock *cnv = (struct dlm_convert_lock *)msg->buf;
@@ -428,7 +429,7 @@
 	struct dlm_lockstatus *lksb;
 	enum dlm_status status = DLM_NORMAL;
 	u32 flags;
-	int call_ast = 0, kick_thread = 0, ast_reserved = 0;
+	int call_ast = 0, kick_thread = 0, ast_reserved = 0, wake = 0;
 
 	if (!dlm_grab(dlm)) {
 		dlm_error(DLM_REJECTED);
@@ -479,25 +480,14 @@
 		}
 		lock = NULL;
 	}
-	if (!lock) {
-		__dlm_print_one_lock_resource(res);
-		list_for_each(iter, &res->granted) {
-			lock = list_entry(iter, struct dlm_lock, list);
-			if (lock->ml.node == cnv->node_idx) {
-				mlog(ML_ERROR, "There is something here "
-				     "for node %u, lock->ml.cookie=%llu, "
-				     "cnv->cookie=%llu\n", cnv->node_idx,
-				     (unsigned long long)lock->ml.cookie,
-				     (unsigned long long)cnv->cookie);
-				break;
-			}
-		}
-		lock = NULL;
-	}
 	spin_unlock(&res->spinlock);
 	if (!lock) {
 		status = DLM_IVLOCKID;
-		dlm_error(status);
+		mlog(ML_ERROR, "did not find lock to convert on grant queue! "
+			       "cookie=%u:%llu\n",
+		     dlm_get_lock_cookie_node(be64_to_cpu(cnv->cookie)),
+		     dlm_get_lock_cookie_seq(be64_to_cpu(cnv->cookie)));
+		__dlm_print_one_lock_resource(res);
 		goto leave;
 	}
 
@@ -524,8 +514,11 @@
 					     cnv->requested_type,
 					     &call_ast, &kick_thread);
 		res->state &= ~DLM_LOCK_RES_IN_PROGRESS;
+		wake = 1;
 	}
 	spin_unlock(&res->spinlock);
+	if (wake)
+		wake_up(&res->wq);
 
 	if (status != DLM_NORMAL) {
 		if (status != DLM_NOTQUEUED)
@@ -534,12 +527,7 @@
 	}
 
 leave:
-	if (!lock)
-		mlog(ML_ERROR, "did not find lock to convert on grant queue! "
-			       "cookie=%u:%llu\n",
-			       dlm_get_lock_cookie_node(cnv->cookie),
-			       dlm_get_lock_cookie_seq(cnv->cookie));
-	else
+	if (lock)
 		dlm_lock_put(lock);
 
 	/* either queue the ast or release it, if reserved */
diff --git a/fs/ocfs2/dlm/dlmdebug.c b/fs/ocfs2/dlm/dlmdebug.c
index 3f6c8d8..64239b3 100644
--- a/fs/ocfs2/dlm/dlmdebug.c
+++ b/fs/ocfs2/dlm/dlmdebug.c
@@ -53,6 +53,23 @@
 	spin_unlock(&res->spinlock);
 }
 
+static void dlm_print_lockres_refmap(struct dlm_lock_resource *res)
+{
+	int bit;
+	assert_spin_locked(&res->spinlock);
+
+	mlog(ML_NOTICE, "  refmap nodes: [ ");
+	bit = 0;
+	while (1) {
+		bit = find_next_bit(res->refmap, O2NM_MAX_NODES, bit);
+		if (bit >= O2NM_MAX_NODES)
+			break;
+		printk("%u ", bit);
+		bit++;
+	}
+	printk("], inflight=%u\n", res->inflight_locks);
+}
+
 void __dlm_print_one_lock_resource(struct dlm_lock_resource *res)
 {
 	struct list_head *iter2;
@@ -65,6 +82,7 @@
 	       res->owner, res->state);
 	mlog(ML_NOTICE, "  last used: %lu, on purge list: %s\n",
 	     res->last_used, list_empty(&res->purge) ? "no" : "yes");
+	dlm_print_lockres_refmap(res);
 	mlog(ML_NOTICE, "  granted queue: \n");
 	list_for_each(iter2, &res->granted) {
 		lock = list_entry(iter2, struct dlm_lock, list);
@@ -72,8 +90,8 @@
 		mlog(ML_NOTICE, "    type=%d, conv=%d, node=%u, "
 		       "cookie=%u:%llu, ast=(empty=%c,pend=%c), bast=(empty=%c,pend=%c)\n", 
 		       lock->ml.type, lock->ml.convert_type, lock->ml.node, 
-		       dlm_get_lock_cookie_node(lock->ml.cookie), 
-		       dlm_get_lock_cookie_seq(lock->ml.cookie), 
+		     dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
+		     dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
 		       list_empty(&lock->ast_list) ? 'y' : 'n',
 		       lock->ast_pending ? 'y' : 'n',
 		       list_empty(&lock->bast_list) ? 'y' : 'n',
@@ -87,8 +105,8 @@
 		mlog(ML_NOTICE, "    type=%d, conv=%d, node=%u, "
 		       "cookie=%u:%llu, ast=(empty=%c,pend=%c), bast=(empty=%c,pend=%c)\n", 
 		       lock->ml.type, lock->ml.convert_type, lock->ml.node, 
-		       dlm_get_lock_cookie_node(lock->ml.cookie), 
-		       dlm_get_lock_cookie_seq(lock->ml.cookie), 
+		     dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
+		     dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
 		       list_empty(&lock->ast_list) ? 'y' : 'n',
 		       lock->ast_pending ? 'y' : 'n',
 		       list_empty(&lock->bast_list) ? 'y' : 'n',
@@ -102,8 +120,8 @@
 		mlog(ML_NOTICE, "    type=%d, conv=%d, node=%u, "
 		       "cookie=%u:%llu, ast=(empty=%c,pend=%c), bast=(empty=%c,pend=%c)\n", 
 		       lock->ml.type, lock->ml.convert_type, lock->ml.node, 
-		       dlm_get_lock_cookie_node(lock->ml.cookie), 
-		       dlm_get_lock_cookie_seq(lock->ml.cookie), 
+		     dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
+		     dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
 		       list_empty(&lock->ast_list) ? 'y' : 'n',
 		       lock->ast_pending ? 'y' : 'n',
 		       list_empty(&lock->bast_list) ? 'y' : 'n',
diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c
index f0b25f2..6087c47 100644
--- a/fs/ocfs2/dlm/dlmdomain.c
+++ b/fs/ocfs2/dlm/dlmdomain.c
@@ -48,6 +48,36 @@
 #define MLOG_MASK_PREFIX (ML_DLM|ML_DLM_DOMAIN)
 #include "cluster/masklog.h"
 
+/*
+ * ocfs2 node maps are array of long int, which limits to send them freely
+ * across the wire due to endianness issues. To workaround this, we convert
+ * long ints to byte arrays. Following 3 routines are helper functions to
+ * set/test/copy bits within those array of bytes
+ */
+static inline void byte_set_bit(u8 nr, u8 map[])
+{
+	map[nr >> 3] |= (1UL << (nr & 7));
+}
+
+static inline int byte_test_bit(u8 nr, u8 map[])
+{
+	return ((1UL << (nr & 7)) & (map[nr >> 3])) != 0;
+}
+
+static inline void byte_copymap(u8 dmap[], unsigned long smap[],
+			unsigned int sz)
+{
+	unsigned int nn;
+
+	if (!sz)
+		return;
+
+	memset(dmap, 0, ((sz + 7) >> 3));
+	for (nn = 0 ; nn < sz; nn++)
+		if (test_bit(nn, smap))
+			byte_set_bit(nn, dmap);
+}
+
 static void dlm_free_pagevec(void **vec, int pages)
 {
 	while (pages--)
@@ -95,10 +125,14 @@
 
 #define DLM_DOMAIN_BACKOFF_MS 200
 
-static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data);
-static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data);
-static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data);
-static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data);
+static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,
+				  void **ret_data);
+static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data,
+				     void **ret_data);
+static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data,
+				   void **ret_data);
+static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data,
+				   void **ret_data);
 
 static void dlm_unregister_domain_handlers(struct dlm_ctxt *dlm);
 
@@ -125,10 +159,10 @@
 	hlist_add_head(&res->hash_node, bucket);
 }
 
-struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm,
-						const char *name,
-						unsigned int len,
-						unsigned int hash)
+struct dlm_lock_resource * __dlm_lookup_lockres_full(struct dlm_ctxt *dlm,
+						     const char *name,
+						     unsigned int len,
+						     unsigned int hash)
 {
 	struct hlist_head *bucket;
 	struct hlist_node *list;
@@ -154,6 +188,37 @@
 	return NULL;
 }
 
+/* intended to be called by functions which do not care about lock
+ * resources which are being purged (most net _handler functions).
+ * this will return NULL for any lock resource which is found but
+ * currently in the process of dropping its mastery reference.
+ * use __dlm_lookup_lockres_full when you need the lock resource
+ * regardless (e.g. dlm_get_lock_resource) */
+struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm,
+						const char *name,
+						unsigned int len,
+						unsigned int hash)
+{
+	struct dlm_lock_resource *res = NULL;
+
+	mlog_entry("%.*s\n", len, name);
+
+	assert_spin_locked(&dlm->spinlock);
+
+	res = __dlm_lookup_lockres_full(dlm, name, len, hash);
+	if (res) {
+		spin_lock(&res->spinlock);
+		if (res->state & DLM_LOCK_RES_DROPPING_REF) {
+			spin_unlock(&res->spinlock);
+			dlm_lockres_put(res);
+			return NULL;
+		}
+		spin_unlock(&res->spinlock);
+	}
+
+	return res;
+}
+
 struct dlm_lock_resource * dlm_lookup_lockres(struct dlm_ctxt *dlm,
 				    const char *name,
 				    unsigned int len)
@@ -330,43 +395,60 @@
 	wake_up(&dlm_domain_events);
 }
 
-static void dlm_migrate_all_locks(struct dlm_ctxt *dlm)
+static int dlm_migrate_all_locks(struct dlm_ctxt *dlm)
 {
-	int i;
+	int i, num, n, ret = 0;
 	struct dlm_lock_resource *res;
+	struct hlist_node *iter;
+	struct hlist_head *bucket;
+	int dropped;
 
 	mlog(0, "Migrating locks from domain %s\n", dlm->name);
-restart:
+
+	num = 0;
 	spin_lock(&dlm->spinlock);
 	for (i = 0; i < DLM_HASH_BUCKETS; i++) {
-		while (!hlist_empty(dlm_lockres_hash(dlm, i))) {
-			res = hlist_entry(dlm_lockres_hash(dlm, i)->first,
-					  struct dlm_lock_resource, hash_node);
-			/* need reference when manually grabbing lockres */
+redo_bucket:
+		n = 0;
+		bucket = dlm_lockres_hash(dlm, i);
+		iter = bucket->first;
+		while (iter) {
+			n++;
+			res = hlist_entry(iter, struct dlm_lock_resource,
+					  hash_node);
 			dlm_lockres_get(res);
-			/* this should unhash the lockres
-			 * and exit with dlm->spinlock */
-			mlog(0, "purging res=%p\n", res);
-			if (dlm_lockres_is_dirty(dlm, res)) {
-				/* HACK!  this should absolutely go.
-				 * need to figure out why some empty
-				 * lockreses are still marked dirty */
-				mlog(ML_ERROR, "lockres %.*s dirty!\n",
-				     res->lockname.len, res->lockname.name);
+			/* migrate, if necessary.  this will drop the dlm
+			 * spinlock and retake it if it does migration. */
+			dropped = dlm_empty_lockres(dlm, res);
 
-				spin_unlock(&dlm->spinlock);
-				dlm_kick_thread(dlm, res);
-				wait_event(dlm->ast_wq, !dlm_lockres_is_dirty(dlm, res));
-				dlm_lockres_put(res);
-				goto restart;
-			}
-			dlm_purge_lockres(dlm, res);
+			spin_lock(&res->spinlock);
+			__dlm_lockres_calc_usage(dlm, res);
+			iter = res->hash_node.next;
+			spin_unlock(&res->spinlock);
+
 			dlm_lockres_put(res);
+
+			cond_resched_lock(&dlm->spinlock);
+
+			if (dropped)
+				goto redo_bucket;
 		}
+		num += n;
+		mlog(0, "%s: touched %d lockreses in bucket %d "
+		     "(tot=%d)\n", dlm->name, n, i, num);
 	}
 	spin_unlock(&dlm->spinlock);
+	wake_up(&dlm->dlm_thread_wq);
 
+	/* let the dlm thread take care of purging, keep scanning until
+	 * nothing remains in the hash */
+	if (num) {
+		mlog(0, "%s: %d lock resources in hash last pass\n",
+		     dlm->name, num);
+		ret = -EAGAIN;
+	}
 	mlog(0, "DONE Migrating locks from domain %s\n", dlm->name);
+	return ret;
 }
 
 static int dlm_no_joining_node(struct dlm_ctxt *dlm)
@@ -418,7 +500,8 @@
 	printk("\n");
 }
 
-static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data)
+static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data,
+				   void **ret_data)
 {
 	struct dlm_ctxt *dlm = data;
 	unsigned int node;
@@ -571,7 +654,9 @@
 		/* We changed dlm state, notify the thread */
 		dlm_kick_thread(dlm, NULL);
 
-		dlm_migrate_all_locks(dlm);
+		while (dlm_migrate_all_locks(dlm)) {
+			mlog(0, "%s: more migration to do\n", dlm->name);
+		}
 		dlm_mark_domain_leaving(dlm);
 		dlm_leave_domain(dlm);
 		dlm_complete_dlm_shutdown(dlm);
@@ -580,11 +665,13 @@
 }
 EXPORT_SYMBOL_GPL(dlm_unregister_domain);
 
-static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data)
+static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,
+				  void **ret_data)
 {
 	struct dlm_query_join_request *query;
 	enum dlm_query_join_response response;
 	struct dlm_ctxt *dlm = NULL;
+	u8 nodenum;
 
 	query = (struct dlm_query_join_request *) msg->buf;
 
@@ -608,6 +695,28 @@
 
 	spin_lock(&dlm_domain_lock);
 	dlm = __dlm_lookup_domain_full(query->domain, query->name_len);
+	if (!dlm)
+		goto unlock_respond;
+
+	/*
+	 * There is a small window where the joining node may not see the
+	 * node(s) that just left but still part of the cluster. DISALLOW
+	 * join request if joining node has different node map.
+	 */
+	nodenum=0;
+	while (nodenum < O2NM_MAX_NODES) {
+		if (test_bit(nodenum, dlm->domain_map)) {
+			if (!byte_test_bit(nodenum, query->node_map)) {
+				mlog(0, "disallow join as node %u does not "
+				     "have node %u in its nodemap\n",
+				     query->node_idx, nodenum);
+				response = JOIN_DISALLOW;
+				goto unlock_respond;
+			}
+		}
+		nodenum++;
+	}
+
 	/* Once the dlm ctxt is marked as leaving then we don't want
 	 * to be put in someone's domain map. 
 	 * Also, explicitly disallow joining at certain troublesome
@@ -626,15 +735,15 @@
 			/* Disallow parallel joins. */
 			response = JOIN_DISALLOW;
 		} else if (dlm->reco.state & DLM_RECO_STATE_ACTIVE) {
-			mlog(ML_NOTICE, "node %u trying to join, but recovery "
+			mlog(0, "node %u trying to join, but recovery "
 			     "is ongoing.\n", bit);
 			response = JOIN_DISALLOW;
 		} else if (test_bit(bit, dlm->recovery_map)) {
-			mlog(ML_NOTICE, "node %u trying to join, but it "
+			mlog(0, "node %u trying to join, but it "
 			     "still needs recovery.\n", bit);
 			response = JOIN_DISALLOW;
 		} else if (test_bit(bit, dlm->domain_map)) {
-			mlog(ML_NOTICE, "node %u trying to join, but it "
+			mlog(0, "node %u trying to join, but it "
 			     "is still in the domain! needs recovery?\n",
 			     bit);
 			response = JOIN_DISALLOW;
@@ -649,6 +758,7 @@
 
 		spin_unlock(&dlm->spinlock);
 	}
+unlock_respond:
 	spin_unlock(&dlm_domain_lock);
 
 respond:
@@ -657,7 +767,8 @@
 	return response;
 }
 
-static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data)
+static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data,
+				     void **ret_data)
 {
 	struct dlm_assert_joined *assert;
 	struct dlm_ctxt *dlm = NULL;
@@ -694,7 +805,8 @@
 	return 0;
 }
 
-static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data)
+static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data,
+				   void **ret_data)
 {
 	struct dlm_cancel_join *cancel;
 	struct dlm_ctxt *dlm = NULL;
@@ -796,6 +908,9 @@
 	join_msg.name_len = strlen(dlm->name);
 	memcpy(join_msg.domain, dlm->name, join_msg.name_len);
 
+	/* copy live node map to join message */
+	byte_copymap(join_msg.node_map, dlm->live_nodes_map, O2NM_MAX_NODES);
+
 	status = o2net_send_message(DLM_QUERY_JOIN_MSG, DLM_MOD_KEY, &join_msg,
 				    sizeof(join_msg), node, &retval);
 	if (status < 0 && status != -ENOPROTOOPT) {
@@ -1036,98 +1151,106 @@
 	status = o2net_register_handler(DLM_MASTER_REQUEST_MSG, dlm->key,
 					sizeof(struct dlm_master_request),
 					dlm_master_request_handler,
-					dlm, &dlm->dlm_domain_handlers);
+					dlm, NULL, &dlm->dlm_domain_handlers);
 	if (status)
 		goto bail;
 
 	status = o2net_register_handler(DLM_ASSERT_MASTER_MSG, dlm->key,
 					sizeof(struct dlm_assert_master),
 					dlm_assert_master_handler,
-					dlm, &dlm->dlm_domain_handlers);
+					dlm, dlm_assert_master_post_handler,
+					&dlm->dlm_domain_handlers);
 	if (status)
 		goto bail;
 
 	status = o2net_register_handler(DLM_CREATE_LOCK_MSG, dlm->key,
 					sizeof(struct dlm_create_lock),
 					dlm_create_lock_handler,
-					dlm, &dlm->dlm_domain_handlers);
+					dlm, NULL, &dlm->dlm_domain_handlers);
 	if (status)
 		goto bail;
 
 	status = o2net_register_handler(DLM_CONVERT_LOCK_MSG, dlm->key,
 					DLM_CONVERT_LOCK_MAX_LEN,
 					dlm_convert_lock_handler,
-					dlm, &dlm->dlm_domain_handlers);
+					dlm, NULL, &dlm->dlm_domain_handlers);
 	if (status)
 		goto bail;
 
 	status = o2net_register_handler(DLM_UNLOCK_LOCK_MSG, dlm->key,
 					DLM_UNLOCK_LOCK_MAX_LEN,
 					dlm_unlock_lock_handler,
-					dlm, &dlm->dlm_domain_handlers);
+					dlm, NULL, &dlm->dlm_domain_handlers);
 	if (status)
 		goto bail;
 
 	status = o2net_register_handler(DLM_PROXY_AST_MSG, dlm->key,
 					DLM_PROXY_AST_MAX_LEN,
 					dlm_proxy_ast_handler,
-					dlm, &dlm->dlm_domain_handlers);
+					dlm, NULL, &dlm->dlm_domain_handlers);
 	if (status)
 		goto bail;
 
 	status = o2net_register_handler(DLM_EXIT_DOMAIN_MSG, dlm->key,
 					sizeof(struct dlm_exit_domain),
 					dlm_exit_domain_handler,
-					dlm, &dlm->dlm_domain_handlers);
+					dlm, NULL, &dlm->dlm_domain_handlers);
+	if (status)
+		goto bail;
+
+	status = o2net_register_handler(DLM_DEREF_LOCKRES_MSG, dlm->key,
+					sizeof(struct dlm_deref_lockres),
+					dlm_deref_lockres_handler,
+					dlm, NULL, &dlm->dlm_domain_handlers);
 	if (status)
 		goto bail;
 
 	status = o2net_register_handler(DLM_MIGRATE_REQUEST_MSG, dlm->key,
 					sizeof(struct dlm_migrate_request),
 					dlm_migrate_request_handler,
-					dlm, &dlm->dlm_domain_handlers);
+					dlm, NULL, &dlm->dlm_domain_handlers);
 	if (status)
 		goto bail;
 
 	status = o2net_register_handler(DLM_MIG_LOCKRES_MSG, dlm->key,
 					DLM_MIG_LOCKRES_MAX_LEN,
 					dlm_mig_lockres_handler,
-					dlm, &dlm->dlm_domain_handlers);
+					dlm, NULL, &dlm->dlm_domain_handlers);
 	if (status)
 		goto bail;
 
 	status = o2net_register_handler(DLM_MASTER_REQUERY_MSG, dlm->key,
 					sizeof(struct dlm_master_requery),
 					dlm_master_requery_handler,
-					dlm, &dlm->dlm_domain_handlers);
+					dlm, NULL, &dlm->dlm_domain_handlers);
 	if (status)
 		goto bail;
 
 	status = o2net_register_handler(DLM_LOCK_REQUEST_MSG, dlm->key,
 					sizeof(struct dlm_lock_request),
 					dlm_request_all_locks_handler,
-					dlm, &dlm->dlm_domain_handlers);
+					dlm, NULL, &dlm->dlm_domain_handlers);
 	if (status)
 		goto bail;
 
 	status = o2net_register_handler(DLM_RECO_DATA_DONE_MSG, dlm->key,
 					sizeof(struct dlm_reco_data_done),
 					dlm_reco_data_done_handler,
-					dlm, &dlm->dlm_domain_handlers);
+					dlm, NULL, &dlm->dlm_domain_handlers);
 	if (status)
 		goto bail;
 
 	status = o2net_register_handler(DLM_BEGIN_RECO_MSG, dlm->key,
 					sizeof(struct dlm_begin_reco),
 					dlm_begin_reco_handler,
-					dlm, &dlm->dlm_domain_handlers);
+					dlm, NULL, &dlm->dlm_domain_handlers);
 	if (status)
 		goto bail;
 
 	status = o2net_register_handler(DLM_FINALIZE_RECO_MSG, dlm->key,
 					sizeof(struct dlm_finalize_reco),
 					dlm_finalize_reco_handler,
-					dlm, &dlm->dlm_domain_handlers);
+					dlm, NULL, &dlm->dlm_domain_handlers);
 	if (status)
 		goto bail;
 
@@ -1141,6 +1264,8 @@
 static int dlm_join_domain(struct dlm_ctxt *dlm)
 {
 	int status;
+	unsigned int backoff;
+	unsigned int total_backoff = 0;
 
 	BUG_ON(!dlm);
 
@@ -1172,18 +1297,27 @@
 	}
 
 	do {
-		unsigned int backoff;
 		status = dlm_try_to_join_domain(dlm);
 
 		/* If we're racing another node to the join, then we
 		 * need to back off temporarily and let them
 		 * complete. */
+#define	DLM_JOIN_TIMEOUT_MSECS	90000
 		if (status == -EAGAIN) {
 			if (signal_pending(current)) {
 				status = -ERESTARTSYS;
 				goto bail;
 			}
 
+			if (total_backoff >
+			    msecs_to_jiffies(DLM_JOIN_TIMEOUT_MSECS)) {
+				status = -ERESTARTSYS;
+				mlog(ML_NOTICE, "Timed out joining dlm domain "
+				     "%s after %u msecs\n", dlm->name,
+				     jiffies_to_msecs(total_backoff));
+				goto bail;
+			}
+
 			/*
 			 * <chip> After you!
 			 * <dale> No, after you!
@@ -1193,6 +1327,7 @@
 			 */
 			backoff = (unsigned int)(jiffies & 0x3);
 			backoff *= DLM_DOMAIN_BACKOFF_MS;
+			total_backoff += backoff;
 			mlog(0, "backoff %d\n", backoff);
 			msleep(backoff);
 		}
@@ -1421,21 +1556,21 @@
 	status = o2net_register_handler(DLM_QUERY_JOIN_MSG, DLM_MOD_KEY,
 					sizeof(struct dlm_query_join_request),
 					dlm_query_join_handler,
-					NULL, &dlm_join_handlers);
+					NULL, NULL, &dlm_join_handlers);
 	if (status)
 		goto bail;
 
 	status = o2net_register_handler(DLM_ASSERT_JOINED_MSG, DLM_MOD_KEY,
 					sizeof(struct dlm_assert_joined),
 					dlm_assert_joined_handler,
-					NULL, &dlm_join_handlers);
+					NULL, NULL, &dlm_join_handlers);
 	if (status)
 		goto bail;
 
 	status = o2net_register_handler(DLM_CANCEL_JOIN_MSG, DLM_MOD_KEY,
 					sizeof(struct dlm_cancel_join),
 					dlm_cancel_join_handler,
-					NULL, &dlm_join_handlers);
+					NULL, NULL, &dlm_join_handlers);
 
 bail:
 	if (status < 0)
diff --git a/fs/ocfs2/dlm/dlmlock.c b/fs/ocfs2/dlm/dlmlock.c
index e5ca3db..52578d9 100644
--- a/fs/ocfs2/dlm/dlmlock.c
+++ b/fs/ocfs2/dlm/dlmlock.c
@@ -163,6 +163,10 @@
 			kick_thread = 1;
 		}
 	}
+	/* reduce the inflight count, this may result in the lockres
+	 * being purged below during calc_usage */
+	if (lock->ml.node == dlm->node_num)
+		dlm_lockres_drop_inflight_ref(dlm, res);
 
 	spin_unlock(&res->spinlock);
 	wake_up(&res->wq);
@@ -437,7 +441,8 @@
  *   held on exit:  none
  * returns: DLM_NORMAL, DLM_SYSERR, DLM_IVLOCKID, DLM_NOTQUEUED
  */
-int dlm_create_lock_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_create_lock_handler(struct o2net_msg *msg, u32 len, void *data,
+			    void **ret_data)
 {
 	struct dlm_ctxt *dlm = data;
 	struct dlm_create_lock *create = (struct dlm_create_lock *)msg->buf;
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
index 0ad8720..77e4e61 100644
--- a/fs/ocfs2/dlm/dlmmaster.c
+++ b/fs/ocfs2/dlm/dlmmaster.c
@@ -99,9 +99,10 @@
 			    int idx);
 
 static void dlm_assert_master_worker(struct dlm_work_item *item, void *data);
-static int dlm_do_assert_master(struct dlm_ctxt *dlm, const char *lockname,
-				unsigned int namelen, void *nodemap,
-				u32 flags);
+static int dlm_do_assert_master(struct dlm_ctxt *dlm,
+				struct dlm_lock_resource *res,
+				void *nodemap, u32 flags);
+static void dlm_deref_lockres_worker(struct dlm_work_item *item, void *data);
 
 static inline int dlm_mle_equal(struct dlm_ctxt *dlm,
 				struct dlm_master_list_entry *mle,
@@ -237,7 +238,8 @@
 			struct dlm_master_list_entry **mle,
 			char *name, unsigned int namelen);
 
-static int dlm_do_master_request(struct dlm_master_list_entry *mle, int to);
+static int dlm_do_master_request(struct dlm_lock_resource *res,
+				 struct dlm_master_list_entry *mle, int to);
 
 
 static int dlm_wait_for_lock_mastery(struct dlm_ctxt *dlm,
@@ -687,6 +689,7 @@
 	INIT_LIST_HEAD(&res->purge);
 	atomic_set(&res->asts_reserved, 0);
 	res->migration_pending = 0;
+	res->inflight_locks = 0;
 
 	kref_init(&res->refs);
 
@@ -700,6 +703,7 @@
 	res->last_used = 0;
 
 	memset(res->lvb, 0, DLM_LVB_LEN);
+	memset(res->refmap, 0, sizeof(res->refmap));
 }
 
 struct dlm_lock_resource *dlm_new_lockres(struct dlm_ctxt *dlm,
@@ -722,6 +726,42 @@
 	return res;
 }
 
+void __dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm,
+				   struct dlm_lock_resource *res,
+				   int new_lockres,
+				   const char *file,
+				   int line)
+{
+	if (!new_lockres)
+		assert_spin_locked(&res->spinlock);
+
+	if (!test_bit(dlm->node_num, res->refmap)) {
+		BUG_ON(res->inflight_locks != 0);
+		dlm_lockres_set_refmap_bit(dlm->node_num, res);
+	}
+	res->inflight_locks++;
+	mlog(0, "%s:%.*s: inflight++: now %u\n",
+	     dlm->name, res->lockname.len, res->lockname.name,
+	     res->inflight_locks);
+}
+
+void __dlm_lockres_drop_inflight_ref(struct dlm_ctxt *dlm,
+				   struct dlm_lock_resource *res,
+				   const char *file,
+				   int line)
+{
+	assert_spin_locked(&res->spinlock);
+
+	BUG_ON(res->inflight_locks == 0);
+	res->inflight_locks--;
+	mlog(0, "%s:%.*s: inflight--: now %u\n",
+	     dlm->name, res->lockname.len, res->lockname.name,
+	     res->inflight_locks);
+	if (res->inflight_locks == 0)
+		dlm_lockres_clear_refmap_bit(dlm->node_num, res);
+	wake_up(&res->wq);
+}
+
 /*
  * lookup a lock resource by name.
  * may already exist in the hashtable.
@@ -752,6 +792,7 @@
 	unsigned int hash;
 	int tries = 0;
 	int bit, wait_on_recovery = 0;
+	int drop_inflight_if_nonlocal = 0;
 
 	BUG_ON(!lockid);
 
@@ -761,9 +802,30 @@
 
 lookup:
 	spin_lock(&dlm->spinlock);
-	tmpres = __dlm_lookup_lockres(dlm, lockid, namelen, hash);
+	tmpres = __dlm_lookup_lockres_full(dlm, lockid, namelen, hash);
 	if (tmpres) {
+		int dropping_ref = 0;
+
+		spin_lock(&tmpres->spinlock);
+		if (tmpres->owner == dlm->node_num) {
+			BUG_ON(tmpres->state & DLM_LOCK_RES_DROPPING_REF);
+			dlm_lockres_grab_inflight_ref(dlm, tmpres);
+		} else if (tmpres->state & DLM_LOCK_RES_DROPPING_REF)
+			dropping_ref = 1;
+		spin_unlock(&tmpres->spinlock);
 		spin_unlock(&dlm->spinlock);
+
+		/* wait until done messaging the master, drop our ref to allow
+		 * the lockres to be purged, start over. */
+		if (dropping_ref) {
+			spin_lock(&tmpres->spinlock);
+			__dlm_wait_on_lockres_flags(tmpres, DLM_LOCK_RES_DROPPING_REF);
+			spin_unlock(&tmpres->spinlock);
+			dlm_lockres_put(tmpres);
+			tmpres = NULL;
+			goto lookup;
+		}
+
 		mlog(0, "found in hash!\n");
 		if (res)
 			dlm_lockres_put(res);
@@ -793,6 +855,7 @@
 		spin_lock(&res->spinlock);
 		dlm_change_lockres_owner(dlm, res, dlm->node_num);
 		__dlm_insert_lockres(dlm, res);
+		dlm_lockres_grab_inflight_ref(dlm, res);
 		spin_unlock(&res->spinlock);
 		spin_unlock(&dlm->spinlock);
 		/* lockres still marked IN_PROGRESS */
@@ -805,29 +868,40 @@
 	/* if we found a block, wait for lock to be mastered by another node */
 	blocked = dlm_find_mle(dlm, &mle, (char *)lockid, namelen);
 	if (blocked) {
+		int mig;
 		if (mle->type == DLM_MLE_MASTER) {
 			mlog(ML_ERROR, "master entry for nonexistent lock!\n");
 			BUG();
-		} else if (mle->type == DLM_MLE_MIGRATION) {
-			/* migration is in progress! */
-			/* the good news is that we now know the
-			 * "current" master (mle->master). */
-
+		}
+		mig = (mle->type == DLM_MLE_MIGRATION);
+		/* if there is a migration in progress, let the migration
+		 * finish before continuing.  we can wait for the absence
+		 * of the MIGRATION mle: either the migrate finished or
+		 * one of the nodes died and the mle was cleaned up.
+		 * if there is a BLOCK here, but it already has a master
+		 * set, we are too late.  the master does not have a ref
+		 * for us in the refmap.  detach the mle and drop it.
+		 * either way, go back to the top and start over. */
+		if (mig || mle->master != O2NM_MAX_NODES) {
+			BUG_ON(mig && mle->master == dlm->node_num);
+			/* we arrived too late.  the master does not
+			 * have a ref for us. retry. */
+			mlog(0, "%s:%.*s: late on %s\n",
+			     dlm->name, namelen, lockid,
+			     mig ?  "MIGRATION" : "BLOCK");
 			spin_unlock(&dlm->master_lock);
-			assert_spin_locked(&dlm->spinlock);
-
-			/* set the lockres owner and hash it */
-			spin_lock(&res->spinlock);
-			dlm_set_lockres_owner(dlm, res, mle->master);
-			__dlm_insert_lockres(dlm, res);
-			spin_unlock(&res->spinlock);
 			spin_unlock(&dlm->spinlock);
 
 			/* master is known, detach */
-			dlm_mle_detach_hb_events(dlm, mle);
+			if (!mig)
+				dlm_mle_detach_hb_events(dlm, mle);
 			dlm_put_mle(mle);
 			mle = NULL;
-			goto wake_waiters;
+			/* this is lame, but we cant wait on either
+			 * the mle or lockres waitqueue here */
+			if (mig)
+				msleep(100);
+			goto lookup;
 		}
 	} else {
 		/* go ahead and try to master lock on this node */
@@ -858,6 +932,13 @@
 
 	/* finally add the lockres to its hash bucket */
 	__dlm_insert_lockres(dlm, res);
+	/* since this lockres is new it doesnt not require the spinlock */
+	dlm_lockres_grab_inflight_ref_new(dlm, res);
+
+	/* if this node does not become the master make sure to drop
+	 * this inflight reference below */
+	drop_inflight_if_nonlocal = 1;
+
 	/* get an extra ref on the mle in case this is a BLOCK
 	 * if so, the creator of the BLOCK may try to put the last
 	 * ref at this time in the assert master handler, so we
@@ -910,7 +991,7 @@
 	ret = -EINVAL;
 	dlm_node_iter_init(mle->vote_map, &iter);
 	while ((nodenum = dlm_node_iter_next(&iter)) >= 0) {
-		ret = dlm_do_master_request(mle, nodenum);
+		ret = dlm_do_master_request(res, mle, nodenum);
 		if (ret < 0)
 			mlog_errno(ret);
 		if (mle->master != O2NM_MAX_NODES) {
@@ -960,6 +1041,8 @@
 
 wake_waiters:
 	spin_lock(&res->spinlock);
+	if (res->owner != dlm->node_num && drop_inflight_if_nonlocal)
+		dlm_lockres_drop_inflight_ref(dlm, res);
 	res->state &= ~DLM_LOCK_RES_IN_PROGRESS;
 	spin_unlock(&res->spinlock);
 	wake_up(&res->wq);
@@ -998,7 +1081,7 @@
 		/* this will cause the master to re-assert across
 		 * the whole cluster, freeing up mles */
 		if (res->owner != dlm->node_num) {
-			ret = dlm_do_master_request(mle, res->owner);
+			ret = dlm_do_master_request(res, mle, res->owner);
 			if (ret < 0) {
 				/* give recovery a chance to run */
 				mlog(ML_ERROR, "link to %u went down?: %d\n", res->owner, ret);
@@ -1062,6 +1145,8 @@
 			 	 * now tell other nodes that I am
 				 * mastering this. */
 				mle->master = dlm->node_num;
+				/* ref was grabbed in get_lock_resource
+				 * will be dropped in dlmlock_master */
 				assert = 1;
 				sleep = 0;
 			}
@@ -1087,7 +1172,8 @@
 					 (atomic_read(&mle->woken) == 1),
 					 timeo);
 		if (res->owner == O2NM_MAX_NODES) {
-			mlog(0, "waiting again\n");
+			mlog(0, "%s:%.*s: waiting again\n", dlm->name,
+			     res->lockname.len, res->lockname.name);
 			goto recheck;
 		}
 		mlog(0, "done waiting, master is %u\n", res->owner);
@@ -1100,8 +1186,7 @@
 		m = dlm->node_num;
 		mlog(0, "about to master %.*s here, this=%u\n",
 		     res->lockname.len, res->lockname.name, m);
-		ret = dlm_do_assert_master(dlm, res->lockname.name,
-					   res->lockname.len, mle->vote_map, 0);
+		ret = dlm_do_assert_master(dlm, res, mle->vote_map, 0);
 		if (ret) {
 			/* This is a failure in the network path,
 			 * not in the response to the assert_master
@@ -1117,6 +1202,8 @@
 
 	/* set the lockres owner */
 	spin_lock(&res->spinlock);
+	/* mastery reference obtained either during
+	 * assert_master_handler or in get_lock_resource */
 	dlm_change_lockres_owner(dlm, res, m);
 	spin_unlock(&res->spinlock);
 
@@ -1283,7 +1370,8 @@
  *
  */
 
-static int dlm_do_master_request(struct dlm_master_list_entry *mle, int to)
+static int dlm_do_master_request(struct dlm_lock_resource *res,
+				 struct dlm_master_list_entry *mle, int to)
 {
 	struct dlm_ctxt *dlm = mle->dlm;
 	struct dlm_master_request request;
@@ -1339,6 +1427,9 @@
 		case DLM_MASTER_RESP_YES:
 			set_bit(to, mle->response_map);
 			mlog(0, "node %u is the master, response=YES\n", to);
+			mlog(0, "%s:%.*s: master node %u now knows I have a "
+			     "reference\n", dlm->name, res->lockname.len,
+			     res->lockname.name, to);
 			mle->master = to;
 			break;
 		case DLM_MASTER_RESP_NO:
@@ -1379,7 +1470,8 @@
  *
  * if possible, TRIM THIS DOWN!!!
  */
-int dlm_master_request_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_master_request_handler(struct o2net_msg *msg, u32 len, void *data,
+			       void **ret_data)
 {
 	u8 response = DLM_MASTER_RESP_MAYBE;
 	struct dlm_ctxt *dlm = data;
@@ -1417,10 +1509,11 @@
 
 		/* take care of the easy cases up front */
 		spin_lock(&res->spinlock);
-		if (res->state & DLM_LOCK_RES_RECOVERING) {
+		if (res->state & (DLM_LOCK_RES_RECOVERING|
+				  DLM_LOCK_RES_MIGRATING)) {
 			spin_unlock(&res->spinlock);
 			mlog(0, "returning DLM_MASTER_RESP_ERROR since res is "
-			     "being recovered\n");
+			     "being recovered/migrated\n");
 			response = DLM_MASTER_RESP_ERROR;
 			if (mle)
 				kmem_cache_free(dlm_mle_cache, mle);
@@ -1428,8 +1521,10 @@
 		}
 
 		if (res->owner == dlm->node_num) {
+			mlog(0, "%s:%.*s: setting bit %u in refmap\n",
+			     dlm->name, namelen, name, request->node_idx);
+			dlm_lockres_set_refmap_bit(request->node_idx, res);
 			spin_unlock(&res->spinlock);
-			// mlog(0, "this node is the master\n");
 			response = DLM_MASTER_RESP_YES;
 			if (mle)
 				kmem_cache_free(dlm_mle_cache, mle);
@@ -1477,7 +1572,6 @@
 			mlog(0, "node %u is master, but trying to migrate to "
 			     "node %u.\n", tmpmle->master, tmpmle->new_master);
 			if (tmpmle->master == dlm->node_num) {
-				response = DLM_MASTER_RESP_YES;
 				mlog(ML_ERROR, "no owner on lockres, but this "
 				     "node is trying to migrate it to %u?!\n",
 				     tmpmle->new_master);
@@ -1494,6 +1588,10 @@
 				 * go back and clean the mles on any
 				 * other nodes */
 				dispatch_assert = 1;
+				dlm_lockres_set_refmap_bit(request->node_idx, res);
+				mlog(0, "%s:%.*s: setting bit %u in refmap\n",
+				     dlm->name, namelen, name,
+				     request->node_idx);
 			} else
 				response = DLM_MASTER_RESP_NO;
 		} else {
@@ -1607,17 +1705,24 @@
  * can periodically run all locks owned by this node
  * and re-assert across the cluster...
  */
-static int dlm_do_assert_master(struct dlm_ctxt *dlm, const char *lockname,
-				unsigned int namelen, void *nodemap,
-				u32 flags)
+int dlm_do_assert_master(struct dlm_ctxt *dlm,
+			 struct dlm_lock_resource *res,
+			 void *nodemap, u32 flags)
 {
 	struct dlm_assert_master assert;
 	int to, tmpret;
 	struct dlm_node_iter iter;
 	int ret = 0;
 	int reassert;
+	const char *lockname = res->lockname.name;
+	unsigned int namelen = res->lockname.len;
 
 	BUG_ON(namelen > O2NM_MAX_NAME_LEN);
+
+	spin_lock(&res->spinlock);
+	res->state |= DLM_LOCK_RES_SETREF_INPROG;
+	spin_unlock(&res->spinlock);
+
 again:
 	reassert = 0;
 
@@ -1647,6 +1752,7 @@
 			mlog(0, "link to %d went down!\n", to);
 			/* any nonzero status return will do */
 			ret = tmpret;
+			r = 0;
 		} else if (r < 0) {
 			/* ok, something horribly messed.  kill thyself. */
 			mlog(ML_ERROR,"during assert master of %.*s to %u, "
@@ -1661,17 +1767,39 @@
 			spin_unlock(&dlm->master_lock);
 			spin_unlock(&dlm->spinlock);
 			BUG();
-		} else if (r == EAGAIN) {
+		}
+
+		if (r & DLM_ASSERT_RESPONSE_REASSERT &&
+		    !(r & DLM_ASSERT_RESPONSE_MASTERY_REF)) {
+				mlog(ML_ERROR, "%.*s: very strange, "
+				     "master MLE but no lockres on %u\n",
+				     namelen, lockname, to);
+		}
+
+		if (r & DLM_ASSERT_RESPONSE_REASSERT) {
 			mlog(0, "%.*s: node %u create mles on other "
 			     "nodes and requests a re-assert\n", 
 			     namelen, lockname, to);
 			reassert = 1;
 		}
+		if (r & DLM_ASSERT_RESPONSE_MASTERY_REF) {
+			mlog(0, "%.*s: node %u has a reference to this "
+			     "lockres, set the bit in the refmap\n",
+			     namelen, lockname, to);
+			spin_lock(&res->spinlock);
+			dlm_lockres_set_refmap_bit(to, res);
+			spin_unlock(&res->spinlock);
+		}
 	}
 
 	if (reassert)
 		goto again;
 
+	spin_lock(&res->spinlock);
+	res->state &= ~DLM_LOCK_RES_SETREF_INPROG;
+	spin_unlock(&res->spinlock);
+	wake_up(&res->wq);
+
 	return ret;
 }
 
@@ -1684,7 +1812,8 @@
  *
  * if possible, TRIM THIS DOWN!!!
  */
-int dlm_assert_master_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_assert_master_handler(struct o2net_msg *msg, u32 len, void *data,
+			      void **ret_data)
 {
 	struct dlm_ctxt *dlm = data;
 	struct dlm_master_list_entry *mle = NULL;
@@ -1693,7 +1822,7 @@
 	char *name;
 	unsigned int namelen, hash;
 	u32 flags;
-	int master_request = 0;
+	int master_request = 0, have_lockres_ref = 0;
 	int ret = 0;
 
 	if (!dlm_grab(dlm))
@@ -1851,6 +1980,7 @@
 		spin_unlock(&mle->spinlock);
 
 		if (res) {
+			int wake = 0;
 			spin_lock(&res->spinlock);
 			if (mle->type == DLM_MLE_MIGRATION) {
 				mlog(0, "finishing off migration of lockres %.*s, "
@@ -1858,12 +1988,16 @@
 			       		res->lockname.len, res->lockname.name,
 			       		dlm->node_num, mle->new_master);
 				res->state &= ~DLM_LOCK_RES_MIGRATING;
+				wake = 1;
 				dlm_change_lockres_owner(dlm, res, mle->new_master);
 				BUG_ON(res->state & DLM_LOCK_RES_DIRTY);
 			} else {
 				dlm_change_lockres_owner(dlm, res, mle->master);
 			}
 			spin_unlock(&res->spinlock);
+			have_lockres_ref = 1;
+			if (wake)
+				wake_up(&res->wq);
 		}
 
 		/* master is known, detach if not already detached.
@@ -1913,12 +2047,28 @@
 
 done:
 	ret = 0;
-	if (res)
-		dlm_lockres_put(res);
+	if (res) {
+		spin_lock(&res->spinlock);
+		res->state |= DLM_LOCK_RES_SETREF_INPROG;
+		spin_unlock(&res->spinlock);
+		*ret_data = (void *)res;
+	}
 	dlm_put(dlm);
 	if (master_request) {
 		mlog(0, "need to tell master to reassert\n");
-		ret = EAGAIN;  // positive. negative would shoot down the node.
+		/* positive. negative would shoot down the node. */
+		ret |= DLM_ASSERT_RESPONSE_REASSERT;
+		if (!have_lockres_ref) {
+			mlog(ML_ERROR, "strange, got assert from %u, MASTER "
+			     "mle present here for %s:%.*s, but no lockres!\n",
+			     assert->node_idx, dlm->name, namelen, name);
+		}
+	}
+	if (have_lockres_ref) {
+		/* let the master know we have a reference to the lockres */
+		ret |= DLM_ASSERT_RESPONSE_MASTERY_REF;
+		mlog(0, "%s:%.*s: got assert from %u, need a ref\n",
+		     dlm->name, namelen, name, assert->node_idx);
 	}
 	return ret;
 
@@ -1929,11 +2079,25 @@
 	__dlm_print_one_lock_resource(res);
 	spin_unlock(&res->spinlock);
 	spin_unlock(&dlm->spinlock);
-	dlm_lockres_put(res);
+	*ret_data = (void *)res; 
 	dlm_put(dlm);
 	return -EINVAL;
 }
 
+void dlm_assert_master_post_handler(int status, void *data, void *ret_data)
+{
+	struct dlm_lock_resource *res = (struct dlm_lock_resource *)ret_data;
+
+	if (ret_data) {
+		spin_lock(&res->spinlock);
+		res->state &= ~DLM_LOCK_RES_SETREF_INPROG;
+		spin_unlock(&res->spinlock);
+		wake_up(&res->wq);
+		dlm_lockres_put(res);
+	}
+	return;
+}
+
 int dlm_dispatch_assert_master(struct dlm_ctxt *dlm,
 			       struct dlm_lock_resource *res,
 			       int ignore_higher, u8 request_from, u32 flags)
@@ -2023,9 +2187,7 @@
 	 * even if one or more nodes die */
 	mlog(0, "worker about to master %.*s here, this=%u\n",
 		     res->lockname.len, res->lockname.name, dlm->node_num);
-	ret = dlm_do_assert_master(dlm, res->lockname.name,
-				   res->lockname.len,
-				   nodemap, flags);
+	ret = dlm_do_assert_master(dlm, res, nodemap, flags);
 	if (ret < 0) {
 		/* no need to restart, we are done */
 		if (!dlm_is_host_down(ret))
@@ -2097,14 +2259,180 @@
 	return ret;
 }
 
+/*
+ * DLM_DEREF_LOCKRES_MSG
+ */
+
+int dlm_drop_lockres_ref(struct dlm_ctxt *dlm, struct dlm_lock_resource *res)
+{
+	struct dlm_deref_lockres deref;
+	int ret = 0, r;
+	const char *lockname;
+	unsigned int namelen;
+
+	lockname = res->lockname.name;
+	namelen = res->lockname.len;
+	BUG_ON(namelen > O2NM_MAX_NAME_LEN);
+
+	mlog(0, "%s:%.*s: sending deref to %d\n",
+	     dlm->name, namelen, lockname, res->owner);
+	memset(&deref, 0, sizeof(deref));
+	deref.node_idx = dlm->node_num;
+	deref.namelen = namelen;
+	memcpy(deref.name, lockname, namelen);
+
+	ret = o2net_send_message(DLM_DEREF_LOCKRES_MSG, dlm->key,
+				 &deref, sizeof(deref), res->owner, &r);
+	if (ret < 0)
+		mlog_errno(ret);
+	else if (r < 0) {
+		/* BAD.  other node says I did not have a ref. */
+		mlog(ML_ERROR,"while dropping ref on %s:%.*s "
+		    "(master=%u) got %d.\n", dlm->name, namelen,
+		    lockname, res->owner, r);
+		dlm_print_one_lock_resource(res);
+		BUG();
+	}
+	return ret;
+}
+
+int dlm_deref_lockres_handler(struct o2net_msg *msg, u32 len, void *data,
+			      void **ret_data)
+{
+	struct dlm_ctxt *dlm = data;
+	struct dlm_deref_lockres *deref = (struct dlm_deref_lockres *)msg->buf;
+	struct dlm_lock_resource *res = NULL;
+	char *name;
+	unsigned int namelen;
+	int ret = -EINVAL;
+	u8 node;
+	unsigned int hash;
+	struct dlm_work_item *item;
+	int cleared = 0;
+	int dispatch = 0;
+
+	if (!dlm_grab(dlm))
+		return 0;
+
+	name = deref->name;
+	namelen = deref->namelen;
+	node = deref->node_idx;
+
+	if (namelen > DLM_LOCKID_NAME_MAX) {
+		mlog(ML_ERROR, "Invalid name length!");
+		goto done;
+	}
+	if (deref->node_idx >= O2NM_MAX_NODES) {
+		mlog(ML_ERROR, "Invalid node number: %u\n", node);
+		goto done;
+	}
+
+	hash = dlm_lockid_hash(name, namelen);
+
+	spin_lock(&dlm->spinlock);
+	res = __dlm_lookup_lockres_full(dlm, name, namelen, hash);
+	if (!res) {
+		spin_unlock(&dlm->spinlock);
+		mlog(ML_ERROR, "%s:%.*s: bad lockres name\n",
+		     dlm->name, namelen, name);
+		goto done;
+	}
+	spin_unlock(&dlm->spinlock);
+
+	spin_lock(&res->spinlock);
+	if (res->state & DLM_LOCK_RES_SETREF_INPROG)
+		dispatch = 1;
+	else {
+		BUG_ON(res->state & DLM_LOCK_RES_DROPPING_REF);
+		if (test_bit(node, res->refmap)) {
+			dlm_lockres_clear_refmap_bit(node, res);
+			cleared = 1;
+		}
+	}
+	spin_unlock(&res->spinlock);
+
+	if (!dispatch) {
+		if (cleared)
+			dlm_lockres_calc_usage(dlm, res);
+		else {
+			mlog(ML_ERROR, "%s:%.*s: node %u trying to drop ref "
+		     	"but it is already dropped!\n", dlm->name,
+		     	res->lockname.len, res->lockname.name, node);
+			__dlm_print_one_lock_resource(res);
+		}
+		ret = 0;
+		goto done;
+	}
+
+	item = kzalloc(sizeof(*item), GFP_NOFS);
+	if (!item) {
+		ret = -ENOMEM;
+		mlog_errno(ret);
+		goto done;
+	}
+
+	dlm_init_work_item(dlm, item, dlm_deref_lockres_worker, NULL);
+	item->u.dl.deref_res = res;
+	item->u.dl.deref_node = node;
+
+	spin_lock(&dlm->work_lock);
+	list_add_tail(&item->list, &dlm->work_list);
+	spin_unlock(&dlm->work_lock);
+
+	queue_work(dlm->dlm_worker, &dlm->dispatched_work);
+	return 0;
+
+done:
+	if (res)
+		dlm_lockres_put(res);
+	dlm_put(dlm);
+
+	return ret;
+}
+
+static void dlm_deref_lockres_worker(struct dlm_work_item *item, void *data)
+{
+	struct dlm_ctxt *dlm;
+	struct dlm_lock_resource *res;
+	u8 node;
+	u8 cleared = 0;
+
+	dlm = item->dlm;
+	res = item->u.dl.deref_res;
+	node = item->u.dl.deref_node;
+
+	spin_lock(&res->spinlock);
+	BUG_ON(res->state & DLM_LOCK_RES_DROPPING_REF);
+	if (test_bit(node, res->refmap)) {
+		__dlm_wait_on_lockres_flags(res, DLM_LOCK_RES_SETREF_INPROG);
+		dlm_lockres_clear_refmap_bit(node, res);
+		cleared = 1;
+	}
+	spin_unlock(&res->spinlock);
+
+	if (cleared) {
+		mlog(0, "%s:%.*s node %u ref dropped in dispatch\n",
+		     dlm->name, res->lockname.len, res->lockname.name, node);
+		dlm_lockres_calc_usage(dlm, res);
+	} else {
+		mlog(ML_ERROR, "%s:%.*s: node %u trying to drop ref "
+		     "but it is already dropped!\n", dlm->name,
+		     res->lockname.len, res->lockname.name, node);
+		__dlm_print_one_lock_resource(res);
+	}
+
+	dlm_lockres_put(res);
+}
+
 
 /*
  * DLM_MIGRATE_LOCKRES
  */
 
 
-int dlm_migrate_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
-			u8 target)
+static int dlm_migrate_lockres(struct dlm_ctxt *dlm,
+			       struct dlm_lock_resource *res,
+			       u8 target)
 {
 	struct dlm_master_list_entry *mle = NULL;
 	struct dlm_master_list_entry *oldmle = NULL;
@@ -2116,7 +2444,7 @@
 	struct list_head *queue, *iter;
 	int i;
 	struct dlm_lock *lock;
-	int empty = 1;
+	int empty = 1, wake = 0;
 
 	if (!dlm_grab(dlm))
 		return -EINVAL;
@@ -2241,6 +2569,7 @@
 		     res->lockname.name, target);
 		spin_lock(&res->spinlock);
 		res->state &= ~DLM_LOCK_RES_MIGRATING;
+		wake = 1;
 		spin_unlock(&res->spinlock);
 		ret = -EINVAL;
 	}
@@ -2268,6 +2597,9 @@
 	 * the lockres
 	 */
 
+	/* now that remote nodes are spinning on the MIGRATING flag,
+	 * ensure that all assert_master work is flushed. */
+	flush_workqueue(dlm->dlm_worker);
 
 	/* get an extra reference on the mle.
 	 * otherwise the assert_master from the new
@@ -2296,6 +2628,7 @@
 		dlm_put_mle_inuse(mle);
 		spin_lock(&res->spinlock);
 		res->state &= ~DLM_LOCK_RES_MIGRATING;
+		wake = 1;
 		spin_unlock(&res->spinlock);
 		goto leave;
 	}
@@ -2322,7 +2655,8 @@
 			    res->owner == target)
 				break;
 
-			mlog(0, "timed out during migration\n");
+			mlog(0, "%s:%.*s: timed out during migration\n",
+			     dlm->name, res->lockname.len, res->lockname.name);
 			/* avoid hang during shutdown when migrating lockres 
 			 * to a node which also goes down */
 			if (dlm_is_node_dead(dlm, target)) {
@@ -2330,20 +2664,20 @@
 				     "target %u is no longer up, restarting\n",
 				     dlm->name, res->lockname.len,
 				     res->lockname.name, target);
-				ret = -ERESTARTSYS;
+				ret = -EINVAL;
+				/* migration failed, detach and clean up mle */
+				dlm_mle_detach_hb_events(dlm, mle);
+				dlm_put_mle(mle);
+				dlm_put_mle_inuse(mle);
+				spin_lock(&res->spinlock);
+				res->state &= ~DLM_LOCK_RES_MIGRATING;
+				wake = 1;
+				spin_unlock(&res->spinlock);
+				goto leave;
 			}
-		}
-		if (ret == -ERESTARTSYS) {
-			/* migration failed, detach and clean up mle */
-			dlm_mle_detach_hb_events(dlm, mle);
-			dlm_put_mle(mle);
-			dlm_put_mle_inuse(mle);
-			spin_lock(&res->spinlock);
-			res->state &= ~DLM_LOCK_RES_MIGRATING;
-			spin_unlock(&res->spinlock);
-			goto leave;
-		}
-		/* TODO: if node died: stop, clean up, return error */
+		} else
+			mlog(0, "%s:%.*s: caught signal during migration\n",
+			     dlm->name, res->lockname.len, res->lockname.name);
 	}
 
 	/* all done, set the owner, clear the flag */
@@ -2366,6 +2700,11 @@
 	if (ret < 0)
 		dlm_kick_thread(dlm, res);
 
+	/* wake up waiters if the MIGRATING flag got set
+	 * but migration failed */
+	if (wake)
+		wake_up(&res->wq);
+
 	/* TODO: cleanup */
 	if (mres)
 		free_page((unsigned long)mres);
@@ -2376,6 +2715,53 @@
 	return ret;
 }
 
+#define DLM_MIGRATION_RETRY_MS  100
+
+/* Should be called only after beginning the domain leave process.
+ * There should not be any remaining locks on nonlocal lock resources,
+ * and there should be no local locks left on locally mastered resources.
+ *
+ * Called with the dlm spinlock held, may drop it to do migration, but
+ * will re-acquire before exit.
+ *
+ * Returns: 1 if dlm->spinlock was dropped/retaken, 0 if never dropped */
+int dlm_empty_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res)
+{
+	int ret;
+	int lock_dropped = 0;
+
+	if (res->owner != dlm->node_num) {
+		if (!__dlm_lockres_unused(res)) {
+			mlog(ML_ERROR, "%s:%.*s: this node is not master, "
+			     "trying to free this but locks remain\n",
+			     dlm->name, res->lockname.len, res->lockname.name);
+		}
+		goto leave;
+	}
+
+	/* Wheee! Migrate lockres here! Will sleep so drop spinlock. */
+	spin_unlock(&dlm->spinlock);
+	lock_dropped = 1;
+	while (1) {
+		ret = dlm_migrate_lockres(dlm, res, O2NM_MAX_NODES);
+		if (ret >= 0)
+			break;
+		if (ret == -ENOTEMPTY) {
+			mlog(ML_ERROR, "lockres %.*s still has local locks!\n",
+		     		res->lockname.len, res->lockname.name);
+			BUG();
+		}
+
+		mlog(0, "lockres %.*s: migrate failed, "
+		     "retrying\n", res->lockname.len,
+		     res->lockname.name);
+		msleep(DLM_MIGRATION_RETRY_MS);
+	}
+	spin_lock(&dlm->spinlock);
+leave:
+	return lock_dropped;
+}
+
 int dlm_lock_basts_flushed(struct dlm_ctxt *dlm, struct dlm_lock *lock)
 {
 	int ret;
@@ -2405,7 +2791,8 @@
 	return can_proceed;
 }
 
-int dlm_lockres_is_dirty(struct dlm_ctxt *dlm, struct dlm_lock_resource *res)
+static int dlm_lockres_is_dirty(struct dlm_ctxt *dlm,
+				struct dlm_lock_resource *res)
 {
 	int ret;
 	spin_lock(&res->spinlock);
@@ -2434,8 +2821,15 @@
 	__dlm_lockres_reserve_ast(res);
 	spin_unlock(&res->spinlock);
 
-	/* now flush all the pending asts.. hang out for a bit */
+	/* now flush all the pending asts */
 	dlm_kick_thread(dlm, res);
+	/* before waiting on DIRTY, block processes which may
+	 * try to dirty the lockres before MIGRATING is set */
+	spin_lock(&res->spinlock);
+	BUG_ON(res->state & DLM_LOCK_RES_BLOCK_DIRTY);
+	res->state |= DLM_LOCK_RES_BLOCK_DIRTY;
+	spin_unlock(&res->spinlock);
+	/* now wait on any pending asts and the DIRTY state */
 	wait_event(dlm->ast_wq, !dlm_lockres_is_dirty(dlm, res));
 	dlm_lockres_release_ast(dlm, res);
 
@@ -2461,6 +2855,13 @@
 		mlog(0, "trying again...\n");
 		goto again;
 	}
+	/* now that we are sure the MIGRATING state is there, drop
+	 * the unneded state which blocked threads trying to DIRTY */
+	spin_lock(&res->spinlock);
+	BUG_ON(!(res->state & DLM_LOCK_RES_BLOCK_DIRTY));
+	BUG_ON(!(res->state & DLM_LOCK_RES_MIGRATING));
+	res->state &= ~DLM_LOCK_RES_BLOCK_DIRTY;
+	spin_unlock(&res->spinlock);
 
 	/* did the target go down or die? */
 	spin_lock(&dlm->spinlock);
@@ -2490,7 +2891,7 @@
 {
 	struct list_head *iter, *iter2;
 	struct list_head *queue = &res->granted;
-	int i;
+	int i, bit;
 	struct dlm_lock *lock;
 
 	assert_spin_locked(&res->spinlock);
@@ -2508,12 +2909,28 @@
 				BUG_ON(!list_empty(&lock->bast_list));
 				BUG_ON(lock->ast_pending);
 				BUG_ON(lock->bast_pending);
+				dlm_lockres_clear_refmap_bit(lock->ml.node, res);
 				list_del_init(&lock->list);
 				dlm_lock_put(lock);
 			}
 		}
 		queue++;
 	}
+	bit = 0;
+	while (1) {
+		bit = find_next_bit(res->refmap, O2NM_MAX_NODES, bit);
+		if (bit >= O2NM_MAX_NODES)
+			break;
+		/* do not clear the local node reference, if there is a
+		 * process holding this, let it drop the ref itself */
+		if (bit != dlm->node_num) {
+			mlog(0, "%s:%.*s: node %u had a ref to this "
+			     "migrating lockres, clearing\n", dlm->name,
+			     res->lockname.len, res->lockname.name, bit);
+			dlm_lockres_clear_refmap_bit(bit, res);
+		}
+		bit++;
+	}
 }
 
 /* for now this is not too intelligent.  we will
@@ -2601,6 +3018,16 @@
 			mlog(0, "migrate request (node %u) returned %d!\n",
 			     nodenum, status);
 			ret = status;
+		} else if (status == DLM_MIGRATE_RESPONSE_MASTERY_REF) {
+			/* during the migration request we short-circuited
+			 * the mastery of the lockres.  make sure we have
+			 * a mastery ref for nodenum */
+			mlog(0, "%s:%.*s: need ref for node %u\n",
+			     dlm->name, res->lockname.len, res->lockname.name,
+			     nodenum);
+			spin_lock(&res->spinlock);
+			dlm_lockres_set_refmap_bit(nodenum, res);
+			spin_unlock(&res->spinlock);
 		}
 	}
 
@@ -2619,7 +3046,8 @@
  * we will have no mle in the list to start with.  now we can add an mle for
  * the migration and this should be the only one found for those scanning the
  * list.  */
-int dlm_migrate_request_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_migrate_request_handler(struct o2net_msg *msg, u32 len, void *data,
+				void **ret_data)
 {
 	struct dlm_ctxt *dlm = data;
 	struct dlm_lock_resource *res = NULL;
@@ -2745,7 +3173,13 @@
 			/* remove it from the list so that only one
 			 * mle will be found */
 			list_del_init(&tmp->list);
-			__dlm_mle_detach_hb_events(dlm, mle);
+			/* this was obviously WRONG.  mle is uninited here.  should be tmp. */
+			__dlm_mle_detach_hb_events(dlm, tmp);
+			ret = DLM_MIGRATE_RESPONSE_MASTERY_REF;
+			mlog(0, "%s:%.*s: master=%u, newmaster=%u, "
+			    "telling master to get ref for cleared out mle "
+			    "during migration\n", dlm->name, namelen, name,
+			    master, new_master);
 		}
 		spin_unlock(&tmp->spinlock);
 	}
@@ -2753,6 +3187,8 @@
 	/* now add a migration mle to the tail of the list */
 	dlm_init_mle(mle, DLM_MLE_MIGRATION, dlm, res, name, namelen);
 	mle->new_master = new_master;
+	/* the new master will be sending an assert master for this.
+	 * at that point we will get the refmap reference */
 	mle->master = master;
 	/* do this for consistency with other mle types */
 	set_bit(new_master, mle->maybe_map);
@@ -2902,6 +3338,13 @@
 	clear_bit(dlm->node_num, iter.node_map);
 	spin_unlock(&dlm->spinlock);
 
+	/* ownership of the lockres is changing.  account for the
+	 * mastery reference here since old_master will briefly have
+	 * a reference after the migration completes */
+	spin_lock(&res->spinlock);
+	dlm_lockres_set_refmap_bit(old_master, res);
+	spin_unlock(&res->spinlock);
+
 	mlog(0, "now time to do a migrate request to other nodes\n");
 	ret = dlm_do_migrate_request(dlm, res, old_master,
 				     dlm->node_num, &iter);
@@ -2914,8 +3357,7 @@
 	     res->lockname.len, res->lockname.name);
 	/* this call now finishes out the nodemap
 	 * even if one or more nodes die */
-	ret = dlm_do_assert_master(dlm, res->lockname.name,
-				   res->lockname.len, iter.node_map,
+	ret = dlm_do_assert_master(dlm, res, iter.node_map,
 				   DLM_ASSERT_MASTER_FINISH_MIGRATION);
 	if (ret < 0) {
 		/* no longer need to retry.  all living nodes contacted. */
@@ -2927,8 +3369,7 @@
 	set_bit(old_master, iter.node_map);
 	mlog(0, "doing assert master of %.*s back to %u\n",
 	     res->lockname.len, res->lockname.name, old_master);
-	ret = dlm_do_assert_master(dlm, res->lockname.name,
-				   res->lockname.len, iter.node_map,
+	ret = dlm_do_assert_master(dlm, res, iter.node_map,
 				   DLM_ASSERT_MASTER_FINISH_MIGRATION);
 	if (ret < 0) {
 		mlog(0, "assert master to original master failed "
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
index 367a11e..6d4a83d 100644
--- a/fs/ocfs2/dlm/dlmrecovery.c
+++ b/fs/ocfs2/dlm/dlmrecovery.c
@@ -163,9 +163,6 @@
 	dlm_workfunc_t *workfunc;
 	int tot=0;
 
-	if (!dlm_joined(dlm))
-		return;
-
 	spin_lock(&dlm->work_lock);
 	list_splice_init(&dlm->work_list, &tmp_list);
 	spin_unlock(&dlm->work_lock);
@@ -821,7 +818,8 @@
 
 }
 
-int dlm_request_all_locks_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_request_all_locks_handler(struct o2net_msg *msg, u32 len, void *data,
+				  void **ret_data)
 {
 	struct dlm_ctxt *dlm = data;
 	struct dlm_lock_request *lr = (struct dlm_lock_request *)msg->buf;
@@ -978,7 +976,8 @@
 }
 
 
-int dlm_reco_data_done_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_reco_data_done_handler(struct o2net_msg *msg, u32 len, void *data,
+			       void **ret_data)
 {
 	struct dlm_ctxt *dlm = data;
 	struct dlm_reco_data_done *done = (struct dlm_reco_data_done *)msg->buf;
@@ -1129,6 +1128,11 @@
 	if (total_locks == mres_total_locks)
 		mres->flags |= DLM_MRES_ALL_DONE;
 
+	mlog(0, "%s:%.*s: sending mig lockres (%s) to %u\n",
+	     dlm->name, res->lockname.len, res->lockname.name,
+	     orig_flags & DLM_MRES_MIGRATION ? "migrate" : "recovery",
+	     send_to);
+
 	/* send it */
 	ret = o2net_send_message(DLM_MIG_LOCKRES_MSG, dlm->key, mres,
 				 sz, send_to, &status);
@@ -1213,6 +1217,34 @@
 	return 0;
 }
 
+static void dlm_add_dummy_lock(struct dlm_ctxt *dlm,
+			       struct dlm_migratable_lockres *mres)
+{
+	struct dlm_lock dummy;
+	memset(&dummy, 0, sizeof(dummy));
+	dummy.ml.cookie = 0;
+	dummy.ml.type = LKM_IVMODE;
+	dummy.ml.convert_type = LKM_IVMODE;
+	dummy.ml.highest_blocked = LKM_IVMODE;
+	dummy.lksb = NULL;
+	dummy.ml.node = dlm->node_num;
+	dlm_add_lock_to_array(&dummy, mres, DLM_BLOCKED_LIST);
+}
+
+static inline int dlm_is_dummy_lock(struct dlm_ctxt *dlm,
+				    struct dlm_migratable_lock *ml,
+				    u8 *nodenum)
+{
+	if (unlikely(ml->cookie == 0 &&
+	    ml->type == LKM_IVMODE &&
+	    ml->convert_type == LKM_IVMODE &&
+	    ml->highest_blocked == LKM_IVMODE &&
+	    ml->list == DLM_BLOCKED_LIST)) {
+		*nodenum = ml->node;
+		return 1;
+	}
+	return 0;
+}
 
 int dlm_send_one_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
 			 struct dlm_migratable_lockres *mres,
@@ -1260,6 +1292,14 @@
 				goto error;
 		}
 	}
+	if (total_locks == 0) {
+		/* send a dummy lock to indicate a mastery reference only */
+		mlog(0, "%s:%.*s: sending dummy lock to %u, %s\n",
+		     dlm->name, res->lockname.len, res->lockname.name,
+		     send_to, flags & DLM_MRES_RECOVERY ? "recovery" :
+		     "migration");
+		dlm_add_dummy_lock(dlm, mres);
+	}
 	/* flush any remaining locks */
 	ret = dlm_send_mig_lockres_msg(dlm, mres, send_to, res, total_locks);
 	if (ret < 0)
@@ -1293,7 +1333,8 @@
  * do we spin?  returning an error only delays the problem really
  */
 
-int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data,
+			    void **ret_data)
 {
 	struct dlm_ctxt *dlm = data;
 	struct dlm_migratable_lockres *mres =
@@ -1382,17 +1423,21 @@
 		spin_lock(&res->spinlock);
 		res->state &= ~DLM_LOCK_RES_IN_PROGRESS;
 		spin_unlock(&res->spinlock);
+		wake_up(&res->wq);
 
 		/* add an extra ref for just-allocated lockres 
 		 * otherwise the lockres will be purged immediately */
 		dlm_lockres_get(res);
-
 	}
 
 	/* at this point we have allocated everything we need,
 	 * and we have a hashed lockres with an extra ref and
 	 * the proper res->state flags. */
 	ret = 0;
+	spin_lock(&res->spinlock);
+	/* drop this either when master requery finds a different master
+	 * or when a lock is added by the recovery worker */
+	dlm_lockres_grab_inflight_ref(dlm, res);
 	if (mres->master == DLM_LOCK_RES_OWNER_UNKNOWN) {
 		/* migration cannot have an unknown master */
 		BUG_ON(!(mres->flags & DLM_MRES_RECOVERY));
@@ -1400,10 +1445,11 @@
 			  "unknown owner.. will need to requery: "
 			  "%.*s\n", mres->lockname_len, mres->lockname);
 	} else {
-		spin_lock(&res->spinlock);
+		/* take a reference now to pin the lockres, drop it
+		 * when locks are added in the worker */
 		dlm_change_lockres_owner(dlm, res, dlm->node_num);
-		spin_unlock(&res->spinlock);
 	}
+	spin_unlock(&res->spinlock);
 
 	/* queue up work for dlm_mig_lockres_worker */
 	dlm_grab(dlm);  /* get an extra ref for the work item */
@@ -1459,6 +1505,9 @@
 				   "this node will take it.\n",
 				   res->lockname.len, res->lockname.name);
 		} else {
+			spin_lock(&res->spinlock);
+			dlm_lockres_drop_inflight_ref(dlm, res);
+			spin_unlock(&res->spinlock);
 			mlog(0, "master needs to respond to sender "
 				  "that node %u still owns %.*s\n",
 				  real_master, res->lockname.len,
@@ -1578,7 +1627,8 @@
 /* this function cannot error, so unless the sending
  * or receiving of the message failed, the owner can
  * be trusted */
-int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data,
+			       void **ret_data)
 {
 	struct dlm_ctxt *dlm = data;
 	struct dlm_master_requery *req = (struct dlm_master_requery *)msg->buf;
@@ -1660,21 +1710,38 @@
 {
 	struct dlm_migratable_lock *ml;
 	struct list_head *queue;
+	struct list_head *tmpq = NULL;
 	struct dlm_lock *newlock = NULL;
 	struct dlm_lockstatus *lksb = NULL;
 	int ret = 0;
-	int i, bad;
+	int i, j, bad;
 	struct list_head *iter;
 	struct dlm_lock *lock = NULL;
+	u8 from = O2NM_MAX_NODES;
+	unsigned int added = 0;
 
 	mlog(0, "running %d locks for this lockres\n", mres->num_locks);
 	for (i=0; i<mres->num_locks; i++) {
 		ml = &(mres->ml[i]);
+
+		if (dlm_is_dummy_lock(dlm, ml, &from)) {
+			/* placeholder, just need to set the refmap bit */
+			BUG_ON(mres->num_locks != 1);
+			mlog(0, "%s:%.*s: dummy lock for %u\n",
+			     dlm->name, mres->lockname_len, mres->lockname,
+			     from);
+			spin_lock(&res->spinlock);
+			dlm_lockres_set_refmap_bit(from, res);
+			spin_unlock(&res->spinlock);
+			added++;
+			break;
+		}
 		BUG_ON(ml->highest_blocked != LKM_IVMODE);
 		newlock = NULL;
 		lksb = NULL;
 
 		queue = dlm_list_num_to_pointer(res, ml->list);
+		tmpq = NULL;
 
 		/* if the lock is for the local node it needs to
 		 * be moved to the proper location within the queue.
@@ -1684,11 +1751,16 @@
 			BUG_ON(!(mres->flags & DLM_MRES_MIGRATION));
 
 			spin_lock(&res->spinlock);
-			list_for_each(iter, queue) {
-				lock = list_entry (iter, struct dlm_lock, list);
-				if (lock->ml.cookie != ml->cookie)
-					lock = NULL;
-				else
+			for (j = DLM_GRANTED_LIST; j <= DLM_BLOCKED_LIST; j++) {
+				tmpq = dlm_list_idx_to_ptr(res, j);
+				list_for_each(iter, tmpq) {
+					lock = list_entry (iter, struct dlm_lock, list);
+					if (lock->ml.cookie != ml->cookie)
+						lock = NULL;
+					else
+						break;
+				}
+				if (lock)
 					break;
 			}
 
@@ -1698,12 +1770,20 @@
 				u64 c = ml->cookie;
 				mlog(ML_ERROR, "could not find local lock "
 					       "with cookie %u:%llu!\n",
-					       dlm_get_lock_cookie_node(c),
-					       dlm_get_lock_cookie_seq(c));
+				     dlm_get_lock_cookie_node(be64_to_cpu(c)),
+				     dlm_get_lock_cookie_seq(be64_to_cpu(c)));
+				__dlm_print_one_lock_resource(res);
 				BUG();
 			}
 			BUG_ON(lock->ml.node != ml->node);
 
+			if (tmpq != queue) {
+				mlog(0, "lock was on %u instead of %u for %.*s\n",
+				     j, ml->list, res->lockname.len, res->lockname.name);
+				spin_unlock(&res->spinlock);
+				continue;
+			}
+
 			/* see NOTE above about why we do not update
 			 * to match the master here */
 
@@ -1711,6 +1791,7 @@
 			/* do not alter lock refcount.  switching lists. */
 			list_move_tail(&lock->list, queue);
 			spin_unlock(&res->spinlock);
+			added++;
 
 			mlog(0, "just reordered a local lock!\n");
 			continue;
@@ -1799,14 +1880,14 @@
 				mlog(ML_ERROR, "%s:%.*s: %u:%llu: lock already "
 				     "exists on this lockres!\n", dlm->name,
 				     res->lockname.len, res->lockname.name,
-				     dlm_get_lock_cookie_node(c),
-				     dlm_get_lock_cookie_seq(c));
+				     dlm_get_lock_cookie_node(be64_to_cpu(c)),
+				     dlm_get_lock_cookie_seq(be64_to_cpu(c)));
 
 				mlog(ML_NOTICE, "sent lock: type=%d, conv=%d, "
 				     "node=%u, cookie=%u:%llu, queue=%d\n",
 	      			     ml->type, ml->convert_type, ml->node,
-				     dlm_get_lock_cookie_node(ml->cookie),
-				     dlm_get_lock_cookie_seq(ml->cookie),
+				     dlm_get_lock_cookie_node(be64_to_cpu(ml->cookie)),
+				     dlm_get_lock_cookie_seq(be64_to_cpu(ml->cookie)),
 				     ml->list);
 
 				__dlm_print_one_lock_resource(res);
@@ -1817,12 +1898,22 @@
 		if (!bad) {
 			dlm_lock_get(newlock);
 			list_add_tail(&newlock->list, queue);
+			mlog(0, "%s:%.*s: added lock for node %u, "
+			     "setting refmap bit\n", dlm->name,
+			     res->lockname.len, res->lockname.name, ml->node);
+			dlm_lockres_set_refmap_bit(ml->node, res);
+			added++;
 		}
 		spin_unlock(&res->spinlock);
 	}
 	mlog(0, "done running all the locks\n");
 
 leave:
+	/* balance the ref taken when the work was queued */
+	spin_lock(&res->spinlock);
+	dlm_lockres_drop_inflight_ref(dlm, res);
+	spin_unlock(&res->spinlock);
+
 	if (ret < 0) {
 		mlog_errno(ret);
 		if (newlock)
@@ -1935,9 +2026,11 @@
 		if (res->owner == dead_node) {
 			list_del_init(&res->recovering);
 			spin_lock(&res->spinlock);
+			/* new_master has our reference from
+			 * the lock state sent during recovery */
 			dlm_change_lockres_owner(dlm, res, new_master);
 			res->state &= ~DLM_LOCK_RES_RECOVERING;
-			if (!__dlm_lockres_unused(res))
+			if (__dlm_lockres_has_locks(res))
 				__dlm_dirty_lockres(dlm, res);
 			spin_unlock(&res->spinlock);
 			wake_up(&res->wq);
@@ -1977,9 +2070,11 @@
 					dlm_lockres_put(res);
 				}
 				spin_lock(&res->spinlock);
+				/* new_master has our reference from
+				 * the lock state sent during recovery */
 				dlm_change_lockres_owner(dlm, res, new_master);
 				res->state &= ~DLM_LOCK_RES_RECOVERING;
-				if (!__dlm_lockres_unused(res))
+				if (__dlm_lockres_has_locks(res))
 					__dlm_dirty_lockres(dlm, res);
 				spin_unlock(&res->spinlock);
 				wake_up(&res->wq);
@@ -2048,6 +2143,7 @@
 {
 	struct list_head *iter, *tmpiter;
 	struct dlm_lock *lock;
+	unsigned int freed = 0;
 
 	/* this node is the lockres master:
 	 * 1) remove any stale locks for the dead node
@@ -2062,6 +2158,7 @@
 		if (lock->ml.node == dead_node) {
 			list_del_init(&lock->list);
 			dlm_lock_put(lock);
+			freed++;
 		}
 	}
 	list_for_each_safe(iter, tmpiter, &res->converting) {
@@ -2069,6 +2166,7 @@
 		if (lock->ml.node == dead_node) {
 			list_del_init(&lock->list);
 			dlm_lock_put(lock);
+			freed++;
 		}
 	}
 	list_for_each_safe(iter, tmpiter, &res->blocked) {
@@ -2076,9 +2174,23 @@
 		if (lock->ml.node == dead_node) {
 			list_del_init(&lock->list);
 			dlm_lock_put(lock);
+			freed++;
 		}
 	}
 
+	if (freed) {
+		mlog(0, "%s:%.*s: freed %u locks for dead node %u, "
+		     "dropping ref from lockres\n", dlm->name,
+		     res->lockname.len, res->lockname.name, freed, dead_node);
+		BUG_ON(!test_bit(dead_node, res->refmap));
+		dlm_lockres_clear_refmap_bit(dead_node, res);
+	} else if (test_bit(dead_node, res->refmap)) {
+		mlog(0, "%s:%.*s: dead node %u had a ref, but had "
+		     "no locks and had not purged before dying\n", dlm->name,
+		     res->lockname.len, res->lockname.name, dead_node);
+		dlm_lockres_clear_refmap_bit(dead_node, res);
+	}
+
 	/* do not kick thread yet */
 	__dlm_dirty_lockres(dlm, res);
 }
@@ -2141,9 +2253,21 @@
 			spin_lock(&res->spinlock);
 			/* zero the lvb if necessary */
 			dlm_revalidate_lvb(dlm, res, dead_node);
-			if (res->owner == dead_node)
+			if (res->owner == dead_node) {
+				if (res->state & DLM_LOCK_RES_DROPPING_REF)
+					mlog(0, "%s:%.*s: owned by "
+					     "dead node %u, this node was "
+					     "dropping its ref when it died. "
+					     "continue, dropping the flag.\n",
+					     dlm->name, res->lockname.len,
+					     res->lockname.name, dead_node);
+
+				/* the wake_up for this will happen when the
+				 * RECOVERING flag is dropped later */
+				res->state &= ~DLM_LOCK_RES_DROPPING_REF;
+
 				dlm_move_lockres_to_recovery_list(dlm, res);
-			else if (res->owner == dlm->node_num) {
+			} else if (res->owner == dlm->node_num) {
 				dlm_free_dead_locks(dlm, res, dead_node);
 				__dlm_lockres_calc_usage(dlm, res);
 			}
@@ -2480,7 +2604,8 @@
 	return ret;
 }
 
-int dlm_begin_reco_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_begin_reco_handler(struct o2net_msg *msg, u32 len, void *data,
+			   void **ret_data)
 {
 	struct dlm_ctxt *dlm = data;
 	struct dlm_begin_reco *br = (struct dlm_begin_reco *)msg->buf;
@@ -2608,7 +2733,8 @@
 	return ret;
 }
 
-int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data,
+			      void **ret_data)
 {
 	struct dlm_ctxt *dlm = data;
 	struct dlm_finalize_reco *fr = (struct dlm_finalize_reco *)msg->buf;
diff --git a/fs/ocfs2/dlm/dlmthread.c b/fs/ocfs2/dlm/dlmthread.c
index 0c822f3..8ffa091 100644
--- a/fs/ocfs2/dlm/dlmthread.c
+++ b/fs/ocfs2/dlm/dlmthread.c
@@ -54,9 +54,6 @@
 #include "cluster/masklog.h"
 
 static int dlm_thread(void *data);
-static void dlm_purge_lockres_now(struct dlm_ctxt *dlm,
-				  struct dlm_lock_resource *lockres);
-
 static void dlm_flush_asts(struct dlm_ctxt *dlm);
 
 #define dlm_lock_is_remote(dlm, lock)     ((lock)->ml.node != (dlm)->node_num)
@@ -82,14 +79,33 @@
 	current->state = TASK_RUNNING;
 }
 
-
-int __dlm_lockres_unused(struct dlm_lock_resource *res)
+int __dlm_lockres_has_locks(struct dlm_lock_resource *res)
 {
 	if (list_empty(&res->granted) &&
 	    list_empty(&res->converting) &&
-	    list_empty(&res->blocked) &&
-	    list_empty(&res->dirty))
-		return 1;
+	    list_empty(&res->blocked))
+		return 0;
+	return 1;
+}
+
+/* "unused": the lockres has no locks, is not on the dirty list,
+ * has no inflight locks (in the gap between mastery and acquiring
+ * the first lock), and has no bits in its refmap.
+ * truly ready to be freed. */
+int __dlm_lockres_unused(struct dlm_lock_resource *res)
+{
+	if (!__dlm_lockres_has_locks(res) &&
+	    (list_empty(&res->dirty) && !(res->state & DLM_LOCK_RES_DIRTY))) {
+		/* try not to scan the bitmap unless the first two
+		 * conditions are already true */
+		int bit = find_next_bit(res->refmap, O2NM_MAX_NODES, 0);
+		if (bit >= O2NM_MAX_NODES) {
+			/* since the bit for dlm->node_num is not
+			 * set, inflight_locks better be zero */
+			BUG_ON(res->inflight_locks != 0);
+			return 1;
+		}
+	}
 	return 0;
 }
 
@@ -106,46 +122,21 @@
 	assert_spin_locked(&res->spinlock);
 
 	if (__dlm_lockres_unused(res)){
-		/* For now, just keep any resource we master */
-		if (res->owner == dlm->node_num)
-		{
-			if (!list_empty(&res->purge)) {
-				mlog(0, "we master %s:%.*s, but it is on "
-				     "the purge list.  Removing\n",
-				     dlm->name, res->lockname.len,
-				     res->lockname.name);
-				list_del_init(&res->purge);
-				dlm->purge_count--;
-			}
-			return;
-		}
-
 		if (list_empty(&res->purge)) {
-			mlog(0, "putting lockres %.*s from purge list\n",
-			     res->lockname.len, res->lockname.name);
+			mlog(0, "putting lockres %.*s:%p onto purge list\n",
+			     res->lockname.len, res->lockname.name, res);
 
 			res->last_used = jiffies;
+			dlm_lockres_get(res);
 			list_add_tail(&res->purge, &dlm->purge_list);
 			dlm->purge_count++;
-
-			/* if this node is not the owner, there is
-			 * no way to keep track of who the owner could be.
-			 * unhash it to avoid serious problems. */
-			if (res->owner != dlm->node_num) {
-				mlog(0, "%s:%.*s: doing immediate "
-				     "purge of lockres owned by %u\n",
-				     dlm->name, res->lockname.len,
-				     res->lockname.name, res->owner);
-
-				dlm_purge_lockres_now(dlm, res);
-			}
 		}
 	} else if (!list_empty(&res->purge)) {
-		mlog(0, "removing lockres %.*s from purge list, "
-		     "owner=%u\n", res->lockname.len, res->lockname.name,
-		     res->owner);
+		mlog(0, "removing lockres %.*s:%p from purge list, owner=%u\n",
+		     res->lockname.len, res->lockname.name, res, res->owner);
 
 		list_del_init(&res->purge);
+		dlm_lockres_put(res);
 		dlm->purge_count--;
 	}
 }
@@ -163,68 +154,65 @@
 	spin_unlock(&dlm->spinlock);
 }
 
-/* TODO: Eventual API: Called with the dlm spinlock held, may drop it
- * to do migration, but will re-acquire before exit. */
-void dlm_purge_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *lockres)
+static int dlm_purge_lockres(struct dlm_ctxt *dlm,
+			     struct dlm_lock_resource *res)
 {
 	int master;
-	int ret;
+	int ret = 0;
 
-	spin_lock(&lockres->spinlock);
-	master = lockres->owner == dlm->node_num;
-	spin_unlock(&lockres->spinlock);
-
-	mlog(0, "purging lockres %.*s, master = %d\n", lockres->lockname.len,
-	     lockres->lockname.name, master);
-
-	/* Non master is the easy case -- no migration required, just
-	 * quit. */
+	spin_lock(&res->spinlock);
+	if (!__dlm_lockres_unused(res)) {
+		spin_unlock(&res->spinlock);
+		mlog(0, "%s:%.*s: tried to purge but not unused\n",
+		     dlm->name, res->lockname.len, res->lockname.name);
+		return -ENOTEMPTY;
+	}
+	master = (res->owner == dlm->node_num);
 	if (!master)
-		goto finish;
+		res->state |= DLM_LOCK_RES_DROPPING_REF;
+	spin_unlock(&res->spinlock);
 
-	/* Wheee! Migrate lockres here! */
-	spin_unlock(&dlm->spinlock);
-again:
+	mlog(0, "purging lockres %.*s, master = %d\n", res->lockname.len,
+	     res->lockname.name, master);
 
-	ret = dlm_migrate_lockres(dlm, lockres, O2NM_MAX_NODES);
-	if (ret == -ENOTEMPTY) {
-		mlog(ML_ERROR, "lockres %.*s still has local locks!\n",
-		     lockres->lockname.len, lockres->lockname.name);
-
-		BUG();
-	} else if (ret < 0) {
-		mlog(ML_NOTICE, "lockres %.*s: migrate failed, retrying\n",
-		     lockres->lockname.len, lockres->lockname.name);
-		msleep(100);
-		goto again;
+	if (!master) {
+		spin_lock(&res->spinlock);
+		/* This ensures that clear refmap is sent after the set */
+		__dlm_wait_on_lockres_flags(res, DLM_LOCK_RES_SETREF_INPROG);
+		spin_unlock(&res->spinlock);
+		/* drop spinlock to do messaging, retake below */
+		spin_unlock(&dlm->spinlock);
+		/* clear our bit from the master's refmap, ignore errors */
+		ret = dlm_drop_lockres_ref(dlm, res);
+		if (ret < 0) {
+			mlog_errno(ret);
+			if (!dlm_is_host_down(ret))
+				BUG();
+		}
+		mlog(0, "%s:%.*s: dlm_deref_lockres returned %d\n",
+		     dlm->name, res->lockname.len, res->lockname.name, ret);
+		spin_lock(&dlm->spinlock);
 	}
 
-	spin_lock(&dlm->spinlock);
-
-finish:
-	if (!list_empty(&lockres->purge)) {
-		list_del_init(&lockres->purge);
+	if (!list_empty(&res->purge)) {
+		mlog(0, "removing lockres %.*s:%p from purgelist, "
+		     "master = %d\n", res->lockname.len, res->lockname.name,
+		     res, master);
+		list_del_init(&res->purge);
+		dlm_lockres_put(res);
 		dlm->purge_count--;
 	}
-	__dlm_unhash_lockres(lockres);
-}
+	__dlm_unhash_lockres(res);
 
-/* make an unused lockres go away immediately.
- * as soon as the dlm spinlock is dropped, this lockres
- * will not be found. kfree still happens on last put. */
-static void dlm_purge_lockres_now(struct dlm_ctxt *dlm,
-				  struct dlm_lock_resource *lockres)
-{
-	assert_spin_locked(&dlm->spinlock);
-	assert_spin_locked(&lockres->spinlock);
-
-	BUG_ON(!__dlm_lockres_unused(lockres));
-
-	if (!list_empty(&lockres->purge)) {
-		list_del_init(&lockres->purge);
-		dlm->purge_count--;
+	/* lockres is not in the hash now.  drop the flag and wake up
+	 * any processes waiting in dlm_get_lock_resource. */
+	if (!master) {
+		spin_lock(&res->spinlock);
+		res->state &= ~DLM_LOCK_RES_DROPPING_REF;
+		spin_unlock(&res->spinlock);
+		wake_up(&res->wq);
 	}
-	__dlm_unhash_lockres(lockres);
+	return 0;
 }
 
 static void dlm_run_purge_list(struct dlm_ctxt *dlm,
@@ -268,13 +256,17 @@
 			break;
 		}
 
+		mlog(0, "removing lockres %.*s:%p from purgelist\n",
+		     lockres->lockname.len, lockres->lockname.name, lockres);
 		list_del_init(&lockres->purge);
+		dlm_lockres_put(lockres);
 		dlm->purge_count--;
 
 		/* This may drop and reacquire the dlm spinlock if it
 		 * has to do migration. */
 		mlog(0, "calling dlm_purge_lockres!\n");
-		dlm_purge_lockres(dlm, lockres);
+		if (dlm_purge_lockres(dlm, lockres))
+			BUG();
 		mlog(0, "DONE calling dlm_purge_lockres!\n");
 
 		/* Avoid adding any scheduling latencies */
@@ -467,12 +459,17 @@
 	assert_spin_locked(&res->spinlock);
 
 	/* don't shuffle secondary queues */
-	if ((res->owner == dlm->node_num) &&
-	    !(res->state & DLM_LOCK_RES_DIRTY)) {
-		/* ref for dirty_list */
-		dlm_lockres_get(res);
-		list_add_tail(&res->dirty, &dlm->dirty_list);
-		res->state |= DLM_LOCK_RES_DIRTY;
+	if ((res->owner == dlm->node_num)) {
+		if (res->state & (DLM_LOCK_RES_MIGRATING |
+				  DLM_LOCK_RES_BLOCK_DIRTY))
+		    return;
+
+		if (list_empty(&res->dirty)) {
+			/* ref for dirty_list */
+			dlm_lockres_get(res);
+			list_add_tail(&res->dirty, &dlm->dirty_list);
+			res->state |= DLM_LOCK_RES_DIRTY;
+		}
 	}
 }
 
@@ -651,7 +648,7 @@
 			dlm_lockres_get(res);
 
 			spin_lock(&res->spinlock);
-			res->state &= ~DLM_LOCK_RES_DIRTY;
+			/* We clear the DLM_LOCK_RES_DIRTY state once we shuffle lists below */
 			list_del_init(&res->dirty);
 			spin_unlock(&res->spinlock);
 			spin_unlock(&dlm->spinlock);
@@ -675,10 +672,11 @@
 			/* it is now ok to move lockreses in these states
 			 * to the dirty list, assuming that they will only be
 			 * dirty for a short while. */
+			BUG_ON(res->state & DLM_LOCK_RES_MIGRATING);
 			if (res->state & (DLM_LOCK_RES_IN_PROGRESS |
-					  DLM_LOCK_RES_MIGRATING |
 					  DLM_LOCK_RES_RECOVERING)) {
 				/* move it to the tail and keep going */
+				res->state &= ~DLM_LOCK_RES_DIRTY;
 				spin_unlock(&res->spinlock);
 				mlog(0, "delaying list shuffling for in-"
 				     "progress lockres %.*s, state=%d\n",
@@ -699,6 +697,7 @@
 
 			/* called while holding lockres lock */
 			dlm_shuffle_lists(dlm, res);
+			res->state &= ~DLM_LOCK_RES_DIRTY;
 			spin_unlock(&res->spinlock);
 
 			dlm_lockres_calc_usage(dlm, res);
@@ -709,11 +708,8 @@
 			/* if the lock was in-progress, stick
 			 * it on the back of the list */
 			if (delay) {
-				/* ref for dirty_list */
-				dlm_lockres_get(res);
 				spin_lock(&res->spinlock);
-				list_add_tail(&res->dirty, &dlm->dirty_list);
-				res->state |= DLM_LOCK_RES_DIRTY;
+				__dlm_dirty_lockres(dlm, res);
 				spin_unlock(&res->spinlock);
 			}
 			dlm_lockres_put(res);
diff --git a/fs/ocfs2/dlm/dlmunlock.c b/fs/ocfs2/dlm/dlmunlock.c
index 37be4b2..86ca085 100644
--- a/fs/ocfs2/dlm/dlmunlock.c
+++ b/fs/ocfs2/dlm/dlmunlock.c
@@ -147,6 +147,10 @@
 		goto leave;
 	}
 
+	if (res->state & DLM_LOCK_RES_MIGRATING) {
+		status = DLM_MIGRATING;
+		goto leave;
+	}
 
 	/* see above for what the spec says about
 	 * LKM_CANCEL and the lock queue state */
@@ -244,8 +248,8 @@
 		/* this should always be coupled with list removal */
 		BUG_ON(!(actions & DLM_UNLOCK_REMOVE_LOCK));
 		mlog(0, "lock %u:%llu should be gone now! refs=%d\n",
-		     dlm_get_lock_cookie_node(lock->ml.cookie),
-		     dlm_get_lock_cookie_seq(lock->ml.cookie),
+		     dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
+		     dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
 		     atomic_read(&lock->lock_refs.refcount)-1);
 		dlm_lock_put(lock);
 	}
@@ -379,7 +383,8 @@
  * returns: DLM_NORMAL, DLM_BADARGS, DLM_IVLOCKID,
  *          return value from dlmunlock_master
  */
-int dlm_unlock_lock_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_unlock_lock_handler(struct o2net_msg *msg, u32 len, void *data,
+			    void **ret_data)
 {
 	struct dlm_ctxt *dlm = data;
 	struct dlm_unlock_lock *unlock = (struct dlm_unlock_lock *)msg->buf;
@@ -502,8 +507,8 @@
 	if (!found)
 		mlog(ML_ERROR, "failed to find lock to unlock! "
 			       "cookie=%u:%llu\n",
-			       dlm_get_lock_cookie_node(unlock->cookie),
-			       dlm_get_lock_cookie_seq(unlock->cookie));
+		     dlm_get_lock_cookie_node(be64_to_cpu(unlock->cookie)),
+		     dlm_get_lock_cookie_seq(be64_to_cpu(unlock->cookie)));
 	else
 		dlm_lock_put(lock);
 
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h
index e121636..d026b4f 100644
--- a/fs/ocfs2/journal.h
+++ b/fs/ocfs2/journal.h
@@ -306,8 +306,8 @@
  * for the dinode, one for the new block. */
 #define OCFS2_SIMPLE_DIR_EXTEND_CREDITS (2)
 
-/* file update (nlink, etc) + dir entry block */
-#define OCFS2_LINK_CREDITS  (OCFS2_INODE_UPDATE_CREDITS + 1)
+/* file update (nlink, etc) + directory mtime/ctime + dir entry block */
+#define OCFS2_LINK_CREDITS  (2*OCFS2_INODE_UPDATE_CREDITS + 1)
 
 /* inode + dir inode (if we unlink a dir), + dir entry block + orphan
  * dir inode link */
diff --git a/fs/ocfs2/vote.c b/fs/ocfs2/vote.c
index 0afd8b9..f30e63b 100644
--- a/fs/ocfs2/vote.c
+++ b/fs/ocfs2/vote.c
@@ -887,7 +887,7 @@
 
 static int ocfs2_handle_response_message(struct o2net_msg *msg,
 					 u32 len,
-					 void *data)
+					 void *data, void **ret_data)
 {
 	unsigned int response_id, node_num;
 	int response_status;
@@ -943,7 +943,7 @@
 
 static int ocfs2_handle_vote_message(struct o2net_msg *msg,
 				     u32 len,
-				     void *data)
+				     void *data, void **ret_data)
 {
 	int status;
 	struct ocfs2_super *osb = data;
@@ -1007,7 +1007,7 @@
 					osb->net_key,
 					sizeof(struct ocfs2_response_msg),
 					ocfs2_handle_response_message,
-					osb, &osb->osb_net_handlers);
+					osb, NULL, &osb->osb_net_handlers);
 	if (status) {
 		mlog_errno(status);
 		goto bail;
@@ -1017,7 +1017,7 @@
 					osb->net_key,
 					sizeof(struct ocfs2_vote_msg),
 					ocfs2_handle_vote_message,
-					osb, &osb->osb_net_handlers);
+					osb, NULL, &osb->osb_net_handlers);
 	if (status) {
 		mlog_errno(status);
 		goto bail;
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index e8f540d..d3b9f5f 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 
 #include <asm/uaccess.h>
+#include <asm/semaphore.h>
 
 #include "sysfs.h"
 
@@ -146,7 +147,7 @@
  Error:
 	module_put(attr->attr.owner);
  Done:
-	if (error && kobj)
+	if (error)
 		kobject_put(kobj);
 	return error;
 }
@@ -157,8 +158,7 @@
 	struct bin_attribute * attr = to_bin_attr(file->f_path.dentry);
 	u8 * buffer = file->private_data;
 
-	if (kobj) 
-		kobject_put(kobj);
+	kobject_put(kobj);
 	module_put(attr->attr.owner);
 	kfree(buffer);
 	return 0;
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 511edef..9dcdf55 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <linux/kobject.h>
 #include <linux/namei.h>
+#include <asm/semaphore.h>
 #include "sysfs.h"
 
 DECLARE_RWSEM(sysfs_rename_sem);
@@ -32,8 +33,7 @@
 /*
  * Allocates a new sysfs_dirent and links it to the parent sysfs_dirent
  */
-static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd,
-						void * element)
+static struct sysfs_dirent * __sysfs_new_dirent(void * element)
 {
 	struct sysfs_dirent * sd;
 
@@ -45,12 +45,28 @@
 	atomic_set(&sd->s_count, 1);
 	atomic_set(&sd->s_event, 1);
 	INIT_LIST_HEAD(&sd->s_children);
-	list_add(&sd->s_sibling, &parent_sd->s_children);
+	INIT_LIST_HEAD(&sd->s_sibling);
 	sd->s_element = element;
 
 	return sd;
 }
 
+static void __sysfs_list_dirent(struct sysfs_dirent *parent_sd,
+			      struct sysfs_dirent *sd)
+{
+	if (sd)
+		list_add(&sd->s_sibling, &parent_sd->s_children);
+}
+
+static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent *parent_sd,
+						void * element)
+{
+	struct sysfs_dirent *sd;
+	sd = __sysfs_new_dirent(element);
+	__sysfs_list_dirent(parent_sd, sd);
+	return sd;
+}
+
 /*
  *
  * Return -EEXIST if there is already a sysfs element with the same name for
@@ -77,14 +93,14 @@
 }
 
 
-int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
-			void * element, umode_t mode, int type)
+static struct sysfs_dirent *
+__sysfs_make_dirent(struct dentry *dentry, void *element, mode_t mode, int type)
 {
 	struct sysfs_dirent * sd;
 
-	sd = sysfs_new_dirent(parent_sd, element);
+	sd = __sysfs_new_dirent(element);
 	if (!sd)
-		return -ENOMEM;
+		goto out;
 
 	sd->s_mode = mode;
 	sd->s_type = type;
@@ -94,7 +110,19 @@
 		dentry->d_op = &sysfs_dentry_ops;
 	}
 
-	return 0;
+out:
+	return sd;
+}
+
+int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
+			void * element, umode_t mode, int type)
+{
+	struct sysfs_dirent *sd;
+
+	sd = __sysfs_make_dirent(dentry, element, mode, type);
+	__sysfs_list_dirent(parent_sd, sd);
+
+	return sd ? 0 : -ENOMEM;
 }
 
 static int init_dir(struct inode * inode)
@@ -165,11 +193,11 @@
 
 /**
  *	sysfs_create_dir - create a directory for an object.
- *	@parent:	parent parent object.
  *	@kobj:		object we're creating directory for. 
+ *	@shadow_parent:	parent parent object.
  */
 
-int sysfs_create_dir(struct kobject * kobj)
+int sysfs_create_dir(struct kobject * kobj, struct dentry *shadow_parent)
 {
 	struct dentry * dentry = NULL;
 	struct dentry * parent;
@@ -177,7 +205,9 @@
 
 	BUG_ON(!kobj);
 
-	if (kobj->parent)
+	if (shadow_parent)
+		parent = shadow_parent;
+	else if (kobj->parent)
 		parent = kobj->parent->dentry;
 	else if (sysfs_mount && sysfs_mount->mnt_sb)
 		parent = sysfs_mount->mnt_sb->s_root;
@@ -298,21 +328,12 @@
 }
 
 
-/**
- *	sysfs_remove_dir - remove an object's directory.
- *	@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.
- */
-
-void sysfs_remove_dir(struct kobject * kobj)
+static void __sysfs_remove_dir(struct dentry *dentry)
 {
-	struct dentry * dentry = dget(kobj->dentry);
 	struct sysfs_dirent * parent_sd;
 	struct sysfs_dirent * sd, * tmp;
 
+	dget(dentry);
 	if (!dentry)
 		return;
 
@@ -333,32 +354,60 @@
 	 * Drop reference from dget() on entrance.
 	 */
 	dput(dentry);
+}
+
+/**
+ *	sysfs_remove_dir - remove an object's directory.
+ *	@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.
+ */
+
+void sysfs_remove_dir(struct kobject * kobj)
+{
+	__sysfs_remove_dir(kobj->dentry);
 	kobj->dentry = NULL;
 }
 
-int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
+int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,
+		     const char *new_name)
 {
 	int error = 0;
-	struct dentry * new_dentry, * parent;
+	struct dentry * new_dentry;
 
-	if (!strcmp(kobject_name(kobj), new_name))
-		return -EINVAL;
-
-	if (!kobj->parent)
-		return -EINVAL;
+	if (!new_parent)
+		return -EFAULT;
 
 	down_write(&sysfs_rename_sem);
-	parent = kobj->parent->dentry;
+	mutex_lock(&new_parent->d_inode->i_mutex);
 
-	mutex_lock(&parent->d_inode->i_mutex);
-
-	new_dentry = lookup_one_len(new_name, parent, strlen(new_name));
+	new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
 	if (!IS_ERR(new_dentry)) {
-  		if (!new_dentry->d_inode) {
+		/* By allowing two different directories with the
+		 * same d_parent we allow this routine to move
+		 * between different shadows of the same directory
+		 */
+		if (kobj->dentry->d_parent->d_inode != new_parent->d_inode)
+			return -EINVAL;
+		else if (new_dentry->d_parent->d_inode != new_parent->d_inode)
+			error = -EINVAL;
+		else if (new_dentry == kobj->dentry)
+			error = -EINVAL;
+		else if (!new_dentry->d_inode) {
 			error = kobject_set_name(kobj, "%s", new_name);
 			if (!error) {
+				struct sysfs_dirent *sd, *parent_sd;
+
 				d_add(new_dentry, NULL);
 				d_move(kobj->dentry, new_dentry);
+
+				sd = kobj->dentry->d_fsdata;
+				parent_sd = new_parent->d_fsdata;
+
+				list_del_init(&sd->s_sibling);
+				list_add(&sd->s_sibling, &parent_sd->s_children);
 			}
 			else
 				d_drop(new_dentry);
@@ -366,7 +415,7 @@
 			error = -EEXIST;
 		dput(new_dentry);
 	}
-	mutex_unlock(&parent->d_inode->i_mutex);
+	mutex_unlock(&new_parent->d_inode->i_mutex);
 	up_write(&sysfs_rename_sem);
 
 	return error;
@@ -378,12 +427,10 @@
 	struct sysfs_dirent *new_parent_sd, *sd;
 	int error;
 
-	if (!new_parent)
-		return -EINVAL;
-
 	old_parent_dentry = kobj->parent ?
 		kobj->parent->dentry : sysfs_mount->mnt_sb->s_root;
-	new_parent_dentry = new_parent->dentry;
+	new_parent_dentry = new_parent ?
+		new_parent->dentry : sysfs_mount->mnt_sb->s_root;
 
 again:
 	mutex_lock(&old_parent_dentry->d_inode->i_mutex);
@@ -547,6 +594,95 @@
 	return offset;
 }
 
+
+/**
+ *	sysfs_make_shadowed_dir - Setup so a directory can be shadowed
+ *	@kobj:	object we're creating shadow of.
+ */
+
+int sysfs_make_shadowed_dir(struct kobject *kobj,
+	void * (*follow_link)(struct dentry *, struct nameidata *))
+{
+	struct inode *inode;
+	struct inode_operations *i_op;
+
+	inode = kobj->dentry->d_inode;
+	if (inode->i_op != &sysfs_dir_inode_operations)
+		return -EINVAL;
+
+	i_op = kmalloc(sizeof(*i_op), GFP_KERNEL);
+	if (!i_op)
+		return -ENOMEM;
+
+	memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op));
+	i_op->follow_link = follow_link;
+
+	/* Locking of inode->i_op?
+	 * Since setting i_op is a single word write and they
+	 * are atomic we should be ok here.
+	 */
+	inode->i_op = i_op;
+	return 0;
+}
+
+/**
+ *	sysfs_create_shadow_dir - create a shadow directory for an object.
+ *	@kobj:	object we're creating directory for.
+ *
+ *	sysfs_make_shadowed_dir must already have been called on this
+ *	directory.
+ */
+
+struct dentry *sysfs_create_shadow_dir(struct kobject *kobj)
+{
+	struct sysfs_dirent *sd;
+	struct dentry *parent, *dir, *shadow;
+	struct inode *inode;
+
+	dir = kobj->dentry;
+	inode = dir->d_inode;
+	parent = dir->d_parent;
+	shadow = ERR_PTR(-EINVAL);
+	if (!sysfs_is_shadowed_inode(inode))
+		goto out;
+
+	shadow = d_alloc(parent, &dir->d_name);
+	if (!shadow)
+		goto nomem;
+
+	sd = __sysfs_make_dirent(shadow, kobj, inode->i_mode, SYSFS_DIR);
+	if (!sd)
+		goto nomem;
+
+	d_instantiate(shadow, igrab(inode));
+	inc_nlink(inode);
+	inc_nlink(parent->d_inode);
+	shadow->d_op = &sysfs_dentry_ops;
+
+	dget(shadow);		/* Extra count - pin the dentry in core */
+
+out:
+	return shadow;
+nomem:
+	dput(shadow);
+	shadow = ERR_PTR(-ENOMEM);
+	goto out;
+}
+
+/**
+ *	sysfs_remove_shadow_dir - remove an object's directory.
+ *	@shadow: dentry of shadow directory
+ *
+ *	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.
+ */
+
+void sysfs_remove_shadow_dir(struct dentry *shadow)
+{
+	__sysfs_remove_dir(shadow);
+}
+
 const struct file_operations sysfs_dir_operations = {
 	.open		= sysfs_dir_open,
 	.release	= sysfs_dir_close,
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 9cfe53e..c0e1176 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -7,6 +7,7 @@
 #include <linux/kobject.h>
 #include <linux/namei.h>
 #include <linux/poll.h>
+#include <linux/list.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 
@@ -50,17 +51,29 @@
 	.store	= subsys_attr_store,
 };
 
+/**
+ *	add_to_collection - add buffer to a collection
+ *	@buffer:	buffer to be added
+ *	@node		inode of set to add to
+ */
 
-struct sysfs_buffer {
-	size_t			count;
-	loff_t			pos;
-	char			* page;
-	struct sysfs_ops	* ops;
-	struct semaphore	sem;
-	int			needs_read_fill;
-	int			event;
-};
+static inline void
+add_to_collection(struct sysfs_buffer *buffer, struct inode *node)
+{
+	struct sysfs_buffer_collection *set = node->i_private;
 
+	mutex_lock(&node->i_mutex);
+	list_add(&buffer->associates, &set->associates);
+	mutex_unlock(&node->i_mutex);
+}
+
+static inline void
+remove_from_collection(struct sysfs_buffer *buffer, struct inode *node)
+{
+	mutex_lock(&node->i_mutex);
+	list_del(&buffer->associates);
+	mutex_unlock(&node->i_mutex);
+}
 
 /**
  *	fill_read_buffer - allocate and fill buffer from object.
@@ -70,7 +83,8 @@
  *	Allocate @buffer->page, if it hasn't been already, then call the
  *	kobject's show() method to fill the buffer with this attribute's 
  *	data. 
- *	This is called only once, on the file's first read. 
+ *	This is called only once, on the file's first read unless an error
+ *	is returned.
  */
 static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
 {
@@ -88,12 +102,13 @@
 
 	buffer->event = atomic_read(&sd->s_event);
 	count = ops->show(kobj,attr,buffer->page);
-	buffer->needs_read_fill = 0;
 	BUG_ON(count > (ssize_t)PAGE_SIZE);
-	if (count >= 0)
+	if (count >= 0) {
+		buffer->needs_read_fill = 0;
 		buffer->count = count;
-	else
+	} else {
 		ret = count;
+	}
 	return ret;
 }
 
@@ -153,6 +168,10 @@
 	ssize_t retval = 0;
 
 	down(&buffer->sem);
+	if (buffer->orphaned) {
+		retval = -ENODEV;
+		goto out;
+	}
 	if (buffer->needs_read_fill) {
 		if ((retval = fill_read_buffer(file->f_path.dentry,buffer)))
 			goto out;
@@ -165,7 +184,6 @@
 	return retval;
 }
 
-
 /**
  *	fill_write_buffer - copy buffer from userspace.
  *	@buffer:	data buffer for file.
@@ -243,19 +261,25 @@
 	ssize_t len;
 
 	down(&buffer->sem);
+	if (buffer->orphaned) {
+		len = -ENODEV;
+		goto out;
+	}
 	len = fill_write_buffer(buffer, buf, count);
 	if (len > 0)
 		len = flush_write_buffer(file->f_path.dentry, buffer, len);
 	if (len > 0)
 		*ppos += len;
+out:
 	up(&buffer->sem);
 	return len;
 }
 
-static int check_perm(struct inode * inode, struct file * file)
+static int sysfs_open_file(struct inode *inode, struct file *file)
 {
 	struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent);
 	struct attribute * attr = to_attr(file->f_path.dentry);
+	struct sysfs_buffer_collection *set;
 	struct sysfs_buffer * buffer;
 	struct sysfs_ops * ops = NULL;
 	int error = 0;
@@ -285,6 +309,18 @@
 	if (!ops)
 		goto Eaccess;
 
+	/* make sure we have a collection to add our buffers to */
+	mutex_lock(&inode->i_mutex);
+	if (!(set = inode->i_private)) {
+		if (!(set = inode->i_private = kmalloc(sizeof(struct sysfs_buffer_collection), GFP_KERNEL))) {
+			error = -ENOMEM;
+			goto Done;
+		} else {
+			INIT_LIST_HEAD(&set->associates);
+		}
+	}
+	mutex_unlock(&inode->i_mutex);
+
 	/* File needs write support.
 	 * The inode's perms must say it's ok, 
 	 * and we must have a store method.
@@ -310,9 +346,11 @@
 	 */
 	buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
 	if (buffer) {
+		INIT_LIST_HEAD(&buffer->associates);
 		init_MUTEX(&buffer->sem);
 		buffer->needs_read_fill = 1;
 		buffer->ops = ops;
+		add_to_collection(buffer, inode);
 		file->private_data = buffer;
 	} else
 		error = -ENOMEM;
@@ -325,16 +363,11 @@
 	error = -EACCES;
 	module_put(attr->owner);
  Done:
-	if (error && kobj)
+	if (error)
 		kobject_put(kobj);
 	return error;
 }
 
-static int sysfs_open_file(struct inode * inode, struct file * filp)
-{
-	return check_perm(inode,filp);
-}
-
 static int sysfs_release(struct inode * inode, struct file * filp)
 {
 	struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent);
@@ -342,8 +375,9 @@
 	struct module * owner = attr->owner;
 	struct sysfs_buffer * buffer = filp->private_data;
 
-	if (kobj) 
-		kobject_put(kobj);
+	if (buffer)
+		remove_from_collection(buffer, inode);
+	kobject_put(kobj);
 	/* After this point, attr should not be accessed. */
 	module_put(owner);
 
@@ -548,7 +582,7 @@
 
 void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
 {
-	sysfs_hash_and_remove(kobj->dentry,attr->name);
+	sysfs_hash_and_remove(kobj->dentry, attr->name);
 }
 
 
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 122145b..b20951c 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -13,6 +13,8 @@
 #include <linux/dcache.h>
 #include <linux/namei.h>
 #include <linux/err.h>
+#include <linux/fs.h>
+#include <asm/semaphore.h>
 #include "sysfs.h"
 
 
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index e79e38d..542d2bc 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -13,6 +13,7 @@
 #include <linux/backing-dev.h>
 #include <linux/capability.h>
 #include <linux/errno.h>
+#include <asm/semaphore.h>
 #include "sysfs.h"
 
 extern struct super_block * sysfs_sb;
@@ -32,6 +33,16 @@
 	.setattr	= sysfs_setattr,
 };
 
+void sysfs_delete_inode(struct inode *inode)
+{
+	/* Free the shadowed directory inode operations */
+	if (sysfs_is_shadowed_inode(inode)) {
+		kfree(inode->i_op);
+		inode->i_op = NULL;
+	}
+	return generic_delete_inode(inode);
+}
+
 int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
 {
 	struct inode * inode = dentry->d_inode;
@@ -209,6 +220,22 @@
 	return NULL;
 }
 
+static inline void orphan_all_buffers(struct inode *node)
+{
+	struct sysfs_buffer_collection *set = node->i_private;
+	struct sysfs_buffer *buf;
+
+	mutex_lock_nested(&node->i_mutex, I_MUTEX_CHILD);
+	if (node->i_private) {
+		list_for_each_entry(buf, &set->associates, associates) {
+			down(&buf->sem);
+			buf->orphaned = 1;
+			up(&buf->sem);
+		}
+	}
+	mutex_unlock(&node->i_mutex);
+}
+
 
 /*
  * Unhashes the dentry corresponding to given sysfs_dirent
@@ -217,16 +244,23 @@
 void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
 {
 	struct dentry * dentry = sd->s_dentry;
+	struct inode *inode;
 
 	if (dentry) {
 		spin_lock(&dcache_lock);
 		spin_lock(&dentry->d_lock);
 		if (!(d_unhashed(dentry) && dentry->d_inode)) {
+			inode = dentry->d_inode;
+			spin_lock(&inode->i_lock);
+			__iget(inode);
+			spin_unlock(&inode->i_lock);
 			dget_locked(dentry);
 			__d_drop(dentry);
 			spin_unlock(&dentry->d_lock);
 			spin_unlock(&dcache_lock);
 			simple_unlink(parent->d_inode, dentry);
+			orphan_all_buffers(inode);
+			iput(inode);
 		} else {
 			spin_unlock(&dentry->d_lock);
 			spin_unlock(&dcache_lock);
@@ -248,7 +282,7 @@
 		return -ENOENT;
 
 	parent_sd = dir->d_fsdata;
-	mutex_lock(&dir->d_inode->i_mutex);
+	mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
 	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
 		if (!sd->s_element)
 			continue;
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index e503f85..f6a87a8 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -8,6 +8,7 @@
 #include <linux/mount.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
+#include <asm/semaphore.h>
 
 #include "sysfs.h"
 
@@ -18,9 +19,12 @@
 struct super_block * sysfs_sb = NULL;
 struct kmem_cache *sysfs_dir_cachep;
 
+static void sysfs_clear_inode(struct inode *inode);
+
 static struct super_operations sysfs_ops = {
 	.statfs		= simple_statfs,
-	.drop_inode	= generic_delete_inode,
+	.drop_inode	= sysfs_delete_inode,
+	.clear_inode	= sysfs_clear_inode,
 };
 
 static struct sysfs_dirent sysfs_root = {
@@ -31,6 +35,11 @@
 	.s_iattr	= NULL,
 };
 
+static void sysfs_clear_inode(struct inode *inode)
+{
+	kfree(inode->i_private);
+}
+
 static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct inode *inode;
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index f50e3cc..4869f61 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -7,6 +7,7 @@
 #include <linux/module.h>
 #include <linux/kobject.h>
 #include <linux/namei.h>
+#include <asm/semaphore.h>
 
 #include "sysfs.h"
 
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index bd7cec2..fe1cbfd 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -2,6 +2,7 @@
 extern struct vfsmount * sysfs_mount;
 extern struct kmem_cache *sysfs_dir_cachep;
 
+extern void sysfs_delete_inode(struct inode *inode);
 extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *);
 extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *));
 
@@ -33,6 +34,22 @@
 	struct kobject * target_kobj;
 };
 
+struct sysfs_buffer {
+	struct list_head		associates;
+	size_t				count;
+	loff_t				pos;
+	char				* page;
+	struct sysfs_ops		* ops;
+	struct semaphore		sem;
+	int				orphaned;
+	int				needs_read_fill;
+	int				event;
+};
+
+struct sysfs_buffer_collection {
+	struct list_head	associates;
+};
+
 static inline struct kobject * to_kobj(struct dentry * dentry)
 {
 	struct sysfs_dirent * sd = dentry->d_fsdata;
@@ -96,3 +113,7 @@
 		release_sysfs_dirent(sd);
 }
 
+static inline int sysfs_is_shadowed_inode(struct inode *inode)
+{
+	return S_ISDIR(inode->i_mode) && inode->i_op->follow_link;
+}
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index 433b6f6..a6c0ca9 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -106,12 +106,13 @@
 	char *kaddr = page_address(page);
 	unsigned offs, rec_len;
 	unsigned limit = PAGE_CACHE_SIZE;
+	const unsigned chunk_mask = UFS_SB(sb)->s_uspi->s_dirblksize - 1;
 	struct ufs_dir_entry *p;
 	char *error;
 
 	if ((dir->i_size >> PAGE_CACHE_SHIFT) == page->index) {
 		limit = dir->i_size & ~PAGE_CACHE_MASK;
-		if (limit & (UFS_SECTOR_SIZE - 1))
+		if (limit & chunk_mask)
 			goto Ebadsize;
 		if (!limit)
 			goto out;
@@ -126,7 +127,7 @@
 			goto Ealign;
 		if (rec_len < UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, p)))
 			goto Enamelen;
-		if (((offs + rec_len - 1) ^ offs) & ~(UFS_SECTOR_SIZE-1))
+		if (((offs + rec_len - 1) ^ offs) & ~chunk_mask)
 			goto Espan;
 		if (fs32_to_cpu(sb, p->d_ino) > (UFS_SB(sb)->s_uspi->s_ipg *
 						  UFS_SB(sb)->s_uspi->s_ncg))
@@ -310,6 +311,7 @@
 	int namelen = dentry->d_name.len;
 	struct super_block *sb = dir->i_sb;
 	unsigned reclen = UFS_DIR_REC_LEN(namelen);
+	const unsigned int chunk_size = UFS_SB(sb)->s_uspi->s_dirblksize;
 	unsigned short rec_len, name_len;
 	struct page *page = NULL;
 	struct ufs_dir_entry *de;
@@ -342,8 +344,8 @@
 			if ((char *)de == dir_end) {
 				/* We hit i_size */
 				name_len = 0;
-				rec_len = UFS_SECTOR_SIZE;
-				de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE);
+				rec_len = chunk_size;
+				de->d_reclen = cpu_to_fs16(sb, chunk_size);
 				de->d_ino = 0;
 				goto got_it;
 			}
@@ -431,7 +433,7 @@
 	unsigned int offset = pos & ~PAGE_CACHE_MASK;
 	unsigned long n = pos >> PAGE_CACHE_SHIFT;
 	unsigned long npages = ufs_dir_pages(inode);
-	unsigned chunk_mask = ~(UFS_SECTOR_SIZE - 1);
+	unsigned chunk_mask = ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1);
 	int need_revalidate = filp->f_version != inode->i_version;
 	unsigned flags = UFS_SB(sb)->s_flags;
 
@@ -511,7 +513,7 @@
 	struct super_block *sb = inode->i_sb;
 	struct address_space *mapping = page->mapping;
 	char *kaddr = page_address(page);
-	unsigned from = ((char*)dir - kaddr) & ~(UFS_SECTOR_SIZE - 1);
+	unsigned from = ((char*)dir - kaddr) & ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1);
 	unsigned to = ((char*)dir - kaddr) + fs16_to_cpu(sb, dir->d_reclen);
 	struct ufs_dir_entry *pde = NULL;
 	struct ufs_dir_entry *de = (struct ufs_dir_entry *) (kaddr + from);
@@ -556,6 +558,7 @@
 	struct super_block * sb = dir->i_sb;
 	struct address_space *mapping = inode->i_mapping;
 	struct page *page = grab_cache_page(mapping, 0);
+	const unsigned int chunk_size = UFS_SB(sb)->s_uspi->s_dirblksize;
 	struct ufs_dir_entry * de;
 	char *base;
 	int err;
@@ -563,7 +566,7 @@
 	if (!page)
 		return -ENOMEM;
 	kmap(page);
-	err = mapping->a_ops->prepare_write(NULL, page, 0, UFS_SECTOR_SIZE);
+	err = mapping->a_ops->prepare_write(NULL, page, 0, chunk_size);
 	if (err) {
 		unlock_page(page);
 		goto fail;
@@ -584,11 +587,11 @@
 		((char *)de + fs16_to_cpu(sb, de->d_reclen));
 	de->d_ino = cpu_to_fs32(sb, dir->i_ino);
 	ufs_set_de_type(sb, de, dir->i_mode);
-	de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE - UFS_DIR_REC_LEN(1));
+	de->d_reclen = cpu_to_fs16(sb, chunk_size - UFS_DIR_REC_LEN(1));
 	ufs_set_de_namlen(sb, de, 2);
 	strcpy (de->d_name, "..");
 
-	err = ufs_commit_chunk(page, 0, UFS_SECTOR_SIZE);
+	err = ufs_commit_chunk(page, 0, chunk_size);
 fail:
 	kunmap(page);
 	page_cache_release(page);
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 8a8e938..209be95 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -649,7 +649,7 @@
 		kmalloc (sizeof(struct ufs_sb_private_info), GFP_KERNEL);
 	if (!uspi)
 		goto failed;
-
+	uspi->s_dirblksize = UFS_SECTOR_SIZE;
 	super_block_offset=UFS_SBLOCK;
 
 	/* Keep 2Gig file limit. Some UFS variants need to override 
@@ -718,6 +718,7 @@
 		break;
 	
 	case UFS_MOUNT_UFSTYPE_NEXTSTEP:
+		/*TODO: check may be we need set special dir block size?*/
 		UFSD("ufstype=nextstep\n");
 		uspi->s_fsize = block_size = 1024;
 		uspi->s_fmask = ~(1024 - 1);
@@ -733,6 +734,7 @@
 		break;
 	
 	case UFS_MOUNT_UFSTYPE_NEXTSTEP_CD:
+		/*TODO: check may be we need set special dir block size?*/
 		UFSD("ufstype=nextstep-cd\n");
 		uspi->s_fsize = block_size = 2048;
 		uspi->s_fmask = ~(2048 - 1);
@@ -754,6 +756,7 @@
 		uspi->s_fshift = 10;
 		uspi->s_sbsize = super_block_size = 2048;
 		uspi->s_sbbase = 0;
+		uspi->s_dirblksize = 1024;
 		flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD;
 		if (!(sb->s_flags & MS_RDONLY)) {
 			if (!silent)
diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h
index ebc1f69..422f29c 100644
--- a/include/acpi/acconfig.h
+++ b/include/acpi/acconfig.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -63,7 +63,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20060707
+#define ACPI_CA_VERSION                 0x20070126
 
 /*
  * OS name, used for the _OS object.  The _OS object is essentially obsolete,
@@ -115,6 +115,10 @@
 
 #define ACPI_NUM_OWNERID_MASKS          8
 
+/* Size of the root table array is increased by this increment */
+
+#define ACPI_ROOT_TABLE_SIZE_INCREMENT  4
+
 /******************************************************************************
  *
  * ACPI Specification constants (Do not change unless the specification changes)
@@ -152,6 +156,11 @@
 #define ACPI_PATH_SEGMENT_LENGTH        5	/* 4 chars for name + 1 char for separator */
 #define ACPI_PATH_SEPARATOR             '.'
 
+/* Sizes for ACPI table headers */
+
+#define ACPI_OEM_ID_SIZE                6
+#define ACPI_OEM_TABLE_ID_SIZE          8
+
 /* Constants used in searching for the RSDP in low memory */
 
 #define ACPI_EBDA_PTR_LOCATION          0x0000040E	/* Physical Address */
diff --git a/include/acpi/acdebug.h b/include/acpi/acdebug.h
index d816709..d626bb1 100644
--- a/include/acpi/acdebug.h
+++ b/include/acpi/acdebug.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -159,6 +159,10 @@
 acpi_db_create_execution_threads(char *num_threads_arg,
 				 char *num_loops_arg, char *method_name_arg);
 
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+u32 acpi_db_get_cache_info(struct acpi_memory_list *cache);
+#endif
+
 /*
  * dbfileio - Debugger file I/O commands
  */
@@ -214,4 +218,6 @@
 
 struct acpi_namespace_node *acpi_db_local_ns_lookup(char *name);
 
+void acpi_db_uint32_to_hex_string(u32 value, char *buffer);
+
 #endif				/* __ACDEBUG_H__ */
diff --git a/include/acpi/acdisasm.h b/include/acpi/acdisasm.h
index 9a7d692..389d772 100644
--- a/include/acpi/acdisasm.h
+++ b/include/acpi/acdisasm.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -97,9 +97,11 @@
 #define ACPI_DMT_CHKSUM                 20
 #define ACPI_DMT_SPACEID                21
 #define ACPI_DMT_GAS                    22
-#define ACPI_DMT_MADT                   23
-#define ACPI_DMT_SRAT                   24
-#define ACPI_DMT_EXIT                   25
+#define ACPI_DMT_DMAR                   23
+#define ACPI_DMT_MADT                   24
+#define ACPI_DMT_SRAT                   25
+#define ACPI_DMT_EXIT                   26
+#define ACPI_DMT_SIG                    27
 
 typedef
 void (*ACPI_TABLE_HANDLER) (struct acpi_table_header * table);
@@ -108,6 +110,7 @@
 	char *signature;
 	struct acpi_dmtable_info *table_info;
 	ACPI_TABLE_HANDLER table_handler;
+	char *name;
 };
 
 struct acpi_op_walk_info {
@@ -139,7 +142,9 @@
 
 extern struct acpi_dmtable_info acpi_dm_table_info_asf0[];
 extern struct acpi_dmtable_info acpi_dm_table_info_asf1[];
+extern struct acpi_dmtable_info acpi_dm_table_info_asf1a[];
 extern struct acpi_dmtable_info acpi_dm_table_info_asf2[];
+extern struct acpi_dmtable_info acpi_dm_table_info_asf2a[];
 extern struct acpi_dmtable_info acpi_dm_table_info_asf3[];
 extern struct acpi_dmtable_info acpi_dm_table_info_asf4[];
 extern struct acpi_dmtable_info acpi_dm_table_info_asf_hdr[];
@@ -147,6 +152,11 @@
 extern struct acpi_dmtable_info acpi_dm_table_info_cpep[];
 extern struct acpi_dmtable_info acpi_dm_table_info_cpep0[];
 extern struct acpi_dmtable_info acpi_dm_table_info_dbgp[];
+extern struct acpi_dmtable_info acpi_dm_table_info_dmar[];
+extern struct acpi_dmtable_info acpi_dm_table_info_dmar_hdr[];
+extern struct acpi_dmtable_info acpi_dm_table_info_dmar_scope[];
+extern struct acpi_dmtable_info acpi_dm_table_info_dmar0[];
+extern struct acpi_dmtable_info acpi_dm_table_info_dmar1[];
 extern struct acpi_dmtable_info acpi_dm_table_info_ecdt[];
 extern struct acpi_dmtable_info acpi_dm_table_info_facs[];
 extern struct acpi_dmtable_info acpi_dm_table_info_fadt1[];
@@ -201,6 +211,8 @@
 
 void acpi_dm_dump_cpep(struct acpi_table_header *table);
 
+void acpi_dm_dump_dmar(struct acpi_table_header *table);
+
 void acpi_dm_dump_fadt(struct acpi_table_header *table);
 
 void acpi_dm_dump_srat(struct acpi_table_header *table);
@@ -314,7 +326,7 @@
 			  union acpi_parse_object *op,
 			  u8 * byte_data, u32 byte_count);
 
-u8 acpi_dm_is_resource_template(union acpi_parse_object *op);
+acpi_status acpi_dm_is_resource_template(union acpi_parse_object *op);
 
 void acpi_dm_indent(u32 level);
 
diff --git a/include/acpi/acdispat.h b/include/acpi/acdispat.h
index a22fe9c..cb8d286 100644
--- a/include/acpi/acdispat.h
+++ b/include/acpi/acdispat.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -210,7 +210,7 @@
  * dsinit
  */
 acpi_status
-acpi_ds_initialize_objects(struct acpi_table_desc *table_desc,
+acpi_ds_initialize_objects(acpi_native_uint table_index,
 			   struct acpi_namespace_node *start_node);
 
 /*
diff --git a/include/acpi/acevents.h b/include/acpi/acevents.h
index 23414282..d23cdf3 100644
--- a/include/acpi/acevents.h
+++ b/include/acpi/acevents.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h
index 797ca1e..b73f18a 100644
--- a/include/acpi/acexcep.h
+++ b/include/acpi/acexcep.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -178,8 +178,10 @@
 #define AE_CTRL_BREAK                   (acpi_status) (0x0009 | AE_CODE_CONTROL)
 #define AE_CTRL_CONTINUE                (acpi_status) (0x000A | AE_CODE_CONTROL)
 #define AE_CTRL_SKIP                    (acpi_status) (0x000B | AE_CODE_CONTROL)
+#define AE_CTRL_PARSE_CONTINUE          (acpi_status) (0x000C | AE_CODE_CONTROL)
+#define AE_CTRL_PARSE_PENDING           (acpi_status) (0x000D | AE_CODE_CONTROL)
 
-#define AE_CODE_CTRL_MAX                0x000B
+#define AE_CODE_CTRL_MAX                0x000D
 
 #ifdef DEFINE_ACPI_GLOBALS
 
@@ -291,7 +293,9 @@
 	"AE_CTRL_TRANSFER",
 	"AE_CTRL_BREAK",
 	"AE_CTRL_CONTINUE",
-	"AE_CTRL_SKIP"
+	"AE_CTRL_SKIP",
+	"AE_CTRL_PARSE_CONTINUE",
+	"AE_CTRL_PARSE_PENDING"
 };
 
 #endif				/* ACPI GLOBALS */
diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h
index 06972e6..24c3f05 100644
--- a/include/acpi/acglobal.h
+++ b/include/acpi/acglobal.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -58,37 +58,6 @@
 #define ACPI_INIT_GLOBAL(a,b) a
 #endif
 
-/*
- * Keep local copies of these FADT-based registers.  NOTE: These globals
- * are first in this file for alignment reasons on 64-bit systems.
- */
-ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable;
-ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable;
-
-/*****************************************************************************
- *
- * Debug support
- *
- ****************************************************************************/
-
-/* Runtime configuration of debug print levels */
-
-extern u32 acpi_dbg_level;
-extern u32 acpi_dbg_layer;
-
-/* Procedure nesting level for debug output */
-
-extern u32 acpi_gbl_nesting_level;
-
-/* Support for dynamic control method tracing mechanism */
-
-ACPI_EXTERN u32 acpi_gbl_original_dbg_level;
-ACPI_EXTERN u32 acpi_gbl_original_dbg_layer;
-ACPI_EXTERN acpi_name acpi_gbl_trace_method_name;
-ACPI_EXTERN u32 acpi_gbl_trace_dbg_level;
-ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer;
-ACPI_EXTERN u32 acpi_gbl_trace_flags;
-
 /*****************************************************************************
  *
  * Runtime configuration (static defaults that can be overriden at runtime)
@@ -135,52 +104,62 @@
 
 /*****************************************************************************
  *
+ * Debug support
+ *
+ ****************************************************************************/
+
+/* Runtime configuration of debug print levels */
+
+extern u32 acpi_dbg_level;
+extern u32 acpi_dbg_layer;
+
+/* Procedure nesting level for debug output */
+
+extern u32 acpi_gbl_nesting_level;
+
+/* Event counters */
+
+ACPI_EXTERN u32 acpi_gpe_count;
+
+/* Support for dynamic control method tracing mechanism */
+
+ACPI_EXTERN u32 acpi_gbl_original_dbg_level;
+ACPI_EXTERN u32 acpi_gbl_original_dbg_layer;
+ACPI_EXTERN acpi_name acpi_gbl_trace_method_name;
+ACPI_EXTERN u32 acpi_gbl_trace_dbg_level;
+ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer;
+ACPI_EXTERN u32 acpi_gbl_trace_flags;
+
+/*****************************************************************************
+ *
  * ACPI Table globals
  *
  ****************************************************************************/
 
 /*
- * Table pointers.
- * Although these pointers are somewhat redundant with the global acpi_table,
- * they are convenient because they are typed pointers.
+ * acpi_gbl_root_table_list is the master list of ACPI tables found in the
+ * RSDT/XSDT.
  *
- * These tables are single-table only; meaning that there can be at most one
- * of each in the system.  Each global points to the actual table.
+ * acpi_gbl_FADT is a local copy of the FADT, converted to a common format.
  */
-ACPI_EXTERN u32 acpi_gbl_table_flags;
-ACPI_EXTERN u32 acpi_gbl_rsdt_table_count;
-ACPI_EXTERN struct rsdp_descriptor *acpi_gbl_RSDP;
-ACPI_EXTERN struct xsdt_descriptor *acpi_gbl_XSDT;
-ACPI_EXTERN struct fadt_descriptor *acpi_gbl_FADT;
-ACPI_EXTERN struct acpi_table_header *acpi_gbl_DSDT;
-ACPI_EXTERN struct facs_descriptor *acpi_gbl_FACS;
-ACPI_EXTERN struct acpi_common_facs acpi_gbl_common_fACS;
-/*
- * Since there may be multiple SSDTs and PSDTs, a single pointer is not
- * sufficient; Therefore, there isn't one!
- */
+ACPI_EXTERN struct acpi_internal_rsdt acpi_gbl_root_table_list;
+ACPI_EXTERN struct acpi_table_fadt acpi_gbl_FADT;
+extern acpi_native_uint acpi_gbl_permanent_mmap;
 
-/* The root table can be either an RSDT or an XSDT */
+/* These addresses are calculated from FADT address values */
 
-ACPI_EXTERN u8 acpi_gbl_root_table_type;
-#define     ACPI_TABLE_TYPE_RSDT        'R'
-#define     ACPI_TABLE_TYPE_XSDT        'X'
+ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable;
+ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable;
 
 /*
- * Handle both ACPI 1.0 and ACPI 2.0 Integer widths:
- * If we are executing a method that exists in a 32-bit ACPI table,
- * use only the lower 32 bits of the (internal) 64-bit Integer.
+ * Handle both ACPI 1.0 and ACPI 2.0 Integer widths. The integer width is
+ * determined by the revision of the DSDT: If the DSDT revision is less than
+ * 2, use only the lower 32 bits of the internal 64-bit Integer.
  */
 ACPI_EXTERN u8 acpi_gbl_integer_bit_width;
 ACPI_EXTERN u8 acpi_gbl_integer_byte_width;
 ACPI_EXTERN u8 acpi_gbl_integer_nybble_width;
 
-/*
- * ACPI Table info arrays
- */
-extern struct acpi_table_list acpi_gbl_table_lists[ACPI_TABLE_ID_MAX + 1];
-extern struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1];
-
 /*****************************************************************************
  *
  * Mutual exlusion within ACPICA subsystem
@@ -188,7 +167,7 @@
  ****************************************************************************/
 
 /*
- * Predefined mutex objects.  This array contains the
+ * Predefined mutex objects. This array contains the
  * actual OS mutex handles, indexed by the local ACPI_MUTEX_HANDLEs.
  * (The table maps local handles to the real OS handles)
  */
@@ -197,6 +176,7 @@
 /*
  * Global lock semaphore works in conjunction with the actual HW global lock
  */
+ACPI_EXTERN acpi_mutex acpi_gbl_global_lock_mutex;
 ACPI_EXTERN acpi_semaphore acpi_gbl_global_lock_semaphore;
 
 /*
@@ -220,6 +200,7 @@
 
 ACPI_EXTERN struct acpi_memory_list *acpi_gbl_global_list;
 ACPI_EXTERN struct acpi_memory_list *acpi_gbl_ns_node_list;
+ACPI_EXTERN u8 acpi_gbl_display_final_mem_stats;
 #endif
 
 /* Object caches */
@@ -240,7 +221,6 @@
 
 /* Misc */
 
-ACPI_EXTERN u32 acpi_gbl_global_lock_thread_count;
 ACPI_EXTERN u32 acpi_gbl_original_mode;
 ACPI_EXTERN u32 acpi_gbl_rsdp_original_location;
 ACPI_EXTERN u32 acpi_gbl_ns_lookup_count;
@@ -260,12 +240,19 @@
 
 extern u8 acpi_gbl_shutdown;
 extern u32 acpi_gbl_startup_flags;
-extern const u8 acpi_gbl_decode_to8bit[8];
 extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT];
 extern const char *acpi_gbl_highest_dstate_names[4];
 extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES];
 extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS];
 
+/* Exception codes */
+
+extern char const *acpi_gbl_exception_names_env[];
+extern char const *acpi_gbl_exception_names_pgm[];
+extern char const *acpi_gbl_exception_names_tbl[];
+extern char const *acpi_gbl_exception_names_aml[];
+extern char const *acpi_gbl_exception_names_ctrl[];
+
 /*****************************************************************************
  *
  * Namespace globals
diff --git a/include/acpi/achware.h b/include/acpi/achware.h
index 29b60a8..9df275c 100644
--- a/include/acpi/achware.h
+++ b/include/acpi/achware.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -61,8 +61,6 @@
 /*
  * hwacpi - high level functions
  */
-acpi_status acpi_hw_initialize(void);
-
 acpi_status acpi_hw_set_mode(u32 mode);
 
 u32 acpi_hw_get_mode(void);
@@ -84,7 +82,7 @@
 acpi_status
 acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address *reg);
 
-acpi_status acpi_hw_clear_acpi_status(u32 flags);
+acpi_status acpi_hw_clear_acpi_status(void);
 
 /*
  * hwgpe - GPE support
diff --git a/include/acpi/acinterp.h b/include/acpi/acinterp.h
index 91586d0..ce7c9d6 100644
--- a/include/acpi/acinterp.h
+++ b/include/acpi/acinterp.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -277,12 +277,6 @@
 
 acpi_status acpi_ex_system_do_stall(u32 time);
 
-acpi_status
-acpi_ex_system_acquire_mutex(union acpi_operand_object *time,
-			     union acpi_operand_object *obj_desc);
-
-acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc);
-
 acpi_status acpi_ex_system_signal_event(union acpi_operand_object *obj_desc);
 
 acpi_status
@@ -451,10 +445,14 @@
 /*
  * exutils - interpreter/scanner utilities
  */
-acpi_status acpi_ex_enter_interpreter(void);
+void acpi_ex_enter_interpreter(void);
 
 void acpi_ex_exit_interpreter(void);
 
+void acpi_ex_reacquire_interpreter(void);
+
+void acpi_ex_relinquish_interpreter(void);
+
 void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc);
 
 u8 acpi_ex_acquire_global_lock(u32 rule);
diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h
index 063c4b5..6f83ddb 100644
--- a/include/acpi/aclocal.h
+++ b/include/acpi/aclocal.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -80,8 +80,8 @@
  * table below also!
  */
 #define ACPI_MTX_INTERPRETER            0	/* AML Interpreter, main lock */
-#define ACPI_MTX_TABLES                 1	/* Data for ACPI tables */
-#define ACPI_MTX_NAMESPACE              2	/* ACPI Namespace */
+#define ACPI_MTX_NAMESPACE              1	/* ACPI Namespace */
+#define ACPI_MTX_TABLES                 2	/* Data for ACPI tables */
 #define ACPI_MTX_EVENTS                 3	/* Data for ACPI events */
 #define ACPI_MTX_CACHES                 4	/* Internal caches, general purposes */
 #define ACPI_MTX_MEMORY                 5	/* Debug memory tracking lists */
@@ -162,7 +162,7 @@
 typedef enum {
 	ACPI_IMODE_LOAD_PASS1 = 0x01,
 	ACPI_IMODE_LOAD_PASS2 = 0x02,
-	ACPI_IMODE_EXECUTE = 0x0E
+	ACPI_IMODE_EXECUTE = 0x03
 } acpi_interpreter_mode;
 
 union acpi_name_union {
@@ -204,7 +204,7 @@
 /* Namespace Node flags */
 
 #define ANOBJ_END_OF_PEER_LIST          0x01	/* End-of-list, Peer field points to parent */
-#define ANOBJ_RESERVED                  0x02	/* Available for future use */
+#define ANOBJ_TEMPORARY                 0x02	/* Node is create by a method and is temporary */
 #define ANOBJ_METHOD_ARG                0x04	/* Node is a method argument */
 #define ANOBJ_METHOD_LOCAL              0x08	/* Node is a method local */
 #define ANOBJ_SUBTREE_HAS_INI           0x10	/* Used to optimize device initialization */
@@ -219,25 +219,42 @@
  * ACPI Table Descriptor.  One per ACPI table
  */
 struct acpi_table_desc {
-	struct acpi_table_desc *prev;
-	struct acpi_table_desc *next;
-	struct acpi_table_desc *installed_desc;
+	acpi_physical_address address;
 	struct acpi_table_header *pointer;
-	u8 *aml_start;
-	u64 physical_address;
-	acpi_size length;
-	u32 aml_length;
+	u32 length;		/* Length fixed at 32 bits */
+	union acpi_name_union signature;
 	acpi_owner_id owner_id;
-	u8 type;
-	u8 allocation;
-	u8 loaded_into_namespace;
+	u8 flags;
 };
 
-struct acpi_table_list {
-	struct acpi_table_desc *next;
+/* Flags for above */
+
+#define ACPI_TABLE_ORIGIN_UNKNOWN       (0)
+#define ACPI_TABLE_ORIGIN_MAPPED        (1)
+#define ACPI_TABLE_ORIGIN_ALLOCATED     (2)
+#define ACPI_TABLE_ORIGIN_MASK          (3)
+#define ACPI_TABLE_IS_LOADED            (4)
+
+/* One internal RSDT for table management */
+
+struct acpi_internal_rsdt {
+	struct acpi_table_desc *tables;
 	u32 count;
+	u32 size;
+	u8 flags;
 };
 
+/* Flags for above */
+
+#define ACPI_ROOT_ORIGIN_UNKNOWN        (0)	/* ~ORIGIN_ALLOCATED */
+#define ACPI_ROOT_ORIGIN_ALLOCATED      (1)
+#define ACPI_ROOT_ALLOW_RESIZE          (2)
+
+/* Predefined (fixed) table indexes */
+
+#define ACPI_TABLE_INDEX_DSDT           (0)
+#define ACPI_TABLE_INDEX_FACS           (1)
+
 struct acpi_find_context {
 	char *search_for;
 	acpi_handle *list;
@@ -350,7 +367,7 @@
 	union acpi_gpe_dispatch_info dispatch;	/* Either Method or Handler */
 	struct acpi_gpe_register_info *register_info;	/* Backpointer to register info */
 	u8 flags;		/* Misc info about this GPE */
-	u8 register_bit;	/* This GPE bit within the register */
+	u8 gpe_number;		/* This GPE */
 };
 
 /* Information about a GPE register pair, one per each status/enable pair in an array */
@@ -855,12 +872,30 @@
  ****************************************************************************/
 
 struct acpi_db_method_info {
-	acpi_handle thread_gate;
+	acpi_handle main_thread_gate;
+	acpi_handle thread_complete_gate;
+	u32 *threads;
+	u32 num_threads;
+	u32 num_created;
+	u32 num_completed;
+
 	char *name;
-	char **args;
 	u32 flags;
 	u32 num_loops;
 	char pathname[128];
+	char **args;
+
+	/*
+	 * Arguments to be passed to method for the command
+	 * Threads -
+	 *   the Number of threads, ID of current thread and
+	 *   Index of current thread inside all them created.
+	 */
+	char init_args;
+	char *arguments[4];
+	char num_threads_str[11];
+	char id_of_thread_str[11];
+	char index_of_thread_str[11];
 };
 
 struct acpi_integrity_info {
@@ -919,6 +954,8 @@
 
 	u32 total_allocated;
 	u32 total_freed;
+	u32 max_occupied;
+	u32 total_size;
 	u32 current_total_size;
 	u32 requests;
 	u32 hits;
diff --git a/include/acpi/acmacros.h b/include/acpi/acmacros.h
index 192fa09..8948a64 100644
--- a/include/acpi/acmacros.h
+++ b/include/acpi/acmacros.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -55,25 +55,12 @@
 #define ACPI_SET_BIT(target,bit)        ((target) |= (bit))
 #define ACPI_CLEAR_BIT(target,bit)      ((target) &= ~(bit))
 #define ACPI_MIN(a,b)                   (((a)<(b))?(a):(b))
+#define ACPI_MAX(a,b)                   (((a)>(b))?(a):(b))
 
 /* Size calculation */
 
 #define ACPI_ARRAY_LENGTH(x)            (sizeof(x) / sizeof((x)[0]))
 
-#if ACPI_MACHINE_WIDTH == 16
-
-/*
- * For 16-bit addresses, we have to assume that the upper 32 bits
- * (out of 64) are zero.
- */
-#define ACPI_LODWORD(l)                 ((u32)(l))
-#define ACPI_HIDWORD(l)                 ((u32)(0))
-
-#define ACPI_GET_ADDRESS(a)             ((a).lo)
-#define ACPI_STORE_ADDRESS(a,b)         {(a).hi=0;(a).lo=(u32)(b);}
-#define ACPI_VALID_ADDRESS(a)           ((a).hi | (a).lo)
-
-#else
 #ifdef ACPI_NO_INTEGER64_SUPPORT
 /*
  * acpi_integer is 32-bits, no 64-bit support on this platform
@@ -81,10 +68,6 @@
 #define ACPI_LODWORD(l)                 ((u32)(l))
 #define ACPI_HIDWORD(l)                 ((u32)(0))
 
-#define ACPI_GET_ADDRESS(a)             (a)
-#define ACPI_STORE_ADDRESS(a,b)         ((a)=(b))
-#define ACPI_VALID_ADDRESS(a)           (a)
-
 #else
 
 /*
@@ -92,11 +75,6 @@
  */
 #define ACPI_LODWORD(l)                 ((u32)(u64)(l))
 #define ACPI_HIDWORD(l)                 ((u32)(((*(struct uint64_struct *)(void *)(&l))).hi))
-
-#define ACPI_GET_ADDRESS(a)             (a)
-#define ACPI_STORE_ADDRESS(a,b)         ((a)=(acpi_physical_address)(b))
-#define ACPI_VALID_ADDRESS(a)           (a)
-#endif
 #endif
 
 /*
@@ -134,15 +112,8 @@
 #define ACPI_TO_POINTER(i)              ACPI_ADD_PTR (void,(void *) NULL,(acpi_native_uint) i)
 #define ACPI_TO_INTEGER(p)              ACPI_PTR_DIFF (p,(void *) NULL)
 #define ACPI_OFFSET(d,f)                (acpi_size) ACPI_PTR_DIFF (&(((d *)0)->f),(void *) NULL)
-
-#if ACPI_MACHINE_WIDTH == 16
-#define ACPI_STORE_POINTER(d,s)         ACPI_MOVE_32_TO_32(d,s)
-#define ACPI_PHYSADDR_TO_PTR(i)         (void *)(i)
-#define ACPI_PTR_TO_PHYSADDR(i)         (u32) ACPI_CAST_PTR (u8,(i))
-#else
 #define ACPI_PHYSADDR_TO_PTR(i)         ACPI_TO_POINTER(i)
 #define ACPI_PTR_TO_PHYSADDR(i)         ACPI_TO_INTEGER(i)
-#endif
 
 #ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED
 #define ACPI_COMPARE_NAME(a,b)          (*ACPI_CAST_PTR (u32,(a)) == *ACPI_CAST_PTR (u32,(b)))
@@ -223,28 +194,6 @@
 
 /* The hardware supports unaligned transfers, just do the little-endian move */
 
-#if ACPI_MACHINE_WIDTH == 16
-
-/* No 64-bit integers */
-/* 16-bit source, 16/32/64 destination */
-
-#define ACPI_MOVE_16_TO_16(d,s)         *(u16 *)(void *)(d) = *(u16 *)(void *)(s)
-#define ACPI_MOVE_16_TO_32(d,s)         *(u32 *)(void *)(d) = *(u16 *)(void *)(s)
-#define ACPI_MOVE_16_TO_64(d,s)         ACPI_MOVE_16_TO_32(d,s)
-
-/* 32-bit source, 16/32/64 destination */
-
-#define ACPI_MOVE_32_TO_16(d,s)         ACPI_MOVE_16_TO_16(d,s)	/* Truncate to 16 */
-#define ACPI_MOVE_32_TO_32(d,s)         *(u32 *)(void *)(d) = *(u32 *)(void *)(s)
-#define ACPI_MOVE_32_TO_64(d,s)         ACPI_MOVE_32_TO_32(d,s)
-
-/* 64-bit source, 16/32/64 destination */
-
-#define ACPI_MOVE_64_TO_16(d,s)         ACPI_MOVE_16_TO_16(d,s)	/* Truncate to 16 */
-#define ACPI_MOVE_64_TO_32(d,s)         ACPI_MOVE_32_TO_32(d,s)	/* Truncate to 32 */
-#define ACPI_MOVE_64_TO_64(d,s)         ACPI_MOVE_32_TO_32(d,s)
-
-#else
 /* 16-bit source, 16/32/64 destination */
 
 #define ACPI_MOVE_16_TO_16(d,s)         *(u16 *)(void *)(d) = *(u16 *)(void *)(s)
@@ -262,7 +211,6 @@
 #define ACPI_MOVE_64_TO_16(d,s)         ACPI_MOVE_16_TO_16(d,s)	/* Truncate to 16 */
 #define ACPI_MOVE_64_TO_32(d,s)         ACPI_MOVE_32_TO_32(d,s)	/* Truncate to 32 */
 #define ACPI_MOVE_64_TO_64(d,s)         *(u64 *)(void *)(d) = *(u64 *)(void *)(s)
-#endif
 
 #else
 /*
@@ -307,10 +255,7 @@
 
 /* Macros based on machine integer width */
 
-#if ACPI_MACHINE_WIDTH == 16
-#define ACPI_MOVE_SIZE_TO_16(d,s)       ACPI_MOVE_16_TO_16(d,s)
-
-#elif ACPI_MACHINE_WIDTH == 32
+#if ACPI_MACHINE_WIDTH == 32
 #define ACPI_MOVE_SIZE_TO_16(d,s)       ACPI_MOVE_32_TO_16(d,s)
 
 #elif ACPI_MACHINE_WIDTH == 64
@@ -695,16 +640,6 @@
 #define ACPI_DEBUGGER_EXEC(a)
 #endif
 
-/*
- * For 16-bit code, we want to shrink some things even though
- * we are using ACPI_DEBUG_OUTPUT to get the debug output
- */
-#if ACPI_MACHINE_WIDTH == 16
-#undef ACPI_DEBUG_ONLY_MEMBERS
-#undef _VERBOSE_STRUCTURES
-#define ACPI_DEBUG_ONLY_MEMBERS(a)
-#endif
-
 #ifdef ACPI_DEBUG_OUTPUT
 /*
  * 1) Set name to blanks
diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h
index b67da36..34bfae8 100644
--- a/include/acpi/acnames.h
+++ b/include/acpi/acnames.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acnamesp.h b/include/acpi/acnamesp.h
index 83b52f9..535b7e1 100644
--- a/include/acpi/acnamesp.h
+++ b/include/acpi/acnamesp.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -65,9 +65,13 @@
 #define ACPI_NS_ERROR_IF_FOUND      0x08
 #define ACPI_NS_PREFIX_IS_SCOPE     0x10
 #define ACPI_NS_EXTERNAL            0x20
+#define ACPI_NS_TEMPORARY           0x40
 
-#define ACPI_NS_WALK_UNLOCK         TRUE
-#define ACPI_NS_WALK_NO_UNLOCK      FALSE
+/* Flags for acpi_ns_walk_namespace */
+
+#define ACPI_NS_WALK_NO_UNLOCK      0
+#define ACPI_NS_WALK_UNLOCK         0x01
+#define ACPI_NS_WALK_TEMP_NODES     0x02
 
 /*
  * nsinit - Namespace initialization
@@ -82,7 +86,7 @@
 acpi_status acpi_ns_load_namespace(void);
 
 acpi_status
-acpi_ns_load_table(struct acpi_table_desc *table_desc,
+acpi_ns_load_table(acpi_native_uint table_index,
 		   struct acpi_namespace_node *node);
 
 /*
@@ -92,7 +96,7 @@
 acpi_ns_walk_namespace(acpi_object_type type,
 		       acpi_handle start_object,
 		       u32 max_depth,
-		       u8 unlock_before_callback,
+		       u32 flags,
 		       acpi_walk_callback user_function,
 		       void *context, void **return_value);
 
@@ -106,11 +110,12 @@
  * nsparse - table parsing
  */
 acpi_status
-acpi_ns_parse_table(struct acpi_table_desc *table_desc,
-		    struct acpi_namespace_node *scope);
+acpi_ns_parse_table(acpi_native_uint table_index,
+		    struct acpi_namespace_node *start_node);
 
 acpi_status
-acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc);
+acpi_ns_one_complete_parse(acpi_native_uint pass_number,
+			   acpi_native_uint table_index);
 
 /*
  * nsaccess - Top-level namespace access
diff --git a/include/acpi/acobject.h b/include/acpi/acobject.h
index 8fdee31..04e9735 100644
--- a/include/acpi/acobject.h
+++ b/include/acpi/acobject.h
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -52,7 +52,15 @@
  * to the interpreter, and to keep track of the various handlers such as
  * address space handlers and notify handlers. The object is a constant
  * size in order to allow it to be cached and reused.
+ *
+ * Note: The object is optimized to be aligned and will not work if it is
+ * byte-packed.
  */
+#if ACPI_MACHINE_WIDTH == 64
+#pragma pack(8)
+#else
+#pragma pack(4)
+#endif
 
 /*******************************************************************************
  *
@@ -101,7 +109,8 @@
 ACPI_OBJECT_COMMON_HEADER};
 
 struct acpi_object_integer {
-	ACPI_OBJECT_COMMON_HEADER acpi_integer value;
+	ACPI_OBJECT_COMMON_HEADER u8 fill[3];	/* Prevent warning on some compilers */
+	acpi_integer value;
 };
 
 /*
@@ -203,7 +212,9 @@
 };
 
 struct acpi_object_processor {
-	ACPI_OBJECT_COMMON_HEADER u8 proc_id;
+	ACPI_OBJECT_COMMON_HEADER
+	    /* The next two fields take advantage of the 3-byte space before NOTIFY_INFO */
+	u8 proc_id;
 	u8 length;
 	 ACPI_COMMON_NOTIFY_INFO acpi_io_address address;
 };
@@ -406,4 +417,6 @@
 	union acpi_parse_object op;
 };
 
+#pragma pack()
+
 #endif				/* _ACOBJECT_H */
diff --git a/include/acpi/acopcode.h b/include/acpi/acopcode.h
index 7659a46..e6f76a2 100644
--- a/include/acpi/acopcode.h
+++ b/include/acpi/acopcode.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -257,7 +257,7 @@
 #define ARGI_LLESSEQUAL_OP              ARGI_INVALID_OPCODE
 #define ARGI_LNOT_OP                    ARGI_LIST1 (ARGI_INTEGER)
 #define ARGI_LNOTEQUAL_OP               ARGI_INVALID_OPCODE
-#define ARGI_LOAD_OP                    ARGI_LIST2 (ARGI_REGION_OR_FIELD,ARGI_TARGETREF)
+#define ARGI_LOAD_OP                    ARGI_LIST2 (ARGI_REGION_OR_BUFFER,ARGI_TARGETREF)
 #define ARGI_LOAD_TABLE_OP              ARGI_LIST6 (ARGI_STRING,     ARGI_STRING,        ARGI_STRING,       ARGI_STRING,    ARGI_STRING, ARGI_ANYTYPE)
 #define ARGI_LOCAL0                     ARG_NONE
 #define ARGI_LOCAL1                     ARG_NONE
diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h
index 8d5039d..7812267 100644
--- a/include/acpi/acoutput.h
+++ b/include/acpi/acoutput.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acparser.h b/include/acpi/acparser.h
index 9d49d3c..85c358e 100644
--- a/include/acpi/acparser.h
+++ b/include/acpi/acparser.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acpi.h b/include/acpi/acpi.h
index b9a39d1..2e5f00d 100644
--- a/include/acpi/acpi.h
+++ b/include/acpi/acpi.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index fdd1095..0d9f984 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -59,7 +59,6 @@
 
 #define ACPI_BUS_FILE_ROOT	"acpi"
 extern struct proc_dir_entry *acpi_root_dir;
-extern struct fadt_descriptor acpi_fadt;
 
 enum acpi_bus_removal_type {
 	ACPI_BUS_REMOVAL_NORMAL = 0,
@@ -92,13 +91,12 @@
 typedef int (*acpi_op_lock) (struct acpi_device * device, int type);
 typedef int (*acpi_op_start) (struct acpi_device * device);
 typedef int (*acpi_op_stop) (struct acpi_device * device, int type);
-typedef int (*acpi_op_suspend) (struct acpi_device * device, int state);
-typedef int (*acpi_op_resume) (struct acpi_device * device, int state);
+typedef int (*acpi_op_suspend) (struct acpi_device * device, pm_message_t state);
+typedef int (*acpi_op_resume) (struct acpi_device * device);
 typedef int (*acpi_op_scan) (struct acpi_device * device);
 typedef int (*acpi_op_bind) (struct acpi_device * device);
 typedef int (*acpi_op_unbind) (struct acpi_device * device);
-typedef int (*acpi_op_match) (struct acpi_device * device,
-			      struct acpi_driver * driver);
+typedef int (*acpi_op_shutdown) (struct acpi_device * device);
 
 struct acpi_bus_ops {
 	u32 acpi_op_add:1;
@@ -111,7 +109,7 @@
 	u32 acpi_op_scan:1;
 	u32 acpi_op_bind:1;
 	u32 acpi_op_unbind:1;
-	u32 acpi_op_match:1;
+	u32 acpi_op_shutdown:1;
 	u32 reserved:21;
 };
 
@@ -126,16 +124,16 @@
 	acpi_op_scan scan;
 	acpi_op_bind bind;
 	acpi_op_unbind unbind;
-	acpi_op_match match;
+	acpi_op_shutdown shutdown;
 };
 
 struct acpi_driver {
-	struct list_head node;
 	char name[80];
 	char class[80];
-	atomic_t references;
 	char *ids;		/* Supported Hardware IDs */
 	struct acpi_device_ops ops;
+	struct device_driver drv;
+	struct module *owner;
 };
 
 /*
@@ -185,7 +183,7 @@
 
 typedef char acpi_bus_id[5];
 typedef unsigned long acpi_bus_address;
-typedef char acpi_hardware_id[9];
+typedef char acpi_hardware_id[15];
 typedef char acpi_unique_id[9];
 typedef char acpi_device_name[40];
 typedef char acpi_device_class[20];
@@ -296,11 +294,14 @@
 	struct acpi_device_ops ops;
 	struct acpi_driver *driver;
 	void *driver_data;
-	struct kobject kobj;
 	struct device dev;
+	struct acpi_bus_ops bus_ops;	/* workaround for different code path for hotplug */
+	enum acpi_bus_removal_type removal_type; /* indicate for different removal type */
 };
 
 #define acpi_driver_data(d)	((d)->driver_data)
+#define to_acpi_device(d)	container_of(d, struct acpi_device, dev)
+#define to_acpi_driver(d)	container_of(d, struct acpi_driver, drv)
 
 /*
  * Events
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
index 6a5bdce..4dc8a50 100644
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -36,13 +36,14 @@
 
 /* _HID definitions */
 
-#define ACPI_POWER_HID			"ACPI_PWR"
-#define ACPI_PROCESSOR_HID		"ACPI_CPU"
-#define ACPI_SYSTEM_HID			"ACPI_SYS"
-#define ACPI_THERMAL_HID		"ACPI_THM"
-#define ACPI_BUTTON_HID_POWERF		"ACPI_FPB"
-#define ACPI_BUTTON_HID_SLEEPF		"ACPI_FSB"
-
+#define ACPI_POWER_HID			"power_resource"
+#define ACPI_PROCESSOR_HID		"ACPI0007"
+#define ACPI_SYSTEM_HID			"acpi_system"
+#define ACPI_THERMAL_HID		"thermal"
+#define ACPI_BUTTON_HID_POWERF		"button_power"
+#define ACPI_BUTTON_HID_SLEEPF		"button_sleep"
+#define ACPI_VIDEO_HID			"video"
+#define ACPI_BAY_HID			"bay"
 /* --------------------------------------------------------------------------
                                        PCI
    -------------------------------------------------------------------------- */
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index 0cd63bc..781394b 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -8,7 +8,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -85,7 +85,7 @@
 /*
  * ACPI Table interfaces
  */
-acpi_status acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *address);
+acpi_physical_address acpi_os_get_root_pointer(void);
 
 acpi_status
 acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
@@ -143,9 +143,7 @@
  */
 void *acpi_os_allocate(acpi_size size);
 
-acpi_status
-acpi_os_map_memory(acpi_physical_address physical_address,
-		   acpi_size size, void __iomem ** logical_address);
+void __iomem *acpi_os_map_memory(acpi_physical_address where, acpi_native_uint length);
 
 void acpi_os_unmap_memory(void __iomem * logical_address, acpi_size size);
 
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 8145876..e08f7df 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -51,6 +51,10 @@
 /*
  * Global interfaces
  */
+acpi_status
+acpi_initialize_tables(struct acpi_table_desc *initial_storage,
+		       u32 initial_table_count, u8 allow_resize);
+
 acpi_status acpi_initialize_subsystem(void);
 
 acpi_status acpi_enable_subsystem(u32 flags);
@@ -92,30 +96,28 @@
 /*
  * ACPI table manipulation interfaces
  */
-acpi_status
-acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address);
+acpi_status acpi_reallocate_root_table(void);
+
+acpi_status acpi_find_root_pointer(acpi_native_uint * rsdp_address);
 
 acpi_status acpi_load_tables(void);
 
 acpi_status acpi_load_table(struct acpi_table_header *table_ptr);
 
-acpi_status acpi_unload_table_id(acpi_table_type table_type, acpi_owner_id id);
-
-#ifdef ACPI_FUTURE_USAGE
-acpi_status acpi_unload_table(acpi_table_type table_type);
-acpi_status
-acpi_get_table_header(acpi_table_type table_type,
-		      u32 instance, struct acpi_table_header *out_table_header);
-#endif				/*  ACPI_FUTURE_USAGE  */
+acpi_status acpi_unload_table_id(acpi_owner_id id);
 
 acpi_status
-acpi_get_table(acpi_table_type table_type,
-	       u32 instance, struct acpi_buffer *ret_buffer);
+acpi_get_table_header(acpi_string signature,
+		      acpi_native_uint instance,
+		      struct acpi_table_header *out_table_header);
 
 acpi_status
-acpi_get_firmware_table(acpi_string signature,
-			u32 instance,
-			u32 flags, struct acpi_table_header **table_pointer);
+acpi_get_table(acpi_string signature,
+	       acpi_native_uint instance, struct acpi_table_header **out_table);
+
+acpi_status
+acpi_get_table_by_index(acpi_native_uint table_index,
+			struct acpi_table_header **out_table);
 
 /*
  * Namespace and name interfaces
@@ -310,9 +312,9 @@
 /*
  * Hardware (ACPI device) interfaces
  */
-acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags);
+acpi_status acpi_get_register(u32 register_id, u32 * return_value);
 
-acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags);
+acpi_status acpi_set_register(u32 register_id, u32 value);
 
 acpi_status
 acpi_set_firmware_waking_vector(acpi_physical_address physical_address);
diff --git a/include/acpi/acresrc.h b/include/acpi/acresrc.h
index 80a3b33..9486ab2 100644
--- a/include/acpi/acresrc.h
+++ b/include/acpi/acresrc.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acstruct.h b/include/acpi/acstruct.h
index 5e8095f..aeb4498 100644
--- a/include/acpi/acstruct.h
+++ b/include/acpi/acstruct.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -139,7 +139,8 @@
 	u16 buffer_init;
 	u16 package_init;
 	u16 object_count;
-	struct acpi_table_desc *table_desc;
+	acpi_owner_id owner_id;
+	acpi_native_uint table_index;
 };
 
 struct acpi_get_devices_info {
diff --git a/include/acpi/actables.h b/include/acpi/actables.h
index 4dbaf02..2b9f46f 100644
--- a/include/acpi/actables.h
+++ b/include/acpi/actables.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,105 +44,75 @@
 #ifndef __ACTABLES_H__
 #define __ACTABLES_H__
 
-/* Used in acpi_tb_map_acpi_table for size parameter if table header is to be used */
-
-#define SIZE_IN_HEADER          0
+acpi_status acpi_allocate_root_table(u32 initial_table_count);
 
 /*
- * tbconvrt - Table conversion routines
+ * tbfadt - FADT parse/convert/validate
  */
-acpi_status acpi_tb_convert_to_xsdt(struct acpi_table_desc *table_info);
+void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags);
 
-acpi_status acpi_tb_convert_table_fadt(void);
-
-acpi_status acpi_tb_build_common_facs(struct acpi_table_desc *table_info);
-
-u32
-acpi_tb_get_table_count(struct rsdp_descriptor *RSDP,
-			struct acpi_table_header *RSDT);
+void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length);
 
 /*
- * tbget - Table "get" routines
- */
-acpi_status
-acpi_tb_get_table(struct acpi_pointer *address,
-		  struct acpi_table_desc *table_info);
-
-acpi_status
-acpi_tb_get_table_header(struct acpi_pointer *address,
-			 struct acpi_table_header *return_header);
-
-acpi_status
-acpi_tb_get_table_body(struct acpi_pointer *address,
-		       struct acpi_table_header *header,
-		       struct acpi_table_desc *table_info);
-
-acpi_status
-acpi_tb_get_table_ptr(acpi_table_type table_type,
-		      u32 instance, struct acpi_table_header **table_ptr_loc);
-
-acpi_status acpi_tb_verify_rsdp(struct acpi_pointer *address);
-
-void acpi_tb_get_rsdt_address(struct acpi_pointer *out_address);
-
-acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr);
-
-/*
- * tbgetall - get multiple required tables
- */
-acpi_status acpi_tb_get_required_tables(void);
-
-/*
- * tbinstall - Table installation
- */
-acpi_status acpi_tb_install_table(struct acpi_table_desc *table_info);
-
-acpi_status
-acpi_tb_recognize_table(struct acpi_table_desc *table_info, u8 search_type);
-
-acpi_status
-acpi_tb_init_table_descriptor(acpi_table_type table_type,
-			      struct acpi_table_desc *table_info);
-
-/*
- * tbremove - Table removal and deletion
- */
-void acpi_tb_delete_all_tables(void);
-
-void acpi_tb_delete_tables_by_type(acpi_table_type type);
-
-void acpi_tb_delete_single_table(struct acpi_table_desc *table_desc);
-
-struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc
-						*table_desc);
-
-/*
- * tbxfroot - RSDP, RSDT utilities
+ * tbfind - find ACPI table
  */
 acpi_status
 acpi_tb_find_table(char *signature,
 		   char *oem_id,
-		   char *oem_table_id, struct acpi_table_header **table_ptr);
-
-acpi_status acpi_tb_get_table_rsdt(void);
-
-acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp);
+		   char *oem_table_id, acpi_native_uint * table_index);
 
 /*
- * tbutils - common table utilities
+ * tbinstal - Table removal and deletion
  */
-acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc);
+acpi_status acpi_tb_resize_root_table_list(void);
+
+acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc);
 
 acpi_status
-acpi_tb_verify_table_checksum(struct acpi_table_header *table_header);
-
-u8 acpi_tb_sum_table(void *buffer, u32 length);
-
-u8 acpi_tb_generate_checksum(struct acpi_table_header *table);
-
-void acpi_tb_set_checksum(struct acpi_table_header *table);
+acpi_tb_add_table(struct acpi_table_desc *table_desc,
+		  acpi_native_uint * table_index);
 
 acpi_status
-acpi_tb_validate_table_header(struct acpi_table_header *table_header);
+acpi_tb_store_table(acpi_physical_address address,
+		    struct acpi_table_header *table,
+		    u32 length, u8 flags, acpi_native_uint * table_index);
+
+void acpi_tb_delete_table(struct acpi_table_desc *table_desc);
+
+void acpi_tb_terminate(void);
+
+void acpi_tb_delete_namespace_by_owner(acpi_native_uint table_index);
+
+acpi_status acpi_tb_allocate_owner_id(acpi_native_uint table_index);
+
+acpi_status acpi_tb_release_owner_id(acpi_native_uint table_index);
+
+acpi_status
+acpi_tb_get_owner_id(acpi_native_uint table_index, acpi_owner_id * owner_id);
+
+u8 acpi_tb_is_table_loaded(acpi_native_uint table_index);
+
+void acpi_tb_set_table_loaded_flag(acpi_native_uint table_index, u8 is_loaded);
+
+/*
+ * tbutils - table manager utilities
+ */
+u8 acpi_tb_tables_loaded(void);
+
+void
+acpi_tb_print_table_header(acpi_physical_address address,
+			   struct acpi_table_header *header);
+
+u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length);
+
+acpi_status
+acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length);
+
+void
+acpi_tb_install_table(acpi_physical_address address,
+		      u8 flags, char *signature, acpi_native_uint table_index);
+
+acpi_status
+acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags);
 
 #endif				/* __ACTABLES_H__ */
diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h
index b125cee..09469e7 100644
--- a/include/acpi/actbl.h
+++ b/include/acpi/actbl.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,15 +48,15 @@
  * Values for description table header signatures. Useful because they make
  * it more difficult to inadvertently type in the wrong signature.
  */
-#define DSDT_SIG                "DSDT"	/* Differentiated System Description Table */
-#define FADT_SIG                "FACP"	/* Fixed ACPI Description Table */
-#define FACS_SIG                "FACS"	/* Firmware ACPI Control Structure */
-#define PSDT_SIG                "PSDT"	/* Persistent System Description Table */
-#define RSDP_SIG                "RSD PTR "	/* Root System Description Pointer */
-#define RSDT_SIG                "RSDT"	/* Root System Description Table */
-#define XSDT_SIG                "XSDT"	/* Extended  System Description Table */
-#define SSDT_SIG                "SSDT"	/* Secondary System Description Table */
-#define RSDP_NAME               "RSDP"
+#define ACPI_SIG_DSDT           "DSDT"	/* Differentiated System Description Table */
+#define ACPI_SIG_FADT           "FACP"	/* Fixed ACPI Description Table */
+#define ACPI_SIG_FACS           "FACS"	/* Firmware ACPI Control Structure */
+#define ACPI_SIG_PSDT           "PSDT"	/* Persistent System Description Table */
+#define ACPI_SIG_RSDP           "RSD PTR "	/* Root System Description Pointer */
+#define ACPI_SIG_RSDT           "RSDT"	/* Root System Description Table */
+#define ACPI_SIG_XSDT           "XSDT"	/* Extended  System Description Table */
+#define ACPI_SIG_SSDT           "SSDT"	/* Secondary System Description Table */
+#define ACPI_RSDP_NAME          "RSDP"	/* Short name for RSDP, not signature */
 
 /*
  * All tables and structures must be byte-packed to match the ACPI
@@ -83,27 +83,29 @@
  *
  ******************************************************************************/
 
-#define ACPI_TABLE_HEADER_DEF \
-	char                            signature[4];           /* ASCII table signature */\
-	u32                             length;                 /* Length of table in bytes, including this header */\
-	u8                              revision;               /* ACPI Specification minor version # */\
-	u8                              checksum;               /* To make sum of entire table == 0 */\
-	char                            oem_id[6];              /* ASCII OEM identification */\
-	char                            oem_table_id[8];        /* ASCII OEM table identification */\
-	u32                             oem_revision;           /* OEM revision number */\
-	char                            asl_compiler_id[4];     /* ASCII ASL compiler vendor ID */\
-	u32                             asl_compiler_revision;	/* ASL compiler version */
-
 struct acpi_table_header {
-ACPI_TABLE_HEADER_DEF};
+	char signature[ACPI_NAME_SIZE];	/* ASCII table signature */
+	u32 length;		/* Length of table in bytes, including this header */
+	u8 revision;		/* ACPI Specification minor version # */
+	u8 checksum;		/* To make sum of entire table == 0 */
+	char oem_id[ACPI_OEM_ID_SIZE];	/* ASCII OEM identification */
+	char oem_table_id[ACPI_OEM_TABLE_ID_SIZE];	/* ASCII OEM table identification */
+	u32 oem_revision;	/* OEM revision number */
+	char asl_compiler_id[ACPI_NAME_SIZE];	/* ASCII ASL compiler vendor ID */
+	u32 asl_compiler_revision;	/* ASL compiler version */
+};
 
 /*
  * GAS - Generic Address Structure (ACPI 2.0+)
+ *
+ * Note: Since this structure is used in the ACPI tables, it is byte aligned.
+ * If misalignment is not supported, access to the Address field must be
+ * performed with care.
  */
 struct acpi_generic_address {
-	u8 address_space_id;	/* Address space where struct or register exists */
-	u8 register_bit_width;	/* Size in bits of given register */
-	u8 register_bit_offset;	/* Bit offset within the register */
+	u8 space_id;		/* Address space where struct or register exists */
+	u8 bit_width;		/* Size in bits of given register */
+	u8 bit_offset;		/* Bit offset within the register */
 	u8 access_width;	/* Minimum Access size (ACPI 3.0) */
 	u64 address;		/* 64-bit address of struct or register */
 };
@@ -114,10 +116,10 @@
  *
  ******************************************************************************/
 
-struct rsdp_descriptor {
+struct acpi_table_rsdp {
 	char signature[8];	/* ACPI signature, contains "RSD PTR " */
 	u8 checksum;		/* ACPI 1.0 checksum */
-	char oem_id[6];		/* OEM identification */
+	char oem_id[ACPI_OEM_ID_SIZE];	/* OEM identification */
 	u8 revision;		/* Must be (0) for ACPI 1.0 or (2) for ACPI 2.0+ */
 	u32 rsdt_physical_address;	/* 32-bit physical address of the RSDT */
 	u32 length;		/* Table length in bytes, including header (ACPI 2.0+) */
@@ -134,12 +136,14 @@
  *
  ******************************************************************************/
 
-struct rsdt_descriptor {
-	ACPI_TABLE_HEADER_DEF u32 table_offset_entry[1];	/* Array of pointers to ACPI tables */
+struct acpi_table_rsdt {
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u32 table_offset_entry[1];	/* Array of pointers to ACPI tables */
 };
 
-struct xsdt_descriptor {
-	ACPI_TABLE_HEADER_DEF u64 table_offset_entry[1];	/* Array of pointers to ACPI tables */
+struct acpi_table_xsdt {
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u64 table_offset_entry[1];	/* Array of pointers to ACPI tables */
 };
 
 /*******************************************************************************
@@ -148,36 +152,27 @@
  *
  ******************************************************************************/
 
-struct facs_descriptor {
+struct acpi_table_facs {
 	char signature[4];	/* ASCII table signature */
 	u32 length;		/* Length of structure, in bytes */
 	u32 hardware_signature;	/* Hardware configuration signature */
 	u32 firmware_waking_vector;	/* 32-bit physical address of the Firmware Waking Vector */
 	u32 global_lock;	/* Global Lock for shared hardware resources */
-
-	/* Flags (32 bits) */
-
-	u8 S4bios_f:1;		/* 00:    S4BIOS support is present */
-	 u8:7;			/* 01-07: Reserved, must be zero */
-	u8 reserved1[3];	/* 08-31: Reserved, must be zero */
-
+	u32 flags;
 	u64 xfirmware_waking_vector;	/* 64-bit version of the Firmware Waking Vector (ACPI 2.0+) */
 	u8 version;		/* Version of this table (ACPI 2.0+) */
 	u8 reserved[31];	/* Reserved, must be zero */
 };
 
+/* Flag macros */
+
+#define ACPI_FACS_S4_BIOS_PRESENT (1)	/* 00: S4BIOS support is present */
+
+/* Global lock flags */
+
 #define ACPI_GLOCK_PENDING      0x01	/* 00: Pending global lock ownership */
 #define ACPI_GLOCK_OWNED        0x02	/* 01: Global lock is owned */
 
-/*
- * Common FACS - This is a version-independent FACS structure used for internal use only
- */
-struct acpi_common_facs {
-	u32 *global_lock;
-	u64 *firmware_waking_vector;
-	u8 vector_width;
-};
-
 /*******************************************************************************
  *
  * FADT - Fixed ACPI Description Table (Signature "FACP")
@@ -186,121 +181,98 @@
 
 /* Fields common to all versions of the FADT */
 
-#define ACPI_FADT_COMMON \
-	ACPI_TABLE_HEADER_DEF \
-	u32                             V1_firmware_ctrl;   /* 32-bit physical address of FACS */ \
-	u32                             V1_dsdt;            /* 32-bit physical address of DSDT */ \
-	u8                              reserved1;          /* System Interrupt Model isn't used in ACPI 2.0*/ \
-	u8                              prefer_PM_profile;  /* Conveys preferred power management profile to OSPM. */ \
-	u16                             sci_int;            /* System vector of SCI interrupt */ \
-	u32                             smi_cmd;            /* Port address of SMI command port */ \
-	u8                              acpi_enable;        /* Value to write to smi_cmd to enable ACPI */ \
-	u8                              acpi_disable;       /* Value to write to smi_cmd to disable ACPI */ \
-	u8                              S4bios_req;         /* Value to write to SMI CMD to enter S4BIOS state */ \
-	u8                              pstate_cnt;         /* Processor performance state control*/ \
-	u32                             V1_pm1a_evt_blk;    /* Port address of Power Mgt 1a Event Reg Blk */ \
-	u32                             V1_pm1b_evt_blk;    /* Port address of Power Mgt 1b Event Reg Blk */ \
-	u32                             V1_pm1a_cnt_blk;    /* Port address of Power Mgt 1a Control Reg Blk */ \
-	u32                             V1_pm1b_cnt_blk;    /* Port address of Power Mgt 1b Control Reg Blk */ \
-	u32                             V1_pm2_cnt_blk;     /* Port address of Power Mgt 2 Control Reg Blk */ \
-	u32                             V1_pm_tmr_blk;      /* Port address of Power Mgt Timer Ctrl Reg Blk */ \
-	u32                             V1_gpe0_blk;        /* Port addr of General Purpose acpi_event 0 Reg Blk */ \
-	u32                             V1_gpe1_blk;        /* Port addr of General Purpose acpi_event 1 Reg Blk */ \
-	u8                              pm1_evt_len;        /* Byte Length of ports at pm1_x_evt_blk */ \
-	u8                              pm1_cnt_len;        /* Byte Length of ports at pm1_x_cnt_blk */ \
-	u8                              pm2_cnt_len;        /* Byte Length of ports at pm2_cnt_blk */ \
-	u8                              pm_tm_len;          /* Byte Length of ports at pm_tm_blk */ \
-	u8                              gpe0_blk_len;       /* Byte Length of ports at gpe0_blk */ \
-	u8                              gpe1_blk_len;       /* Byte Length of ports at gpe1_blk */ \
-	u8                              gpe1_base;          /* Offset in gpe model where gpe1 events start */ \
-	u8                              cst_cnt;            /* Support for the _CST object and C States change notification.*/ \
-	u16                             plvl2_lat;          /* Worst case HW latency to enter/exit C2 state */ \
-	u16                             plvl3_lat;          /* Worst case HW latency to enter/exit C3 state */ \
-	u16                             flush_size;         /* Processor's memory cache line width, in bytes */ \
-	u16                             flush_stride;       /* Number of flush strides that need to be read */ \
-	u8                              duty_offset;        /* Processor's duty cycle index in processor's P_CNT reg*/ \
-	u8                              duty_width;         /* Processor's duty cycle value bit width in P_CNT register.*/ \
-	u8                              day_alrm;           /* Index to day-of-month alarm in RTC CMOS RAM */ \
-	u8                              mon_alrm;           /* Index to month-of-year alarm in RTC CMOS RAM */ \
-	u8                              century;            /* Index to century in RTC CMOS RAM */ \
-	u16                             iapc_boot_arch;     /* IA-PC Boot Architecture Flags. See Table 5-10 for description*/ \
-	u8                              reserved2;          /* Reserved, must be zero */
-
-/*
- * ACPI 2.0+ FADT
- */
-struct fadt_descriptor {
-	ACPI_FADT_COMMON
-	    /* Flags (32 bits) */
-	u8 wb_invd:1;		/* 00:    The wbinvd instruction works properly */
-	u8 wb_invd_flush:1;	/* 01:    The wbinvd flushes but does not invalidate */
-	u8 proc_c1:1;		/* 02:    All processors support C1 state */
-	u8 plvl2_up:1;		/* 03:    C2 state works on MP system */
-	u8 pwr_button:1;	/* 04:    Power button is handled as a generic feature */
-	u8 sleep_button:1;	/* 05:    Sleep button is handled as a generic feature, or not present */
-	u8 fixed_rTC:1;		/* 06:    RTC wakeup stat not in fixed register space */
-	u8 rtcs4:1;		/* 07:    RTC wakeup stat not possible from S4 */
-	u8 tmr_val_ext:1;	/* 08:    tmr_val is 32 bits 0=24-bits */
-	u8 dock_cap:1;		/* 09:    Docking supported */
-	u8 reset_reg_sup:1;	/* 10:    System reset via the FADT RESET_REG supported */
-	u8 sealed_case:1;	/* 11:    No internal expansion capabilities and case is sealed */
-	u8 headless:1;		/* 12:    No local video capabilities or local input devices */
-	u8 cpu_sw_sleep:1;	/* 13:    Must execute native instruction after writing SLP_TYPx register */
-
-	u8 pci_exp_wak:1;	/* 14:    System supports PCIEXP_WAKE (STS/EN) bits (ACPI 3.0) */
-	u8 use_platform_clock:1;	/* 15:    OSPM should use platform-provided timer (ACPI 3.0) */
-	u8 S4rtc_sts_valid:1;	/* 16:    Contents of RTC_STS valid after S4 wake (ACPI 3.0) */
-	u8 remote_power_on_capable:1;	/* 17:    System is compatible with remote power on (ACPI 3.0) */
-	u8 force_apic_cluster_model:1;	/* 18:    All local APICs must use cluster model (ACPI 3.0) */
-	u8 force_apic_physical_destination_mode:1;	/* 19:   All local x_aPICs must use physical dest mode (ACPI 3.0) */
-	 u8:4;			/* 20-23: Reserved, must be zero */
-	u8 reserved3;		/* 24-31: Reserved, must be zero */
-
-	struct acpi_generic_address reset_register;	/* Reset register address in GAS format */
+struct acpi_table_fadt {
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u32 facs;		/* 32-bit physical address of FACS */
+	u32 dsdt;		/* 32-bit physical address of DSDT */
+	u8 model;		/* System Interrupt Model (ACPI 1.0) - not used in ACPI 2.0+ */
+	u8 preferred_profile;	/* Conveys preferred power management profile to OSPM. */
+	u16 sci_interrupt;	/* System vector of SCI interrupt */
+	u32 smi_command;	/* 32-bit Port address of SMI command port */
+	u8 acpi_enable;		/* Value to write to smi_cmd to enable ACPI */
+	u8 acpi_disable;	/* Value to write to smi_cmd to disable ACPI */
+	u8 S4bios_request;	/* Value to write to SMI CMD to enter S4BIOS state */
+	u8 pstate_control;	/* Processor performance state control */
+	u32 pm1a_event_block;	/* 32-bit Port address of Power Mgt 1a Event Reg Blk */
+	u32 pm1b_event_block;	/* 32-bit Port address of Power Mgt 1b Event Reg Blk */
+	u32 pm1a_control_block;	/* 32-bit Port address of Power Mgt 1a Control Reg Blk */
+	u32 pm1b_control_block;	/* 32-bit Port address of Power Mgt 1b Control Reg Blk */
+	u32 pm2_control_block;	/* 32-bit Port address of Power Mgt 2 Control Reg Blk */
+	u32 pm_timer_block;	/* 32-bit Port address of Power Mgt Timer Ctrl Reg Blk */
+	u32 gpe0_block;		/* 32-bit Port address of General Purpose Event 0 Reg Blk */
+	u32 gpe1_block;		/* 32-bit Port address of General Purpose Event 1 Reg Blk */
+	u8 pm1_event_length;	/* Byte Length of ports at pm1x_event_block */
+	u8 pm1_control_length;	/* Byte Length of ports at pm1x_control_block */
+	u8 pm2_control_length;	/* Byte Length of ports at pm2_control_block */
+	u8 pm_timer_length;	/* Byte Length of ports at pm_timer_block */
+	u8 gpe0_block_length;	/* Byte Length of ports at gpe0_block */
+	u8 gpe1_block_length;	/* Byte Length of ports at gpe1_block */
+	u8 gpe1_base;		/* Offset in GPE number space where GPE1 events start */
+	u8 cst_control;		/* Support for the _CST object and C States change notification */
+	u16 C2latency;		/* Worst case HW latency to enter/exit C2 state */
+	u16 C3latency;		/* Worst case HW latency to enter/exit C3 state */
+	u16 flush_size;		/* Processor's memory cache line width, in bytes */
+	u16 flush_stride;	/* Number of flush strides that need to be read */
+	u8 duty_offset;		/* Processor duty cycle index in processor's P_CNT reg */
+	u8 duty_width;		/* Processor duty cycle value bit width in P_CNT register. */
+	u8 day_alarm;		/* Index to day-of-month alarm in RTC CMOS RAM */
+	u8 month_alarm;		/* Index to month-of-year alarm in RTC CMOS RAM */
+	u8 century;		/* Index to century in RTC CMOS RAM */
+	u16 boot_flags;		/* IA-PC Boot Architecture Flags. See Table 5-10 for description */
+	u8 reserved;		/* Reserved, must be zero */
+	u32 flags;		/* Miscellaneous flag bits (see below for individual flags) */
+	struct acpi_generic_address reset_register;	/* 64-bit address of the Reset register */
 	u8 reset_value;		/* Value to write to the reset_register port to reset the system */
-	u8 reserved4[3];	/* These three bytes must be zero */
-	u64 xfirmware_ctrl;	/* 64-bit physical address of FACS */
+	u8 reserved4[3];	/* Reserved, must be zero */
+	u64 Xfacs;		/* 64-bit physical address of FACS */
 	u64 Xdsdt;		/* 64-bit physical address of DSDT */
-	struct acpi_generic_address xpm1a_evt_blk;	/* Extended Power Mgt 1a acpi_event Reg Blk address */
-	struct acpi_generic_address xpm1b_evt_blk;	/* Extended Power Mgt 1b acpi_event Reg Blk address */
-	struct acpi_generic_address xpm1a_cnt_blk;	/* Extended Power Mgt 1a Control Reg Blk address */
-	struct acpi_generic_address xpm1b_cnt_blk;	/* Extended Power Mgt 1b Control Reg Blk address */
-	struct acpi_generic_address xpm2_cnt_blk;	/* Extended Power Mgt 2 Control Reg Blk address */
-	struct acpi_generic_address xpm_tmr_blk;	/* Extended Power Mgt Timer Ctrl Reg Blk address */
-	struct acpi_generic_address xgpe0_blk;	/* Extended General Purpose acpi_event 0 Reg Blk address */
-	struct acpi_generic_address xgpe1_blk;	/* Extended General Purpose acpi_event 1 Reg Blk address */
+	struct acpi_generic_address xpm1a_event_block;	/* 64-bit Extended Power Mgt 1a Event Reg Blk address */
+	struct acpi_generic_address xpm1b_event_block;	/* 64-bit Extended Power Mgt 1b Event Reg Blk address */
+	struct acpi_generic_address xpm1a_control_block;	/* 64-bit Extended Power Mgt 1a Control Reg Blk address */
+	struct acpi_generic_address xpm1b_control_block;	/* 64-bit Extended Power Mgt 1b Control Reg Blk address */
+	struct acpi_generic_address xpm2_control_block;	/* 64-bit Extended Power Mgt 2 Control Reg Blk address */
+	struct acpi_generic_address xpm_timer_block;	/* 64-bit Extended Power Mgt Timer Ctrl Reg Blk address */
+	struct acpi_generic_address xgpe0_block;	/* 64-bit Extended General Purpose Event 0 Reg Blk address */
+	struct acpi_generic_address xgpe1_block;	/* 64-bit Extended General Purpose Event 1 Reg Blk address */
 };
 
+/* FADT flags */
+
+#define ACPI_FADT_WBINVD            (1)	/* 00: The wbinvd instruction works properly */
+#define ACPI_FADT_WBINVD_FLUSH      (1<<1)	/* 01: The wbinvd flushes but does not invalidate */
+#define ACPI_FADT_C1_SUPPORTED      (1<<2)	/* 02: All processors support C1 state */
+#define ACPI_FADT_C2_MP_SUPPORTED   (1<<3)	/* 03: C2 state works on MP system */
+#define ACPI_FADT_POWER_BUTTON      (1<<4)	/* 04: Power button is handled as a generic feature */
+#define ACPI_FADT_SLEEP_BUTTON      (1<<5)	/* 05: Sleep button is handled as a generic feature, or  not present */
+#define ACPI_FADT_FIXED_RTC         (1<<6)	/* 06: RTC wakeup stat not in fixed register space */
+#define ACPI_FADT_S4_RTC_WAKE       (1<<7)	/* 07: RTC wakeup stat not possible from S4 */
+#define ACPI_FADT_32BIT_TIMER       (1<<8)	/* 08: tmr_val is 32 bits 0=24-bits */
+#define ACPI_FADT_DOCKING_SUPPORTED (1<<9)	/* 09: Docking supported */
+#define ACPI_FADT_RESET_REGISTER    (1<<10)	/* 10: System reset via the FADT RESET_REG supported */
+#define ACPI_FADT_SEALED_CASE       (1<<11)	/* 11: No internal expansion capabilities and case is sealed */
+#define ACPI_FADT_HEADLESS          (1<<12)	/* 12: No local video capabilities or local input devices */
+#define ACPI_FADT_SLEEP_TYPE        (1<<13)	/* 13: Must execute native instruction after writing  SLP_TYPx register */
+#define ACPI_FADT_PCI_EXPRESS_WAKE  (1<<14)	/* 14: System supports PCIEXP_WAKE (STS/EN) bits (ACPI 3.0) */
+#define ACPI_FADT_PLATFORM_CLOCK    (1<<15)	/* 15: OSPM should use platform-provided timer (ACPI 3.0) */
+#define ACPI_FADT_S4_RTC_VALID      (1<<16)	/* 16: Contents of RTC_STS valid after S4 wake (ACPI 3.0) */
+#define ACPI_FADT_REMOTE_POWER_ON   (1<<17)	/* 17: System is compatible with remote power on (ACPI 3.0) */
+#define ACPI_FADT_APIC_CLUSTER      (1<<18)	/* 18: All local APICs must use cluster model (ACPI 3.0) */
+#define ACPI_FADT_APIC_PHYSICAL     (1<<19)	/* 19: All local x_aPICs must use physical dest mode (ACPI 3.0) */
+
 /*
- * "Down-revved" ACPI 2.0 FADT descriptor
- * Defined here to allow compiler to generate the length of the struct
+ * FADT Prefered Power Management Profiles
  */
-struct fadt_descriptor_rev2_minus {
-	ACPI_FADT_COMMON u32 flags;
-	struct acpi_generic_address reset_register;	/* Reset register address in GAS format */
-	u8 reset_value;		/* Value to write to the reset_register port to reset the system. */
-	u8 reserved7[3];	/* Reserved, must be zero */
+enum acpi_prefered_pm_profiles {
+	PM_UNSPECIFIED = 0,
+	PM_DESKTOP = 1,
+	PM_MOBILE = 2,
+	PM_WORKSTATION = 3,
+	PM_ENTERPRISE_SERVER = 4,
+	PM_SOHO_SERVER = 5,
+	PM_APPLIANCE_PC = 6
 };
 
-/*
- * ACPI 1.0 FADT
- * Defined here to allow compiler to generate the length of the struct
- */
-struct fadt_descriptor_rev1 {
-	ACPI_FADT_COMMON u32 flags;
-};
-
-/* FADT: Prefered Power Management Profiles */
-
-#define PM_UNSPECIFIED                  0
-#define PM_DESKTOP                      1
-#define PM_MOBILE                       2
-#define PM_WORKSTATION                  3
-#define PM_ENTERPRISE_SERVER            4
-#define PM_SOHO_SERVER                  5
-#define PM_APPLIANCE_PC                 6
-
-/* FADT: Boot Arch Flags */
+/* FADT Boot Arch Flags */
 
 #define BAF_LEGACY_DEVICES              0x0001
 #define BAF_8042_KEYBOARD_CONTROLLER    0x0002
@@ -312,59 +284,12 @@
 
 #pragma pack()
 
-/*
- * This macro is temporary until the table bitfield flag definitions
- * are removed and replaced by a Flags field.
- */
-#define ACPI_FLAG_OFFSET(d,f,o)         (u8) (ACPI_OFFSET (d,f) + \
-			  sizeof(((d *)0)->f) + o)
+#define ACPI_FADT_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_fadt, f)
+
 /*
  * Get the remaining ACPI tables
  */
-#include "actbl1.h"
 
-/*
- * ACPI Table information.  We save the table address, length,
- * and type of memory allocation (mapped or allocated) for each
- * table for 1) when we exit, and 2) if a new table is installed
- */
-#define ACPI_MEM_NOT_ALLOCATED  0
-#define ACPI_MEM_ALLOCATED      1
-#define ACPI_MEM_MAPPED         2
-
-/* Definitions for the Flags bitfield member of struct acpi_table_support */
-
-#define ACPI_TABLE_SINGLE       0x00
-#define ACPI_TABLE_MULTIPLE     0x01
-#define ACPI_TABLE_EXECUTABLE   0x02
-
-#define ACPI_TABLE_ROOT         0x00
-#define ACPI_TABLE_PRIMARY      0x10
-#define ACPI_TABLE_SECONDARY    0x20
-#define ACPI_TABLE_ALL          0x30
-#define ACPI_TABLE_TYPE_MASK    0x30
-
-/* Data about each known table type */
-
-struct acpi_table_support {
-	char *name;
-	char *signature;
-	void **global_ptr;
-	u8 sig_length;
-	u8 flags;
-};
-
-extern u8 acpi_fadt_is_v1;	/* is set to 1 if FADT is revision 1,
-				 * needed for certain workarounds */
-/* Macros used to generate offsets to specific table fields */
-
-#define ACPI_FACS_OFFSET(f)             (u8) ACPI_OFFSET (struct facs_descriptor,f)
-#define ACPI_FADT_OFFSET(f)             (u8) ACPI_OFFSET (struct fadt_descriptor, f)
-#define ACPI_GAS_OFFSET(f)              (u8) ACPI_OFFSET (struct acpi_generic_address,f)
-#define ACPI_HDR_OFFSET(f)              (u8) ACPI_OFFSET (struct acpi_table_header,f)
-#define ACPI_RSDP_OFFSET(f)             (u8) ACPI_OFFSET (struct rsdp_descriptor,f)
-
-#define ACPI_FADT_FLAG_OFFSET(f,o)      ACPI_FLAG_OFFSET (struct fadt_descriptor,f,o)
-#define ACPI_FACS_FLAG_OFFSET(f,o)      ACPI_FLAG_OFFSET (struct facs_descriptor,f,o)
+#include <acpi/actbl1.h>
 
 #endif				/* __ACTBL_H__ */
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
index 745a644..4e5d3ca 100644
--- a/include/acpi/actbl1.h
+++ b/include/acpi/actbl1.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -61,6 +61,7 @@
 #define ACPI_SIG_BOOT           "BOOT"	/* Simple Boot Flag Table */
 #define ACPI_SIG_CPEP           "CPEP"	/* Corrected Platform Error Polling table */
 #define ACPI_SIG_DBGP           "DBGP"	/* Debug Port table */
+#define ACPI_SIG_DMAR           "DMAR"	/* DMA Remapping table */
 #define ACPI_SIG_ECDT           "ECDT"	/* Embedded Controller Boot Resources Table */
 #define ACPI_SIG_HPET           "HPET"	/* High Precision Event Timer table */
 #define ACPI_SIG_MADT           "APIC"	/* Multiple APIC Description Table */
@@ -73,12 +74,6 @@
 #define ACPI_SIG_TCPA           "TCPA"	/* Trusted Computing Platform Alliance table */
 #define ACPI_SIG_WDRT           "WDRT"	/* Watchdog Resource Table */
 
-/* Legacy names */
-
-#define APIC_SIG                "APIC"	/* Multiple APIC Description Table */
-#define BOOT_SIG                "BOOT"	/* Simple Boot Flag Table */
-#define SBST_SIG                "SBST"	/* Smart Battery Specification Table */
-
 /*
  * All tables must be byte-packed to match the ACPI specification, since
  * the tables are provided by the system BIOS.
@@ -91,31 +86,43 @@
  * portable, so do not use any other bitfield types.
  */
 
+/* Common Sub-table header (used in MADT, SRAT, etc.) */
+
+struct acpi_subtable_header {
+	u8 type;
+	u8 length;
+};
+
 /*******************************************************************************
  *
  * ASF - Alert Standard Format table (Signature "ASF!")
  *
+ * Conforms to the Alert Standard Format Specification V2.0, 23 April 2003
+ *
  ******************************************************************************/
 
 struct acpi_table_asf {
-ACPI_TABLE_HEADER_DEF};
+	struct acpi_table_header header;	/* Common ACPI table header */
+};
 
-#define ACPI_ASF_HEADER_DEF \
-	u8                              type; \
-	u8                              reserved; \
-	u16                             length;
+/* ASF subtable header */
 
 struct acpi_asf_header {
-ACPI_ASF_HEADER_DEF};
+	u8 type;
+	u8 reserved;
+	u16 length;
+};
 
-/* Values for Type field */
+/* Values for Type field above */
 
-#define ASF_INFO                0
-#define ASF_ALERT               1
-#define ASF_CONTROL             2
-#define ASF_BOOT                3
-#define ASF_ADDRESS             4
-#define ASF_RESERVED            5
+enum acpi_asf_type {
+	ACPI_ASF_TYPE_INFO = 0,
+	ACPI_ASF_TYPE_ALERT = 1,
+	ACPI_ASF_TYPE_CONTROL = 2,
+	ACPI_ASF_TYPE_BOOT = 3,
+	ACPI_ASF_TYPE_ADDRESS = 4,
+	ACPI_ASF_TYPE_RESERVED = 5
+};
 
 /*
  * ASF subtables
@@ -124,7 +131,8 @@
 /* 0: ASF Information */
 
 struct acpi_asf_info {
-	ACPI_ASF_HEADER_DEF u8 min_reset_value;
+	struct acpi_asf_header header;
+	u8 min_reset_value;
 	u8 min_poll_interval;
 	u16 system_id;
 	u32 mfg_id;
@@ -135,26 +143,49 @@
 /* 1: ASF Alerts */
 
 struct acpi_asf_alert {
-	ACPI_ASF_HEADER_DEF u8 assert_mask;
+	struct acpi_asf_header header;
+	u8 assert_mask;
 	u8 deassert_mask;
 	u8 alerts;
 	u8 data_length;
-	u8 array[1];
+};
+
+struct acpi_asf_alert_data {
+	u8 address;
+	u8 command;
+	u8 mask;
+	u8 value;
+	u8 sensor_type;
+	u8 type;
+	u8 offset;
+	u8 source_type;
+	u8 severity;
+	u8 sensor_number;
+	u8 entity;
+	u8 instance;
 };
 
 /* 2: ASF Remote Control */
 
 struct acpi_asf_remote {
-	ACPI_ASF_HEADER_DEF u8 controls;
+	struct acpi_asf_header header;
+	u8 controls;
 	u8 data_length;
 	u16 reserved2;
-	u8 array[1];
+};
+
+struct acpi_asf_control_data {
+	u8 function;
+	u8 address;
+	u8 command;
+	u8 value;
 };
 
 /* 3: ASF RMCP Boot Options */
 
 struct acpi_asf_rmcp {
-	ACPI_ASF_HEADER_DEF u8 capabilities[7];
+	struct acpi_asf_header header;
+	u8 capabilities[7];
 	u8 completion_code;
 	u32 enterprise_id;
 	u8 command;
@@ -166,9 +197,9 @@
 /* 4: ASF Address */
 
 struct acpi_asf_address {
-	ACPI_ASF_HEADER_DEF u8 eprom_address;
+	struct acpi_asf_header header;
+	u8 eprom_address;
 	u8 devices;
-	u8 smbus_addresses[1];
 };
 
 /*******************************************************************************
@@ -178,7 +209,8 @@
  ******************************************************************************/
 
 struct acpi_table_boot {
-	ACPI_TABLE_HEADER_DEF u8 cmos_index;	/* Index in CMOS RAM for the boot register */
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u8 cmos_index;		/* Index in CMOS RAM for the boot register */
 	u8 reserved[3];
 };
 
@@ -189,7 +221,8 @@
  ******************************************************************************/
 
 struct acpi_table_cpep {
-	ACPI_TABLE_HEADER_DEF u64 reserved;
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u64 reserved;
 };
 
 /* Subtable */
@@ -197,9 +230,9 @@
 struct acpi_cpep_polling {
 	u8 type;
 	u8 length;
-	u8 processor_id;	/* Processor ID */
-	u8 processor_eid;	/* Processor EID */
-	u32 polling_interval;	/* Polling interval (msec) */
+	u8 id;			/* Processor ID */
+	u8 eid;			/* Processor EID */
+	u32 interval;		/* Polling interval (msec) */
 };
 
 /*******************************************************************************
@@ -209,23 +242,97 @@
  ******************************************************************************/
 
 struct acpi_table_dbgp {
-	ACPI_TABLE_HEADER_DEF u8 interface_type;	/* 0=full 16550, 1=subset of 16550 */
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u8 type;		/* 0=full 16550, 1=subset of 16550 */
 	u8 reserved[3];
 	struct acpi_generic_address debug_port;
 };
 
 /*******************************************************************************
  *
+ * DMAR - DMA Remapping table
+ *
+ ******************************************************************************/
+
+struct acpi_table_dmar {
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u8 width;		/* Host Address Width */
+	u8 reserved[11];
+};
+
+/* DMAR subtable header */
+
+struct acpi_dmar_header {
+	u16 type;
+	u16 length;
+	u8 flags;
+	u8 reserved[3];
+};
+
+/* Values for subtable type in struct acpi_dmar_header */
+
+enum acpi_dmar_type {
+	ACPI_DMAR_TYPE_HARDWARE_UNIT = 0,
+	ACPI_DMAR_TYPE_RESERVED_MEMORY = 1,
+	ACPI_DMAR_TYPE_RESERVED = 2	/* 2 and greater are reserved */
+};
+
+struct acpi_dmar_device_scope {
+	u8 entry_type;
+	u8 length;
+	u8 segment;
+	u8 bus;
+};
+
+/* Values for entry_type in struct acpi_dmar_device_scope */
+
+enum acpi_dmar_scope_type {
+	ACPI_DMAR_SCOPE_TYPE_NOT_USED = 0,
+	ACPI_DMAR_SCOPE_TYPE_ENDPOINT = 1,
+	ACPI_DMAR_SCOPE_TYPE_BRIDGE = 2,
+	ACPI_DMAR_SCOPE_TYPE_RESERVED = 3	/* 3 and greater are reserved */
+};
+
+/*
+ * DMAR Sub-tables, correspond to Type in struct acpi_dmar_header
+ */
+
+/* 0: Hardware Unit Definition */
+
+struct acpi_dmar_hardware_unit {
+	struct acpi_dmar_header header;
+	u64 address;		/* Register Base Address */
+};
+
+/* Flags */
+
+#define ACPI_DMAR_INCLUDE_ALL       (1)
+
+/* 1: Reserved Memory Defininition */
+
+struct acpi_dmar_reserved_memory {
+	struct acpi_dmar_header header;
+	u64 address;		/* 4_k aligned base address */
+	u64 end_address;	/* 4_k aligned limit address */
+};
+
+/* Flags */
+
+#define ACPI_DMAR_ALLOW_ALL         (1)
+
+/*******************************************************************************
+ *
  * ECDT - Embedded Controller Boot Resources Table
  *
  ******************************************************************************/
 
-struct ec_boot_resources {
-	ACPI_TABLE_HEADER_DEF struct acpi_generic_address ec_control;	/* Address of EC command/status register */
-	struct acpi_generic_address ec_data;	/* Address of EC data register */
+struct acpi_table_ecdt {
+	struct acpi_table_header header;	/* Common ACPI table header */
+	struct acpi_generic_address control;	/* Address of EC command/status register */
+	struct acpi_generic_address data;	/* Address of EC data register */
 	u32 uid;		/* Unique ID - must be same as the EC _UID method */
-	u8 gpe_bit;		/* The GPE for the EC */
-	u8 ec_id[1];		/* Full namepath of the EC in the ACPI namespace */
+	u8 gpe;			/* The GPE for the EC */
+	u8 id[1];		/* Full namepath of the EC in the ACPI namespace */
 };
 
 /*******************************************************************************
@@ -234,22 +341,22 @@
  *
  ******************************************************************************/
 
-struct acpi_hpet_table {
-	ACPI_TABLE_HEADER_DEF u32 hardware_id;	/* Hardware ID of event timer block */
-	struct acpi_generic_address base_address;	/* Address of event timer block */
-	u8 hpet_number;		/* HPET sequence number */
-	u16 clock_tick;		/* Main counter min tick, periodic mode */
-	u8 attributes;
+struct acpi_table_hpet {
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u32 id;			/* Hardware ID of event timer block */
+	struct acpi_generic_address address;	/* Address of event timer block */
+	u8 sequence;		/* HPET sequence number */
+	u16 minimum_tick;	/* Main counter min tick, periodic mode */
+	u8 flags;
 };
 
-#if 0				/* HPET flags to be converted to macros */
-struct {			/* Flags (8 bits) */
-	u8 page_protect:1;	/* 00:    No page protection */
-	u8 page_protect4:1;	/* 01:    4_kB page protected */
-	u8 page_protect64:1;	/* 02:    64_kB page protected */
-	 u8:5;			/* 03-07: Reserved, must be zero */
-} flags;
-#endif
+/*! Flags */
+
+#define ACPI_HPET_PAGE_PROTECT      (1)	/* 00: No page protection */
+#define ACPI_HPET_PAGE_PROTECT_4    (1<<1)	/* 01: 4KB page protected */
+#define ACPI_HPET_PAGE_PROTECT_64   (1<<2)	/* 02: 64KB page protected */
+
+/*! [End] no source code translation !*/
 
 /*******************************************************************************
  *
@@ -257,148 +364,159 @@
  *
  ******************************************************************************/
 
-struct multiple_apic_table {
-	ACPI_TABLE_HEADER_DEF u32 local_apic_address;	/* Physical address of local APIC */
-
-	/* Flags (32 bits) */
-
-	u8 PCATcompat:1;	/* 00:    System also has dual 8259s */
-	 u8:7;			/* 01-07: Reserved, must be zero */
-	u8 reserved1[3];	/* 08-31: Reserved, must be zero */
+struct acpi_table_madt {
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u32 address;		/* Physical address of local APIC */
+	u32 flags;
 };
 
-/* Values for MADT PCATCompat */
+/* Flags */
 
-#define DUAL_PIC                0
-#define MULTIPLE_APIC           1
+#define ACPI_MADT_PCAT_COMPAT       (1)	/* 00:    System also has dual 8259s */
 
-/* Common MADT Sub-table header */
+/* Values for PCATCompat flag */
 
-#define APIC_HEADER_DEF \
-	u8                              type; \
-	u8                              length;
+#define ACPI_MADT_DUAL_PIC          0
+#define ACPI_MADT_MULTIPLE_APIC     1
 
-struct apic_header {
-APIC_HEADER_DEF};
+/* Values for subtable type in struct acpi_subtable_header */
 
-/* Values for Type in struct apic_header */
-
-#define APIC_PROCESSOR          0
-#define APIC_IO                 1
-#define APIC_XRUPT_OVERRIDE     2
-#define APIC_NMI                3
-#define APIC_LOCAL_NMI          4
-#define APIC_ADDRESS_OVERRIDE   5
-#define APIC_IO_SAPIC           6
-#define APIC_LOCAL_SAPIC        7
-#define APIC_XRUPT_SOURCE       8
-#define APIC_RESERVED           9	/* 9 and greater are reserved */
-
-/* Flag definitions for MADT sub-tables */
-
-#define ACPI_MADT_IFLAGS /* INTI flags (16 bits) */ \
-	u8                              polarity        : 2;    /* 00-01: Polarity of APIC I/O input signals */\
-	u8                              trigger_mode    : 2;    /* 02-03: Trigger mode of APIC input signals */\
-	u8                                              : 4;    /* 04-07: Reserved, must be zero */\
-	u8                              reserved1;	/* 08-15: Reserved, must be zero */
-
-#define ACPI_MADT_LFLAGS /* Local Sapic flags (32 bits) */ \
-	u8                              processor_enabled: 1;   /* 00:    Processor is usable if set */\
-	u8                                              : 7;    /* 01-07: Reserved, must be zero */\
-	u8                              reserved2[3];	/* 08-31: Reserved, must be zero */
-
-/* Values for MPS INTI flags */
-
-#define POLARITY_CONFORMS       0
-#define POLARITY_ACTIVE_HIGH    1
-#define POLARITY_RESERVED       2
-#define POLARITY_ACTIVE_LOW     3
-
-#define TRIGGER_CONFORMS        0
-#define TRIGGER_EDGE            1
-#define TRIGGER_RESERVED        2
-#define TRIGGER_LEVEL           3
+enum acpi_madt_type {
+	ACPI_MADT_TYPE_LOCAL_APIC = 0,
+	ACPI_MADT_TYPE_IO_APIC = 1,
+	ACPI_MADT_TYPE_INTERRUPT_OVERRIDE = 2,
+	ACPI_MADT_TYPE_NMI_SOURCE = 3,
+	ACPI_MADT_TYPE_LOCAL_APIC_NMI = 4,
+	ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE = 5,
+	ACPI_MADT_TYPE_IO_SAPIC = 6,
+	ACPI_MADT_TYPE_LOCAL_SAPIC = 7,
+	ACPI_MADT_TYPE_INTERRUPT_SOURCE = 8,
+	ACPI_MADT_TYPE_RESERVED = 9	/* 9 and greater are reserved */
+};
 
 /*
- * MADT Sub-tables, correspond to Type in struct apic_header
+ * MADT Sub-tables, correspond to Type in struct acpi_subtable_header
  */
 
-/* 0: processor APIC */
+/* 0: Processor Local APIC */
 
-struct madt_processor_apic {
-	APIC_HEADER_DEF u8 processor_id;	/* ACPI processor id */
-	u8 local_apic_id;	/* Processor's local APIC id */
- ACPI_MADT_LFLAGS};
+struct acpi_madt_local_apic {
+	struct acpi_subtable_header header;
+	u8 processor_id;	/* ACPI processor id */
+	u8 id;			/* Processor's local APIC id */
+	u32 lapic_flags;
+};
 
 /* 1: IO APIC */
 
-struct madt_io_apic {
-	APIC_HEADER_DEF u8 io_apic_id;	/* I/O APIC ID */
+struct acpi_madt_io_apic {
+	struct acpi_subtable_header header;
+	u8 id;			/* I/O APIC ID */
 	u8 reserved;		/* Reserved - must be zero */
 	u32 address;		/* APIC physical address */
-	u32 interrupt;		/* Global system interrupt where INTI lines start */
+	u32 global_irq_base;	/* Global system interrupt where INTI lines start */
 };
 
 /* 2: Interrupt Override */
 
-struct madt_interrupt_override {
-	APIC_HEADER_DEF u8 bus;	/* 0 - ISA */
-	u8 source;		/* Interrupt source (IRQ) */
-	u32 interrupt;		/* Global system interrupt */
- ACPI_MADT_IFLAGS};
+struct acpi_madt_interrupt_override {
+	struct acpi_subtable_header header;
+	u8 bus;			/* 0 - ISA */
+	u8 source_irq;		/* Interrupt source (IRQ) */
+	u32 global_irq;		/* Global system interrupt */
+	u16 inti_flags;
+};
 
-/* 3: NMI Sources */
+/* 3: NMI Source */
 
-struct madt_nmi_source {
-	APIC_HEADER_DEF ACPI_MADT_IFLAGS u32 interrupt;	/* Global system interrupt */
+struct acpi_madt_nmi_source {
+	struct acpi_subtable_header header;
+	u16 inti_flags;
+	u32 global_irq;		/* Global system interrupt */
 };
 
 /* 4: Local APIC NMI */
 
-struct madt_local_apic_nmi {
-	APIC_HEADER_DEF u8 processor_id;	/* ACPI processor id */
-	ACPI_MADT_IFLAGS u8 lint;	/* LINTn to which NMI is connected */
+struct acpi_madt_local_apic_nmi {
+	struct acpi_subtable_header header;
+	u8 processor_id;	/* ACPI processor id */
+	u16 inti_flags;
+	u8 lint;		/* LINTn to which NMI is connected */
 };
 
 /* 5: Address Override */
 
-struct madt_address_override {
-	APIC_HEADER_DEF u16 reserved;	/* Reserved, must be zero */
+struct acpi_madt_local_apic_override {
+	struct acpi_subtable_header header;
+	u16 reserved;		/* Reserved, must be zero */
 	u64 address;		/* APIC physical address */
 };
 
 /* 6: I/O Sapic */
 
-struct madt_io_sapic {
-	APIC_HEADER_DEF u8 io_sapic_id;	/* I/O SAPIC ID */
+struct acpi_madt_io_sapic {
+	struct acpi_subtable_header header;
+	u8 id;			/* I/O SAPIC ID */
 	u8 reserved;		/* Reserved, must be zero */
-	u32 interrupt_base;	/* Glocal interrupt for SAPIC start */
+	u32 global_irq_base;	/* Global interrupt for SAPIC start */
 	u64 address;		/* SAPIC physical address */
 };
 
 /* 7: Local Sapic */
 
-struct madt_local_sapic {
-	APIC_HEADER_DEF u8 processor_id;	/* ACPI processor id */
-	u8 local_sapic_id;	/* SAPIC ID */
-	u8 local_sapic_eid;	/* SAPIC EID */
+struct acpi_madt_local_sapic {
+	struct acpi_subtable_header header;
+	u8 processor_id;	/* ACPI processor id */
+	u8 id;			/* SAPIC ID */
+	u8 eid;			/* SAPIC EID */
 	u8 reserved[3];		/* Reserved, must be zero */
-	 ACPI_MADT_LFLAGS u32 processor_uID;	/* Numeric UID - ACPI 3.0 */
-	char processor_uIDstring[1];	/* String UID  - ACPI 3.0 */
+	u32 lapic_flags;
+	u32 uid;		/* Numeric UID - ACPI 3.0 */
+	char uid_string[1];	/* String UID  - ACPI 3.0 */
 };
 
 /* 8: Platform Interrupt Source */
 
-struct madt_interrupt_source {
-	APIC_HEADER_DEF ACPI_MADT_IFLAGS u8 interrupt_type;	/* 1=PMI, 2=INIT, 3=corrected */
-	u8 processor_id;	/* Processor ID */
-	u8 processor_eid;	/* Processor EID */
+struct acpi_madt_interrupt_source {
+	struct acpi_subtable_header header;
+	u16 inti_flags;
+	u8 type;		/* 1=PMI, 2=INIT, 3=corrected */
+	u8 id;			/* Processor ID */
+	u8 eid;			/* Processor EID */
 	u8 io_sapic_vector;	/* Vector value for PMI interrupts */
-	u32 interrupt;		/* Global system interrupt */
+	u32 global_irq;		/* Global system interrupt */
 	u32 flags;		/* Interrupt Source Flags */
 };
 
-#ifdef DUPLICATE_DEFINITION_WITH_LINUX_ACPI_H
+/* Flags field above */
+
+#define ACPI_MADT_CPEI_OVERRIDE     (1)
+
+/*
+ * Common flags fields for MADT subtables
+ */
+
+/* MADT Local APIC flags (lapic_flags) */
+
+#define ACPI_MADT_ENABLED           (1)	/* 00: Processor is usable if set */
+
+/* MADT MPS INTI flags (inti_flags) */
+
+#define ACPI_MADT_POLARITY_MASK     (3)	/* 00-01: Polarity of APIC I/O input signals */
+#define ACPI_MADT_TRIGGER_MASK      (3<<2)	/* 02-03: Trigger mode of APIC input signals */
+
+/* Values for MPS INTI flags */
+
+#define ACPI_MADT_POLARITY_CONFORMS       0
+#define ACPI_MADT_POLARITY_ACTIVE_HIGH    1
+#define ACPI_MADT_POLARITY_RESERVED       2
+#define ACPI_MADT_POLARITY_ACTIVE_LOW     3
+
+#define ACPI_MADT_TRIGGER_CONFORMS        (0)
+#define ACPI_MADT_TRIGGER_EDGE            (1<<2)
+#define ACPI_MADT_TRIGGER_RESERVED        (2<<2)
+#define ACPI_MADT_TRIGGER_LEVEL           (3<<2)
+
 /*******************************************************************************
  *
  * MCFG - PCI Memory Mapped Configuration table and sub-table
@@ -406,17 +524,19 @@
  ******************************************************************************/
 
 struct acpi_table_mcfg {
-	ACPI_TABLE_HEADER_DEF u8 reserved[8];
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u8 reserved[8];
 };
 
+/* Subtable */
+
 struct acpi_mcfg_allocation {
-	u64 base_address;	/* Base address, processor-relative */
+	u64 address;		/* Base address, processor-relative */
 	u16 pci_segment;	/* PCI segment group number */
 	u8 start_bus_number;	/* Starting PCI Bus number */
 	u8 end_bus_number;	/* Final PCI Bus number */
 	u32 reserved;
 };
-#endif
 
 /*******************************************************************************
  *
@@ -424,8 +544,9 @@
  *
  ******************************************************************************/
 
-struct smart_battery_table {
-	ACPI_TABLE_HEADER_DEF u32 warning_level;
+struct acpi_table_sbst {
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u32 warning_level;
 	u32 low_level;
 	u32 critical_level;
 };
@@ -436,9 +557,10 @@
  *
  ******************************************************************************/
 
-struct system_locality_info {
-	ACPI_TABLE_HEADER_DEF u64 locality_count;
-	u8 entry[1][1];
+struct acpi_table_slit {
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u64 locality_count;
+	u8 entry[1];		/* Real size = localities^2 */
 };
 
 /*******************************************************************************
@@ -448,7 +570,8 @@
  ******************************************************************************/
 
 struct acpi_table_spcr {
-	ACPI_TABLE_HEADER_DEF u8 interface_type;	/* 0=full 16550, 1=subset of 16550 */
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u8 interface_type;	/* 0=full 16550, 1=subset of 16550 */
 	u8 reserved[3];
 	struct acpi_generic_address serial_port;
 	u8 interrupt_type;
@@ -459,7 +582,7 @@
 	u8 stop_bits;
 	u8 flow_control;
 	u8 terminal_type;
-	u8 reserved2;
+	u8 reserved1;
 	u16 pci_device_id;
 	u16 pci_vendor_id;
 	u8 pci_bus;
@@ -467,7 +590,7 @@
 	u8 pci_function;
 	u32 pci_flags;
 	u8 pci_segment;
-	u32 reserved3;
+	u32 reserved2;
 };
 
 /*******************************************************************************
@@ -477,12 +600,13 @@
  ******************************************************************************/
 
 struct acpi_table_spmi {
-	ACPI_TABLE_HEADER_DEF u8 reserved;
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u8 reserved;
 	u8 interface_type;
 	u16 spec_revision;	/* Version of IPMI */
 	u8 interrupt_type;
 	u8 gpe_number;		/* GPE assigned */
-	u8 reserved2;
+	u8 reserved1;
 	u8 pci_device_flag;
 	u32 interrupt;
 	struct acpi_generic_address ipmi_register;
@@ -498,58 +622,53 @@
  *
  ******************************************************************************/
 
-struct system_resource_affinity {
-	ACPI_TABLE_HEADER_DEF u32 reserved1;	/* Must be value '1' */
-	u64 reserved2;		/* Reserved, must be zero */
+struct acpi_table_srat {
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u32 table_revision;	/* Must be value '1' */
+	u64 reserved;		/* Reserved, must be zero */
 };
 
-/* SRAT common sub-table header */
+/* Values for subtable type in struct acpi_subtable_header */
 
-#define SRAT_SUBTABLE_HEADER \
-	u8                              type; \
-	u8                              length;
-
-/* Values for Type above */
-
-#define SRAT_CPU_AFFINITY       0
-#define SRAT_MEMORY_AFFINITY    1
-#define SRAT_RESERVED           2
+enum acpi_srat_type {
+	ACPI_SRAT_TYPE_CPU_AFFINITY = 0,
+	ACPI_SRAT_TYPE_MEMORY_AFFINITY = 1,
+	ACPI_SRAT_TYPE_RESERVED = 2
+};
 
 /* SRAT sub-tables */
 
-struct static_resource_alloc {
-	SRAT_SUBTABLE_HEADER u8 proximity_domain_lo;
+struct acpi_srat_cpu_affinity {
+	struct acpi_subtable_header header;
+	u8 proximity_domain_lo;
 	u8 apic_id;
-
-	/* Flags (32 bits) */
-
-	u8 enabled:1;		/* 00:    Use affinity structure */
-	 u8:7;			/* 01-07: Reserved, must be zero */
-	u8 reserved3[3];	/* 08-31: Reserved, must be zero */
-
+	u32 flags;
 	u8 local_sapic_eid;
 	u8 proximity_domain_hi[3];
-	u32 reserved4;		/* Reserved, must be zero */
+	u32 reserved;		/* Reserved, must be zero */
 };
 
-struct memory_affinity {
-	SRAT_SUBTABLE_HEADER u32 proximity_domain;
-	u16 reserved3;
+/* Flags */
+
+#define ACPI_SRAT_CPU_ENABLED       (1)	/* 00: Use affinity structure */
+
+struct acpi_srat_mem_affinity {
+	struct acpi_subtable_header header;
+	u32 proximity_domain;
+	u16 reserved;		/* Reserved, must be zero */
 	u64 base_address;
-	u64 address_length;
-	u32 reserved4;
-
-	/* Flags (32 bits) */
-
-	u8 enabled:1;		/* 00:    Use affinity structure */
-	u8 hot_pluggable:1;	/* 01:    Memory region is hot pluggable */
-	u8 non_volatile:1;	/* 02:    Memory is non-volatile */
-	 u8:5;			/* 03-07: Reserved, must be zero */
-	u8 reserved5[3];	/* 08-31: Reserved, must be zero */
-
-	u64 reserved6;		/* Reserved, must be zero */
+	u64 length;
+	u32 memory_type;	/* See acpi_address_range_id */
+	u32 flags;
+	u64 reserved1;		/* Reserved, must be zero */
 };
 
+/* Flags */
+
+#define ACPI_SRAT_MEM_ENABLED       (1)	/* 00: Use affinity structure */
+#define ACPI_SRAT_MEM_HOT_PLUGGABLE (1<<1)	/* 01: Memory region is hot pluggable */
+#define ACPI_SRAT_MEM_NON_VOLATILE  (1<<2)	/* 02: Memory region is non-volatile */
+
 /*******************************************************************************
  *
  * TCPA - Trusted Computing Platform Alliance table
@@ -557,7 +676,8 @@
  ******************************************************************************/
 
 struct acpi_table_tcpa {
-	ACPI_TABLE_HEADER_DEF u16 reserved;
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u16 reserved;
 	u32 max_log_length;	/* Maximum length for the event log area */
 	u64 log_address;	/* Address of the event log area */
 };
@@ -569,7 +689,8 @@
  ******************************************************************************/
 
 struct acpi_table_wdrt {
-	ACPI_TABLE_HEADER_DEF u32 header_length;	/* Watchdog Header Length */
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u32 header_length;	/* Watchdog Header Length */
 	u8 pci_segment;		/* PCI Segment number */
 	u8 pci_bus;		/* PCI Bus number */
 	u8 pci_device;		/* PCI Device number */
@@ -582,58 +703,9 @@
 	u32 entries;		/* Number of watchdog entries that follow */
 };
 
-#if 0				/* Flags, will be converted to macros */
-u8 enabled:1;			/* 00:    Timer enabled */
-u8:6;				/* 01-06: Reserved */
-u8 sleep_stop:1;		/* 07:    Timer stopped in sleep state */
-#endif
+/* Flags */
 
-/* Macros used to generate offsets to specific table fields */
-
-#define ACPI_ASF0_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_asf_info,f)
-#define ACPI_ASF1_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_asf_alert,f)
-#define ACPI_ASF2_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_asf_remote,f)
-#define ACPI_ASF3_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_asf_rmcp,f)
-#define ACPI_ASF4_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_asf_address,f)
-#define ACPI_BOOT_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_boot,f)
-#define ACPI_CPEP_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_cpep,f)
-#define ACPI_CPEP0_OFFSET(f)            (u8) ACPI_OFFSET (struct acpi_cpep_polling,f)
-#define ACPI_DBGP_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_dbgp,f)
-#define ACPI_ECDT_OFFSET(f)             (u8) ACPI_OFFSET (struct ec_boot_resources,f)
-#define ACPI_HPET_OFFSET(f)             (u8) ACPI_OFFSET (struct hpet_table,f)
-#define ACPI_MADT_OFFSET(f)             (u8) ACPI_OFFSET (struct multiple_apic_table,f)
-#define ACPI_MADT0_OFFSET(f)            (u8) ACPI_OFFSET (struct madt_processor_apic,f)
-#define ACPI_MADT1_OFFSET(f)            (u8) ACPI_OFFSET (struct madt_io_apic,f)
-#define ACPI_MADT2_OFFSET(f)            (u8) ACPI_OFFSET (struct madt_interrupt_override,f)
-#define ACPI_MADT3_OFFSET(f)            (u8) ACPI_OFFSET (struct madt_nmi_source,f)
-#define ACPI_MADT4_OFFSET(f)            (u8) ACPI_OFFSET (struct madt_local_apic_nmi,f)
-#define ACPI_MADT5_OFFSET(f)            (u8) ACPI_OFFSET (struct madt_address_override,f)
-#define ACPI_MADT6_OFFSET(f)            (u8) ACPI_OFFSET (struct madt_io_sapic,f)
-#define ACPI_MADT7_OFFSET(f)            (u8) ACPI_OFFSET (struct madt_local_sapic,f)
-#define ACPI_MADT8_OFFSET(f)            (u8) ACPI_OFFSET (struct madt_interrupt_source,f)
-#define ACPI_MADTH_OFFSET(f)            (u8) ACPI_OFFSET (struct apic_header,f)
-#define ACPI_MCFG_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_mcfg,f)
-#define ACPI_MCFG0_OFFSET(f)            (u8) ACPI_OFFSET (struct acpi_mcfg_allocation,f)
-#define ACPI_SBST_OFFSET(f)             (u8) ACPI_OFFSET (struct smart_battery_table,f)
-#define ACPI_SLIT_OFFSET(f)             (u8) ACPI_OFFSET (struct system_locality_info,f)
-#define ACPI_SPCR_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_spcr,f)
-#define ACPI_SPMI_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_spmi,f)
-#define ACPI_SRAT_OFFSET(f)             (u8) ACPI_OFFSET (struct system_resource_affinity,f)
-#define ACPI_SRAT0_OFFSET(f)            (u8) ACPI_OFFSET (struct static_resource_alloc,f)
-#define ACPI_SRAT1_OFFSET(f)            (u8) ACPI_OFFSET (struct memory_affinity,f)
-#define ACPI_TCPA_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_tcpa,f)
-#define ACPI_WDRT_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_wdrt,f)
-
-#define ACPI_HPET_FLAG_OFFSET(f,o)      ACPI_FLAG_OFFSET (struct hpet_table,f,o)
-#define ACPI_SRAT0_FLAG_OFFSET(f,o)     ACPI_FLAG_OFFSET (struct static_resource_alloc,f,o)
-#define ACPI_SRAT1_FLAG_OFFSET(f,o)     ACPI_FLAG_OFFSET (struct memory_affinity,f,o)
-#define ACPI_MADT_FLAG_OFFSET(f,o)      ACPI_FLAG_OFFSET (struct multiple_apic_table,f,o)
-#define ACPI_MADT0_FLAG_OFFSET(f,o)     ACPI_FLAG_OFFSET (struct madt_processor_apic,f,o)
-#define ACPI_MADT2_FLAG_OFFSET(f,o)     ACPI_FLAG_OFFSET (struct madt_interrupt_override,f,o)
-#define ACPI_MADT3_FLAG_OFFSET(f,o)     ACPI_FLAG_OFFSET (struct madt_nmi_source,f,o)
-#define ACPI_MADT4_FLAG_OFFSET(f,o)     ACPI_FLAG_OFFSET (struct madt_local_apic_nmi,f,o)
-#define ACPI_MADT7_FLAG_OFFSET(f,o)     ACPI_FLAG_OFFSET (struct madt_local_sapic,f,o)
-#define ACPI_MADT8_FLAG_OFFSET(f,o)     ACPI_FLAG_OFFSET (struct madt_interrupt_source,f,o)
+#define ACPI_WDRT_TIMER_ENABLED     (1)	/* 00: Timer enabled */
 
 /* Reset to default packing */
 
diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
deleted file mode 100644
index 67efe6c..0000000
--- a/include/acpi/actbl2.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/******************************************************************************
- *
- * Name: actbl2.h - ACPI Specification Revision 2.0 Tables
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- *    substantially similar to the "NO WARRANTY" disclaimer below
- *    ("Disclaimer") and any redistribution must be conditioned upon
- *    including a substantially similar Disclaimer requirement for further
- *    binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- *    of any contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#ifndef __ACTBL2_H__
-#define __ACTBL2_H__
-
-/* Code moved to both actbl.h and actbl1.h */
-
-#endif				/* __ACTBL2_H__ */
diff --git a/include/acpi/actbl71.h b/include/acpi/actbl71.h
deleted file mode 100644
index 10ac05b..0000000
--- a/include/acpi/actbl71.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/******************************************************************************
- *
- * Name: actbl71.h - IA-64 Extensions to the ACPI Spec Rev. 0.71
- *                   This file includes tables specific to this
- *                   specification revision.
- *
- *****************************************************************************/
-
-/*
- *  Copyright (C) 2000 - 2003, R. Byron Moore
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#ifndef __ACTBL71_H__
-#define __ACTBL71_H__
-
-/* 0.71 FADT address_space data item bitmasks defines */
-/* If the associated bit is zero then it is in memory space else in io space */
-
-#define SMI_CMD_ADDRESS_SPACE       0x01
-#define PM1_BLK_ADDRESS_SPACE       0x02
-#define PM2_CNT_BLK_ADDRESS_SPACE   0x04
-#define PM_TMR_BLK_ADDRESS_SPACE    0x08
-#define GPE0_BLK_ADDRESS_SPACE      0x10
-#define GPE1_BLK_ADDRESS_SPACE      0x20
-
-/* Only for clarity in declarations */
-
-typedef u64 IO_ADDRESS;
-
-#pragma pack(1)
-struct {			/* Root System Descriptor Pointer */
-	NATIVE_CHAR signature[8];	/* contains "RSD PTR " */
-	u8 checksum;		/* to make sum of struct == 0 */
-	NATIVE_CHAR oem_id[6];	/* OEM identification */
-	u8 reserved;		/* Must be 0 for 1.0, 2 for 2.0 */
-	u64 rsdt_physical_address;	/* 64-bit physical address of RSDT */
-};
-
-/*****************************************/
-/* IA64 Extensions to ACPI Spec Rev 0.71 */
-/* for the Root System Description Table */
-/*****************************************/
-struct {
-	struct acpi_table_header header;	/* Table header */
-	u32 reserved_pad;	/* IA64 alignment, must be 0 */
-	u64 table_offset_entry[1];	/* Array of pointers to other */
-	/* tables' headers */
-};
-
-/*******************************************/
-/* IA64 Extensions to ACPI Spec Rev 0.71   */
-/* for the Firmware ACPI Control Structure */
-/*******************************************/
-struct {
-	NATIVE_CHAR signature[4];	/* signature "FACS" */
-	u32 length;		/* length of structure, in bytes */
-	u32 hardware_signature;	/* hardware configuration signature */
-	u32 reserved4;		/* must be 0 */
-	u64 firmware_waking_vector;	/* ACPI OS waking vector */
-	u64 global_lock;	/* Global Lock */
-	u32 S4bios_f:1;		/* Indicates if S4BIOS support is present */
-	u32 reserved1:31;	/* must be 0 */
-	u8 reserved3[28];	/* reserved - must be zero */
-};
-
-/******************************************/
-/* IA64 Extensions to ACPI Spec Rev 0.71  */
-/* for the Fixed ACPI Description Table   */
-/******************************************/
-struct {
-	struct acpi_table_header header;	/* table header */
-	u32 reserved_pad;	/* IA64 alignment, must be 0 */
-	u64 firmware_ctrl;	/* 64-bit Physical address of FACS */
-	u64 dsdt;		/* 64-bit Physical address of DSDT */
-	u8 model;		/* System Interrupt Model */
-	u8 address_space;	/* Address Space Bitmask */
-	u16 sci_int;		/* System vector of SCI interrupt */
-	u8 acpi_enable;		/* value to write to smi_cmd to enable ACPI */
-	u8 acpi_disable;	/* value to write to smi_cmd to disable ACPI */
-	u8 S4bios_req;		/* Value to write to SMI CMD to enter S4BIOS state */
-	u8 reserved2;		/* reserved - must be zero */
-	u64 smi_cmd;		/* Port address of SMI command port */
-	u64 pm1a_evt_blk;	/* Port address of Power Mgt 1a acpi_event Reg Blk */
-	u64 pm1b_evt_blk;	/* Port address of Power Mgt 1b acpi_event Reg Blk */
-	u64 pm1a_cnt_blk;	/* Port address of Power Mgt 1a Control Reg Blk */
-	u64 pm1b_cnt_blk;	/* Port address of Power Mgt 1b Control Reg Blk */
-	u64 pm2_cnt_blk;	/* Port address of Power Mgt 2 Control Reg Blk */
-	u64 pm_tmr_blk;		/* Port address of Power Mgt Timer Ctrl Reg Blk */
-	u64 gpe0_blk;		/* Port addr of General Purpose acpi_event 0 Reg Blk */
-	u64 gpe1_blk;		/* Port addr of General Purpose acpi_event 1 Reg Blk */
-	u8 pm1_evt_len;		/* Byte length of ports at pm1_x_evt_blk */
-	u8 pm1_cnt_len;		/* Byte length of ports at pm1_x_cnt_blk */
-	u8 pm2_cnt_len;		/* Byte Length of ports at pm2_cnt_blk */
-	u8 pm_tm_len;		/* Byte Length of ports at pm_tm_blk */
-	u8 gpe0_blk_len;	/* Byte Length of ports at gpe0_blk */
-	u8 gpe1_blk_len;	/* Byte Length of ports at gpe1_blk */
-	u8 gpe1_base;		/* offset in gpe model where gpe1 events start */
-	u8 reserved3;		/* reserved */
-	u16 plvl2_lat;		/* worst case HW latency to enter/exit C2 state */
-	u16 plvl3_lat;		/* worst case HW latency to enter/exit C3 state */
-	u8 day_alrm;		/* index to day-of-month alarm in RTC CMOS RAM */
-	u8 mon_alrm;		/* index to month-of-year alarm in RTC CMOS RAM */
-	u8 century;		/* index to century in RTC CMOS RAM */
-	u8 reserved4;		/* reserved */
-	u32 flush_cash:1;	/* PAL_FLUSH_CACHE is correctly supported */
-	u32 reserved5:1;	/* reserved - must be zero */
-	u32 proc_c1:1;		/* all processors support C1 state */
-	u32 plvl2_up:1;		/* C2 state works on MP system */
-	u32 pwr_button:1;	/* Power button is handled as a generic feature */
-	u32 sleep_button:1;	/* Sleep button is handled as a generic feature, or not present */
-	u32 fixed_rTC:1;	/* RTC wakeup stat not in fixed register space */
-	u32 rtcs4:1;		/* RTC wakeup stat not possible from S4 */
-	u32 tmr_val_ext:1;	/* tmr_val is 32 bits */
-	u32 dock_cap:1;		/* Supports Docking */
-	u32 reserved6:22;	/* reserved - must be zero */
-};
-
-#pragma pack()
-
-#endif				/* __ACTBL71_H__ */
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index 64b603c..72a6e2c 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,7 +48,8 @@
 
 /*
  * ACPI_MACHINE_WIDTH must be specified in an OS- or compiler-dependent header
- * and must be either 16, 32, or 64
+ * and must be either 32 or 64. 16-bit ACPICA is no longer supported, as of
+ * 12/2006.
  */
 #ifndef ACPI_MACHINE_WIDTH
 #error ACPI_MACHINE_WIDTH not defined
@@ -149,7 +150,6 @@
 typedef u64 acpi_native_uint;
 typedef s64 acpi_native_int;
 
-typedef u64 acpi_table_ptr;
 typedef u64 acpi_io_address;
 typedef u64 acpi_physical_address;
 
@@ -189,48 +189,15 @@
 typedef u32 acpi_native_uint;
 typedef s32 acpi_native_int;
 
-typedef u64 acpi_table_ptr;
 typedef u32 acpi_io_address;
-typedef u64 acpi_physical_address;
+typedef u32 acpi_physical_address;
 
 #define ACPI_MAX_PTR                    ACPI_UINT32_MAX
 #define ACPI_SIZE_MAX                   ACPI_UINT32_MAX
 
-/*******************************************************************************
- *
- * Types specific to 16-bit targets
- *
- ******************************************************************************/
-
-#elif ACPI_MACHINE_WIDTH == 16
-
-/*! [Begin] no source code translation (keep the typedefs as-is) */
-
-typedef unsigned long UINT32;
-typedef short INT16;
-typedef long INT32;
-
-/*! [End] no source code translation !*/
-
-typedef u16 acpi_native_uint;
-typedef s16 acpi_native_int;
-
-typedef u32 acpi_table_ptr;
-typedef u32 acpi_io_address;
-typedef char *acpi_physical_address;
-
-#define ACPI_MAX_PTR                    ACPI_UINT16_MAX
-#define ACPI_SIZE_MAX                   ACPI_UINT16_MAX
-
-#define ACPI_USE_NATIVE_DIVIDE	/* No 64-bit integers, ok to use native divide */
-
-/* 64-bit integers cannot be supported */
-
-#define ACPI_NO_INTEGER64_SUPPORT
-
 #else
 
-/* ACPI_MACHINE_WIDTH must be either 64, 32, or 16 */
+/* ACPI_MACHINE_WIDTH must be either 64 or 32 */
 
 #error unknown ACPI_MACHINE_WIDTH
 #endif
@@ -311,36 +278,6 @@
  *
  ******************************************************************************/
 
-/*
- * Pointer overlays to avoid lots of typecasting for
- * code that accepts both physical and logical pointers.
- */
-union acpi_pointers {
-	acpi_physical_address physical;
-	void *logical;
-	acpi_table_ptr value;
-};
-
-struct acpi_pointer {
-	u32 pointer_type;
-	union acpi_pointers pointer;
-};
-
-/* pointer_types for above */
-
-#define ACPI_PHYSICAL_POINTER           0x01
-#define ACPI_LOGICAL_POINTER            0x02
-
-/* Processor mode */
-
-#define ACPI_PHYSICAL_ADDRESSING        0x04
-#define ACPI_LOGICAL_ADDRESSING         0x08
-#define ACPI_MEMORY_MODE                0x0C
-
-#define ACPI_PHYSMODE_PHYSPTR           ACPI_PHYSICAL_ADDRESSING | ACPI_PHYSICAL_POINTER
-#define ACPI_LOGMODE_PHYSPTR            ACPI_LOGICAL_ADDRESSING  | ACPI_PHYSICAL_POINTER
-#define ACPI_LOGMODE_LOGPTR             ACPI_LOGICAL_ADDRESSING  | ACPI_LOGICAL_POINTER
-
 /* Logical defines and NULL */
 
 #ifdef FALSE
@@ -442,7 +379,8 @@
 /*
  * Initialization state
  */
-#define ACPI_INITIALIZED_OK             0x01
+#define ACPI_SUBSYSTEM_INITIALIZE       0x01
+#define ACPI_INITIALIZED_OK             0x02
 
 /*
  * Power state values
@@ -491,21 +429,6 @@
 #define ACPI_NOTIFY_POWER_FAULT         (u8) 7
 
 /*
- *  Table types.  These values are passed to the table related APIs
- */
-typedef u32 acpi_table_type;
-
-#define ACPI_TABLE_ID_RSDP              (acpi_table_type) 0
-#define ACPI_TABLE_ID_DSDT              (acpi_table_type) 1
-#define ACPI_TABLE_ID_FADT              (acpi_table_type) 2
-#define ACPI_TABLE_ID_FACS              (acpi_table_type) 3
-#define ACPI_TABLE_ID_PSDT              (acpi_table_type) 4
-#define ACPI_TABLE_ID_SSDT              (acpi_table_type) 5
-#define ACPI_TABLE_ID_XSDT              (acpi_table_type) 6
-#define ACPI_TABLE_ID_MAX               6
-#define ACPI_NUM_TABLE_TYPES            (ACPI_TABLE_ID_MAX+1)
-
-/*
  * Types associated with ACPI names and objects.  The first group of
  * values (up to ACPI_TYPE_EXTERNAL_MAX) correspond to the definition
  * of the ACPI object_type() operator (See the ACPI Spec). Therefore,
@@ -637,7 +560,7 @@
  *  | | |  +--- Type of dispatch -- to method, handler, or none
  *  | | +--- Enabled for runtime?
  *  | +--- Enabled for wake?
- *  +--- System state when GPE ocurred (running/waking)
+ *  +--- Unused
  */
 #define ACPI_GPE_XRUPT_TYPE_MASK        (u8) 0x01
 #define ACPI_GPE_LEVEL_TRIGGERED        (u8) 0x01
@@ -663,10 +586,6 @@
 
 #define ACPI_GPE_ENABLE_MASK            (u8) 0x60	/* Both run/wake */
 
-#define ACPI_GPE_SYSTEM_MASK            (u8) 0x80
-#define ACPI_GPE_SYSTEM_RUNNING         (u8) 0x80
-#define ACPI_GPE_SYSTEM_WAKING          (u8) 0x00
-
 /*
  * Flags for GPE and Lock interfaces
  */
@@ -816,13 +735,6 @@
 #define ACPI_SYS_MODES_MASK             0x0003
 
 /*
- * ACPI Table Info.  One per ACPI table _type_
- */
-struct acpi_table_info {
-	u32 count;
-};
-
-/*
  * System info returned by acpi_get_system_info()
  */
 struct acpi_system_info {
@@ -833,8 +745,6 @@
 	u32 reserved2;
 	u32 debug_level;
 	u32 debug_layer;
-	u32 num_table_types;
-	struct acpi_table_info table_info[ACPI_TABLE_ID_MAX + 1];
 };
 
 /*
diff --git a/include/acpi/acutils.h b/include/acpi/acutils.h
index ba039ea..883ffe9 100644
--- a/include/acpi/acutils.h
+++ b/include/acpi/acutils.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -141,8 +141,6 @@
 
 void acpi_ut_subsystem_shutdown(void);
 
-acpi_status acpi_ut_validate_fadt(void);
-
 /*
  * utclib - Local implementations of C library functions
  */
@@ -453,6 +451,8 @@
 /*
  * utmisc
  */
+const char *acpi_ut_validate_exception(acpi_status status);
+
 u8 acpi_ut_is_aml_table(struct acpi_table_header *table);
 
 acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id);
@@ -470,7 +470,7 @@
 
 u8 acpi_ut_valid_acpi_name(u32 name);
 
-acpi_name acpi_ut_repair_name(acpi_name name);
+acpi_name acpi_ut_repair_name(char *name);
 
 u8 acpi_ut_valid_acpi_char(char character, acpi_native_uint position);
 
diff --git a/include/acpi/amlcode.h b/include/acpi/amlcode.h
index cf18426..da53a4e 100644
--- a/include/acpi/amlcode.h
+++ b/include/acpi/amlcode.h
@@ -7,7 +7,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -273,7 +273,7 @@
 #define ARGI_DATAOBJECT             0x12	/* Buffer, String, package or reference to a Node - Used only by size_of operator */
 #define ARGI_COMPLEXOBJ             0x13	/* Buffer, String, or package (Used by INDEX op only) */
 #define ARGI_REF_OR_STRING          0x14	/* Reference or String (Used by DEREFOF op only) */
-#define ARGI_REGION_OR_FIELD        0x15	/* Used by LOAD op only */
+#define ARGI_REGION_OR_BUFFER       0x15	/* Used by LOAD op only */
 #define ARGI_DATAREFOBJ             0x16
 
 /* Note: types above can expand to 0x1F maximum */
diff --git a/include/acpi/amlresrc.h b/include/acpi/amlresrc.h
index be03818..f7d5412 100644
--- a/include/acpi/amlresrc.h
+++ b/include/acpi/amlresrc.h
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index 453a469..dab2ec5 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h
index da80933..3bb5049 100644
--- a/include/acpi/platform/acgcc.h
+++ b/include/acpi/platform/acgcc.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 7f1e929..5f532d2 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/include/asm-alpha/io.h b/include/asm-alpha/io.h
index 5d15af2..24bdcc8 100644
--- a/include/asm-alpha/io.h
+++ b/include/asm-alpha/io.h
@@ -525,15 +525,6 @@
 extern void outsl (unsigned long port, const void *src, unsigned long count);
 
 /*
- * XXX - We don't have csum_partial_copy_fromio() yet, so we cheat here and 
- * just copy it. The net code will then do the checksum later. Presently 
- * only used by some shared memory 8390 Ethernet cards anyway.
- */
-
-#define eth_io_copy_and_sum(skb,src,len,unused) \
-  memcpy_fromio((skb)->data,src,len)
-
-/*
  * The Alpha Jensen hardware for some rather strange reason puts
  * the RTC clock at 0x170 instead of 0x70. Probably due to some
  * misguided idea about using 0x70 for NMI stuff.
diff --git a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h
index 4e115f3..85aa112 100644
--- a/include/asm-alpha/pci.h
+++ b/include/asm-alpha/pci.h
@@ -293,4 +293,6 @@
 #define IOBASE_ROOT_BUS		5
 #define IOBASE_FROM_HOSE	0x10000
 
+extern struct pci_dev *isa_bridge;
+
 #endif /* __ALPHA_PCI_H */
diff --git a/include/asm-arm/arch-ixp4xx/io.h b/include/asm-arm/arch-ixp4xx/io.h
index 0d51726..b7b5414 100644
--- a/include/asm-arm/arch-ixp4xx/io.h
+++ b/include/asm-arm/arch-ixp4xx/io.h
@@ -238,9 +238,6 @@
 #define memcpy_fromio(a,c,l)		_memcpy_fromio((a),(c),(l))
 #define memcpy_toio(c,a,l)		_memcpy_toio((c),(a),(l))
 
-#define eth_io_copy_and_sum(s,c,l,b) \
-				eth_copy_and_sum((s),__mem_pci(c),(l),(b))
-
 static inline int
 check_signature(const unsigned char __iomem *bus_addr, const unsigned char *signature,
 		int length)
diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h
index 288f76b16..5f60b42 100644
--- a/include/asm-arm/io.h
+++ b/include/asm-arm/io.h
@@ -182,9 +182,6 @@
 #define memcpy_fromio(a,c,l)	_memcpy_fromio((a),__mem_pci(c),(l))
 #define memcpy_toio(c,a,l)	_memcpy_toio(__mem_pci(c),(a),(l))
 
-#define eth_io_copy_and_sum(s,c,l,b) \
-				eth_copy_and_sum((s),__mem_pci(c),(l),(b))
-
 #elif !defined(readb)
 
 #define readb(c)			(__readwrite_bug("readb"),0)
@@ -194,8 +191,6 @@
 #define writew(v,c)			__readwrite_bug("writew")
 #define writel(v,c)			__readwrite_bug("writel")
 
-#define eth_io_copy_and_sum(s,c,l,b)	__readwrite_bug("eth_io_copy_and_sum")
-
 #define check_signature(io,sig,len)	(0)
 
 #endif	/* __mem_pci */
diff --git a/include/asm-avr32/arch-at32ap/at32ap7000.h b/include/asm-avr32/arch-at32ap/at32ap7000.h
index ba85e04..3914d7b 100644
--- a/include/asm-avr32/arch-at32ap/at32ap7000.h
+++ b/include/asm-avr32/arch-at32ap/at32ap7000.h
@@ -24,10 +24,12 @@
 #define GPIO_PIOB_BASE	(GPIO_PIOA_BASE + 32)
 #define GPIO_PIOC_BASE	(GPIO_PIOB_BASE + 32)
 #define GPIO_PIOD_BASE	(GPIO_PIOC_BASE + 32)
+#define GPIO_PIOE_BASE	(GPIO_PIOD_BASE + 32)
 
 #define GPIO_PIN_PA(N)	(GPIO_PIOA_BASE + (N))
 #define GPIO_PIN_PB(N)	(GPIO_PIOB_BASE + (N))
 #define GPIO_PIN_PC(N)	(GPIO_PIOC_BASE + (N))
 #define GPIO_PIN_PD(N)	(GPIO_PIOD_BASE + (N))
+#define GPIO_PIN_PE(N)	(GPIO_PIOE_BASE + (N))
 
 #endif /* __ASM_ARCH_AT32AP7000_H__ */
diff --git a/include/asm-avr32/arch-at32ap/gpio.h b/include/asm-avr32/arch-at32ap/gpio.h
new file mode 100644
index 0000000..fcb756b
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/gpio.h
@@ -0,0 +1,27 @@
+#ifndef __ASM_AVR32_ARCH_GPIO_H
+#define __ASM_AVR32_ARCH_GPIO_H
+
+#include <linux/compiler.h>
+#include <asm/irq.h>
+
+
+/* Arch-neutral GPIO API */
+int __must_check gpio_request(unsigned int gpio, const char *label);
+void gpio_free(unsigned int gpio);
+
+int gpio_direction_input(unsigned int gpio);
+int gpio_direction_output(unsigned int gpio);
+int gpio_get_value(unsigned int gpio);
+void gpio_set_value(unsigned int gpio, int value);
+
+static inline int gpio_to_irq(unsigned int gpio)
+{
+	return gpio + GPIO_IRQ_BASE;
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+	return irq - GPIO_IRQ_BASE;
+}
+
+#endif /* __ASM_AVR32_ARCH_GPIO_H */
diff --git a/include/asm-avr32/arch-at32ap/irq.h b/include/asm-avr32/arch-at32ap/irq.h
new file mode 100644
index 0000000..5adffab
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/irq.h
@@ -0,0 +1,14 @@
+#ifndef __ASM_AVR32_ARCH_IRQ_H
+#define __ASM_AVR32_ARCH_IRQ_H
+
+#define EIM_IRQ_BASE	NR_INTERNAL_IRQS
+#define NR_EIM_IRQS	32
+
+#define AT32_EXTINT(n)	(EIM_IRQ_BASE + (n))
+
+#define GPIO_IRQ_BASE	(EIM_IRQ_BASE + NR_EIM_IRQS)
+#define NR_GPIO_IRQS	(5 * 32)
+
+#define NR_IRQS		(GPIO_IRQ_BASE + NR_GPIO_IRQS)
+
+#endif /* __ASM_AVR32_ARCH_IRQ_H */
diff --git a/include/asm-avr32/arch-at32ap/portmux.h b/include/asm-avr32/arch-at32ap/portmux.h
index 83c6905..9930871 100644
--- a/include/asm-avr32/arch-at32ap/portmux.h
+++ b/include/asm-avr32/arch-at32ap/portmux.h
@@ -15,12 +15,14 @@
  *
  * The following flags determine the initial state of the pin.
  */
-#define AT32_GPIOF_PULLUP	0x00000001	/* Enable pull-up */
-#define AT32_GPIOF_OUTPUT	0x00000002	/* Enable output driver */
-#define AT32_GPIOF_HIGH		0x00000004	/* Set output high */
+#define AT32_GPIOF_PULLUP	0x00000001	/* (not-OUT) Enable pull-up */
+#define AT32_GPIOF_OUTPUT	0x00000002	/* (OUT) Enable output driver */
+#define AT32_GPIOF_HIGH		0x00000004	/* (OUT) Set output high */
+#define AT32_GPIOF_DEGLITCH	0x00000008	/* (IN) Filter glitches */
 
 void at32_select_periph(unsigned int pin, unsigned int periph,
 			unsigned long flags);
 void at32_select_gpio(unsigned int pin, unsigned long flags);
+void at32_reserve_pin(unsigned int pin);
 
 #endif /* __ASM_ARCH_PORTMUX_H__ */
diff --git a/include/asm-avr32/checksum.h b/include/asm-avr32/checksum.h
index af9d53f..4ddbfd2 100644
--- a/include/asm-avr32/checksum.h
+++ b/include/asm-avr32/checksum.h
@@ -38,7 +38,7 @@
  *	passed in an incorrect kernel address to one of these functions.
  *
  *	If you use these functions directly please don't forget the
- *	verify_area().
+ *	access_ok().
  */
 static inline
 __wsum csum_partial_copy_nocheck(const void *src, void *dst,
diff --git a/include/asm-avr32/dma-mapping.h b/include/asm-avr32/dma-mapping.h
index 5c01e27..115813e 100644
--- a/include/asm-avr32/dma-mapping.h
+++ b/include/asm-avr32/dma-mapping.h
@@ -32,6 +32,14 @@
 	return 0;
 }
 
+/*
+ * dma_map_single can't fail as it is implemented now.
+ */
+static inline int dma_mapping_error(dma_addr_t addr)
+{
+	return 0;
+}
+
 /**
  * dma_alloc_coherent - allocate consistent memory for DMA
  * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
diff --git a/include/asm-avr32/gpio.h b/include/asm-avr32/gpio.h
new file mode 100644
index 0000000..19e8ccc
--- /dev/null
+++ b/include/asm-avr32/gpio.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_AVR32_GPIO_H
+#define __ASM_AVR32_GPIO_H
+
+#include <asm/arch/gpio.h>
+
+#endif /* __ASM_AVR32_GPIO_H */
diff --git a/include/asm-avr32/irq.h b/include/asm-avr32/irq.h
index f7e7257..83e6549 100644
--- a/include/asm-avr32/irq.h
+++ b/include/asm-avr32/irq.h
@@ -2,8 +2,12 @@
 #define __ASM_AVR32_IRQ_H
 
 #define NR_INTERNAL_IRQS	64
-#define NR_EXTERNAL_IRQS	64
-#define NR_IRQS			(NR_INTERNAL_IRQS + NR_EXTERNAL_IRQS)
+
+#include <asm/arch/irq.h>
+
+#ifndef NR_IRQS
+#define NR_IRQS			(NR_INTERNAL_IRQS)
+#endif
 
 #define irq_canonicalize(i)	(i)
 
diff --git a/include/asm-avr32/posix_types.h b/include/asm-avr32/posix_types.h
index 2831b03..9e255b9 100644
--- a/include/asm-avr32/posix_types.h
+++ b/include/asm-avr32/posix_types.h
@@ -23,7 +23,7 @@
 typedef unsigned int	__kernel_uid_t;
 typedef unsigned int	__kernel_gid_t;
 typedef unsigned long	__kernel_size_t;
-typedef int             __kernel_ssize_t;
+typedef long		__kernel_ssize_t;
 typedef int             __kernel_ptrdiff_t;
 typedef long            __kernel_time_t;
 typedef long            __kernel_suseconds_t;
diff --git a/include/asm-avr32/uaccess.h b/include/asm-avr32/uaccess.h
index 821deb5..74a679e9 100644
--- a/include/asm-avr32/uaccess.h
+++ b/include/asm-avr32/uaccess.h
@@ -68,12 +68,6 @@
 
 #define access_ok(type, addr, size) (likely(__range_ok(addr, size) == 0))
 
-static inline int
-verify_area(int type, const void __user *addr, unsigned long size)
-{
-	return access_ok(type, addr, size) ? 0 : -EFAULT;
-}
-
 /* Generic arbitrary sized copy. Return the number of bytes NOT copied */
 extern __kernel_size_t __copy_user(void *to, const void *from,
 				   __kernel_size_t n);
diff --git a/include/asm-cris/io.h b/include/asm-cris/io.h
index 716c69b..d196dd6 100644
--- a/include/asm-cris/io.h
+++ b/include/asm-cris/io.h
@@ -121,11 +121,6 @@
 #define memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
 #define memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
 
-/*
- * Again, CRIS does not require mem IO specific function.
- */
-
-#define eth_io_copy_and_sum(a,b,c,d)	eth_copy_and_sum((a),(void __force *)(b),(c),(d))
 
 /* The following is junk needed for the arch-independent code but which
  * we never use in the CRIS port
diff --git a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h
index 7cfad93..5e657eb 100644
--- a/include/asm-i386/acpi.h
+++ b/include/asm-i386/acpi.h
@@ -39,7 +39,7 @@
  * Calling conventions:
  *
  * ACPI_SYSTEM_XFACE        - Interfaces to host OS (handlers, threads)
- * ACPI_EXTERNAL_XFACE      - External ACPI interfaces 
+ * ACPI_EXTERNAL_XFACE      - External ACPI interfaces
  * ACPI_INTERNAL_XFACE      - Internal ACPI interfaces
  * ACPI_INTERNAL_VAR_XFACE  - Internal variable-parameter list interfaces
  */
@@ -59,11 +59,11 @@
 int __acpi_acquire_global_lock(unsigned int *lock);
 int __acpi_release_global_lock(unsigned int *lock);
 
-#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
-	((Acq) = __acpi_acquire_global_lock((unsigned int *) GLptr))
+#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
+	((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
 
-#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \
-	((Acq) = __acpi_release_global_lock((unsigned int *) GLptr))
+#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \
+	((Acq) = __acpi_release_global_lock(&facs->global_lock))
 
 /*
  * Math helper asm macros
@@ -87,7 +87,7 @@
 static inline void check_acpi_pci(void) { }
 #endif
 
-#ifdef CONFIG_ACPI 
+#ifdef CONFIG_ACPI
 extern int acpi_lapic;
 extern int acpi_ioapic;
 extern int acpi_noirq;
@@ -95,9 +95,9 @@
 extern int acpi_disabled;
 extern int acpi_ht;
 extern int acpi_pci_disabled;
-static inline void disable_acpi(void) 
-{ 
-	acpi_disabled = 1; 
+static inline void disable_acpi(void)
+{
+	acpi_disabled = 1;
 	acpi_ht = 0;
 	acpi_pci_disabled = 1;
 	acpi_noirq = 1;
@@ -114,9 +114,9 @@
 #endif
 
 static inline void acpi_noirq_set(void) { acpi_noirq = 1; }
-static inline void acpi_disable_pci(void) 
+static inline void acpi_disable_pci(void)
 {
-	acpi_pci_disabled = 1; 
+	acpi_pci_disabled = 1;
 	acpi_noirq_set();
 }
 extern int acpi_irq_balance_set(char *str);
@@ -144,8 +144,6 @@
 
 #endif /*CONFIG_ACPI_SLEEP*/
 
-extern u8 x86_acpiid_to_apicid[];
-
 #define ARCH_HAS_POWER_INIT	1
 
 #endif /*__KERNEL__*/
diff --git a/include/asm-i386/io.h b/include/asm-i386/io.h
index 86ff5e8..59fe616 100644
--- a/include/asm-i386/io.h
+++ b/include/asm-i386/io.h
@@ -219,12 +219,6 @@
 #define __ISA_IO_base ((char __iomem *)(PAGE_OFFSET))
 
 /*
- * Again, i386 does not require mem IO specific function.
- */
-
-#define eth_io_copy_and_sum(a,b,c,d)		eth_copy_and_sum((a),(void __force *)(b),(c),(d))
-
-/*
  *	Cache management
  *
  *	This needed for two cases
diff --git a/include/asm-i386/mach-es7000/mach_mpparse.h b/include/asm-i386/mach-es7000/mach_mpparse.h
index 99f66be..24990e5 100644
--- a/include/asm-i386/mach-es7000/mach_mpparse.h
+++ b/include/asm-i386/mach-es7000/mach_mpparse.h
@@ -3,13 +3,13 @@
 
 #include <linux/acpi.h>
 
-static inline void mpc_oem_bus_info(struct mpc_config_bus *m, char *name, 
+static inline void mpc_oem_bus_info(struct mpc_config_bus *m, char *name,
 				struct mpc_config_translation *translation)
 {
 	Dprintk("Bus #%d is %s\n", m->mpc_busid, name);
 }
 
-static inline void mpc_oem_pci_bus(struct mpc_config_bus *m, 
+static inline void mpc_oem_pci_bus(struct mpc_config_bus *m,
 				struct mpc_config_translation *translation)
 {
 }
@@ -22,7 +22,7 @@
 		char *productid)
 {
 	if (mpc->mpc_oemptr) {
-		struct mp_config_oemtable *oem_table = 
+		struct mp_config_oemtable *oem_table =
 			(struct mp_config_oemtable *)mpc->mpc_oemptr;
 		if (!strncmp(oem, "UNISYS", 6))
 			return parse_unisys_oem((char *)oem_table);
@@ -31,12 +31,13 @@
 }
 
 #ifdef CONFIG_ACPI
+
 static inline int es7000_check_dsdt(void)
 {
-	struct acpi_table_header *header = NULL;
-	if(!acpi_get_table_header_early(ACPI_DSDT, &header))
-		acpi_table_print(header, 0);
-	if (!strncmp(header->oem_id, "UNISYS", 6))
+	struct acpi_table_header header;
+	memcpy(&header, 0, sizeof(struct acpi_table_header));
+	acpi_get_table_header(ACPI_SIG_DSDT, 0, &header);
+	if (!strncmp(header.oem_id, "UNISYS", 6))
 		return 1;
 	return 0;
 }
@@ -44,7 +45,7 @@
 /* Hook from generic ACPI tables.c */
 static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 {
-	unsigned long oem_addr; 
+	unsigned long oem_addr;
 	if (!find_unisys_acpi_oem_table(&oem_addr)) {
 		if (es7000_check_dsdt())
 			return parse_unisys_oem((char *)oem_addr);
diff --git a/include/asm-ia64/acpi.h b/include/asm-ia64/acpi.h
index 09a5dd0..5d03792 100644
--- a/include/asm-ia64/acpi.h
+++ b/include/asm-ia64/acpi.h
@@ -82,11 +82,11 @@
 	return old & 0x1;
 }
 
-#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq)				\
-	((Acq) = ia64_acpi_acquire_global_lock((unsigned int *) GLptr))
+#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq)				\
+	((Acq) = ia64_acpi_acquire_global_lock(&facs->global_lock))
 
-#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq)				\
-	((Acq) = ia64_acpi_release_global_lock((unsigned int *) GLptr))
+#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq)				\
+	((Acq) = ia64_acpi_release_global_lock(&facs->global_lock))
 
 #define acpi_disabled 0	/* ACPI always enabled on IA64 */
 #define acpi_noirq 0	/* ACPI always enabled on IA64 */
@@ -119,8 +119,6 @@
 extern int __initdata nid_to_pxm_map[MAX_NUMNODES];
 #endif
 
-extern u16 ia64_acpiid_to_sapicid[];
-
 /*
  * Refer Intel ACPI _PDC support document for bit definitions
  */
diff --git a/include/asm-ia64/dma.h b/include/asm-ia64/dma.h
index dad3a73..4d97f60 100644
--- a/include/asm-ia64/dma.h
+++ b/include/asm-ia64/dma.h
@@ -19,4 +19,6 @@
 
 #define free_dma(x)
 
+void dma_mark_clean(void *addr, size_t size);
+
 #endif /* _ASM_IA64_DMA_H */
diff --git a/include/asm-ia64/esi.h b/include/asm-ia64/esi.h
index 84aac0e..40991c6 100644
--- a/include/asm-ia64/esi.h
+++ b/include/asm-ia64/esi.h
@@ -19,7 +19,6 @@
 	ESI_PROC_REENTRANT	/* MP-safe and reentrant */
 };
 
-extern int ia64_esi_init (void);
 extern struct ia64_sal_retval esi_call_phys (void *, u64 *);
 extern int ia64_esi_call(efi_guid_t, struct ia64_sal_retval *,
 			 enum esi_proc_type,
diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h
index a3891eb..3c96ac1 100644
--- a/include/asm-ia64/machvec.h
+++ b/include/asm-ia64/machvec.h
@@ -21,6 +21,7 @@
 struct pci_bus;
 struct task_struct;
 struct pci_dev;
+struct msi_desc;
 
 typedef void ia64_mv_setup_t (char **);
 typedef void ia64_mv_cpu_init_t (void);
@@ -79,7 +80,7 @@
 typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
 typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
 
-typedef int ia64_mv_setup_msi_irq_t (unsigned int irq, struct pci_dev *pdev);
+typedef int ia64_mv_setup_msi_irq_t (struct pci_dev *pdev, struct msi_desc *);
 typedef void ia64_mv_teardown_msi_irq_t (unsigned int irq);
 
 static inline void
diff --git a/include/asm-ia64/meminit.h b/include/asm-ia64/meminit.h
index c8df759..6dd476b 100644
--- a/include/asm-ia64/meminit.h
+++ b/include/asm-ia64/meminit.h
@@ -51,12 +51,13 @@
 
 #define IGNORE_PFN0	1	/* XXX fix me: ignore pfn 0 until TLB miss handler is updated... */
 
+extern int register_active_ranges(u64 start, u64 end, void *arg);
+
 #ifdef CONFIG_VIRTUAL_MEM_MAP
 # define LARGE_GAP	0x40000000 /* Use virtual mem map if hole is > than this */
   extern unsigned long vmalloc_end;
   extern struct page *vmem_map;
   extern int find_largest_hole (u64 start, u64 end, void *arg);
-  extern int register_active_ranges (u64 start, u64 end, void *arg);
   extern int create_mem_map_page_table (u64 start, u64 end, void *arg);
   extern int vmemmap_find_next_valid_pfn(int, int);
 #else
diff --git a/include/asm-ia64/pgalloc.h b/include/asm-ia64/pgalloc.h
index 393e04c..560c287 100644
--- a/include/asm-ia64/pgalloc.h
+++ b/include/asm-ia64/pgalloc.h
@@ -137,7 +137,8 @@
 static inline struct page *pte_alloc_one(struct mm_struct *mm,
 					 unsigned long addr)
 {
-	return virt_to_page(pgtable_quicklist_alloc());
+	void *pg = pgtable_quicklist_alloc();
+	return pg ? virt_to_page(pg) : NULL;
 }
 
 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
diff --git a/include/asm-ia64/sn/acpi.h b/include/asm-ia64/sn/acpi.h
index 2850a7e..9ce2801 100644
--- a/include/asm-ia64/sn/acpi.h
+++ b/include/asm-ia64/sn/acpi.h
@@ -11,6 +11,7 @@
 
 #include "acpi/acglobal.h"
 
-#define SN_ACPI_BASE_SUPPORT()   (acpi_gbl_DSDT->oem_revision >= 0x20101)
+extern int sn_acpi_rev;
+#define SN_ACPI_BASE_SUPPORT()   (sn_acpi_rev >= 0x20101)
 
 #endif /* _ASM_IA64_SN_ACPI_H */
diff --git a/include/asm-ia64/sn/pcibr_provider.h b/include/asm-ia64/sn/pcibr_provider.h
index da3eade..17cb6cc 100644
--- a/include/asm-ia64/sn/pcibr_provider.h
+++ b/include/asm-ia64/sn/pcibr_provider.h
@@ -142,7 +142,7 @@
 extern void 		pcibr_ate_free(struct pcibus_info *, int);
 extern void 		ate_write(struct pcibus_info *, int, int, u64);
 extern int sal_pcibr_slot_enable(struct pcibus_info *soft, int device,
-				 void *resp);
+				 void *resp, char **ssdt);
 extern int sal_pcibr_slot_disable(struct pcibus_info *soft, int device,
 				  int action, void *resp);
 extern u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus);
diff --git a/include/asm-ia64/sn/pcidev.h b/include/asm-ia64/sn/pcidev.h
index 9fe89a9..1c2382c 100644
--- a/include/asm-ia64/sn/pcidev.h
+++ b/include/asm-ia64/sn/pcidev.h
@@ -70,10 +70,16 @@
 			 struct sn_irq_info *sn_irq_info);
 extern void sn_irq_unfixup(struct pci_dev *pci_dev);
 extern struct pcidev_info * sn_pcidev_info_get(struct pci_dev *);
+extern void sn_bus_fixup(struct pci_bus *);
+extern void sn_acpi_bus_fixup(struct pci_bus *);
+extern void sn_common_bus_fixup(struct pci_bus *, struct pcibus_bussoft *);
 extern void sn_bus_store_sysdata(struct pci_dev *dev);
 extern void sn_bus_free_sysdata(void);
 extern void sn_generate_path(struct pci_bus *pci_bus, char *address);
-extern void sn_pci_fixup_slot(struct pci_dev *dev);
+extern void sn_io_slot_fixup(struct pci_dev *);
+extern void sn_acpi_slot_fixup(struct pci_dev *);
+extern void sn_pci_fixup_slot(struct pci_dev *dev, struct pcidev_info *,
+			      struct sn_irq_info *);
 extern void sn_pci_unfixup_slot(struct pci_dev *dev);
 extern void sn_irq_lh_init(void);
 #endif				/* _ASM_IA64_SN_PCI_PCIDEV_H */
diff --git a/include/asm-ia64/swiotlb.h b/include/asm-ia64/swiotlb.h
new file mode 100644
index 0000000..452c162
--- /dev/null
+++ b/include/asm-ia64/swiotlb.h
@@ -0,0 +1,9 @@
+#ifndef _ASM_SWIOTLB_H
+#define _ASM_SWIOTLB_H 1
+
+#include <asm/machvec.h>
+
+#define SWIOTLB_ARCH_NEED_LATE_INIT
+#define SWIOTLB_ARCH_NEED_ALLOC
+
+#endif /* _ASM_SWIOTLB_H */
diff --git a/include/asm-ia64/thread_info.h b/include/asm-ia64/thread_info.h
index 9b505b2..9169859 100644
--- a/include/asm-ia64/thread_info.h
+++ b/include/asm-ia64/thread_info.h
@@ -84,6 +84,7 @@
 #define TIF_NEED_RESCHED	2	/* rescheduling necessary */
 #define TIF_SYSCALL_TRACE	3	/* syscall trace active */
 #define TIF_SYSCALL_AUDIT	4	/* syscall auditing active */
+#define TIF_SINGLESTEP		5	/* restore singlestep on return to user mode */
 #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		17
 #define TIF_MCA_INIT		18	/* this task is processing MCA or INIT */
@@ -92,7 +93,8 @@
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
-#define _TIF_SYSCALL_TRACEAUDIT	(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+#define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
+#define _TIF_SYSCALL_TRACEAUDIT	(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h
index 53c5c0e..a9e1fa4 100644
--- a/include/asm-ia64/unistd.h
+++ b/include/asm-ia64/unistd.h
@@ -291,11 +291,13 @@
 #define __NR_sync_file_range		1300
 #define __NR_tee			1301
 #define __NR_vmsplice			1302
+/* 1303 reserved for move_pages */
+#define __NR_getcpu			1304
 
 #ifdef __KERNEL__
 
 
-#define NR_syscalls			279 /* length of syscall table */
+#define NR_syscalls			281 /* length of syscall table */
 
 #define __ARCH_WANT_SYS_RT_SIGACTION
 
diff --git a/include/asm-m68knommu/bitops.h b/include/asm-m68knommu/bitops.h
index d7fa7d9..7d6075d 100644
--- a/include/asm-m68knommu/bitops.h
+++ b/include/asm-m68knommu/bitops.h
@@ -7,7 +7,6 @@
 
 #include <linux/compiler.h>
 #include <asm/byteorder.h>	/* swab32 */
-#include <asm/system.h>		/* save_flags */
 
 #ifdef __KERNEL__
 
diff --git a/include/asm-mips/apm.h b/include/asm-mips/apm.h
deleted file mode 100644
index 4b99ffc..0000000
--- a/include/asm-mips/apm.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* -*- linux-c -*-
- *
- * (C) 2003 zecke@handhelds.org
- *
- * GPL version 2
- *
- * based on arch/arm/kernel/apm.c
- * factor out the information needed by architectures to provide
- * apm status
- *
- *
- */
-#ifndef MIPS_ASM_SA1100_APM_H
-#define MIPS_ASM_SA1100_APM_H
-
-#include <linux/apm_bios.h>
-
-/*
- * This structure gets filled in by the machine specific 'get_power_status'
- * implementation.  Any fields which are not set default to a safe value.
- */
-struct apm_power_info {
-	unsigned char	ac_line_status;
-#define APM_AC_OFFLINE			0
-#define APM_AC_ONLINE			1
-#define APM_AC_BACKUP			2
-#define APM_AC_UNKNOWN			0xff
-
-	unsigned char	battery_status;
-#define APM_BATTERY_STATUS_HIGH		0
-#define APM_BATTERY_STATUS_LOW		1
-#define APM_BATTERY_STATUS_CRITICAL	2
-#define APM_BATTERY_STATUS_CHARGING	3
-#define APM_BATTERY_STATUS_NOT_PRESENT	4
-#define APM_BATTERY_STATUS_UNKNOWN	0xff
-
-	unsigned char	battery_flag;
-#define APM_BATTERY_FLAG_HIGH		(1 << 0)
-#define APM_BATTERY_FLAG_LOW		(1 << 1)
-#define APM_BATTERY_FLAG_CRITICAL	(1 << 2)
-#define APM_BATTERY_FLAG_CHARGING	(1 << 3)
-#define APM_BATTERY_FLAG_NOT_PRESENT	(1 << 7)
-#define APM_BATTERY_FLAG_UNKNOWN	0xff
-
-	int		battery_life;
-	int		time;
-	int		units;
-#define APM_UNITS_MINS			0
-#define APM_UNITS_SECS			1
-#define APM_UNITS_UNKNOWN		-1
-
-};
-
-/*
- * This allows machines to provide their own "apm get power status" function.
- */
-extern void (*apm_get_power_status)(struct apm_power_info *);
-
-/*
- * Queue an event (APM_SYS_SUSPEND or APM_CRITICAL_SUSPEND)
- */
-void apm_queue_event(apm_event_t event);
-
-#endif
diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h
index 8e321f5..c7c945b 100644
--- a/include/asm-mips/bootinfo.h
+++ b/include/asm-mips/bootinfo.h
@@ -243,6 +243,10 @@
 extern void add_memory_region(phys_t start, phys_t size, long type);
 
 extern void prom_init(void);
+extern void prom_free_prom_memory(void);
+
+extern void free_init_pages(const char *what,
+			    unsigned long begin, unsigned long end);
 
 /*
  * Initial kernel command line, usually setup by prom_init()
diff --git a/include/asm-mips/ddb5xxx/ddb5477.h b/include/asm-mips/ddb5xxx/ddb5477.h
index c5af4b7..6cf177c 100644
--- a/include/asm-mips/ddb5xxx/ddb5477.h
+++ b/include/asm-mips/ddb5xxx/ddb5477.h
@@ -17,6 +17,7 @@
 #ifndef __ASM_DDB5XXX_DDB5477_H
 #define __ASM_DDB5XXX_DDB5477_H
 
+#include <irq.h>
 
 /*
  * This contains macros that are specific to DDB5477 or renamed from
@@ -251,14 +252,10 @@
  */
 
 #define	NUM_CPU_IRQ		8
-#define	NUM_I8259_IRQ		16
 #define	NUM_VRC5477_IRQ		32
 
-#define	DDB_IRQ_BASE		0
-
-#define	I8259_IRQ_BASE		DDB_IRQ_BASE
-#define	VRC5477_IRQ_BASE	(I8259_IRQ_BASE + NUM_I8259_IRQ)
-#define	CPU_IRQ_BASE		(VRC5477_IRQ_BASE + NUM_VRC5477_IRQ)
+#define	CPU_IRQ_BASE		MIPS_CPU_IRQ_BASE
+#define	VRC5477_IRQ_BASE	(CPU_IRQ_BASE + NUM_CPU_IRQ)
 
 /*
  * vrc5477 irq defs
@@ -300,22 +297,22 @@
 /*
  * i2859 irq assignment
  */
-#define I8259_IRQ_RESERVED_0	(0 + I8259_IRQ_BASE)
-#define I8259_IRQ_KEYBOARD	(1 + I8259_IRQ_BASE)	/* M1543 default */
-#define I8259_IRQ_CASCADE	(2 + I8259_IRQ_BASE)
-#define I8259_IRQ_UART_B	(3 + I8259_IRQ_BASE)	/* M1543 default, may conflict with RTC according to schematic diagram  */
-#define I8259_IRQ_UART_A	(4 + I8259_IRQ_BASE)	/* M1543 default */
-#define I8259_IRQ_PARALLEL	(5 + I8259_IRQ_BASE)	/* M1543 default */
-#define I8259_IRQ_RESERVED_6	(6 + I8259_IRQ_BASE)
-#define I8259_IRQ_RESERVED_7	(7 + I8259_IRQ_BASE)
-#define I8259_IRQ_RTC		(8 + I8259_IRQ_BASE)	/* who set this? */
-#define I8259_IRQ_USB		(9 + I8259_IRQ_BASE)	/* ddb_setup */
-#define I8259_IRQ_PMU		(10 + I8259_IRQ_BASE)	/* ddb_setup */
-#define I8259_IRQ_RESERVED_11	(11 + I8259_IRQ_BASE)
-#define I8259_IRQ_RESERVED_12	(12 + I8259_IRQ_BASE)	/* m1543_irq_setup */
-#define I8259_IRQ_RESERVED_13	(13 + I8259_IRQ_BASE)
-#define I8259_IRQ_HDC1		(14 + I8259_IRQ_BASE)	/* default and ddb_setup */
-#define I8259_IRQ_HDC2		(15 + I8259_IRQ_BASE)	/* default */
+#define I8259_IRQ_RESERVED_0	(0 + I8259A_IRQ_BASE)
+#define I8259_IRQ_KEYBOARD	(1 + I8259A_IRQ_BASE)	/* M1543 default */
+#define I8259_IRQ_CASCADE	(2 + I8259A_IRQ_BASE)
+#define I8259_IRQ_UART_B	(3 + I8259A_IRQ_BASE)	/* M1543 default, may conflict with RTC according to schematic diagram  */
+#define I8259_IRQ_UART_A	(4 + I8259A_IRQ_BASE)	/* M1543 default */
+#define I8259_IRQ_PARALLEL	(5 + I8259A_IRQ_BASE)	/* M1543 default */
+#define I8259_IRQ_RESERVED_6	(6 + I8259A_IRQ_BASE)
+#define I8259_IRQ_RESERVED_7	(7 + I8259A_IRQ_BASE)
+#define I8259_IRQ_RTC		(8 + I8259A_IRQ_BASE)	/* who set this? */
+#define I8259_IRQ_USB		(9 + I8259A_IRQ_BASE)	/* ddb_setup */
+#define I8259_IRQ_PMU		(10 + I8259A_IRQ_BASE)	/* ddb_setup */
+#define I8259_IRQ_RESERVED_11	(11 + I8259A_IRQ_BASE)
+#define I8259_IRQ_RESERVED_12	(12 + I8259A_IRQ_BASE)	/* m1543_irq_setup */
+#define I8259_IRQ_RESERVED_13	(13 + I8259A_IRQ_BASE)
+#define I8259_IRQ_HDC1		(14 + I8259A_IRQ_BASE)	/* default and ddb_setup */
+#define I8259_IRQ_HDC2		(15 + I8259A_IRQ_BASE)	/* default */
 
 
 /*
diff --git a/include/asm-mips/dec/interrupts.h b/include/asm-mips/dec/interrupts.h
index 273e4d6..e10d341 100644
--- a/include/asm-mips/dec/interrupts.h
+++ b/include/asm-mips/dec/interrupts.h
@@ -14,6 +14,7 @@
 #ifndef __ASM_DEC_INTERRUPTS_H
 #define __ASM_DEC_INTERRUPTS_H
 
+#include <irq.h>
 #include <asm/mipsregs.h>
 
 
@@ -87,7 +88,7 @@
 #define DEC_CPU_INR_SW1		1	/* software #1 */
 #define DEC_CPU_INR_SW0		0	/* software #0 */
 
-#define DEC_CPU_IRQ_BASE	0	/* first IRQ assigned to CPU */
+#define DEC_CPU_IRQ_BASE	MIPS_CPU_IRQ_BASE	/* first IRQ assigned to CPU */
 
 #define DEC_CPU_IRQ_NR(n)	((n) + DEC_CPU_IRQ_BASE)
 #define DEC_CPU_IRQ_MASK(n)	(1 << ((n) + CAUSEB_IP))
diff --git a/include/asm-mips/dec/system.h b/include/asm-mips/dec/system.h
index 78af51f..b2afacc 100644
--- a/include/asm-mips/dec/system.h
+++ b/include/asm-mips/dec/system.h
@@ -3,7 +3,7 @@
  *
  *	Generic DECstation/DECsystem bits.
  *
- *	Copyright (C) 2005  Maciej W. Rozycki
+ *	Copyright (C) 2005, 2006  Maciej W. Rozycki
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -14,5 +14,6 @@
 #define __ASM_DEC_SYSTEM_H
 
 extern unsigned long dec_kn_slot_base, dec_kn_slot_size;
+extern int dec_tc_bus;
 
 #endif /* __ASM_DEC_SYSTEM_H */
diff --git a/include/asm-mips/dec/tc.h b/include/asm-mips/dec/tc.h
deleted file mode 100644
index 9cb51f2..0000000
--- a/include/asm-mips/dec/tc.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Interface to the TURBOchannel related routines
- *
- * 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.
- *
- * Copyright (c) 1998 Harald Koerfgen
- */
-#ifndef __ASM_DEC_TC_H
-#define __ASM_DEC_TC_H
-
-/*
- * Search for a TURBOchannel Option Module
- * with a certain name. Returns slot number
- * of the first card not in use or -ENODEV
- * if none found.
- */
-extern int search_tc_card(const char *);
-/*
- * Marks the card in slot as used
- */
-extern void claim_tc_card(int);
-/*
- * Marks the card in slot as free
- */
-extern void release_tc_card(int);
-/*
- * Return base address of card in slot
- */
-extern unsigned long get_tc_base_addr(int);
-/*
- * Return interrupt number of slot
- */
-extern unsigned long get_tc_irq_nr(int);
-/*
- * Return TURBOchannel clock frequency in Hz
- */
-extern unsigned long get_tc_speed(void);
-
-#endif /* __ASM_DEC_TC_H */
diff --git a/include/asm-mips/dec/tcinfo.h b/include/asm-mips/dec/tcinfo.h
deleted file mode 100644
index cc23509..0000000
--- a/include/asm-mips/dec/tcinfo.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Various TURBOchannel related stuff
- *
- * 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.
- *
- * Information obtained through the get_tcinfo prom call
- * created from:
- *
- * TURBOchannel Firmware Specification
- *
- * EK-TCAAD-FS-004
- * from Digital Equipment Corporation
- *
- * Copyright (c) 1998 Harald Koerfgen
- */
-
-typedef struct {
-	int revision;
-	int clk_period;
-	int slot_size;
-	int io_timeout;
-	int dma_range;
-	int max_dma_burst;
-	int parity;
-	int reserved[4];
-} tcinfo;
-
-#define MAX_SLOT 7
-
-typedef struct {
-	unsigned long base_addr;
-	unsigned char name[9];
-	unsigned char vendor[9];
-	unsigned char firmware[9];
-	int interrupt;
-	int flags;
-} slot_info;
-
-/*
- * Values for flags
- */
-#define FREE 	1<<0
-#define IN_USE	1<<1
-
-
diff --git a/include/asm-mips/dec/tcmodule.h b/include/asm-mips/dec/tcmodule.h
deleted file mode 100644
index 6268e89..0000000
--- a/include/asm-mips/dec/tcmodule.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- *
- * Offsets for the ROM header locations for
- * TURBOchannel cards
- *
- * created from:
- *
- * TURBOchannel Firmware Specification
- *
- * EK-TCAAD-FS-004
- * from Digital Equipment Corporation
- *
- * Jan.1998 Harald Koerfgen
- */
-#ifndef __ASM_DEC_TCMODULE_H
-#define __ASM_DEC_TCMODULE_H
-
-#define OLDCARD 0x3c0000
-#define NEWCARD 0x000000
-
-#define TC_ROM_WIDTH	0x3e0
-#define TC_ROM_STRIDE	0x3e4
-#define TC_ROM_SIZE	0x3e8
-#define TC_SLOT_SIZE	0x3ec
-#define TC_PATTERN0	0x3f0
-#define TC_PATTERN1	0x3f4
-#define TC_PATTERN2	0x3f8
-#define TC_PATTERN3	0x3fc
-#define TC_FIRM_VER	0x400
-#define TC_VENDOR	0x420
-#define TC_MODULE	0x440
-#define TC_FIRM_TYPE	0x460
-#define TC_FLAGS	0x470
-#define TC_ROM_OBJECTS	0x480
-
-#endif /* __ASM_DEC_TCMODULE_H */
diff --git a/include/asm-mips/dma.h b/include/asm-mips/dma.h
index 23f789c..e06ef07 100644
--- a/include/asm-mips/dma.h
+++ b/include/asm-mips/dma.h
@@ -91,6 +91,7 @@
 #else
 #define MAX_DMA_ADDRESS		(PAGE_OFFSET + 0x01000000)
 #endif
+#define MAX_DMA_PFN		PFN_DOWN(virt_to_phys((void *)MAX_DMA_ADDRESS))
 
 /* 8237 DMA controllers */
 #define IO_DMA1_BASE	0x00	/* 8 bit slave DMA, channels 0..3 */
diff --git a/include/asm-mips/emma2rh/emma2rh.h b/include/asm-mips/emma2rh/emma2rh.h
index 4fb8df7..6a1af0a 100644
--- a/include/asm-mips/emma2rh/emma2rh.h
+++ b/include/asm-mips/emma2rh/emma2rh.h
@@ -24,6 +24,8 @@
 #ifndef __ASM_EMMA2RH_EMMA2RH_H
 #define __ASM_EMMA2RH_EMMA2RH_H
 
+#include <irq.h>
+
 /*
  * EMMA2RH registers
  */
@@ -104,7 +106,8 @@
 #define NUM_EMMA2RH_IRQ		96
 
 #define CPU_EMMA2RH_CASCADE	2
-#define EMMA2RH_IRQ_BASE	0
+#define CPU_IRQ_BASE		MIPS_CPU_IRQ_BASE
+#define EMMA2RH_IRQ_BASE	(CPU_IRQ_BASE + NUM_CPU_IRQ)
 
 /*
  * emma2rh irq defs
diff --git a/include/asm-mips/emma2rh/markeins.h b/include/asm-mips/emma2rh/markeins.h
index 8fa7667..973b062 100644
--- a/include/asm-mips/emma2rh/markeins.h
+++ b/include/asm-mips/emma2rh/markeins.h
@@ -33,7 +33,6 @@
 
 #define EMMA2RH_SW_IRQ_BASE	(EMMA2RH_IRQ_BASE + NUM_EMMA2RH_IRQ)
 #define EMMA2RH_GPIO_IRQ_BASE	(EMMA2RH_SW_IRQ_BASE + NUM_EMMA2RH_IRQ_SW)
-#define CPU_IRQ_BASE		(EMMA2RH_GPIO_IRQ_BASE + NUM_EMMA2RH_IRQ_GPIO)
 
 #define EMMA2RH_SW_IRQ_INT0	(0+EMMA2RH_SW_IRQ_BASE)
 #define EMMA2RH_SW_IRQ_INT1	(1+EMMA2RH_SW_IRQ_BASE)
diff --git a/include/asm-mips/i8259.h b/include/asm-mips/i8259.h
index 4df8d8b..e88a016 100644
--- a/include/asm-mips/i8259.h
+++ b/include/asm-mips/i8259.h
@@ -18,6 +18,7 @@
 #include <linux/spinlock.h>
 
 #include <asm/io.h>
+#include <irq.h>
 
 /* i8259A PIC registers */
 #define PIC_MASTER_CMD		0x20
@@ -42,8 +43,6 @@
 
 extern void init_i8259_irqs(void);
 
-#define I8259A_IRQ_BASE	0
-
 /*
  * Do the traditional i8259 interrupt polling thing.  This is for the few
  * cases where no better interrupt acknowledge method is available and we
diff --git a/include/asm-mips/io.h b/include/asm-mips/io.h
index d77b657..b6a2eb8 100644
--- a/include/asm-mips/io.h
+++ b/include/asm-mips/io.h
@@ -115,7 +115,7 @@
  */
 static inline unsigned long virt_to_phys(volatile const void *address)
 {
-	return (unsigned long)address - PAGE_OFFSET;
+	return (unsigned long)address - PAGE_OFFSET + PHYS_OFFSET;
 }
 
 /*
@@ -132,7 +132,7 @@
  */
 static inline void * phys_to_virt(unsigned long address)
 {
-	return (void *)(address + PAGE_OFFSET);
+	return (void *)(address + PAGE_OFFSET - PHYS_OFFSET);
 }
 
 /*
@@ -556,12 +556,6 @@
 #define __ISA_IO_base ((char *)(isa_slot_offset))
 
 /*
- * We don't have csum_partial_copy_fromio() yet, so we cheat here and
- * just copy it. The net code will then do the checksum later.
- */
-#define eth_io_copy_and_sum(skb,src,len,unused) memcpy_fromio((skb)->data,(src),(len))
-
-/*
  * The caches on some architectures aren't dma-coherent and have need to
  * handle this in software.  There are three types of operations that
  * can be applied to dma buffers.
diff --git a/include/asm-mips/irq.h b/include/asm-mips/irq.h
index 386da82..91803ba 100644
--- a/include/asm-mips/irq.h
+++ b/include/asm-mips/irq.h
@@ -18,7 +18,7 @@
 #ifdef CONFIG_I8259
 static inline int irq_canonicalize(int irq)
 {
-	return ((irq == 2) ? 9 : irq);
+	return ((irq == I8259A_IRQ_BASE + 2) ? I8259A_IRQ_BASE + 9 : irq);
 }
 #else
 #define irq_canonicalize(irq) (irq)	/* Sane hardware, sane code ... */
diff --git a/include/asm-mips/irq_cpu.h b/include/asm-mips/irq_cpu.h
index ed3d1e3..ef6a07c 100644
--- a/include/asm-mips/irq_cpu.h
+++ b/include/asm-mips/irq_cpu.h
@@ -13,8 +13,8 @@
 #ifndef _ASM_IRQ_CPU_H
 #define _ASM_IRQ_CPU_H
 
-extern void mips_cpu_irq_init(int irq_base);
-extern void rm7k_cpu_irq_init(int irq_base);
-extern void rm9k_cpu_irq_init(int irq_base);
+extern void mips_cpu_irq_init(void);
+extern void rm7k_cpu_irq_init(void);
+extern void rm9k_cpu_irq_init(void);
 
 #endif /* _ASM_IRQ_CPU_H */
diff --git a/include/asm-mips/mach-au1x00/au1000.h b/include/asm-mips/mach-au1x00/au1000.h
index 582acd8..58fca8a 100644
--- a/include/asm-mips/mach-au1x00/au1000.h
+++ b/include/asm-mips/mach-au1x00/au1000.h
@@ -39,6 +39,7 @@
 #ifndef _LANGUAGE_ASSEMBLY
 
 #include <linux/delay.h>
+#include <linux/types.h>
 #include <asm/io.h>
 
 /* cpu pipeline flush */
diff --git a/include/asm-mips/mach-cobalt/cobalt.h b/include/asm-mips/mach-cobalt/cobalt.h
index 00b0fc6..24a8d51 100644
--- a/include/asm-mips/mach-cobalt/cobalt.h
+++ b/include/asm-mips/mach-cobalt/cobalt.h
@@ -12,6 +12,8 @@
 #ifndef __ASM_COBALT_H
 #define __ASM_COBALT_H
 
+#include <irq.h>
+
 /*
  * i8259 legacy interrupts used on Cobalt:
  *
@@ -25,7 +27,7 @@
 /*
  * CPU IRQs  are 16 ... 23
  */
-#define COBALT_CPU_IRQ		16
+#define COBALT_CPU_IRQ		MIPS_CPU_IRQ_BASE
 
 #define COBALT_GALILEO_IRQ	(COBALT_CPU_IRQ + 2)
 #define COBALT_SCC_IRQ          (COBALT_CPU_IRQ + 3)	/* pre-production has 85C30 */
diff --git a/include/asm-mips/mach-emma2rh/irq.h b/include/asm-mips/mach-emma2rh/irq.h
index bce6424..5439eb8 100644
--- a/include/asm-mips/mach-emma2rh/irq.h
+++ b/include/asm-mips/mach-emma2rh/irq.h
@@ -10,4 +10,6 @@
 
 #define NR_IRQS	256
 
+#include_next <irq.h>
+
 #endif /* __ASM_MACH_EMMA2RH_IRQ_H */
diff --git a/include/asm-mips/mach-generic/irq.h b/include/asm-mips/mach-generic/irq.h
index 500e10f..70d9a25 100644
--- a/include/asm-mips/mach-generic/irq.h
+++ b/include/asm-mips/mach-generic/irq.h
@@ -8,6 +8,38 @@
 #ifndef __ASM_MACH_GENERIC_IRQ_H
 #define __ASM_MACH_GENERIC_IRQ_H
 
+#ifndef NR_IRQS
 #define NR_IRQS	128
+#endif
+
+#ifdef CONFIG_I8259
+#ifndef I8259A_IRQ_BASE
+#define I8259A_IRQ_BASE	0
+#endif
+#endif
+
+#ifdef CONFIG_IRQ_CPU
+
+#ifndef MIPS_CPU_IRQ_BASE
+#ifdef CONFIG_I8259
+#define MIPS_CPU_IRQ_BASE 16
+#else
+#define MIPS_CPU_IRQ_BASE 0
+#endif /* CONFIG_I8259 */
+#endif
+
+#ifdef CONFIG_IRQ_CPU_RM7K
+#ifndef RM7K_CPU_IRQ_BASE
+#define RM7K_CPU_IRQ_BASE (MIPS_CPU_IRQ_BASE+8)
+#endif
+#endif
+
+#ifdef CONFIG_IRQ_CPU_RM9K
+#ifndef RM9K_CPU_IRQ_BASE
+#define RM9K_CPU_IRQ_BASE (MIPS_CPU_IRQ_BASE+12)
+#endif
+#endif
+
+#endif /* CONFIG_IRQ_CPU */
 
 #endif /* __ASM_MACH_GENERIC_IRQ_H */
diff --git a/include/asm-mips/mach-mips/irq.h b/include/asm-mips/mach-mips/irq.h
index e994b0c..9b9da26 100644
--- a/include/asm-mips/mach-mips/irq.h
+++ b/include/asm-mips/mach-mips/irq.h
@@ -4,4 +4,6 @@
 
 #define NR_IRQS	256
 
+#include_next <irq.h>
+
 #endif /* __ASM_MACH_MIPS_IRQ_H */
diff --git a/include/asm-mips/mach-vr41xx/irq.h b/include/asm-mips/mach-vr41xx/irq.h
new file mode 100644
index 0000000..8488122
--- /dev/null
+++ b/include/asm-mips/mach-vr41xx/irq.h
@@ -0,0 +1,11 @@
+#ifndef __ASM_MACH_VR41XX_IRQ_H
+#define __ASM_MACH_VR41XX_IRQ_H
+
+#include <asm/vr41xx/irq.h> /* for MIPS_CPU_IRQ_BASE */
+#ifdef CONFIG_NEC_CMBVR4133
+#include <asm/vr41xx/cmbvr4133.h> /* for I8259A_IRQ_BASE */
+#endif
+
+#include_next <irq.h>
+
+#endif /* __ASM_MACH_VR41XX_IRQ_H */
diff --git a/include/asm-mips/mips-boards/atlasint.h b/include/asm-mips/mips-boards/atlasint.h
index b15e4ea..76add42 100644
--- a/include/asm-mips/mips-boards/atlasint.h
+++ b/include/asm-mips/mips-boards/atlasint.h
@@ -26,10 +26,12 @@
 #ifndef _MIPS_ATLASINT_H
 #define _MIPS_ATLASINT_H
 
+#include <irq.h>
+
 /*
  * Interrupts 0..7 are used for Atlas CPU interrupts (nonEIC mode)
  */
-#define MIPSCPU_INT_BASE	0
+#define MIPSCPU_INT_BASE	MIPS_CPU_IRQ_BASE
 
 /* CPU interrupt offsets */
 #define MIPSCPU_INT_SW0		0
diff --git a/include/asm-mips/mips-boards/maltaint.h b/include/asm-mips/mips-boards/maltaint.h
index da6cc2f..9180d64 100644
--- a/include/asm-mips/mips-boards/maltaint.h
+++ b/include/asm-mips/mips-boards/maltaint.h
@@ -25,6 +25,8 @@
 #ifndef _MIPS_MALTAINT_H
 #define _MIPS_MALTAINT_H
 
+#include <irq.h>
+
 /*
  * Interrupts 0..15 are used for Malta ISA compatible interrupts
  */
@@ -33,7 +35,7 @@
 /*
  * Interrupts 16..23 are used for Malta CPU interrupts (nonEIC mode)
  */
-#define MIPSCPU_INT_BASE	16
+#define MIPSCPU_INT_BASE	MIPS_CPU_IRQ_BASE
 
 /* CPU interrupt offsets */
 #define MIPSCPU_INT_SW0		0
diff --git a/include/asm-mips/mips-boards/prom.h b/include/asm-mips/mips-boards/prom.h
index 4168c7f..7bf6f5f 100644
--- a/include/asm-mips/mips-boards/prom.h
+++ b/include/asm-mips/mips-boards/prom.h
@@ -33,7 +33,6 @@
 extern void prom_init_cmdline(void);
 extern void prom_meminit(void);
 extern void prom_fixup_mem_map(unsigned long start_mem, unsigned long end_mem);
-extern unsigned long prom_free_prom_memory (void);
 extern void mips_display_message(const char *str);
 extern void mips_display_word(unsigned int num);
 extern int get_ethernet_addr(char *ethernet_addr);
diff --git a/include/asm-mips/mips-boards/seadint.h b/include/asm-mips/mips-boards/seadint.h
index 365c2a3..4f6a393 100644
--- a/include/asm-mips/mips-boards/seadint.h
+++ b/include/asm-mips/mips-boards/seadint.h
@@ -20,10 +20,12 @@
 #ifndef _MIPS_SEADINT_H
 #define _MIPS_SEADINT_H
 
+#include <irq.h>
+
 /*
  * Interrupts 0..7 are used for SEAD CPU interrupts
  */
-#define MIPSCPU_INT_BASE	0
+#define MIPSCPU_INT_BASE	MIPS_CPU_IRQ_BASE
 
 #define MIPSCPU_INT_UART0	2
 #define MIPSCPU_INT_UART1	3
diff --git a/include/asm-mips/mips-boards/simint.h b/include/asm-mips/mips-boards/simint.h
index 4952e0b..54f2fe6 100644
--- a/include/asm-mips/mips-boards/simint.h
+++ b/include/asm-mips/mips-boards/simint.h
@@ -17,10 +17,11 @@
 #ifndef _MIPS_SIMINT_H
 #define _MIPS_SIMINT_H
 
+#include <irq.h>
 
 #define SIM_INT_BASE		0
 #define MIPSCPU_INT_MB0		2
-#define MIPSCPU_INT_BASE	16
+#define MIPSCPU_INT_BASE	MIPS_CPU_IRQ_BASE
 #define MIPS_CPU_TIMER_IRQ	7
 
 
diff --git a/include/asm-mips/mipsmtregs.h b/include/asm-mips/mipsmtregs.h
index 3e9468f..294bca1 100644
--- a/include/asm-mips/mipsmtregs.h
+++ b/include/asm-mips/mipsmtregs.h
@@ -165,8 +165,6 @@
 
 #ifndef __ASSEMBLY__
 
-extern void mips_mt_regdump(unsigned long previous_mvpcontrol_value);
-
 static inline unsigned int dvpe(void)
 {
 	int res = 0;
diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h
index 2f9e1a9..d3fbd83 100644
--- a/include/asm-mips/page.h
+++ b/include/asm-mips/page.h
@@ -34,6 +34,20 @@
 
 #ifndef __ASSEMBLY__
 
+/*
+ * This gives the physical RAM offset.
+ */
+#ifndef PHYS_OFFSET
+#define PHYS_OFFSET		0UL
+#endif
+
+/*
+ * It's normally defined only for FLATMEM config but it's
+ * used in our early mem init code for all memory models.
+ * So always define it.
+ */
+#define ARCH_PFN_OFFSET		PFN_UP(PHYS_OFFSET)
+
 #include <linux/pfn.h>
 #include <asm/io.h>
 
@@ -132,20 +146,23 @@
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)	(((addr) + PAGE_SIZE - 1) & PAGE_MASK)
 
+/*
+ * __pa()/__va() should be used only during mem init.
+ */
 #if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
 #define __pa_page_offset(x)	((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0)
 #else
 #define __pa_page_offset(x)	PAGE_OFFSET
 #endif
-#define __pa(x)			((unsigned long)(x) - __pa_page_offset(x))
-#define __pa_symbol(x)		__pa(RELOC_HIDE((unsigned long)(x),0))
-#define __va(x)			((void *)((unsigned long)(x) + PAGE_OFFSET))
+#define __pa(x)		((unsigned long)(x) - __pa_page_offset(x) + PHYS_OFFSET)
+#define __va(x)		((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))
+#define __pa_symbol(x)	__pa(RELOC_HIDE((unsigned long)(x),0))
 
 #define pfn_to_kaddr(pfn)	__va((pfn) << PAGE_SHIFT)
 
 #ifdef CONFIG_FLATMEM
 
-#define pfn_valid(pfn)		((pfn) < max_mapnr)
+#define pfn_valid(pfn)		((pfn) >= ARCH_PFN_OFFSET && (pfn) < max_mapnr)
 
 #elif defined(CONFIG_SPARSEMEM)
 
diff --git a/include/asm-mips/rtlx.h b/include/asm-mips/rtlx.h
index 76cd51c..59162f7 100644
--- a/include/asm-mips/rtlx.h
+++ b/include/asm-mips/rtlx.h
@@ -6,9 +6,10 @@
 #ifndef __ASM_RTLX_H
 #define __ASM_RTLX_H_
 
+#include <irq.h>
+
 #define LX_NODE_BASE 10
 
-#define MIPSCPU_INT_BASE       16
 #define MIPS_CPU_RTLX_IRQ 0
 
 #define RTLX_VERSION 2
diff --git a/include/asm-mips/sections.h b/include/asm-mips/sections.h
index f701627..b7e3726 100644
--- a/include/asm-mips/sections.h
+++ b/include/asm-mips/sections.h
@@ -3,6 +3,4 @@
 
 #include <asm-generic/sections.h>
 
-extern char _fdata;
-
 #endif /* _ASM_SECTIONS_H */
diff --git a/include/asm-mips/sgi/ip22.h b/include/asm-mips/sgi/ip22.h
index bbfc05c..6592f3b 100644
--- a/include/asm-mips/sgi/ip22.h
+++ b/include/asm-mips/sgi/ip22.h
@@ -21,15 +21,16 @@
  * HAL2 driver). This will prevent many complications, trust me ;-)
  */
 
+#include <irq.h>
 #include <asm/sgi/ioc.h>
 
 #define SGINT_EISA	0	/* 16 EISA irq levels (Indigo2) */
-#define SGINT_CPU	16	/* MIPS CPU define 8 interrupt sources */
-#define SGINT_LOCAL0	24	/* 8 local0 irq levels */
-#define SGINT_LOCAL1	32	/* 8 local1 irq levels */
-#define SGINT_LOCAL2	40	/* 8 local2 vectored irq levels */
-#define SGINT_LOCAL3	48	/* 8 local3 vectored irq levels */
-#define SGINT_END	56	/* End of 'spaces' */
+#define SGINT_CPU	MIPS_CPU_IRQ_BASE	/* MIPS CPU define 8 interrupt sources */
+#define SGINT_LOCAL0	(SGINT_CPU+8)	/* 8 local0 irq levels */
+#define SGINT_LOCAL1	(SGINT_CPU+16)	/* 8 local1 irq levels */
+#define SGINT_LOCAL2	(SGINT_CPU+24)	/* 8 local2 vectored irq levels */
+#define SGINT_LOCAL3	(SGINT_CPU+32)	/* 8 local3 vectored irq levels */
+#define SGINT_END	(SGINT_CPU+40)	/* End of 'spaces' */
 
 /*
  * Individual interrupt definitions for the Indy and Indigo2
diff --git a/include/asm-mips/smtc_ipi.h b/include/asm-mips/smtc_ipi.h
index f22c3e2..55f3419 100644
--- a/include/asm-mips/smtc_ipi.h
+++ b/include/asm-mips/smtc_ipi.h
@@ -44,9 +44,6 @@
 	int depth;
 };
 
-extern struct smtc_ipi_q IPIQ[NR_CPUS];
-extern struct smtc_ipi_q freeIPIq;
-
 static inline void smtc_ipi_nq(struct smtc_ipi_q *q, struct smtc_ipi *p)
 {
 	long flags;
diff --git a/include/asm-mips/uaccess.h b/include/asm-mips/uaccess.h
index 1cdd4ee..c12ebc5 100644
--- a/include/asm-mips/uaccess.h
+++ b/include/asm-mips/uaccess.h
@@ -488,7 +488,8 @@
 })
 
 /*
- * __copy_from_user: - Copy a block of data from user space, with less checking. * @to:   Destination address, in kernel space.
+ * __copy_from_user: - Copy a block of data from user space, with less checking.
+ * @to:   Destination address, in kernel space.
  * @from: Source address, in user space.
  * @n:    Number of bytes to copy.
  *
diff --git a/include/asm-mips/vr41xx/cmbvr4133.h b/include/asm-mips/vr41xx/cmbvr4133.h
index 9490ade..4230003 100644
--- a/include/asm-mips/vr41xx/cmbvr4133.h
+++ b/include/asm-mips/vr41xx/cmbvr4133.h
@@ -35,8 +35,8 @@
 #define CMBVR41XX_INTD_IRQ		GIU_IRQ(CMBVR41XX_INTD_PIN)
 #define CMBVR41XX_INTE_IRQ		GIU_IRQ(CMBVR41XX_INTE_PIN)
 
-#define I8259_IRQ_BASE			72
-#define I8259_IRQ(x)			(I8259_IRQ_BASE + (x))
+#define I8259A_IRQ_BASE			72
+#define I8259_IRQ(x)			(I8259A_IRQ_BASE + (x))
 #define TIMER_IRQ			I8259_IRQ(0)
 #define KEYBOARD_IRQ			I8259_IRQ(1)
 #define I8259_SLAVE_IRQ			I8259_IRQ(2)
@@ -52,6 +52,5 @@
 #define AUX_IRQ				I8259_IRQ(12)
 #define IDE_PRIMARY_IRQ			I8259_IRQ(14)
 #define IDE_SECONDARY_IRQ		I8259_IRQ(15)
-#define I8259_IRQ_LAST			IDE_SECONDARY_IRQ
 
 #endif /* __NEC_CMBVR4133_H */
diff --git a/include/asm-parisc/io.h b/include/asm-parisc/io.h
index c1963ce..ca46e7c 100644
--- a/include/asm-parisc/io.h
+++ b/include/asm-parisc/io.h
@@ -191,15 +191,6 @@
 void memcpy_fromio(void *dst, const volatile void __iomem *src, int count);
 void memcpy_toio(volatile void __iomem *dst, const void *src, int count);
 
-/*
- * XXX - We don't have csum_partial_copy_fromio() yet, so we cheat here and 
- * just copy it. The net code will then do the checksum later. Presently 
- * only used by some shared memory 8390 Ethernet cards anyway.
- */
-
-#define eth_io_copy_and_sum(skb,src,len,unused) \
-  memcpy_fromio((skb)->data,(src),(len))
-
 /* Port-space IO */
 
 #define inb_p inb
diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h
index 7384b80..e870b53 100644
--- a/include/asm-powerpc/cputable.h
+++ b/include/asm-powerpc/cputable.h
@@ -50,6 +50,12 @@
 	PPC_OPROFILE_CELL = 5,
 };
 
+enum powerpc_pmc_type {
+	PPC_PMC_DEFAULT = 0,
+	PPC_PMC_IBM = 1,
+	PPC_PMC_PA6T = 2,
+};
+
 struct cpu_spec {
 	/* CPU is matched via (PVR & pvr_mask) == pvr_value */
 	unsigned int	pvr_mask;
@@ -65,6 +71,7 @@
 
 	/* number of performance monitor counters */
 	unsigned int	num_pmcs;
+	enum powerpc_pmc_type pmc_type;
 
 	/* this is called to initialize various CPU bits like L1 cache,
 	 * BHT, SPD, etc... from head.S before branching to identify_machine
@@ -337,12 +344,6 @@
 	    CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
 	    CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
 	    CPU_FTR_DSCR)
-#define CPU_FTRS_POWER6X (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
-	    CPU_FTR_MMCRA | CPU_FTR_SMT | \
-	    CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
-	    CPU_FTR_PURR | CPU_FTR_CI_LARGE_PAGE | \
-	    CPU_FTR_SPURR | CPU_FTR_REAL_LE | CPU_FTR_DSCR)
 #define CPU_FTRS_CELL	(CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
 	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
diff --git a/include/asm-powerpc/dcr.h b/include/asm-powerpc/dcr.h
index b66c5e6..9338d50 100644
--- a/include/asm-powerpc/dcr.h
+++ b/include/asm-powerpc/dcr.h
@@ -33,6 +33,7 @@
  * base from the device-tree
  */
 #ifdef CONFIG_PPC_MERGE
+struct device_node;
 extern unsigned int dcr_resource_start(struct device_node *np,
 				       unsigned int index);
 extern unsigned int dcr_resource_len(struct device_node *np,
diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h
index d36426c..de50799 100644
--- a/include/asm-powerpc/elf.h
+++ b/include/asm-powerpc/elf.h
@@ -173,7 +173,7 @@
    the loader.  We need to make sure that it is out of the way of the program
    that it will "exec", and that there is sufficient room for the brk.  */
 
-#define ELF_ET_DYN_BASE         (0x08000000)
+#define ELF_ET_DYN_BASE         (0x20000000)
 
 /* Common routine for both 32-bit and 64-bit processes */
 static inline void ppc_elf_core_copy_regs(elf_gregset_t elf_regs,
diff --git a/include/asm-powerpc/firmware.h b/include/asm-powerpc/firmware.h
index 98f7b62..3671c12 100644
--- a/include/asm-powerpc/firmware.h
+++ b/include/asm-powerpc/firmware.h
@@ -43,6 +43,8 @@
 #define FW_FEATURE_ISERIES	ASM_CONST(0x0000000000200000)
 #define FW_FEATURE_LPAR		ASM_CONST(0x0000000000400000)
 #define FW_FEATURE_PS3_LV1	ASM_CONST(0x0000000000800000)
+#define FW_FEATURE_BEAT		ASM_CONST(0x0000000001000000)
+#define FW_FEATURE_BULK_REMOVE	ASM_CONST(0x0000000002000000)
 
 #ifndef __ASSEMBLY__
 
@@ -61,6 +63,8 @@
 	FW_FEATURE_ISERIES_ALWAYS = FW_FEATURE_ISERIES | FW_FEATURE_LPAR,
 	FW_FEATURE_PS3_POSSIBLE = FW_FEATURE_LPAR | FW_FEATURE_PS3_LV1,
 	FW_FEATURE_PS3_ALWAYS = FW_FEATURE_LPAR | FW_FEATURE_PS3_LV1,
+	FW_FEATURE_CELLEB_POSSIBLE = FW_FEATURE_LPAR | FW_FEATURE_BEAT,
+	FW_FEATURE_CELLEB_ALWAYS = FW_FEATURE_LPAR | FW_FEATURE_BEAT,
 	FW_FEATURE_NATIVE_POSSIBLE = 0,
 	FW_FEATURE_NATIVE_ALWAYS = 0,
 	FW_FEATURE_POSSIBLE =
@@ -73,6 +77,9 @@
 #ifdef CONFIG_PPC_PS3
 		FW_FEATURE_PS3_POSSIBLE |
 #endif
+#ifdef CONFIG_PPC_CELLEB
+		FW_FEATURE_CELLEB_POSSIBLE |
+#endif
 #ifdef CONFIG_PPC_NATIVE
 		FW_FEATURE_NATIVE_ALWAYS |
 #endif
@@ -87,6 +94,9 @@
 #ifdef CONFIG_PPC_PS3
 		FW_FEATURE_PS3_ALWAYS &
 #endif
+#ifdef CONFIG_PPC_CELLEB
+		FW_FEATURE_CELLEB_ALWAYS &
+#endif
 #ifdef CONFIG_PPC_NATIVE
 		FW_FEATURE_NATIVE_ALWAYS &
 #endif
diff --git a/include/asm-powerpc/fs_pd.h b/include/asm-powerpc/fs_pd.h
index 3d0e819..c624915 100644
--- a/include/asm-powerpc/fs_pd.h
+++ b/include/asm-powerpc/fs_pd.h
@@ -11,19 +11,17 @@
 
 #ifndef FS_PD_H
 #define FS_PD_H
-#include <asm/cpm2.h>
 #include <sysdev/fsl_soc.h>
 #include <asm/time.h>
 
-static inline int uart_baudrate(void)
-{
-        return get_baudrate();
-}
+#ifdef CONFIG_CPM2
+#include <asm/cpm2.h>
 
-static inline int uart_clock(void)
-{
-        return ppc_proc_freq;
-}
+#if defined(CONFIG_8260)
+#include <asm/mpc8260.h>
+#elif defined(CONFIG_85xx)
+#include <asm/mpc85xx.h>
+#endif
 
 #define cpm2_map(member)						\
 ({									\
@@ -41,5 +39,38 @@
 })
 
 #define cpm2_unmap(addr)	iounmap(addr)
+#endif
+
+#ifdef CONFIG_8xx
+#include <asm/8xx_immap.h>
+#include <asm/mpc8xx.h>
+
+#define immr_map(member)						\
+({									\
+	u32 offset = offsetof(immap_t, member);				\
+	void *addr = ioremap (IMAP_ADDR + offset,			\
+			      sizeof( ((immap_t*)0)->member));		\
+	addr;								\
+})
+
+#define immr_map_size(member, size)					\
+({									\
+	u32 offset = offsetof(immap_t, member);				\
+	void *addr = ioremap (IMAP_ADDR + offset, size);		\
+	addr;								\
+})
+
+#define immr_unmap(addr)		iounmap(addr)
+#endif
+
+static inline int uart_baudrate(void)
+{
+        return get_baudrate();
+}
+
+static inline int uart_clock(void)
+{
+        return ppc_proc_freq;
+}
 
 #endif
diff --git a/include/asm-powerpc/hvcall.h b/include/asm-powerpc/hvcall.h
index 7a50073..6097780 100644
--- a/include/asm-powerpc/hvcall.h
+++ b/include/asm-powerpc/hvcall.h
@@ -168,6 +168,7 @@
 #define H_FREE_LOGICAL_LAN	0x118
 #define H_ADD_LOGICAL_LAN_BUFFER 0x11C
 #define H_SEND_LOGICAL_LAN	0x120
+#define H_BULK_REMOVE		0x124
 #define H_MULTICAST_CTRL	0x130
 #define H_SET_XDABR		0x134
 #define H_STUFF_TCE		0x138
diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h
index 1cd5323..301c9bb 100644
--- a/include/asm-powerpc/io.h
+++ b/include/asm-powerpc/io.h
@@ -732,6 +732,12 @@
 
 #endif /* CONFIG_PPC32 */
 
+/* access ports */
+#define setbits32(_addr, _v) out_be32((_addr), in_be32(_addr) |  (_v))
+#define clrbits32(_addr, _v) out_be32((_addr), in_be32(_addr) & ~(_v))
+
+#define setbits16(_addr, _v) out_be16((_addr), in_be16(_addr) |  (_v))
+#define clrbits16(_addr, _v) out_be16((_addr), in_be16(_addr) & ~(_v))
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h
index f85dbd3..b2e56b3 100644
--- a/include/asm-powerpc/iommu.h
+++ b/include/asm-powerpc/iommu.h
@@ -99,6 +99,7 @@
 extern void iommu_init_early_pSeries(void);
 extern void iommu_init_early_iSeries(void);
 extern void iommu_init_early_dart(void);
+extern void iommu_init_early_pasemi(void);
 
 #ifdef CONFIG_PCI
 extern void pci_iommu_init(void);
diff --git a/include/asm-powerpc/ipic.h b/include/asm-powerpc/ipic.h
index 9fbb034..edec79d 100644
--- a/include/asm-powerpc/ipic.h
+++ b/include/asm-powerpc/ipic.h
@@ -78,7 +78,7 @@
 extern void ipic_clear_mcp_status(u32 mask);
 
 #ifdef CONFIG_PPC_MERGE
-extern void ipic_init(struct device_node *node, unsigned int flags);
+extern struct ipic * ipic_init(struct device_node *node, unsigned int flags);
 extern unsigned int ipic_get_irq(void);
 #else
 extern void ipic_init(phys_addr_t phys_addr, unsigned int flags,
diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h
index 46476e9..4734cc1 100644
--- a/include/asm-powerpc/irq.h
+++ b/include/asm-powerpc/irq.h
@@ -89,6 +89,9 @@
 	/* Dispose of such a mapping */
 	void (*unmap)(struct irq_host *h, unsigned int virq);
 
+	/* Update of such a mapping  */
+	void (*remap)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw);
+
 	/* Translate device-tree interrupt specifier from raw format coming
 	 * from the firmware to a irq_hw_number_t (interrupt line number) and
 	 * type (sense) that can be passed to set_irq_type(). In the absence
diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h
index 2dafa37..3a5dd49 100644
--- a/include/asm-powerpc/kprobes.h
+++ b/include/asm-powerpc/kprobes.h
@@ -44,6 +44,7 @@
 #define IS_TDI(instr)		(((instr) & 0xfc000000) == 0x08000000)
 #define IS_TWI(instr)		(((instr) & 0xfc000000) == 0x0c000000)
 
+#ifdef CONFIG_PPC64
 /*
  * 64bit powerpc uses function descriptors.
  * Handle cases where:
@@ -67,9 +68,13 @@
 }
 
 #define JPROBE_ENTRY(pentry)	(kprobe_opcode_t *)((func_descr_t *)pentry)
-
 #define is_trap(instr)	(IS_TW(instr) || IS_TD(instr) || \
 			IS_TWI(instr) || IS_TDI(instr))
+#else
+/* Use stock kprobe_lookup_name since ppc32 doesn't use function descriptors */
+#define JPROBE_ENTRY(pentry)	(kprobe_opcode_t *)(pentry)
+#define is_trap(instr)	(IS_TW(instr) || IS_TWI(instr))
+#endif
 
 #define ARCH_SUPPORTS_KRETPROBES
 #define  ARCH_INACTIVE_KPROBE_COUNT 1
diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h
index 41c8c9c..200055a 100644
--- a/include/asm-powerpc/mmu.h
+++ b/include/asm-powerpc/mmu.h
@@ -247,6 +247,7 @@
 extern void hpte_init_native(void);
 extern void hpte_init_lpar(void);
 extern void hpte_init_iSeries(void);
+extern void hpte_init_beat(void);
 
 extern void stabs_alloc(void);
 extern void slb_initialize(void);
diff --git a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h
index 4560d72..7afd5bf 100644
--- a/include/asm-powerpc/mpc52xx.h
+++ b/include/asm-powerpc/mpc52xx.h
@@ -249,6 +249,8 @@
 extern void mpc52xx_init_irq(void);
 extern unsigned int mpc52xx_get_irq(void);
 
+extern int __init mpc52xx_add_bridge(struct device_node *node);
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __ASM_POWERPC_MPC52xx_H__ */
diff --git a/include/asm-powerpc/mpc8260.h b/include/asm-powerpc/mpc8260.h
new file mode 100644
index 0000000..f1b83b0
--- /dev/null
+++ b/include/asm-powerpc/mpc8260.h
@@ -0,0 +1,24 @@
+/*
+ * Since there are many different boards and no standard configuration,
+ * we have a unique include file for each.  Rather than change every
+ * file that has to include MPC8260 configuration, they all include
+ * this one and the configuration switching is done here.
+ */
+#ifdef __KERNEL__
+#ifndef __ASM_PPC_MPC8260_H__
+#define __ASM_PPC_MPC8260_H__
+
+
+#ifdef CONFIG_8260
+
+#if defined(CONFIG_PQ2ADS) || defined (CONFIG_PQ2FADS)
+#include <platforms/82xx/pq2ads.h>
+#endif
+
+#ifdef CONFIG_PCI_8260
+#include <platforms/82xx/m82xx_pci.h>
+#endif
+
+#endif /* CONFIG_8260 */
+#endif /* !__ASM_PPC_MPC8260_H__ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/mpc8xx.h b/include/asm-powerpc/mpc8xx.h
new file mode 100644
index 0000000..5803711
--- /dev/null
+++ b/include/asm-powerpc/mpc8xx.h
@@ -0,0 +1,28 @@
+/* This is the single file included by all MPC8xx build options.
+ * Since there are many different boards and no standard configuration,
+ * we have a unique include file for each.  Rather than change every
+ * file that has to include MPC8xx configuration, they all include
+ * this one and the configuration switching is done here.
+ */
+#ifdef __KERNEL__
+#ifndef __CONFIG_8xx_DEFS
+#define __CONFIG_8xx_DEFS
+
+
+#ifdef CONFIG_8xx
+
+#ifdef CONFIG_FADS
+#include <platforms/fads.h>
+#endif
+
+#if defined(CONFIG_MPC86XADS)
+#include <platforms/8xx/mpc86xads.h>
+#endif
+
+#if defined(CONFIG_MPC885ADS)
+#include <platforms/8xx/mpc885ads.h>
+#endif
+
+#endif /* CONFIG_8xx */
+#endif /* __CONFIG_8xx_DEFS */
+#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h
index b71e7b3..cb204a7 100644
--- a/include/asm-powerpc/mpic.h
+++ b/include/asm-powerpc/mpic.h
@@ -103,21 +103,6 @@
 #define MPIC_MAX_ISU		32
 
 /*
- * Special vector numbers (internal use only)
- */
-#define MPIC_VEC_SPURRIOUS	255
-#define MPIC_VEC_IPI_3		254
-#define MPIC_VEC_IPI_2		253
-#define MPIC_VEC_IPI_1		252
-#define MPIC_VEC_IPI_0		251
-
-/* unused */
-#define MPIC_VEC_TIMER_3	250
-#define MPIC_VEC_TIMER_2	249
-#define MPIC_VEC_TIMER_1	248
-#define MPIC_VEC_TIMER_0	247
-
-/*
  * Tsi108 implementation of MPIC has many differences from the original one
  */
 
@@ -276,6 +261,13 @@
 	unsigned char		*senses;
 	unsigned int		senses_count;
 
+	/* vector numbers used for internal sources (ipi/timers) */
+	unsigned int		ipi_vecs[4];
+	unsigned int		timer_vecs[4];
+
+	/* Spurious vector to program into unused sources */
+	unsigned int		spurious_vec;
+
 #ifdef CONFIG_MPIC_BROKEN_U3
 	/* The fixup table */
 	struct mpic_irq_fixup	*fixups;
@@ -332,6 +324,8 @@
 #define MPIC_NO_PTHROU_DIS		0x00000040
 /* DCR based MPIC */
 #define MPIC_USES_DCR			0x00000080
+/* MPIC has 11-bit vector fields (or larger) */
+#define MPIC_LARGE_VECTORS		0x00000100
 
 /* MPIC HW modification ID */
 #define MPIC_REGSET_MASK		0xf0000000
diff --git a/include/asm-powerpc/oprofile_impl.h b/include/asm-powerpc/oprofile_impl.h
index 71043bf..94c0ad2 100644
--- a/include/asm-powerpc/oprofile_impl.h
+++ b/include/asm-powerpc/oprofile_impl.h
@@ -58,10 +58,8 @@
 extern struct op_powerpc_model op_model_7450;
 extern struct op_powerpc_model op_model_cell;
 
-#ifndef CONFIG_FSL_BOOKE
-
 /* All the classic PPC parts use these */
-static inline unsigned int ctr_read(unsigned int i)
+static inline unsigned int classic_ctr_read(unsigned int i)
 {
 	switch(i) {
 	case 0:
@@ -89,7 +87,7 @@
 	}
 }
 
-static inline void ctr_write(unsigned int i, unsigned int val)
+static inline void classic_ctr_write(unsigned int i, unsigned int val)
 {
 	switch(i) {
 	case 0:
@@ -124,89 +122,6 @@
 		break;
 	}
 }
-#else /* CONFIG_FSL_BOOKE */
-static inline u32 get_pmlca(int ctr)
-{
-	u32 pmlca;
-
-	switch (ctr) {
-		case 0:
-			pmlca = mfpmr(PMRN_PMLCA0);
-			break;
-		case 1:
-			pmlca = mfpmr(PMRN_PMLCA1);
-			break;
-		case 2:
-			pmlca = mfpmr(PMRN_PMLCA2);
-			break;
-		case 3:
-			pmlca = mfpmr(PMRN_PMLCA3);
-			break;
-		default:
-			panic("Bad ctr number\n");
-	}
-
-	return pmlca;
-}
-
-static inline void set_pmlca(int ctr, u32 pmlca)
-{
-	switch (ctr) {
-		case 0:
-			mtpmr(PMRN_PMLCA0, pmlca);
-			break;
-		case 1:
-			mtpmr(PMRN_PMLCA1, pmlca);
-			break;
-		case 2:
-			mtpmr(PMRN_PMLCA2, pmlca);
-			break;
-		case 3:
-			mtpmr(PMRN_PMLCA3, pmlca);
-			break;
-		default:
-			panic("Bad ctr number\n");
-	}
-}
-
-static inline unsigned int ctr_read(unsigned int i)
-{
-	switch(i) {
-		case 0:
-			return mfpmr(PMRN_PMC0);
-		case 1:
-			return mfpmr(PMRN_PMC1);
-		case 2:
-			return mfpmr(PMRN_PMC2);
-		case 3:
-			return mfpmr(PMRN_PMC3);
-		default:
-			return 0;
-	}
-}
-
-static inline void ctr_write(unsigned int i, unsigned int val)
-{
-	switch(i) {
-		case 0:
-			mtpmr(PMRN_PMC0, val);
-			break;
-		case 1:
-			mtpmr(PMRN_PMC1, val);
-			break;
-		case 2:
-			mtpmr(PMRN_PMC2, val);
-			break;
-		case 3:
-			mtpmr(PMRN_PMC3, val);
-			break;
-		default:
-			break;
-	}
-}
-
-
-#endif /* CONFIG_FSL_BOOKE */
 
 
 extern void op_powerpc_backtrace(struct pt_regs * const regs, unsigned int depth);
diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h
index cb02c9d..d9bf5ab 100644
--- a/include/asm-powerpc/pci-bridge.h
+++ b/include/asm-powerpc/pci-bridge.h
@@ -53,6 +53,8 @@
 	unsigned long buid;
 	unsigned long dma_window_base_cur;
 	unsigned long dma_window_size;
+
+	void *private_data;
 };
 
 /*
diff --git a/include/asm-powerpc/ps3.h b/include/asm-powerpc/ps3.h
index 52a69ed..4f5a1e0 100644
--- a/include/asm-powerpc/ps3.h
+++ b/include/asm-powerpc/ps3.h
@@ -21,11 +21,33 @@
 #if !defined(_ASM_POWERPC_PS3_H)
 #define _ASM_POWERPC_PS3_H
 
-#include <linux/compiler.h> /* for __deprecated */
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/device.h>
 
+union ps3_firmware_version {
+	u64 raw;
+	struct {
+		u16 pad;
+		u16 major;
+		u16 minor;
+		u16 rev;
+	};
+};
+
+int ps3_get_firmware_version(union ps3_firmware_version *v);
+
+/* 'Other OS' area */
+
+enum ps3_param_av_multi_out {
+	PS3_PARAM_AV_MULTI_OUT_NTSC = 0,
+	PS3_PARAM_AV_MULTI_OUT_PAL_RGB = 1,
+	PS3_PARAM_AV_MULTI_OUT_PAL_YCBCR = 2,
+	PS3_PARAM_AV_MULTI_OUT_SECAM = 3,
+};
+
+enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void);
+
 /**
  * struct ps3_device_id - HV bus device identifier from the system repository
  * @bus_id: HV bus id, {1..} (zero invalid)
@@ -139,20 +161,32 @@
 
 /* inrerrupt routines */
 
-int ps3_alloc_io_irq(unsigned int interrupt_id, unsigned int *virq);
+enum ps3_cpu_binding {
+	PS3_BINDING_CPU_ANY = -1,
+	PS3_BINDING_CPU_0 = 0,
+	PS3_BINDING_CPU_1 = 1,
+};
+
+int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
+	unsigned int *virq);
 int ps3_free_io_irq(unsigned int virq);
-int ps3_alloc_event_irq(unsigned int *virq);
+int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq);
 int ps3_free_event_irq(unsigned int virq);
 int ps3_send_event_locally(unsigned int virq);
-int ps3_connect_event_irq(const struct ps3_device_id *did,
-	unsigned int interrupt_id, unsigned int *virq);
+int ps3_connect_event_irq(enum ps3_cpu_binding cpu,
+	const struct ps3_device_id *did, unsigned int interrupt_id,
+	unsigned int *virq);
 int ps3_disconnect_event_irq(const struct ps3_device_id *did,
 	unsigned int interrupt_id, unsigned int virq);
-int ps3_alloc_vuart_irq(void* virt_addr_bmp, unsigned int *virq);
-int ps3_free_vuart_irq(unsigned int virq);
-int ps3_alloc_spe_irq(unsigned long spe_id, unsigned int class,
+int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
 	unsigned int *virq);
+int ps3_free_vuart_irq(unsigned int virq);
+int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id,
+	unsigned int class, unsigned int *virq);
 int ps3_free_spe_irq(unsigned int virq);
+int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
+	unsigned int *virq);
+int ps3_free_irq(unsigned int virq);
 
 /* lv1 result codes */
 
@@ -247,146 +281,6 @@
 #endif
 }
 
-/* repository bus info */
-
-enum ps3_bus_type {
-	PS3_BUS_TYPE_SB = 4,
-	PS3_BUS_TYPE_STORAGE = 5,
-};
-
-enum ps3_dev_type {
-	PS3_DEV_TYPE_SB_GELIC = 3,
-	PS3_DEV_TYPE_SB_USB = 4,
-	PS3_DEV_TYPE_SB_GPIO = 6,
-};
-
-int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str,
-	u64 *value);
-int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id);
-int ps3_repository_read_bus_type(unsigned int bus_index,
-	enum ps3_bus_type *bus_type);
-int ps3_repository_read_bus_num_dev(unsigned int bus_index,
-	unsigned int *num_dev);
-
-/* repository bus device info */
-
-enum ps3_interrupt_type {
-	PS3_INTERRUPT_TYPE_EVENT_PORT = 2,
-	PS3_INTERRUPT_TYPE_SB_OHCI = 3,
-	PS3_INTERRUPT_TYPE_SB_EHCI = 4,
-	PS3_INTERRUPT_TYPE_OTHER = 5,
-};
-
-enum ps3_region_type {
-	PS3_REGION_TYPE_SB_OHCI = 3,
-	PS3_REGION_TYPE_SB_EHCI = 4,
-	PS3_REGION_TYPE_SB_GPIO = 5,
-};
-
-int ps3_repository_read_dev_str(unsigned int bus_index,
-	unsigned int dev_index, const char *dev_str, u64 *value);
-int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index,
-	unsigned int *dev_id);
-int ps3_repository_read_dev_type(unsigned int bus_index,
-	unsigned int dev_index, enum ps3_dev_type *dev_type);
-int ps3_repository_read_dev_intr(unsigned int bus_index,
-	unsigned int dev_index, unsigned int intr_index,
-	enum ps3_interrupt_type *intr_type, unsigned int *interrupt_id);
-int ps3_repository_read_dev_reg_type(unsigned int bus_index,
-	unsigned int dev_index, unsigned int reg_index,
-	enum ps3_region_type *reg_type);
-int ps3_repository_read_dev_reg_addr(unsigned int bus_index,
-	unsigned int dev_index, unsigned int reg_index, u64 *bus_addr,
-	u64 *len);
-int ps3_repository_read_dev_reg(unsigned int bus_index,
-	unsigned int dev_index, unsigned int reg_index,
-	enum ps3_region_type *reg_type, u64 *bus_addr, u64 *len);
-
-/* repository bus enumerators */
-
-struct ps3_repository_device {
-	unsigned int bus_index;
-	unsigned int dev_index;
-	struct ps3_device_id did;
-};
-
-int ps3_repository_find_device(enum ps3_bus_type bus_type,
-	enum ps3_dev_type dev_type,
-	const struct ps3_repository_device *start_dev,
-	struct ps3_repository_device *dev);
-static inline int ps3_repository_find_first_device(
-	enum ps3_bus_type bus_type, enum ps3_dev_type dev_type,
-	struct ps3_repository_device *dev)
-{
-	return ps3_repository_find_device(bus_type, dev_type, NULL, dev);
-}
-int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
-	enum ps3_interrupt_type intr_type, unsigned int *interrupt_id);
-int ps3_repository_find_region(const struct ps3_repository_device *dev,
-	enum ps3_region_type reg_type, u64 *bus_addr, u64 *len);
-
-/* repository block device info */
-
-int ps3_repository_read_dev_port(unsigned int bus_index,
-	unsigned int dev_index, u64 *port);
-int ps3_repository_read_dev_blk_size(unsigned int bus_index,
-	unsigned int dev_index, u64 *blk_size);
-int ps3_repository_read_dev_num_blocks(unsigned int bus_index,
-	unsigned int dev_index, u64 *num_blocks);
-int ps3_repository_read_dev_num_regions(unsigned int bus_index,
-	unsigned int dev_index, unsigned int *num_regions);
-int ps3_repository_read_dev_region_id(unsigned int bus_index,
-	unsigned int dev_index, unsigned int region_index,
-	unsigned int *region_id);
-int ps3_repository_read_dev_region_size(unsigned int bus_index,
-	unsigned int dev_index,	unsigned int region_index, u64 *region_size);
-int ps3_repository_read_dev_region_start(unsigned int bus_index,
-	unsigned int dev_index, unsigned int region_index, u64 *region_start);
-
-/* repository pu and memory info */
-
-int ps3_repository_read_num_pu(unsigned int *num_pu);
-int ps3_repository_read_ppe_id(unsigned int *pu_index, unsigned int *ppe_id);
-int ps3_repository_read_rm_base(unsigned int ppe_id, u64 *rm_base);
-int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size);
-int ps3_repository_read_region_total(u64 *region_total);
-int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size,
-	u64 *region_total);
-
-/* repository pme info */
-
-int ps3_repository_read_num_be(unsigned int *num_be);
-int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id);
-int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq);
-int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq);
-
-/* repository 'Other OS' area */
-
-int ps3_repository_read_boot_dat_addr(u64 *lpar_addr);
-int ps3_repository_read_boot_dat_size(unsigned int *size);
-int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size);
-
-/* repository spu info */
-
-/**
- * enum spu_resource_type - Type of spu resource.
- * @spu_resource_type_shared: Logical spu is shared with other partions.
- * @spu_resource_type_exclusive: Logical spu is not shared with other partions.
- *
- * Returned by ps3_repository_read_spu_resource_id().
- */
-
-enum ps3_spu_resource_type {
-	PS3_SPU_RESOURCE_TYPE_SHARED = 0,
-	PS3_SPU_RESOURCE_TYPE_EXCLUSIVE = 0x8000000000000000UL,
-};
-
-int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved);
-int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id);
-int ps3_repository_read_spu_resource_id(unsigned int res_index,
-	enum ps3_spu_resource_type* resource_type, unsigned int *resource_id);
-
-
 /* system bus routines */
 
 enum ps3_match_id {
@@ -459,4 +353,39 @@
 
 extern struct bus_type ps3_system_bus_type;
 
+/* vuart routines */
+
+struct ps3_vuart_stats {
+	unsigned long bytes_written;
+	unsigned long bytes_read;
+	unsigned long tx_interrupts;
+	unsigned long rx_interrupts;
+	unsigned long disconnect_interrupts;
+};
+
+/**
+ * struct ps3_vuart_port_device - a device on a vuart port
+ */
+
+struct ps3_vuart_port_device {
+	enum ps3_match_id match_id;
+	struct device core;
+
+	/* private driver variables */
+	unsigned int port_number;
+	u64 interrupt_mask;
+	struct {
+		spinlock_t lock;
+		struct list_head head;
+	} tx_list;
+	struct {
+		unsigned long bytes_held;
+		spinlock_t lock;
+		struct list_head head;
+	} rx_list;
+	struct ps3_vuart_stats stats;
+};
+
+int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev);
+
 #endif
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
index a3631b1..0d7f016 100644
--- a/include/asm-powerpc/reg.h
+++ b/include/asm-powerpc/reg.h
@@ -166,6 +166,7 @@
 #define SPRN_TBWU	0x11D	/* Time Base Upper Register (super, R/W) */
 #define SPRN_SPURR	0x134	/* Scaled PURR */
 #define SPRN_HIOR	0x137	/* 970 Hypervisor interrupt offset */
+#define SPRN_LPCR	0x13E	/* LPAR Control Register */
 #define SPRN_DBAT0L	0x219	/* Data BAT 0 Lower Register */
 #define SPRN_DBAT0U	0x218	/* Data BAT 0 Upper Register */
 #define SPRN_DBAT1L	0x21B	/* Data BAT 1 Lower Register */
@@ -391,6 +392,12 @@
 #define SPRN_HSRR0	0x13A	/* Save/Restore Register 0 */
 #define SPRN_HSRR1	0x13B	/* Save/Restore Register 1 */
 
+#define SPRN_TBCTL	0x35f	/* PA6T Timebase control register */
+#define   TBCTL_FREEZE		0x0000000000000000ull /* Freeze all tbs */
+#define   TBCTL_RESTART		0x0000000100000000ull /* Restart all tbs */
+#define   TBCTL_UPDATE_UPPER	0x0000000200000000ull /* Set upper 32 bits */
+#define   TBCTL_UPDATE_LOWER	0x0000000300000000ull /* Set lower 32 bits */
+
 #ifndef SPRN_SVR
 #define SPRN_SVR	0x11E	/* System Version Register */
 #endif
@@ -462,6 +469,13 @@
 #define SPRN_SIAR	780
 #define SPRN_SDAR	781
 
+#define PA6T_SPRN_PMC0	787
+#define PA6T_SPRN_PMC1	788
+#define PA6T_SPRN_PMC2	789
+#define PA6T_SPRN_PMC3	790
+#define PA6T_SPRN_PMC4	791
+#define PA6T_SPRN_PMC5	792
+
 #else /* 32-bit */
 #define SPRN_MMCR0	952	/* Monitor Mode Control Register 0 */
 #define   MMCR0_FC	0x80000000UL /* freeze counters */
diff --git a/include/asm-powerpc/smp.h b/include/asm-powerpc/smp.h
index 20ea7c7..01717f2 100644
--- a/include/asm-powerpc/smp.h
+++ b/include/asm-powerpc/smp.h
@@ -75,6 +75,7 @@
 void smp_init_iSeries(void);
 void smp_init_pSeries(void);
 void smp_init_cell(void);
+void smp_init_celleb(void);
 void smp_setup_cpu_maps(void);
 
 extern int __cpu_disable(void);
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h
index 3d90264..b634e16 100644
--- a/include/asm-powerpc/spu.h
+++ b/include/asm-powerpc/spu.h
@@ -104,6 +104,7 @@
 
 struct spu_context;
 struct spu_runqueue;
+struct device_node;
 
 struct spu {
 	const char *name;
@@ -142,7 +143,19 @@
 	char irq_c1[8];
 	char irq_c2[8];
 
+	u64 spe_id;
+
 	void* pdata; /* platform private data */
+
+	/* of based platforms only */
+	struct device_node *devnode;
+
+	/* native only */
+	struct spu_priv1 __iomem *priv1;
+
+	/* beat only */
+	u64 shadow_int_mask_RW[3];
+
 	struct sys_device sysdev;
 };
 
diff --git a/include/asm-powerpc/spu_priv1.h b/include/asm-powerpc/spu_priv1.h
index 69dcb0c..7e78f6a 100644
--- a/include/asm-powerpc/spu_priv1.h
+++ b/include/asm-powerpc/spu_priv1.h
@@ -206,6 +206,8 @@
  */
 
 extern const struct spu_priv1_ops spu_priv1_mmio_ops;
+extern const struct spu_priv1_ops spu_priv1_beat_ops;
+
 extern const struct spu_management_ops spu_management_of_ops;
 
 #endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/sstep.h b/include/asm-powerpc/sstep.h
index 630a988..f593b0f 100644
--- a/include/asm-powerpc/sstep.h
+++ b/include/asm-powerpc/sstep.h
@@ -21,6 +21,7 @@
  */
 #define IS_MTMSRD(instr)	(((instr) & 0xfc0007be) == 0x7c000124)
 #define IS_RFID(instr)		(((instr) & 0xfc0007fe) == 0x4c000024)
+#define IS_RFI(instr)		(((instr) & 0xfc0007fe) == 0x4c000064)
 
 /* Emulate instructions that cause a transfer of control. */
 extern int emulate_step(struct pt_regs *regs, unsigned int instr);
diff --git a/include/asm-powerpc/time.h b/include/asm-powerpc/time.h
index 4cff977..3fd57c0 100644
--- a/include/asm-powerpc/time.h
+++ b/include/asm-powerpc/time.h
@@ -39,6 +39,8 @@
 extern void wakeup_decrementer(void);
 extern void snapshot_timebase(void);
 
+extern void set_dec_cpu6(unsigned int val);
+
 /* Some sane defaults: 125 MHz timebase, 1GHz processor */
 extern unsigned long ppc_proc_freq;
 #define DEFAULT_PROC_FREQ	(DEFAULT_TB_FREQ * 8)
diff --git a/include/asm-powerpc/udbg.h b/include/asm-powerpc/udbg.h
index 55e5784..4cbc313 100644
--- a/include/asm-powerpc/udbg.h
+++ b/include/asm-powerpc/udbg.h
@@ -41,9 +41,11 @@
 extern void __init udbg_init_debug_lpar(void);
 extern void __init udbg_init_pmac_realmode(void);
 extern void __init udbg_init_maple_realmode(void);
+extern void __init udbg_init_pas_realmode(void);
 extern void __init udbg_init_iseries(void);
 extern void __init udbg_init_rtas_panel(void);
 extern void __init udbg_init_rtas_console(void);
+extern void __init udbg_init_debug_beat(void);
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_UDBG_H */
diff --git a/include/asm-ppc/commproc.h b/include/asm-ppc/commproc.h
index 7b06b4e..4f99df1 100644
--- a/include/asm-ppc/commproc.h
+++ b/include/asm-ppc/commproc.h
@@ -77,6 +77,7 @@
 extern uint cpm_dpalloc_fixed(uint offset, uint size, uint align);
 extern void cpm_dpdump(void);
 extern void *cpm_dpram_addr(uint offset);
+extern uint cpm_dpram_phys(u8* addr);
 extern void cpm_setbrg(uint brg, uint rate);
 
 extern uint m8xx_cpm_hostalloc(uint size);
diff --git a/include/asm-ppc/ibm4xx.h b/include/asm-ppc/ibm4xx.h
index 499c146..7a64ede 100644
--- a/include/asm-ppc/ibm4xx.h
+++ b/include/asm-ppc/ibm4xx.h
@@ -15,6 +15,7 @@
 #define __ASM_IBM4XX_H__
 
 #include <asm/types.h>
+#include <asm/dcr.h>
 
 #ifdef CONFIG_40x
 
diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h
index ccf1a9b..95d5904 100644
--- a/include/asm-ppc/io.h
+++ b/include/asm-ppc/io.h
@@ -358,8 +358,6 @@
 }
 #endif
 
-#define eth_io_copy_and_sum(a,b,c,d)		eth_copy_and_sum((a),(void __force *)(void __iomem *)(b),(c),(d))
-
 /*
  * Map in an area of physical address space, for accessing
  * I/O devices etc.
diff --git a/include/asm-ppc/m48t35.h b/include/asm-ppc/m48t35.h
deleted file mode 100644
index a5277ea..0000000
--- a/include/asm-ppc/m48t35.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- *  Registers for the SGS-Thomson M48T35 Timekeeper RAM chip
- *  and
- *  Registers for the SGS-Thomson M48T37 Timekeeper RAM chip
- *  The 37 is the 35 plus alarm and century thus the offsets
- *  are shifted by the extra registers.
- */
-
-#ifndef __PPC_M48T35_H
-#define __PPC_M48T35_H
-
-/* RTC offsets */
-#define M48T35_RTC_FLAGS	(-8)	/* the negative regs are really T37 only */
-#define M48T35_RTC_CENTURY	(-7)
-#define M48T35_RTC_AL_SEC	(-6)
-#define M48T35_RTC_AL_MIN	(-5)
-#define M48T35_RTC_AL_HRS	(-4)
-#define M48T35_RTC_AL_DOM	(-3)
-#define M48T35_RTC_INTERRUPT	(-2)
-#define M48T35_RTC_WATCHDOG	(-1)
-#define M48T35_RTC_CONTROL	0	/* T35 starts here */
-#define M48T35_RTC_SECONDS	1
-#define M48T35_RTC_MINUTES	2
-#define M48T35_RTC_HOURS	3
-#define M48T35_RTC_DAY		4
-#define M48T35_RTC_DOM		5
-#define M48T35_RTC_MONTH	6
-#define M48T35_RTC_YEAR		7
-
-/* this way help us know which bits go with which regs */
-#define M48T35_RTC_FLAGS_BL           0x10
-#define M48T35_RTC_FLAGS_AF           0x40
-#define M48T35_RTC_FLAGS_WDF          0x80
-
-#define M48T35_RTC_INTERRUPT_AFE       0x80
-#define M48T35_RTC_INTERRUPT_ABE       0x20
-#define M48T35_RTC_INTERRUPT_ALL       (M48T35_RTC_INTERRUPT_AFE|M48T35_RTC_INTERRUPT_ABE)
-
-#define M48T35_RTC_WATCHDOG_RB         0x03
-#define M48T35_RTC_WATCHDOG_BMB        0x7c
-#define M48T35_RTC_WATCHDOG_WDS        0x80
-#define M48T35_RTC_WATCHDOG_ALL        (M48T35_RTC_WATCHDOG_RB|M48T35_RTC_WATCHDOG_BMB|M48T35_RTC_W)
-
-#define M48T35_RTC_CONTROL_WRITE       0x80
-#define M48T35_RTC_CONTROL_READ        0x40
-#define M48T35_RTC_CONTROL_CAL_SIGN    0x20
-#define M48T35_RTC_CONTROL_CAL_VALUE   0x1f
-#define M48T35_RTC_CONTROL_LOCKED      (M48T35_RTC_WRITE|M48T35_RTC_READ)
-#define M48T35_RTC_CONTROL_CALIBRATION (M48T35_RTC_CONTROL_CAL_SIGN|M48T35_RTC_CONTROL_CAL_VALUE)
-
-#define M48T35_RTC_SECONDS_SEC_1       0x0f
-#define M48T35_RTC_SECONDS_SEC_10      0x70
-#define M48T35_RTC_SECONDS_ST          0x80
-#define M48T35_RTC_SECONDS_SEC_ALL     (M48T35_RTC_SECONDS_SEC_1|M48T35_RTC_SECONDS_SEC_10)
-
-#define M48T35_RTC_MINUTES_MIN_1       0x0f
-#define M48T35_RTC_MINUTES_MIN_10      0x70
-#define M48T35_RTC_MINUTES_MIN_ALL     (M48T35_RTC_MINUTES_MIN_1|M48T35_RTC_MINUTES_MIN_10)
-
-#define M48T35_RTC_HOURS_HRS_1         0x0f
-#define M48T35_RTC_HOURS_HRS_10        0x30
-#define M48T35_RTC_HOURS_HRS_ALL       (M48T35_RTC_HOURS_HRS_1|M48T35_RTC_HOURS_HRS_10)
-
-#define M48T35_RTC_DAY_DAY_1           0x03
-#define M48T35_RTC_DAY_FT              0x40
-
-#define M48T35_RTC_ALARM_OFF           0x00
-#define M48T35_RTC_WATCHDOG_OFF        0x00
-
-
-/* legacy */
-#define M48T35_RTC_SET      0x80
-#define M48T35_RTC_STOPPED  0x80
-#define M48T35_RTC_READ     0x40
-
-
-#endif
diff --git a/include/asm-ppc/reg_booke.h b/include/asm-ppc/reg_booke.h
index a263fc1e..82948ed 100644
--- a/include/asm-ppc/reg_booke.h
+++ b/include/asm-ppc/reg_booke.h
@@ -9,8 +9,6 @@
 #ifndef __ASM_PPC_REG_BOOKE_H__
 #define __ASM_PPC_REG_BOOKE_H__
 
-#include <asm/dcr.h>
-
 #ifndef __ASSEMBLY__
 /* Performance Monitor Registers */
 #define mfpmr(rn)	({unsigned int rval; \
diff --git a/include/asm-ppc/serial.h b/include/asm-ppc/serial.h
index 8a59f88..8fc1b54 100644
--- a/include/asm-ppc/serial.h
+++ b/include/asm-ppc/serial.h
@@ -11,8 +11,6 @@
 #include <platforms/ev64260.h>
 #elif defined(CONFIG_CHESTNUT)
 #include <platforms/chestnut.h>
-#elif defined(CONFIG_GEMINI)
-#include <platforms/gemini_serial.h>
 #elif defined(CONFIG_POWERPMC250)
 #include <platforms/powerpmc250.h>
 #elif defined(CONFIG_LOPEC)
diff --git a/include/asm-s390/compat.h b/include/asm-s390/compat.h
index 356a0b1..296f4f1 100644
--- a/include/asm-s390/compat.h
+++ b/include/asm-s390/compat.h
@@ -6,6 +6,34 @@
 #include <linux/types.h>
 #include <linux/sched.h>
 
+#define PSW32_MASK_PER		0x40000000UL
+#define PSW32_MASK_DAT		0x04000000UL
+#define PSW32_MASK_IO		0x02000000UL
+#define PSW32_MASK_EXT		0x01000000UL
+#define PSW32_MASK_KEY		0x00F00000UL
+#define PSW32_MASK_MCHECK	0x00040000UL
+#define PSW32_MASK_WAIT		0x00020000UL
+#define PSW32_MASK_PSTATE	0x00010000UL
+#define PSW32_MASK_ASC		0x0000C000UL
+#define PSW32_MASK_CC		0x00003000UL
+#define PSW32_MASK_PM		0x00000f00UL
+
+#define PSW32_ADDR_AMODE31	0x80000000UL
+#define PSW32_ADDR_INSN		0x7FFFFFFFUL
+
+#define PSW32_BASE_BITS		0x00080000UL
+
+#define PSW32_ASC_PRIMARY	0x00000000UL
+#define PSW32_ASC_ACCREG	0x00004000UL
+#define PSW32_ASC_SECONDARY	0x00008000UL
+#define PSW32_ASC_HOME		0x0000C000UL
+
+#define PSW32_MASK_MERGE(CURRENT,NEW) \
+	(((CURRENT) & ~(PSW32_MASK_CC|PSW32_MASK_PM)) | \
+	 ((NEW) & (PSW32_MASK_CC|PSW32_MASK_PM)))
+
+extern long psw32_user_bits;
+
 #define COMPAT_USER_HZ	100
 
 typedef u32		compat_size_t;
diff --git a/include/asm-s390/etr.h b/include/asm-s390/etr.h
new file mode 100644
index 0000000..b498f19
--- /dev/null
+++ b/include/asm-s390/etr.h
@@ -0,0 +1,219 @@
+/*
+ *  include/asm-s390/etr.h
+ *
+ *  Copyright IBM Corp. 2006
+ *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+#ifndef __S390_ETR_H
+#define __S390_ETR_H
+
+/* ETR attachment control register */
+struct etr_eacr {
+	unsigned int e0		: 1;	/* port 0 stepping control */
+	unsigned int e1		: 1;	/* port 1 stepping control */
+	unsigned int _pad0	: 5;	/* must be 00100 */
+	unsigned int dp		: 1;	/* data port control */
+	unsigned int p0		: 1;	/* port 0 change recognition control */
+	unsigned int p1		: 1;	/* port 1 change recognition control */
+	unsigned int _pad1	: 3;	/* must be 000 */
+	unsigned int ea		: 1;	/* ETR alert control */
+	unsigned int es		: 1;	/* ETR sync check control */
+	unsigned int sl		: 1;	/* switch to local control */
+} __attribute__ ((packed));
+
+/* Port state returned by steai */
+enum etr_psc {
+	etr_psc_operational = 0,
+	etr_psc_semi_operational = 1,
+	etr_psc_protocol_error =  4,
+	etr_psc_no_symbols = 8,
+	etr_psc_no_signal = 12,
+	etr_psc_pps_mode = 13
+};
+
+/* Logical port state returned by stetr */
+enum etr_lpsc {
+	etr_lpsc_operational_step = 0,
+	etr_lpsc_operational_alt = 1,
+	etr_lpsc_semi_operational = 2,
+	etr_lpsc_protocol_error =  4,
+	etr_lpsc_no_symbol_sync = 8,
+	etr_lpsc_no_signal = 12,
+	etr_lpsc_pps_mode = 13
+};
+
+/* ETR status words */
+struct etr_esw {
+	struct etr_eacr eacr;		/* attachment control register */
+	unsigned int y		: 1;	/* stepping mode */
+	unsigned int _pad0	: 5;	/* must be 00000 */
+	unsigned int p		: 1;	/* stepping port number */
+	unsigned int q		: 1;	/* data port number */
+	unsigned int psc0	: 4;	/* port 0 state code */
+	unsigned int psc1	: 4;	/* port 1 state code */
+} __attribute__ ((packed));
+
+/* Second level data register status word */
+struct etr_slsw {
+	unsigned int vv1	: 1;	/* copy of validity bit data frame 1 */
+	unsigned int vv2	: 1;	/* copy of validity bit data frame 2 */
+	unsigned int vv3	: 1;	/* copy of validity bit data frame 3 */
+	unsigned int vv4	: 1;	/* copy of validity bit data frame 4 */
+	unsigned int _pad0	: 19;	/* must by all zeroes */
+	unsigned int n		: 1;	/* EAF port number */
+	unsigned int v1		: 1;	/* validity bit ETR data frame 1 */
+	unsigned int v2		: 1;	/* validity bit ETR data frame 2 */
+	unsigned int v3		: 1;	/* validity bit ETR data frame 3 */
+	unsigned int v4		: 1;	/* validity bit ETR data frame 4 */
+	unsigned int _pad1	: 4;	/* must be 0000 */
+} __attribute__ ((packed));
+
+/* ETR data frames */
+struct etr_edf1 {
+	unsigned int u		: 1;	/* untuned bit */
+	unsigned int _pad0	: 1;	/* must be 0 */
+	unsigned int r		: 1;	/* service request bit */
+	unsigned int _pad1	: 4;	/* must be 0000 */
+	unsigned int a		: 1;	/* time adjustment bit */
+	unsigned int net_id	: 8;	/* ETR network id */
+	unsigned int etr_id	: 8;	/* id of ETR which sends data frames */
+	unsigned int etr_pn	: 8;	/* port number of ETR output port */
+} __attribute__ ((packed));
+
+struct etr_edf2 {
+	unsigned int etv	: 32;	/* Upper 32 bits of TOD. */
+} __attribute__ ((packed));
+
+struct etr_edf3 {
+	unsigned int rc		: 8;	/* failure reason code */
+	unsigned int _pad0	: 3;	/* must be 000 */
+	unsigned int c		: 1;	/* ETR coupled bit */
+	unsigned int tc		: 4;	/* ETR type code */
+	unsigned int blto	: 8;	/* biased local time offset */
+					/* (blto - 128) * 15 = minutes */
+	unsigned int buo	: 8;	/* biased utc offset */
+					/* (buo - 128) = leap seconds */
+} __attribute__ ((packed));
+
+struct etr_edf4 {
+	unsigned int ed		: 8;	/* ETS device dependent data */
+	unsigned int _pad0	: 1;	/* must be 0 */
+	unsigned int buc	: 5;	/* biased ut1 correction */
+					/* (buc - 16) * 0.1 seconds */
+	unsigned int em		: 6;	/* ETS error magnitude */
+	unsigned int dc		: 6;	/* ETS drift code */
+	unsigned int sc		: 6;	/* ETS steering code */
+} __attribute__ ((packed));
+
+/*
+ * ETR attachment information block, two formats
+ * format 1 has 4 reserved words with a size of 64 bytes
+ * format 2 has 16 reserved words with a size of 96 bytes
+ */
+struct etr_aib {
+	struct etr_esw esw;
+	struct etr_slsw slsw;
+	unsigned long long tsp;
+	struct etr_edf1 edf1;
+	struct etr_edf2 edf2;
+	struct etr_edf3 edf3;
+	struct etr_edf4 edf4;
+	unsigned int reserved[16];
+} __attribute__ ((packed,aligned(8)));
+
+/* ETR interruption parameter */
+struct etr_interruption_parameter {
+	unsigned int _pad0	: 8;
+	unsigned int pc0	: 1;	/* port 0 state change */
+	unsigned int pc1	: 1;	/* port 1 state change */
+	unsigned int _pad1	: 3;
+	unsigned int eai	: 1;	/* ETR alert indication */
+	unsigned int _pad2	: 18;
+} __attribute__ ((packed));
+
+/* Query TOD offset result */
+struct etr_ptff_qto {
+	unsigned long long physical_clock;
+	unsigned long long tod_offset;
+	unsigned long long logical_tod_offset;
+	unsigned long long tod_epoch_difference;
+} __attribute__ ((packed));
+
+/* Inline assembly helper functions */
+static inline int etr_setr(struct etr_eacr *ctrl)
+{
+	int rc = -ENOSYS;
+
+	asm volatile(
+		"	.insn	s,0xb2160000,0(%2)\n"
+		"0:	la	%0,0\n"
+		"1:\n"
+		EX_TABLE(0b,1b)
+		: "+d" (rc) : "m" (*ctrl), "a" (ctrl));
+	return rc;
+}
+
+/* Stores a format 1 aib with 64 bytes */
+static inline int etr_stetr(struct etr_aib *aib)
+{
+	int rc = -ENOSYS;
+
+	asm volatile(
+		"	.insn	s,0xb2170000,0(%2)\n"
+		"0:	la	%0,0\n"
+		"1:\n"
+		EX_TABLE(0b,1b)
+		: "+d" (rc) : "m" (*aib), "a" (aib));
+	return rc;
+}
+
+/* Stores a format 2 aib with 96 bytes for specified port */
+static inline int etr_steai(struct etr_aib *aib, unsigned int func)
+{
+	register unsigned int reg0 asm("0") = func;
+	int rc = -ENOSYS;
+
+	asm volatile(
+		"	.insn	s,0xb2b30000,0(%2)\n"
+		"0:	la	%0,0\n"
+		"1:\n"
+		EX_TABLE(0b,1b)
+		: "+d" (rc) : "m" (*aib), "a" (aib), "d" (reg0));
+	return rc;
+}
+
+/* Function codes for the steai instruction. */
+#define ETR_STEAI_STEPPING_PORT		0x10
+#define ETR_STEAI_ALTERNATE_PORT	0x11
+#define ETR_STEAI_PORT_0		0x12
+#define ETR_STEAI_PORT_1		0x13
+
+static inline int etr_ptff(void *ptff_block, unsigned int func)
+{
+	register unsigned int reg0 asm("0") = func;
+	register unsigned long reg1 asm("1") = (unsigned long) ptff_block;
+	int rc = -ENOSYS;
+
+	asm volatile(
+		"	.word	0x0104\n"
+		"	ipm	%0\n"
+		"	srl	%0,28\n"
+		: "=d" (rc), "=m" (ptff_block)
+		: "d" (reg0), "d" (reg1), "m" (ptff_block) : "cc");
+	return rc;
+}
+
+/* Function codes for the ptff instruction. */
+#define ETR_PTFF_QAF	0x00	/* query available functions */
+#define ETR_PTFF_QTO	0x01	/* query tod offset */
+#define ETR_PTFF_QSI	0x02	/* query steering information */
+#define ETR_PTFF_ATO	0x40	/* adjust tod offset */
+#define ETR_PTFF_STO	0x41	/* set tod offset */
+#define ETR_PTFF_SFS	0x42	/* set fine steering rate */
+#define ETR_PTFF_SGS	0x43	/* set gross steering rate */
+
+/* Functions needed by the machine check handler */
+extern void etr_switch_to_local(void);
+extern void etr_sync_check(void);
+
+#endif /* __S390_ETR_H */
diff --git a/include/asm-s390/hardirq.h b/include/asm-s390/hardirq.h
index c2f6a87..31beb18 100644
--- a/include/asm-s390/hardirq.h
+++ b/include/asm-s390/hardirq.h
@@ -32,6 +32,6 @@
 
 #define HARDIRQ_BITS	8
 
-extern void account_ticks(void);
+extern void account_ticks(u64 time);
 
 #endif /* __ASM_HARDIRQ_H */
diff --git a/include/asm-s390/io.h b/include/asm-s390/io.h
index efb7de9..a4c2d55 100644
--- a/include/asm-s390/io.h
+++ b/include/asm-s390/io.h
@@ -28,11 +28,7 @@
 {
 	unsigned long real_address;
 	asm volatile(
-#ifndef __s390x__
 		 "	lra	%0,0(%1)\n"
-#else /* __s390x__ */
-		 "	lrag	%0,0(%1)\n"
-#endif /* __s390x__ */
 		 "	jz	0f\n"
 		 "	la	%0,0\n"
                  "0:"
diff --git a/include/asm-s390/kdebug.h b/include/asm-s390/kdebug.h
index 40cc680..1b50f89 100644
--- a/include/asm-s390/kdebug.h
+++ b/include/asm-s390/kdebug.h
@@ -26,7 +26,6 @@
 extern int unregister_page_fault_notifier(struct notifier_block *);
 extern struct atomic_notifier_head s390die_chain;
 
-
 enum die_val {
 	DIE_OOPS = 1,
 	DIE_BPT,
@@ -56,4 +55,6 @@
 	return atomic_notifier_call_chain(&s390die_chain, val, &args);
 }
 
+extern void die(const char *, struct pt_regs *, long);
+
 #endif
diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h
index 74f7389..4a31d0a 100644
--- a/include/asm-s390/lowcore.h
+++ b/include/asm-s390/lowcore.h
@@ -220,7 +220,8 @@
 	__u32        kernel_asce;              /* 0xc4c */
 	__u32        user_asce;                /* 0xc50 */
 	__u32        panic_stack;              /* 0xc54 */
-	__u8         pad10[0xc60-0xc58];       /* 0xc58 */
+	__u32	     user_exec_asce;	       /* 0xc58 */
+	__u8	     pad10[0xc60-0xc5c];       /* 0xc5c */
 	/* entry.S sensitive area start */
 	struct       cpuinfo_S390 cpu_data;    /* 0xc60 */
 	__u32        ipl_device;               /* 0xc7c */
@@ -310,7 +311,8 @@
 	__u64        kernel_asce;              /* 0xd58 */
 	__u64        user_asce;                /* 0xd60 */
 	__u64        panic_stack;              /* 0xd68 */
-	__u8         pad10[0xd80-0xd70];       /* 0xd70 */
+	__u64	     user_exec_asce;	       /* 0xd70 */
+	__u8	     pad10[0xd80-0xd78];       /* 0xd78 */
 	/* entry.S sensitive area start */
 	struct       cpuinfo_S390 cpu_data;    /* 0xd80 */
 	__u32        ipl_device;               /* 0xdb8 */
diff --git a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h
index bcf24a8..1d21da2 100644
--- a/include/asm-s390/mmu_context.h
+++ b/include/asm-s390/mmu_context.h
@@ -9,6 +9,7 @@
 #ifndef __S390_MMU_CONTEXT_H
 #define __S390_MMU_CONTEXT_H
 
+#include <asm/pgalloc.h>
 /*
  * get a new mmu context.. S390 don't know about contexts.
  */
@@ -16,29 +17,44 @@
 
 #define destroy_context(mm)             do { } while (0)
 
+#ifndef __s390x__
+#define LCTL_OPCODE "lctl"
+#define PGTABLE_BITS (_SEGMENT_TABLE|USER_STD_MASK)
+#else
+#define LCTL_OPCODE "lctlg"
+#define PGTABLE_BITS (_REGION_TABLE|USER_STD_MASK)
+#endif
+
 static inline void enter_lazy_tlb(struct mm_struct *mm,
                                   struct task_struct *tsk)
 {
 }
 
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
-                             struct task_struct *tsk)
+			     struct task_struct *tsk)
 {
-        if (prev != next) {
-#ifndef __s390x__
-	        S390_lowcore.user_asce = (__pa(next->pgd)&PAGE_MASK) |
-                      (_SEGMENT_TABLE|USER_STD_MASK);
-                /* Load home space page table origin. */
-                asm volatile("lctl  13,13,%0"
-			     : : "m" (S390_lowcore.user_asce) );
-#else /* __s390x__ */
-                S390_lowcore.user_asce = (__pa(next->pgd) & PAGE_MASK) |
-			(_REGION_TABLE|USER_STD_MASK);
-		/* Load home space page table origin. */
-		asm volatile("lctlg  13,13,%0"
-			     : : "m" (S390_lowcore.user_asce) );
-#endif /* __s390x__ */
-        }
+	pgd_t *shadow_pgd = get_shadow_pgd(next->pgd);
+
+	if (prev != next) {
+		S390_lowcore.user_asce = (__pa(next->pgd) & PAGE_MASK) |
+					 PGTABLE_BITS;
+		if (shadow_pgd) {
+			/* Load primary/secondary space page table origin. */
+			S390_lowcore.user_exec_asce =
+				(__pa(shadow_pgd) & PAGE_MASK) | PGTABLE_BITS;
+			asm volatile(LCTL_OPCODE" 1,1,%0\n"
+				     LCTL_OPCODE" 7,7,%1"
+				     : : "m" (S390_lowcore.user_exec_asce),
+					 "m" (S390_lowcore.user_asce) );
+		} else if (switch_amode) {
+			/* Load primary space page table origin. */
+			asm volatile(LCTL_OPCODE" 1,1,%0"
+				     : : "m" (S390_lowcore.user_asce) );
+		} else
+			/* Load home space page table origin. */
+			asm volatile(LCTL_OPCODE" 13,13,%0"
+				     : : "m" (S390_lowcore.user_asce) );
+	}
 	cpu_set(smp_processor_id(), next->cpu_vm_mask);
 }
 
@@ -51,4 +67,4 @@
 	set_fs(current->thread.mm_segment);
 }
 
-#endif
+#endif /* __S390_MMU_CONTEXT_H */
diff --git a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h
index 0707a7e..56c8a6c 100644
--- a/include/asm-s390/pgalloc.h
+++ b/include/asm-s390/pgalloc.h
@@ -47,6 +47,17 @@
 
 	if (!pgd)
 		return NULL;
+	if (s390_noexec) {
+		pgd_t *shadow_pgd = (pgd_t *)
+			__get_free_pages(GFP_KERNEL, PGD_ALLOC_ORDER);
+		struct page *page = virt_to_page(pgd);
+
+		if (!shadow_pgd) {
+			free_pages((unsigned long) pgd, PGD_ALLOC_ORDER);
+			return NULL;
+		}
+		page->lru.next = (void *) shadow_pgd;
+	}
 	for (i = 0; i < PTRS_PER_PGD; i++)
 #ifndef __s390x__
 		pmd_clear(pmd_offset(pgd + i, i*PGDIR_SIZE));
@@ -58,6 +69,10 @@
 
 static inline void pgd_free(pgd_t *pgd)
 {
+	pgd_t *shadow_pgd = get_shadow_pgd(pgd);
+
+	if (shadow_pgd)
+		free_pages((unsigned long) shadow_pgd, PGD_ALLOC_ORDER);
 	free_pages((unsigned long) pgd, PGD_ALLOC_ORDER);
 }
 
@@ -71,6 +86,7 @@
 #define pmd_free(x)                     do { } while (0)
 #define __pmd_free_tlb(tlb,x)		do { } while (0)
 #define pgd_populate(mm, pmd, pte)      BUG()
+#define pgd_populate_kernel(mm, pmd, pte)	BUG()
 #else /* __s390x__ */
 static inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
 {
@@ -79,6 +95,17 @@
 
 	if (!pmd)
 		return NULL;
+	if (s390_noexec) {
+		pmd_t *shadow_pmd = (pmd_t *)
+			__get_free_pages(GFP_KERNEL, PMD_ALLOC_ORDER);
+		struct page *page = virt_to_page(pmd);
+
+		if (!shadow_pmd) {
+			free_pages((unsigned long) pmd, PMD_ALLOC_ORDER);
+			return NULL;
+		}
+		page->lru.next = (void *) shadow_pmd;
+	}
 	for (i=0; i < PTRS_PER_PMD; i++)
 		pmd_clear(pmd + i);
 	return pmd;
@@ -86,6 +113,10 @@
 
 static inline void pmd_free (pmd_t *pmd)
 {
+	pmd_t *shadow_pmd = get_shadow_pmd(pmd);
+
+	if (shadow_pmd)
+		free_pages((unsigned long) shadow_pmd, PMD_ALLOC_ORDER);
 	free_pages((unsigned long) pmd, PMD_ALLOC_ORDER);
 }
 
@@ -95,11 +126,22 @@
 		pmd_free(pmd);			\
 	 } while (0)
 
-static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
+static inline void
+pgd_populate_kernel(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
 {
 	pgd_val(*pgd) = _PGD_ENTRY | __pa(pmd);
 }
 
+static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
+{
+	pgd_t *shadow_pgd = get_shadow_pgd(pgd);
+	pmd_t *shadow_pmd = get_shadow_pmd(pmd);
+
+	if (shadow_pgd && shadow_pmd)
+		pgd_populate_kernel(mm, shadow_pgd, shadow_pmd);
+	pgd_populate_kernel(mm, pgd, pmd);
+}
+
 #endif /* __s390x__ */
 
 static inline void 
@@ -119,7 +161,13 @@
 static inline void
 pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *page)
 {
-	pmd_populate_kernel(mm, pmd, (pte_t *)page_to_phys(page));
+	pte_t *pte = (pte_t *)page_to_phys(page);
+	pmd_t *shadow_pmd = get_shadow_pmd(pmd);
+	pte_t *shadow_pte = get_shadow_pte(pte);
+
+	pmd_populate_kernel(mm, pmd, pte);
+	if (shadow_pmd && shadow_pte)
+		pmd_populate_kernel(mm, shadow_pmd, shadow_pte);
 }
 
 /*
@@ -133,6 +181,17 @@
 
 	if (!pte)
 		return NULL;
+	if (s390_noexec) {
+		pte_t *shadow_pte = (pte_t *)
+			__get_free_page(GFP_KERNEL|__GFP_REPEAT);
+		struct page *page = virt_to_page(pte);
+
+		if (!shadow_pte) {
+			free_page((unsigned long) pte);
+			return NULL;
+		}
+		page->lru.next = (void *) shadow_pte;
+	}
 	for (i=0; i < PTRS_PER_PTE; i++) {
 		pte_clear(mm, vmaddr, pte + i);
 		vmaddr += PAGE_SIZE;
@@ -151,14 +210,30 @@
 
 static inline void pte_free_kernel(pte_t *pte)
 {
-        free_page((unsigned long) pte);
+	pte_t *shadow_pte = get_shadow_pte(pte);
+
+	if (shadow_pte)
+		free_page((unsigned long) shadow_pte);
+	free_page((unsigned long) pte);
 }
 
 static inline void pte_free(struct page *pte)
 {
-        __free_page(pte);
+	struct page *shadow_page = get_shadow_page(pte);
+
+	if (shadow_page)
+		__free_page(shadow_page);
+	__free_page(pte);
 }
 
-#define __pte_free_tlb(tlb,pte) tlb_remove_page(tlb,pte)
+#define __pte_free_tlb(tlb, pte)					\
+({									\
+	struct mmu_gather *__tlb = (tlb);				\
+	struct page *__pte = (pte);					\
+	struct page *shadow_page = get_shadow_page(__pte);		\
+	if (shadow_page)						\
+		tlb_remove_page(__tlb, shadow_page);			\
+	tlb_remove_page(__tlb, __pte);					\
+})
 
 #endif /* _S390_PGALLOC_H */
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
index ae61aca..13c1654 100644
--- a/include/asm-s390/pgtable.h
+++ b/include/asm-s390/pgtable.h
@@ -40,6 +40,7 @@
 
 extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096)));
 extern void paging_init(void);
+extern void vmem_map_init(void);
 
 /*
  * The S390 doesn't have any external MMU info: the kernel page
@@ -223,6 +224,8 @@
 #define _PAGE_TYPE_FILE		0x601	/* bit 0x002 is used for offset !! */
 #define _PAGE_TYPE_RO		0x200
 #define _PAGE_TYPE_RW		0x000
+#define _PAGE_TYPE_EX_RO	0x202
+#define _PAGE_TYPE_EX_RW	0x002
 
 /*
  * PTE type bits are rather complicated. handle_pte_fault uses pte_present,
@@ -243,11 +246,13 @@
  * _PAGE_TYPE_FILE	11?1   ->   11?1
  * _PAGE_TYPE_RO	0100   ->   1100
  * _PAGE_TYPE_RW	0000   ->   1000
+ * _PAGE_TYPE_EX_RO	0110   ->   1110
+ * _PAGE_TYPE_EX_RW	0010   ->   1010
  *
- * pte_none is true for bits combinations 1000, 1100
+ * pte_none is true for bits combinations 1000, 1010, 1100, 1110
  * pte_present is true for bits combinations 0000, 0010, 0100, 0110, 1001
  * pte_file is true for bits combinations 1101, 1111
- * swap pte is 1011 and 0001, 0011, 0101, 0111, 1010 and 1110 are invalid.
+ * swap pte is 1011 and 0001, 0011, 0101, 0111 are invalid.
  */
 
 #ifndef __s390x__
@@ -312,33 +317,100 @@
 #define PAGE_NONE	__pgprot(_PAGE_TYPE_NONE)
 #define PAGE_RO		__pgprot(_PAGE_TYPE_RO)
 #define PAGE_RW		__pgprot(_PAGE_TYPE_RW)
+#define PAGE_EX_RO	__pgprot(_PAGE_TYPE_EX_RO)
+#define PAGE_EX_RW	__pgprot(_PAGE_TYPE_EX_RW)
 
 #define PAGE_KERNEL	PAGE_RW
 #define PAGE_COPY	PAGE_RO
 
 /*
- * The S390 can't do page protection for execute, and considers that the
- * same are read. Also, write permissions imply read permissions. This is
- * the closest we can get..
+ * Dependent on the EXEC_PROTECT option s390 can do execute protection.
+ * Write permission always implies read permission. In theory with a
+ * primary/secondary page table execute only can be implemented but
+ * it would cost an additional bit in the pte to distinguish all the
+ * different pte types. To avoid that execute permission currently
+ * implies read permission as well.
  */
          /*xwr*/
 #define __P000	PAGE_NONE
 #define __P001	PAGE_RO
 #define __P010	PAGE_RO
 #define __P011	PAGE_RO
-#define __P100	PAGE_RO
-#define __P101	PAGE_RO
-#define __P110	PAGE_RO
-#define __P111	PAGE_RO
+#define __P100	PAGE_EX_RO
+#define __P101	PAGE_EX_RO
+#define __P110	PAGE_EX_RO
+#define __P111	PAGE_EX_RO
 
 #define __S000	PAGE_NONE
 #define __S001	PAGE_RO
 #define __S010	PAGE_RW
 #define __S011	PAGE_RW
-#define __S100	PAGE_RO
-#define __S101	PAGE_RO
-#define __S110	PAGE_RW
-#define __S111	PAGE_RW
+#define __S100	PAGE_EX_RO
+#define __S101	PAGE_EX_RO
+#define __S110	PAGE_EX_RW
+#define __S111	PAGE_EX_RW
+
+#ifndef __s390x__
+# define PMD_SHADOW_SHIFT	1
+# define PGD_SHADOW_SHIFT	1
+#else /* __s390x__ */
+# define PMD_SHADOW_SHIFT	2
+# define PGD_SHADOW_SHIFT	2
+#endif /* __s390x__ */
+
+static inline struct page *get_shadow_page(struct page *page)
+{
+	if (s390_noexec && !list_empty(&page->lru))
+		return virt_to_page(page->lru.next);
+	return NULL;
+}
+
+static inline pte_t *get_shadow_pte(pte_t *ptep)
+{
+	unsigned long pteptr = (unsigned long) (ptep);
+
+	if (s390_noexec) {
+		unsigned long offset = pteptr & (PAGE_SIZE - 1);
+		void *addr = (void *) (pteptr ^ offset);
+		struct page *page = virt_to_page(addr);
+		if (!list_empty(&page->lru))
+			return (pte_t *) ((unsigned long) page->lru.next |
+								offset);
+	}
+	return NULL;
+}
+
+static inline pmd_t *get_shadow_pmd(pmd_t *pmdp)
+{
+	unsigned long pmdptr = (unsigned long) (pmdp);
+
+	if (s390_noexec) {
+		unsigned long offset = pmdptr &
+				((PAGE_SIZE << PMD_SHADOW_SHIFT) - 1);
+		void *addr = (void *) (pmdptr ^ offset);
+		struct page *page = virt_to_page(addr);
+		if (!list_empty(&page->lru))
+			return (pmd_t *) ((unsigned long) page->lru.next |
+								offset);
+	}
+	return NULL;
+}
+
+static inline pgd_t *get_shadow_pgd(pgd_t *pgdp)
+{
+	unsigned long pgdptr = (unsigned long) (pgdp);
+
+	if (s390_noexec) {
+		unsigned long offset = pgdptr &
+				((PAGE_SIZE << PGD_SHADOW_SHIFT) - 1);
+		void *addr = (void *) (pgdptr ^ offset);
+		struct page *page = virt_to_page(addr);
+		if (!list_empty(&page->lru))
+			return (pgd_t *) ((unsigned long) page->lru.next |
+								offset);
+	}
+	return NULL;
+}
 
 /*
  * Certain architectures need to do special things when PTEs
@@ -347,7 +419,16 @@
  */
 static inline void set_pte(pte_t *pteptr, pte_t pteval)
 {
+	pte_t *shadow_pte = get_shadow_pte(pteptr);
+
 	*pteptr = pteval;
+	if (shadow_pte) {
+		if (!(pte_val(pteval) & _PAGE_INVALID) &&
+		    (pte_val(pteval) & _PAGE_SWX))
+			pte_val(*shadow_pte) = pte_val(pteval) | _PAGE_RO;
+		else
+			pte_val(*shadow_pte) = _PAGE_TYPE_EMPTY;
+	}
 }
 #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
@@ -465,7 +546,7 @@
 
 static inline void pgd_clear(pgd_t * pgdp)      { }
 
-static inline void pmd_clear(pmd_t * pmdp)
+static inline void pmd_clear_kernel(pmd_t * pmdp)
 {
 	pmd_val(pmdp[0]) = _PAGE_TABLE_INV;
 	pmd_val(pmdp[1]) = _PAGE_TABLE_INV;
@@ -473,24 +554,55 @@
 	pmd_val(pmdp[3]) = _PAGE_TABLE_INV;
 }
 
+static inline void pmd_clear(pmd_t * pmdp)
+{
+	pmd_t *shadow_pmd = get_shadow_pmd(pmdp);
+
+	pmd_clear_kernel(pmdp);
+	if (shadow_pmd)
+		pmd_clear_kernel(shadow_pmd);
+}
+
 #else /* __s390x__ */
 
-static inline void pgd_clear(pgd_t * pgdp)
+static inline void pgd_clear_kernel(pgd_t * pgdp)
 {
 	pgd_val(*pgdp) = _PGD_ENTRY_INV | _PGD_ENTRY;
 }
 
-static inline void pmd_clear(pmd_t * pmdp)
+static inline void pgd_clear(pgd_t * pgdp)
+{
+	pgd_t *shadow_pgd = get_shadow_pgd(pgdp);
+
+	pgd_clear_kernel(pgdp);
+	if (shadow_pgd)
+		pgd_clear_kernel(shadow_pgd);
+}
+
+static inline void pmd_clear_kernel(pmd_t * pmdp)
 {
 	pmd_val(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY;
 	pmd_val1(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY;
 }
 
+static inline void pmd_clear(pmd_t * pmdp)
+{
+	pmd_t *shadow_pmd = get_shadow_pmd(pmdp);
+
+	pmd_clear_kernel(pmdp);
+	if (shadow_pmd)
+		pmd_clear_kernel(shadow_pmd);
+}
+
 #endif /* __s390x__ */
 
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
+	pte_t *shadow_pte = get_shadow_pte(ptep);
+
 	pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+	if (shadow_pte)
+		pte_val(*shadow_pte) = _PAGE_TYPE_EMPTY;
 }
 
 /*
@@ -608,8 +720,11 @@
 		 unsigned long address, pte_t *ptep)
 {
 	pte_t pte = *ptep;
+	pte_t *shadow_pte = get_shadow_pte(ptep);
 
 	__ptep_ipte(address, ptep);
+	if (shadow_pte)
+		__ptep_ipte(address, shadow_pte);
 	return pte;
 }
 
diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h
index cbbedc6..4c1b739 100644
--- a/include/asm-s390/processor.h
+++ b/include/asm-s390/processor.h
@@ -50,6 +50,7 @@
         unsigned long pgtable_cache_sz;
 };
 
+extern void s390_adjust_jiffies(void);
 extern void print_cpu_info(struct cpuinfo_S390 *);
 
 /* Lazy FPU handling on uni-processor */
@@ -144,7 +145,8 @@
 #ifndef __s390x__
 
 #define start_thread(regs, new_psw, new_stackp) do {            \
-        regs->psw.mask  = PSW_USER_BITS;                        \
+	set_fs(USER_DS);					\
+	regs->psw.mask	= psw_user_bits;			\
         regs->psw.addr  = new_psw | PSW_ADDR_AMODE;             \
         regs->gprs[15]  = new_stackp ;                          \
 } while (0)
@@ -152,13 +154,15 @@
 #else /* __s390x__ */
 
 #define start_thread(regs, new_psw, new_stackp) do {            \
-        regs->psw.mask  = PSW_USER_BITS;                        \
+	set_fs(USER_DS);					\
+	regs->psw.mask	= psw_user_bits;			\
         regs->psw.addr  = new_psw;                              \
         regs->gprs[15]  = new_stackp;                           \
 } while (0)
 
 #define start_thread31(regs, new_psw, new_stackp) do {          \
-	regs->psw.mask  = PSW_USER32_BITS;			\
+	set_fs(USER_DS);					\
+	regs->psw.mask	= psw_user32_bits;			\
         regs->psw.addr  = new_psw;                              \
         regs->gprs[15]  = new_stackp;                           \
 } while (0)
@@ -201,9 +205,8 @@
 static inline void cpu_relax(void)
 {
 	if (MACHINE_HAS_DIAG44)
-		asm volatile("diag 0,0,68" : : : "memory");
-	else
-		barrier();
+		asm volatile("diag 0,0,68");
+	barrier();
 }
 
 /*
@@ -328,6 +331,18 @@
 }
 
 /*
+ * Basic Machine Check/Program Check Handler.
+ */
+
+extern void s390_base_mcck_handler(void);
+extern void s390_base_pgm_handler(void);
+extern void s390_base_ext_handler(void);
+
+extern void (*s390_base_mcck_handler_fn)(void);
+extern void (*s390_base_pgm_handler_fn)(void);
+extern void (*s390_base_ext_handler_fn)(void);
+
+/*
  * CPU idle notifier chain.
  */
 #define CPU_IDLE	0
diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h
index 7b768c5..fa6ca87 100644
--- a/include/asm-s390/ptrace.h
+++ b/include/asm-s390/ptrace.h
@@ -266,17 +266,12 @@
 #define PSW_ASC_SECONDARY	0x0000800000000000UL
 #define PSW_ASC_HOME		0x0000C00000000000UL
 
-#define PSW_USER32_BITS (PSW_BASE32_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \
-			 PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \
-			 PSW_MASK_PSTATE | PSW_DEFAULT_KEY)
+extern long psw_user32_bits;
 
 #endif /* __s390x__ */
 
-#define PSW_KERNEL_BITS	(PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | \
-			 PSW_MASK_MCHECK | PSW_DEFAULT_KEY)
-#define PSW_USER_BITS	(PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \
-			 PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \
-			 PSW_MASK_PSTATE | PSW_DEFAULT_KEY)
+extern long psw_kernel_bits;
+extern long psw_user_bits;
 
 /* This macro merges a NEW PSW mask specified by the user into
    the currently active PSW mask CURRENT, modifying only those
diff --git a/include/asm-s390/reset.h b/include/asm-s390/reset.h
index 532e65a..f584f4a 100644
--- a/include/asm-s390/reset.h
+++ b/include/asm-s390/reset.h
@@ -18,7 +18,4 @@
 extern void register_reset_call(struct reset_call *reset);
 extern void unregister_reset_call(struct reset_call *reset);
 extern void s390_reset_system(void);
-extern void (*s390_reset_mcck_handler)(void);
-extern void (*s390_reset_pgm_handler)(void);
-
 #endif /* _ASM_S390_RESET_H */
diff --git a/include/asm-s390/sclp.h b/include/asm-s390/sclp.h
new file mode 100644
index 0000000..468b970
--- /dev/null
+++ b/include/asm-s390/sclp.h
@@ -0,0 +1,39 @@
+/*
+ *  include/asm-s390/sclp.h
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#ifndef _ASM_S390_SCLP_H
+#define _ASM_S390_SCLP_H
+
+#include <linux/types.h>
+
+struct sccb_header {
+	u16	length;
+	u8	function_code;
+	u8	control_mask[3];
+	u16	response_code;
+} __attribute__((packed));
+
+#define LOADPARM_LEN 8
+
+struct sclp_readinfo_sccb {
+	struct	sccb_header header;	/* 0-7 */
+	u16	rnmax;			/* 8-9 */
+	u8	rnsize;			/* 10 */
+	u8	_reserved0[24 - 11];	/* 11-23 */
+	u8	loadparm[LOADPARM_LEN];	/* 24-31 */
+	u8	_reserved1[91 - 32];	/* 32-90 */
+	u8	flags;			/* 91 */
+	u8	_reserved2[100 - 92];	/* 92-99 */
+	u32	rnsize2;		/* 100-103 */
+	u64	rnmax2;			/* 104-111 */
+	u8	_reserved3[4096 - 112];	/* 112-4095 */
+} __attribute__((packed, aligned(4096)));
+
+extern struct sclp_readinfo_sccb s390_readinfo_sccb;
+extern void sclp_readinfo_early(void);
+
+#endif /* _ASM_S390_SCLP_H */
diff --git a/include/asm-s390/sections.h b/include/asm-s390/sections.h
index 3a0b8ff..1c5a2c4 100644
--- a/include/asm-s390/sections.h
+++ b/include/asm-s390/sections.h
@@ -3,4 +3,6 @@
 
 #include <asm-generic/sections.h>
 
+extern char _eshared[];
+
 #endif
diff --git a/include/asm-s390/setup.h b/include/asm-s390/setup.h
index 9574fe8..3388bb5 100644
--- a/include/asm-s390/setup.h
+++ b/include/asm-s390/setup.h
@@ -42,6 +42,18 @@
 
 extern struct mem_chunk memory_chunk[];
 
+#ifdef CONFIG_S390_SWITCH_AMODE
+extern unsigned int switch_amode;
+#else
+#define switch_amode	(0)
+#endif
+
+#ifdef CONFIG_S390_EXEC_PROTECT
+extern unsigned int s390_noexec;
+#else
+#define s390_noexec	(0)
+#endif
+
 /*
  * Machine features detected in head.S
  */
@@ -74,6 +86,9 @@
 extern unsigned int console_devno;
 extern unsigned int console_irq;
 
+extern char vmhalt_cmd[];
+extern char vmpoff_cmd[];
+
 #define CONSOLE_IS_UNDEFINED	(console_mode == 0)
 #define CONSOLE_IS_SCLP		(console_mode == 1)
 #define CONSOLE_IS_3215		(console_mode == 2)
@@ -141,13 +156,19 @@
 extern u32 ipl_flags;
 extern u16 ipl_devno;
 
-void do_reipl(void);
+extern void do_reipl(void);
+extern void ipl_save_parameters(void);
 
 enum {
 	IPL_DEVNO_VALID	= 1,
 	IPL_PARMBLOCK_VALID = 2,
+	IPL_NSS_VALID = 4,
 };
 
+#define NSS_NAME_SIZE	8
+
+extern char kernel_nss_name[];
+
 #define IPL_PARMBLOCK_START	((struct ipl_parameter_block *) \
 				 IPL_PARMBLOCK_ORIGIN)
 #define IPL_PARMBLOCK_SIZE	(IPL_PARMBLOCK_START->hdr.len)
diff --git a/arch/s390/math-emu/sfp-util.h b/include/asm-s390/sfp-util.h
similarity index 90%
rename from arch/s390/math-emu/sfp-util.h
rename to include/asm-s390/sfp-util.h
index 5b6ca45..8cabcd2 100644
--- a/arch/s390/math-emu/sfp-util.h
+++ b/include/asm-s390/sfp-util.h
@@ -52,12 +52,12 @@
 })
 
 #define udiv_qrnnd(q, r, n1, n0, d)			\
-  do { unsigned long __r;				\
+  do { unsigned int __r;				\
     (q) = __udiv_qrnnd (&__r, (n1), (n0), (d));		\
     (r) = __r;						\
   } while (0)
-extern unsigned long __udiv_qrnnd (unsigned long *, unsigned long,
-				   unsigned long , unsigned long);
+extern unsigned long __udiv_qrnnd (unsigned int *, unsigned int,
+				   unsigned int , unsigned int);
 
 #define UDIV_NEEDS_NORMALIZATION 0
 
diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h
index 7097c96..b957e4c 100644
--- a/include/asm-s390/smp.h
+++ b/include/asm-s390/smp.h
@@ -31,6 +31,10 @@
 	__u16      cpu;
 } sigp_info;
 
+extern void machine_restart_smp(char *);
+extern void machine_halt_smp(void);
+extern void machine_power_off_smp(void);
+
 extern void smp_setup_cpu_possible_map(void);
 extern int smp_call_function_on(void (*func) (void *info), void *info,
 				int nonatomic, int wait, int cpu);
@@ -106,7 +110,7 @@
 static inline void smp_send_stop(void)
 {
 	/* Disable all interrupts/machine checks */
-	__load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK);
+	__load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK);
 }
 
 #define smp_cpu_not_running(cpu)	1
diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h
index bd0b05a..bbe137c 100644
--- a/include/asm-s390/system.h
+++ b/include/asm-s390/system.h
@@ -373,8 +373,8 @@
 	__load_psw_mask(mask | (__raw_local_irq_stosm(0x00) & ~(-1UL >> 8)));
 }
 
-#define local_mcck_enable()  __set_psw_mask(PSW_KERNEL_BITS)
-#define local_mcck_disable() __set_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK)
+#define local_mcck_enable()  __set_psw_mask(psw_kernel_bits)
+#define local_mcck_disable() __set_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK)
 
 #ifdef CONFIG_SMP
 
diff --git a/include/asm-s390/tape390.h b/include/asm-s390/tape390.h
index f1d66ba..884fba4 100644
--- a/include/asm-s390/tape390.h
+++ b/include/asm-s390/tape390.h
@@ -1,11 +1,11 @@
 /*************************************************************************
  *
  * tape390.h
- *         enables user programs to display messages on the tape device
+ *	   enables user programs to display messages and control encryption
+ *	   on s390 tape devices
  *
- *  S390 and zSeries version
- *         Copyright (C) 2001 IBM Corporation
- *         Author(s): Despina Papadopoulou <despina_p@de.ibm.com>
+ *	   Copyright IBM Corp. 2001,2006
+ *	   Author(s): Michael Holzheu <holzheu@de.ibm.com>
  *
  *************************************************************************/
 
@@ -36,4 +36,68 @@
         char message2[8];
 } display_struct;
 
+/*
+ * Tape encryption support
+ */
+
+struct tape390_crypt_info {
+	char capability;
+	char status;
+	char medium_status;
+} __attribute__ ((packed));
+
+
+/* Macros for "capable" field */
+#define TAPE390_CRYPT_SUPPORTED_MASK 0x01
+#define TAPE390_CRYPT_SUPPORTED(x) \
+	((x.capability & TAPE390_CRYPT_SUPPORTED_MASK))
+
+/* Macros for "status" field */
+#define TAPE390_CRYPT_ON_MASK 0x01
+#define TAPE390_CRYPT_ON(x) (((x.status) & TAPE390_CRYPT_ON_MASK))
+
+/* Macros for "medium status" field */
+#define TAPE390_MEDIUM_LOADED_MASK 0x01
+#define TAPE390_MEDIUM_ENCRYPTED_MASK 0x02
+#define TAPE390_MEDIUM_ENCRYPTED(x) \
+	(((x.medium_status) & TAPE390_MEDIUM_ENCRYPTED_MASK))
+#define TAPE390_MEDIUM_LOADED(x) \
+	(((x.medium_status) & TAPE390_MEDIUM_LOADED_MASK))
+
+/*
+ * The TAPE390_CRYPT_SET ioctl is used to switch on/off encryption.
+ * The "encryption_capable" and "tape_status" fields are ignored for this ioctl!
+ */
+#define TAPE390_CRYPT_SET _IOW('d', 2, struct tape390_crypt_info)
+
+/*
+ * The TAPE390_CRYPT_QUERY ioctl is used to query the encryption state.
+ */
+#define TAPE390_CRYPT_QUERY _IOR('d', 3, struct tape390_crypt_info)
+
+/* Values for "kekl1/2_type" and "kekl1/2_type_on_tape" fields */
+#define TAPE390_KEKL_TYPE_NONE 0
+#define TAPE390_KEKL_TYPE_LABEL 1
+#define TAPE390_KEKL_TYPE_HASH 2
+
+struct tape390_kekl {
+	unsigned char type;
+	unsigned char type_on_tape;
+	char label[65];
+} __attribute__ ((packed));
+
+struct tape390_kekl_pair {
+	struct tape390_kekl kekl[2];
+} __attribute__ ((packed));
+
+/*
+ * The TAPE390_KEKL_SET ioctl is used to set Key Encrypting Key labels.
+ */
+#define TAPE390_KEKL_SET _IOW('d', 4, struct tape390_kekl_pair)
+
+/*
+ * The TAPE390_KEKL_QUERY ioctl is used to query Key Encrypting Key labels.
+ */
+#define TAPE390_KEKL_QUERY _IOR('d', 5, struct tape390_kekl_pair)
+
 #endif 
diff --git a/include/asm-s390/timer.h b/include/asm-s390/timer.h
index 30e5cbe..adb3486 100644
--- a/include/asm-s390/timer.h
+++ b/include/asm-s390/timer.h
@@ -45,6 +45,9 @@
 extern int mod_virt_timer(struct vtimer_list *timer, __u64 expires);
 extern int del_virt_timer(struct vtimer_list *timer);
 
+extern void init_cpu_vtimer(void);
+extern void vtime_init(void);
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_S390_TIMER_H */
diff --git a/include/asm-s390/timex.h b/include/asm-s390/timex.h
index 4df4a41..98229db 100644
--- a/include/asm-s390/timex.h
+++ b/include/asm-s390/timex.h
@@ -11,6 +11,41 @@
 #ifndef _ASM_S390_TIMEX_H
 #define _ASM_S390_TIMEX_H
 
+/* Inline functions for clock register access. */
+static inline int set_clock(__u64 time)
+{
+	int cc;
+
+	asm volatile(
+		"   sck   0(%2)\n"
+		"   ipm   %0\n"
+		"   srl   %0,28\n"
+		: "=d" (cc) : "m" (time), "a" (&time) : "cc");
+	return cc;
+}
+
+static inline int store_clock(__u64 *time)
+{
+	int cc;
+
+	asm volatile(
+		"   stck  0(%2)\n"
+		"   ipm   %0\n"
+		"   srl   %0,28\n"
+		: "=d" (cc), "=m" (*time) : "a" (time) : "cc");
+	return cc;
+}
+
+static inline void set_clock_comparator(__u64 time)
+{
+	asm volatile("sckc 0(%1)" : : "m" (time), "a" (&time));
+}
+
+static inline void store_clock_comparator(__u64 *time)
+{
+	asm volatile("stckc 0(%1)" : "=m" (*time) : "a" (time));
+}
+
 #define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
 
 typedef unsigned long long cycles_t;
@@ -27,9 +62,24 @@
 	return clk;
 }
 
+static inline void get_clock_extended(void *dest)
+{
+	typedef struct { unsigned long long clk[2]; } __clock_t;
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
+	asm volatile("stcke %0" : "=Q" (*((__clock_t *)dest)) : : "cc");
+#else /* __GNUC__ */
+	asm volatile("stcke 0(%1)" : "=m" (*((__clock_t *)dest))
+				   : "a" ((__clock_t *)dest) : "cc");
+#endif /* __GNUC__ */
+}
+
 static inline cycles_t get_cycles(void)
 {
 	return (cycles_t) get_clock() >> 2;
 }
 
+int get_sync_clock(unsigned long long *clock);
+void init_cpu_timer(void);
+
 #endif
diff --git a/include/asm-s390/tlbflush.h b/include/asm-s390/tlbflush.h
index fa4dc91..66793f5 100644
--- a/include/asm-s390/tlbflush.h
+++ b/include/asm-s390/tlbflush.h
@@ -3,6 +3,7 @@
 
 #include <linux/mm.h>
 #include <asm/processor.h>
+#include <asm/pgalloc.h>
 
 /*
  * TLB flushing:
@@ -102,6 +103,14 @@
 	if (unlikely(cpus_empty(mm->cpu_vm_mask)))
 		return;
 	if (MACHINE_HAS_IDTE) {
+		pgd_t *shadow_pgd = get_shadow_pgd(mm->pgd);
+
+		if (shadow_pgd) {
+			asm volatile(
+				"	.insn	rrf,0xb98e0000,0,%0,%1,0"
+				: : "a" (2048),
+				"a" (__pa(shadow_pgd) & PAGE_MASK) : "cc" );
+		}
 		asm volatile(
 			"	.insn	rrf,0xb98e0000,0,%0,%1,0"
 			: : "a" (2048), "a" (__pa(mm->pgd)&PAGE_MASK) : "cc");
diff --git a/include/asm-s390/uaccess.h b/include/asm-s390/uaccess.h
index 73ac4e8..0235970 100644
--- a/include/asm-s390/uaccess.h
+++ b/include/asm-s390/uaccess.h
@@ -90,6 +90,8 @@
 extern struct uaccess_ops uaccess;
 extern struct uaccess_ops uaccess_std;
 extern struct uaccess_ops uaccess_mvcos;
+extern struct uaccess_ops uaccess_mvcos_switch;
+extern struct uaccess_ops uaccess_pt;
 
 static inline int __put_user_fn(size_t size, void __user *ptr, void *x)
 {
diff --git a/include/asm-sh/apm.h b/include/asm-sh/apm.h
deleted file mode 100644
index 8b091e9..0000000
--- a/include/asm-sh/apm.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2006 (c) Andriy Skulysh <askulysh@gmail.com>
- *
- * 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.
- *
- */
-
-#ifndef __ASM_SH_APM_H
-#define __ASM_SH_APM_H
-
-#define APM_AC_OFFLINE			0
-#define APM_AC_ONLINE			1
-#define APM_AC_BACKUP			2
-#define APM_AC_UNKNOWN			0xff
-
-#define APM_BATTERY_STATUS_HIGH		0
-#define APM_BATTERY_STATUS_LOW		1
-#define APM_BATTERY_STATUS_CRITICAL	2
-#define APM_BATTERY_STATUS_CHARGING	3
-#define APM_BATTERY_STATUS_NOT_PRESENT	4
-#define APM_BATTERY_STATUS_UNKNOWN	0xff
-
-#define APM_BATTERY_LIFE_UNKNOWN	0xFFFF
-#define APM_BATTERY_LIFE_MINUTES	0x8000
-#define APM_BATTERY_LIFE_VALUE_MASK	0x7FFF
-
-#define APM_BATTERY_FLAG_HIGH		(1 << 0)
-#define APM_BATTERY_FLAG_LOW		(1 << 1)
-#define APM_BATTERY_FLAG_CRITICAL	(1 << 2)
-#define APM_BATTERY_FLAG_CHARGING	(1 << 3)
-#define APM_BATTERY_FLAG_NOT_PRESENT	(1 << 7)
-#define APM_BATTERY_FLAG_UNKNOWN	0xff
-
-#define APM_UNITS_MINS			0
-#define APM_UNITS_SECS			1
-#define APM_UNITS_UNKNOWN		-1
-
-
-extern int (*apm_get_info)(char *buf, char **start, off_t fpos, int length);
-extern int apm_suspended;
-
-void apm_queue_event(apm_event_t event);
-
-#endif
diff --git a/include/asm-x86_64/acpi.h b/include/asm-x86_64/acpi.h
index 6b6fc6f..a29f050 100644
--- a/include/asm-x86_64/acpi.h
+++ b/include/asm-x86_64/acpi.h
@@ -37,7 +37,7 @@
  * Calling conventions:
  *
  * ACPI_SYSTEM_XFACE        - Interfaces to host OS (handlers, threads)
- * ACPI_EXTERNAL_XFACE      - External ACPI interfaces 
+ * ACPI_EXTERNAL_XFACE      - External ACPI interfaces
  * ACPI_INTERNAL_XFACE      - Internal ACPI interfaces
  * ACPI_INTERNAL_VAR_XFACE  - Internal variable-parameter list interfaces
  */
@@ -57,11 +57,11 @@
 int __acpi_acquire_global_lock(unsigned int *lock);
 int __acpi_release_global_lock(unsigned int *lock);
 
-#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
-	((Acq) = __acpi_acquire_global_lock((unsigned int *) GLptr))
+#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
+	((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
 
-#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \
-	((Acq) = __acpi_release_global_lock((unsigned int *) GLptr))
+#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \
+	((Acq) = __acpi_release_global_lock(&facs->global_lock))
 
 /*
  * Math helper asm macros
@@ -87,10 +87,10 @@
 extern int acpi_disabled;
 extern int acpi_pci_disabled;
 extern int acpi_ht;
-static inline void disable_acpi(void) 
-{ 
-	acpi_disabled = 1; 
-	acpi_ht = 0; 
+static inline void disable_acpi(void)
+{
+	acpi_disabled = 1;
+	acpi_ht = 0;
 	acpi_pci_disabled = 1;
 	acpi_noirq = 1;
 }
@@ -100,9 +100,9 @@
 
 extern int acpi_gsi_to_irq(u32 gsi, unsigned int *irq);
 static inline void acpi_noirq_set(void) { acpi_noirq = 1; }
-static inline void acpi_disable_pci(void) 
+static inline void acpi_disable_pci(void)
 {
-	acpi_pci_disabled = 1; 
+	acpi_pci_disabled = 1;
 	acpi_noirq_set();
 }
 extern int acpi_irq_balance_set(char *str);
@@ -136,8 +136,6 @@
 extern int acpi_disabled;
 extern int acpi_pci_disabled;
 
-extern u8 x86_acpiid_to_apicid[];
-
 #define ARCH_HAS_POWER_INIT 1
 
 extern int acpi_skip_timer_override;
diff --git a/include/asm-x86_64/io.h b/include/asm-x86_64/io.h
index 6ee9fad..f5d84bb 100644
--- a/include/asm-x86_64/io.h
+++ b/include/asm-x86_64/io.h
@@ -248,12 +248,6 @@
  */
 #define __ISA_IO_base ((char __iomem *)(PAGE_OFFSET))
 
-/*
- * Again, x86-64 does not require mem IO specific function.
- */
-
-#define eth_io_copy_and_sum(a,b,c,d)		eth_copy_and_sum((a),(void *)(b),(c),(d))
-
 /* Nothing to do */
 
 #define dma_cache_inv(_start,_size)		do { } while (0)
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
index 6d324b8..a6d2ff5 100644
--- a/include/asm-x86_64/proto.h
+++ b/include/asm-x86_64/proto.h
@@ -81,7 +81,6 @@
 extern void __show_regs(struct pt_regs * regs);
 extern void show_regs(struct pt_regs * regs);
 
-extern char *syscall32_page;
 extern void syscall32_cpu_init(void);
 
 extern void setup_node_bootmem(int nodeid, unsigned long start, unsigned long end);
diff --git a/include/asm-x86_64/swiotlb.h b/include/asm-x86_64/swiotlb.h
index ba94ab3..ab913ff 100644
--- a/include/asm-x86_64/swiotlb.h
+++ b/include/asm-x86_64/swiotlb.h
@@ -1,6 +1,5 @@
 #ifndef _ASM_SWIOTLB_H
-#define _ASM_SWTIOLB_H 1
-
+#define _ASM_SWIOTLB_H 1
 
 #include <asm/dma-mapping.h>
 
@@ -45,6 +44,7 @@
 extern int swiotlb_force;
 
 #ifdef CONFIG_SWIOTLB
+#define SWIOTLB_ARCH_NEED_ALLOC
 extern int swiotlb;
 #else
 #define swiotlb 0
@@ -52,4 +52,6 @@
 
 extern void pci_swiotlb_init(void);
 
-#endif /* _ASM_SWTIOLB_H */
+static inline void dma_mark_clean(void *addr, size_t size) {}
+
+#endif /* _ASM_SWIOTLB_H */
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index 5748aec..4e05e93 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -18,8 +18,8 @@
 struct seq_file;
 
 struct crypto_type {
-	unsigned int (*ctxsize)(struct crypto_alg *alg);
-	int (*init)(struct crypto_tfm *tfm);
+	unsigned int (*ctxsize)(struct crypto_alg *alg, u32 type, u32 mask);
+	int (*init)(struct crypto_tfm *tfm, u32 type, u32 mask);
 	void (*exit)(struct crypto_tfm *tfm);
 	void (*show)(struct seq_file *m, struct crypto_alg *alg);
 };
@@ -93,7 +93,8 @@
 int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
 		      struct crypto_instance *inst);
 void crypto_drop_spawn(struct crypto_spawn *spawn);
-struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn);
+struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
+				    u32 mask);
 
 struct crypto_alg *crypto_get_attr_alg(void *param, unsigned int len,
 				       u32 type, u32 mask);
@@ -132,11 +133,28 @@
 	return crypto_tfm_ctx_aligned(&tfm->base);
 }
 
+static inline struct crypto_cipher *crypto_spawn_cipher(
+	struct crypto_spawn *spawn)
+{
+	u32 type = CRYPTO_ALG_TYPE_CIPHER;
+	u32 mask = CRYPTO_ALG_TYPE_MASK;
+
+	return __crypto_cipher_cast(crypto_spawn_tfm(spawn, type, mask));
+}
+
 static inline struct cipher_alg *crypto_cipher_alg(struct crypto_cipher *tfm)
 {
 	return &crypto_cipher_tfm(tfm)->__crt_alg->cra_cipher;
 }
 
+static inline struct crypto_hash *crypto_spawn_hash(struct crypto_spawn *spawn)
+{
+	u32 type = CRYPTO_ALG_TYPE_HASH;
+	u32 mask = CRYPTO_ALG_TYPE_HASH_MASK;
+
+	return __crypto_hash_cast(crypto_spawn_tfm(spawn, type, mask));
+}
+
 static inline void *crypto_hash_ctx_aligned(struct crypto_hash *tfm)
 {
 	return crypto_tfm_ctx_aligned(&tfm->base);
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 157db77..683513e 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -11,6 +11,7 @@
 header-y += netfilter_bridge/
 header-y += netfilter_ipv4/
 header-y += netfilter_ipv6/
+header-y += usb/
 
 header-y += affs_hardblocks.h
 header-y += aio_abi.h
@@ -326,7 +327,6 @@
 unifdef-y += uinput.h
 unifdef-y += uio.h
 unifdef-y += unistd.h
-unifdef-y += usb_ch9.h
 unifdef-y += usbdevice_fs.h
 unifdef-y += user.h
 unifdef-y += utsname.h
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 91f1f23..815f1fb 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -53,166 +53,6 @@
 
 extern enum acpi_irq_model_id	acpi_irq_model;
 
-
-/* Root System Description Pointer (RSDP) */
-
-struct acpi_table_rsdp {
-	char			signature[8];
-	u8			checksum;
-	char			oem_id[6];
-	u8			revision;
-	u32			rsdt_address;
-} __attribute__ ((packed));
-
-struct acpi20_table_rsdp {
-	char			signature[8];
-	u8			checksum;
-	char			oem_id[6];
-	u8			revision;
-	u32			rsdt_address;
-	u32			length;
-	u64			xsdt_address;
-	u8			ext_checksum;
-	u8			reserved[3];
-} __attribute__ ((packed));
-
-typedef struct {
-	u8			type;
-	u8			length;
-} __attribute__ ((packed)) acpi_table_entry_header;
-
-/* Root System Description Table (RSDT) */
-
-struct acpi_table_rsdt {
-	struct acpi_table_header header;
-	u32			entry[8];
-} __attribute__ ((packed));
-
-/* Extended System Description Table (XSDT) */
-
-struct acpi_table_xsdt {
-	struct acpi_table_header header;
-	u64			entry[1];
-} __attribute__ ((packed));
-
-/* Fixed ACPI Description Table (FADT) */
-
-struct acpi_table_fadt {
-	struct acpi_table_header header;
-	u32 facs_addr;
-	u32 dsdt_addr;
-	/* ... */
-} __attribute__ ((packed));
-
-/* Multiple APIC Description Table (MADT) */
-
-struct acpi_table_madt {
-	struct acpi_table_header header;
-	u32			lapic_address;
-	struct {
-		u32			pcat_compat:1;
-		u32			reserved:31;
-	}			flags;
-} __attribute__ ((packed));
-
-enum acpi_madt_entry_id {
-	ACPI_MADT_LAPIC = 0,
-	ACPI_MADT_IOAPIC,
-	ACPI_MADT_INT_SRC_OVR,
-	ACPI_MADT_NMI_SRC,
-	ACPI_MADT_LAPIC_NMI,
-	ACPI_MADT_LAPIC_ADDR_OVR,
-	ACPI_MADT_IOSAPIC,
-	ACPI_MADT_LSAPIC,
-	ACPI_MADT_PLAT_INT_SRC,
-	ACPI_MADT_ENTRY_COUNT
-};
-
-typedef struct {
-	u16			polarity:2;
-	u16			trigger:2;
-	u16			reserved:12;
-} __attribute__ ((packed)) acpi_interrupt_flags;
-
-struct acpi_table_lapic {
-	acpi_table_entry_header	header;
-	u8			acpi_id;
-	u8			id;
-	struct {
-		u32			enabled:1;
-		u32			reserved:31;
-	}			flags;
-} __attribute__ ((packed));
-
-struct acpi_table_ioapic {
-	acpi_table_entry_header	header;
-	u8			id;
-	u8			reserved;
-	u32			address;
-	u32			global_irq_base;
-} __attribute__ ((packed));
-
-struct acpi_table_int_src_ovr {
-	acpi_table_entry_header	header;
-	u8			bus;
-	u8			bus_irq;
-	u32			global_irq;
-	acpi_interrupt_flags	flags;
-} __attribute__ ((packed));
-
-struct acpi_table_nmi_src {
-	acpi_table_entry_header	header;
-	acpi_interrupt_flags	flags;
-	u32			global_irq;
-} __attribute__ ((packed));
-
-struct acpi_table_lapic_nmi {
-	acpi_table_entry_header	header;
-	u8			acpi_id;
-	acpi_interrupt_flags	flags;
-	u8			lint;
-} __attribute__ ((packed));
-
-struct acpi_table_lapic_addr_ovr {
-	acpi_table_entry_header	header;
-	u8			reserved[2];
-	u64			address;
-} __attribute__ ((packed));
-
-struct acpi_table_iosapic {
-	acpi_table_entry_header	header;
-	u8			id;
-	u8			reserved;
-	u32			global_irq_base;
-	u64			address;
-} __attribute__ ((packed));
-
-struct acpi_table_lsapic {
-	acpi_table_entry_header	header;
-	u8			acpi_id;
-	u8			id;
-	u8			eid;
-	u8			reserved[3];
-	struct {
-		u32			enabled:1;
-		u32			reserved:31;
-	}			flags;
-} __attribute__ ((packed));
-
-struct acpi_table_plat_int_src {
-	acpi_table_entry_header	header;
-	acpi_interrupt_flags	flags;
-	u8			type;	/* See acpi_interrupt_type */
-	u8			id;
-	u8			eid;
-	u8			iosapic_vector;
-	u32			global_irq;
-	struct {
-		u32			cpei_override_flag:1;
-		u32			reserved:31;
-	}			plint_flags;
-} __attribute__ ((packed));
-
 enum acpi_interrupt_id {
 	ACPI_INTERRUPT_PMI	= 1,
 	ACPI_INTERRUPT_INIT,
@@ -222,89 +62,6 @@
 
 #define	ACPI_SPACE_MEM		0
 
-struct acpi_gen_regaddr {
-	u8  space_id;
-	u8  bit_width;
-	u8  bit_offset;
-	u8  resv;
-	u32 addrl;
-	u32 addrh;
-} __attribute__ ((packed));
-
-struct acpi_table_hpet {
-	struct acpi_table_header header;
-	u32 id;
-	struct acpi_gen_regaddr addr;
-	u8 number;
-	u16 min_tick;
-	u8 page_protect;
-} __attribute__ ((packed));
-
-/*
- * Simple Boot Flags
- * http://www.microsoft.com/whdc/hwdev/resources/specs/simp_bios.mspx
- */
-struct acpi_table_sbf
-{
-	u8 sbf_signature[4];
-	u32 sbf_len;
-	u8 sbf_revision;
-	u8 sbf_csum;
-	u8 sbf_oemid[6];
-	u8 sbf_oemtable[8];
-	u8 sbf_revdata[4];
-	u8 sbf_creator[4];
-	u8 sbf_crearev[4];
-	u8 sbf_cmos;
-	u8 sbf_spare[3];
-} __attribute__ ((packed));
-
-/*
- * System Resource Affinity Table (SRAT)
- * http://www.microsoft.com/whdc/hwdev/platform/proc/SRAT.mspx
- */
-
-struct acpi_table_srat {
-	struct acpi_table_header header;
-	u32			table_revision;
-	u64			reserved;
-} __attribute__ ((packed));
-
-enum acpi_srat_entry_id {
-	ACPI_SRAT_PROCESSOR_AFFINITY = 0,
-	ACPI_SRAT_MEMORY_AFFINITY,
-	ACPI_SRAT_ENTRY_COUNT
-};
-
-struct acpi_table_processor_affinity {
-	acpi_table_entry_header	header;
-	u8			proximity_domain;
-	u8			apic_id;
-	struct {
-		u32			enabled:1;
-		u32			reserved:31;
-	}			flags;
-	u8			lsapic_eid;
-	u8			reserved[7];
-} __attribute__ ((packed));
-
-struct acpi_table_memory_affinity {
-	acpi_table_entry_header	header;
-	u8			proximity_domain;
-	u8			reserved1[5];
-	u32			base_addr_lo;
-	u32			base_addr_hi;
-	u32			length_lo;
-	u32			length_hi;
-	u32			memory_type;	/* See acpi_address_range_id */
-	struct {
-		u32			enabled:1;
-		u32			hot_pluggable:1;
-		u32			reserved:30;
-	}			flags;
-	u64			reserved2;
-} __attribute__ ((packed));
-
 enum acpi_address_range_id {
 	ACPI_ADDRESS_RANGE_MEMORY = 1,
 	ACPI_ADDRESS_RANGE_RESERVED = 2,
@@ -313,84 +70,12 @@
 	ACPI_ADDRESS_RANGE_COUNT
 };
 
-/*
- * System Locality Information Table (SLIT)
- *   see http://devresource.hp.com/devresource/docs/techpapers/ia64/slit.pdf
- */
-
-struct acpi_table_slit {
-	struct acpi_table_header header;
-	u64			localities;
-	u8			entry[1];	/* real size = localities^2 */
-} __attribute__ ((packed));
-
-/* Smart Battery Description Table (SBST) */
-
-struct acpi_table_sbst {
-	struct acpi_table_header header;
-	u32			warning;	/* Warn user */
-	u32			low;		/* Critical sleep */
-	u32			critical;	/* Critical shutdown */
-} __attribute__ ((packed));
-
-/* Embedded Controller Boot Resources Table (ECDT) */
-
-struct acpi_table_ecdt {
-	struct acpi_table_header 	header;
-	struct acpi_generic_address	ec_control;
-	struct acpi_generic_address	ec_data;
-	u32				uid;
-	u8				gpe_bit;
-	char				ec_id[0];
-} __attribute__ ((packed));
-
-/* PCI MMCONFIG */
-
-/* Defined in PCI Firmware Specification 3.0 */
-struct acpi_table_mcfg_config {
-	u32				base_address;
-	u32				base_reserved;
-	u16				pci_segment_group_number;
-	u8				start_bus_number;
-	u8				end_bus_number;
-	u8				reserved[4];
-} __attribute__ ((packed));
-struct acpi_table_mcfg {
-	struct acpi_table_header	header;
-	u8				reserved[8];
-	struct acpi_table_mcfg_config	config[0];
-} __attribute__ ((packed));
 
 /* Table Handlers */
 
-enum acpi_table_id {
-	ACPI_TABLE_UNKNOWN = 0,
-	ACPI_APIC,
-	ACPI_BOOT,
-	ACPI_DBGP,
-	ACPI_DSDT,
-	ACPI_ECDT,
-	ACPI_ETDT,
-	ACPI_FADT,
-	ACPI_FACS,
-	ACPI_OEMX,
-	ACPI_PSDT,
-	ACPI_SBST,
-	ACPI_SLIT,
-	ACPI_SPCR,
-	ACPI_SRAT,
-	ACPI_SSDT,
-	ACPI_SPMI,
-	ACPI_HPET,
-	ACPI_MCFG,
-	ACPI_TABLE_COUNT
-};
+typedef int (*acpi_table_handler) (struct acpi_table_header *table);
 
-typedef int (*acpi_table_handler) (unsigned long phys_addr, unsigned long size);
-
-extern acpi_table_handler acpi_table_ops[ACPI_TABLE_COUNT];
-
-typedef int (*acpi_madt_entry_handler) (acpi_table_entry_header *header, const unsigned long end);
+typedef int (*acpi_madt_entry_handler) (struct acpi_subtable_header *header, const unsigned long end);
 
 char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
 unsigned long acpi_find_rsdp (void);
@@ -399,14 +84,12 @@
 int acpi_numa_init (void);
 
 int acpi_table_init (void);
-int acpi_table_parse (enum acpi_table_id id, acpi_table_handler handler);
-int acpi_get_table_header_early (enum acpi_table_id id, struct acpi_table_header **header);
-int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries);
-int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries);
-int acpi_parse_mcfg (unsigned long phys_addr, unsigned long size);
-void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr);
-void acpi_table_print_madt_entry (acpi_table_entry_header *madt);
-void acpi_table_print_srat_entry (acpi_table_entry_header *srat);
+int acpi_table_parse (char *id, acpi_table_handler handler);
+int acpi_table_parse_madt (enum acpi_madt_type id, acpi_madt_entry_handler handler, unsigned int max_entries);
+int acpi_table_parse_srat (enum acpi_srat_type id, acpi_madt_entry_handler handler, unsigned int max_entries);
+int acpi_parse_mcfg (struct acpi_table_header *header);
+void acpi_table_print_madt_entry (struct acpi_subtable_header *madt);
+void acpi_table_print_srat_entry (struct acpi_subtable_header *srat);
 
 /* the following four functions are architecture-dependent */
 #ifdef CONFIG_HAVE_ARCH_PARSE_SRAT
@@ -417,8 +100,8 @@
 #define acpi_numa_arch_fixup() do {} while (0)
 #else
 void acpi_numa_slit_init (struct acpi_table_slit *slit);
-void acpi_numa_processor_affinity_init (struct acpi_table_processor_affinity *pa);
-void acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma);
+void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa);
+void acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma);
 void acpi_numa_arch_fixup(void);
 #endif
 
@@ -433,7 +116,7 @@
 
 extern int acpi_mp_config;
 
-extern struct acpi_table_mcfg_config *pci_mmcfg_config;
+extern struct acpi_mcfg_allocation *pci_mmcfg_config;
 extern int pci_mmcfg_config_num;
 
 extern int sbf_port;
diff --git a/include/asm-arm/apm.h b/include/linux/apm-emulation.h
similarity index 92%
rename from include/asm-arm/apm.h
rename to include/linux/apm-emulation.h
index d09113b..e6d8003 100644
--- a/include/asm-arm/apm.h
+++ b/include/linux/apm-emulation.h
@@ -7,11 +7,9 @@
  * based on arch/arm/kernel/apm.c
  * factor out the information needed by architectures to provide
  * apm status
- *
- *
  */
-#ifndef ARM_ASM_SA1100_APM_H
-#define ARM_ASM_SA1100_APM_H
+#ifndef __LINUX_APM_EMULATION_H
+#define __LINUX_APM_EMULATION_H
 
 #include <linux/apm_bios.h>
 
@@ -61,4 +59,4 @@
  */
 void apm_queue_event(apm_event_t event);
 
-#endif
+#endif /* __LINUX_APM_EMULATION_H */
diff --git a/include/linux/atmarp.h b/include/linux/atmarp.h
index ee108f9..231f4bd 100644
--- a/include/linux/atmarp.h
+++ b/include/linux/atmarp.h
@@ -6,9 +6,7 @@
 #ifndef _LINUX_ATMARP_H
 #define _LINUX_ATMARP_H
 
-#ifdef __KERNEL__
 #include <linux/types.h>
-#endif
 #include <linux/atmapi.h>
 #include <linux/atmioc.h>
 
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 4aa9046..779aa78 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -51,15 +51,9 @@
 /*
  * Transform masks and values (for crt_flags).
  */
-#define CRYPTO_TFM_MODE_MASK		0x000000ff
 #define CRYPTO_TFM_REQ_MASK		0x000fff00
 #define CRYPTO_TFM_RES_MASK		0xfff00000
 
-#define CRYPTO_TFM_MODE_ECB		0x00000001
-#define CRYPTO_TFM_MODE_CBC		0x00000002
-#define CRYPTO_TFM_MODE_CFB		0x00000004
-#define CRYPTO_TFM_MODE_CTR		0x00000008
-
 #define CRYPTO_TFM_REQ_WEAK_KEY		0x00000100
 #define CRYPTO_TFM_REQ_MAY_SLEEP	0x00000200
 #define CRYPTO_TFM_RES_WEAK_KEY		0x00100000
@@ -71,12 +65,8 @@
 /*
  * Miscellaneous stuff.
  */
-#define CRYPTO_UNSPEC			0
 #define CRYPTO_MAX_ALG_NAME		64
 
-#define CRYPTO_DIR_ENCRYPT		1
-#define CRYPTO_DIR_DECRYPT		0
-
 /*
  * The macro CRYPTO_MINALIGN_ATTR (along with the void * type in the actual
  * declaration) is used to ensure that the crypto_tfm context structure is
@@ -148,19 +138,6 @@
 	                  unsigned int keylen);
 	void (*cia_encrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
 	void (*cia_decrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
-
-	unsigned int (*cia_encrypt_ecb)(const struct cipher_desc *desc,
-					u8 *dst, const u8 *src,
-					unsigned int nbytes) __deprecated;
-	unsigned int (*cia_decrypt_ecb)(const struct cipher_desc *desc,
-					u8 *dst, const u8 *src,
-					unsigned int nbytes) __deprecated;
-	unsigned int (*cia_encrypt_cbc)(const struct cipher_desc *desc,
-					u8 *dst, const u8 *src,
-					unsigned int nbytes) __deprecated;
-	unsigned int (*cia_decrypt_cbc)(const struct cipher_desc *desc,
-					u8 *dst, const u8 *src,
-					unsigned int nbytes) __deprecated;
 };
 
 struct digest_alg {
@@ -243,11 +220,6 @@
 #ifdef CONFIG_CRYPTO
 int crypto_has_alg(const char *name, u32 type, u32 mask);
 #else
-static inline int crypto_alg_available(const char *name, u32 flags)
-{
-	return 0;
-}
-
 static inline int crypto_has_alg(const char *name, u32 type, u32 mask)
 {
 	return 0;
@@ -339,13 +311,18 @@
 	void *__crt_ctx[] CRYPTO_MINALIGN_ATTR;
 };
 
-#define crypto_cipher crypto_tfm
-#define crypto_comp crypto_tfm
-
 struct crypto_blkcipher {
 	struct crypto_tfm base;
 };
 
+struct crypto_cipher {
+	struct crypto_tfm base;
+};
+
+struct crypto_comp {
+	struct crypto_tfm base;
+};
+
 struct crypto_hash {
 	struct crypto_tfm base;
 };
@@ -395,40 +372,11 @@
 	return tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK;
 }
 
-static unsigned int crypto_tfm_alg_min_keysize(struct crypto_tfm *tfm)
-	__deprecated;
-static inline unsigned int crypto_tfm_alg_min_keysize(struct crypto_tfm *tfm)
-{
-	BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
-	return tfm->__crt_alg->cra_cipher.cia_min_keysize;
-}
-
-static unsigned int crypto_tfm_alg_max_keysize(struct crypto_tfm *tfm)
-	__deprecated;
-static inline unsigned int crypto_tfm_alg_max_keysize(struct crypto_tfm *tfm)
-{
-	BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
-	return tfm->__crt_alg->cra_cipher.cia_max_keysize;
-}
-
-static unsigned int crypto_tfm_alg_ivsize(struct crypto_tfm *tfm) __deprecated;
-static inline unsigned int crypto_tfm_alg_ivsize(struct crypto_tfm *tfm)
-{
-	BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
-	return tfm->crt_cipher.cit_ivsize;
-}
-
 static inline unsigned int crypto_tfm_alg_blocksize(struct crypto_tfm *tfm)
 {
 	return tfm->__crt_alg->cra_blocksize;
 }
 
-static inline unsigned int crypto_tfm_alg_digestsize(struct crypto_tfm *tfm)
-{
-	BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
-	return tfm->__crt_alg->cra_digest.dia_digestsize;
-}
-
 static inline unsigned int crypto_tfm_alg_alignmask(struct crypto_tfm *tfm)
 {
 	return tfm->__crt_alg->cra_alignmask;
@@ -633,7 +581,7 @@
 
 static inline struct crypto_tfm *crypto_cipher_tfm(struct crypto_cipher *tfm)
 {
-	return tfm;
+	return &tfm->base;
 }
 
 static inline void crypto_free_cipher(struct crypto_cipher *tfm)
@@ -809,76 +757,6 @@
 	return crypto_hash_crt(hash)->setkey(hash, key, keylen);
 }
 
-static int crypto_cipher_encrypt(struct crypto_tfm *tfm,
-				 struct scatterlist *dst,
-				 struct scatterlist *src,
-				 unsigned int nbytes) __deprecated;
-static inline int crypto_cipher_encrypt(struct crypto_tfm *tfm,
-                                        struct scatterlist *dst,
-                                        struct scatterlist *src,
-                                        unsigned int nbytes)
-{
-	BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
-	return tfm->crt_cipher.cit_encrypt(tfm, dst, src, nbytes);
-}                                        
-
-static int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm,
-				    struct scatterlist *dst,
-				    struct scatterlist *src,
-				    unsigned int nbytes, u8 *iv) __deprecated;
-static inline int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm,
-                                           struct scatterlist *dst,
-                                           struct scatterlist *src,
-                                           unsigned int nbytes, u8 *iv)
-{
-	BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
-	return tfm->crt_cipher.cit_encrypt_iv(tfm, dst, src, nbytes, iv);
-}                                        
-
-static int crypto_cipher_decrypt(struct crypto_tfm *tfm,
-				 struct scatterlist *dst,
-				 struct scatterlist *src,
-				 unsigned int nbytes) __deprecated;
-static inline int crypto_cipher_decrypt(struct crypto_tfm *tfm,
-                                        struct scatterlist *dst,
-                                        struct scatterlist *src,
-                                        unsigned int nbytes)
-{
-	BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
-	return tfm->crt_cipher.cit_decrypt(tfm, dst, src, nbytes);
-}
-
-static int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm,
-				    struct scatterlist *dst,
-				    struct scatterlist *src,
-				    unsigned int nbytes, u8 *iv) __deprecated;
-static inline int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm,
-                                           struct scatterlist *dst,
-                                           struct scatterlist *src,
-                                           unsigned int nbytes, u8 *iv)
-{
-	BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
-	return tfm->crt_cipher.cit_decrypt_iv(tfm, dst, src, nbytes, iv);
-}
-
-static void crypto_cipher_set_iv(struct crypto_tfm *tfm,
-				 const u8 *src, unsigned int len) __deprecated;
-static inline void crypto_cipher_set_iv(struct crypto_tfm *tfm,
-                                        const u8 *src, unsigned int len)
-{
-	BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
-	memcpy(tfm->crt_cipher.cit_iv, src, len);
-}
-
-static void crypto_cipher_get_iv(struct crypto_tfm *tfm,
-				 u8 *dst, unsigned int len) __deprecated;
-static inline void crypto_cipher_get_iv(struct crypto_tfm *tfm,
-                                        u8 *dst, unsigned int len)
-{
-	BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
-	memcpy(dst, tfm->crt_cipher.cit_iv, len);
-}
-
 static inline struct crypto_comp *__crypto_comp_cast(struct crypto_tfm *tfm)
 {
 	return (struct crypto_comp *)tfm;
@@ -903,7 +781,7 @@
 
 static inline struct crypto_tfm *crypto_comp_tfm(struct crypto_comp *tfm)
 {
-	return tfm;
+	return &tfm->base;
 }
 
 static inline void crypto_free_comp(struct crypto_comp *tfm)
@@ -934,14 +812,16 @@
                                        const u8 *src, unsigned int slen,
                                        u8 *dst, unsigned int *dlen)
 {
-	return crypto_comp_crt(tfm)->cot_compress(tfm, src, slen, dst, dlen);
+	return crypto_comp_crt(tfm)->cot_compress(crypto_comp_tfm(tfm),
+						  src, slen, dst, dlen);
 }
 
 static inline int crypto_comp_decompress(struct crypto_comp *tfm,
                                          const u8 *src, unsigned int slen,
                                          u8 *dst, unsigned int *dlen)
 {
-	return crypto_comp_crt(tfm)->cot_decompress(tfm, src, slen, dst, dlen);
+	return crypto_comp_crt(tfm)->cot_decompress(crypto_comp_tfm(tfm),
+						    src, slen, dst, dlen);
 }
 
 #endif	/* _LINUX_CRYPTO_H */
diff --git a/include/linux/device.h b/include/linux/device.h
index f44247f..5ca1cdb 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -126,6 +126,7 @@
 	struct klist_node	knode_bus;
 
 	struct module		* owner;
+	const char 		* mod_name;	/* used for built-in modules */
 
 	int	(*probe)	(struct device * dev);
 	int	(*remove)	(struct device * dev);
@@ -327,6 +328,13 @@
 					__attribute__((format(printf,5,6)));
 extern void class_device_destroy(struct class *cls, dev_t devt);
 
+struct device_type {
+	struct device_attribute *attrs;
+	int (*uevent)(struct device *dev, char **envp, int num_envp,
+		      char *buffer, int buffer_size);
+	void (*release)(struct device *dev);
+};
+
 /* interface for exporting device attributes */
 struct device_attribute {
 	struct attribute	attr;
@@ -355,6 +363,7 @@
 
 	struct kobject kobj;
 	char	bus_id[BUS_ID_SIZE];	/* position on parent bus */
+	struct device_type	*type;
 	unsigned		is_registered:1;
 	struct device_attribute uevent_attr;
 	struct device_attribute *devt_attr;
@@ -390,9 +399,10 @@
 
 	/* class_device migration path */
 	struct list_head	node;
-	struct class		*class;		/* optional*/
+	struct class		*class;
 	dev_t			devt;		/* dev_t, creates the sysfs "dev" */
 	struct attribute_group	**groups;	/* optional groups */
+	int			uevent_suppress;
 
 	void	(*release)(struct device * dev);
 };
diff --git a/include/linux/eisa.h b/include/linux/eisa.h
index 1ff7c13..fe806b6 100644
--- a/include/linux/eisa.h
+++ b/include/linux/eisa.h
@@ -61,10 +61,20 @@
 
 #define to_eisa_driver(drv) container_of(drv,struct eisa_driver, driver)
 
+/* These external functions are only available when EISA support is enabled. */
+#ifdef CONFIG_EISA
+
 extern struct bus_type eisa_bus_type;
 int eisa_driver_register (struct eisa_driver *edrv);
 void eisa_driver_unregister (struct eisa_driver *edrv);
 
+#else /* !CONFIG_EISA */
+
+static inline int eisa_driver_register (struct eisa_driver *edrv) { return 0; }
+static inline void eisa_driver_unregister (struct eisa_driver *edrv) { }
+
+#endif /* !CONFIG_EISA */
+
 /* Mimics pci.h... */
 static inline void *eisa_get_drvdata (struct eisa_device *edev)
 {
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 00c314a..063799e 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -70,7 +70,7 @@
 #ifdef CONFIG_NUMA
 #define GFP_THISNODE	(__GFP_THISNODE | __GFP_NOWARN | __GFP_NORETRY)
 #else
-#define GFP_THISNODE	0
+#define GFP_THISNODE	((__force gfp_t)0)
 #endif
 
 
diff --git a/include/linux/hid-debug.h b/include/linux/hid-debug.h
index 8e4dbb5..50d568e 100644
--- a/include/linux/hid-debug.h
+++ b/include/linux/hid-debug.h
@@ -1,10 +1,8 @@
+#ifndef __HID_DEBUG_H
+#define __HID_DEBUG_H
+
 /*
- * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $
- *
- *  (c) 1999 Andreas Gal		<gal@cs.uni-magdeburg.de>
- *  (c) 2000-2001 Vojtech Pavlik	<vojtech@ucw.cz>
- *
- *  Some debug stuff for the HID parser.
+ *  Copyright (c) 2007	Jiri Kosina
  */
 
 /*
@@ -22,737 +20,26 @@
  * 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
  */
 
-#include <linux/input.h>
+#ifdef CONFIG_HID_DEBUG
 
-struct hid_usage_entry {
-	unsigned  page;
-	unsigned  usage;
-	char     *description;
-};
+void hid_dump_input(struct hid_usage *, __s32);
+void hid_dump_device(struct hid_device *);
+void hid_dump_field(struct hid_field *, int);
+void hid_resolv_usage(unsigned);
+void hid_resolv_event(__u8, __u16);
 
-static const struct hid_usage_entry hid_usage_table[] = {
-  {  0,      0, "Undefined" },
-  {  1,      0, "GenericDesktop" },
-    {0, 0x01, "Pointer"},
-    {0, 0x02, "Mouse"},
-    {0, 0x04, "Joystick"},
-    {0, 0x05, "GamePad"},
-    {0, 0x06, "Keyboard"},
-    {0, 0x07, "Keypad"},
-    {0, 0x08, "MultiAxis"},
-      {0, 0x30, "X"},
-      {0, 0x31, "Y"},
-      {0, 0x32, "Z"},
-      {0, 0x33, "Rx"},
-      {0, 0x34, "Ry"},
-      {0, 0x35, "Rz"},
-      {0, 0x36, "Slider"},
-      {0, 0x37, "Dial"},
-      {0, 0x38, "Wheel"},
-      {0, 0x39, "HatSwitch"},
-    {0, 0x3a, "CountedBuffer"},
-      {0, 0x3b, "ByteCount"},
-      {0, 0x3c, "MotionWakeup"},
-      {0, 0x3d, "Start"},
-      {0, 0x3e, "Select"},
-      {0, 0x40, "Vx"},
-      {0, 0x41, "Vy"},
-      {0, 0x42, "Vz"},
-      {0, 0x43, "Vbrx"},
-      {0, 0x44, "Vbry"},
-      {0, 0x45, "Vbrz"},
-      {0, 0x46, "Vno"},
-    {0, 0x80, "SystemControl"},
-      {0, 0x81, "SystemPowerDown"},
-      {0, 0x82, "SystemSleep"},
-      {0, 0x83, "SystemWakeUp"},
-      {0, 0x84, "SystemContextMenu"},
-      {0, 0x85, "SystemMainMenu"},
-      {0, 0x86, "SystemAppMenu"},
-      {0, 0x87, "SystemMenuHelp"},
-      {0, 0x88, "SystemMenuExit"},
-      {0, 0x89, "SystemMenuSelect"},
-      {0, 0x8a, "SystemMenuRight"},
-      {0, 0x8b, "SystemMenuLeft"},
-      {0, 0x8c, "SystemMenuUp"},
-      {0, 0x8d, "SystemMenuDown"},
-      {0, 0x90, "D-PadUp"},
-      {0, 0x91, "D-PadDown"},
-      {0, 0x92, "D-PadRight"},
-      {0, 0x93, "D-PadLeft"},
-  {  2, 0, "Simulation" },
-      {0, 0xb0, "Aileron"},
-      {0, 0xb1, "AileronTrim"},
-      {0, 0xb2, "Anti-Torque"},
-      {0, 0xb3, "Autopilot"},
-      {0, 0xb4, "Chaff"},
-      {0, 0xb5, "Collective"},
-      {0, 0xb6, "DiveBrake"},
-      {0, 0xb7, "ElectronicCountermeasures"},
-      {0, 0xb8, "Elevator"},
-      {0, 0xb9, "ElevatorTrim"},
-      {0, 0xba, "Rudder"},
-      {0, 0xbb, "Throttle"},
-      {0, 0xbc, "FlightCommunications"},
-      {0, 0xbd, "FlareRelease"},
-      {0, 0xbe, "LandingGear"},
-      {0, 0xbf, "ToeBrake"},
-  {  7, 0, "Keyboard" },
-  {  8, 0, "LED" },
-      {0, 0x01, "NumLock"},
-      {0, 0x02, "CapsLock"},
-      {0, 0x03, "ScrollLock"},
-      {0, 0x04, "Compose"},
-      {0, 0x05, "Kana"},
-      {0, 0x4b, "GenericIndicator"},
-  {  9, 0, "Button" },
-  { 10, 0, "Ordinal" },
-  { 12, 0, "Consumer" },
-      {0, 0x238, "HorizontalWheel"},
-  { 13, 0, "Digitizers" },
-    {0, 0x01, "Digitizer"},
-    {0, 0x02, "Pen"},
-    {0, 0x03, "LightPen"},
-    {0, 0x04, "TouchScreen"},
-    {0, 0x05, "TouchPad"},
-    {0, 0x20, "Stylus"},
-    {0, 0x21, "Puck"},
-    {0, 0x22, "Finger"},
-    {0, 0x30, "TipPressure"},
-    {0, 0x31, "BarrelPressure"},
-    {0, 0x32, "InRange"},
-    {0, 0x33, "Touch"},
-    {0, 0x34, "UnTouch"},
-    {0, 0x35, "Tap"},
-    {0, 0x39, "TabletFunctionKey"},
-    {0, 0x3a, "ProgramChangeKey"},
-    {0, 0x3c, "Invert"},
-    {0, 0x42, "TipSwitch"},
-    {0, 0x43, "SecondaryTipSwitch"},
-    {0, 0x44, "BarrelSwitch"},
-    {0, 0x45, "Eraser"},
-    {0, 0x46, "TabletPick"},
-  { 15, 0, "PhysicalInterfaceDevice" },
-    {0, 0x00, "Undefined"},
-    {0, 0x01, "Physical_Interface_Device"},
-      {0, 0x20, "Normal"},
-    {0, 0x21, "Set_Effect_Report"},
-      {0, 0x22, "Effect_Block_Index"},
-      {0, 0x23, "Parameter_Block_Offset"},
-      {0, 0x24, "ROM_Flag"},
-      {0, 0x25, "Effect_Type"},
-        {0, 0x26, "ET_Constant_Force"},
-        {0, 0x27, "ET_Ramp"},
-        {0, 0x28, "ET_Custom_Force_Data"},
-        {0, 0x30, "ET_Square"},
-        {0, 0x31, "ET_Sine"},
-        {0, 0x32, "ET_Triangle"},
-        {0, 0x33, "ET_Sawtooth_Up"},
-        {0, 0x34, "ET_Sawtooth_Down"},
-        {0, 0x40, "ET_Spring"},
-        {0, 0x41, "ET_Damper"},
-        {0, 0x42, "ET_Inertia"},
-        {0, 0x43, "ET_Friction"},
-      {0, 0x50, "Duration"},
-      {0, 0x51, "Sample_Period"},
-      {0, 0x52, "Gain"},
-      {0, 0x53, "Trigger_Button"},
-      {0, 0x54, "Trigger_Repeat_Interval"},
-      {0, 0x55, "Axes_Enable"},
-        {0, 0x56, "Direction_Enable"},
-      {0, 0x57, "Direction"},
-      {0, 0x58, "Type_Specific_Block_Offset"},
-        {0, 0x59, "Block_Type"},
-        {0, 0x5A, "Set_Envelope_Report"},
-          {0, 0x5B, "Attack_Level"},
-          {0, 0x5C, "Attack_Time"},
-          {0, 0x5D, "Fade_Level"},
-          {0, 0x5E, "Fade_Time"},
-        {0, 0x5F, "Set_Condition_Report"},
-        {0, 0x60, "CP_Offset"},
-        {0, 0x61, "Positive_Coefficient"},
-        {0, 0x62, "Negative_Coefficient"},
-        {0, 0x63, "Positive_Saturation"},
-        {0, 0x64, "Negative_Saturation"},
-        {0, 0x65, "Dead_Band"},
-      {0, 0x66, "Download_Force_Sample"},
-      {0, 0x67, "Isoch_Custom_Force_Enable"},
-      {0, 0x68, "Custom_Force_Data_Report"},
-        {0, 0x69, "Custom_Force_Data"},
-        {0, 0x6A, "Custom_Force_Vendor_Defined_Data"},
-      {0, 0x6B, "Set_Custom_Force_Report"},
-        {0, 0x6C, "Custom_Force_Data_Offset"},
-        {0, 0x6D, "Sample_Count"},
-      {0, 0x6E, "Set_Periodic_Report"},
-        {0, 0x6F, "Offset"},
-        {0, 0x70, "Magnitude"},
-        {0, 0x71, "Phase"},
-        {0, 0x72, "Period"},
-      {0, 0x73, "Set_Constant_Force_Report"},
-        {0, 0x74, "Set_Ramp_Force_Report"},
-        {0, 0x75, "Ramp_Start"},
-        {0, 0x76, "Ramp_End"},
-      {0, 0x77, "Effect_Operation_Report"},
-        {0, 0x78, "Effect_Operation"},
-          {0, 0x79, "Op_Effect_Start"},
-          {0, 0x7A, "Op_Effect_Start_Solo"},
-          {0, 0x7B, "Op_Effect_Stop"},
-          {0, 0x7C, "Loop_Count"},
-      {0, 0x7D, "Device_Gain_Report"},
-        {0, 0x7E, "Device_Gain"},
-    {0, 0x7F, "PID_Pool_Report"},
-      {0, 0x80, "RAM_Pool_Size"},
-      {0, 0x81, "ROM_Pool_Size"},
-      {0, 0x82, "ROM_Effect_Block_Count"},
-      {0, 0x83, "Simultaneous_Effects_Max"},
-      {0, 0x84, "Pool_Alignment"},
-    {0, 0x85, "PID_Pool_Move_Report"},
-      {0, 0x86, "Move_Source"},
-      {0, 0x87, "Move_Destination"},
-      {0, 0x88, "Move_Length"},
-    {0, 0x89, "PID_Block_Load_Report"},
-      {0, 0x8B, "Block_Load_Status"},
-      {0, 0x8C, "Block_Load_Success"},
-      {0, 0x8D, "Block_Load_Full"},
-      {0, 0x8E, "Block_Load_Error"},
-      {0, 0x8F, "Block_Handle"},
-      {0, 0x90, "PID_Block_Free_Report"},
-      {0, 0x91, "Type_Specific_Block_Handle"},
-    {0, 0x92, "PID_State_Report"},
-      {0, 0x94, "Effect_Playing"},
-      {0, 0x95, "PID_Device_Control_Report"},
-        {0, 0x96, "PID_Device_Control"},
-        {0, 0x97, "DC_Enable_Actuators"},
-        {0, 0x98, "DC_Disable_Actuators"},
-        {0, 0x99, "DC_Stop_All_Effects"},
-        {0, 0x9A, "DC_Device_Reset"},
-        {0, 0x9B, "DC_Device_Pause"},
-        {0, 0x9C, "DC_Device_Continue"},
-      {0, 0x9F, "Device_Paused"},
-      {0, 0xA0, "Actuators_Enabled"},
-      {0, 0xA4, "Safety_Switch"},
-      {0, 0xA5, "Actuator_Override_Switch"},
-      {0, 0xA6, "Actuator_Power"},
-    {0, 0xA7, "Start_Delay"},
-    {0, 0xA8, "Parameter_Block_Size"},
-    {0, 0xA9, "Device_Managed_Pool"},
-    {0, 0xAA, "Shared_Parameter_Blocks"},
-    {0, 0xAB, "Create_New_Effect_Report"},
-    {0, 0xAC, "RAM_Pool_Available"},
-  { 0x84, 0, "Power Device" },
-    { 0x84, 0x02, "PresentStatus" },
-    { 0x84, 0x03, "ChangeStatus" },
-    { 0x84, 0x04, "UPS" },
-    { 0x84, 0x05, "PowerSupply" },
-    { 0x84, 0x10, "BatterySystem" },
-    { 0x84, 0x11, "BatterySystemID" },
-    { 0x84, 0x12, "Battery" },
-    { 0x84, 0x13, "BatteryID" },
-    { 0x84, 0x14, "Charger" },
-    { 0x84, 0x15, "ChargerID" },
-    { 0x84, 0x16, "PowerConverter" },
-    { 0x84, 0x17, "PowerConverterID" },
-    { 0x84, 0x18, "OutletSystem" },
-    { 0x84, 0x19, "OutletSystemID" },
-    { 0x84, 0x1a, "Input" },
-    { 0x84, 0x1b, "InputID" },
-    { 0x84, 0x1c, "Output" },
-    { 0x84, 0x1d, "OutputID" },
-    { 0x84, 0x1e, "Flow" },
-    { 0x84, 0x1f, "FlowID" },
-    { 0x84, 0x20, "Outlet" },
-    { 0x84, 0x21, "OutletID" },
-    { 0x84, 0x22, "Gang" },
-    { 0x84, 0x24, "PowerSummary" },
-    { 0x84, 0x25, "PowerSummaryID" },
-    { 0x84, 0x30, "Voltage" },
-    { 0x84, 0x31, "Current" },
-    { 0x84, 0x32, "Frequency" },
-    { 0x84, 0x33, "ApparentPower" },
-    { 0x84, 0x35, "PercentLoad" },
-    { 0x84, 0x40, "ConfigVoltage" },
-    { 0x84, 0x41, "ConfigCurrent" },
-    { 0x84, 0x43, "ConfigApparentPower" },
-    { 0x84, 0x53, "LowVoltageTransfer" },
-    { 0x84, 0x54, "HighVoltageTransfer" },
-    { 0x84, 0x56, "DelayBeforeStartup" },
-    { 0x84, 0x57, "DelayBeforeShutdown" },
-    { 0x84, 0x58, "Test" },
-    { 0x84, 0x5a, "AudibleAlarmControl" },
-    { 0x84, 0x60, "Present" },
-    { 0x84, 0x61, "Good" },
-    { 0x84, 0x62, "InternalFailure" },
-    { 0x84, 0x65, "Overload" },
-    { 0x84, 0x66, "OverCharged" },
-    { 0x84, 0x67, "OverTemperature" },
-    { 0x84, 0x68, "ShutdownRequested" },
-    { 0x84, 0x69, "ShutdownImminent" },
-    { 0x84, 0x6b, "SwitchOn/Off" },
-    { 0x84, 0x6c, "Switchable" },
-    { 0x84, 0x6d, "Used" },
-    { 0x84, 0x6e, "Boost" },
-    { 0x84, 0x73, "CommunicationLost" },
-    { 0x84, 0xfd, "iManufacturer" },
-    { 0x84, 0xfe, "iProduct" },
-    { 0x84, 0xff, "iSerialNumber" },
-  { 0x85, 0, "Battery System" },
-    { 0x85, 0x01, "SMBBatteryMode" },
-    { 0x85, 0x02, "SMBBatteryStatus" },
-    { 0x85, 0x03, "SMBAlarmWarning" },
-    { 0x85, 0x04, "SMBChargerMode" },
-    { 0x85, 0x05, "SMBChargerStatus" },
-    { 0x85, 0x06, "SMBChargerSpecInfo" },
-    { 0x85, 0x07, "SMBSelectorState" },
-    { 0x85, 0x08, "SMBSelectorPresets" },
-    { 0x85, 0x09, "SMBSelectorInfo" },
-    { 0x85, 0x29, "RemainingCapacityLimit" },
-    { 0x85, 0x2c, "CapacityMode" },
-    { 0x85, 0x42, "BelowRemainingCapacityLimit" },
-    { 0x85, 0x44, "Charging" },
-    { 0x85, 0x45, "Discharging" },
-    { 0x85, 0x4b, "NeedReplacement" },
-    { 0x85, 0x66, "RemainingCapacity" },
-    { 0x85, 0x68, "RunTimeToEmpty" },
-    { 0x85, 0x6a, "AverageTimeToFull" },
-    { 0x85, 0x83, "DesignCapacity" },
-    { 0x85, 0x85, "ManufacturerDate" },
-    { 0x85, 0x89, "iDeviceChemistry" },
-    { 0x85, 0x8b, "Rechargable" },
-    { 0x85, 0x8f, "iOEMInformation" },
-    { 0x85, 0x8d, "CapacityGranularity1" },
-    { 0x85, 0xd0, "ACPresent" },
-  /* pages 0xff00 to 0xffff are vendor-specific */
-  { 0xffff, 0, "Vendor-specific-FF" },
-  { 0, 0, NULL }
-};
+#else
 
-static void resolv_usage_page(unsigned page) {
-	const struct hid_usage_entry *p;
+#define hid_dump_input(a,b)     do { } while (0)
+#define hid_dump_device(c)      do { } while (0)
+#define hid_dump_field(a,b)     do { } while (0)
+#define hid_resolv_usage(a)         do { } while (0)
+#define hid_resolv_event(a,b)       do { } while (0)
 
-	for (p = hid_usage_table; p->description; p++)
-		if (p->page == page) {
-			printk("%s", p->description);
-			return;
-		}
-	printk("%04x", page);
-}
-
-static void resolv_usage(unsigned usage) {
-	const struct hid_usage_entry *p;
-
-	resolv_usage_page(usage >> 16);
-	printk(".");
-	for (p = hid_usage_table; p->description; p++)
-		if (p->page == (usage >> 16)) {
-			for(++p; p->description && p->usage != 0; p++)
-				if (p->usage == (usage & 0xffff)) {
-					printk("%s", p->description);
-					return;
-				}
-			break;
-		}
-	printk("%04x", usage & 0xffff);
-}
-
-__inline__ static void tab(int n) {
-	while (n--) printk(" ");
-}
-
-static void hid_dump_field(struct hid_field *field, int n) {
-	int j;
-
-	if (field->physical) {
-		tab(n);
-		printk("Physical(");
-		resolv_usage(field->physical); printk(")\n");
-	}
-	if (field->logical) {
-		tab(n);
-		printk("Logical(");
-		resolv_usage(field->logical); printk(")\n");
-	}
-	tab(n); printk("Usage(%d)\n", field->maxusage);
-	for (j = 0; j < field->maxusage; j++) {
-		tab(n+2);resolv_usage(field->usage[j].hid); printk("\n");
-	}
-	if (field->logical_minimum != field->logical_maximum) {
-		tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum);
-		tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum);
-	}
-	if (field->physical_minimum != field->physical_maximum) {
-		tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum);
-		tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum);
-	}
-	if (field->unit_exponent) {
-		tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent);
-	}
-	if (field->unit) {
-		char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
-		char *units[5][8] = {
-			{ "None", "None", "None", "None", "None", "None", "None", "None" },
-			{ "None", "Centimeter", "Gram", "Seconds", "Kelvin",     "Ampere", "Candela", "None" },
-			{ "None", "Radians",    "Gram", "Seconds", "Kelvin",     "Ampere", "Candela", "None" },
-			{ "None", "Inch",       "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" },
-			{ "None", "Degrees",    "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }
-		};
-
-		int i;
-		int sys;
-                __u32 data = field->unit;
-
-		/* First nibble tells us which system we're in. */
-		sys = data & 0xf;
-		data >>= 4;
-
-		if(sys > 4) {
-			tab(n); printk("Unit(Invalid)\n");
-		}
-		else {
-			int earlier_unit = 0;
-
-			tab(n); printk("Unit(%s : ", systems[sys]);
-
-			for (i=1 ; i<sizeof(__u32)*2 ; i++) {
-				char nibble = data & 0xf;
-				data >>= 4;
-				if (nibble != 0) {
-					if(earlier_unit++ > 0)
-						printk("*");
-					printk("%s", units[sys][i]);
-					if(nibble != 1) {
-						/* This is a _signed_ nibble(!) */
-
-						int val = nibble & 0x7;
-						if(nibble & 0x08)
-							val = -((0x7 & ~val) +1);
-						printk("^%d", val);
-					}
-				}
-			}
-			printk(")\n");
-		}
-	}
-	tab(n); printk("Report Size(%u)\n", field->report_size);
-	tab(n); printk("Report Count(%u)\n", field->report_count);
-	tab(n); printk("Report Offset(%u)\n", field->report_offset);
-
-	tab(n); printk("Flags( ");
-	j = field->flags;
-	printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : "");
-	printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array ");
-	printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute ");
-	printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : "");
-	printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : "");
-	printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : "");
-	printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : "");
-	printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : "");
-	printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : "");
-	printk(")\n");
-}
-
-static void __attribute__((unused)) hid_dump_device(struct hid_device *device) {
-	struct hid_report_enum *report_enum;
-	struct hid_report *report;
-	struct list_head *list;
-	unsigned i,k;
-	static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
-
-	for (i = 0; i < HID_REPORT_TYPES; i++) {
-		report_enum = device->report_enum + i;
-		list = report_enum->report_list.next;
-		while (list != &report_enum->report_list) {
-			report = (struct hid_report *) list;
-			tab(2);
-			printk("%s", table[i]);
-			if (report->id)
-				printk("(%d)", report->id);
-			printk("[%s]", table[report->type]);
-			printk("\n");
-			for (k = 0; k < report->maxfield; k++) {
-				tab(4);
-				printk("Field(%d)\n", k);
-				hid_dump_field(report->field[k], 6);
-			}
-			list = list->next;
-		}
-	}
-}
-
-static void __attribute__((unused)) hid_dump_input(struct hid_usage *usage, __s32 value) {
-	printk("hid-debug: input ");
-	resolv_usage(usage->hid);
-	printk(" = %d\n", value);
-}
+#endif /* CONFIG_HID_DEBUG */
 
 
-static char *events[EV_MAX + 1] = {
-	[EV_SYN] = "Sync",			[EV_KEY] = "Key",
-	[EV_REL] = "Relative",			[EV_ABS] = "Absolute",
-	[EV_MSC] = "Misc",			[EV_LED] = "LED",
-	[EV_SND] = "Sound",			[EV_REP] = "Repeat",
-	[EV_FF] = "ForceFeedback",		[EV_PWR] = "Power",
-	[EV_FF_STATUS] = "ForceFeedbackStatus",
-};
+#endif
 
-static char *syncs[2] = {
-	[SYN_REPORT] = "Report",		[SYN_CONFIG] = "Config",
-};
-static char *keys[KEY_MAX + 1] = {
-	[KEY_RESERVED] = "Reserved",		[KEY_ESC] = "Esc",
-	[KEY_1] = "1",				[KEY_2] = "2",
-	[KEY_3] = "3",				[KEY_4] = "4",
-	[KEY_5] = "5",				[KEY_6] = "6",
-	[KEY_7] = "7",				[KEY_8] = "8",
-	[KEY_9] = "9",				[KEY_0] = "0",
-	[KEY_MINUS] = "Minus",			[KEY_EQUAL] = "Equal",
-	[KEY_BACKSPACE] = "Backspace",		[KEY_TAB] = "Tab",
-	[KEY_Q] = "Q",				[KEY_W] = "W",
-	[KEY_E] = "E",				[KEY_R] = "R",
-	[KEY_T] = "T",				[KEY_Y] = "Y",
-	[KEY_U] = "U",				[KEY_I] = "I",
-	[KEY_O] = "O",				[KEY_P] = "P",
-	[KEY_LEFTBRACE] = "LeftBrace",		[KEY_RIGHTBRACE] = "RightBrace",
-	[KEY_ENTER] = "Enter",			[KEY_LEFTCTRL] = "LeftControl",
-	[KEY_A] = "A",				[KEY_S] = "S",
-	[KEY_D] = "D",				[KEY_F] = "F",
-	[KEY_G] = "G",				[KEY_H] = "H",
-	[KEY_J] = "J",				[KEY_K] = "K",
-	[KEY_L] = "L",				[KEY_SEMICOLON] = "Semicolon",
-	[KEY_APOSTROPHE] = "Apostrophe",	[KEY_GRAVE] = "Grave",
-	[KEY_LEFTSHIFT] = "LeftShift",		[KEY_BACKSLASH] = "BackSlash",
-	[KEY_Z] = "Z",				[KEY_X] = "X",
-	[KEY_C] = "C",				[KEY_V] = "V",
-	[KEY_B] = "B",				[KEY_N] = "N",
-	[KEY_M] = "M",				[KEY_COMMA] = "Comma",
-	[KEY_DOT] = "Dot",			[KEY_SLASH] = "Slash",
-	[KEY_RIGHTSHIFT] = "RightShift",	[KEY_KPASTERISK] = "KPAsterisk",
-	[KEY_LEFTALT] = "LeftAlt",		[KEY_SPACE] = "Space",
-	[KEY_CAPSLOCK] = "CapsLock",		[KEY_F1] = "F1",
-	[KEY_F2] = "F2",			[KEY_F3] = "F3",
-	[KEY_F4] = "F4",			[KEY_F5] = "F5",
-	[KEY_F6] = "F6",			[KEY_F7] = "F7",
-	[KEY_F8] = "F8",			[KEY_F9] = "F9",
-	[KEY_F10] = "F10",			[KEY_NUMLOCK] = "NumLock",
-	[KEY_SCROLLLOCK] = "ScrollLock",	[KEY_KP7] = "KP7",
-	[KEY_KP8] = "KP8",			[KEY_KP9] = "KP9",
-	[KEY_KPMINUS] = "KPMinus",		[KEY_KP4] = "KP4",
-	[KEY_KP5] = "KP5",			[KEY_KP6] = "KP6",
-	[KEY_KPPLUS] = "KPPlus",		[KEY_KP1] = "KP1",
-	[KEY_KP2] = "KP2",			[KEY_KP3] = "KP3",
-	[KEY_KP0] = "KP0",			[KEY_KPDOT] = "KPDot",
-	[KEY_ZENKAKUHANKAKU] = "Zenkaku/Hankaku", [KEY_102ND] = "102nd",
-	[KEY_F11] = "F11",			[KEY_F12] = "F12",
-	[KEY_RO] = "RO",			[KEY_KATAKANA] = "Katakana",
-	[KEY_HIRAGANA] = "HIRAGANA",		[KEY_HENKAN] = "Henkan",
-	[KEY_KATAKANAHIRAGANA] = "Katakana/Hiragana", [KEY_MUHENKAN] = "Muhenkan",
-	[KEY_KPJPCOMMA] = "KPJpComma",		[KEY_KPENTER] = "KPEnter",
-	[KEY_RIGHTCTRL] = "RightCtrl",		[KEY_KPSLASH] = "KPSlash",
-	[KEY_SYSRQ] = "SysRq",			[KEY_RIGHTALT] = "RightAlt",
-	[KEY_LINEFEED] = "LineFeed",		[KEY_HOME] = "Home",
-	[KEY_UP] = "Up",			[KEY_PAGEUP] = "PageUp",
-	[KEY_LEFT] = "Left",			[KEY_RIGHT] = "Right",
-	[KEY_END] = "End",			[KEY_DOWN] = "Down",
-	[KEY_PAGEDOWN] = "PageDown",		[KEY_INSERT] = "Insert",
-	[KEY_DELETE] = "Delete",		[KEY_MACRO] = "Macro",
-	[KEY_MUTE] = "Mute",			[KEY_VOLUMEDOWN] = "VolumeDown",
-	[KEY_VOLUMEUP] = "VolumeUp",		[KEY_POWER] = "Power",
-	[KEY_KPEQUAL] = "KPEqual",		[KEY_KPPLUSMINUS] = "KPPlusMinus",
-	[KEY_PAUSE] = "Pause",			[KEY_KPCOMMA] = "KPComma",
-	[KEY_HANGUEL] = "Hangeul",		[KEY_HANJA] = "Hanja",
-	[KEY_YEN] = "Yen",			[KEY_LEFTMETA] = "LeftMeta",
-	[KEY_RIGHTMETA] = "RightMeta",		[KEY_COMPOSE] = "Compose",
-	[KEY_STOP] = "Stop",			[KEY_AGAIN] = "Again",
-	[KEY_PROPS] = "Props",			[KEY_UNDO] = "Undo",
-	[KEY_FRONT] = "Front",			[KEY_COPY] = "Copy",
-	[KEY_OPEN] = "Open",			[KEY_PASTE] = "Paste",
-	[KEY_FIND] = "Find",			[KEY_CUT] = "Cut",
-	[KEY_HELP] = "Help",			[KEY_MENU] = "Menu",
-	[KEY_CALC] = "Calc",			[KEY_SETUP] = "Setup",
-	[KEY_SLEEP] = "Sleep",			[KEY_WAKEUP] = "WakeUp",
-	[KEY_FILE] = "File",			[KEY_SENDFILE] = "SendFile",
-	[KEY_DELETEFILE] = "DeleteFile",	[KEY_XFER] = "X-fer",
-	[KEY_PROG1] = "Prog1",			[KEY_PROG2] = "Prog2",
-	[KEY_WWW] = "WWW",			[KEY_MSDOS] = "MSDOS",
-	[KEY_COFFEE] = "Coffee",		[KEY_DIRECTION] = "Direction",
-	[KEY_CYCLEWINDOWS] = "CycleWindows",	[KEY_MAIL] = "Mail",
-	[KEY_BOOKMARKS] = "Bookmarks",		[KEY_COMPUTER] = "Computer",
-	[KEY_BACK] = "Back",			[KEY_FORWARD] = "Forward",
-	[KEY_CLOSECD] = "CloseCD",		[KEY_EJECTCD] = "EjectCD",
-	[KEY_EJECTCLOSECD] = "EjectCloseCD",	[KEY_NEXTSONG] = "NextSong",
-	[KEY_PLAYPAUSE] = "PlayPause",		[KEY_PREVIOUSSONG] = "PreviousSong",
-	[KEY_STOPCD] = "StopCD",		[KEY_RECORD] = "Record",
-	[KEY_REWIND] = "Rewind",		[KEY_PHONE] = "Phone",
-	[KEY_ISO] = "ISOKey",			[KEY_CONFIG] = "Config",
-	[KEY_HOMEPAGE] = "HomePage",		[KEY_REFRESH] = "Refresh",
-	[KEY_EXIT] = "Exit",			[KEY_MOVE] = "Move",
-	[KEY_EDIT] = "Edit",			[KEY_SCROLLUP] = "ScrollUp",
-	[KEY_SCROLLDOWN] = "ScrollDown",	[KEY_KPLEFTPAREN] = "KPLeftParenthesis",
-	[KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_NEW] = "New",
-	[KEY_REDO] = "Redo",			[KEY_F13] = "F13",
-	[KEY_F14] = "F14",			[KEY_F15] = "F15",
-	[KEY_F16] = "F16",			[KEY_F17] = "F17",
-	[KEY_F18] = "F18",			[KEY_F19] = "F19",
-	[KEY_F20] = "F20",			[KEY_F21] = "F21",
-	[KEY_F22] = "F22",			[KEY_F23] = "F23",
-	[KEY_F24] = "F24",			[KEY_PLAYCD] = "PlayCD",
-	[KEY_PAUSECD] = "PauseCD",		[KEY_PROG3] = "Prog3",
-	[KEY_PROG4] = "Prog4",			[KEY_SUSPEND] = "Suspend",
-	[KEY_CLOSE] = "Close",			[KEY_PLAY] = "Play",
-	[KEY_FASTFORWARD] = "FastForward",	[KEY_BASSBOOST] = "BassBoost",
-	[KEY_PRINT] = "Print",			[KEY_HP] = "HP",
-	[KEY_CAMERA] = "Camera",		[KEY_SOUND] = "Sound",
-	[KEY_QUESTION] = "Question",		[KEY_EMAIL] = "Email",
-	[KEY_CHAT] = "Chat",			[KEY_SEARCH] = "Search",
-	[KEY_CONNECT] = "Connect",		[KEY_FINANCE] = "Finance",
-	[KEY_SPORT] = "Sport",			[KEY_SHOP] = "Shop",
-	[KEY_ALTERASE] = "AlternateErase",	[KEY_CANCEL] = "Cancel",
-	[KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp",
-	[KEY_MEDIA] = "Media",			[KEY_UNKNOWN] = "Unknown",
-	[BTN_0] = "Btn0",			[BTN_1] = "Btn1",
-	[BTN_2] = "Btn2",			[BTN_3] = "Btn3",
-	[BTN_4] = "Btn4",			[BTN_5] = "Btn5",
-	[BTN_6] = "Btn6",			[BTN_7] = "Btn7",
-	[BTN_8] = "Btn8",			[BTN_9] = "Btn9",
-	[BTN_LEFT] = "LeftBtn",			[BTN_RIGHT] = "RightBtn",
-	[BTN_MIDDLE] = "MiddleBtn",		[BTN_SIDE] = "SideBtn",
-	[BTN_EXTRA] = "ExtraBtn",		[BTN_FORWARD] = "ForwardBtn",
-	[BTN_BACK] = "BackBtn",			[BTN_TASK] = "TaskBtn",
-	[BTN_TRIGGER] = "Trigger",		[BTN_THUMB] = "ThumbBtn",
-	[BTN_THUMB2] = "ThumbBtn2",		[BTN_TOP] = "TopBtn",
-	[BTN_TOP2] = "TopBtn2",			[BTN_PINKIE] = "PinkieBtn",
-	[BTN_BASE] = "BaseBtn",			[BTN_BASE2] = "BaseBtn2",
-	[BTN_BASE3] = "BaseBtn3",		[BTN_BASE4] = "BaseBtn4",
-	[BTN_BASE5] = "BaseBtn5",		[BTN_BASE6] = "BaseBtn6",
-	[BTN_DEAD] = "BtnDead",			[BTN_A] = "BtnA",
-	[BTN_B] = "BtnB",			[BTN_C] = "BtnC",
-	[BTN_X] = "BtnX",			[BTN_Y] = "BtnY",
-	[BTN_Z] = "BtnZ",			[BTN_TL] = "BtnTL",
-	[BTN_TR] = "BtnTR",			[BTN_TL2] = "BtnTL2",
-	[BTN_TR2] = "BtnTR2",			[BTN_SELECT] = "BtnSelect",
-	[BTN_START] = "BtnStart",		[BTN_MODE] = "BtnMode",
-	[BTN_THUMBL] = "BtnThumbL",		[BTN_THUMBR] = "BtnThumbR",
-	[BTN_TOOL_PEN] = "ToolPen",		[BTN_TOOL_RUBBER] = "ToolRubber",
-	[BTN_TOOL_BRUSH] = "ToolBrush",		[BTN_TOOL_PENCIL] = "ToolPencil",
-	[BTN_TOOL_AIRBRUSH] = "ToolAirbrush",	[BTN_TOOL_FINGER] = "ToolFinger",
-	[BTN_TOOL_MOUSE] = "ToolMouse",		[BTN_TOOL_LENS] = "ToolLens",
-	[BTN_TOUCH] = "Touch",			[BTN_STYLUS] = "Stylus",
-	[BTN_STYLUS2] = "Stylus2",		[BTN_TOOL_DOUBLETAP] = "ToolDoubleTap",
-	[BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn",
-	[BTN_GEAR_UP] = "Gear up",		[KEY_OK] = "Ok",
-	[KEY_SELECT] = "Select",		[KEY_GOTO] = "Goto",
-	[KEY_CLEAR] = "Clear",			[KEY_POWER2] = "Power2",
-	[KEY_OPTION] = "Option",		[KEY_INFO] = "Info",
-	[KEY_TIME] = "Time",			[KEY_VENDOR] = "Vendor",
-	[KEY_ARCHIVE] = "Archive",		[KEY_PROGRAM] = "Program",
-	[KEY_CHANNEL] = "Channel",		[KEY_FAVORITES] = "Favorites",
-	[KEY_EPG] = "EPG",			[KEY_PVR] = "PVR",
-	[KEY_MHP] = "MHP",			[KEY_LANGUAGE] = "Language",
-	[KEY_TITLE] = "Title",			[KEY_SUBTITLE] = "Subtitle",
-	[KEY_ANGLE] = "Angle",			[KEY_ZOOM] = "Zoom",
-	[KEY_MODE] = "Mode",			[KEY_KEYBOARD] = "Keyboard",
-	[KEY_SCREEN] = "Screen",		[KEY_PC] = "PC",
-	[KEY_TV] = "TV",			[KEY_TV2] = "TV2",
-	[KEY_VCR] = "VCR",			[KEY_VCR2] = "VCR2",
-	[KEY_SAT] = "Sat",			[KEY_SAT2] = "Sat2",
-	[KEY_CD] = "CD",			[KEY_TAPE] = "Tape",
-	[KEY_RADIO] = "Radio",			[KEY_TUNER] = "Tuner",
-	[KEY_PLAYER] = "Player",		[KEY_TEXT] = "Text",
-	[KEY_DVD] = "DVD",			[KEY_AUX] = "Aux",
-	[KEY_MP3] = "MP3",			[KEY_AUDIO] = "Audio",
-	[KEY_VIDEO] = "Video",			[KEY_DIRECTORY] = "Directory",
-	[KEY_LIST] = "List",			[KEY_MEMO] = "Memo",
-	[KEY_CALENDAR] = "Calendar",		[KEY_RED] = "Red",
-	[KEY_GREEN] = "Green",			[KEY_YELLOW] = "Yellow",
-	[KEY_BLUE] = "Blue",			[KEY_CHANNELUP] = "ChannelUp",
-	[KEY_CHANNELDOWN] = "ChannelDown",	[KEY_FIRST] = "First",
-	[KEY_LAST] = "Last",			[KEY_AB] = "AB",
-	[KEY_NEXT] = "Next",			[KEY_RESTART] = "Restart",
-	[KEY_SLOW] = "Slow",			[KEY_SHUFFLE] = "Shuffle",
-	[KEY_BREAK] = "Break",			[KEY_PREVIOUS] = "Previous",
-	[KEY_DIGITS] = "Digits",		[KEY_TEEN] = "TEEN",
-	[KEY_TWEN] = "TWEN",			[KEY_DEL_EOL] = "DeleteEOL",
-	[KEY_DEL_EOS] = "DeleteEOS",		[KEY_INS_LINE] = "InsertLine",
-	[KEY_DEL_LINE] = "DeleteLine",
-	[KEY_SEND] = "Send",			[KEY_REPLY] = "Reply",
-	[KEY_FORWARDMAIL] = "ForwardMail",	[KEY_SAVE] = "Save",
-	[KEY_DOCUMENTS] = "Documents",
-	[KEY_FN] = "Fn",			[KEY_FN_ESC] = "Fn+ESC",
-	[KEY_FN_1] = "Fn+1",			[KEY_FN_2] = "Fn+2",
-	[KEY_FN_B] = "Fn+B",			[KEY_FN_D] = "Fn+D",
-	[KEY_FN_E] = "Fn+E",			[KEY_FN_F] = "Fn+F",
-	[KEY_FN_S] = "Fn+S",
-	[KEY_FN_F1] = "Fn+F1",			[KEY_FN_F2] = "Fn+F2",
-	[KEY_FN_F3] = "Fn+F3",			[KEY_FN_F4] = "Fn+F4",
-	[KEY_FN_F5] = "Fn+F5",			[KEY_FN_F6] = "Fn+F6",
-	[KEY_FN_F7] = "Fn+F7",			[KEY_FN_F8] = "Fn+F8",
-	[KEY_FN_F9] = "Fn+F9",			[KEY_FN_F10] = "Fn+F10",
-	[KEY_FN_F11] = "Fn+F11",		[KEY_FN_F12] = "Fn+F12",
-	[KEY_KBDILLUMTOGGLE] = "KbdIlluminationToggle",
-	[KEY_KBDILLUMDOWN] = "KbdIlluminationDown",
-	[KEY_KBDILLUMUP] = "KbdIlluminationUp",
-	[KEY_SWITCHVIDEOMODE] = "SwitchVideoMode",
-};
-
-static char *relatives[REL_MAX + 1] = {
-	[REL_X] = "X",			[REL_Y] = "Y",
-	[REL_Z] = "Z",			[REL_RX] = "Rx",
-	[REL_RY] = "Ry",		[REL_RZ] = "Rz",
-	[REL_HWHEEL] = "HWheel",	[REL_DIAL] = "Dial",
-	[REL_WHEEL] = "Wheel",		[REL_MISC] = "Misc",
-};
-
-static char *absolutes[ABS_MAX + 1] = {
-	[ABS_X] = "X",			[ABS_Y] = "Y",
-	[ABS_Z] = "Z",			[ABS_RX] = "Rx",
-	[ABS_RY] = "Ry",		[ABS_RZ] = "Rz",
-	[ABS_THROTTLE] = "Throttle",	[ABS_RUDDER] = "Rudder",
-	[ABS_WHEEL] = "Wheel",		[ABS_GAS] = "Gas",
-	[ABS_BRAKE] = "Brake",		[ABS_HAT0X] = "Hat0X",
-	[ABS_HAT0Y] = "Hat0Y",		[ABS_HAT1X] = "Hat1X",
-	[ABS_HAT1Y] = "Hat1Y",		[ABS_HAT2X] = "Hat2X",
-	[ABS_HAT2Y] = "Hat2Y",		[ABS_HAT3X] = "Hat3X",
-	[ABS_HAT3Y] = "Hat 3Y",		[ABS_PRESSURE] = "Pressure",
-	[ABS_DISTANCE] = "Distance",	[ABS_TILT_X] = "XTilt",
-	[ABS_TILT_Y] = "YTilt",		[ABS_TOOL_WIDTH] = "Tool Width",
-	[ABS_VOLUME] = "Volume",	[ABS_MISC] = "Misc",
-};
-
-static char *misc[MSC_MAX + 1] = {
-	[MSC_SERIAL] = "Serial",	[MSC_PULSELED] = "Pulseled",
-	[MSC_GESTURE] = "Gesture",	[MSC_RAW] = "RawData"
-};
-
-static char *leds[LED_MAX + 1] = {
-	[LED_NUML] = "NumLock",		[LED_CAPSL] = "CapsLock",
-	[LED_SCROLLL] = "ScrollLock",	[LED_COMPOSE] = "Compose",
-	[LED_KANA] = "Kana",		[LED_SLEEP] = "Sleep",
-	[LED_SUSPEND] = "Suspend",	[LED_MUTE] = "Mute",
-	[LED_MISC] = "Misc",
-};
-
-static char *repeats[REP_MAX + 1] = {
-	[REP_DELAY] = "Delay",		[REP_PERIOD] = "Period"
-};
-
-static char *sounds[SND_MAX + 1] = {
-	[SND_CLICK] = "Click",		[SND_BELL] = "Bell",
-	[SND_TONE] = "Tone"
-};
-
-static char **names[EV_MAX + 1] = {
-	[EV_SYN] = syncs,			[EV_KEY] = keys,
-	[EV_REL] = relatives,			[EV_ABS] = absolutes,
-	[EV_MSC] = misc,			[EV_LED] = leds,
-	[EV_SND] = sounds,			[EV_REP] = repeats,
-};
-
-static void __attribute__((unused)) resolv_event(__u8 type, __u16 code) {
-
-	printk("%s.%s", events[type] ? events[type] : "?",
-		names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
-}
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 342b4e6..d26b08f 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -264,6 +264,9 @@
 #define HID_QUIRK_INVERT_HWHEEL			0x00004000
 #define HID_QUIRK_POWERBOOK_ISO_KEYBOARD        0x00008000
 #define HID_QUIRK_BAD_RELATIVE_KEYS		0x00010000
+#define HID_QUIRK_SKIP_OUTPUT_REPORTS		0x00020000
+#define HID_QUIRK_IGNORE_MOUSE			0x00040000
+#define HID_QUIRK_SONY_PS3_CONTROLLER		0x00080000
 
 /*
  * This is the global environment of the parser. This information is
@@ -430,8 +433,8 @@
 
 	/* device-specific function pointers */
 	int (*hidinput_input_event) (struct input_dev *, unsigned int, unsigned int, int);
-	int (*hidinput_open) (struct input_dev *);
-	void (*hidinput_close) (struct input_dev *);
+	int (*hid_open) (struct hid_device *);
+	void (*hid_close) (struct hid_device *);
 
 	/* hiddev event handler */
 	void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field,
@@ -471,16 +474,6 @@
 	struct hid_class_descriptor desc[1];
 } __attribute__ ((packed));
 
-#ifdef DEBUG
-#include "hid-debug.h"
-#else
-#define hid_dump_input(a,b)	do { } while (0)
-#define hid_dump_device(c)	do { } while (0)
-#define hid_dump_field(a,b)	do { } while (0)
-#define resolv_usage(a)		do { } while (0)
-#define resolv_event(a,b)	do { } while (0)
-#endif
-
 /* Applications from HID Usage Tables 4/8/99 Version 1.1 */
 /* We ignore a few input applications that are not widely used */
 #define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001))
@@ -503,6 +496,7 @@
 int hid_ff_init(struct hid_device *hid);
 
 int hid_lgff_init(struct hid_device *hid);
+int hid_plff_init(struct hid_device *hid);
 int hid_tmff_init(struct hid_device *hid);
 int hid_zpff_init(struct hid_device *hid);
 #ifdef CONFIG_HID_PID
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index d38778f..6e7ec4c 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -115,6 +115,8 @@
 #define I2C_DRIVERID_KS0127	86	/* Samsung ks0127 video decoder */
 #define I2C_DRIVERID_TLV320AIC23B 87	/* TI TLV320AIC23B audio codec  */
 #define I2C_DRIVERID_ISL1208	88	/* Intersil ISL1208 RTC		*/
+#define I2C_DRIVERID_WM8731		89	/* Wolfson WM8731 audio codec */
+#define I2C_DRIVERID_WM8750		90	/* Wolfson WM8750 audio codec */
 
 #define I2C_DRIVERID_I2CDEV	900
 #define I2C_DRIVERID_ARP        902    /* SMBus ARP Client              */
diff --git a/include/linux/ide.h b/include/linux/ide.h
index e26a039..04e0fa9 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -18,6 +18,9 @@
 #include <linux/device.h>
 #include <linux/pci.h>
 #include <linux/completion.h>
+#ifdef CONFIG_BLK_DEV_IDEACPI
+#include <acpi/acpi.h>
+#endif
 #include <asm/byteorder.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -541,6 +544,11 @@
 struct ide_driver_s;
 struct ide_settings_s;
 
+#ifdef CONFIG_BLK_DEV_IDEACPI
+struct ide_acpi_drive_link;
+struct ide_acpi_hwif_link;
+#endif
+
 typedef struct ide_drive_s {
 	char		name[4];	/* drive name, such as "hda" */
         char            driver_req[10];	/* requests specific driver */
@@ -637,6 +645,9 @@
 
 	int		lun;		/* logical unit */
 	int		crc_count;	/* crc counter to reduce drive speed */
+#ifdef CONFIG_BLK_DEV_IDEACPI
+	struct ide_acpi_drive_link *acpidata;
+#endif
 	struct list_head list;
 	struct device	gendev;
 	struct completion gendev_rel_comp;	/* to deal with device release() */
@@ -804,6 +815,10 @@
 	void		*hwif_data;	/* extra hwif data */
 
 	unsigned dma;
+
+#ifdef CONFIG_BLK_DEV_IDEACPI
+	struct ide_acpi_hwif_link *acpidata;
+#endif
 } ____cacheline_internodealigned_in_smp ide_hwif_t;
 
 /*
@@ -1192,8 +1207,8 @@
 extern int ideprobe_init(void);
 
 extern void ide_scan_pcibus(int scan_direction) __init;
-extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner);
-#define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE)
+extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner, const char *mod_name);
+#define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE, KBUILD_MODNAME)
 void ide_pci_setup_ports(struct pci_dev *, struct ide_pci_device_s *, int, ata_index_t *);
 extern void ide_setup_pci_noise (struct pci_dev *dev, struct ide_pci_device_s *d);
 
@@ -1298,6 +1313,18 @@
 static inline void ide_release_dma(ide_hwif_t *drive) {;}
 #endif
 
+#ifdef CONFIG_BLK_DEV_IDEACPI
+extern int ide_acpi_exec_tfs(ide_drive_t *drive);
+extern void ide_acpi_get_timing(ide_hwif_t *hwif);
+extern void ide_acpi_push_timing(ide_hwif_t *hwif);
+extern void ide_acpi_init(ide_hwif_t *hwif);
+#else
+static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; }
+static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; }
+static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; }
+static inline void ide_acpi_init(ide_hwif_t *hwif) { ; }
+#endif
+
 extern int ide_hwif_request_regions(ide_hwif_t *hwif);
 extern void ide_hwif_release_regions(ide_hwif_t* hwif);
 extern void ide_unregister (unsigned int index);
diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h
index 99393ef..f3de05c 100644
--- a/include/linux/if_packet.h
+++ b/include/linux/if_packet.h
@@ -41,6 +41,7 @@
 #define PACKET_RX_RING			5
 #define PACKET_STATISTICS		6
 #define PACKET_COPY_THRESH		7
+#define PACKET_AUXDATA			8
 
 struct tpacket_stats
 {
@@ -48,6 +49,15 @@
 	unsigned int	tp_drops;
 };
 
+struct tpacket_auxdata
+{
+	__u32		tp_status;
+	__u32		tp_len;
+	__u32		tp_snaplen;
+	__u16		tp_mac;
+	__u16		tp_net;
+};
+
 struct tpacket_hdr
 {
 	unsigned long	tp_status;
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 52fc405..5504b67 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -68,6 +68,7 @@
 #define IRQ_MOVE_PENDING	0x40000000	/* need to re-target IRQ destination */
 
 struct proc_dir_entry;
+struct msi_desc;
 
 /**
  * struct irq_chip - hardware interrupt chip descriptor
@@ -148,6 +149,7 @@
 struct irq_desc {
 	irq_flow_handler_t	handle_irq;
 	struct irq_chip		*chip;
+	struct msi_desc		*msi_desc;
 	void			*handler_data;
 	void			*chip_data;
 	struct irqaction	*action;	/* IRQ action list */
@@ -373,10 +375,12 @@
 extern int set_irq_data(unsigned int irq, void *data);
 extern int set_irq_chip_data(unsigned int irq, void *data);
 extern int set_irq_type(unsigned int irq, unsigned int type);
+extern int set_irq_msi(unsigned int irq, struct msi_desc *entry);
 
 #define get_irq_chip(irq)	(irq_desc[irq].chip)
 #define get_irq_chip_data(irq)	(irq_desc[irq].chip_data)
 #define get_irq_data(irq)	(irq_desc[irq].handler_data)
+#define get_irq_msi(irq)	(irq_desc[irq].msi_desc)
 
 #endif /* CONFIG_GENERIC_HARDIRQS */
 
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index 76538fc..b850e03 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -74,9 +74,13 @@
 extern void kobject_cleanup(struct kobject *);
 
 extern int __must_check kobject_add(struct kobject *);
+extern int __must_check kobject_shadow_add(struct kobject *, struct dentry *);
 extern void kobject_del(struct kobject *);
 
 extern int __must_check kobject_rename(struct kobject *, const char *new_name);
+extern int __must_check kobject_shadow_rename(struct kobject *kobj,
+						struct dentry *new_parent,
+						const char *new_name);
 extern int __must_check kobject_move(struct kobject *, struct kobject *);
 
 extern int __must_check kobject_register(struct kobject *);
diff --git a/include/linux/log2.h b/include/linux/log2.h
index d02e1a5..99922be 100644
--- a/include/linux/log2.h
+++ b/include/linux/log2.h
@@ -44,6 +44,17 @@
 #endif
 
 /*
+ *  Determine whether some value is a power of two, where zero is
+ * *not* considered a power of two.
+ */
+
+static inline __attribute__((const))
+bool is_power_of_2(unsigned long n)
+{
+	return (n != 0 && ((n & (n - 1)) == 0));
+}
+
+/*
  * round up to nearest power of two
  */
 static inline __attribute__((const))
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 2d2c08d..bb793a4 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1030,6 +1030,9 @@
 	unsigned long addr, unsigned long len, pgoff_t pgoff);
 extern void exit_mmap(struct mm_struct *);
 extern int may_expand_vm(struct mm_struct *mm, unsigned long npages);
+extern int install_special_mapping(struct mm_struct *mm,
+				   unsigned long addr, unsigned long len,
+				   unsigned long flags, struct page **pages);
 
 extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index d0e6a54..e45712a 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -71,6 +71,7 @@
 #define MMC_STATE_SDCARD	(1<<3)		/* is an SD card */
 #define MMC_STATE_READONLY	(1<<4)		/* card is read-only */
 #define MMC_STATE_HIGHSPEED	(1<<5)		/* card is in high speed mode */
+#define MMC_STATE_BLOCKADDR	(1<<6)		/* card uses block-addressing */
 	u32			raw_cid[4];	/* raw card CID */
 	u32			raw_csd[4];	/* raw card CSD */
 	u32			raw_scr[2];	/* raw card SCR */
@@ -87,6 +88,7 @@
 #define mmc_card_sd(c)		((c)->state & MMC_STATE_SDCARD)
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
 #define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
+#define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_dead(c)	((c)->state |= MMC_STATE_DEAD)
@@ -94,6 +96,7 @@
 #define mmc_card_set_sd(c)	((c)->state |= MMC_STATE_SDCARD)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
+#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
 
 #define mmc_card_name(c)	((c)->cid.prod_name)
 #define mmc_card_id(c)		((c)->dev.bus_id)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index c15ae19..913e575 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -92,8 +92,10 @@
 	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
 	unsigned short		max_hw_segs;	/* see blk_queue_max_hw_segments */
 	unsigned short		max_phys_segs;	/* see blk_queue_max_phys_segments */
-	unsigned short		max_sectors;	/* see blk_queue_max_sectors */
 	unsigned short		unused;
+	unsigned int		max_req_size;	/* maximum number of bytes in one req */
+	unsigned int		max_blk_size;	/* maximum size of one mmc block */
+	unsigned int		max_blk_count;	/* maximum number of blocks in one req */
 
 	/* private data */
 	struct mmc_ios		ios;		/* current io bus settings */
@@ -106,8 +108,9 @@
 	struct list_head	cards;		/* devices attached to this host */
 
 	wait_queue_head_t	wq;
-	spinlock_t		lock;		/* card_busy lock */
-	struct mmc_card		*card_busy;	/* the MMC card claiming host */
+	spinlock_t		lock;		/* claimed lock */
+	unsigned int		claimed:1;	/* host exclusively claimed */
+
 	struct mmc_card		*card_selected;	/* the selected MMC card */
 
 	struct delayed_work	detect;
@@ -126,6 +129,7 @@
 }
 
 #define mmc_dev(x)	((x)->parent)
+#define mmc_classdev(x)	(&(x)->class_dev)
 #define mmc_hostname(x)	((x)->class_dev.bus_id)
 
 extern int mmc_suspend_host(struct mmc_host *, pm_message_t);
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index bcf2490..cdc54be 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -43,6 +43,7 @@
 #define MMC_RSP_R2	(MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC)
 #define MMC_RSP_R3	(MMC_RSP_PRESENT)
 #define MMC_RSP_R6	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+#define MMC_RSP_R7	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
 
 #define mmc_resp_type(cmd)	((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE))
 
diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h
index 2dce60c..c90b676 100644
--- a/include/linux/mmc/protocol.h
+++ b/include/linux/mmc/protocol.h
@@ -79,9 +79,12 @@
 #define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1  */
 
 /* SD commands                           type  argument     response */
-  /* class 8 */
+  /* class 0 */
 /* This is basically the same command as for MMC with some quirks. */
 #define SD_SEND_RELATIVE_ADDR     3   /* bcr                     R6  */
+#define SD_SEND_IF_COND           8   /* bcr  [11:0] See below   R7  */
+
+  /* class 10 */
 #define SD_SWITCH                 6   /* adtc [31:0] See below   R1  */
 
   /* Application commands */
@@ -115,6 +118,14 @@
  */
 
 /*
+ * SD_SEND_IF_COND argument format:
+ *
+ *	[31:12] Reserved (0)
+ *	[11:8] Host Voltage Supply Flags
+ *	[7:0] Check Pattern (0xAA)
+ */
+
+/*
   MMC status in R1
   Type
   	e : error bit
diff --git a/include/linux/module.h b/include/linux/module.h
index 10f771a..419d3ef 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -58,6 +58,7 @@
 {
 	struct kobject kobj;
 	struct module *mod;
+	struct kobject *drivers_dir;
 };
 
 /* These are either module local, or the kernel's dummy ones. */
@@ -263,7 +264,7 @@
 	struct module_attribute *modinfo_attrs;
 	const char *version;
 	const char *srcversion;
-	struct kobject *drivers_dir;
+	struct kobject *holders_dir;
 
 	/* Exported symbols */
 	const struct kernel_symbol *syms;
diff --git a/include/linux/msi.h b/include/linux/msi.h
index c7ef943..74c8a2e 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -7,11 +7,10 @@
 	u32	data;		/* 16 bits of msi message data */
 };
 
-/* Heper functions */
+/* Helper functions */
 extern void mask_msi_irq(unsigned int irq);
 extern void unmask_msi_irq(unsigned int irq);
 extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
-
 extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
 
 struct msi_desc {
@@ -42,7 +41,7 @@
 /*
  * The arch hook for setup up msi irqs
  */
-int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev);
+int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc);
 void arch_teardown_msi_irq(unsigned int irq);
 
 
diff --git a/include/linux/net.h b/include/linux/net.h
index f28d8a2..4db21e6 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -24,7 +24,7 @@
 struct poll_table_struct;
 struct inode;
 
-#define NPROTO		32		/* should be enough for now..	*/
+#define NPROTO		33		/* should be enough for now..	*/
 
 #define SYS_SOCKET	1		/* sys_socket(2)		*/
 #define SYS_BIND	2		/* sys_bind(2)			*/
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index fea0d9d..1a52854 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -529,10 +529,11 @@
 	struct net_bridge_port	*br_port;
 
 	/* class/net/name entry */
-	struct class_device	class_dev;
+	struct device		dev;
 	/* space for optional statistics and wireless sysfs groups */
 	struct attribute_group  *sysfs_groups[3];
 };
+#define to_net_dev(d) container_of(d, struct net_device, dev)
 
 #define	NETDEV_ALIGN		32
 #define	NETDEV_ALIGN_CONST	(NETDEV_ALIGN - 1)
@@ -548,7 +549,7 @@
 /* Set the sysfs physical device reference for the network logical device
  * if set prior to registration will cause a symlink during initialization.
  */
-#define SET_NETDEV_DEV(net, pdev)	((net)->class_dev.dev = (pdev))
+#define SET_NETDEV_DEV(net, pdev)	((net)->dev.parent = (pdev))
 
 struct packet_type {
 	__be16			type;	/* This is really htons(ether_type). */
@@ -588,7 +589,7 @@
 extern int		dev_close(struct net_device *dev);
 extern int		dev_queue_xmit(struct sk_buff *skb);
 extern int		register_netdevice(struct net_device *dev);
-extern int		unregister_netdevice(struct net_device *dev);
+extern void		unregister_netdevice(struct net_device *dev);
 extern void		free_netdev(struct net_device *dev);
 extern void		synchronize_net(void);
 extern int 		register_netdevice_notifier(struct notifier_block *nb);
diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild
index 6328175..43397a4 100644
--- a/include/linux/netfilter/Kbuild
+++ b/include/linux/netfilter/Kbuild
@@ -33,6 +33,7 @@
 header-y += xt_tcpudp.h
 header-y += xt_SECMARK.h
 header-y += xt_CONNSECMARK.h
+header-y += xt_TCPMSS.h
 
 unifdef-y += nf_conntrack_common.h
 unifdef-y += nf_conntrack_ftp.h
diff --git a/include/linux/netfilter/nf_conntrack_sane.h b/include/linux/netfilter/nf_conntrack_sane.h
new file mode 100644
index 0000000..4767d6e
--- /dev/null
+++ b/include/linux/netfilter/nf_conntrack_sane.h
@@ -0,0 +1,21 @@
+#ifndef _NF_CONNTRACK_SANE_H
+#define _NF_CONNTRACK_SANE_H
+/* SANE tracking. */
+
+#ifdef __KERNEL__
+
+#define SANE_PORT	6566
+
+enum sane_state {
+	SANE_STATE_NORMAL,
+	SANE_STATE_START_REQUESTED,
+};
+
+/* This structure exists only once per master */
+struct nf_ct_sane_master {
+	enum sane_state state;
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* _NF_CONNTRACK_SANE_H */
diff --git a/include/linux/netfilter/nf_conntrack_tcp.h b/include/linux/netfilter/nf_conntrack_tcp.h
index 2f4e98b..007af4c 100644
--- a/include/linux/netfilter/nf_conntrack_tcp.h
+++ b/include/linux/netfilter/nf_conntrack_tcp.h
@@ -27,6 +27,9 @@
 /* This sender sent FIN first */
 #define IP_CT_TCP_FLAG_CLOSE_INIT		0x04
 
+/* Be liberal in window checking */
+#define IP_CT_TCP_FLAG_BE_LIBERAL		0x08
+
 #ifdef __KERNEL__
 
 struct ip_ct_tcp_state {
@@ -34,7 +37,6 @@
 	u_int32_t	td_maxend;	/* max of ack + max(win, 1) */
 	u_int32_t	td_maxwin;	/* max(win) */
 	u_int8_t	td_scale;	/* window scale factor */
-	u_int8_t	loose;		/* used when connection picked up from the middle */
 	u_int8_t	flags;		/* per direction options */
 };
 
diff --git a/include/linux/netfilter/xt_TCPMSS.h b/include/linux/netfilter/xt_TCPMSS.h
new file mode 100644
index 0000000..53a292c
--- /dev/null
+++ b/include/linux/netfilter/xt_TCPMSS.h
@@ -0,0 +1,10 @@
+#ifndef _XT_TCPMSS_H
+#define _XT_TCPMSS_H
+
+struct xt_tcpmss_info {
+	u_int16_t mss;
+};
+
+#define XT_TCPMSS_CLAMP_PMTU 0xffff
+
+#endif /* _XT_TCPMSS_H */
diff --git a/include/linux/netfilter_ipv4/ip_nat.h b/include/linux/netfilter_ipv4/ip_nat.h
index bdf5536..bbca89a 100644
--- a/include/linux/netfilter_ipv4/ip_nat.h
+++ b/include/linux/netfilter_ipv4/ip_nat.h
@@ -16,6 +16,7 @@
 
 #define IP_NAT_RANGE_MAP_IPS 1
 #define IP_NAT_RANGE_PROTO_SPECIFIED 2
+#define IP_NAT_RANGE_PROTO_RANDOM 4 /* add randomness to "port" selection */
 
 /* NAT sequence number modifications */
 struct ip_nat_seq {
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h
index 98d566c..9527296 100644
--- a/include/linux/netfilter_ipv4/ip_tables.h
+++ b/include/linux/netfilter_ipv4/ip_tables.h
@@ -272,25 +272,9 @@
 #include <linux/init.h>
 extern void ipt_init(void) __init;
 
-#define ipt_register_target(tgt) 	\
-({	(tgt)->family = AF_INET;	\
- 	xt_register_target(tgt); })
-#define ipt_unregister_target(tgt) xt_unregister_target(tgt)
-
-#define ipt_register_match(mtch) 	\
-({	(mtch)->family = AF_INET;	\
-	xt_register_match(mtch); })
-#define ipt_unregister_match(mtch) xt_unregister_match(mtch)
-
-//#define ipt_register_table(tbl, repl) xt_register_table(AF_INET, tbl, repl)
-//#define ipt_unregister_table(tbl) xt_unregister_table(AF_INET, tbl)
-
-extern int ipt_register_table(struct ipt_table *table,
+extern int ipt_register_table(struct xt_table *table,
 			      const struct ipt_replace *repl);
-extern void ipt_unregister_table(struct ipt_table *table);
-
-/* net/sched/ipt.c: Gimme access to your targets!  Gets target->me. */
-extern struct ipt_target *ipt_find_target(const char *name, u8 revision);
+extern void ipt_unregister_table(struct xt_table *table);
 
 /* Standard entry. */
 struct ipt_standard
@@ -315,7 +299,7 @@
 				 unsigned int hook,
 				 const struct net_device *in,
 				 const struct net_device *out,
-				 struct ipt_table *table);
+				 struct xt_table *table);
 
 #define IPT_ALIGN(s) XT_ALIGN(s)
 
diff --git a/include/linux/netfilter_ipv4/ipt_TCPMSS.h b/include/linux/netfilter_ipv4/ipt_TCPMSS.h
index aadb395..7a850f9 100644
--- a/include/linux/netfilter_ipv4/ipt_TCPMSS.h
+++ b/include/linux/netfilter_ipv4/ipt_TCPMSS.h
@@ -1,10 +1,9 @@
 #ifndef _IPT_TCPMSS_H
 #define _IPT_TCPMSS_H
 
-struct ipt_tcpmss_info {
-	u_int16_t mss;
-};
+#include <linux/netfilter/xt_TCPMSS.h>
 
-#define IPT_TCPMSS_CLAMP_PMTU 0xffff
+#define ipt_tcpmss_info		xt_tcpmss_info
+#define IPT_TCPMSS_CLAMP_PMTU	XT_TCPMSS_CLAMP_PMTU
 
 #endif /*_IPT_TCPMSS_H*/
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
index 4aed340..61aa104 100644
--- a/include/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -104,6 +104,25 @@
 	unsigned char elems[0];
 };
 
+/* Standard entry */
+struct ip6t_standard
+{
+	struct ip6t_entry entry;
+	struct ip6t_standard_target target;
+};
+
+struct ip6t_error_target
+{
+	struct ip6t_entry_target target;
+	char errorname[IP6T_FUNCTION_MAXNAMELEN];
+};
+
+struct ip6t_error
+{
+	struct ip6t_entry entry;
+	struct ip6t_error_target target;
+};
+
 /*
  * New IP firewall options for [gs]etsockopt at the RAW IP level.
  * Unlike BSD Linux inherits IP options so you don't have to use
@@ -286,24 +305,14 @@
 #include <linux/init.h>
 extern void ip6t_init(void) __init;
 
-#define ip6t_register_target(tgt) 		\
-({	(tgt)->family = AF_INET6;		\
- 	xt_register_target(tgt); })
-#define ip6t_unregister_target(tgt) xt_unregister_target(tgt)
-
-#define ip6t_register_match(match)		\
-({	(match)->family = AF_INET6;		\
-	xt_register_match(match); })
-#define ip6t_unregister_match(match) xt_unregister_match(match)
-
-extern int ip6t_register_table(struct ip6t_table *table,
+extern int ip6t_register_table(struct xt_table *table,
 			       const struct ip6t_replace *repl);
-extern void ip6t_unregister_table(struct ip6t_table *table);
+extern void ip6t_unregister_table(struct xt_table *table);
 extern unsigned int ip6t_do_table(struct sk_buff **pskb,
 				  unsigned int hook,
 				  const struct net_device *in,
 				  const struct net_device *out,
-				  struct ip6t_table *table);
+				  struct xt_table *table);
 
 /* Check for an extension */
 extern int ip6t_ext_hdr(u8 nexthdr);
diff --git a/include/linux/netfilter_ipv6/ip6t_mh.h b/include/linux/netfilter_ipv6/ip6t_mh.h
new file mode 100644
index 0000000..b9ca9a5
--- /dev/null
+++ b/include/linux/netfilter_ipv6/ip6t_mh.h
@@ -0,0 +1,15 @@
+#ifndef _IP6T_MH_H
+#define _IP6T_MH_H
+
+/* MH matching stuff */
+struct ip6t_mh
+{
+	u_int8_t types[2];	/* MH type range */
+	u_int8_t invflags;	/* Inverse flags */
+};
+
+/* Values for "invflags" field in struct ip6t_mh. */
+#define IP6T_MH_INV_TYPE	0x01	/* Invert the sense of type. */
+#define IP6T_MH_INV_MASK	0x01	/* All possible flags. */
+
+#endif /*_IP6T_MH_H*/
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index c3e255b..7a8dcb8 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -76,8 +76,6 @@
 				unsigned long index);
 extern struct page * find_lock_page(struct address_space *mapping,
 				unsigned long index);
-extern __deprecated_for_modules struct page * find_trylock_page(
-			struct address_space *mapping, unsigned long index);
 extern struct page * find_or_create_page(struct address_space *mapping,
 				unsigned long index, gfp_t gfp_mask);
 unsigned find_get_pages(struct address_space *mapping, pgoff_t start,
diff --git a/include/linux/pci.h b/include/linux/pci.h
index f3c617e..805412c 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -174,6 +174,9 @@
 	struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */
 	int rom_attr_enabled;		/* has display of the rom attribute been enabled? */
 	struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */
+#ifdef CONFIG_PCI_MSI
+	unsigned int first_msi_irq;
+#endif
 };
 
 #define pci_dev_g(n) list_entry(n, struct pci_dev, global_list)
@@ -181,6 +184,11 @@
 #define	to_pci_dev(n) container_of(n, struct pci_dev, dev)
 #define for_each_pci_dev(d) while ((d = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, d)) != NULL)
 
+static inline int pci_channel_offline(struct pci_dev *pdev)
+{
+	return (pdev->error_state != pci_channel_io_normal);
+}
+
 static inline struct pci_cap_saved_state *pci_find_saved_cap(
 	struct pci_dev *pci_dev,char cap)
 {
@@ -463,8 +471,7 @@
 
 /* Generic PCI functions exported to card drivers */
 
-struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from);
-struct pci_dev *pci_find_device_reverse (unsigned int vendor, unsigned int device, const struct pci_dev *from);
+struct pci_dev __deprecated *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from);
 struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
 int pci_find_capability (struct pci_dev *dev, int cap);
 int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap);
@@ -533,6 +540,7 @@
 int __must_check pci_assign_resource(struct pci_dev *dev, int i);
 int __must_check pci_assign_resource_fixed(struct pci_dev *dev, int i);
 void pci_restore_bars(struct pci_dev *dev);
+int pci_select_bars(struct pci_dev *dev, unsigned long flags);
 
 /* ROM control related routines */
 void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size);
@@ -561,6 +569,8 @@
 void pci_release_regions(struct pci_dev *);
 int __must_check pci_request_region(struct pci_dev *, int, const char *);
 void pci_release_region(struct pci_dev *, int);
+int pci_request_selected_regions(struct pci_dev *, int, const char *);
+void pci_release_selected_regions(struct pci_dev *, int);
 
 /* drivers/pci/bus.c */
 int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
@@ -573,10 +583,11 @@
 void pci_enable_bridges(struct pci_bus *bus);
 
 /* Proper probing supporting hot-pluggable devices */
-int __must_check __pci_register_driver(struct pci_driver *, struct module *);
+int __must_check __pci_register_driver(struct pci_driver *, struct module *,
+				       const char *mod_name);
 static inline int __must_check pci_register_driver(struct pci_driver *driver)
 {
-	return __pci_register_driver(driver, THIS_MODULE);
+	return __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
 }
 
 void pci_unregister_driver(struct pci_driver *);
@@ -611,10 +622,6 @@
 				   strategy_parameter byte boundaries */
 };
 
-#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
-extern struct pci_dev *isa_bridge;
-#endif
-
 struct msix_entry {
 	u16 	vector;	/* kernel uses to write allocated vector */
 	u16	entry;	/* driver uses to specify entry, OS writes */
@@ -622,7 +629,6 @@
 
 
 #ifndef CONFIG_PCI_MSI
-static inline void pci_scan_msi_device(struct pci_dev *dev) {}
 static inline int pci_enable_msi(struct pci_dev *dev) {return -1;}
 static inline void pci_disable_msi(struct pci_dev *dev) {}
 static inline int pci_enable_msix(struct pci_dev* dev,
@@ -630,7 +636,6 @@
 static inline void pci_disable_msix(struct pci_dev *dev) {}
 static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
 #else
-extern void pci_scan_msi_device(struct pci_dev *dev);
 extern int pci_enable_msi(struct pci_dev *dev);
 extern void pci_disable_msi(struct pci_dev *dev);
 extern int pci_enable_msix(struct pci_dev* dev,
@@ -722,8 +727,6 @@
 static inline pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { return PCI_D0; }
 static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) { return 0; }
 
-#define	isa_bridge	((struct pci_dev *)NULL)
-
 #define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0)
 
 static inline void pci_block_user_cfg_access(struct pci_dev *dev) { }
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 3d1d210..6252cb9 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -95,6 +95,7 @@
 
 #define PCI_BASE_CLASS_SERIAL		0x0c
 #define PCI_CLASS_SERIAL_FIREWIRE	0x0c00
+#define PCI_CLASS_SERIAL_FIREWIRE_OHCI	0x0c0010
 #define PCI_CLASS_SERIAL_ACCESS		0x0c01
 #define PCI_CLASS_SERIAL_SSA		0x0c02
 #define PCI_CLASS_SERIAL_USB		0x0c03
@@ -735,9 +736,11 @@
 #define PCI_DEVICE_ID_TI_TVP4020	0x3d07
 #define PCI_DEVICE_ID_TI_4450		0x8011
 #define PCI_DEVICE_ID_TI_XX21_XX11	0x8031
+#define PCI_DEVICE_ID_TI_XX21_XX11_FM	0x8033
 #define PCI_DEVICE_ID_TI_XX21_XX11_SD	0x8034
 #define PCI_DEVICE_ID_TI_X515		0x8036
 #define PCI_DEVICE_ID_TI_XX12		0x8039
+#define PCI_DEVICE_ID_TI_XX12_FM	0x803b
 #define PCI_DEVICE_ID_TI_1130		0xac12
 #define PCI_DEVICE_ID_TI_1031		0xac13
 #define PCI_DEVICE_ID_TI_1131		0xac15
@@ -765,6 +768,7 @@
 #define PCI_DEVICE_ID_TI_1510		0xac56
 #define PCI_DEVICE_ID_TI_X620		0xac8d
 #define PCI_DEVICE_ID_TI_X420		0xac8e
+#define PCI_DEVICE_ID_TI_XX20_FM	0xac8f
 
 #define PCI_VENDOR_ID_SONY		0x104d
 
@@ -1451,6 +1455,7 @@
 
 #define PCI_VENDOR_ID_TOSHIBA_2		0x102f
 #define PCI_DEVICE_ID_TOSHIBA_TC35815CF	0x0030
+#define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE	0x0105
 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC	0x0108
 #define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3
 
@@ -1971,6 +1976,7 @@
 #define PCI_DEVICE_ID_TOPIC_TP560	0x0000
 
 #define PCI_VENDOR_ID_ENE		0x1524
+#define PCI_DEVICE_ID_ENE_CB712_SD	0x0550
 #define PCI_DEVICE_ID_ENE_1211		0x1211
 #define PCI_DEVICE_ID_ENE_1225		0x1225
 #define PCI_DEVICE_ID_ENE_1410		0x1410
@@ -2066,6 +2072,10 @@
 #define PCI_VENDOR_ID_TDI               0x192E
 #define PCI_DEVICE_ID_TDI_EHCI          0x0101
 
+#define PCI_VENDOR_ID_PASEMI		0x1959
+
+#define PCI_VENDOR_ID_ATTANSIC		0x1969
+
 #define PCI_VENDOR_ID_JMICRON		0x197B
 #define PCI_DEVICE_ID_JMICRON_JMB360	0x2360
 #define PCI_DEVICE_ID_JMICRON_JMB361	0x2361
diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h
index 265bafa..d9db5f6 100644
--- a/include/linux/pfkeyv2.h
+++ b/include/linux/pfkeyv2.h
@@ -251,7 +251,8 @@
 #define SADB_X_SPDEXPIRE	21
 #define SADB_X_SPDDELETE2	22
 #define SADB_X_NAT_T_NEW_MAPPING	23
-#define SADB_MAX		23
+#define SADB_X_MIGRATE		24
+#define SADB_MAX		24
 
 /* Security Association flags */
 #define SADB_SAFLAGS_PFS	1
@@ -297,6 +298,7 @@
 #define SADB_X_EALG_BLOWFISHCBC		7
 #define SADB_EALG_NULL			11
 #define SADB_X_EALG_AESCBC		12
+#define SADB_X_EALG_CAMELLIACBC		22
 #define SADB_EALG_MAX                   253 /* last EALG */
 /* private allocations should use 249-255 (RFC2407) */
 #define SADB_X_EALG_SERPENTCBC  252     /* draft-ietf-ipsec-ciph-aes-cbc-00 */
diff --git a/include/linux/raid/bitmap.h b/include/linux/raid/bitmap.h
index ebd42a3..6db9a4c 100644
--- a/include/linux/raid/bitmap.h
+++ b/include/linux/raid/bitmap.h
@@ -247,6 +247,7 @@
 
 	atomic_t pending_writes; /* pending writes to the bitmap file */
 	wait_queue_head_t write_wait;
+	wait_queue_head_t overflow_wait;
 
 };
 
diff --git a/include/linux/serio.h b/include/linux/serio.h
index 0f478a8..ac2c70e 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -86,6 +86,11 @@
 void serio_unregister_port(struct serio *serio);
 void serio_unregister_child_port(struct serio *serio);
 
+int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name);
+static inline int serio_register_driver(struct serio_driver *drv)
+{
+	return __serio_register_driver(drv, THIS_MODULE, KBUILD_MODNAME);
+}
 int serio_register_driver(struct serio_driver *drv);
 void serio_unregister_driver(struct serio_driver *drv);
 
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 92cd38e..fcd35a2 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -187,7 +187,8 @@
 #define AF_LLC		26	/* Linux LLC			*/
 #define AF_TIPC		30	/* TIPC sockets			*/
 #define AF_BLUETOOTH	31	/* Bluetooth sockets 		*/
-#define AF_MAX		32	/* For now.. */
+#define AF_IUCV		32	/* IUCV sockets			*/
+#define AF_MAX		33	/* For now.. */
 
 /* Protocol families, same as address families. */
 #define PF_UNSPEC	AF_UNSPEC
@@ -220,6 +221,7 @@
 #define PF_LLC		AF_LLC
 #define PF_TIPC		AF_TIPC
 #define PF_BLUETOOTH	AF_BLUETOOTH
+#define PF_IUCV		AF_IUCV
 #define PF_MAX		AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 98b21ad..db312a1 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -63,7 +63,7 @@
  * Function prototypes.
  */
 int		svc_makesock(struct svc_serv *, int, unsigned short);
-void		svc_delete_socket(struct svc_sock *);
+void		svc_close_socket(struct svc_sock *);
 int		svc_recv(struct svc_rqst *, long);
 int		svc_send(struct svc_rqst *);
 void		svc_drop(struct svc_rqst *);
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 81480e6..665412c 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -699,7 +699,8 @@
 	NET_X25_CALL_REQUEST_TIMEOUT=2,
 	NET_X25_RESET_REQUEST_TIMEOUT=3,
 	NET_X25_CLEAR_REQUEST_TIMEOUT=4,
-	NET_X25_ACK_HOLD_BACK_TIMEOUT=5
+	NET_X25_ACK_HOLD_BACK_TIMEOUT=5,
+	NET_X25_FORWARD=6
 };
 
 /* /proc/sys/net/token-ring */
diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h
index 166a2e5..389ccf8 100644
--- a/include/linux/sysdev.h
+++ b/include/linux/sysdev.h
@@ -98,12 +98,16 @@
 };
 
 
-#define SYSDEV_ATTR(_name,_mode,_show,_store) 		\
-struct sysdev_attribute attr_##_name = { 			\
-	.attr = {.name = __stringify(_name), .mode = _mode },	\
+#define _SYSDEV_ATTR(_name,_mode,_show,_store)			\
+{								\
+	.attr = { .name = __stringify(_name), .mode = _mode,	\
+		 .owner = THIS_MODULE },			\
 	.show	= _show,					\
 	.store	= _store,					\
-};
+}
+
+#define SYSDEV_ATTR(_name,_mode,_show,_store)		\
+struct sysdev_attribute attr_##_name = _SYSDEV_ATTR(_name,_mode,_show,_store);
 
 extern int sysdev_create_file(struct sys_device *, struct sysdev_attribute *);
 extern void sysdev_remove_file(struct sys_device *, struct sysdev_attribute *);
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 2129d1b..192de3a 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -11,10 +11,12 @@
 #define _SYSFS_H_
 
 #include <linux/compiler.h>
+#include <linux/list.h>
 #include <asm/atomic.h>
 
 struct kobject;
 struct module;
+struct nameidata;
 
 struct attribute {
 	const char		* name;
@@ -88,13 +90,13 @@
 #ifdef CONFIG_SYSFS
 
 extern int __must_check
-sysfs_create_dir(struct kobject *);
+sysfs_create_dir(struct kobject *, struct dentry *);
 
 extern void
 sysfs_remove_dir(struct kobject *);
 
 extern int __must_check
-sysfs_rename_dir(struct kobject *, const char *new_name);
+sysfs_rename_dir(struct kobject *, struct dentry *, const char *new_name);
 
 extern int __must_check
 sysfs_move_dir(struct kobject *, struct kobject *);
@@ -126,11 +128,17 @@
 void sysfs_remove_group(struct kobject *, const struct attribute_group *);
 void sysfs_notify(struct kobject * k, char *dir, char *attr);
 
+
+extern int sysfs_make_shadowed_dir(struct kobject *kobj,
+	void * (*follow_link)(struct dentry *, struct nameidata *));
+extern struct dentry *sysfs_create_shadow_dir(struct kobject *kobj);
+extern void sysfs_remove_shadow_dir(struct dentry *dir);
+
 extern int __must_check sysfs_init(void);
 
 #else /* CONFIG_SYSFS */
 
-static inline int sysfs_create_dir(struct kobject * k)
+static inline int sysfs_create_dir(struct kobject * k, struct dentry *shadow)
 {
 	return 0;
 }
@@ -140,7 +148,9 @@
 	;
 }
 
-static inline int sysfs_rename_dir(struct kobject * k, const char *new_name)
+static inline int sysfs_rename_dir(struct kobject * k,
+					struct dentry *new_parent,
+					const char *new_name)
 {
 	return 0;
 }
@@ -204,6 +214,12 @@
 {
 }
 
+static inline int sysfs_make_shadowed_dir(struct kobject *kobj,
+	void * (*follow_link)(struct dentry *, struct nameidata *))
+{
+	return 0;
+}
+
 static inline int __must_check sysfs_init(void)
 {
 	return 0;
diff --git a/include/linux/tc.h b/include/linux/tc.h
new file mode 100644
index 0000000..f92511e
--- /dev/null
+++ b/include/linux/tc.h
@@ -0,0 +1,141 @@
+/*
+ *	Interface to the TURBOchannel related routines.
+ *
+ *	Copyright (c) 1998  Harald Koerfgen
+ *	Copyright (c) 2005  James Simmons
+ *	Copyright (c) 2006  Maciej W. Rozycki
+ *
+ *	Based on:
+ *
+ *	"TURBOchannel Firmware Specification", EK-TCAAD-FS-004
+ *
+ *	from Digital Equipment Corporation.
+ *
+ *	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.
+ */
+#ifndef _LINUX_TC_H
+#define _LINUX_TC_H
+
+#include <linux/compiler.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+
+/*
+ * Offsets for the ROM header locations for TURBOchannel cards.
+ */
+#define TC_OLDCARD	0x3c0000
+#define TC_NEWCARD	0x000000
+
+#define TC_ROM_WIDTH	0x3e0
+#define TC_ROM_STRIDE	0x3e4
+#define TC_ROM_SIZE	0x3e8
+#define TC_SLOT_SIZE	0x3ec
+#define TC_PATTERN0	0x3f0
+#define TC_PATTERN1	0x3f4
+#define TC_PATTERN2	0x3f8
+#define TC_PATTERN3	0x3fc
+#define TC_FIRM_VER	0x400
+#define TC_VENDOR	0x420
+#define TC_MODULE	0x440
+#define TC_FIRM_TYPE	0x460
+#define TC_FLAGS	0x470
+#define TC_ROM_OBJECTS	0x480
+
+/*
+ * Information obtained through the get_tcinfo() PROM call.
+ */
+struct tcinfo {
+	s32		revision;	/* Hardware revision level. */
+	s32		clk_period;	/* Clock period in nanoseconds. */
+	s32		slot_size;	/* Slot size in megabytes. */
+	s32		io_timeout;	/* I/O timeout in cycles. */
+	s32		dma_range;	/* DMA address range in megabytes. */
+	s32		max_dma_burst;	/* Maximum DMA burst length. */
+	s32		parity;		/* System module supports TC parity. */
+	s32		reserved[4];
+};
+
+/*
+ * TURBOchannel bus.
+ */
+struct tc_bus {
+	struct list_head devices;	/* List of devices on this bus. */
+	struct resource	resource[2];	/* Address space routed to this bus. */
+
+	struct device	dev;
+	char		name[13];
+	resource_size_t	slot_base;
+	resource_size_t	ext_slot_base;
+	resource_size_t	ext_slot_size;
+	int		num_tcslots;
+	struct tcinfo	info;
+};
+
+/*
+ * TURBOchannel device.
+ */
+struct tc_dev {
+	struct list_head node;		/* Node in list of all TC devices. */
+	struct tc_bus	*bus;		/* Bus this device is on. */
+	struct tc_driver *driver;	/* Which driver has allocated this
+					   device. */
+	struct device	dev;		/* Generic device interface. */
+	struct resource	resource;	/* Address space of this device. */
+	char		vendor[9];
+	char		name[9];
+	char		firmware[9];
+	int		interrupt;
+	int		slot;
+};
+
+#define to_tc_dev(n) container_of(n, struct tc_dev, dev)
+
+struct tc_device_id {
+	char		vendor[9];
+	char		name[9];
+};
+
+/*
+ * TURBOchannel driver.
+ */
+struct tc_driver {
+	struct list_head node;
+	const struct tc_device_id *id_table;
+	struct device_driver driver;
+};
+
+#define to_tc_driver(drv) container_of(drv, struct tc_driver, driver)
+
+/*
+ * Return TURBOchannel clock frequency in Hz.
+ */
+static inline unsigned long tc_get_speed(struct tc_bus *tbus)
+{
+	return 100000 * (10000 / (unsigned long)tbus->info.clk_period);
+}
+
+#ifdef CONFIG_TC
+
+extern struct bus_type tc_bus_type;
+
+extern int tc_register_driver(struct tc_driver *tdrv);
+extern void tc_unregister_driver(struct tc_driver *tdrv);
+
+#else /* !CONFIG_TC */
+
+static inline int tc_register_driver(struct tc_driver *tdrv) { return 0; }
+static inline void tc_unregister_driver(struct tc_driver *tdrv) { }
+
+#endif /* CONFIG_TC */
+
+/*
+ * These have to be provided by the architecture.
+ */
+extern int tc_preadb(u8 *valp, void __iomem *addr);
+extern int tc_bus_get_info(struct tc_bus *tbus);
+extern void tc_device_get_irq(struct tc_dev *tdev);
+
+#endif /* _LINUX_TC_H */
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 3cc70d1..29d3089 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -316,7 +316,7 @@
 	struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */
 	struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/
 
-	struct tcp_sack_block recv_sack_cache[4];
+	struct tcp_sack_block_wire recv_sack_cache[4];
 
 	/* from STCP, retrans queue hinting */
 	struct sk_buff* lost_skb_hint;
diff --git a/include/linux/tifm.h b/include/linux/tifm.h
index dfb8052..3deb0a6 100644
--- a/include/linux/tifm.h
+++ b/include/linux/tifm.h
@@ -17,7 +17,7 @@
 #include <linux/wait.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
-#include <linux/scatterlist.h>
+#include <linux/kthread.h>
 
 /* Host registers (relative to pci base address): */
 enum {
@@ -62,11 +62,10 @@
 
 
 #define TIFM_IRQ_ENABLE           0x80000000
-#define TIFM_IRQ_SOCKMASK         0x00000001
-#define TIFM_IRQ_CARDMASK         0x00000100
-#define TIFM_IRQ_FIFOMASK         0x00010000
+#define TIFM_IRQ_SOCKMASK(x)      (x)
+#define TIFM_IRQ_CARDMASK(x)      ((x) << 8)
+#define TIFM_IRQ_FIFOMASK(x)      ((x) << 16)
 #define TIFM_IRQ_SETALL           0xffffffff
-#define TIFM_IRQ_SETALLSOCK       0x0000000f
 
 #define TIFM_CTRL_LED             0x00000040
 #define TIFM_CTRL_FAST_CLK        0x00000100
@@ -89,10 +88,9 @@
 	char __iomem            *addr;
 	spinlock_t              lock;
 	tifm_media_id           media_id;
-	char                    wq_name[KOBJ_NAME_LEN];
-	struct workqueue_struct *wq;
+	unsigned int            socket_id;
 
-	unsigned int            (*signal_irq)(struct tifm_dev *sock,
+	void                    (*signal_irq)(struct tifm_dev *sock,
 					      unsigned int sock_irq_status);
 
 	struct tifm_driver      *drv;
@@ -103,24 +101,23 @@
 	tifm_media_id        *id_table;
 	int                  (*probe)(struct tifm_dev *dev);
 	void                 (*remove)(struct tifm_dev *dev);
+	int                  (*suspend)(struct tifm_dev *dev,
+                                        pm_message_t state);
+	int                  (*resume)(struct tifm_dev *dev);
 
 	struct device_driver driver;
 };
 
 struct tifm_adapter {
 	char __iomem            *addr;
-	unsigned int            irq_status;
-	unsigned int            insert_mask;
-	unsigned int            remove_mask;
 	spinlock_t              lock;
+	unsigned int            irq_status;
+	unsigned int            socket_change_set;
+	wait_queue_head_t       change_set_notify;
 	unsigned int            id;
-	unsigned int            max_sockets;
-	char                    wq_name[KOBJ_NAME_LEN];
-	unsigned int            inhibit_new_cards;
-	struct workqueue_struct *wq;
-	struct work_struct      media_inserter;
-	struct work_struct      media_remover;
+	unsigned int            num_sockets;
 	struct tifm_dev         **sockets;
+	struct task_struct      *media_switcher;
 	struct class_device     cdev;
 	struct device           *dev;
 
@@ -130,9 +127,9 @@
 struct tifm_adapter *tifm_alloc_adapter(void);
 void tifm_free_device(struct device *dev);
 void tifm_free_adapter(struct tifm_adapter *fm);
-int tifm_add_adapter(struct tifm_adapter *fm);
+int tifm_add_adapter(struct tifm_adapter *fm, int (*mediathreadfn)(void *data));
 void tifm_remove_adapter(struct tifm_adapter *fm);
-struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id);
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm);
 int tifm_register_driver(struct tifm_driver *drv);
 void tifm_unregister_driver(struct tifm_driver *drv);
 void tifm_eject(struct tifm_dev *sock);
diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h
index 28967ed..d3a4f99 100644
--- a/include/linux/ufs_fs.h
+++ b/include/linux/ufs_fs.h
@@ -789,6 +789,7 @@
 
 	__u32	s_maxsymlinklen;/* upper limit on fast symlinks' size */
 	__s32	fs_magic;       /* filesystem magic */
+	unsigned int s_dirblksize;
 };
 
 /*
diff --git a/include/linux/usb.h b/include/linux/usb.h
index aab5b1b..b5c226a 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -2,7 +2,7 @@
 #define __LINUX_USB_H
 
 #include <linux/mod_devicetable.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 
 #define USB_MAJOR			180
 #define USB_DEVICE_MAJOR		189
@@ -107,7 +107,8 @@
  * @needs_remote_wakeup: flag set when the driver requires remote-wakeup
  *	capability during autosuspend.
  * @dev: driver model's view of this device
- * @class_dev: driver model's class view of this device.
+ * @usb_dev: if an interface is bound to the USB major, this will point
+ *	to the sysfs representation for that device.
  * @pm_usage_cnt: PM usage counter for this interface; autosuspend is not
  *	allowed unless the counter is 0.
  *
@@ -152,7 +153,7 @@
 	unsigned needs_remote_wakeup:1;	/* driver requires remote wakeup */
 
 	struct device dev;		/* interface specific device info */
-	struct class_device *class_dev;
+	struct device *usb_dev;		/* pointer to the usb class's device, if any */
 	int pm_usage_cnt;		/* usage counter for autosuspend */
 };
 #define	to_usb_interface(d) container_of(d, struct usb_interface, dev)
@@ -372,7 +373,7 @@
 	char *serial;			/* iSerialNumber string, if present */
 
 	struct list_head filelist;
-	struct class_device *class_dev;
+	struct device *usbfs_dev;
 	struct dentry *usbfs_dentry;	/* usbfs dentry entry for the device */
 
 	/*
@@ -475,6 +476,8 @@
 			struct usb_interface *iface);
 const struct usb_device_id *usb_match_id(struct usb_interface *interface,
 					 const struct usb_device_id *id);
+extern int usb_match_one_id(struct usb_interface *interface,
+			    const struct usb_device_id *id);
 
 extern struct usb_interface *usb_find_interface(struct usb_driver *drv,
 		int minor);
@@ -554,6 +557,18 @@
 }
 
 /**
+ * usb_endpoint_xfer_control - check if the endpoint has control transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type control, otherwise it returns false.
+ */
+static inline int usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd)
+{
+	return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+		USB_ENDPOINT_XFER_CONTROL);
+}
+
+/**
  * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type
  * @epd: endpoint to be checked
  *
@@ -723,11 +738,21 @@
 
 /* ----------------------------------------------------------------------- */
 
+/* Stuff for dynamic usb ids */
 struct usb_dynids {
 	spinlock_t lock;
 	struct list_head list;
 };
 
+struct usb_dynid {
+	struct list_head node;
+	struct usb_device_id id;
+};
+
+extern ssize_t usb_store_new_id(struct usb_dynids *dynids,
+				struct device_driver *driver,
+				const char *buf, size_t count);
+
 /**
  * struct usbdrv_wrap - wrapper for driver-model structure
  * @driver: The driver-model core driver structure.
@@ -868,10 +893,11 @@
  * use these in module_init()/module_exit()
  * and don't forget MODULE_DEVICE_TABLE(usb, ...)
  */
-extern int usb_register_driver(struct usb_driver *, struct module *);
+extern int usb_register_driver(struct usb_driver *, struct module *,
+			       const char *);
 static inline int usb_register(struct usb_driver *driver)
 {
-	return usb_register_driver(driver, THIS_MODULE);
+	return usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
 }
 extern void usb_deregister(struct usb_driver *);
 
@@ -1085,7 +1111,6 @@
 	struct kref kref;		/* reference count of the URB */
 	spinlock_t lock;		/* lock for the URB */
 	void *hcpriv;			/* private data for host controller */
-	int bandwidth;			/* bandwidth for INT/ISO request */
 	atomic_t use_count;		/* concurrent submissions counter */
 	u8 reject;			/* submissions will fail */
 
diff --git a/include/linux/usb/Kbuild b/include/linux/usb/Kbuild
new file mode 100644
index 0000000..43f160c
--- /dev/null
+++ b/include/linux/usb/Kbuild
@@ -0,0 +1,5 @@
+unifdef-y += audio.h
+unifdef-y += cdc.h
+unifdef-y += ch9.h
+unifdef-y += midi.h
+
diff --git a/include/linux/usb_ch9.h b/include/linux/usb/ch9.h
similarity index 99%
rename from include/linux/usb_ch9.h
rename to include/linux/usb/ch9.h
index c720d10..ae78337 100644
--- a/include/linux/usb_ch9.h
+++ b/include/linux/usb/ch9.h
@@ -224,6 +224,7 @@
 #define USB_CLASS_CONTENT_SEC		0x0d	/* content security */
 #define USB_CLASS_VIDEO			0x0e
 #define USB_CLASS_WIRELESS_CONTROLLER	0xe0
+#define USB_CLASS_MISC			0xef
 #define USB_CLASS_APP_SPEC		0xfe
 #define USB_CLASS_VENDOR_SPEC		0xff
 
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index 10f99e5..33dcd85 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -179,6 +179,9 @@
  *	memory structure allocation at this point in time.
  * @shutdown: pointer to the driver's shutdown function.  This will be
  *	called when the device is removed from the system.
+ * @usb_driver: pointer to the struct usb_driver that controls this
+ *	device.  This is necessary to allow dynamic ids to be added to
+ *	the driver from sysfs.
  *
  * This structure is defines a USB Serial driver.  It provides all of
  * the information that the USB serial core code needs.  If the function
@@ -202,6 +205,8 @@
 
 	struct list_head	driver_list;
 	struct device_driver	driver;
+	struct usb_driver	*usb_driver;
+	struct usb_dynids	dynids;
 
 	int (*probe) (struct usb_serial *serial, const struct usb_device_id *id);
 	int (*attach) (struct usb_serial *serial);
diff --git a/include/linux/usb_gadgetfs.h b/include/linux/usb_gadgetfs.h
index b53d6ae..8086d5a 100644
--- a/include/linux/usb_gadgetfs.h
+++ b/include/linux/usb_gadgetfs.h
@@ -2,7 +2,7 @@
 #include <asm/types.h>
 #include <asm/ioctl.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 
 /*
  * Filesystem based user-mode API to USB Gadget controller hardware
diff --git a/include/linux/video_output.h b/include/linux/video_output.h
new file mode 100644
index 0000000..e63e0c0
--- /dev/null
+++ b/include/linux/video_output.h
@@ -0,0 +1,42 @@
+/*
+ *
+ *  Copyright (C) 2006 Luming Yu <luming.yu@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or (at
+ *  your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef _LINUX_VIDEO_OUTPUT_H
+#define _LINUX_VIDEO_OUTPUT_H
+#include <linux/device.h>
+struct output_device;
+struct output_properties {
+	int (*set_state)(struct output_device *);
+	int (*get_status)(struct output_device *);
+};
+struct output_device {
+	int request_state;
+	struct output_properties *props;
+	struct class_device class_dev;
+};
+#define to_output_device(obj) container_of(obj, struct output_device, class_dev)
+struct output_device *video_output_register(const char *name,
+	struct device *dev,
+	void *devdata,
+	struct output_properties *op);
+void video_output_unregister(struct output_device *dev);
+#endif
diff --git a/include/linux/wanrouter.h b/include/linux/wanrouter.h
index 2cd0501..3add874 100644
--- a/include/linux/wanrouter.h
+++ b/include/linux/wanrouter.h
@@ -516,9 +516,6 @@
 /* Public functions available for device drivers */
 extern int register_wan_device(struct wan_device *wandev);
 extern int unregister_wan_device(char *name);
-__be16 wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev);
-int wanrouter_encapsulate(struct sk_buff *skb, struct net_device *dev,
-			  unsigned short type);
 
 /* Proc interface functions. These must not be called by the drivers! */
 extern int wanrouter_proc_init(void);
@@ -527,11 +524,6 @@
 extern int wanrouter_proc_delete(struct wan_device *wandev);
 extern int wanrouter_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
 
-extern void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
-extern void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
-
-
-
 /* Public Data */
 /* list of registered devices */
 extern struct wan_device *wanrouter_router_devlist;
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index 9529ea1..15ca89e 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -178,6 +178,9 @@
 	XFRM_MSG_REPORT,
 #define XFRM_MSG_REPORT XFRM_MSG_REPORT
 
+	XFRM_MSG_MIGRATE,
+#define XFRM_MSG_MIGRATE XFRM_MSG_MIGRATE
+
 	__XFRM_MSG_MAX
 };
 #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
@@ -256,6 +259,7 @@
 	XFRMA_COADDR,		/* xfrm_address_t */
 	XFRMA_LASTUSED,
 	XFRMA_POLICY_TYPE,	/* struct xfrm_userpolicy_type */
+	XFRMA_MIGRATE,
 	__XFRMA_MAX
 
 #define XFRMA_MAX (__XFRMA_MAX - 1)
@@ -351,6 +355,19 @@
 	struct xfrm_selector		sel;
 };
 
+struct xfrm_user_migrate {
+	xfrm_address_t			old_daddr;
+	xfrm_address_t			old_saddr;
+	xfrm_address_t			new_daddr;
+	xfrm_address_t			new_saddr;
+	__u8				proto;
+	__u8				mode;
+	__u16				reserved;
+	__u32				reqid;
+	__u16				old_family;
+	__u16				new_family;
+};
+
 #ifndef __KERNEL__
 /* backwards compatibility for userspace */
 #define XFRMGRP_ACQUIRE		1
@@ -375,6 +392,8 @@
 #define XFRMNLGRP_AEVENTS	XFRMNLGRP_AEVENTS
 	XFRMNLGRP_REPORT,
 #define XFRMNLGRP_REPORT	XFRMNLGRP_REPORT
+	XFRMNLGRP_MIGRATE,
+#define XFRMNLGRP_MIGRATE	XFRMNLGRP_MIGRATE
 	__XFRMNLGRP_MAX
 };
 #define XFRMNLGRP_MAX	(__XFRMNLGRP_MAX - 1)
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index 34cc76e..d27ee8c 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -34,12 +34,13 @@
 #include <asm/byteorder.h>
 
 /* This is for all connections with a full identity, no wildcards.
- * New scheme, half the table is for TIME_WAIT, the other half is
- * for the rest.  I'll experiment with dynamic table growth later.
+ * One chain is dedicated to TIME_WAIT sockets.
+ * I'll experiment with dynamic table growth later.
  */
 struct inet_ehash_bucket {
 	rwlock_t	  lock;
 	struct hlist_head chain;
+	struct hlist_head twchain;
 };
 
 /* There are a few simple rules, which allow for local port reuse by
@@ -97,8 +98,7 @@
 	 *
 	 *          TCP_ESTABLISHED <= sk->sk_state < TCP_CLOSE
 	 *
-	 * First half of the table is for sockets not in TIME_WAIT, second half
-	 * is for TIME_WAIT sockets only.
+	 * TIME_WAIT sockets use a separate chain (twchain).
 	 */
 	struct inet_ehash_bucket	*ehash;
 
@@ -369,7 +369,7 @@
 	}
 
 	/* Must check for a TIME_WAIT'er before going to listener hash. */
-	sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) {
+	sk_for_each(sk, node, &head->twchain) {
 		if (INET_TW_MATCH(sk, hash, acookie, saddr, daddr, ports, dif))
 			goto hit;
 	}
diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h
new file mode 100644
index 0000000..04d1abb
--- /dev/null
+++ b/include/net/iucv/af_iucv.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2006 IBM Corporation
+ * IUCV protocol stack for Linux on zSeries
+ * Version 1.0
+ * Author(s): Jennifer Hunt <jenhunt@us.ibm.com>
+ *
+ */
+
+#ifndef __AFIUCV_H
+#define __AFIUCV_H
+
+#include <asm/types.h>
+#include <asm/byteorder.h>
+#include <linux/list.h>
+#include <linux/poll.h>
+#include <linux/socket.h>
+
+#ifndef AF_IUCV
+#define AF_IUCV		32
+#define PF_IUCV		AF_IUCV
+#endif
+
+/* Connection and socket states */
+enum {
+	IUCV_CONNECTED = 1,
+	IUCV_OPEN,
+	IUCV_BOUND,
+	IUCV_LISTEN,
+	IUCV_SEVERED,
+	IUCV_DISCONN,
+	IUCV_CLOSED
+};
+
+#define IUCV_QUEUELEN_DEFAULT	65535
+#define IUCV_CONN_TIMEOUT	(HZ * 40)
+#define IUCV_DISCONN_TIMEOUT	(HZ * 2)
+#define IUCV_CONN_IDLE_TIMEOUT	(HZ * 60)
+#define IUCV_BUFSIZE_DEFAULT	32768
+
+/* IUCV socket address */
+struct sockaddr_iucv {
+	sa_family_t	siucv_family;
+	unsigned short	siucv_port;		/* Reserved */
+	unsigned int	siucv_addr;		/* Reserved */
+	char		siucv_nodeid[8];	/* Reserved */
+	char		siucv_user_id[8];	/* Guest User Id */
+	char		siucv_name[8];		/* Application Name */
+};
+
+
+/* Common socket structures and functions */
+
+#define iucv_sk(__sk) ((struct iucv_sock *) __sk)
+
+struct iucv_sock {
+	struct sock		sk;
+	char			src_user_id[8];
+	char			src_name[8];
+	char			dst_user_id[8];
+	char			dst_name[8];
+	struct list_head	accept_q;
+	struct sock		*parent;
+	struct iucv_path	*path;
+	struct sk_buff_head	send_skb_q;
+	unsigned int		send_tag;
+};
+
+struct iucv_sock_list {
+	struct hlist_head head;
+	rwlock_t	  lock;
+	atomic_t	  autobind_name;
+};
+
+static void iucv_sock_destruct(struct sock *sk);
+static void iucv_sock_cleanup_listen(struct sock *parent);
+static void iucv_sock_kill(struct sock *sk);
+static void iucv_sock_close(struct sock *sk);
+static int  iucv_sock_create(struct socket *sock, int proto);
+static int  iucv_sock_bind(struct socket *sock, struct sockaddr *addr,
+			int addr_len);
+static int  iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
+			      int alen, int flags);
+static int  iucv_sock_listen(struct socket *sock, int backlog);
+static int  iucv_sock_accept(struct socket *sock, struct socket *newsock,
+			     int flags);
+static int  iucv_sock_getname(struct socket *sock, struct sockaddr *addr,
+			      int *len, int peer);
+static int  iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
+			      struct msghdr *msg, size_t len);
+static int  iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+			      struct msghdr *msg, size_t len, int flags);
+unsigned int iucv_sock_poll(struct file *file, struct socket *sock,
+			    poll_table *wait);
+static int iucv_sock_release(struct socket *sock);
+static int iucv_sock_shutdown(struct socket *sock, int how);
+
+void iucv_sock_link(struct iucv_sock_list *l, struct sock *s);
+void iucv_sock_unlink(struct iucv_sock_list *l, struct sock *s);
+int  iucv_sock_wait_state(struct sock *sk, int state, int state2,
+			  unsigned long timeo);
+int  iucv_sock_wait_cnt(struct sock *sk, unsigned long timeo);
+void iucv_accept_enqueue(struct sock *parent, struct sock *sk);
+void iucv_accept_unlink(struct sock *sk);
+struct sock *iucv_accept_dequeue(struct sock *parent, struct socket *newsock);
+
+#endif /* __IUCV_H */
diff --git a/include/net/iucv/iucv.h b/include/net/iucv/iucv.h
new file mode 100644
index 0000000..746e741
--- /dev/null
+++ b/include/net/iucv/iucv.h
@@ -0,0 +1,415 @@
+/*
+ *  drivers/s390/net/iucv.h
+ *    IUCV base support.
+ *
+ *  S390 version
+ *    Copyright 2000, 2006 IBM Corporation
+ *    Author(s):Alan Altmark (Alan_Altmark@us.ibm.com)
+ *		Xenia Tkatschow (xenia@us.ibm.com)
+ *    Rewritten for af_iucv:
+ *	Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *
+ *
+ * Functionality:
+ * To explore any of the IUCV functions, one must first register their
+ * program using iucv_register(). Once your program has successfully
+ * completed a register, it can exploit the other functions.
+ * For furthur reference on all IUCV functionality, refer to the
+ * CP Programming Services book, also available on the web thru
+ * www.ibm.com/s390/vm/pubs, manual # SC24-5760
+ *
+ * Definition of Return Codes
+ * - All positive return codes including zero are reflected back
+ *   from CP. The definition of each return code can be found in
+ *   CP Programming Services book.
+ * - Return Code of:
+ *   -EINVAL: Invalid value
+ *   -ENOMEM: storage allocation failed
+ */
+
+#include <linux/types.h>
+#include <asm/debug.h>
+
+/*
+ * IUCV option flags usable by device drivers:
+ *
+ * IUCV_IPRMDATA  Indicates that your program can handle a message in the
+ *		  parameter list / a message is sent in the parameter list.
+ *		  Used for iucv_path_accept, iucv_path_connect,
+ *		  iucv_message_reply, iucv_message_send, iucv_message_send2way.
+ * IUCV_IPQUSCE	  Indicates that you do not want to receive messages on this
+ *		  path until an iucv_path_resume is issued.
+ *		  Used for iucv_path_accept, iucv_path_connect.
+ * IUCV_IPBUFLST  Indicates that an address list is used for the message data.
+ *		  Used for iucv_message_receive, iucv_message_send,
+ *		  iucv_message_send2way.
+ * IUCV_IPPRTY	  Specifies that you want to send priority messages.
+ *		  Used for iucv_path_accept, iucv_path_connect,
+ *		  iucv_message_reply, iucv_message_send, iucv_message_send2way.
+ * IUCV_IPSYNC	  Indicates a synchronous send request.
+ *		  Used for iucv_message_send, iucv_message_send2way.
+ * IUCV_IPANSLST  Indicates that an address list is used for the reply data.
+ *		  Used for iucv_message_reply, iucv_message_send2way.
+ * IUCV_IPLOCAL	  Specifies that the communication partner has to be on the
+ *		  local system. If local is specified no target class can be
+ *		  specified.
+ *		  Used for iucv_path_connect.
+ *
+ * All flags are defined in the input field IPFLAGS1 of each function
+ * and can be found in CP Programming Services.
+ */
+#define IUCV_IPRMDATA	0x80
+#define IUCV_IPQUSCE	0x40
+#define IUCV_IPBUFLST	0x40
+#define IUCV_IPPRTY	0x20
+#define IUCV_IPANSLST	0x08
+#define IUCV_IPSYNC	0x04
+#define IUCV_IPLOCAL	0x01
+
+/*
+ * iucv_array : Defines buffer array.
+ * Inside the array may be 31- bit addresses and 31-bit lengths.
+ * Use a pointer to an iucv_array as the buffer, reply or answer
+ * parameter on iucv_message_send, iucv_message_send2way, iucv_message_receive
+ * and iucv_message_reply if IUCV_IPBUFLST or IUCV_IPANSLST are used.
+ */
+struct iucv_array {
+	u32 address;
+	u32 length;
+} __attribute__ ((aligned (8)));
+
+extern struct bus_type iucv_bus;
+extern struct device *iucv_root;
+
+/*
+ * struct iucv_path
+ * pathid: 16 bit path identification
+ * msglim: 16 bit message limit
+ * flags: properties of the path: IPRMDATA, IPQUSCE, IPPRTY
+ * handler:  address of iucv handler structure
+ * private: private information of the handler associated with the path
+ * list: list_head for the iucv_handler path list.
+ */
+struct iucv_path {
+	u16 pathid;
+	u16 msglim;
+	u8  flags;
+	void *private;
+	struct iucv_handler *handler;
+	struct list_head list;
+};
+
+/*
+ * struct iucv_message
+ * id: 32 bit message id
+ * audit: 32 bit error information of purged or replied messages
+ * class: 32 bit target class of a message (source class for replies)
+ * tag: 32 bit tag to be associated with the message
+ * length: 32 bit length of the message / reply
+ * reply_size: 32 bit maximum allowed length of the reply
+ * rmmsg: 8 byte inline message
+ * flags: message properties (IUCV_IPPRTY)
+ */
+struct iucv_message {
+	u32 id;
+	u32 audit;
+	u32 class;
+	u32 tag;
+	u32 length;
+	u32 reply_size;
+	u8  rmmsg[8];
+	u8  flags;
+};
+
+/*
+ * struct iucv_handler
+ *
+ * A vector of functions that handle IUCV interrupts. Each functions gets
+ * a parameter area as defined by the CP Programming Services and private
+ * pointer that is provided by the user of the interface.
+ */
+struct iucv_handler {
+	 /*
+	  * The path_pending function is called after an iucv interrupt
+	  * type 0x01 has been received. The base code allocates a path
+	  * structure and "asks" the handler if this path belongs to the
+	  * handler. To accept the path the path_pending function needs
+	  * to call iucv_path_accept and return 0. If the callback returns
+	  * a value != 0 the iucv base code will continue with the next
+	  * handler. The order in which the path_pending functions are
+	  * called is the order of the registration of the iucv handlers
+	  * to the base code.
+	  */
+	int  (*path_pending)(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]);
+	/*
+	 * The path_complete function is called after an iucv interrupt
+	 * type 0x02 has been received for a path that has been established
+	 * for this handler with iucv_path_connect and got accepted by the
+	 * peer with iucv_path_accept.
+	 */
+	void (*path_complete)(struct iucv_path *, u8 ipuser[16]);
+	 /*
+	  * The path_severed function is called after an iucv interrupt
+	  * type 0x03 has been received. The communication peer shutdown
+	  * his end of the communication path. The path still exists and
+	  * remaining messages can be received until a iucv_path_sever
+	  * shuts down the other end of the path as well.
+	  */
+	void (*path_severed)(struct iucv_path *, u8 ipuser[16]);
+	/*
+	 * The path_quiesced function is called after an icuv interrupt
+	 * type 0x04 has been received. The communication peer has quiesced
+	 * the path. Delivery of messages is stopped until iucv_path_resume
+	 * has been called.
+	 */
+	void (*path_quiesced)(struct iucv_path *, u8 ipuser[16]);
+	/*
+	 * The path_resumed function is called after an icuv interrupt
+	 * type 0x05 has been received. The communication peer has resumed
+	 * the path.
+	 */
+	void (*path_resumed)(struct iucv_path *, u8 ipuser[16]);
+	/*
+	 * The message_pending function is called after an icuv interrupt
+	 * type 0x06 or type 0x07 has been received. A new message is
+	 * availabe and can be received with iucv_message_receive.
+	 */
+	void (*message_pending)(struct iucv_path *, struct iucv_message *);
+	/*
+	 * The message_complete function is called after an icuv interrupt
+	 * type 0x08 or type 0x09 has been received. A message send with
+	 * iucv_message_send2way has been replied to. The reply can be
+	 * received with iucv_message_receive.
+	 */
+	void (*message_complete)(struct iucv_path *, struct iucv_message *);
+
+	struct list_head list;
+	struct list_head paths;
+};
+
+/**
+ * iucv_register:
+ * @handler: address of iucv handler structure
+ * @smp: != 0 indicates that the handler can deal with out of order messages
+ *
+ * Registers a driver with IUCV.
+ *
+ * Returns 0 on success, -ENOMEM if the memory allocation for the pathid
+ * table failed, or -EIO if IUCV_DECLARE_BUFFER failed on all cpus.
+ */
+int iucv_register(struct iucv_handler *handler, int smp);
+
+/**
+ * iucv_unregister
+ * @handler:  address of iucv handler structure
+ * @smp: != 0 indicates that the handler can deal with out of order messages
+ *
+ * Unregister driver from IUCV.
+ */
+void iucv_unregister(struct iucv_handler *handle, int smp);
+
+/**
+ * iucv_path_alloc
+ * @msglim: initial message limit
+ * @flags: initial flags
+ * @gfp: kmalloc allocation flag
+ *
+ * Allocate a new path structure for use with iucv_connect.
+ *
+ * Returns NULL if the memory allocation failed or a pointer to the
+ * path structure.
+ */
+static inline struct iucv_path *iucv_path_alloc(u16 msglim, u8 flags, gfp_t gfp)
+{
+	struct iucv_path *path;
+
+	path = kzalloc(sizeof(struct iucv_path), gfp);
+	if (path) {
+		path->msglim = msglim;
+		path->flags = flags;
+	}
+	return path;
+}
+
+/**
+ * iucv_path_free
+ * @path: address of iucv path structure
+ *
+ * Frees a path structure.
+ */
+static inline void iucv_path_free(struct iucv_path *path)
+{
+	kfree(path);
+}
+
+/**
+ * iucv_path_accept
+ * @path: address of iucv path structure
+ * @handler: address of iucv handler structure
+ * @userdata: 16 bytes of data reflected to the communication partner
+ * @private: private data passed to interrupt handlers for this path
+ *
+ * This function is issued after the user received a connection pending
+ * external interrupt and now wishes to complete the IUCV communication path.
+ *
+ * Returns the result of the CP IUCV call.
+ */
+int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler,
+		     u8 userdata[16], void *private);
+
+/**
+ * iucv_path_connect
+ * @path: address of iucv path structure
+ * @handler: address of iucv handler structure
+ * @userid: 8-byte user identification
+ * @system: 8-byte target system identification
+ * @userdata: 16 bytes of data reflected to the communication partner
+ * @private: private data passed to interrupt handlers for this path
+ *
+ * This function establishes an IUCV path. Although the connect may complete
+ * successfully, you are not able to use the path until you receive an IUCV
+ * Connection Complete external interrupt.
+ *
+ * Returns the result of the CP IUCV call.
+ */
+int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler,
+		      u8 userid[8], u8 system[8], u8 userdata[16],
+		      void *private);
+
+/**
+ * iucv_path_quiesce:
+ * @path: address of iucv path structure
+ * @userdata: 16 bytes of data reflected to the communication partner
+ *
+ * This function temporarily suspends incoming messages on an IUCV path.
+ * You can later reactivate the path by invoking the iucv_resume function.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16]);
+
+/**
+ * iucv_path_resume:
+ * @path: address of iucv path structure
+ * @userdata: 16 bytes of data reflected to the communication partner
+ *
+ * This function resumes incoming messages on an IUCV path that has
+ * been stopped with iucv_path_quiesce.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_path_resume(struct iucv_path *path, u8 userdata[16]);
+
+/**
+ * iucv_path_sever
+ * @path: address of iucv path structure
+ * @userdata: 16 bytes of data reflected to the communication partner
+ *
+ * This function terminates an IUCV path.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_path_sever(struct iucv_path *path, u8 userdata[16]);
+
+/**
+ * iucv_message_purge
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @srccls: source class of message
+ *
+ * Cancels a message you have sent.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg,
+		       u32 srccls);
+
+/**
+ * iucv_message_receive
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: flags that affect how the message is received (IUCV_IPBUFLST)
+ * @buffer: address of data buffer or address of struct iucv_array
+ * @size: length of data buffer
+ * @residual:
+ *
+ * This function receives messages that are being sent to you over
+ * established paths. This function will deal with RMDATA messages
+ * embedded in struct iucv_message as well.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
+			 u8 flags, void *buffer, size_t size, size_t *residual);
+
+/**
+ * iucv_message_reject
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ *
+ * The reject function refuses a specified message. Between the time you
+ * are notified of a message and the time that you complete the message,
+ * the message may be rejected.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg);
+
+/**
+ * iucv_message_reply
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: how the reply is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST)
+ * @reply: address of data buffer or address of struct iucv_array
+ * @size: length of reply data buffer
+ *
+ * This function responds to the two-way messages that you receive. You
+ * must identify completely the message to which you wish to reply. ie,
+ * pathid, msgid, and trgcls. Prmmsg signifies the data is moved into
+ * the parameter list.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg,
+		       u8 flags, void *reply, size_t size);
+
+/**
+ * iucv_message_send
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST)
+ * @srccls: source class of message
+ * @buffer: address of data buffer or address of struct iucv_array
+ * @size: length of send buffer
+ *
+ * This function transmits data to another application. Data to be
+ * transmitted is in a buffer and this is a one-way message and the
+ * receiver will not reply to the message.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
+		      u8 flags, u32 srccls, void *buffer, size_t size);
+
+/**
+ * iucv_message_send2way
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: how the message is sent and the reply is received
+ *	   (IUCV_IPRMDATA, IUCV_IPBUFLST, IUCV_IPPRTY, IUCV_ANSLST)
+ * @srccls: source class of message
+ * @buffer: address of data buffer or address of struct iucv_array
+ * @size: length of send buffer
+ * @ansbuf: address of answer buffer or address of struct iucv_array
+ * @asize: size of reply buffer
+ *
+ * This function transmits data to another application. Data to be
+ * transmitted is in a buffer. The receiver of the send is expected to
+ * reply to the message and a buffer is provided into which IUCV moves
+ * the reply to this message.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg,
+			  u8 flags, u32 srccls, void *buffer, size_t size,
+			  void *answer, size_t asize, size_t *residual);
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index bd01b46..68ec274 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -45,6 +45,7 @@
 #include <linux/netfilter/nf_conntrack_ftp.h>
 #include <linux/netfilter/nf_conntrack_pptp.h>
 #include <linux/netfilter/nf_conntrack_h323.h>
+#include <linux/netfilter/nf_conntrack_sane.h>
 
 /* per conntrack: application helper private data */
 union nf_conntrack_help {
@@ -52,6 +53,7 @@
 	struct nf_ct_ftp_master ct_ftp_info;
 	struct nf_ct_pptp_master ct_pptp_info;
 	struct nf_ct_h323_master ct_h323_info;
+	struct nf_ct_sane_master ct_sane_info;
 };
 
 #include <linux/types.h>
diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h
index 61c6206..bc57dd7 100644
--- a/include/net/netfilter/nf_nat.h
+++ b/include/net/netfilter/nf_nat.h
@@ -16,6 +16,7 @@
 
 #define IP_NAT_RANGE_MAP_IPS 1
 #define IP_NAT_RANGE_PROTO_SPECIFIED 2
+#define IP_NAT_RANGE_PROTO_RANDOM 4
 
 /* NAT sequence number modifications */
 struct nf_nat_seq {
diff --git a/include/net/route.h b/include/net/route.h
index 486e37a..1440bdb 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -146,7 +146,8 @@
 
 static inline int ip_route_connect(struct rtable **rp, __be32 dst,
 				   __be32 src, u32 tos, int oif, u8 protocol,
-				   __be16 sport, __be16 dport, struct sock *sk)
+				   __be16 sport, __be16 dport, struct sock *sk,
+				   int flags)
 {
 	struct flowi fl = { .oif = oif,
 			    .nl_u = { .ip4_u = { .daddr = dst,
@@ -168,7 +169,7 @@
 		*rp = NULL;
 	}
 	security_sk_classify_flow(sk, &fl);
-	return ip_route_output_flow(rp, &fl, sk, 0);
+	return ip_route_output_flow(rp, &fl, sk, flags);
 }
 
 static inline int ip_route_newports(struct rtable **rp, u8 protocol,
diff --git a/include/net/tcp.h b/include/net/tcp.h
index cd8fa0c..5c472f2 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -802,9 +802,8 @@
 /*
  * Calculate(/check) TCP checksum
  */
-static inline __sum16 tcp_v4_check(struct tcphdr *th, int len,
-			       __be32 saddr, __be32 daddr,
-			       __wsum base)
+static inline __sum16 tcp_v4_check(int len, __be32 saddr,
+				   __be32 daddr, __wsum base)
 {
 	return csum_tcpudp_magic(saddr,daddr,len,IPPROTO_TCP,base);
 }
diff --git a/include/net/x25.h b/include/net/x25.h
index e47fe44..fc3f03d 100644
--- a/include/net/x25.h
+++ b/include/net/x25.h
@@ -161,6 +161,14 @@
 	unsigned long 		vc_facil_mask;	/* inc_call facilities mask */
 };
 
+struct x25_forward {
+	struct list_head	node;
+	unsigned int		lci;
+	struct net_device	*dev1;
+	struct net_device	*dev2;
+	atomic_t		refcnt;
+};
+
 static inline struct x25_sock *x25_sk(const struct sock *sk)
 {
 	return (struct x25_sock *)sk;
@@ -172,6 +180,7 @@
 extern int  sysctl_x25_reset_request_timeout;
 extern int  sysctl_x25_clear_request_timeout;
 extern int  sysctl_x25_ack_holdback_timeout;
+extern int  sysctl_x25_forward;
 
 extern int  x25_addr_ntoa(unsigned char *, struct x25_address *,
 			  struct x25_address *);
@@ -198,6 +207,13 @@
 				struct x25_dte_facilities *);
 extern void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *);
 
+/* x25_forward.c */
+extern void x25_clear_forward_by_lci(unsigned int lci);
+extern void x25_clear_forward_by_dev(struct net_device *);
+extern int x25_forward_data(int, struct x25_neigh *, struct sk_buff *);
+extern int x25_forward_call(struct x25_address *, struct x25_neigh *,
+				struct sk_buff *, int);
+
 /* x25_in.c */
 extern int  x25_process_rx_frame(struct sock *, struct sk_buff *);
 extern int  x25_backlog_rcv(struct sock *, struct sk_buff *);
@@ -282,6 +298,8 @@
 extern rwlock_t x25_list_lock;
 extern struct list_head x25_route_list;
 extern rwlock_t x25_route_list_lock;
+extern struct list_head x25_forward_list;
+extern rwlock_t x25_forward_list_lock;
 
 extern int x25_proc_init(void);
 extern void x25_proc_exit(void);
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index e476541..16924cb 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -252,10 +252,13 @@
 						xfrm_address_t *daddr, xfrm_address_t *saddr);
 	int			(*tmpl_sort)(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n);
 	int			(*state_sort)(struct xfrm_state **dst, struct xfrm_state **src, int n);
+	int			(*output)(struct sk_buff *skb);
 };
 
 extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo);
 extern int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo);
+extern struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family);
+extern void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
 
 extern void xfrm_state_delete_tunnel(struct xfrm_state *x);
 
@@ -359,6 +362,19 @@
 	struct xfrm_tmpl       	xfrm_vec[XFRM_MAX_DEPTH];
 };
 
+struct xfrm_migrate {
+	xfrm_address_t		old_daddr;
+	xfrm_address_t		old_saddr;
+	xfrm_address_t		new_daddr;
+	xfrm_address_t		new_saddr;
+	u8			proto;
+	u8			mode;
+	u16			reserved;
+	u32			reqid;
+	u16			old_family;
+	u16			new_family;
+};
+
 #define XFRM_KM_TIMEOUT                30
 /* which seqno */
 #define XFRM_REPLAY_SEQ		1
@@ -385,6 +401,7 @@
 	int			(*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
 	int			(*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c);
 	int			(*report)(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr);
+	int			(*migrate)(struct xfrm_selector *sel, u8 dir, u8 type, struct xfrm_migrate *m, int num_bundles);
 };
 
 extern int xfrm_register_km(struct xfrm_mgr *km);
@@ -985,6 +1002,16 @@
 			  struct flowi *fl, int family, int strict);
 extern void xfrm_init_pmtu(struct dst_entry *dst);
 
+#ifdef CONFIG_XFRM_MIGRATE
+extern int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
+		      struct xfrm_migrate *m, int num_bundles);
+extern struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m);
+extern struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
+					      struct xfrm_migrate *m);
+extern int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
+			struct xfrm_migrate *m, int num_bundles);
+#endif
+
 extern wait_queue_head_t km_waitq;
 extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
 extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid);
@@ -1050,5 +1077,25 @@
 		xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
 }
 
+#ifdef CONFIG_XFRM_MIGRATE
+static inline struct xfrm_algo *xfrm_algo_clone(struct xfrm_algo *orig)
+{
+	return (struct xfrm_algo *)kmemdup(orig, sizeof(*orig) + orig->alg_key_len, GFP_KERNEL);
+}
+
+static inline void xfrm_states_put(struct xfrm_state **states, int n)
+{
+	int i;
+	for (i = 0; i < n; i++)
+		xfrm_state_put(*(states + i));
+}
+
+static inline void xfrm_states_delete(struct xfrm_state **states, int n)
+{
+	int i;
+	for (i = 0; i < n; i++)
+		xfrm_state_delete(*(states + i));
+}
+#endif
 
 #endif	/* _NET_XFRM_H */
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h
index 623a0fc..6e84258 100644
--- a/include/pcmcia/ss.h
+++ b/include/pcmcia/ss.h
@@ -284,7 +284,7 @@
 #endif
 
 	/* socket device */
-	struct class_device		dev;
+	struct device			dev;
 	void				*driver_data;	/* data internal to the socket driver */
 
 };
diff --git a/include/rdma/ib_user_mad.h b/include/rdma/ib_user_mad.h
index 44537aa..d66b15e 100644
--- a/include/rdma/ib_user_mad.h
+++ b/include/rdma/ib_user_mad.h
@@ -98,7 +98,7 @@
  */
 struct ib_user_mad {
 	struct ib_user_mad_hdr hdr;
-	__u8	data[0];
+	__u64	data[0];
 };
 
 /**
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 0bfa332..765589f 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -45,6 +45,7 @@
 #include <linux/device.h>
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
+#include <linux/kref.h>
 
 #include <asm/atomic.h>
 #include <asm/scatterlist.h>
@@ -419,8 +420,8 @@
 	enum ib_wc_opcode	opcode;
 	u32			vendor_err;
 	u32			byte_len;
+	struct ib_qp	       *qp;
 	__be32			imm_data;
-	u32			qp_num;
 	u32			src_qp;
 	int			wc_flags;
 	u16			pkey_index;
diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h
index 02f6e4b..4a44278 100644
--- a/include/scsi/iscsi_proto.h
+++ b/include/scsi/iscsi_proto.h
@@ -40,6 +40,14 @@
 }
 #define zero_data(p) {p[0]=0;p[1]=0;p[2]=0;}
 
+/* initiator tags; opaque for target */
+typedef uint32_t __bitwise__ itt_t;
+/* below makes sense only for initiator that created this tag */
+#define build_itt(itt, id, age) ((__force itt_t)\
+	((itt) | ((id) << ISCSI_CID_SHIFT) | ((age) << ISCSI_AGE_SHIFT)))
+#define get_itt(itt) ((__force uint32_t)(itt_t)(itt) & ISCSI_ITT_MASK)
+#define RESERVED_ITT ((__force itt_t)0xffffffff)
+
 /*
  * iSCSI Template Message Header
  */
@@ -50,7 +58,7 @@
 	uint8_t		hlength;	/* AHSs total length */
 	uint8_t		dlength[3];	/* Data length */
 	uint8_t		lun[8];
-	__be32		itt;		/* Initiator Task Tag */
+	itt_t		itt;		/* Initiator Task Tag, opaque for target */
 	__be32		ttt;		/* Target Task Tag */
 	__be32		statsn;
 	__be32		exp_statsn;
@@ -111,7 +119,7 @@
 	uint8_t hlength;
 	uint8_t dlength[3];
 	uint8_t lun[8];
-	__be32 itt;	/* Initiator Task Tag */
+	itt_t	 itt;	/* Initiator Task Tag */
 	__be32 data_length;
 	__be32 cmdsn;
 	__be32 exp_statsn;
@@ -148,7 +156,7 @@
 	uint8_t hlength;
 	uint8_t dlength[3];
 	uint8_t rsvd[8];
-	__be32	itt;	/* Initiator Task Tag */
+	itt_t	 itt;	/* Initiator Task Tag */
 	__be32	rsvd1;
 	__be32	statsn;
 	__be32	exp_cmdsn;
@@ -206,7 +214,7 @@
 	uint8_t rsvd3;
 	uint8_t dlength[3];
 	uint8_t lun[8];
-	__be32	itt;	/* Initiator Task Tag */
+	itt_t	 itt;	/* Initiator Task Tag */
 	__be32	ttt;	/* Target Transfer Tag */
 	__be32	cmdsn;
 	__be32	exp_statsn;
@@ -221,7 +229,7 @@
 	uint8_t rsvd3;
 	uint8_t dlength[3];
 	uint8_t lun[8];
-	__be32	itt;	/* Initiator Task Tag */
+	itt_t	 itt;	/* Initiator Task Tag */
 	__be32	ttt;	/* Target Transfer Tag */
 	__be32	statsn;
 	__be32	exp_cmdsn;
@@ -237,8 +245,8 @@
 	uint8_t hlength;
 	uint8_t dlength[3];
 	uint8_t lun[8];
-	__be32	itt;	/* Initiator Task Tag */
-	__be32	rtt;	/* Reference Task Tag */
+	itt_t	 itt;	/* Initiator Task Tag */
+	itt_t	 rtt;	/* Reference Task Tag */
 	__be32	cmdsn;
 	__be32	exp_statsn;
 	__be32	refcmdsn;
@@ -267,8 +275,8 @@
 	uint8_t hlength;
 	uint8_t dlength[3];
 	uint8_t rsvd2[8];
-	__be32	itt;	/* Initiator Task Tag */
-	__be32	rtt;	/* Reference Task Tag */
+	itt_t	 itt;	/* Initiator Task Tag */
+	itt_t	 rtt;	/* Reference Task Tag */
 	__be32	statsn;
 	__be32	exp_cmdsn;
 	__be32	max_cmdsn;
@@ -293,7 +301,7 @@
 	uint8_t	hlength;
 	uint8_t	dlength[3];
 	uint8_t lun[8];
-	__be32	itt;	/* Initiator Task Tag */
+	itt_t	 itt;	/* Initiator Task Tag */
 	__be32	ttt;	/* Target Transfer Tag */
 	__be32	statsn;
 	__be32	exp_cmdsn;
@@ -311,7 +319,7 @@
 	uint8_t rsvd3;
 	uint8_t dlength[3];
 	uint8_t lun[8];
-	__be32	itt;
+	itt_t	 itt;
 	__be32	ttt;
 	__be32	rsvd4;
 	__be32	exp_statsn;
@@ -331,7 +339,7 @@
 	uint8_t hlength;
 	uint8_t dlength[3];
 	uint8_t lun[8];
-	__be32	itt;
+	itt_t	 itt;
 	__be32	ttt;
 	__be32	statsn;
 	__be32	exp_cmdsn;
@@ -355,7 +363,7 @@
 	uint8_t hlength;
 	uint8_t dlength[3];
 	uint8_t rsvd4[8];
-	__be32	itt;
+	itt_t	 itt;
 	__be32	ttt;
 	__be32	cmdsn;
 	__be32	exp_statsn;
@@ -373,7 +381,7 @@
 	uint8_t hlength;
 	uint8_t dlength[3];
 	uint8_t rsvd4[8];
-	__be32	itt;
+	itt_t	 itt;
 	__be32	ttt;
 	__be32	statsn;
 	__be32	exp_cmdsn;
@@ -392,7 +400,7 @@
 	uint8_t dlength[3];
 	uint8_t isid[6];	/* Initiator Session ID */
 	__be16	tsih;	/* Target Session Handle */
-	__be32	itt;	/* Initiator Task Tag */
+	itt_t	 itt;	/* Initiator Task Tag */
 	__be16	cid;
 	__be16	rsvd3;
 	__be32	cmdsn;
@@ -421,7 +429,7 @@
 	uint8_t dlength[3];
 	uint8_t isid[6];	/* Initiator Session ID */
 	__be16	tsih;	/* Target Session Handle */
-	__be32	itt;	/* Initiator Task Tag */
+	itt_t	 itt;	/* Initiator Task Tag */
 	__be32	rsvd3;
 	__be32	statsn;
 	__be32	exp_cmdsn;
@@ -478,7 +486,7 @@
 	uint8_t hlength;
 	uint8_t dlength[3];
 	uint8_t rsvd2[8];
-	__be32	itt;	/* Initiator Task Tag */
+	itt_t	 itt;	/* Initiator Task Tag */
 	__be16	cid;
 	uint8_t rsvd3[2];
 	__be32	cmdsn;
@@ -505,7 +513,7 @@
 	uint8_t hlength;
 	uint8_t dlength[3];
 	uint8_t rsvd3[8];
-	__be32	itt;	/* Initiator Task Tag */
+	itt_t	 itt;	/* Initiator Task Tag */
 	__be32	rsvd4;
 	__be32	statsn;
 	__be32	exp_cmdsn;
@@ -528,7 +536,7 @@
 	uint8_t opcode;
 	uint8_t flags;
 	uint8_t rsvd2[14];
-	__be32	itt;
+	itt_t	 itt;
 	__be32	begrun;
 	__be32	runlength;
 	__be32	exp_statsn;
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index 3372039..246ac23 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -375,6 +375,7 @@
 #define AC97_SCAP_DETECT_BY_VENDOR (1<<8) /* use vendor registers for read tests */
 #define AC97_SCAP_NO_SPDIF	(1<<9)	/* don't build SPDIF controls */
 #define AC97_SCAP_EAPD_LED	(1<<10)	/* EAPD as mute LED */
+#define AC97_SCAP_POWER_SAVE	(1<<11)	/* capable for aggresive power-saving */
 
 /* ac97->flags */
 #define AC97_HAS_PC_BEEP	(1<<0)	/* force PC Speaker usage */
@@ -425,6 +426,7 @@
 
 struct snd_ac97_bus_ops {
 	void (*reset) (struct snd_ac97 *ac97);
+	void (*warm_reset)(struct snd_ac97 *ac97);
 	void (*write) (struct snd_ac97 *ac97, unsigned short reg, unsigned short val);
 	unsigned short (*read) (struct snd_ac97 *ac97, unsigned short reg);
 	void (*wait) (struct snd_ac97 *ac97);
@@ -501,6 +503,7 @@
 			unsigned short id[3];		// codec IDs (lower 16-bit word)
 			unsigned short pcmreg[3];	// PCM registers
 			unsigned short codec_cfg[3];	// CODEC_CFG bits
+			unsigned char swap_mic_linein;	// AD1986/AD1986A only
 		} ad18xx;
 		unsigned int dev_flags;		/* device specific */
 	} spec;
@@ -510,7 +513,6 @@
 
 #ifdef CONFIG_SND_AC97_POWER_SAVE
 	unsigned int power_up;	/* power states */
-	struct workqueue_struct *power_workq;
 	struct delayed_work power_work;
 #endif
 	struct device dev;
diff --git a/include/sound/ad1848.h b/include/sound/ad1848.h
index c8de6f8..b2c3f00 100644
--- a/include/sound/ad1848.h
+++ b/include/sound/ad1848.h
@@ -185,7 +185,7 @@
 	int index;
 	int type;
 	unsigned long private_value;
-	unsigned int *tlv;
+	const unsigned int *tlv;
 };
 
 #define AD1848_SINGLE(xname, xindex, reg, shift, mask, invert) \
diff --git a/include/sound/ak4114.h b/include/sound/ak4114.h
index 2ee0616..c149d3b 100644
--- a/include/sound/ak4114.h
+++ b/include/sound/ak4114.h
@@ -181,7 +181,6 @@
 	unsigned long ccrc_errors;
 	unsigned char rcs0;
 	unsigned char rcs1;
-	struct workqueue_struct *workqueue;
 	struct delayed_work work;
 	void *change_callback_private;
 	void (*change_callback)(struct ak4114 *ak4114, unsigned char c0, unsigned char c1);
@@ -189,7 +188,7 @@
 
 int snd_ak4114_create(struct snd_card *card,
 		      ak4114_read_t *read, ak4114_write_t *write,
-		      unsigned char pgm[7], unsigned char txcsb[5],
+		      const unsigned char pgm[7], const unsigned char txcsb[5],
 		      void *private_data, struct ak4114 **r_ak4114);
 void snd_ak4114_reg_write(struct ak4114 *ak4114, unsigned char reg, unsigned char mask, unsigned char val);
 void snd_ak4114_reinit(struct ak4114 *ak4114);
diff --git a/include/sound/ak4117.h b/include/sound/ak4117.h
index 2b96c32..d650d52 100644
--- a/include/sound/ak4117.h
+++ b/include/sound/ak4117.h
@@ -178,7 +178,7 @@
 };
 
 int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write,
-		      unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117);
+		      const unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117);
 void snd_ak4117_reg_write(struct ak4117 *ak4117, unsigned char reg, unsigned char mask, unsigned char val);
 void snd_ak4117_reinit(struct ak4117 *ak4117);
 int snd_ak4117_build(struct ak4117 *ak4117, struct snd_pcm_substream *capture_substream);
diff --git a/include/sound/ak4xxx-adda.h b/include/sound/ak4xxx-adda.h
index d0deca6..aa49dda 100644
--- a/include/sound/ak4xxx-adda.h
+++ b/include/sound/ak4xxx-adda.h
@@ -50,6 +50,8 @@
 	char *name;		/* capture gain volume label */
 	char *switch_name;	/* capture switch */
 	unsigned int num_channels;
+	char *selector_name;	/* capture source select label */
+	const char **input_names; /* capture source names (NULL terminated) */
 };
 
 struct snd_akm4xxx {
@@ -69,8 +71,8 @@
 	} type;
 
 	/* (array) information of combined codecs */
-	struct snd_akm4xxx_dac_channel *dac_info;
-	struct snd_akm4xxx_adc_channel *adc_info;
+	const struct snd_akm4xxx_dac_channel *dac_info;
+	const struct snd_akm4xxx_adc_channel *adc_info;
 
 	struct snd_ak4xxx_ops ops;
 };
diff --git a/include/sound/control.h b/include/sound/control.h
index 1de148b..72e759f 100644
--- a/include/sound/control.h
+++ b/include/sound/control.h
@@ -49,7 +49,7 @@
 	snd_kcontrol_put_t *put;
 	union {
 		snd_kcontrol_tlv_rw_t *c;
-		unsigned int *p;
+		const unsigned int *p;
 	} tlv;
 	unsigned long private_value;
 };
@@ -69,7 +69,7 @@
 	snd_kcontrol_put_t *put;
 	union {
 		snd_kcontrol_tlv_rw_t *c;
-		unsigned int *p;
+		const unsigned int *p;
 	} tlv;
 	unsigned long private_value;
 	void *private_data;
@@ -108,7 +108,6 @@
 
 void snd_ctl_notify(struct snd_card * card, unsigned int mask, struct snd_ctl_elem_id * id);
 
-struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol * kcontrol, unsigned int access);
 struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new * kcontrolnew, void * private_data);
 void snd_ctl_free_one(struct snd_kcontrol * kcontrol);
 int snd_ctl_add(struct snd_card * card, struct snd_kcontrol * kcontrol);
diff --git a/include/sound/core.h b/include/sound/core.h
index 521f036..4b9e609 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -211,9 +211,40 @@
 
 void snd_request_card(int card);
 
-int snd_register_device(int type, struct snd_card *card, int dev,
-			const struct file_operations *f_ops, void *private_data,
-			const char *name);
+int snd_register_device_for_dev(int type, struct snd_card *card,
+				int dev,
+				const struct file_operations *f_ops,
+				void *private_data,
+				const char *name,
+				struct device *device);
+
+/**
+ * snd_register_device - Register the ALSA device file for the card
+ * @type: the device type, SNDRV_DEVICE_TYPE_XXX
+ * @card: the card instance
+ * @dev: the device index
+ * @f_ops: the file operations
+ * @private_data: user pointer for f_ops->open()
+ * @name: the device file name
+ *
+ * Registers an ALSA device file for the given card.
+ * The operators have to be set in reg parameter.
+ *
+ * This function uses the card's device pointer to link to the
+ * correct &struct device.
+ *
+ * Returns zero if successful, or a negative error code on failure.
+ */
+static inline int snd_register_device(int type, struct snd_card *card, int dev,
+				      const struct file_operations *f_ops,
+				      void *private_data,
+				      const char *name)
+{
+	return snd_register_device_for_dev(type, card, dev, f_ops,
+					   private_data, name,
+					   snd_card_get_device_link(card));
+}
+
 int snd_unregister_device(int type, struct snd_card *card, int dev);
 void *snd_lookup_minor_data(unsigned int minor, int type);
 int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev,
@@ -396,6 +427,29 @@
 #endif
 #endif
 
-#include "typedefs.h"
+/* PCI quirk list helper */
+struct snd_pci_quirk {
+	unsigned short subvendor;	/* PCI subvendor ID */
+	unsigned short subdevice;	/* PCI subdevice ID */
+	int value;			/* value */
+#ifdef CONFIG_SND_DEBUG_DETECT
+	const char *name;		/* name of the device (optional) */
+#endif
+};
+
+#define _SND_PCI_QUIRK_ID(vend,dev) \
+	.subvendor = (vend), .subdevice = (dev)
+#define SND_PCI_QUIRK_ID(vend,dev) {_SND_PCI_QUIRK_ID(vend, dev)}
+#ifdef CONFIG_SND_DEBUG_DETECT
+#define SND_PCI_QUIRK(vend,dev,xname,val) \
+	{_SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname)}
+#else
+#define SND_PCI_QUIRK(vend,dev,xname,val) \
+	{_SND_PCI_QUIRK_ID(vend, dev), .value = (val)}
+#endif
+
+const struct snd_pci_quirk *
+snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list);
+
 
 #endif /* __SOUND_CORE_H */
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 3d3c151..eb7ce96 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -188,7 +188,35 @@
 #define HCFG_LEGACYINT		0x00200000	/* 1 = legacy event captured. Write 1 to clear.	*/
 						/* NOTE: The rest of the bits in this register	*/
 						/* _are_ relevant under Linux.			*/
-#define HCFG_CODECFORMAT_MASK	0x00070000	/* CODEC format					*/
+#define HCFG_PUSH_BUTTON_ENABLE 0x00100000	/* Enables Volume Inc/Dec and Mute functions    */
+#define HCFG_BAUD_RATE		0x00080000	/* 0 = 48kHz, 1 = 44.1kHz			*/
+#define HCFG_EXPANDED_MEM	0x00040000	/* 1 = any 16M of 4G addr, 0 = 32M of 2G addr	*/
+#define HCFG_CODECFORMAT_MASK	0x00030000	/* CODEC format					*/
+
+/* Specific to Alice2, CA0102 */
+#define HCFG_CODECFORMAT_AC97_1	0x00000000	/* AC97 CODEC format -- Ver 1.03		*/
+#define HCFG_CODECFORMAT_AC97_2	0x00010000	/* AC97 CODEC format -- Ver 2.1			*/
+#define HCFG_AUTOMUTE_ASYNC	0x00008000	/* When set, the async sample rate convertors	*/
+						/* will automatically mute their output when	*/
+						/* they are not rate-locked to the external	*/
+						/* async audio source  				*/
+#define HCFG_AUTOMUTE_SPDIF	0x00004000	/* When set, the async sample rate convertors	*/
+						/* will automatically mute their output when	*/
+						/* the SPDIF V-bit indicates invalid audio	*/
+#define HCFG_EMU32_SLAVE	0x00002000	/* 0 = Master, 1 = Slave. Slave for EMU1010	*/
+#define HCFG_SLOW_RAMP		0x00001000	/* Increases Send Smoothing time constant	*/
+/* 0x00000800 not used on Alice2 */
+#define HCFG_PHASE_TRACK_MASK	0x00000700	/* When set, forces corresponding input to	*/
+						/* phase track the previous input.		*/
+						/* I2S0 can phase track the last S/PDIF input	*/
+#define HCFG_I2S_ASRC_ENABLE	0x00000070	/* When set, enables asynchronous sample rate   */
+						/* conversion for the corresponding		*/
+ 						/* I2S format input				*/
+/* Rest of HCFG 0x0000000f same as below. LOCKSOUNDCACHE etc.  */
+
+
+
+/* Older chips */
 #define HCFG_CODECFORMAT_AC97	0x00000000	/* AC97 CODEC format -- Primary Output		*/
 #define HCFG_CODECFORMAT_I2S	0x00010000	/* I2S CODEC format -- Secondary (Rear) Output	*/
 #define HCFG_GPINPUT0		0x00004000	/* External pin112				*/
@@ -432,6 +460,7 @@
 #define FXRT_CHANNELC		0x0f000000	/* Effects send bus number for channel's effects send C	*/
 #define FXRT_CHANNELD		0xf0000000	/* Effects send bus number for channel's effects send D	*/
 
+#define A_HR			0x0b	/* High Resolution. 24bit playback from host to DSP. */
 #define MAPA			0x0c		/* Cache map A						*/
 
 #define MAPB			0x0d		/* Cache map B						*/
@@ -439,6 +468,8 @@
 #define MAP_PTE_MASK		0xffffe000	/* The 19 MSBs of the PTE indexed by the PTI		*/
 #define MAP_PTI_MASK		0x00001fff	/* The 13 bit index to one of the 8192 PTE dwords      	*/
 
+/* 0x0e, 0x0f: Not used */
+
 #define ENVVOL			0x10		/* Volume envelope register				*/
 #define ENVVOL_MASK		0x0000ffff	/* Current value of volume envelope state variable	*/  
 						/* 0x8000-n == 666*n usec delay	       			*/
@@ -527,7 +558,7 @@
 						/* NOTE: All channels contain internal variables; do	*/
 						/* not write to these locations.			*/
 
-/* 1f something */
+/* 0x1f: not used */
 
 #define CD0			0x20		/* Cache data 0 register				*/
 #define CD1			0x21		/* Cache data 1 register				*/
@@ -597,6 +628,8 @@
 #define FXWC_SPDIFLEFT          (1<<22)		/* 0x00400000 */
 #define FXWC_SPDIFRIGHT         (1<<23)		/* 0x00800000 */
 
+#define A_TBLSZ	`		0x43	/* Effects Tank Internal Table Size. Only low byte or register used */
+
 #define TCBS			0x44		/* Tank cache buffer size register			*/
 #define TCBS_MASK		0x00000007	/* Tank cache buffer size field				*/
 #define TCBS_BUFFSIZE_16K	0x00000000
@@ -617,7 +650,7 @@
 #define FXBA			0x47		/* FX Buffer Address */
 #define FXBA_MASK		0xfffff000	/* 20 bit base address					*/
 
-/* 0x48 something - word access, defaults to 3f */
+#define A_HWM			0x48	/* High PCI Water Mark - word access, defaults to 3f */
 
 #define MICBS			0x49		/* Microphone buffer size register			*/
 
@@ -661,6 +694,18 @@
 #define ADCBS_BUFSIZE_57344	0x0000001e
 #define ADCBS_BUFSIZE_65536	0x0000001f
 
+/* Current Send B, A Amounts */
+#define A_CSBA			0x4c
+
+/* Current Send D, C Amounts */
+#define A_CSDC			0x4d
+
+/* Current Send F, E Amounts */
+#define A_CSFE			0x4e
+
+/* Current Send H, G Amounts */
+#define A_CSHG			0x4f
+
 
 #define CDCS			0x50		/* CD-ROM digital channel status register	*/
 
@@ -668,6 +713,9 @@
 
 #define DBG			0x52		/* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
 
+/* S/PDIF Input C Channel Status */
+#define A_SPSC			0x52
+
 #define REG53			0x53		/* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
 
 #define A_DBG			 0x53
@@ -708,6 +756,8 @@
 #define SPCS_NOTAUDIODATA	0x00000002	/* 0 = Digital audio, 1 = not audio		*/
 #define SPCS_PROFESSIONAL	0x00000001	/* 0 = Consumer (IEC-958), 1 = pro (AES3-1992)	*/
 
+/* 0x57: Not used */
+
 /* The 32-bit CLIx and SOLx registers all have one bit per channel control/status      		*/
 #define CLIEL			0x58		/* Channel loop interrupt enable low register	*/
 
@@ -733,6 +783,9 @@
 #define AC97SLOT_CNTR		0x10            /* Center enable */
 #define AC97SLOT_LFE		0x20            /* LFE enable */
 
+/* PCB Revision */
+#define A_PCB			0x5f
+
 // NOTE: 0x60,61,62: 64-bit
 #define CDSRCS			0x60		/* CD-ROM Sample Rate Converter status register	*/
 
@@ -780,9 +833,18 @@
 
 #define HLIPH			0x69		/* Channel half loop interrupt pending high register	*/
 
-// 0x6a,6b,6c used for some recording
-// 0x6d unused
-// 0x6e,6f - tanktable base / offset
+/* S/PDIF Host Record Index (bypasses SRC) */
+#define A_SPRI			0x6a
+/* S/PDIF Host Record Address */
+#define A_SPRA			0x6b
+/* S/PDIF Host Record Control */
+#define A_SPRC			0x6c
+/* Delayed Interrupt Counter & Enable */
+#define A_DICE			0x6d
+/* Tank Table Base */
+#define A_TTB			0x6e
+/* Tank Delay Offset */
+#define A_TDOF			0x6f
 
 /* This is the MPU port on the card (via the game port)						*/
 #define A_MUDATA1		0x70
@@ -800,6 +862,7 @@
 #define A_FXWC1			0x74            /* Selects 0x7f-0x60 for FX recording           */
 #define A_FXWC2			0x75		/* Selects 0x9f-0x80 for FX recording           */
 
+/* Extended Hardware Control */
 #define A_SPDIF_SAMPLERATE	0x76		/* Set the sample rate of SPDIF output		*/
 #define A_SAMPLE_RATE		0x76		/* Various sample rate settings. */
 #define A_SAMPLE_RATE_NOT_USED  0x0ffc111e	/* Bits that are not used and cannot be set. 	*/
@@ -822,8 +885,20 @@
 #define A_PCM_96000		0x00004000
 #define A_PCM_44100		0x00008000
 
-/* 0x77,0x78,0x79 "something i2s-related" - default to 0x01080000 on my audigy 2 ZS --rlrevell	*/
-/* 0x7a, 0x7b - lookup tables */
+/* I2S0 Sample Rate Tracker Status */
+#define A_SRT3			0x77
+
+/* I2S1 Sample Rate Tracker Status */
+#define A_SRT4			0x78
+
+/* I2S2 Sample Rate Tracker Status */
+#define A_SRT5			0x79
+/* - default to 0x01080000 on my audigy 2 ZS --rlrevell	*/
+
+/* Tank Table DMA Address */
+#define A_TTDA			0x7a
+/* Tank Table DMA Data */
+#define A_TTDD			0x7b
 
 #define A_FXRT2			0x7c
 #define A_FXRT_CHANNELE		0x0000003f	/* Effects send bus number for channel's effects send E	*/
@@ -845,7 +920,7 @@
 #define A_FXRT_CHANNELC		0x003f0000
 #define A_FXRT_CHANNELD		0x3f000000
 
-
+/* 0x7f: Not used */
 /* Each FX general purpose register is 32 bits in length, all bits are used			*/
 #define FXGPREGBASE		0x100		/* FX general purpose registers base       	*/
 #define A_FXGPREGBASE		0x400		/* Audigy GPRs, 0x400 to 0x5ff			*/
@@ -886,6 +961,293 @@
 #define A_HIWORD_RESULT_MASK	0x007ff000
 #define A_HIWORD_OPA_MASK	0x000007ff
 
+/************************************************************************************************/
+/* EMU1010m HANA FPGA registers									*/
+/************************************************************************************************/
+#define EMU_HANA_DESTHI		0x00	/* 0000xxx  3 bits Link Destination */
+#define EMU_HANA_DESTLO		0x01	/* 00xxxxx  5 bits */
+#define EMU_HANA_SRCHI		0x02	/* 0000xxx  3 bits Link Source */
+#define EMU_HANA_SRCLO		0x03	/* 00xxxxx  5 bits */
+#define EMU_HANA_DOCK_PWR	0x04	/* 000000x  1 bits Audio Dock power */
+#define EMU_HANA_DOCK_PWR_ON		0x01 /* Audio Dock power on */
+#define EMU_HANA_WCLOCK		0x05	/* 0000xxx  3 bits Word Clock source select  */
+					/* Must be written after power on to reset DLL */
+					/* One is unable to detect the Audio dock without this */
+#define EMU_HANA_WCLOCK_SRC_MASK	0x07
+#define EMU_HANA_WCLOCK_INT_48K		0x00
+#define EMU_HANA_WCLOCK_INT_44_1K	0x01
+#define EMU_HANA_WCLOCK_HANA_SPDIF_IN	0x02
+#define EMU_HANA_WCLOCK_HANA_ADAT_IN	0x03
+#define EMU_HANA_WCLOCK_SYNC_BNCN	0x04
+#define EMU_HANA_WCLOCK_2ND_HANA	0x05
+#define EMU_HANA_WCLOCK_SRC_RESERVED	0x06
+#define EMU_HANA_WCLOCK_OFF		0x07 /* For testing, forces fallback to DEFCLOCK */
+#define EMU_HANA_WCLOCK_MULT_MASK	0x18
+#define EMU_HANA_WCLOCK_1X		0x00
+#define EMU_HANA_WCLOCK_2X		0x08
+#define EMU_HANA_WCLOCK_4X		0x10
+#define EMU_HANA_WCLOCK_MULT_RESERVED	0x18
+
+#define EMU_HANA_DEFCLOCK	0x06	/* 000000x  1 bits Default Word Clock  */
+#define EMU_HANA_DEFCLOCK_48K		0x00
+#define EMU_HANA_DEFCLOCK_44_1K		0x01
+
+#define EMU_HANA_UNMUTE		0x07	/* 000000x  1 bits Mute all audio outputs  */
+#define EMU_MUTE			0x00
+#define EMU_UNMUTE			0x01
+
+#define EMU_HANA_FPGA_CONFIG	0x08	/* 00000xx  2 bits Config control of FPGAs  */
+#define EMU_HANA_FPGA_CONFIG_AUDIODOCK	0x01 /* Set in order to program FPGA on Audio Dock */
+#define EMU_HANA_FPGA_CONFIG_HANA	0x02 /* Set in order to program FPGA on Hana */
+
+#define EMU_HANA_IRQ_ENABLE	0x09	/* 000xxxx  4 bits IRQ Enable  */
+#define EMU_HANA_IRQ_WCLK_CHANGED	0x01
+#define EMU_HANA_IRQ_ADAT		0x02
+#define EMU_HANA_IRQ_DOCK		0x04
+#define EMU_HANA_IRQ_DOCK_LOST		0x08
+
+#define EMU_HANA_SPDIF_MODE	0x0a	/* 00xxxxx  5 bits SPDIF MODE  */
+#define EMU_HANA_SPDIF_MODE_TX_COMSUMER	0x00
+#define EMU_HANA_SPDIF_MODE_TX_PRO	0x01
+#define EMU_HANA_SPDIF_MODE_TX_NOCOPY	0x02
+#define EMU_HANA_SPDIF_MODE_RX_COMSUMER	0x00
+#define EMU_HANA_SPDIF_MODE_RX_PRO	0x04
+#define EMU_HANA_SPDIF_MODE_RX_NOCOPY	0x08
+#define EMU_HANA_SPDIF_MODE_RX_INVALID	0x10
+
+#define EMU_HANA_OPTICAL_TYPE	0x0b	/* 00000xx  2 bits ADAT or SPDIF in/out  */
+#define EMU_HANA_OPTICAL_IN_SPDIF	0x00
+#define EMU_HANA_OPTICAL_IN_ADAT	0x01
+#define EMU_HANA_OPTICAL_OUT_SPDIF	0x00
+#define EMU_HANA_OPTICAL_OUT_ADAT	0x02
+
+#define EMU_HANA_MIDI_IN		0x0c	/* 000000x  1 bit  Control MIDI  */
+#define EMU_HANA_MIDI_IN_FROM_HAMOA	0x00 /* HAMOA MIDI in to Alice 2 MIDI B */
+#define EMU_HANA_MIDI_IN_FROM_DOCK	0x01 /* Audio Dock MIDI in to Alice 2 MIDI B */
+
+#define EMU_HANA_DOCK_LEDS_1	0x0d	/* 000xxxx  4 bit  Audio Dock LEDs  */
+#define EMU_HANA_DOCK_LEDS_1_MIDI1	0x01	/* MIDI 1 LED on */
+#define EMU_HANA_DOCK_LEDS_1_MIDI2	0x02	/* MIDI 2 LED on */
+#define EMU_HANA_DOCK_LEDS_1_SMPTE_IN	0x04	/* SMPTE IN LED on */
+#define EMU_HANA_DOCK_LEDS_1_SMPTE_OUT	0x08	/* SMPTE OUT LED on */
+
+#define EMU_HANA_DOCK_LEDS_2	0x0e	/* 0xxxxxx  6 bit  Audio Dock LEDs  */
+#define EMU_HANA_DOCK_LEDS_2_44K	0x01	/* 44.1 kHz LED on */
+#define EMU_HANA_DOCK_LEDS_2_48K	0x02	/* 48 kHz LED on */
+#define EMU_HANA_DOCK_LEDS_2_96K	0x04	/* 96 kHz LED on */
+#define EMU_HANA_DOCK_LEDS_2_192K	0x08	/* 192 kHz LED on */
+#define EMU_HANA_DOCK_LEDS_2_LOCK	0x10	/* LOCK LED on */
+#define EMU_HANA_DOCK_LEDS_2_EXT	0x20	/* EXT LED on */
+
+#define EMU_HANA_DOCK_LEDS_3	0x0f	/* 0xxxxxx  6 bit  Audio Dock LEDs  */
+#define EMU_HANA_DOCK_LEDS_3_CLIP_A	0x01	/* Mic A Clip LED on */
+#define EMU_HANA_DOCK_LEDS_3_CLIP_B	0x02	/* Mic B Clip LED on */
+#define EMU_HANA_DOCK_LEDS_3_SIGNAL_A	0x04	/* Signal A Clip LED on */
+#define EMU_HANA_DOCK_LEDS_3_SIGNAL_B	0x08	/* Signal B Clip LED on */
+#define EMU_HANA_DOCK_LEDS_3_MANUAL_CLIP	0x10	/* Manual Clip detection */
+#define EMU_HANA_DOCK_LEDS_3_MANUAL_SIGNAL	0x20	/* Manual Signal detection */
+
+#define EMU_HANA_ADC_PADS	0x10	/* 0000xxx  3 bit  Audio Dock ADC 14dB pads */
+#define EMU_HANA_DOCK_ADC_PAD1	0x01	/* 14dB Attenuation on Audio Dock ADC 1 */
+#define EMU_HANA_DOCK_ADC_PAD2	0x02	/* 14dB Attenuation on Audio Dock ADC 2 */
+#define EMU_HANA_DOCK_ADC_PAD3	0x04	/* 14dB Attenuation on Audio Dock ADC 3 */
+#define EMU_HANA_0202_ADC_PAD1	0x08	/* 14dB Attenuation on 0202 ADC 1 */
+
+#define EMU_HANA_DOCK_MISC	0x11	/* 0xxxxxx  6 bit  Audio Dock misc bits */
+#define EMU_HANA_DOCK_DAC1_MUTE	0x01	/* DAC 1 Mute */
+#define EMU_HANA_DOCK_DAC2_MUTE	0x02	/* DAC 2 Mute */
+#define EMU_HANA_DOCK_DAC3_MUTE	0x04	/* DAC 3 Mute */
+#define EMU_HANA_DOCK_DAC4_MUTE	0x08	/* DAC 4 Mute */
+#define EMU_HANA_DOCK_PHONES_192_DAC1	0x00	/* DAC 1 Headphones source at 192kHz */
+#define EMU_HANA_DOCK_PHONES_192_DAC2	0x10	/* DAC 2 Headphones source at 192kHz */
+#define EMU_HANA_DOCK_PHONES_192_DAC3	0x20	/* DAC 3 Headphones source at 192kHz */
+#define EMU_HANA_DOCK_PHONES_192_DAC4	0x30	/* DAC 4 Headphones source at 192kHz */
+
+#define EMU_HANA_MIDI_OUT	0x12	/* 00xxxxx  5 bit  Source for each MIDI out port */
+#define EMU_HANA_MIDI_OUT_0202	0x01 /* 0202 MIDI from Alice 2. 0 = A, 1 = B */
+#define EMU_HANA_MIDI_OUT_DOCK1	0x02 /* Audio Dock MIDI1 front, from Alice 2. 0 = A, 1 = B */
+#define EMU_HANA_MIDI_OUT_DOCK2	0x04 /* Audio Dock MIDI2 rear, from Alice 2. 0 = A, 1 = B */
+#define EMU_HANA_MIDI_OUT_SYNC2	0x08 /* Sync card. Not the actual MIDI out jack. 0 = A, 1 = B */
+#define EMU_HANA_MIDI_OUT_LOOP	0x10 /* 0 = bits (3:0) normal. 1 = MIDI loopback enabled. */
+
+#define EMU_HANA_DAC_PADS	0x13	/* 00xxxxx  5 bit  DAC 14dB attenuation pads */
+#define EMU_HANA_DOCK_DAC_PAD1	0x01	/* 14dB Attenuation on AudioDock DAC 1. Left and Right */
+#define EMU_HANA_DOCK_DAC_PAD2	0x02	/* 14dB Attenuation on AudioDock DAC 2. Left and Right */
+#define EMU_HANA_DOCK_DAC_PAD3	0x04	/* 14dB Attenuation on AudioDock DAC 3. Left and Right */
+#define EMU_HANA_DOCK_DAC_PAD4	0x08	/* 14dB Attenuation on AudioDock DAC 4. Left and Right */
+#define EMU_HANA_0202_DAC_PAD1	0x10	/* 14dB Attenuation on 0202 DAC 1. Left and Right */
+
+/* 0x14 - 0x1f Unused R/W registers */
+#define EMU_HANA_IRQ_STATUS	0x20	/* 000xxxx  4 bits IRQ Status  */
+#if 0  /* Already defined for reg 0x09 IRQ_ENABLE */
+#define EMU_HANA_IRQ_WCLK_CHANGED	0x01
+#define EMU_HANA_IRQ_ADAT		0x02
+#define EMU_HANA_IRQ_DOCK		0x04
+#define EMU_HANA_IRQ_DOCK_LOST		0x08
+#endif
+
+#define EMU_HANA_OPTION_CARDS	0x21	/* 000xxxx  4 bits Presence of option cards */
+#define EMU_HANA_OPTION_HAMOA	0x01	/* HAMOA card present */
+#define EMU_HANA_OPTION_SYNC	0x02	/* Sync card present */
+#define EMU_HANA_OPTION_DOCK_ONLINE	0x04	/* Audio Dock online and FPGA configured */
+#define EMU_HANA_OPTION_DOCK_OFFLINE	0x08	/* Audio Dock online and FPGA not configured */
+
+#define EMU_HANA_ID		0x22	/* 1010101  7 bits ID byte & 0x7f = 0x55 */
+
+#define EMU_HANA_MAJOR_REV	0x23	/* 0000xxx  3 bit  Hana FPGA Major rev */
+#define EMU_HANA_MINOR_REV	0x24	/* 0000xxx  3 bit  Hana FPGA Minor rev */
+
+#define EMU_DOCK_MAJOR_REV	0x25	/* 0000xxx  3 bit  Audio Dock FPGA Major rev */
+#define EMU_DOCK_MINOR_REV	0x26	/* 0000xxx  3 bit  Audio Dock FPGA Minor rev */
+
+#define EMU_DOCK_BOARD_ID	0x27	/* 00000xx  2 bits Audio Dock ID pins */
+#define EMU_DOCK_BOARD_ID0	0x00	/* ID bit 0 */
+#define EMU_DOCK_BOARD_ID1	0x03	/* ID bit 1 */
+
+#define EMU_HANA_WC_SPDIF_HI	0x28	/* 0xxxxxx  6 bit  SPDIF IN Word clock, upper 6 bits */
+#define EMU_HANA_WC_SPDIF_LO	0x29	/* 0xxxxxx  6 bit  SPDIF IN Word clock, lower 6 bits */
+
+#define EMU_HANA_WC_ADAT_HI	0x2a	/* 0xxxxxx  6 bit  ADAT IN Word clock, upper 6 bits */
+#define EMU_HANA_WC_ADAT_LO	0x2b	/* 0xxxxxx  6 bit  ADAT IN Word clock, lower 6 bits */
+
+#define EMU_HANA_WC_BNC_LO	0x2c	/* 0xxxxxx  6 bit  BNC IN Word clock, lower 6 bits */
+#define EMU_HANA_WC_BNC_HI	0x2d	/* 0xxxxxx  6 bit  BNC IN Word clock, upper 6 bits */
+
+#define EMU_HANA2_WC_SPDIF_HI	0x2e	/* 0xxxxxx  6 bit  HANA2 SPDIF IN Word clock, upper 6 bits */
+#define EMU_HANA2_WC_SPDIF_LO	0x2f	/* 0xxxxxx  6 bit  HANA2 SPDIF IN Word clock, lower 6 bits */
+/* 0x30 - 0x3f Unused Read only registers */
+
+/************************************************************************************************/
+/* EMU1010m HANA Destinations									*/
+/************************************************************************************************/
+#define EMU_DST_ALICE2_EMU32_0	0x000f	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_1	0x0000	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_2	0x0001	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_3	0x0002	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_4	0x0003	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_5	0x0004	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_6	0x0005	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_7	0x0006	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_8	0x0007	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_9	0x0008	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_A	0x0009	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_B	0x000a	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_C	0x000b	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_D	0x000c	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_E	0x000d	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_F	0x000e	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_DOCK_DAC1_LEFT1	0x0100	/* Audio Dock DAC1 Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC1_LEFT2	0x0101	/* Audio Dock DAC1 Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC1_LEFT3	0x0102	/* Audio Dock DAC1 Left, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC1_LEFT4	0x0103	/* Audio Dock DAC1 Left, 4th or 192kHz */
+#define EMU_DST_DOCK_DAC1_RIGHT1	0x0104	/* Audio Dock DAC1 Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC1_RIGHT2	0x0105	/* Audio Dock DAC1 Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC1_RIGHT3	0x0106	/* Audio Dock DAC1 Right, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC1_RIGHT4	0x0107	/* Audio Dock DAC1 Right, 4th or 192kHz */
+#define EMU_DST_DOCK_DAC2_LEFT1	0x0108	/* Audio Dock DAC2 Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC2_LEFT2	0x0109	/* Audio Dock DAC2 Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC2_LEFT3	0x010a	/* Audio Dock DAC2 Left, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC2_LEFT4	0x010b	/* Audio Dock DAC2 Left, 4th or 192kHz */
+#define EMU_DST_DOCK_DAC2_RIGHT1	0x010c	/* Audio Dock DAC2 Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC2_RIGHT2	0x010d	/* Audio Dock DAC2 Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC2_RIGHT3	0x010e	/* Audio Dock DAC2 Right, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC2_RIGHT4	0x010f	/* Audio Dock DAC2 Right, 4th or 192kHz */
+#define EMU_DST_DOCK_DAC3_LEFT1	0x0110	/* Audio Dock DAC1 Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC3_LEFT2	0x0111	/* Audio Dock DAC1 Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC3_LEFT3	0x0112	/* Audio Dock DAC1 Left, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC3_LEFT4	0x0113	/* Audio Dock DAC1 Left, 4th or 192kHz */
+#define EMU_DST_DOCK_PHONES_LEFT1	0x0112	/* Audio Dock PHONES Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_PHONES_LEFT2	0x0113	/* Audio Dock PHONES Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC3_RIGHT1	0x0114	/* Audio Dock DAC1 Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC3_RIGHT2	0x0115	/* Audio Dock DAC1 Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC3_RIGHT3	0x0116	/* Audio Dock DAC1 Right, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC3_RIGHT4	0x0117	/* Audio Dock DAC1 Right, 4th or 192kHz */
+#define EMU_DST_DOCK_PHONES_RIGHT1	0x0116	/* Audio Dock PHONES Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_PHONES_RIGHT2	0x0117	/* Audio Dock PHONES Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC4_LEFT1	0x0118	/* Audio Dock DAC2 Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC4_LEFT2	0x0119	/* Audio Dock DAC2 Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC4_LEFT3	0x011a	/* Audio Dock DAC2 Left, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC4_LEFT4	0x011b	/* Audio Dock DAC2 Left, 4th or 192kHz */
+#define EMU_DST_DOCK_SPDIF_LEFT1	0x011a	/* Audio Dock SPDIF Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_SPDIF_LEFT2	0x011b	/* Audio Dock SPDIF Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC4_RIGHT1	0x011c	/* Audio Dock DAC2 Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC4_RIGHT2	0x011d	/* Audio Dock DAC2 Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC4_RIGHT3	0x011e	/* Audio Dock DAC2 Right, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC4_RIGHT4	0x011f	/* Audio Dock DAC2 Right, 4th or 192kHz */
+#define EMU_DST_DOCK_SPDIF_RIGHT1	0x011e	/* Audio Dock SPDIF Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_SPDIF_RIGHT2	0x011f	/* Audio Dock SPDIF Right, 2nd or 96kHz */
+#define EMU_DST_HANA_SPDIF_LEFT1	0x0200	/* Hana SPDIF Left, 1st or 48kHz only */
+#define EMU_DST_HANA_SPDIF_LEFT2	0x0202	/* Hana SPDIF Left, 2nd or 96kHz */
+#define EMU_DST_HANA_SPDIF_RIGHT1	0x0201	/* Hana SPDIF Right, 1st or 48kHz only */
+#define EMU_DST_HANA_SPDIF_RIGHT2	0x0203	/* Hana SPDIF Right, 2nd or 96kHz */
+#define EMU_DST_HAMOA_DAC_LEFT1	0x0300	/* Hamoa DAC Left, 1st or 48kHz only */
+#define EMU_DST_HAMOA_DAC_LEFT2	0x0302	/* Hamoa DAC Left, 2nd or 96kHz */
+#define EMU_DST_HAMOA_DAC_LEFT3	0x0304	/* Hamoa DAC Left, 3rd or 192kHz */
+#define EMU_DST_HAMOA_DAC_LEFT4	0x0306	/* Hamoa DAC Left, 4th or 192kHz */
+#define EMU_DST_HAMOA_DAC_RIGHT1	0x0301	/* Hamoa DAC Right, 1st or 48kHz only */
+#define EMU_DST_HAMOA_DAC_RIGHT2	0x0303	/* Hamoa DAC Right, 2nd or 96kHz */
+#define EMU_DST_HAMOA_DAC_RIGHT3	0x0305	/* Hamoa DAC Right, 3rd or 192kHz */
+#define EMU_DST_HAMOA_DAC_RIGHT4	0x0307	/* Hamoa DAC Right, 4th or 192kHz */
+#define EMU_DST_HANA_ADAT	0x0400	/* Hana ADAT 8 channel out +0 to +7 */
+#define EMU_DST_ALICE_I2S0_LEFT		0x0500	/* Alice2 I2S0 Left */
+#define EMU_DST_ALICE_I2S0_RIGHT	0x0501	/* Alice2 I2S0 Right */
+#define EMU_DST_ALICE_I2S1_LEFT		0x0600	/* Alice2 I2S1 Left */
+#define EMU_DST_ALICE_I2S1_RIGHT	0x0601	/* Alice2 I2S1 Right */
+#define EMU_DST_ALICE_I2S2_LEFT		0x0700	/* Alice2 I2S2 Left */
+#define EMU_DST_ALICE_I2S2_RIGHT	0x0701	/* Alice2 I2S2 Right */
+
+/************************************************************************************************/
+/* EMU1010m HANA Sources									*/
+/************************************************************************************************/
+#define EMU_SRC_SILENCE		0x0000	/* Silence */
+#define EMU_SRC_DOCK_MIC_A1	0x0100	/* Audio Dock Mic A, 1st or 48kHz only */
+#define EMU_SRC_DOCK_MIC_A2	0x0101	/* Audio Dock Mic A, 2nd or 96kHz */
+#define EMU_SRC_DOCK_MIC_A3	0x0102	/* Audio Dock Mic A, 3rd or 192kHz */
+#define EMU_SRC_DOCK_MIC_A4	0x0103	/* Audio Dock Mic A, 4th or 192kHz */
+#define EMU_SRC_DOCK_MIC_B1	0x0104	/* Audio Dock Mic B, 1st or 48kHz only */
+#define EMU_SRC_DOCK_MIC_B2	0x0105	/* Audio Dock Mic B, 2nd or 96kHz */
+#define EMU_SRC_DOCK_MIC_B3	0x0106	/* Audio Dock Mic B, 3rd or 192kHz */
+#define EMU_SRC_DOCK_MIC_B4	0x0107	/* Audio Dock Mic B, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC1_LEFT1	0x0108	/* Audio Dock ADC1 Left, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC1_LEFT2	0x0109	/* Audio Dock ADC1 Left, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC1_LEFT3	0x010a	/* Audio Dock ADC1 Left, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC1_LEFT4	0x010b	/* Audio Dock ADC1 Left, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC1_RIGHT1	0x010c	/* Audio Dock ADC1 Right, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC1_RIGHT2	0x010d	/* Audio Dock ADC1 Right, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC1_RIGHT3	0x010e	/* Audio Dock ADC1 Right, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC1_RIGHT4	0x010f	/* Audio Dock ADC1 Right, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC2_LEFT1	0x0110	/* Audio Dock ADC2 Left, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC2_LEFT2	0x0111	/* Audio Dock ADC2 Left, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC2_LEFT3	0x0112	/* Audio Dock ADC2 Left, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC2_LEFT4	0x0113	/* Audio Dock ADC2 Left, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC2_RIGHT1	0x0114	/* Audio Dock ADC2 Right, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC2_RIGHT2	0x0115	/* Audio Dock ADC2 Right, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC2_RIGHT3	0x0116	/* Audio Dock ADC2 Right, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC2_RIGHT4	0x0117	/* Audio Dock ADC2 Right, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC3_LEFT1	0x0118	/* Audio Dock ADC3 Left, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC3_LEFT2	0x0119	/* Audio Dock ADC3 Left, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC3_LEFT3	0x011a	/* Audio Dock ADC3 Left, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC3_LEFT4	0x011b	/* Audio Dock ADC3 Left, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC3_RIGHT1	0x011c	/* Audio Dock ADC3 Right, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC3_RIGHT2	0x011d	/* Audio Dock ADC3 Right, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC3_RIGHT3	0x011e	/* Audio Dock ADC3 Right, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC3_RIGHT4	0x011f	/* Audio Dock ADC3 Right, 4th or 192kHz */
+#define EMU_SRC_HAMOA_ADC_LEFT1	0x0200	/* Hamoa ADC Left, 1st or 48kHz only */
+#define EMU_SRC_HAMOA_ADC_LEFT2	0x0202	/* Hamoa ADC Left, 2nd or 96kHz */
+#define EMU_SRC_HAMOA_ADC_LEFT3	0x0204	/* Hamoa ADC Left, 3rd or 192kHz */
+#define EMU_SRC_HAMOA_ADC_LEFT4	0x0206	/* Hamoa ADC Left, 4th or 192kHz */
+#define EMU_SRC_HAMOA_ADC_RIGHT1	0x0201	/* Hamoa ADC Right, 1st or 48kHz only */
+#define EMU_SRC_HAMOA_ADC_RIGHT2	0x0203	/* Hamoa ADC Right, 2nd or 96kHz */
+#define EMU_SRC_HAMOA_ADC_RIGHT3	0x0205	/* Hamoa ADC Right, 3rd or 192kHz */
+#define EMU_SRC_HAMOA_ADC_RIGHT4	0x0207	/* Hamoa ADC Right, 4th or 192kHz */
+#define EMU_SRC_ALICE_EMU32A		0x0300	/* Alice2 EMU32a 16 outputs. +0 to +0xf */
+#define EMU_SRC_ALICE_EMU32B		0x0310	/* Alice2 EMU32b 16 outputs. +0 to +0xf */
+#define EMU_SRC_HANA_ADAT	0x0400	/* Hana ADAT 8 channel in +0 to +7 */
+#define EMU_SRC_HANA_SPDIF_LEFT1	0x0500	/* Hana SPDIF Left, 1st or 48kHz only */
+#define EMU_SRC_HANA_SPDIF_LEFT2	0x0502	/* Hana SPDIF Left, 2nd or 96kHz */
+#define EMU_SRC_HANA_SPDIF_RIGHT1	0x0501	/* Hana SPDIF Right, 1st or 48kHz only */
+#define EMU_SRC_HANA_SPDIF_RIGHT2	0x0503	/* Hana SPDIF Right, 2nd or 96kHz */
+/* 0x600 and 0x700 no used */
 
 /* ------------------- STRUCTURES -------------------- */
 
@@ -1063,7 +1425,7 @@
 	unsigned char spdif_bug;    /* Has Spdif phasing bug */
 	unsigned char ac97_chip;    /* Has an AC97 chip: 1 = mandatory, 2 = optional */
 	unsigned char ecard;        /* APS EEPROM */
-	unsigned char emu1212m;     /* EMU 1212m card */
+	unsigned char emu1010;     /* EMU 1010m card */
 	unsigned char spi_dac;      /* SPI interface for DAC */
 	unsigned char i2c_adc;      /* I2C interface for ADC */
 	unsigned char adc_1361t;    /* Use Philips 1361T ADC */
@@ -1072,6 +1434,14 @@
 	const char *id;		/* for backward compatibility - can be NULL if not needed */
 };
 
+struct snd_emu1010 {
+	unsigned int output_source[64];
+	unsigned int input_source[64];
+	unsigned int adc_pads; /* bit mask */
+	unsigned int dac_pads; /* bit mask */
+	unsigned int internal_clock; /* 44100 or 48000 */
+};
+
 struct snd_emu10k1 {
 	int irq;
 
@@ -1079,6 +1449,7 @@
 	unsigned int tos_link: 1,		/* tos link detected */
 		rear_ac97: 1,			/* rear channels are on AC'97 */
 		enable_ir: 1;
+	unsigned int support_tlv :1;
 	/* Contains profile of card capabilities */
 	const struct snd_emu_chip_details *card_capabilities;
 	unsigned int audigy;			/* is Audigy? */
@@ -1104,6 +1475,8 @@
 	spinlock_t memblk_lock;
 
 	unsigned int spdif_bits[3];		/* s/pdif out setup */
+	unsigned int i2c_capture_source;
+	u8 i2c_capture_volume[4][2];
 
 	struct snd_emu10k1_fx8010 fx8010;		/* FX8010 info */
 	int gpr_base;
@@ -1132,6 +1505,7 @@
 	int p16v_device_offset;
 	u32 p16v_capture_source;
 	u32 p16v_capture_channel;
+        struct snd_emu1010 emu1010;
 	struct snd_emu10k1_pcm_mixer pcm_mixer[32];
 	struct snd_emu10k1_pcm_mixer efx_pcm_mixer[NUM_EFX_PLAYBACK];
 	struct snd_kcontrol *ctl_send_routing;
@@ -1208,6 +1582,10 @@
 unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn);
 void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data);
 int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data);
+int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
+int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value);
+int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value);
+int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src);
 unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc);
 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb);
 void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb);
@@ -1524,11 +1902,20 @@
 	unsigned int value[32];		/* initial values */
 	unsigned int min;		/* minimum range */
 	unsigned int max;		/* maximum range */
-	union {
-		snd_kcontrol_tlv_rw_t *c;
-		unsigned int *p;
-	} tlv;
 	unsigned int translation;	/* translation type (EMU10K1_GPR_TRANSLATION*) */
+	const unsigned int *tlv;
+};
+
+/* old ABI without TLV support */
+struct snd_emu10k1_fx8010_control_old_gpr {
+	struct snd_ctl_elem_id id;
+	unsigned int vcount;
+	unsigned int count;
+	unsigned short gpr[32];
+	unsigned int value[32];
+	unsigned int min;
+	unsigned int max;
+	unsigned int translation;
 };
 
 struct snd_emu10k1_fx8010_code {
@@ -1579,6 +1966,8 @@
 	unsigned int res2;		/* reserved */
 };
 
+#define SNDRV_EMU10K1_VERSION		SNDRV_PROTOCOL_VERSION(1, 0, 1)
+
 #define SNDRV_EMU10K1_IOCTL_INFO	_IOR ('H', 0x10, struct snd_emu10k1_fx8010_info)
 #define SNDRV_EMU10K1_IOCTL_CODE_POKE	_IOW ('H', 0x11, struct snd_emu10k1_fx8010_code)
 #define SNDRV_EMU10K1_IOCTL_CODE_PEEK	_IOWR('H', 0x12, struct snd_emu10k1_fx8010_code)
@@ -1587,6 +1976,7 @@
 #define SNDRV_EMU10K1_IOCTL_TRAM_PEEK	_IOWR('H', 0x22, struct snd_emu10k1_fx8010_tram)
 #define SNDRV_EMU10K1_IOCTL_PCM_POKE	_IOW ('H', 0x30, struct snd_emu10k1_fx8010_pcm_rec)
 #define SNDRV_EMU10K1_IOCTL_PCM_PEEK	_IOWR('H', 0x31, struct snd_emu10k1_fx8010_pcm_rec)
+#define SNDRV_EMU10K1_IOCTL_PVERSION	_IOR ('H', 0x40, int)
 #define SNDRV_EMU10K1_IOCTL_STOP	_IO  ('H', 0x80)
 #define SNDRV_EMU10K1_IOCTL_CONTINUE	_IO  ('H', 0x81)
 #define SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER _IO ('H', 0x82)
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 2f645df..ee6bc2d 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -56,6 +56,8 @@
 	size_t fifo_size;		/* fifo size in bytes */
 };
 
+struct snd_pcm_substream;
+
 struct snd_pcm_ops {
 	int (*open)(struct snd_pcm_substream *substream);
 	int (*close)(struct snd_pcm_substream *substream);
@@ -384,6 +386,7 @@
 	struct snd_info_entry *proc_sw_params_entry;
 	struct snd_info_entry *proc_status_entry;
 	struct snd_info_entry *proc_prealloc_entry;
+	struct snd_info_entry *proc_prealloc_max_entry;
 #endif
 	/* misc flags */
 	unsigned int hw_opened: 1;
@@ -427,6 +430,7 @@
 	wait_queue_head_t open_wait;
 	void *private_data;
 	void (*private_free) (struct snd_pcm *pcm);
+	struct device *dev; /* actual hw device this belongs to */
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
 	struct snd_pcm_oss oss;
 #endif
diff --git a/include/sound/pt2258.h b/include/sound/pt2258.h
new file mode 100644
index 0000000..160f812
--- /dev/null
+++ b/include/sound/pt2258.h
@@ -0,0 +1,37 @@
+/*
+ *   ALSA Driver for the PT2258 volume controller.
+ *
+ *	Copyright (c) 2006  Jochen Voss <voss@seehuhn.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
+ *
+ */      
+
+#ifndef __SOUND_PT2258_H
+#define __SOUND_PT2258_H
+
+struct snd_pt2258 {
+	struct snd_card *card;
+	struct snd_i2c_bus *i2c_bus;
+	struct snd_i2c_device *i2c_dev;
+
+	unsigned char volume[6];
+	int mute;
+};
+
+extern int snd_pt2258_reset(struct snd_pt2258 *pt);
+extern int snd_pt2258_build_controls(struct snd_pt2258 *pt);
+
+#endif /* __SOUND_PT2258_H */
diff --git a/include/sound/sb16_csp.h b/include/sound/sb16_csp.h
index caf6fe2..736eac7 100644
--- a/include/sound/sb16_csp.h
+++ b/include/sound/sb16_csp.h
@@ -114,9 +114,21 @@
 #ifdef __KERNEL__
 #include "sb.h"
 #include "hwdep.h"
+#include <linux/firmware.h>
 
 struct snd_sb_csp;
 
+/* indices for the known CSP programs */
+enum {
+	CSP_PROGRAM_MULAW,
+	CSP_PROGRAM_ALAW,
+	CSP_PROGRAM_ADPCM_INIT,
+	CSP_PROGRAM_ADPCM_PLAYBACK,
+	CSP_PROGRAM_ADPCM_CAPTURE,
+
+	CSP_PROGRAM_COUNT
+};
+
 /*
  * CSP operators
  */
@@ -159,6 +171,8 @@
 	struct snd_kcontrol *qsound_space;
 
 	struct mutex access_mutex;	/* locking */
+
+	const struct firmware *csp_programs[CSP_PROGRAM_COUNT];
 };
 
 int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep);
diff --git a/include/sound/snd_wavefront.h b/include/sound/snd_wavefront.h
index 0b9e5de..9688d4b 100644
--- a/include/sound/snd_wavefront.h
+++ b/include/sound/snd_wavefront.h
@@ -85,6 +85,7 @@
 	char hw_version[2];                /* major = [0], minor = [1] */
 	char israw;                        /* needs Motorola microcode */
 	char has_fx;                       /* has FX processor (Tropez+) */
+	char fx_initialized;               /* FX's register pages initialized */
 	char prog_status[WF_MAX_PROGRAM];  /* WF_SLOT_* */
 	char patch_status[WF_MAX_PATCH];   /* WF_SLOT_* */
 	char sample_status[WF_MAX_SAMPLE]; /* WF_ST_* | WF_SLOT_* */
@@ -94,6 +95,7 @@
 	spinlock_t irq_lock;
 	wait_queue_head_t interrupt_sleeper; 
 	snd_wavefront_midi_t midi;         /* ICS2115 MIDI interface */
+	struct snd_card *card;
 };
 
 struct _snd_wavefront_card {
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
new file mode 100644
index 0000000..2b1ae8e
--- /dev/null
+++ b/include/sound/soc-dapm.h
@@ -0,0 +1,286 @@
+/*
+ * linux/sound/soc-dapm.h -- ALSA SoC Dynamic Audio Power Management
+ *
+ * Author:		Liam Girdwood
+ * Created:		Aug 11th 2005
+ * Copyright:	Wolfson Microelectronics. PLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_SOC_DAPM_H
+#define __LINUX_SND_SOC_DAPM_H
+
+#include <linux/device.h>
+#include <linux/types.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+
+/* widget has no PM register bit */
+#define SND_SOC_NOPM	-1
+
+/*
+ * SoC dynamic audio power managment
+ *
+ * We can have upto 4 power domains
+ * 	1. Codec domain - VREF, VMID
+ *     Usually controlled at codec probe/remove, although can be set
+ *     at stream time if power is not needed for sidetone, etc.
+ *  2. Platform/Machine domain - physically connected inputs and outputs
+ *     Is platform/machine and user action specific, is set in the machine
+ *     driver and by userspace e.g when HP are inserted
+ *  3. Path domain - Internal codec path mixers
+ *     Are automatically set when mixer and mux settings are
+ *     changed by the user.
+ *  4. Stream domain - DAC's and ADC's.
+ *     Enabled when stream playback/capture is started.
+ */
+
+/* codec domain */
+#define SND_SOC_DAPM_VMID(wname) \
+{	.id = snd_soc_dapm_vmid, .name = wname, .kcontrols = NULL, \
+	.num_kcontrols = 0}
+
+/* platform domain */
+#define SND_SOC_DAPM_INPUT(wname) \
+{	.id = snd_soc_dapm_input, .name = wname, .kcontrols = NULL, \
+	.num_kcontrols = 0}
+#define SND_SOC_DAPM_OUTPUT(wname) \
+{	.id = snd_soc_dapm_output, .name = wname, .kcontrols = NULL, \
+	.num_kcontrols = 0}
+#define SND_SOC_DAPM_MIC(wname, wevent) \
+{	.id = snd_soc_dapm_mic, .name = wname, .kcontrols = NULL, \
+	.num_kcontrols = 0, .event = wevent, \
+	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
+#define SND_SOC_DAPM_HP(wname, wevent) \
+{	.id = snd_soc_dapm_hp, .name = wname, .kcontrols = NULL, \
+	.num_kcontrols = 0, .event = wevent, \
+	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
+#define SND_SOC_DAPM_SPK(wname, wevent) \
+{	.id = snd_soc_dapm_spk, .name = wname, .kcontrols = NULL, \
+	.num_kcontrols = 0, .event = wevent, \
+	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
+#define SND_SOC_DAPM_LINE(wname, wevent) \
+{	.id = snd_soc_dapm_line, .name = wname, .kcontrols = NULL, \
+	.num_kcontrols = 0, .event = wevent, \
+	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
+
+/* path domain */
+#define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
+	 wcontrols, wncontrols) \
+{	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
+	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
+#define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
+	 wcontrols, wncontrols)\
+{	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
+	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
+#define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
+{	.id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
+	.invert = winvert, .kcontrols = NULL, .num_kcontrols = 0}
+#define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
+{	.id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
+	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
+#define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
+{	.id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
+	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
+
+/* path domain with event - event handler must return 0 for success */
+#define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
+	wncontrols, wevent, wflags) \
+{	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
+	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
+	.event = wevent, .event_flags = wflags}
+#define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
+	wncontrols, wevent, wflags) \
+{	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
+	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
+	.event = wevent, .event_flags = wflags}
+#define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \
+{	.id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
+	.invert = winvert, .kcontrols = NULL, .num_kcontrols = 0, \
+	.event = wevent, .event_flags = wflags}
+#define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
+	wevent, wflags) \
+{	.id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
+	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1 \
+	.event = wevent, .event_flags = wflags}
+#define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
+	wevent, wflags) \
+{	.id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
+	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
+	.event = wevent, .event_flags = wflags}
+
+/* events that are pre and post DAPM */
+#define SND_SOC_DAPM_PRE(wname, wevent) \
+{	.id = snd_soc_dapm_pre, .name = wname, .kcontrols = NULL, \
+	.num_kcontrols = 0, .event = wevent, \
+	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD}
+#define SND_SOC_DAPM_POST(wname, wevent) \
+{	.id = snd_soc_dapm_post, .name = wname, .kcontrols = NULL, \
+	.num_kcontrols = 0, .event = wevent, \
+	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD}
+
+/* stream domain */
+#define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
+{	.id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
+	.shift = wshift, .invert = winvert}
+#define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \
+{	.id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
+	.shift = wshift, .invert = winvert}
+
+/* dapm kcontrol types */
+#define SOC_DAPM_SINGLE(xname, reg, shift, mask, invert) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_volsw, \
+	.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
+	.private_value =  SOC_SINGLE_VALUE(reg, shift, mask, invert) }
+#define SOC_DAPM_DOUBLE(xname, reg, shift_left, shift_right, mask, invert, \
+	power) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.info = snd_soc_info_volsw, \
+ 	.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
+ 	.private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) |\
+ 		 ((mask) << 16) | ((invert) << 24) }
+#define SOC_DAPM_ENUM(xname, xenum) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_enum_double, \
+ 	.get = snd_soc_dapm_get_enum_double, \
+ 	.put = snd_soc_dapm_put_enum_double, \
+  	.private_value = (unsigned long)&xenum }
+
+/* dapm stream operations */
+#define SND_SOC_DAPM_STREAM_NOP			0x0
+#define SND_SOC_DAPM_STREAM_START		0x1
+#define SND_SOC_DAPM_STREAM_STOP		0x2
+#define SND_SOC_DAPM_STREAM_SUSPEND		0x4
+#define SND_SOC_DAPM_STREAM_RESUME		0x8
+#define SND_SOC_DAPM_STREAM_PAUSE_PUSH	0x10
+#define SND_SOC_DAPM_STREAM_PAUSE_RELEASE	0x20
+
+/* dapm event types */
+#define SND_SOC_DAPM_PRE_PMU	0x1 	/* before widget power up */
+#define SND_SOC_DAPM_POST_PMU	0x2		/* after widget power up */
+#define SND_SOC_DAPM_PRE_PMD	0x4 	/* before widget power down */
+#define SND_SOC_DAPM_POST_PMD	0x8		/* after widget power down */
+#define SND_SOC_DAPM_PRE_REG	0x10	/* before audio path setup */
+#define SND_SOC_DAPM_POST_REG	0x20	/* after audio path setup */
+
+/* convenience event type detection */
+#define SND_SOC_DAPM_EVENT_ON(e)	\
+	(e & (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU))
+#define SND_SOC_DAPM_EVENT_OFF(e)	\
+	(e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD))
+
+struct snd_soc_dapm_widget;
+enum snd_soc_dapm_type;
+struct snd_soc_dapm_path;
+struct snd_soc_dapm_pin;
+
+/* dapm controls */
+int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
+	const struct snd_soc_dapm_widget *widget);
+
+/* dapm path setup */
+int snd_soc_dapm_connect_input(struct snd_soc_codec *codec,
+	const char *sink_name, const char *control_name, const char *src_name);
+int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
+void snd_soc_dapm_free(struct snd_soc_device *socdev);
+
+/* dapm events */
+int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
+	int event);
+
+/* dapm sys fs - used by the core */
+int snd_soc_dapm_sys_add(struct device *dev);
+
+/* dapm audio endpoint control */
+int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec,
+	char *pin, int status);
+int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec);
+
+/* dapm widget types */
+enum snd_soc_dapm_type {
+	snd_soc_dapm_input = 0,		/* input pin */
+	snd_soc_dapm_output,		/* output pin */
+	snd_soc_dapm_mux,			/* selects 1 analog signal from many inputs */
+	snd_soc_dapm_mixer,			/* mixes several analog signals together */
+	snd_soc_dapm_pga,			/* programmable gain/attenuation (volume) */
+	snd_soc_dapm_adc,			/* analog to digital converter */
+	snd_soc_dapm_dac,			/* digital to analog converter */
+	snd_soc_dapm_micbias,		/* microphone bias (power) */
+	snd_soc_dapm_mic,			/* microphone */
+	snd_soc_dapm_hp,			/* headphones */
+	snd_soc_dapm_spk,			/* speaker */
+	snd_soc_dapm_line,			/* line input/output */
+	snd_soc_dapm_switch,		/* analog switch */
+	snd_soc_dapm_vmid,			/* codec bias/vmid - to minimise pops */
+	snd_soc_dapm_pre,			/* machine specific pre widget - exec first */
+	snd_soc_dapm_post,			/* machine specific post widget - exec last */
+};
+
+/* dapm audio path between two widgets */
+struct snd_soc_dapm_path {
+	char *name;
+	char *long_name;
+
+	/* source (input) and sink (output) widgets */
+	struct snd_soc_dapm_widget *source;
+	struct snd_soc_dapm_widget *sink;
+	struct snd_kcontrol *kcontrol;
+
+	/* status */
+	u32 connect:1;	/* source and sink widgets are connected */
+	u32 walked:1;	/* path has been walked */
+
+	struct list_head list_source;
+	struct list_head list_sink;
+	struct list_head list;
+};
+
+/* dapm widget */
+struct snd_soc_dapm_widget {
+	enum snd_soc_dapm_type id;
+	char *name;		/* widget name */
+	char *sname;	/* stream name */
+	struct snd_soc_codec *codec;
+	struct list_head list;
+
+	/* dapm control */
+	short reg;						/* negative reg = no direct dapm */
+	unsigned char shift;			/* bits to shift */
+	unsigned int saved_value;		/* widget saved value */
+	unsigned int value;				/* widget current value */
+	unsigned char power:1;			/* block power status */
+	unsigned char invert:1;			/* invert the power bit */
+	unsigned char active:1;			/* active stream on DAC, ADC's */
+	unsigned char connected:1;		/* connected codec pin */
+	unsigned char new:1;			/* cnew complete */
+	unsigned char ext:1;			/* has external widgets */
+	unsigned char muted:1;			/* muted for pop reduction */
+	unsigned char suspend:1;		/* was active before suspend */
+	unsigned char pmdown:1;			/* waiting for timeout */
+
+	/* external events */
+	unsigned short event_flags;		/* flags to specify event types */
+	int (*event)(struct snd_soc_dapm_widget*, int);
+
+	/* kcontrols that relate to this widget */
+	int num_kcontrols;
+	const struct snd_kcontrol_new *kcontrols;
+
+	/* widget input and outputs */
+	struct list_head sources;
+	struct list_head sinks;
+};
+
+#endif
diff --git a/include/sound/soc.h b/include/sound/soc.h
new file mode 100644
index 0000000..b1dc364
--- /dev/null
+++ b/include/sound/soc.h
@@ -0,0 +1,461 @@
+/*
+ * linux/sound/soc.h -- ALSA SoC Layer
+ *
+ * Author:		Liam Girdwood
+ * Created:		Aug 11th 2005
+ * Copyright:	Wolfson Microelectronics. PLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_SOC_H
+#define __LINUX_SND_SOC_H
+
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/control.h>
+#include <sound/ac97_codec.h>
+
+#define SND_SOC_VERSION "0.13.0"
+
+/*
+ * Convenience kcontrol builders
+ */
+#define SOC_SINGLE_VALUE(reg,shift,mask,invert) ((reg) | ((shift) << 8) |\
+	((shift) << 12) | ((mask) << 16) | ((invert) << 24))
+#define SOC_SINGLE_VALUE_EXT(reg,mask,invert) ((reg) | ((mask) << 16) |\
+	((invert) << 31))
+#define SOC_SINGLE(xname, reg, shift, mask, invert) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
+	.put = snd_soc_put_volsw, \
+	.private_value =  SOC_SINGLE_VALUE(reg, shift, mask, invert) }
+#define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
+	.put = snd_soc_put_volsw, \
+	.private_value = (reg) | ((shift_left) << 8) | \
+		((shift_right) << 12) | ((mask) << 16) | ((invert) << 24) }
+#define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.info = snd_soc_info_volsw_2r, \
+	.get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
+	.private_value = (reg_left) | ((shift) << 8)  | \
+		((mask) << 12) | ((invert) << 20) | ((reg_right) << 24) }
+#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \
+{	.reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
+	.mask = xmask, .texts = xtexts }
+#define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts) \
+	SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xtexts)
+#define SOC_ENUM_SINGLE_EXT(xmask, xtexts) \
+{	.mask = xmask, .texts = xtexts }
+#define SOC_ENUM(xname, xenum) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
+	.info = snd_soc_info_enum_double, \
+	.get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \
+	.private_value = (unsigned long)&xenum }
+#define SOC_SINGLE_EXT(xname, xreg, xshift, xmask, xinvert,\
+	 xhandler_get, xhandler_put) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_volsw, \
+	.get = xhandler_get, .put = xhandler_put, \
+	.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) }
+#define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_bool_ext, \
+	.get = xhandler_get, .put = xhandler_put, \
+	.private_value = xdata }
+#define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_enum_ext, \
+	.get = xhandler_get, .put = xhandler_put, \
+	.private_value = (unsigned long)&xenum }
+
+/*
+ * Digital Audio Interface (DAI) types
+ */
+#define SND_SOC_DAI_AC97	0x1
+#define SND_SOC_DAI_I2S		0x2
+#define SND_SOC_DAI_PCM		0x4
+
+/*
+ * DAI hardware audio formats
+ */
+#define SND_SOC_DAIFMT_I2S		0	/* I2S mode */
+#define SND_SOC_DAIFMT_RIGHT_J	1	/* Right justified mode */
+#define SND_SOC_DAIFMT_LEFT_J	2	/* Left Justified mode */
+#define SND_SOC_DAIFMT_DSP_A	3	/* L data msb after FRM or LRC */
+#define SND_SOC_DAIFMT_DSP_B	4	/* L data msb during FRM or LRC */
+#define SND_SOC_DAIFMT_AC97		5	/* AC97 */
+
+#define SND_SOC_DAIFMT_MSB 	SND_SOC_DAIFMT_LEFT_J
+#define SND_SOC_DAIFMT_LSB	SND_SOC_DAIFMT_RIGHT_J
+
+/*
+ * DAI Gating
+ */
+#define SND_SOC_DAIFMT_CONT			(0 << 4)	/* continuous clock */
+#define SND_SOC_DAIFMT_GATED		(1 << 4)	/* clock is gated when not Tx/Rx */
+
+/*
+ * DAI hardware signal inversions
+ */
+#define SND_SOC_DAIFMT_NB_NF		(0 << 8)	/* normal bit clock + frame */
+#define SND_SOC_DAIFMT_NB_IF		(1 << 8)	/* normal bclk + inv frm */
+#define SND_SOC_DAIFMT_IB_NF		(2 << 8)	/* invert bclk + nor frm */
+#define SND_SOC_DAIFMT_IB_IF		(3 << 8)	/* invert bclk + frm */
+
+/*
+ * DAI hardware clock masters
+ * This is wrt the codec, the inverse is true for the interface
+ * i.e. if the codec is clk and frm master then the interface is
+ * clk and frame slave.
+ */
+#define SND_SOC_DAIFMT_CBM_CFM	(0 << 12) /* codec clk & frm master */
+#define SND_SOC_DAIFMT_CBS_CFM	(1 << 12) /* codec clk slave & frm master */
+#define SND_SOC_DAIFMT_CBM_CFS	(2 << 12) /* codec clk master & frame slave */
+#define SND_SOC_DAIFMT_CBS_CFS	(3 << 12) /* codec clk & frm slave */
+
+#define SND_SOC_DAIFMT_FORMAT_MASK		0x000f
+#define SND_SOC_DAIFMT_CLOCK_MASK		0x00f0
+#define SND_SOC_DAIFMT_INV_MASK			0x0f00
+#define SND_SOC_DAIFMT_MASTER_MASK		0xf000
+
+
+/*
+ * Master Clock Directions
+ */
+#define SND_SOC_CLOCK_IN	0
+#define SND_SOC_CLOCK_OUT	1
+
+/*
+ * AC97 codec ID's bitmask
+ */
+#define SND_SOC_DAI_AC97_ID0	(1 << 0)
+#define SND_SOC_DAI_AC97_ID1	(1 << 1)
+#define SND_SOC_DAI_AC97_ID2	(1 << 2)
+#define SND_SOC_DAI_AC97_ID3	(1 << 3)
+
+struct snd_soc_device;
+struct snd_soc_pcm_stream;
+struct snd_soc_ops;
+struct snd_soc_dai_mode;
+struct snd_soc_pcm_runtime;
+struct snd_soc_codec_dai;
+struct snd_soc_cpu_dai;
+struct snd_soc_codec;
+struct snd_soc_machine_config;
+struct soc_enum;
+struct snd_soc_ac97_ops;
+struct snd_soc_clock_info;
+
+typedef int (*hw_write_t)(void *,const char* ,int);
+typedef int (*hw_read_t)(void *,char* ,int);
+
+extern struct snd_ac97_bus_ops soc_ac97_ops;
+
+/* pcm <-> DAI connect */
+void snd_soc_free_pcms(struct snd_soc_device *socdev);
+int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid);
+int snd_soc_register_card(struct snd_soc_device *socdev);
+
+/* set runtime hw params */
+int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
+	const struct snd_pcm_hardware *hw);
+
+/* codec IO */
+#define snd_soc_read(codec, reg) codec->read(codec, reg)
+#define snd_soc_write(codec, reg, value) codec->write(codec, reg, value)
+
+/* codec register bit access */
+int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
+				unsigned short mask, unsigned short value);
+int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
+				unsigned short mask, unsigned short value);
+
+int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
+	struct snd_ac97_bus_ops *ops, int num);
+void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
+
+/*
+ *Controls
+ */
+struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
+	void *data, char *long_name);
+int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo);
+int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo);
+int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo);
+int snd_soc_info_bool_ext(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+
+/* SoC PCM stream information */
+struct snd_soc_pcm_stream {
+	char *stream_name;
+	u64 formats;			/* SNDRV_PCM_FMTBIT_* */
+	unsigned int rates;		/* SNDRV_PCM_RATE_* */
+	unsigned int rate_min;		/* min rate */
+	unsigned int rate_max;		/* max rate */
+	unsigned int channels_min;	/* min channels */
+	unsigned int channels_max;	/* max channels */
+	unsigned int active:1;		/* stream is in use */
+};
+
+/* SoC audio ops */
+struct snd_soc_ops {
+	int (*startup)(struct snd_pcm_substream *);
+	void (*shutdown)(struct snd_pcm_substream *);
+	int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
+	int (*hw_free)(struct snd_pcm_substream *);
+	int (*prepare)(struct snd_pcm_substream *);
+	int (*trigger)(struct snd_pcm_substream *, int);
+};
+
+/* ASoC codec DAI ops */
+struct snd_soc_codec_ops {
+	/* codec DAI clocking configuration */
+	int (*set_sysclk)(struct snd_soc_codec_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir);
+	int (*set_pll)(struct snd_soc_codec_dai *codec_dai,
+		int pll_id, unsigned int freq_in, unsigned int freq_out);
+	int (*set_clkdiv)(struct snd_soc_codec_dai *codec_dai,
+		int div_id, int div);
+
+	/* CPU DAI format configuration */
+	int (*set_fmt)(struct snd_soc_codec_dai *codec_dai,
+		unsigned int fmt);
+	int (*set_tdm_slot)(struct snd_soc_codec_dai *codec_dai,
+		unsigned int mask, int slots);
+	int (*set_tristate)(struct snd_soc_codec_dai *, int tristate);
+
+	/* digital mute */
+	int (*digital_mute)(struct snd_soc_codec_dai *, int mute);
+};
+
+/* ASoC cpu DAI ops */
+struct snd_soc_cpu_ops {
+	/* CPU DAI clocking configuration */
+	int (*set_sysclk)(struct snd_soc_cpu_dai *cpu_dai,
+		int clk_id, unsigned int freq, int dir);
+	int (*set_clkdiv)(struct snd_soc_cpu_dai *cpu_dai,
+		int div_id, int div);
+	int (*set_pll)(struct snd_soc_cpu_dai *cpu_dai,
+		int pll_id, unsigned int freq_in, unsigned int freq_out);
+
+	/* CPU DAI format configuration */
+	int (*set_fmt)(struct snd_soc_cpu_dai *cpu_dai,
+		unsigned int fmt);
+	int (*set_tdm_slot)(struct snd_soc_cpu_dai *cpu_dai,
+		unsigned int mask, int slots);
+	int (*set_tristate)(struct snd_soc_cpu_dai *, int tristate);
+};
+
+/* SoC Codec DAI */
+struct snd_soc_codec_dai {
+	char *name;
+	int id;
+
+	/* DAI capabilities */
+	struct snd_soc_pcm_stream playback;
+	struct snd_soc_pcm_stream capture;
+
+	/* DAI runtime info */
+	struct snd_soc_codec *codec;
+	unsigned int active;
+	unsigned char pop_wait:1;
+
+	/* ops */
+	struct snd_soc_ops ops;
+	struct snd_soc_codec_ops dai_ops;
+
+	/* DAI private data */
+	void *private_data;
+};
+
+/* SoC CPU DAI */
+struct snd_soc_cpu_dai {
+
+	/* DAI description */
+	char *name;
+	unsigned int id;
+	unsigned char type;
+
+	/* DAI callbacks */
+	int (*probe)(struct platform_device *pdev);
+	void (*remove)(struct platform_device *pdev);
+	int (*suspend)(struct platform_device *pdev,
+		struct snd_soc_cpu_dai *cpu_dai);
+	int (*resume)(struct platform_device *pdev,
+		struct snd_soc_cpu_dai *cpu_dai);
+
+	/* ops */
+	struct snd_soc_ops ops;
+	struct snd_soc_cpu_ops dai_ops;
+
+	/* DAI capabilities */
+	struct snd_soc_pcm_stream capture;
+	struct snd_soc_pcm_stream playback;
+
+	/* DAI runtime info */
+	struct snd_pcm_runtime *runtime;
+	unsigned char active:1;
+	void *dma_data;
+
+	/* DAI private data */
+	void *private_data;
+};
+
+/* SoC Audio Codec */
+struct snd_soc_codec {
+	char *name;
+	struct module *owner;
+	struct mutex mutex;
+
+	/* callbacks */
+	int (*dapm_event)(struct snd_soc_codec *codec, int event);
+
+	/* runtime */
+	struct snd_card *card;
+	struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
+	unsigned int active;
+	unsigned int pcm_devs;
+	void *private_data;
+
+	/* codec IO */
+	void *control_data; /* codec control (i2c/3wire) data */
+	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
+	int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
+	hw_write_t hw_write;
+	hw_read_t hw_read;
+	void *reg_cache;
+	short reg_cache_size;
+	short reg_cache_step;
+
+	/* dapm */
+	struct list_head dapm_widgets;
+	struct list_head dapm_paths;
+	unsigned int dapm_state;
+	unsigned int suspend_dapm_state;
+	struct delayed_work delayed_work;
+
+	/* codec DAI's */
+	struct snd_soc_codec_dai *dai;
+	unsigned int num_dai;
+};
+
+/* codec device */
+struct snd_soc_codec_device {
+	int (*probe)(struct platform_device *pdev);
+	int (*remove)(struct platform_device *pdev);
+	int (*suspend)(struct platform_device *pdev, pm_message_t state);
+	int (*resume)(struct platform_device *pdev);
+};
+
+/* SoC platform interface */
+struct snd_soc_platform {
+	char *name;
+
+	int (*probe)(struct platform_device *pdev);
+	int (*remove)(struct platform_device *pdev);
+	int (*suspend)(struct platform_device *pdev,
+		struct snd_soc_cpu_dai *cpu_dai);
+	int (*resume)(struct platform_device *pdev,
+		struct snd_soc_cpu_dai *cpu_dai);
+
+	/* pcm creation and destruction */
+	int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *,
+		struct snd_pcm *);
+	void (*pcm_free)(struct snd_pcm *);
+
+	/* platform stream ops */
+	struct snd_pcm_ops *pcm_ops;
+};
+
+/* SoC machine DAI configuration, glues a codec and cpu DAI together */
+struct snd_soc_dai_link  {
+	char *name;			/* Codec name */
+	char *stream_name;		/* Stream name */
+
+	/* DAI */
+	struct snd_soc_codec_dai *codec_dai;
+	struct snd_soc_cpu_dai *cpu_dai;
+
+	/* machine stream operations */
+	struct snd_soc_ops *ops;
+
+	/* codec/machine specific init - e.g. add machine controls */
+	int (*init)(struct snd_soc_codec *codec);
+};
+
+/* SoC machine */
+struct snd_soc_machine {
+	char *name;
+
+	int (*probe)(struct platform_device *pdev);
+	int (*remove)(struct platform_device *pdev);
+
+	/* the pre and post PM functions are used to do any PM work before and
+	 * after the codec and DAI's do any PM work. */
+	int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);
+	int (*suspend_post)(struct platform_device *pdev, pm_message_t state);
+	int (*resume_pre)(struct platform_device *pdev);
+	int (*resume_post)(struct platform_device *pdev);
+
+	/* CPU <--> Codec DAI links  */
+	struct snd_soc_dai_link *dai_link;
+	int num_links;
+};
+
+/* SoC Device - the audio subsystem */
+struct snd_soc_device {
+	struct device *dev;
+	struct snd_soc_machine *machine;
+	struct snd_soc_platform *platform;
+	struct snd_soc_codec *codec;
+	struct snd_soc_codec_device *codec_dev;
+	struct delayed_work delayed_work;
+	void *codec_data;
+};
+
+/* runtime channel data */
+struct snd_soc_pcm_runtime {
+	struct snd_soc_dai_link *dai;
+	struct snd_soc_device *socdev;
+};
+
+/* enumerated kcontrol */
+struct soc_enum {
+	unsigned short reg;
+	unsigned short reg2;
+	unsigned char shift_l;
+	unsigned char shift_r;
+	unsigned int mask;
+	const char **texts;
+	void *dapm;
+};
+
+#endif
diff --git a/include/sound/typedefs.h b/include/sound/typedefs.h
deleted file mode 100644
index f454b02..0000000
--- a/include/sound/typedefs.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Typedef's for backward compatibility (for out-of-kernel drivers)
- *
- * This file will be removed soon in future
- */
-
-/* core stuff */
-typedef struct snd_card snd_card_t;
-typedef struct snd_device snd_device_t;
-typedef struct snd_device_ops snd_device_ops_t;
-typedef enum snd_card_type snd_card_type_t;
-typedef struct snd_minor snd_minor_t;
-
-/* info */
-typedef struct snd_info_entry snd_info_entry_t;
-typedef struct snd_info_buffer snd_info_buffer_t;
-
-/* control */
-typedef struct snd_ctl_file snd_ctl_file_t;
-typedef struct snd_kcontrol snd_kcontrol_t;
-typedef struct snd_kcontrol_new snd_kcontrol_new_t;
-typedef struct snd_kcontrol_volatile snd_kcontrol_volatile_t;
-typedef struct snd_kctl_event snd_kctl_event_t;
-typedef struct snd_aes_iec958 snd_aes_iec958_t;
-typedef struct snd_ctl_card_info snd_ctl_card_info_t;
-typedef struct snd_ctl_elem_id snd_ctl_elem_id_t;
-typedef struct snd_ctl_elem_list snd_ctl_elem_list_t;
-typedef struct snd_ctl_elem_info snd_ctl_elem_info_t;
-typedef struct snd_ctl_elem_value snd_ctl_elem_value_t;
-typedef struct snd_ctl_event snd_ctl_event_t;
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
-typedef struct snd_mixer_oss snd_mixer_oss_t;
-#endif
-
-/* timer */
-typedef struct snd_timer snd_timer_t;
-typedef struct snd_timer_instance snd_timer_instance_t;
-typedef struct snd_timer_id snd_timer_id_t;
-typedef struct snd_timer_ginfo snd_timer_ginfo_t;
-typedef struct snd_timer_gparams snd_timer_gparams_t;
-typedef struct snd_timer_gstatus snd_timer_gstatus_t;
-typedef struct snd_timer_select snd_timer_select_t;
-typedef struct snd_timer_info snd_timer_info_t;
-typedef struct snd_timer_params snd_timer_params_t;
-typedef struct snd_timer_status snd_timer_status_t;
-typedef struct snd_timer_read snd_timer_read_t;
-typedef struct snd_timer_tread snd_timer_tread_t;
-
-/* PCM */
-typedef struct snd_pcm snd_pcm_t;
-typedef struct snd_pcm_str snd_pcm_str_t;
-typedef struct snd_pcm_substream snd_pcm_substream_t;
-typedef struct snd_pcm_info snd_pcm_info_t;
-typedef struct snd_pcm_hw_params snd_pcm_hw_params_t;
-typedef struct snd_pcm_sw_params snd_pcm_sw_params_t;
-typedef struct snd_pcm_channel_info snd_pcm_channel_info_t;
-typedef struct snd_pcm_status snd_pcm_status_t;
-typedef struct snd_pcm_mmap_status snd_pcm_mmap_status_t;
-typedef struct snd_pcm_mmap_control snd_pcm_mmap_control_t;
-typedef struct snd_mask snd_mask_t;
-typedef struct snd_sg_buf snd_pcm_sgbuf_t;
-
-typedef struct snd_interval snd_interval_t;
-typedef struct snd_xferi snd_xferi_t;
-typedef struct snd_xfern snd_xfern_t;
-typedef struct snd_xferv snd_xferv_t;
-
-typedef struct snd_pcm_file snd_pcm_file_t;
-typedef struct snd_pcm_runtime snd_pcm_runtime_t;
-typedef struct snd_pcm_hardware snd_pcm_hardware_t;
-typedef struct snd_pcm_ops snd_pcm_ops_t;
-typedef struct snd_pcm_hw_rule snd_pcm_hw_rule_t;
-typedef struct snd_pcm_hw_constraints snd_pcm_hw_constraints_t;
-typedef struct snd_ratnum ratnum_t;
-typedef struct snd_ratden ratden_t;
-typedef struct snd_pcm_hw_constraint_ratnums snd_pcm_hw_constraint_ratnums_t;
-typedef struct snd_pcm_hw_constraint_ratdens snd_pcm_hw_constraint_ratdens_t;
-typedef struct snd_pcm_hw_constraint_list snd_pcm_hw_constraint_list_t;
-typedef struct snd_pcm_group snd_pcm_group_t;
-typedef struct snd_pcm_notify snd_pcm_notify_t;
-
-/* rawmidi */
-typedef struct snd_rawmidi snd_rawmidi_t;
-typedef struct snd_rawmidi_info snd_rawmidi_info_t;
-typedef struct snd_rawmidi_params snd_rawmidi_params_t;
-typedef struct snd_rawmidi_status snd_rawmidi_status_t;
-typedef struct snd_rawmidi_runtime snd_rawmidi_runtime_t;
-typedef struct snd_rawmidi_substream snd_rawmidi_substream_t;
-typedef struct snd_rawmidi_str snd_rawmidi_str_t;
-typedef struct snd_rawmidi_ops snd_rawmidi_ops_t;
-typedef struct snd_rawmidi_global_ops snd_rawmidi_global_ops_t;
-typedef struct snd_rawmidi_file snd_rawmidi_file_t;
-
-/* hwdep */
-typedef struct snd_hwdep snd_hwdep_t;
-typedef struct snd_hwdep_info snd_hwdep_info_t;
-typedef struct snd_hwdep_dsp_status snd_hwdep_dsp_status_t;
-typedef struct snd_hwdep_dsp_image snd_hwdep_dsp_image_t;
-typedef struct snd_hwdep_ops snd_hwdep_ops_t;
-
-/* sequencer */
-typedef struct snd_seq_port_info snd_seq_port_info_t;
-typedef struct snd_seq_port_subscribe snd_seq_port_subscribe_t;
-typedef struct snd_seq_event snd_seq_event_t;
-typedef struct snd_seq_addr snd_seq_addr_t;
-typedef struct snd_seq_ev_volume snd_seq_ev_volume_t;
-typedef struct snd_seq_ev_loop snd_seq_ev_loop_t;
-typedef struct snd_seq_remove_events snd_seq_remove_events_t;
-typedef struct snd_seq_query_subs snd_seq_query_subs_t;
-typedef struct snd_seq_system_info snd_seq_system_info_t;
-typedef struct snd_seq_client_info snd_seq_client_info_t;
-typedef struct snd_seq_queue_info snd_seq_queue_info_t;
-typedef struct snd_seq_queue_status snd_seq_queue_status_t;
-typedef struct snd_seq_queue_tempo snd_seq_queue_tempo_t;
-typedef struct snd_seq_queue_owner snd_seq_queue_owner_t;
-typedef struct snd_seq_queue_timer snd_seq_queue_timer_t;
-typedef struct snd_seq_queue_client snd_seq_queue_client_t;
-typedef struct snd_seq_client_pool snd_seq_client_pool_t;
-typedef struct snd_seq_instr snd_seq_instr_t;
-typedef struct snd_seq_instr_data snd_seq_instr_data_t;
-typedef struct snd_seq_instr_header snd_seq_instr_header_t;
-
-typedef struct snd_seq_user_client user_client_t;
-typedef struct snd_seq_kernel_client kernel_client_t;
-typedef struct snd_seq_client client_t;
-typedef struct snd_seq_queue queue_t;
-
-/* seq_device */
-typedef struct snd_seq_device snd_seq_device_t;
-typedef struct snd_seq_dev_ops snd_seq_dev_ops_t;
-
-/* seq_midi */
-typedef struct snd_midi_event snd_midi_event_t;
-
-/* seq_midi_emul */
-typedef struct snd_midi_channel snd_midi_channel_t;
-typedef struct snd_midi_channel_set snd_midi_channel_set_t;
-typedef struct snd_midi_op snd_midi_op_t;
-
-/* seq_oss */
-typedef struct snd_seq_oss_arg snd_seq_oss_arg_t;
-typedef struct snd_seq_oss_callback snd_seq_oss_callback_t;
-typedef struct snd_seq_oss_reg snd_seq_oss_reg_t;
-
-/* virmidi */
-typedef struct snd_virmidi_dev snd_virmidi_dev_t;
-typedef struct snd_virmidi snd_virmidi_t;
-
-/* seq_instr */
-typedef struct snd_seq_kcluster snd_seq_kcluster_t;
-typedef struct snd_seq_kinstr_ops snd_seq_kinstr_ops_t;
-typedef struct snd_seq_kinstr snd_seq_kinstr_t;
-typedef struct snd_seq_kinstr_list snd_seq_kinstr_list_t;
-
-/* ac97 */
-typedef struct snd_ac97_bus ac97_bus_t;
-typedef struct snd_ac97_bus_ops ac97_bus_ops_t;
-typedef struct snd_ac97_template ac97_template_t;
-typedef struct snd_ac97 ac97_t;
-
-/* opl3/4 */
-typedef struct snd_opl3 opl3_t;
-typedef struct snd_opl4 opl4_t;
-
-/* mpu401 */
-typedef struct snd_mpu401 mpu401_t;
-
-/* i2c */
-typedef struct snd_i2c_device snd_i2c_device_t;
-typedef struct snd_i2c_bus snd_i2c_bus_t;
-
-typedef struct snd_ak4531 ak4531_t;
-
diff --git a/include/sound/version.h b/include/sound/version.h
index 20f7bab..c39b380 100644
--- a/include/sound/version.h
+++ b/include/sound/version.h
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by alsa/ksync script.  */
-#define CONFIG_SND_VERSION "1.0.14rc1"
-#define CONFIG_SND_DATE " (Tue Jan 09 09:56:17 2007 UTC)"
+#define CONFIG_SND_VERSION "1.0.14rc2"
+#define CONFIG_SND_DATE " (Fri Feb 09 13:50:10 2007 UTC)"
diff --git a/include/sound/vx_core.h b/include/sound/vx_core.h
index 2173946..4830651 100644
--- a/include/sound/vx_core.h
+++ b/include/sound/vx_core.h
@@ -128,7 +128,7 @@
 	unsigned int num_ins;
 	unsigned int num_outs;
 	unsigned int output_level_max;
-	unsigned int *output_level_db_scale;
+	const unsigned int *output_level_db_scale;
 };
 
 /* hwdep id string */
diff --git a/include/sound/ymfpci.h b/include/sound/ymfpci.h
index f3514ee..203d2b4 100644
--- a/include/sound/ymfpci.h
+++ b/include/sound/ymfpci.h
@@ -270,6 +270,7 @@
 	struct snd_pcm_substream *substream;
 	struct snd_ymfpci_voice *voices[2];	/* playback only */
 	unsigned int running: 1,
+		     use_441_slot: 1,
 	             output_front: 1,
 	             output_rear: 1,
 	             swap_rear: 1;
@@ -324,6 +325,7 @@
 
 	u32 active_bank;
 	struct snd_ymfpci_voice voices[64];
+	int src441_used;
 
 	struct snd_ac97_bus *ac97_bus;
 	struct snd_ac97 *ac97;
@@ -346,7 +348,7 @@
 	int mode_dup4ch;
 	int rear_opened;
 	int spdif_opened;
-	struct {
+	struct snd_ymfpci_pcm_mixer {
 		u16 left;
 		u16 right;
 		struct snd_kcontrol *ctl;
@@ -357,6 +359,8 @@
 	wait_queue_head_t interrupt_sleep;
 	atomic_t interrupt_sleep_count;
 	struct snd_info_entry *proc_entry;
+	const struct firmware *dsp_microcode;
+	const struct firmware *controller_microcode;
 
 #ifdef CONFIG_PM
 	u32 *saved_regs;
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index d27b258..475e8a7 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -39,6 +39,7 @@
 	desc->chip = &no_irq_chip;
 	desc->handle_irq = handle_bad_irq;
 	desc->depth = 1;
+	desc->msi_desc = NULL;
 	desc->handler_data = NULL;
 	desc->chip_data = NULL;
 	desc->action = NULL;
@@ -74,6 +75,9 @@
 		WARN_ON(1);
 		return;
 	}
+	desc->msi_desc = NULL;
+	desc->handler_data = NULL;
+	desc->chip_data = NULL;
 	desc->handle_irq = handle_bad_irq;
 	desc->chip = &no_irq_chip;
 	spin_unlock_irqrestore(&desc->lock, flags);
@@ -162,6 +166,30 @@
 EXPORT_SYMBOL(set_irq_data);
 
 /**
+ *	set_irq_data - set irq type data for an irq
+ *	@irq:	Interrupt number
+ *	@data:	Pointer to interrupt specific data
+ *
+ *	Set the hardware irq controller data for an irq
+ */
+int set_irq_msi(unsigned int irq, struct msi_desc *entry)
+{
+	struct irq_desc *desc;
+	unsigned long flags;
+
+	if (irq >= NR_IRQS) {
+		printk(KERN_ERR
+		       "Trying to install msi data for IRQ%d\n", irq);
+		return -EINVAL;
+	}
+	desc = irq_desc + irq;
+	spin_lock_irqsave(&desc->lock, flags);
+	desc->msi_desc = entry;
+	spin_unlock_irqrestore(&desc->lock, flags);
+	return 0;
+}
+
+/**
  *	set_irq_chip_data - set irq chip data for an irq
  *	@irq:	Interrupt number
  *	@data:	Pointer to chip specific data
diff --git a/kernel/module.c b/kernel/module.c
index d0f2260..8a94e05 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -537,6 +537,8 @@
 static int use_module(struct module *a, struct module *b)
 {
 	struct module_use *use;
+	int no_warn;
+
 	if (b == NULL || already_uses(a, b)) return 1;
 
 	if (!strong_try_module_get(b))
@@ -552,6 +554,7 @@
 
 	use->module_which_uses = a;
 	list_add(&use->list, &b->modules_which_use_me);
+	no_warn = sysfs_create_link(b->holders_dir, &a->mkobj.kobj, a->name);
 	return 1;
 }
 
@@ -569,6 +572,7 @@
 				module_put(i);
 				list_del(&use->list);
 				kfree(use);
+				sysfs_remove_link(i->holders_dir, mod->name);
 				/* There can be at most one match. */
 				break;
 			}
@@ -1106,9 +1110,7 @@
 	kfree(mod->modinfo_attrs);
 }
 
-static int mod_sysfs_setup(struct module *mod,
-			   struct kernel_param *kparam,
-			   unsigned int num_params)
+static int mod_sysfs_init(struct module *mod)
 {
 	int err;
 
@@ -1125,21 +1127,30 @@
 	kobj_set_kset_s(&mod->mkobj, module_subsys);
 	mod->mkobj.mod = mod;
 
-	/* delay uevent until full sysfs population */
 	kobject_init(&mod->mkobj.kobj);
+
+out:
+	return err;
+}
+
+static int mod_sysfs_setup(struct module *mod,
+			   struct kernel_param *kparam,
+			   unsigned int num_params)
+{
+	int err;
+
+	/* delay uevent until full sysfs population */
 	err = kobject_add(&mod->mkobj.kobj);
 	if (err)
 		goto out;
 
-	mod->drivers_dir = kobject_add_dir(&mod->mkobj.kobj, "drivers");
-	if (!mod->drivers_dir) {
-		err = -ENOMEM;
+	mod->holders_dir = kobject_add_dir(&mod->mkobj.kobj, "holders");
+	if (!mod->holders_dir)
 		goto out_unreg;
-	}
 
 	err = module_param_sysfs_setup(mod, kparam, num_params);
 	if (err)
-		goto out_unreg_drivers;
+		goto out_unreg_holders;
 
 	err = module_add_modinfo_attrs(mod);
 	if (err)
@@ -1150,8 +1161,8 @@
 
 out_unreg_param:
 	module_param_sysfs_remove(mod);
-out_unreg_drivers:
-	kobject_unregister(mod->drivers_dir);
+out_unreg_holders:
+	kobject_unregister(mod->holders_dir);
 out_unreg:
 	kobject_del(&mod->mkobj.kobj);
 	kobject_put(&mod->mkobj.kobj);
@@ -1163,7 +1174,10 @@
 {
 	module_remove_modinfo_attrs(mod);
 	module_param_sysfs_remove(mod);
-	kobject_unregister(mod->drivers_dir);
+	if (mod->mkobj.drivers_dir)
+		kobject_unregister(mod->mkobj.drivers_dir);
+	if (mod->holders_dir)
+		kobject_unregister(mod->holders_dir);
 
 	kobject_unregister(&mod->mkobj.kobj);
 }
@@ -1768,6 +1782,10 @@
 	/* Now we've moved module, initialize linked lists, etc. */
 	module_unload_init(mod);
 
+	/* Initialize kobject, so we can reference it. */
+	if (mod_sysfs_init(mod) != 0)
+		goto cleanup;
+
 	/* Set up license info based on the info section */
 	set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
 
@@ -2340,19 +2358,43 @@
 	return driver_name;
 }
 
+static void module_create_drivers_dir(struct module_kobject *mk)
+{
+	if (!mk || mk->drivers_dir)
+		return;
+
+	mk->drivers_dir = kobject_add_dir(&mk->kobj, "drivers");
+}
+
 void module_add_driver(struct module *mod, struct device_driver *drv)
 {
 	char *driver_name;
 	int no_warn;
+	struct module_kobject *mk = NULL;
 
-	if (!mod || !drv)
+	if (!drv)
+		return;
+
+	if (mod)
+		mk = &mod->mkobj;
+	else if (drv->mod_name) {
+		struct kobject *mkobj;
+
+		/* Lookup built-in module entry in /sys/modules */
+		mkobj = kset_find_obj(&module_subsys.kset, drv->mod_name);
+		if (mkobj)
+			mk = container_of(mkobj, struct module_kobject, kobj);
+	}
+
+	if (!mk)
 		return;
 
 	/* Don't check return codes; these calls are idempotent */
-	no_warn = sysfs_create_link(&drv->kobj, &mod->mkobj.kobj, "module");
+	no_warn = sysfs_create_link(&drv->kobj, &mk->kobj, "module");
 	driver_name = make_driver_name(drv);
 	if (driver_name) {
-		no_warn = sysfs_create_link(mod->drivers_dir, &drv->kobj,
+		module_create_drivers_dir(mk);
+		no_warn = sysfs_create_link(mk->drivers_dir, &drv->kobj,
 					    driver_name);
 		kfree(driver_name);
 	}
@@ -2367,10 +2409,10 @@
 		return;
 
 	sysfs_remove_link(&drv->kobj, "module");
-	if (drv->owner && drv->owner->drivers_dir) {
+	if (drv->owner && drv->owner->mkobj.drivers_dir) {
 		driver_name = make_driver_name(drv);
 		if (driver_name) {
-			sysfs_remove_link(drv->owner->drivers_dir,
+			sysfs_remove_link(drv->owner->mkobj.drivers_dir,
 					  driver_name);
 			kfree(driver_name);
 		}
diff --git a/kernel/params.c b/kernel/params.c
index 718945d..553cf7d 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -30,6 +30,8 @@
 #define DEBUGP(fmt, a...)
 #endif
 
+static struct kobj_type module_ktype;
+
 static inline char dash2underscore(char c)
 {
 	if (c == '-')
@@ -561,14 +563,11 @@
 	mk->mod = THIS_MODULE;
 	kobj_set_kset_s(mk, module_subsys);
 	kobject_set_name(&mk->kobj, name);
-	ret = kobject_register(&mk->kobj);
+	kobject_init(&mk->kobj);
+	ret = kobject_add(&mk->kobj);
 	BUG_ON(ret < 0);
-
-	/* no need to keep the kobject if no parameter is exported */
-	if (!param_sysfs_setup(mk, kparam, num_params, name_skip)) {
-		kobject_unregister(&mk->kobj);
-		kfree(mk);
-	}
+	param_sysfs_setup(mk, kparam, num_params, name_skip);
+	kobject_uevent(&mk->kobj, KOBJ_ADD);
 }
 
 /*
@@ -674,6 +673,19 @@
 	.store = module_attr_store,
 };
 
+static int uevent_filter(struct kset *kset, struct kobject *kobj)
+{
+	struct kobj_type *ktype = get_ktype(kobj);
+
+	if (ktype == &module_ktype)
+		return 1;
+	return 0;
+}
+
+static struct kset_uevent_ops module_uevent_ops = {
+	.filter = uevent_filter,
+};
+
 #else
 static struct sysfs_ops module_sysfs_ops = {
 	.show = NULL,
@@ -685,7 +697,7 @@
 	.sysfs_ops =	&module_sysfs_ops,
 };
 
-decl_subsys(module, &module_ktype, NULL);
+decl_subsys(module, &module_ktype, &module_uevent_ops);
 
 /*
  * param_sysfs_init - wrapper for built-in params support
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index ed29622..95f6657 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -131,3 +131,29 @@
 	bool
 	depends on HOTPLUG_CPU && X86 && PM
 	default y
+
+config APM_EMULATION
+	tristate "Advanced Power Management Emulation"
+	depends on PM && SYS_SUPPORTS_APM_EMULATION
+	help
+	  APM is a BIOS specification for saving power using several different
+	  techniques. This is mostly useful for battery powered laptops with
+	  APM compliant BIOSes. If you say Y here, the system time will be
+	  reset after a RESUME operation, the /proc/apm device will provide
+	  battery status information, and user-space programs will receive
+	  notification of APM "events" (e.g. battery status change).
+
+	  In order to use APM, you will need supporting software. For location
+	  and more information, read <file:Documentation/pm.txt> and the
+	  Battery Powered Linux mini-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  This driver does not spin down disk drives (see the hdparm(8)
+	  manpage ("man 8 hdparm") for that), and it doesn't turn off
+	  VESA-compliant "green" monitors.
+
+	  Generally, if you don't have a battery in your machine, there isn't
+	  much point in using this driver and you should say N. If you get
+	  random kernel OOPSes or reboots that don't seem to be related to
+	  anything, try disabling/enabling this option (or disabling/enabling
+	  APM in your BIOS).
diff --git a/lib/kobject.c b/lib/kobject.c
index 7ce6dc1..c2917ffe 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -44,11 +44,11 @@
 	return error;
 }
 
-static int create_dir(struct kobject * kobj)
+static int create_dir(struct kobject * kobj, struct dentry *shadow_parent)
 {
 	int error = 0;
 	if (kobject_name(kobj)) {
-		error = sysfs_create_dir(kobj);
+		error = sysfs_create_dir(kobj, shadow_parent);
 		if (!error) {
 			if ((error = populate_dir(kobj)))
 				sysfs_remove_dir(kobj);
@@ -126,6 +126,8 @@
  */
 void kobject_init(struct kobject * kobj)
 {
+	if (!kobj)
+		return;
 	kref_init(&kobj->kref);
 	INIT_LIST_HEAD(&kobj->entry);
 	init_waitqueue_head(&kobj->poll);
@@ -156,9 +158,10 @@
 /**
  *	kobject_add - add an object to the hierarchy.
  *	@kobj:	object.
+ *	@shadow_parent: sysfs directory to add to.
  */
 
-int kobject_add(struct kobject * kobj)
+int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent)
 {
 	int error = 0;
 	struct kobject * parent;
@@ -189,12 +192,11 @@
 	}
 	kobj->parent = parent;
 
-	error = create_dir(kobj);
+	error = create_dir(kobj, shadow_parent);
 	if (error) {
 		/* unlink does the kobject_put() for us */
 		unlink(kobj);
-		if (parent)
-			kobject_put(parent);
+		kobject_put(parent);
 
 		/* be noisy on error issues */
 		if (error == -EEXIST)
@@ -211,6 +213,15 @@
 	return error;
 }
 
+/**
+ *	kobject_add - add an object to the hierarchy.
+ *	@kobj:	object.
+ */
+int kobject_add(struct kobject * kobj)
+{
+	return kobject_shadow_add(kobj, NULL);
+}
+
 
 /**
  *	kobject_register - initialize and add an object.
@@ -303,7 +314,29 @@
 	kobj = kobject_get(kobj);
 	if (!kobj)
 		return -EINVAL;
-	error = sysfs_rename_dir(kobj, new_name);
+	if (!kobj->parent)
+		return -EINVAL;
+	error = sysfs_rename_dir(kobj, kobj->parent->dentry, new_name);
+	kobject_put(kobj);
+
+	return error;
+}
+
+/**
+ *	kobject_rename - change the name of an object
+ *	@kobj:	object in question.
+ *	@new_name: object's new name
+ */
+
+int kobject_shadow_rename(struct kobject * kobj, struct dentry *new_parent,
+			  const char *new_name)
+{
+	int error = 0;
+
+	kobj = kobject_get(kobj);
+	if (!kobj)
+		return -EINVAL;
+	error = sysfs_rename_dir(kobj, new_parent, new_name);
 	kobject_put(kobj);
 
 	return error;
@@ -312,7 +345,7 @@
 /**
  *	kobject_move - move object to another parent
  *	@kobj:	object in question.
- *	@new_parent: object's new parent
+ *	@new_parent: object's new parent (can be NULL)
  */
 
 int kobject_move(struct kobject *kobj, struct kobject *new_parent)
@@ -328,8 +361,8 @@
 		return -EINVAL;
 	new_parent = kobject_get(new_parent);
 	if (!new_parent) {
-		error = -EINVAL;
-		goto out;
+		if (kobj->kset)
+			new_parent = kobject_get(&kobj->kset->kobj);
 	}
 	/* old object path */
 	devpath = kobject_get_path(kobj, GFP_KERNEL);
@@ -366,6 +399,8 @@
 
 void kobject_del(struct kobject * kobj)
 {
+	if (!kobj)
+		return;
 	sysfs_remove_dir(kobj);
 	unlink(kobj);
 }
@@ -377,6 +412,8 @@
 
 void kobject_unregister(struct kobject * kobj)
 {
+	if (!kobj)
+		return;
 	pr_debug("kobject %s: unregistering\n",kobject_name(kobj));
 	kobject_uevent(kobj, KOBJ_REMOVE);
 	kobject_del(kobj);
@@ -414,8 +451,7 @@
 		t->release(kobj);
 	if (s)
 		kset_put(s);
-	if (parent) 
-		kobject_put(parent);
+	kobject_put(parent);
 }
 
 static void kobject_release(struct kref *kref)
@@ -523,6 +559,8 @@
 
 int kset_register(struct kset * k)
 {
+	if (!k)
+		return -EINVAL;
 	kset_init(k);
 	return kset_add(k);
 }
@@ -535,6 +573,8 @@
 
 void kset_unregister(struct kset * k)
 {
+	if (!k)
+		return;
 	kobject_unregister(&k->kobj);
 }
 
@@ -586,6 +626,9 @@
 {
 	int error;
 
+	if (!s)
+		return -EINVAL;
+
 	subsystem_init(s);
 	pr_debug("subsystem %s: registering\n",s->kset.kobj.name);
 
@@ -598,6 +641,8 @@
 
 void subsystem_unregister(struct subsystem * s)
 {
+	if (!s)
+		return;
 	pr_debug("subsystem %s: unregistering\n",s->kset.kobj.name);
 	kset_unregister(&s->kset);
 }
@@ -612,6 +657,10 @@
 int subsys_create_file(struct subsystem * s, struct subsys_attribute * a)
 {
 	int error = 0;
+
+	if (!s || !a)
+		return -EINVAL;
+
 	if (subsys_get(s)) {
 		error = sysfs_create_file(&s->kset.kobj,&a->attr);
 		subsys_put(s);
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index 1062578..50a4380 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -1,7 +1,7 @@
 /*
  * Dynamic DMA mapping support.
  *
- * This implementation is for IA-64 and EM64T platforms that do not support
+ * This implementation is a fallback for platforms that do not support
  * I/O TLBs (aka DMA address translation hardware).
  * Copyright (C) 2000 Asit Mallick <Asit.K.Mallick@intel.com>
  * Copyright (C) 2000 Goutham Rao <goutham.rao@intel.com>
@@ -28,6 +28,7 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/scatterlist.h>
+#include <asm/swiotlb.h>
 
 #include <linux/init.h>
 #include <linux/bootmem.h>
@@ -35,8 +36,10 @@
 #define OFFSET(val,align) ((unsigned long)	\
 	                   ( (val) & ( (align) - 1)))
 
+#ifndef SG_ENT_VIRT_ADDRESS
 #define SG_ENT_VIRT_ADDRESS(sg)	(page_address((sg)->page) + (sg)->offset)
-#define SG_ENT_PHYS_ADDRESS(SG)	virt_to_phys(SG_ENT_VIRT_ADDRESS(SG))
+#define SG_ENT_PHYS_ADDRESS(sg)	virt_to_bus(SG_ENT_VIRT_ADDRESS(sg))
+#endif
 
 /*
  * Maximum allowable number of contiguous slabs to map,
@@ -101,13 +104,25 @@
  * We need to save away the original address corresponding to a mapped entry
  * for the sync operations.
  */
-static unsigned char **io_tlb_orig_addr;
+#ifndef SWIOTLB_ARCH_HAS_IO_TLB_ADDR_T
+typedef char *io_tlb_addr_t;
+#define swiotlb_orig_addr_null(buffer) (!(buffer))
+#define ptr_to_io_tlb_addr(ptr) (ptr)
+#define page_to_io_tlb_addr(pg, off) (page_address(pg) + (off))
+#define sg_to_io_tlb_addr(sg) SG_ENT_VIRT_ADDRESS(sg)
+#endif
+static io_tlb_addr_t *io_tlb_orig_addr;
 
 /*
  * Protect the above data structures in the map and unmap calls
  */
 static DEFINE_SPINLOCK(io_tlb_lock);
 
+#ifdef SWIOTLB_EXTRA_VARIABLES
+SWIOTLB_EXTRA_VARIABLES;
+#endif
+
+#ifndef SWIOTLB_ARCH_HAS_SETUP_IO_TLB_NPAGES
 static int __init
 setup_io_tlb_npages(char *str)
 {
@@ -122,30 +137,50 @@
 		swiotlb_force = 1;
 	return 1;
 }
+#endif
 __setup("swiotlb=", setup_io_tlb_npages);
 /* make io_tlb_overflow tunable too? */
 
+#ifndef swiotlb_adjust_size
+#define swiotlb_adjust_size(size) ((void)0)
+#endif
+
+#ifndef swiotlb_adjust_seg
+#define swiotlb_adjust_seg(start, size) ((void)0)
+#endif
+
+#ifndef swiotlb_print_info
+#define swiotlb_print_info(bytes) \
+	printk(KERN_INFO "Placing %luMB software IO TLB between 0x%lx - " \
+	       "0x%lx\n", bytes >> 20, \
+	       virt_to_bus(io_tlb_start), virt_to_bus(io_tlb_end))
+#endif
+
 /*
  * Statically reserve bounce buffer space and initialize bounce buffer data
  * structures for the software IO TLB used to implement the DMA API.
  */
-void
-swiotlb_init_with_default_size (size_t default_size)
+void __init
+swiotlb_init_with_default_size(size_t default_size)
 {
-	unsigned long i;
+	unsigned long i, bytes;
 
 	if (!io_tlb_nslabs) {
 		io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
 		io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
 	}
+	swiotlb_adjust_size(io_tlb_nslabs);
+	swiotlb_adjust_size(io_tlb_overflow);
+
+	bytes = io_tlb_nslabs << IO_TLB_SHIFT;
 
 	/*
 	 * Get IO TLB memory from the low pages
 	 */
-	io_tlb_start = alloc_bootmem_low_pages(io_tlb_nslabs * (1 << IO_TLB_SHIFT));
+	io_tlb_start = alloc_bootmem_low_pages(bytes);
 	if (!io_tlb_start)
 		panic("Cannot allocate SWIOTLB buffer");
-	io_tlb_end = io_tlb_start + io_tlb_nslabs * (1 << IO_TLB_SHIFT);
+	io_tlb_end = io_tlb_start + bytes;
 
 	/*
 	 * Allocate and initialize the free list array.  This array is used
@@ -153,34 +188,45 @@
 	 * between io_tlb_start and io_tlb_end.
 	 */
 	io_tlb_list = alloc_bootmem(io_tlb_nslabs * sizeof(int));
-	for (i = 0; i < io_tlb_nslabs; i++)
+	for (i = 0; i < io_tlb_nslabs; i++) {
+		if ( !(i % IO_TLB_SEGSIZE) )
+			swiotlb_adjust_seg(io_tlb_start + (i << IO_TLB_SHIFT),
+				IO_TLB_SEGSIZE << IO_TLB_SHIFT);
  		io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
+ 	}
 	io_tlb_index = 0;
-	io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(char *));
+	io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(io_tlb_addr_t));
 
 	/*
 	 * Get the overflow emergency buffer
 	 */
 	io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow);
-	printk(KERN_INFO "Placing software IO TLB between 0x%lx - 0x%lx\n",
-	       virt_to_phys(io_tlb_start), virt_to_phys(io_tlb_end));
-}
+	if (!io_tlb_overflow_buffer)
+		panic("Cannot allocate SWIOTLB overflow buffer!\n");
+	swiotlb_adjust_seg(io_tlb_overflow_buffer, io_tlb_overflow);
 
-void
-swiotlb_init (void)
+	swiotlb_print_info(bytes);
+}
+#ifndef __swiotlb_init_with_default_size
+#define __swiotlb_init_with_default_size swiotlb_init_with_default_size
+#endif
+
+void __init
+swiotlb_init(void)
 {
-	swiotlb_init_with_default_size(64 * (1<<20));	/* default to 64MB */
+	__swiotlb_init_with_default_size(64 * (1<<20)); /* default to 64MB */
 }
 
+#ifdef SWIOTLB_ARCH_NEED_LATE_INIT
 /*
  * Systems with larger DMA zones (those that don't support ISA) can
  * initialize the swiotlb later using the slab allocator if needed.
  * This should be just like above, but with some error catching.
  */
 int
-swiotlb_late_init_with_default_size (size_t default_size)
+swiotlb_late_init_with_default_size(size_t default_size)
 {
-	unsigned long i, req_nslabs = io_tlb_nslabs;
+	unsigned long i, bytes, req_nslabs = io_tlb_nslabs;
 	unsigned int order;
 
 	if (!io_tlb_nslabs) {
@@ -191,8 +237,9 @@
 	/*
 	 * Get IO TLB memory from the low pages
 	 */
-	order = get_order(io_tlb_nslabs * (1 << IO_TLB_SHIFT));
+	order = get_order(io_tlb_nslabs << IO_TLB_SHIFT);
 	io_tlb_nslabs = SLABS_PER_PAGE << order;
+	bytes = io_tlb_nslabs << IO_TLB_SHIFT;
 
 	while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
 		io_tlb_start = (char *)__get_free_pages(GFP_DMA | __GFP_NOWARN,
@@ -205,13 +252,14 @@
 	if (!io_tlb_start)
 		goto cleanup1;
 
-	if (order != get_order(io_tlb_nslabs * (1 << IO_TLB_SHIFT))) {
+	if (order != get_order(bytes)) {
 		printk(KERN_WARNING "Warning: only able to allocate %ld MB "
 		       "for software IO TLB\n", (PAGE_SIZE << order) >> 20);
 		io_tlb_nslabs = SLABS_PER_PAGE << order;
+		bytes = io_tlb_nslabs << IO_TLB_SHIFT;
 	}
-	io_tlb_end = io_tlb_start + io_tlb_nslabs * (1 << IO_TLB_SHIFT);
-	memset(io_tlb_start, 0, io_tlb_nslabs * (1 << IO_TLB_SHIFT));
+	io_tlb_end = io_tlb_start + bytes;
+	memset(io_tlb_start, 0, bytes);
 
 	/*
 	 * Allocate and initialize the free list array.  This array is used
@@ -227,12 +275,12 @@
  		io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
 	io_tlb_index = 0;
 
-	io_tlb_orig_addr = (unsigned char **)__get_free_pages(GFP_KERNEL,
-	                           get_order(io_tlb_nslabs * sizeof(char *)));
+	io_tlb_orig_addr = (io_tlb_addr_t *)__get_free_pages(GFP_KERNEL,
+	                           get_order(io_tlb_nslabs * sizeof(io_tlb_addr_t)));
 	if (!io_tlb_orig_addr)
 		goto cleanup3;
 
-	memset(io_tlb_orig_addr, 0, io_tlb_nslabs * sizeof(char *));
+	memset(io_tlb_orig_addr, 0, io_tlb_nslabs * sizeof(io_tlb_addr_t));
 
 	/*
 	 * Get the overflow emergency buffer
@@ -242,29 +290,29 @@
 	if (!io_tlb_overflow_buffer)
 		goto cleanup4;
 
-	printk(KERN_INFO "Placing %ldMB software IO TLB between 0x%lx - "
-	       "0x%lx\n", (io_tlb_nslabs * (1 << IO_TLB_SHIFT)) >> 20,
-	       virt_to_phys(io_tlb_start), virt_to_phys(io_tlb_end));
+	swiotlb_print_info(bytes);
 
 	return 0;
 
 cleanup4:
-	free_pages((unsigned long)io_tlb_orig_addr, get_order(io_tlb_nslabs *
-	                                                      sizeof(char *)));
+	free_pages((unsigned long)io_tlb_orig_addr,
+		   get_order(io_tlb_nslabs * sizeof(io_tlb_addr_t)));
 	io_tlb_orig_addr = NULL;
 cleanup3:
-	free_pages((unsigned long)io_tlb_list, get_order(io_tlb_nslabs *
-	                                                 sizeof(int)));
+	free_pages((unsigned long)io_tlb_list,
+		   get_order(io_tlb_nslabs * sizeof(int)));
 	io_tlb_list = NULL;
-	io_tlb_end = NULL;
 cleanup2:
+	io_tlb_end = NULL;
 	free_pages((unsigned long)io_tlb_start, order);
 	io_tlb_start = NULL;
 cleanup1:
 	io_tlb_nslabs = req_nslabs;
 	return -ENOMEM;
 }
+#endif
 
+#ifndef SWIOTLB_ARCH_HAS_NEEDS_MAPPING
 static inline int
 address_needs_mapping(struct device *hwdev, dma_addr_t addr)
 {
@@ -275,11 +323,35 @@
 	return (addr & ~mask) != 0;
 }
 
+static inline int range_needs_mapping(const void *ptr, size_t size)
+{
+	return swiotlb_force;
+}
+
+static inline int order_needs_mapping(unsigned int order)
+{
+	return 0;
+}
+#endif
+
+static void
+__sync_single(io_tlb_addr_t buffer, char *dma_addr, size_t size, int dir)
+{
+#ifndef SWIOTLB_ARCH_HAS_SYNC_SINGLE
+	if (dir == DMA_TO_DEVICE)
+		memcpy(dma_addr, buffer, size);
+	else
+		memcpy(buffer, dma_addr, size);
+#else
+	__swiotlb_arch_sync_single(buffer, dma_addr, size, dir);
+#endif
+}
+
 /*
  * Allocates bounce buffer and returns its kernel virtual address.
  */
 static void *
-map_single(struct device *hwdev, char *buffer, size_t size, int dir)
+map_single(struct device *hwdev, io_tlb_addr_t buffer, size_t size, int dir)
 {
 	unsigned long flags;
 	char *dma_addr;
@@ -352,7 +424,7 @@
 	 */
 	io_tlb_orig_addr[index] = buffer;
 	if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)
-		memcpy(dma_addr, buffer, size);
+		__sync_single(buffer, dma_addr, size, DMA_TO_DEVICE);
 
 	return dma_addr;
 }
@@ -366,17 +438,18 @@
 	unsigned long flags;
 	int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
 	int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
-	char *buffer = io_tlb_orig_addr[index];
+	io_tlb_addr_t buffer = io_tlb_orig_addr[index];
 
 	/*
 	 * First, sync the memory before unmapping the entry
 	 */
-	if (buffer && ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)))
+	if (!swiotlb_orig_addr_null(buffer)
+	    && ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)))
 		/*
 		 * bounce... copy the data back into the original buffer * and
 		 * delete the bounce buffer.
 		 */
-		memcpy(buffer, dma_addr, size);
+		__sync_single(buffer, dma_addr, size, DMA_FROM_DEVICE);
 
 	/*
 	 * Return the buffer to the free list by setting the corresponding
@@ -409,18 +482,18 @@
 	    int dir, int target)
 {
 	int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
-	char *buffer = io_tlb_orig_addr[index];
+	io_tlb_addr_t buffer = io_tlb_orig_addr[index];
 
 	switch (target) {
 	case SYNC_FOR_CPU:
 		if (likely(dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL))
-			memcpy(buffer, dma_addr, size);
+			__sync_single(buffer, dma_addr, size, DMA_FROM_DEVICE);
 		else
 			BUG_ON(dir != DMA_TO_DEVICE);
 		break;
 	case SYNC_FOR_DEVICE:
 		if (likely(dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL))
-			memcpy(dma_addr, buffer, size);
+			__sync_single(buffer, dma_addr, size, DMA_TO_DEVICE);
 		else
 			BUG_ON(dir != DMA_FROM_DEVICE);
 		break;
@@ -429,11 +502,13 @@
 	}
 }
 
+#ifdef SWIOTLB_ARCH_NEED_ALLOC
+
 void *
 swiotlb_alloc_coherent(struct device *hwdev, size_t size,
 		       dma_addr_t *dma_handle, gfp_t flags)
 {
-	unsigned long dev_addr;
+	dma_addr_t dev_addr;
 	void *ret;
 	int order = get_order(size);
 
@@ -444,8 +519,11 @@
 	 */
 	flags |= GFP_DMA;
 
-	ret = (void *)__get_free_pages(flags, order);
-	if (ret && address_needs_mapping(hwdev, virt_to_phys(ret))) {
+	if (!order_needs_mapping(order))
+		ret = (void *)__get_free_pages(flags, order);
+	else
+		ret = NULL;
+	if (ret && address_needs_mapping(hwdev, virt_to_bus(ret))) {
 		/*
 		 * The allocated memory isn't reachable by the device.
 		 * Fall back on swiotlb_map_single().
@@ -465,22 +543,24 @@
 		if (swiotlb_dma_mapping_error(handle))
 			return NULL;
 
-		ret = phys_to_virt(handle);
+		ret = bus_to_virt(handle);
 	}
 
 	memset(ret, 0, size);
-	dev_addr = virt_to_phys(ret);
+	dev_addr = virt_to_bus(ret);
 
 	/* Confirm address can be DMA'd by device */
 	if (address_needs_mapping(hwdev, dev_addr)) {
-		printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016lx\n",
-		       (unsigned long long)*hwdev->dma_mask, dev_addr);
+		printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n",
+		       (unsigned long long)*hwdev->dma_mask,
+		       (unsigned long long)dev_addr);
 		panic("swiotlb_alloc_coherent: allocated memory is out of "
 		      "range for device");
 	}
 	*dma_handle = dev_addr;
 	return ret;
 }
+EXPORT_SYMBOL(swiotlb_alloc_coherent);
 
 void
 swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
@@ -493,6 +573,9 @@
 		/* DMA_TO_DEVICE to avoid memcpy in unmap_single */
 		swiotlb_unmap_single (hwdev, dma_handle, size, DMA_TO_DEVICE);
 }
+EXPORT_SYMBOL(swiotlb_free_coherent);
+
+#endif
 
 static void
 swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
@@ -504,7 +587,7 @@
 	 * When the mapping is small enough return a static buffer to limit
 	 * the damage, or panic when the transfer is too big.
 	 */
-	printk(KERN_ERR "DMA: Out of SW-IOMMU space for %lu bytes at "
+	printk(KERN_ERR "DMA: Out of SW-IOMMU space for %zu bytes at "
 	       "device %s\n", size, dev ? dev->bus_id : "?");
 
 	if (size > io_tlb_overflow && do_panic) {
@@ -525,7 +608,7 @@
 dma_addr_t
 swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir)
 {
-	unsigned long dev_addr = virt_to_phys(ptr);
+	dma_addr_t dev_addr = virt_to_bus(ptr);
 	void *map;
 
 	BUG_ON(dir == DMA_NONE);
@@ -534,19 +617,20 @@
 	 * we can safely return the device addr and not worry about bounce
 	 * buffering it.
 	 */
-	if (!address_needs_mapping(hwdev, dev_addr) && !swiotlb_force)
+	if (!range_needs_mapping(ptr, size)
+	    && !address_needs_mapping(hwdev, dev_addr))
 		return dev_addr;
 
 	/*
 	 * Oh well, have to allocate and map a bounce buffer.
 	 */
-	map = map_single(hwdev, ptr, size, dir);
+	map = map_single(hwdev, ptr_to_io_tlb_addr(ptr), size, dir);
 	if (!map) {
 		swiotlb_full(hwdev, size, dir, 1);
 		map = io_tlb_overflow_buffer;
 	}
 
-	dev_addr = virt_to_phys(map);
+	dev_addr = virt_to_bus(map);
 
 	/*
 	 * Ensure that the address returned is DMA'ble
@@ -558,25 +642,6 @@
 }
 
 /*
- * Since DMA is i-cache coherent, any (complete) pages that were written via
- * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to
- * flush them when they get mapped into an executable vm-area.
- */
-static void
-mark_clean(void *addr, size_t size)
-{
-	unsigned long pg_addr, end;
-
-	pg_addr = PAGE_ALIGN((unsigned long) addr);
-	end = (unsigned long) addr + size;
-	while (pg_addr + PAGE_SIZE <= end) {
-		struct page *page = virt_to_page(pg_addr);
-		set_bit(PG_arch_1, &page->flags);
-		pg_addr += PAGE_SIZE;
-	}
-}
-
-/*
  * Unmap a single streaming mode DMA translation.  The dma_addr and size must
  * match what was provided for in a previous swiotlb_map_single call.  All
  * other usages are undefined.
@@ -588,13 +653,13 @@
 swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr, size_t size,
 		     int dir)
 {
-	char *dma_addr = phys_to_virt(dev_addr);
+	char *dma_addr = bus_to_virt(dev_addr);
 
 	BUG_ON(dir == DMA_NONE);
 	if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
 		unmap_single(hwdev, dma_addr, size, dir);
 	else if (dir == DMA_FROM_DEVICE)
-		mark_clean(dma_addr, size);
+		dma_mark_clean(dma_addr, size);
 }
 
 /*
@@ -611,13 +676,13 @@
 swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,
 		    size_t size, int dir, int target)
 {
-	char *dma_addr = phys_to_virt(dev_addr);
+	char *dma_addr = bus_to_virt(dev_addr);
 
 	BUG_ON(dir == DMA_NONE);
 	if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
 		sync_single(hwdev, dma_addr, size, dir, target);
 	else if (dir == DMA_FROM_DEVICE)
-		mark_clean(dma_addr, size);
+		dma_mark_clean(dma_addr, size);
 }
 
 void
@@ -642,13 +707,13 @@
 			  unsigned long offset, size_t size,
 			  int dir, int target)
 {
-	char *dma_addr = phys_to_virt(dev_addr) + offset;
+	char *dma_addr = bus_to_virt(dev_addr) + offset;
 
 	BUG_ON(dir == DMA_NONE);
 	if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
 		sync_single(hwdev, dma_addr, size, dir, target);
 	else if (dir == DMA_FROM_DEVICE)
-		mark_clean(dma_addr, size);
+		dma_mark_clean(dma_addr, size);
 }
 
 void
@@ -687,18 +752,16 @@
 swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nelems,
 	       int dir)
 {
-	void *addr;
-	unsigned long dev_addr;
+	dma_addr_t dev_addr;
 	int i;
 
 	BUG_ON(dir == DMA_NONE);
 
 	for (i = 0; i < nelems; i++, sg++) {
-		addr = SG_ENT_VIRT_ADDRESS(sg);
-		dev_addr = virt_to_phys(addr);
-		if (swiotlb_force || address_needs_mapping(hwdev, dev_addr)) {
-			void *map = map_single(hwdev, addr, sg->length, dir);
-			sg->dma_address = virt_to_bus(map);
+		dev_addr = SG_ENT_PHYS_ADDRESS(sg);
+		if (range_needs_mapping(SG_ENT_VIRT_ADDRESS(sg), sg->length)
+		    || address_needs_mapping(hwdev, dev_addr)) {
+			void *map = map_single(hwdev, sg_to_io_tlb_addr(sg), sg->length, dir);
 			if (!map) {
 				/* Don't panic here, we expect map_sg users
 				   to do proper error handling. */
@@ -707,6 +770,7 @@
 				sg[0].dma_length = 0;
 				return 0;
 			}
+			sg->dma_address = virt_to_bus(map);
 		} else
 			sg->dma_address = dev_addr;
 		sg->dma_length = sg->length;
@@ -728,9 +792,10 @@
 
 	for (i = 0; i < nelems; i++, sg++)
 		if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
-			unmap_single(hwdev, (void *) phys_to_virt(sg->dma_address), sg->dma_length, dir);
+			unmap_single(hwdev, bus_to_virt(sg->dma_address),
+				     sg->dma_length, dir);
 		else if (dir == DMA_FROM_DEVICE)
-			mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length);
+			dma_mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length);
 }
 
 /*
@@ -750,8 +815,10 @@
 
 	for (i = 0; i < nelems; i++, sg++)
 		if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
-			sync_single(hwdev, (void *) sg->dma_address,
+			sync_single(hwdev, bus_to_virt(sg->dma_address),
 				    sg->dma_length, dir, target);
+		else if (dir == DMA_FROM_DEVICE)
+			dma_mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length);
 }
 
 void
@@ -768,10 +835,48 @@
 	swiotlb_sync_sg(hwdev, sg, nelems, dir, SYNC_FOR_DEVICE);
 }
 
+#ifdef SWIOTLB_ARCH_NEED_MAP_PAGE
+
+dma_addr_t
+swiotlb_map_page(struct device *hwdev, struct page *page,
+		 unsigned long offset, size_t size,
+		 enum dma_data_direction direction)
+{
+	dma_addr_t dev_addr;
+	char *map;
+
+	dev_addr = page_to_bus(page) + offset;
+	if (address_needs_mapping(hwdev, dev_addr)) {
+		map = map_single(hwdev, page_to_io_tlb_addr(page, offset), size, direction);
+		if (!map) {
+			swiotlb_full(hwdev, size, direction, 1);
+			map = io_tlb_overflow_buffer;
+		}
+		dev_addr = virt_to_bus(map);
+	}
+
+	return dev_addr;
+}
+
+void
+swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
+		   size_t size, enum dma_data_direction direction)
+{
+	char *dma_addr = bus_to_virt(dev_addr);
+
+	BUG_ON(direction == DMA_NONE);
+	if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
+		unmap_single(hwdev, dma_addr, size, direction);
+	else if (direction == DMA_FROM_DEVICE)
+		dma_mark_clean(dma_addr, size);
+}
+
+#endif
+
 int
 swiotlb_dma_mapping_error(dma_addr_t dma_addr)
 {
-	return (dma_addr == virt_to_phys(io_tlb_overflow_buffer));
+	return (dma_addr == virt_to_bus(io_tlb_overflow_buffer));
 }
 
 /*
@@ -780,10 +885,13 @@
  * during bus mastering, then you would pass 0x00ffffff as the mask to
  * this function.
  */
+#ifndef __swiotlb_dma_supported
+#define __swiotlb_dma_supported(hwdev, mask) (virt_to_bus(io_tlb_end - 1) <= (mask))
+#endif
 int
-swiotlb_dma_supported (struct device *hwdev, u64 mask)
+swiotlb_dma_supported(struct device *hwdev, u64 mask)
 {
-	return (virt_to_phys (io_tlb_end) - 1) <= mask;
+	return __swiotlb_dma_supported(hwdev, mask);
 }
 
 EXPORT_SYMBOL(swiotlb_init);
@@ -798,6 +906,4 @@
 EXPORT_SYMBOL(swiotlb_sync_sg_for_cpu);
 EXPORT_SYMBOL(swiotlb_sync_sg_for_device);
 EXPORT_SYMBOL(swiotlb_dma_mapping_error);
-EXPORT_SYMBOL(swiotlb_alloc_coherent);
-EXPORT_SYMBOL(swiotlb_free_coherent);
 EXPORT_SYMBOL(swiotlb_dma_supported);
diff --git a/mm/filemap.c b/mm/filemap.c
index 8332c77..f30ef28 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -606,26 +606,6 @@
 EXPORT_SYMBOL(find_get_page);
 
 /**
- * find_trylock_page - find and lock a page
- * @mapping: the address_space to search
- * @offset: the page index
- *
- * Same as find_get_page(), but trylock it instead of incrementing the count.
- */
-struct page *find_trylock_page(struct address_space *mapping, unsigned long offset)
-{
-	struct page *page;
-
-	read_lock_irq(&mapping->tree_lock);
-	page = radix_tree_lookup(&mapping->page_tree, offset);
-	if (page && TestSetPageLocked(page))
-		page = NULL;
-	read_unlock_irq(&mapping->tree_lock);
-	return page;
-}
-EXPORT_SYMBOL(find_trylock_page);
-
-/**
  * find_lock_page - locate, pin and lock a pagecache page
  * @mapping: the address_space to search
  * @offset: the page index
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index cb362f7..36db012 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -389,6 +389,8 @@
 			continue;
 
 		page = pte_page(pte);
+		if (pte_dirty(pte))
+			set_page_dirty(page);
 		list_add(&page->lru, &page_list);
 	}
 	spin_unlock(&mm->page_table_lock);
diff --git a/mm/mmap.c b/mm/mmap.c
index cc3a208..eb509ae 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2101,3 +2101,75 @@
 		return 0;
 	return 1;
 }
+
+
+static struct page *special_mapping_nopage(struct vm_area_struct *vma,
+					   unsigned long address, int *type)
+{
+	struct page **pages;
+
+	BUG_ON(address < vma->vm_start || address >= vma->vm_end);
+
+	address -= vma->vm_start;
+	for (pages = vma->vm_private_data; address > 0 && *pages; ++pages)
+		address -= PAGE_SIZE;
+
+	if (*pages) {
+		struct page *page = *pages;
+		get_page(page);
+		return page;
+	}
+
+	return NOPAGE_SIGBUS;
+}
+
+/*
+ * Having a close hook prevents vma merging regardless of flags.
+ */
+static void special_mapping_close(struct vm_area_struct *vma)
+{
+}
+
+static struct vm_operations_struct special_mapping_vmops = {
+	.close = special_mapping_close,
+	.nopage	= special_mapping_nopage,
+};
+
+/*
+ * Called with mm->mmap_sem held for writing.
+ * Insert a new vma covering the given region, with the given flags.
+ * Its pages are supplied by the given array of struct page *.
+ * The array can be shorter than len >> PAGE_SHIFT if it's null-terminated.
+ * The region past the last page supplied will always produce SIGBUS.
+ * The array pointer and the pages it points to are assumed to stay alive
+ * for as long as this mapping might exist.
+ */
+int install_special_mapping(struct mm_struct *mm,
+			    unsigned long addr, unsigned long len,
+			    unsigned long vm_flags, struct page **pages)
+{
+	struct vm_area_struct *vma;
+
+	vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
+	if (unlikely(vma == NULL))
+		return -ENOMEM;
+
+	vma->vm_mm = mm;
+	vma->vm_start = addr;
+	vma->vm_end = addr + len;
+
+	vma->vm_flags = vm_flags | mm->def_flags;
+	vma->vm_page_prot = protection_map[vma->vm_flags & 7];
+
+	vma->vm_ops = &special_mapping_vmops;
+	vma->vm_private_data = pages;
+
+	if (unlikely(insert_vm_struct(mm, vma))) {
+		kmem_cache_free(vm_area_cachep, vma);
+		return -ENOMEM;
+	}
+
+	mm->total_vm += len >> PAGE_SHIFT;
+
+	return 0;
+}
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 2c606cc..f12052d 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1579,8 +1579,8 @@
 
 	get_zone_counts(&active, &inactive, &free);
 
-	printk("Active:%lu inactive:%lu dirty:%lu writeback:%lu "
-		"unstable:%lu free:%u slab:%lu mapped:%lu pagetables:%lu\n",
+	printk("Active:%lu inactive:%lu dirty:%lu writeback:%lu unstable:%lu\n"
+		" free:%u slab:%lu mapped:%lu pagetables:%lu bounce:%lu\n",
 		active,
 		inactive,
 		global_page_state(NR_FILE_DIRTY),
@@ -1590,7 +1590,8 @@
 		global_page_state(NR_SLAB_RECLAIMABLE) +
 			global_page_state(NR_SLAB_UNRECLAIMABLE),
 		global_page_state(NR_FILE_MAPPED),
-		global_page_state(NR_PAGETABLE));
+		global_page_state(NR_PAGETABLE),
+		global_page_state(NR_BOUNCE));
 
 	for_each_zone(zone) {
 		int i;
diff --git a/net/Kconfig b/net/Kconfig
index 7dfc949..9156578 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -37,6 +37,7 @@
 source "net/packet/Kconfig"
 source "net/unix/Kconfig"
 source "net/xfrm/Kconfig"
+source "net/iucv/Kconfig"
 
 config INET
 	bool "TCP/IP networking"
diff --git a/net/Makefile b/net/Makefile
index ad4d14f..4854ac5 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -47,6 +47,7 @@
 obj-$(CONFIG_IEEE80211)		+= ieee80211/
 obj-$(CONFIG_TIPC)		+= tipc/
 obj-$(CONFIG_NETLABEL)		+= netlabel/
+obj-$(CONFIG_IUCV)		+= iucv/
 
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_SYSCTL)		+= sysctl_net.o
diff --git a/net/atm/common.c b/net/atm/common.c
index fbabff4..a2878e9 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -816,7 +816,8 @@
 	proto_unregister(&vcc_proto);
 }
 
-module_init(atm_init);
+subsys_initcall(atm_init);
+
 module_exit(atm_exit);
 
 MODULE_LICENSE("GPL");
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h
index c2775f5..c8dfacd 100644
--- a/net/bluetooth/hidp/hidp.h
+++ b/net/bluetooth/hidp/hidp.h
@@ -86,7 +86,7 @@
 	int   intr_sock;	// Connteted interrupt socket
 	__u16 parser;
 	__u16 rd_size;
-	__u8 *rd_data;
+	__u8 __user *rd_data;
 	__u8  country;
 	__u8  subclass;
 	__u16 vendor;
diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c
index 407fba4..93cf9e5 100644
--- a/net/bluetooth/hidp/sock.c
+++ b/net/bluetooth/hidp/sock.c
@@ -189,7 +189,7 @@
 
 		uca = compat_alloc_user_space(sizeof(*uca));
 
-		if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
+		if (copy_from_user(&ca, (void __user *) arg, sizeof(ca)))
 			return -EFAULT;
 
 		if (put_user(ca.ctrl_sock, &uca->ctrl_sock) ||
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 55bb263..2b7c2c7 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -286,7 +286,7 @@
 	kobject_init(&p->kobj);
 	kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR);
 	p->kobj.ktype = &brport_ktype;
-	p->kobj.parent = &(dev->class_dev.kobj);
+	p->kobj.parent = &(dev->dev.kobj);
 	p->kobj.kset = NULL;
 
 	return p;
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index ea3337a..a25fa8c 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -949,44 +949,29 @@
 };
 #endif
 
-int br_netfilter_init(void)
+int __init br_netfilter_init(void)
 {
-	int i;
+	int ret;
 
-	for (i = 0; i < ARRAY_SIZE(br_nf_ops); i++) {
-		int ret;
-
-		if ((ret = nf_register_hook(&br_nf_ops[i])) >= 0)
-			continue;
-
-		while (i--)
-			nf_unregister_hook(&br_nf_ops[i]);
-
+	ret = nf_register_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
+	if (ret < 0)
 		return ret;
-	}
-
 #ifdef CONFIG_SYSCTL
 	brnf_sysctl_header = register_sysctl_table(brnf_net_table, 0);
 	if (brnf_sysctl_header == NULL) {
 		printk(KERN_WARNING
 		       "br_netfilter: can't register to sysctl.\n");
-		for (i = 0; i < ARRAY_SIZE(br_nf_ops); i++)
-			nf_unregister_hook(&br_nf_ops[i]);
-		return -EFAULT;
+		nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
+		return -ENOMEM;
 	}
 #endif
-
 	printk(KERN_NOTICE "Bridge firewalling registered\n");
-
 	return 0;
 }
 
 void br_netfilter_fini(void)
 {
-	int i;
-
-	for (i = ARRAY_SIZE(br_nf_ops) - 1; i >= 0; i--)
-		nf_unregister_hook(&br_nf_ops[i]);
+	nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
 #ifdef CONFIG_SYSCTL
 	unregister_sysctl_table(brnf_sysctl_header);
 #endif
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index a913968..7d68b24 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -45,7 +45,7 @@
 
 	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags);
 	if (nlh == NULL)
-		return -ENOBUFS;
+		return -EMSGSIZE;
 
 	hdr = nlmsg_data(nlh);
 	hdr->ifi_family = AF_BRIDGE;
@@ -72,7 +72,8 @@
 	return nlmsg_end(skb, nlh);
 
 nla_put_failure:
-	return nlmsg_cancel(skb, nlh);
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
 }
 
 /*
@@ -89,9 +90,12 @@
 		goto errout;
 
 	err = br_fill_ifinfo(skb, port, 0, 0, event, 0);
-	/* failure implies BUG in br_nlmsg_size() */
-	BUG_ON(err < 0);
-
+	if (err < 0) {
+		/* -EMSGSIZE implies BUG in br_nlmsg_size() */
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(skb);
+		goto errout;
+	}
 	err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
 errout:
 	if (err < 0)
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index de9d1a9..ce10464 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -21,18 +21,17 @@
 
 #include "br_private.h"
 
-#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)
+#define to_dev(obj)	container_of(obj, struct device, kobj)
 #define to_bridge(cd)	((struct net_bridge *)(to_net_dev(cd)->priv))
 
 /*
  * Common code for storing bridge parameters.
  */
-static ssize_t store_bridge_parm(struct class_device *cd,
+static ssize_t store_bridge_parm(struct device *d,
 				 const char *buf, size_t len,
 				 void (*set)(struct net_bridge *, unsigned long))
 {
-	struct net_bridge *br = to_bridge(cd);
+	struct net_bridge *br = to_bridge(d);
 	char *endp;
 	unsigned long val;
 
@@ -50,9 +49,10 @@
 }
 
 
-static ssize_t show_forward_delay(struct class_device *cd, char *buf)
+static ssize_t show_forward_delay(struct device *d,
+				  struct device_attribute *attr, char *buf)
 {
-	struct net_bridge *br = to_bridge(cd);
+	struct net_bridge *br = to_bridge(d);
 	return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
 }
 
@@ -64,18 +64,20 @@
 		br->bridge_forward_delay = delay;
 }
 
-static ssize_t store_forward_delay(struct class_device *cd, const char *buf,
-				   size_t len)
+static ssize_t store_forward_delay(struct device *d,
+				   struct device_attribute *attr,
+				   const char *buf, size_t len)
 {
-	return store_bridge_parm(cd, buf, len, set_forward_delay);
+	return store_bridge_parm(d, buf, len, set_forward_delay);
 }
-static CLASS_DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
-			 show_forward_delay, store_forward_delay);
+static DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
+		   show_forward_delay, store_forward_delay);
 
-static ssize_t show_hello_time(struct class_device *cd, char *buf)
+static ssize_t show_hello_time(struct device *d, struct device_attribute *attr,
+			       char *buf)
 {
 	return sprintf(buf, "%lu\n",
-		       jiffies_to_clock_t(to_bridge(cd)->hello_time));
+		       jiffies_to_clock_t(to_bridge(d)->hello_time));
 }
 
 static void set_hello_time(struct net_bridge *br, unsigned long val)
@@ -86,19 +88,20 @@
 		br->bridge_hello_time = t;
 }
 
-static ssize_t store_hello_time(struct class_device *cd, const char *buf,
+static ssize_t store_hello_time(struct device *d,
+				struct device_attribute *attr, const char *buf,
 				size_t len)
 {
-	return store_bridge_parm(cd, buf, len, set_hello_time);
+	return store_bridge_parm(d, buf, len, set_hello_time);
 }
+static DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
+		   store_hello_time);
 
-static CLASS_DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
-			 store_hello_time);
-
-static ssize_t show_max_age(struct class_device *cd, char *buf)
+static ssize_t show_max_age(struct device *d, struct device_attribute *attr,
+			    char *buf)
 {
 	return sprintf(buf, "%lu\n",
-		       jiffies_to_clock_t(to_bridge(cd)->max_age));
+		       jiffies_to_clock_t(to_bridge(d)->max_age));
 }
 
 static void set_max_age(struct net_bridge *br, unsigned long val)
@@ -109,18 +112,17 @@
 		br->bridge_max_age = t;
 }
 
-static ssize_t store_max_age(struct class_device *cd, const char *buf,
-				size_t len)
+static ssize_t store_max_age(struct device *d, struct device_attribute *attr,
+			     const char *buf, size_t len)
 {
-	return store_bridge_parm(cd, buf, len, set_max_age);
+	return store_bridge_parm(d, buf, len, set_max_age);
 }
+static DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age);
 
-static CLASS_DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age,
-			 store_max_age);
-
-static ssize_t show_ageing_time(struct class_device *cd, char *buf)
+static ssize_t show_ageing_time(struct device *d,
+				struct device_attribute *attr, char *buf)
 {
-	struct net_bridge *br = to_bridge(cd);
+	struct net_bridge *br = to_bridge(d);
 	return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time));
 }
 
@@ -129,17 +131,19 @@
 	br->ageing_time = clock_t_to_jiffies(val);
 }
 
-static ssize_t store_ageing_time(struct class_device *cd, const char *buf,
-				 size_t len)
+static ssize_t store_ageing_time(struct device *d,
+				 struct device_attribute *attr,
+				 const char *buf, size_t len)
 {
-	return store_bridge_parm(cd, buf, len, set_ageing_time);
+	return store_bridge_parm(d, buf, len, set_ageing_time);
 }
+static DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time,
+		   store_ageing_time);
 
-static CLASS_DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time,
-			 store_ageing_time);
-static ssize_t show_stp_state(struct class_device *cd, char *buf)
+static ssize_t show_stp_state(struct device *d,
+			      struct device_attribute *attr, char *buf)
 {
-	struct net_bridge *br = to_bridge(cd);
+	struct net_bridge *br = to_bridge(d);
 	return sprintf(buf, "%d\n", br->stp_enabled);
 }
 
@@ -148,18 +152,19 @@
 	br->stp_enabled = val;
 }
 
-static ssize_t store_stp_state(struct class_device *cd,
-			       const char *buf, size_t len)
+static ssize_t store_stp_state(struct device *d,
+			       struct device_attribute *attr, const char *buf,
+			       size_t len)
 {
-	return store_bridge_parm(cd, buf, len, set_stp_state);
+	return store_bridge_parm(d, buf, len, set_stp_state);
 }
+static DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
+		   store_stp_state);
 
-static CLASS_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
-			 store_stp_state);
-
-static ssize_t show_priority(struct class_device *cd, char *buf)
+static ssize_t show_priority(struct device *d, struct device_attribute *attr,
+			     char *buf)
 {
-	struct net_bridge *br = to_bridge(cd);
+	struct net_bridge *br = to_bridge(d);
 	return sprintf(buf, "%d\n",
 		       (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
 }
@@ -169,92 +174,107 @@
 	br_stp_set_bridge_priority(br, (u16) val);
 }
 
-static ssize_t store_priority(struct class_device *cd,
+static ssize_t store_priority(struct device *d, struct device_attribute *attr,
 			       const char *buf, size_t len)
 {
-	return store_bridge_parm(cd, buf, len, set_priority);
+	return store_bridge_parm(d, buf, len, set_priority);
 }
-static CLASS_DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority,
-			 store_priority);
+static DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority);
 
-static ssize_t show_root_id(struct class_device *cd, char *buf)
+static ssize_t show_root_id(struct device *d, struct device_attribute *attr,
+			    char *buf)
 {
-	return br_show_bridge_id(buf, &to_bridge(cd)->designated_root);
+	return br_show_bridge_id(buf, &to_bridge(d)->designated_root);
 }
-static CLASS_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
+static DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
 
-static ssize_t show_bridge_id(struct class_device *cd, char *buf)
+static ssize_t show_bridge_id(struct device *d, struct device_attribute *attr,
+			      char *buf)
 {
-	return br_show_bridge_id(buf, &to_bridge(cd)->bridge_id);
+	return br_show_bridge_id(buf, &to_bridge(d)->bridge_id);
 }
-static CLASS_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
+static DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
 
-static ssize_t show_root_port(struct class_device *cd, char *buf)
+static ssize_t show_root_port(struct device *d, struct device_attribute *attr,
+			      char *buf)
 {
-	return sprintf(buf, "%d\n", to_bridge(cd)->root_port);
+	return sprintf(buf, "%d\n", to_bridge(d)->root_port);
 }
-static CLASS_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
+static DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
 
-static ssize_t show_root_path_cost(struct class_device *cd, char *buf)
+static ssize_t show_root_path_cost(struct device *d,
+				   struct device_attribute *attr, char *buf)
 {
-	return sprintf(buf, "%d\n", to_bridge(cd)->root_path_cost);
+	return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost);
 }
-static CLASS_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
+static DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
 
-static ssize_t show_topology_change(struct class_device *cd, char *buf)
+static ssize_t show_topology_change(struct device *d,
+				    struct device_attribute *attr, char *buf)
 {
-	return sprintf(buf, "%d\n", to_bridge(cd)->topology_change);
+	return sprintf(buf, "%d\n", to_bridge(d)->topology_change);
 }
-static CLASS_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
+static DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
 
-static ssize_t show_topology_change_detected(struct class_device *cd, char *buf)
+static ssize_t show_topology_change_detected(struct device *d,
+					     struct device_attribute *attr,
+					     char *buf)
 {
-	struct net_bridge *br = to_bridge(cd);
+	struct net_bridge *br = to_bridge(d);
 	return sprintf(buf, "%d\n", br->topology_change_detected);
 }
-static CLASS_DEVICE_ATTR(topology_change_detected, S_IRUGO, show_topology_change_detected, NULL);
+static DEVICE_ATTR(topology_change_detected, S_IRUGO,
+		   show_topology_change_detected, NULL);
 
-static ssize_t show_hello_timer(struct class_device *cd, char *buf)
+static ssize_t show_hello_timer(struct device *d,
+				struct device_attribute *attr, char *buf)
 {
-	struct net_bridge *br = to_bridge(cd);
+	struct net_bridge *br = to_bridge(d);
 	return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer));
 }
-static CLASS_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
+static DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
 
-static ssize_t show_tcn_timer(struct class_device *cd, char *buf)
+static ssize_t show_tcn_timer(struct device *d, struct device_attribute *attr,
+			      char *buf)
 {
-	struct net_bridge *br = to_bridge(cd);
+	struct net_bridge *br = to_bridge(d);
 	return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer));
 }
-static CLASS_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
+static DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
 
-static ssize_t show_topology_change_timer(struct class_device *cd, char *buf)
+static ssize_t show_topology_change_timer(struct device *d,
+					  struct device_attribute *attr,
+					  char *buf)
 {
-	struct net_bridge *br = to_bridge(cd);
+	struct net_bridge *br = to_bridge(d);
 	return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer));
 }
-static CLASS_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer, NULL);
+static DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer,
+		   NULL);
 
-static ssize_t show_gc_timer(struct class_device *cd, char *buf)
+static ssize_t show_gc_timer(struct device *d, struct device_attribute *attr,
+			     char *buf)
 {
-	struct net_bridge *br = to_bridge(cd);
+	struct net_bridge *br = to_bridge(d);
 	return sprintf(buf, "%ld\n", br_timer_value(&br->gc_timer));
 }
-static CLASS_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
+static DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
 
-static ssize_t show_group_addr(struct class_device *cd, char *buf)
+static ssize_t show_group_addr(struct device *d,
+			       struct device_attribute *attr, char *buf)
 {
-	struct net_bridge *br = to_bridge(cd);
+	struct net_bridge *br = to_bridge(d);
 	return sprintf(buf, "%x:%x:%x:%x:%x:%x\n",
 		       br->group_addr[0], br->group_addr[1],
 		       br->group_addr[2], br->group_addr[3],
 		       br->group_addr[4], br->group_addr[5]);
 }
 
-static ssize_t store_group_addr(struct class_device *cd, const char *buf,
-				    size_t len)
+static ssize_t store_group_addr(struct device *d,
+				struct device_attribute *attr,
+				const char *buf, size_t len)
 {
-	struct net_bridge *br = to_bridge(cd);
+	struct net_bridge *br = to_bridge(d);
 	unsigned new_addr[6];
 	int i;
 
@@ -286,28 +306,28 @@
 	return len;
 }
 
-static CLASS_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
-			 show_group_addr, store_group_addr);
+static DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
+		   show_group_addr, store_group_addr);
 
 
 static struct attribute *bridge_attrs[] = {
-	&class_device_attr_forward_delay.attr,
-	&class_device_attr_hello_time.attr,
-	&class_device_attr_max_age.attr,
-	&class_device_attr_ageing_time.attr,
-	&class_device_attr_stp_state.attr,
-	&class_device_attr_priority.attr,
-	&class_device_attr_bridge_id.attr,
-	&class_device_attr_root_id.attr,
-	&class_device_attr_root_path_cost.attr,
-	&class_device_attr_root_port.attr,
-	&class_device_attr_topology_change.attr,
-	&class_device_attr_topology_change_detected.attr,
-	&class_device_attr_hello_timer.attr,
-	&class_device_attr_tcn_timer.attr,
-	&class_device_attr_topology_change_timer.attr,
-	&class_device_attr_gc_timer.attr,
-	&class_device_attr_group_addr.attr,
+	&dev_attr_forward_delay.attr,
+	&dev_attr_hello_time.attr,
+	&dev_attr_max_age.attr,
+	&dev_attr_ageing_time.attr,
+	&dev_attr_stp_state.attr,
+	&dev_attr_priority.attr,
+	&dev_attr_bridge_id.attr,
+	&dev_attr_root_id.attr,
+	&dev_attr_root_path_cost.attr,
+	&dev_attr_root_port.attr,
+	&dev_attr_topology_change.attr,
+	&dev_attr_topology_change_detected.attr,
+	&dev_attr_hello_timer.attr,
+	&dev_attr_tcn_timer.attr,
+	&dev_attr_topology_change_timer.attr,
+	&dev_attr_gc_timer.attr,
+	&dev_attr_group_addr.attr,
 	NULL
 };
 
@@ -325,8 +345,8 @@
 static ssize_t brforward_read(struct kobject *kobj, char *buf,
 			   loff_t off, size_t count)
 {
-	struct class_device *cdev = to_class_dev(kobj);
-	struct net_bridge *br = to_bridge(cdev);
+	struct device *dev = to_dev(kobj);
+	struct net_bridge *br = to_bridge(dev);
 	int n;
 
 	/* must read whole records */
@@ -363,7 +383,7 @@
  */
 int br_sysfs_addbr(struct net_device *dev)
 {
-	struct kobject *brobj = &dev->class_dev.kobj;
+	struct kobject *brobj = &dev->dev.kobj;
 	struct net_bridge *br = netdev_priv(dev);
 	int err;
 
@@ -395,9 +415,9 @@
 	}
 	return 0;
  out3:
-	sysfs_remove_bin_file(&dev->class_dev.kobj, &bridge_forward);
+	sysfs_remove_bin_file(&dev->dev.kobj, &bridge_forward);
  out2:
-	sysfs_remove_group(&dev->class_dev.kobj, &bridge_group);
+	sysfs_remove_group(&dev->dev.kobj, &bridge_group);
  out1:
 	return err;
 
@@ -405,7 +425,7 @@
 
 void br_sysfs_delbr(struct net_device *dev)
 {
-	struct kobject *kobj = &dev->class_dev.kobj;
+	struct kobject *kobj = &dev->dev.kobj;
 	struct net_bridge *br = netdev_priv(dev);
 
 	kobject_unregister(&br->ifobj);
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index c51c9e4..0bc2aef 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -211,7 +211,7 @@
 	struct brport_attribute **a;
 	int err;
 
-	err = sysfs_create_link(&p->kobj, &br->dev->class_dev.kobj, 
+	err = sysfs_create_link(&p->kobj, &br->dev->dev.kobj,
 				SYSFS_BRIDGE_PORT_LINK);
 	if (err)
 		goto out2;
diff --git a/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c
index e4c6424..6afa4d0 100644
--- a/net/bridge/netfilter/ebt_ip.c
+++ b/net/bridge/netfilter/ebt_ip.c
@@ -93,6 +93,7 @@
 			return -EINVAL;
 		if (info->protocol != IPPROTO_TCP &&
 		    info->protocol != IPPROTO_UDP &&
+		    info->protocol != IPPROTO_UDPLITE &&
 		    info->protocol != IPPROTO_SCTP &&
 		    info->protocol != IPPROTO_DCCP)
 			 return -EINVAL;
diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c
index a184f87..985df82 100644
--- a/net/bridge/netfilter/ebt_log.c
+++ b/net/bridge/netfilter/ebt_log.c
@@ -96,6 +96,7 @@
 		       NIPQUAD(ih->daddr), ih->tos, ih->protocol);
 		if (ih->protocol == IPPROTO_TCP ||
 		    ih->protocol == IPPROTO_UDP ||
+		    ih->protocol == IPPROTO_UDPLITE ||
 		    ih->protocol == IPPROTO_SCTP ||
 		    ih->protocol == IPPROTO_DCCP) {
 			struct tcpudphdr _ports, *pptr;
diff --git a/net/core/dev.c b/net/core/dev.c
index e660cb5..1e94a1b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -751,7 +751,7 @@
 	else
 		strlcpy(dev->name, newname, IFNAMSIZ);
 
-	err = class_device_rename(&dev->class_dev, dev->name);
+	err = device_rename(&dev->dev, dev->name);
 	if (!err) {
 		hlist_del(&dev->name_hlist);
 		hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name));
@@ -3221,8 +3221,8 @@
 	BUG_ON(dev->reg_state != NETREG_UNREGISTERED);
 	dev->reg_state = NETREG_RELEASED;
 
-	/* will free via class release */
-	class_device_put(&dev->class_dev);
+	/* will free via device release */
+	put_device(&dev->dev);
 #else
 	kfree((char *)dev - dev->padded);
 #endif
@@ -3247,7 +3247,7 @@
  *	unregister_netdev() instead of this.
  */
 
-int unregister_netdevice(struct net_device *dev)
+void unregister_netdevice(struct net_device *dev)
 {
 	struct net_device *d, **dp;
 
@@ -3258,7 +3258,9 @@
 	if (dev->reg_state == NETREG_UNINITIALIZED) {
 		printk(KERN_DEBUG "unregister_netdevice: device %s/%p never "
 				  "was registered\n", dev->name, dev);
-		return -ENODEV;
+
+		WARN_ON(1);
+		return;
 	}
 
 	BUG_ON(dev->reg_state != NETREG_REGISTERED);
@@ -3280,11 +3282,7 @@
 			break;
 		}
 	}
-	if (!d) {
-		printk(KERN_ERR "unregister net_device: '%s' not found\n",
-		       dev->name);
-		return -ENODEV;
-	}
+	BUG_ON(!d);
 
 	dev->reg_state = NETREG_UNREGISTERING;
 
@@ -3316,7 +3314,6 @@
 	synchronize_net();
 
 	dev_put(dev);
-	return 0;
 }
 
 /**
diff --git a/net/core/dst.c b/net/core/dst.c
index 836ec66..1a53fb3 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -99,7 +99,14 @@
 	printk("dst_total: %d/%d %ld\n",
 	       atomic_read(&dst_total), delayed,  dst_gc_timer_expires);
 #endif
-	mod_timer(&dst_gc_timer, jiffies + dst_gc_timer_expires);
+	/* if the next desired timer is more than 4 seconds in the future
+	 * then round the timer to whole seconds
+	 */
+	if (dst_gc_timer_expires > 4*HZ)
+		mod_timer(&dst_gc_timer,
+			round_jiffies(jiffies + dst_gc_timer_expires));
+	else
+		mod_timer(&dst_gc_timer, jiffies + dst_gc_timer_expires);
 
 out:
 	spin_unlock(&dst_lock);
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 1df6cd45..215f1bff 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -331,7 +331,7 @@
 
 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*frh), flags);
 	if (nlh == NULL)
-		return -1;
+		return -EMSGSIZE;
 
 	frh = nlmsg_data(nlh);
 	frh->table = rule->table;
@@ -359,7 +359,8 @@
 	return nlmsg_end(skb, nlh);
 
 nla_put_failure:
-	return nlmsg_cancel(skb, nlh);
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
 }
 
 int fib_rules_dump(struct sk_buff *skb, struct netlink_callback *cb, int family)
@@ -405,9 +406,12 @@
 		goto errout;
 
 	err = fib_nl_fill_rule(skb, rule, pid, nlh->nlmsg_seq, event, 0, ops);
-	/* failure implies BUG in fib_rule_nlmsg_size() */
-	BUG_ON(err < 0);
-
+	if (err < 0) {
+		/* -EMSGSIZE implies BUG in fib_rule_nlmsg_size() */
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(skb);
+		goto errout;
+	}
 	err = rtnl_notify(skb, pid, ops->nlgroup, nlh, GFP_KERNEL);
 errout:
 	if (err < 0)
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index e7300b6..054d464 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -696,7 +696,10 @@
 	if (!expire)
 		expire = 1;
 
- 	mod_timer(&tbl->gc_timer, now + expire);
+	if (expire>HZ)
+		mod_timer(&tbl->gc_timer, round_jiffies(now + expire));
+	else
+		mod_timer(&tbl->gc_timer, now + expire);
 
 	write_unlock(&tbl->lock);
 }
@@ -1637,7 +1640,7 @@
 
 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
 	if (nlh == NULL)
-		return -ENOBUFS;
+		return -EMSGSIZE;
 
 	ndtmsg = nlmsg_data(nlh);
 
@@ -1706,7 +1709,8 @@
 
 nla_put_failure:
 	read_unlock_bh(&tbl->lock);
-	return nlmsg_cancel(skb, nlh);
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
 }
 
 static int neightbl_fill_param_info(struct sk_buff *skb,
@@ -1720,7 +1724,7 @@
 
 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
 	if (nlh == NULL)
-		return -ENOBUFS;
+		return -EMSGSIZE;
 
 	ndtmsg = nlmsg_data(nlh);
 
@@ -1737,7 +1741,8 @@
 	return nlmsg_end(skb, nlh);
 errout:
 	read_unlock_bh(&tbl->lock);
-	return nlmsg_cancel(skb, nlh);
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
 }
  
 static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl,
@@ -1955,7 +1960,7 @@
 
 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
 	if (nlh == NULL)
-		return -ENOBUFS;
+		return -EMSGSIZE;
 
 	ndm = nlmsg_data(nlh);
 	ndm->ndm_family	 = neigh->ops->family;
@@ -1987,7 +1992,8 @@
 	return nlmsg_end(skb, nlh);
 
 nla_put_failure:
-	return nlmsg_cancel(skb, nlh);
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
 }
 
 
@@ -2429,9 +2435,12 @@
 		goto errout;
 
 	err = neigh_fill_info(skb, n, 0, 0, type, flags);
-	/* failure implies BUG in neigh_nlmsg_size() */
-	BUG_ON(err < 0);
-
+	if (err < 0) {
+		/* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(skb);
+		goto errout;
+	}
 	err = rtnl_notify(skb, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
 errout:
 	if (err < 0)
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 44e69a2..cd59ac6 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -18,9 +18,6 @@
 #include <linux/wireless.h>
 #include <net/iw_handler.h>
 
-#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_long_hex[] = "%#lx\n";
 static const char fmt_dec[] = "%d\n";
@@ -32,10 +29,11 @@
 }
 
 /* use same locking rules as GIF* ioctl's */
-static ssize_t netdev_show(const struct class_device *cd, char *buf,
+static ssize_t netdev_show(const struct device *dev,
+			   struct device_attribute *attr, char *buf,
 			   ssize_t (*format)(const struct net_device *, char *))
 {
-	struct net_device *net = to_net_dev(cd);
+	struct net_device *net = to_net_dev(dev);
 	ssize_t ret = -EINVAL;
 
 	read_lock(&dev_base_lock);
@@ -52,14 +50,15 @@
 {									\
 	return sprintf(buf, format_string, net->field);			\
 }									\
-static ssize_t show_##field(struct class_device *cd, char *buf)		\
+static ssize_t show_##field(struct device *dev,				\
+			    struct device_attribute *attr, char *buf)	\
 {									\
-	return netdev_show(cd, buf, format_##field);			\
+	return netdev_show(dev, attr, buf, format_##field);		\
 }
 
 
 /* use same locking and permission rules as SIF* ioctl's */
-static ssize_t netdev_store(struct class_device *dev,
+static ssize_t netdev_store(struct device *dev, struct device_attribute *attr,
 			    const char *buf, size_t len,
 			    int (*set)(struct net_device *, unsigned long))
 {
@@ -104,7 +103,8 @@
 	return cp - buf;
 }
 
-static ssize_t show_address(struct class_device *dev, char *buf)
+static ssize_t show_address(struct device *dev, struct device_attribute *attr,
+			    char *buf)
 {
 	struct net_device *net = to_net_dev(dev);
 	ssize_t ret = -EINVAL;
@@ -116,7 +116,8 @@
 	return ret;
 }
 
-static ssize_t show_broadcast(struct class_device *dev, char *buf)
+static ssize_t show_broadcast(struct device *dev,
+			    struct device_attribute *attr, char *buf)
 {
 	struct net_device *net = to_net_dev(dev);
 	if (dev_isalive(net))
@@ -124,7 +125,8 @@
 	return -EINVAL;
 }
 
-static ssize_t show_carrier(struct class_device *dev, char *buf)
+static ssize_t show_carrier(struct device *dev,
+			    struct device_attribute *attr, char *buf)
 {
 	struct net_device *netdev = to_net_dev(dev);
 	if (netif_running(netdev)) {
@@ -133,7 +135,8 @@
 	return -EINVAL;
 }
 
-static ssize_t show_dormant(struct class_device *dev, char *buf)
+static ssize_t show_dormant(struct device *dev,
+			    struct device_attribute *attr, char *buf)
 {
 	struct net_device *netdev = to_net_dev(dev);
 
@@ -153,7 +156,8 @@
 	"up"
 };
 
-static ssize_t show_operstate(struct class_device *dev, char *buf)
+static ssize_t show_operstate(struct device *dev,
+			      struct device_attribute *attr, char *buf)
 {
 	const struct net_device *netdev = to_net_dev(dev);
 	unsigned char operstate;
@@ -178,9 +182,10 @@
 	return dev_set_mtu(net, (int) new_mtu);
 }
 
-static ssize_t store_mtu(struct class_device *dev, const char *buf, size_t len)
+static ssize_t store_mtu(struct device *dev, struct device_attribute *attr,
+			 const char *buf, size_t len)
 {
-	return netdev_store(dev, buf, len, change_mtu);
+	return netdev_store(dev, attr, buf, len, change_mtu);
 }
 
 NETDEVICE_SHOW(flags, fmt_hex);
@@ -190,9 +195,10 @@
 	return dev_change_flags(net, (unsigned) new_flags);
 }
 
-static ssize_t store_flags(struct class_device *dev, const char *buf, size_t len)
+static ssize_t store_flags(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t len)
 {
-	return netdev_store(dev, buf, len, change_flags);
+	return netdev_store(dev, attr, buf, len, change_flags);
 }
 
 NETDEVICE_SHOW(tx_queue_len, fmt_ulong);
@@ -203,9 +209,11 @@
 	return 0;
 }
 
-static ssize_t store_tx_queue_len(struct class_device *dev, const char *buf, size_t len)
+static ssize_t store_tx_queue_len(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t len)
 {
-	return netdev_store(dev, buf, len, change_tx_queue_len);
+	return netdev_store(dev, attr, buf, len, change_tx_queue_len);
 }
 
 NETDEVICE_SHOW(weight, fmt_dec);
@@ -216,12 +224,13 @@
 	return 0;
 }
 
-static ssize_t store_weight(struct class_device *dev, const char *buf, size_t len)
+static ssize_t store_weight(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t len)
 {
-	return netdev_store(dev, buf, len, change_weight);
+	return netdev_store(dev, attr, buf, len, change_weight);
 }
 
-static struct class_device_attribute net_class_attributes[] = {
+static struct device_attribute net_class_attributes[] = {
 	__ATTR(addr_len, S_IRUGO, show_addr_len, NULL),
 	__ATTR(iflink, S_IRUGO, show_iflink, NULL),
 	__ATTR(ifindex, S_IRUGO, show_ifindex, NULL),
@@ -242,10 +251,11 @@
 };
 
 /* Show a given an attribute in the statistics group */
-static ssize_t netstat_show(const struct class_device *cd, char *buf, 
+static ssize_t netstat_show(const struct device *d,
+			    struct device_attribute *attr, char *buf,
 			    unsigned long offset)
 {
-	struct net_device *dev = to_net_dev(cd);
+	struct net_device *dev = to_net_dev(d);
 	struct net_device_stats *stats;
 	ssize_t ret = -EINVAL;
 
@@ -265,12 +275,13 @@
 
 /* generate a read-only statistics attribute */
 #define NETSTAT_ENTRY(name)						\
-static ssize_t show_##name(struct class_device *cd, char *buf) 		\
+static ssize_t show_##name(struct device *d,				\
+			   struct device_attribute *attr, char *buf) 	\
 {									\
-	return netstat_show(cd, buf, 					\
+	return netstat_show(d, attr, buf,				\
 			    offsetof(struct net_device_stats, name));	\
 }									\
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
 
 NETSTAT_ENTRY(rx_packets);
 NETSTAT_ENTRY(tx_packets);
@@ -297,29 +308,29 @@
 NETSTAT_ENTRY(tx_compressed);
 
 static struct attribute *netstat_attrs[] = {
-	&class_device_attr_rx_packets.attr,
-	&class_device_attr_tx_packets.attr,
-	&class_device_attr_rx_bytes.attr,
-	&class_device_attr_tx_bytes.attr,
-	&class_device_attr_rx_errors.attr,
-	&class_device_attr_tx_errors.attr,
-	&class_device_attr_rx_dropped.attr,
-	&class_device_attr_tx_dropped.attr,
-	&class_device_attr_multicast.attr,
-	&class_device_attr_collisions.attr,
-	&class_device_attr_rx_length_errors.attr,
-	&class_device_attr_rx_over_errors.attr,
-	&class_device_attr_rx_crc_errors.attr,
-	&class_device_attr_rx_frame_errors.attr,
-	&class_device_attr_rx_fifo_errors.attr,
-	&class_device_attr_rx_missed_errors.attr,
-	&class_device_attr_tx_aborted_errors.attr,
-	&class_device_attr_tx_carrier_errors.attr,
-	&class_device_attr_tx_fifo_errors.attr,
-	&class_device_attr_tx_heartbeat_errors.attr,
-	&class_device_attr_tx_window_errors.attr,
-	&class_device_attr_rx_compressed.attr,
-	&class_device_attr_tx_compressed.attr,
+	&dev_attr_rx_packets.attr,
+	&dev_attr_tx_packets.attr,
+	&dev_attr_rx_bytes.attr,
+	&dev_attr_tx_bytes.attr,
+	&dev_attr_rx_errors.attr,
+	&dev_attr_tx_errors.attr,
+	&dev_attr_rx_dropped.attr,
+	&dev_attr_tx_dropped.attr,
+	&dev_attr_multicast.attr,
+	&dev_attr_collisions.attr,
+	&dev_attr_rx_length_errors.attr,
+	&dev_attr_rx_over_errors.attr,
+	&dev_attr_rx_crc_errors.attr,
+	&dev_attr_rx_frame_errors.attr,
+	&dev_attr_rx_fifo_errors.attr,
+	&dev_attr_rx_missed_errors.attr,
+	&dev_attr_tx_aborted_errors.attr,
+	&dev_attr_tx_carrier_errors.attr,
+	&dev_attr_tx_fifo_errors.attr,
+	&dev_attr_tx_heartbeat_errors.attr,
+	&dev_attr_tx_window_errors.attr,
+	&dev_attr_rx_compressed.attr,
+	&dev_attr_tx_compressed.attr,
 	NULL
 };
 
@@ -331,11 +342,11 @@
 
 #ifdef CONFIG_WIRELESS_EXT
 /* helper function that does all the locking etc for wireless stats */
-static ssize_t wireless_show(struct class_device *cd, char *buf,
+static ssize_t wireless_show(struct device *d, char *buf,
 			     ssize_t (*format)(const struct iw_statistics *,
 					       char *))
 {
-	struct net_device *dev = to_net_dev(cd);
+	struct net_device *dev = to_net_dev(d);
 	const struct iw_statistics *iw = NULL;
 	ssize_t ret = -EINVAL;
 	
@@ -358,11 +369,12 @@
 {									\
 	return sprintf(buf, format_string, iw->field);			\
 }									\
-static ssize_t show_iw_##name(struct class_device *cd, char *buf)	\
+static ssize_t show_iw_##name(struct device *d,				\
+			      struct device_attribute *attr, char *buf)	\
 {									\
-	return wireless_show(cd, buf, format_iw_##name);		\
+	return wireless_show(d, buf, format_iw_##name);			\
 }									\
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL)
+static DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL)
 
 WIRELESS_SHOW(status, status, fmt_hex);
 WIRELESS_SHOW(link, qual.qual, fmt_dec);
@@ -376,16 +388,16 @@
 WIRELESS_SHOW(beacon, miss.beacon, fmt_dec);
 
 static struct attribute *wireless_attrs[] = {
-	&class_device_attr_status.attr,
-	&class_device_attr_link.attr,
-	&class_device_attr_level.attr,
-	&class_device_attr_noise.attr,
-	&class_device_attr_nwid.attr,
-	&class_device_attr_crypt.attr,
-	&class_device_attr_fragment.attr,
-	&class_device_attr_retries.attr,
-	&class_device_attr_misc.attr,
-	&class_device_attr_beacon.attr,
+	&dev_attr_status.attr,
+	&dev_attr_link.attr,
+	&dev_attr_level.attr,
+	&dev_attr_noise.attr,
+	&dev_attr_nwid.attr,
+	&dev_attr_crypt.attr,
+	&dev_attr_fragment.attr,
+	&dev_attr_retries.attr,
+	&dev_attr_misc.attr,
+	&dev_attr_beacon.attr,
 	NULL
 };
 
@@ -396,10 +408,10 @@
 #endif
 
 #ifdef CONFIG_HOTPLUG
-static int netdev_uevent(struct class_device *cd, char **envp,
+static int netdev_uevent(struct device *d, char **envp,
 			 int num_envp, char *buf, int size)
 {
-	struct net_device *dev = to_net_dev(cd);
+	struct net_device *dev = to_net_dev(d);
 	int i = 0;
 	int n;
 
@@ -419,12 +431,11 @@
 
 /*
  *	netdev_release -- destroy and free a dead device. 
- *	Called when last reference to class_device kobject is gone.
+ *	Called when last reference to device kobject is gone.
  */
-static void netdev_release(struct class_device *cd)
+static void netdev_release(struct device *d)
 {
-	struct net_device *dev 
-		= container_of(cd, struct net_device, class_dev);
+	struct net_device *dev = to_net_dev(d);
 
 	BUG_ON(dev->reg_state != NETREG_RELEASED);
 
@@ -433,31 +444,31 @@
 
 static struct class net_class = {
 	.name = "net",
-	.release = netdev_release,
-	.class_dev_attrs = net_class_attributes,
+	.dev_release = netdev_release,
+	.dev_attrs = net_class_attributes,
 #ifdef CONFIG_HOTPLUG
-	.uevent = netdev_uevent,
+	.dev_uevent = netdev_uevent,
 #endif
 };
 
 void netdev_unregister_sysfs(struct net_device * net)
 {
-	class_device_del(&(net->class_dev));
+	device_del(&(net->dev));
 }
 
 /* Create sysfs entries for network device. */
 int netdev_register_sysfs(struct net_device *net)
 {
-	struct class_device *class_dev = &(net->class_dev);
+	struct device *dev = &(net->dev);
 	struct attribute_group **groups = net->sysfs_groups;
 
-	class_device_initialize(class_dev);
-	class_dev->class = &net_class;
-	class_dev->class_data = net;
-	class_dev->groups = groups;
+	device_initialize(dev);
+	dev->class = &net_class;
+	dev->platform_data = net;
+	dev->groups = groups;
 
 	BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ);
-	strlcpy(class_dev->class_id, net->name, BUS_ID_SIZE);
+	strlcpy(dev->bus_id, net->name, BUS_ID_SIZE);
 
 	if (net->get_stats)
 		*groups++ = &netstat_group;
@@ -467,7 +478,7 @@
 		*groups++ = &wireless_group;
 #endif
 
-	return class_device_add(class_dev);
+	return device_add(dev);
 }
 
 int netdev_sysfs_init(void)
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index e76539a..9bf9ae0 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -320,7 +320,7 @@
 
 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
 	if (nlh == NULL)
-		return -ENOBUFS;
+		return -EMSGSIZE;
 
 	ifm = nlmsg_data(nlh);
 	ifm->ifi_family = AF_UNSPEC;
@@ -384,7 +384,8 @@
 	return nlmsg_end(skb, nlh);
 
 nla_put_failure:
-	return nlmsg_cancel(skb, nlh);
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
 }
 
 static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
@@ -633,9 +634,12 @@
 
 	err = rtnl_fill_ifinfo(nskb, dev, iw, iw_buf_len, RTM_NEWLINK,
 			       NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, 0);
-	/* failure impilies BUG in if_nlmsg_size or wireless_rtnetlink_get */
-	BUG_ON(err < 0);
-
+	if (err < 0) {
+		/* -EMSGSIZE implies BUG in if_nlmsg_size */
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(nskb);
+		goto errout;
+	}
 	err = rtnl_unicast(nskb, NETLINK_CB(skb).pid);
 errout:
 	kfree(iw_buf);
@@ -678,9 +682,12 @@
 		goto errout;
 
 	err = rtnl_fill_ifinfo(skb, dev, NULL, 0, type, 0, 0, change, 0);
-	/* failure implies BUG in if_nlmsg_size() */
-	BUG_ON(err < 0);
-
+	if (err < 0) {
+		/* -EMSGSIZE implies BUG in if_nlmsg_size() */
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(skb);
+		goto errout;
+	}
 	err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
 errout:
 	if (err < 0)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index de7801d..f3404ae 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -268,7 +268,7 @@
 struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
 		unsigned int length, gfp_t gfp_mask)
 {
-	int node = dev->class_dev.dev ? dev_to_node(dev->class_dev.dev) : -1;
+	int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1;
 	struct sk_buff *skb;
 
  	skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, 0, node);
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
index 40402c5..5c452a3 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -479,7 +479,8 @@
 
 			ccid3_pr_debug("%s(%p), s=%u, w_init=%llu, "
 				       "R_sample=%dus, X=%u\n", dccp_role(sk),
-				       sk, hctx->ccid3hctx_s, w_init,
+				       sk, hctx->ccid3hctx_s,
+				       (unsigned long long)w_init,
 				       (int)r_sample,
 				       (unsigned)(hctx->ccid3hctx_x >> 6));
 
@@ -1005,7 +1006,7 @@
 		DCCP_BUG_ON(r_sample < 0);
 		if (unlikely(r_sample <= t_elapsed))
 			DCCP_WARN("r_sample=%ldus, t_elapsed=%ldus\n",
-				  r_sample, t_elapsed);
+				  (long)r_sample, (long)t_elapsed);
 		else
 			r_sample -= t_elapsed;
 		CCID3_RTT_SANITY_CHECK(r_sample);
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 90c74b4..fa2c982 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -72,7 +72,7 @@
 	tmp = ip_route_connect(&rt, nexthop, inet->saddr,
 			       RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
 			       IPPROTO_DCCP,
-			       inet->sport, usin->sin_port, sk);
+			       inet->sport, usin->sin_port, sk, 1);
 	if (tmp < 0)
 		return tmp;
 
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 6b91a9d..79140b3 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -1041,7 +1041,7 @@
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	err = xfrm_lookup(&dst, &fl, sk, 0);
+	err = xfrm_lookup(&dst, &fl, sk, 1);
 	if (err < 0)
 		goto failure;
 
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 63b3fa2..4843856 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -1024,7 +1024,6 @@
 	do {
 		dccp_hashinfo.ehash_size = (1UL << ehash_order) * PAGE_SIZE /
 					sizeof(struct inet_ehash_bucket);
-		dccp_hashinfo.ehash_size >>= 1;
 		while (dccp_hashinfo.ehash_size &
 		       (dccp_hashinfo.ehash_size - 1))
 			dccp_hashinfo.ehash_size--;
@@ -1037,9 +1036,10 @@
 		goto out_free_bind_bucket_cachep;
 	}
 
-	for (i = 0; i < (dccp_hashinfo.ehash_size << 1); i++) {
+	for (i = 0; i < dccp_hashinfo.ehash_size; i++) {
 		rwlock_init(&dccp_hashinfo.ehash[i].lock);
 		INIT_HLIST_HEAD(&dccp_hashinfo.ehash[i].chain);
+		INIT_HLIST_HEAD(&dccp_hashinfo.ehash[i].twchain);
 	}
 
 	bhash_order = ehash_order;
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index ed083ab..90b3dfd 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -749,7 +749,7 @@
 
 	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags);
 	if (nlh == NULL)
-		return -ENOBUFS;
+		return -EMSGSIZE;
 
 	ifm = nlmsg_data(nlh);
 	ifm->ifa_family = AF_DECnet;
@@ -768,7 +768,8 @@
 	return nlmsg_end(skb, nlh);
 
 nla_put_failure:
-	return nlmsg_cancel(skb, nlh);
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
 }
 
 static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa)
@@ -781,9 +782,12 @@
 		goto errout;
 
 	err = dn_nl_fill_ifaddr(skb, ifa, 0, 0, event, 0);
-	/* failure implies BUG in dn_ifaddr_nlmsg_size() */
-	BUG_ON(err < 0);
-
+	if (err < 0) {
+		/* -EMSGSIZE implies BUG in dn_ifaddr_nlmsg_size() */
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(skb);
+		goto errout;
+	}
 	err = rtnl_notify(skb, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL);
 errout:
 	if (err < 0)
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c
index 13b2421..c1f0cc1 100644
--- a/net/decnet/dn_table.c
+++ b/net/decnet/dn_table.c
@@ -350,7 +350,7 @@
 nlmsg_failure:
 rtattr_failure:
         skb_trim(skb, b - skb->data);
-        return -1;
+        return -EMSGSIZE;
 }
 
 
@@ -368,9 +368,12 @@
         err = dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id,
 			       f->fn_type, f->fn_scope, &f->fn_key, z,
 			       DN_FIB_INFO(f), 0);
-	/* failure implies BUG in dn_fib_nlmsg_size() */
-	BUG_ON(err < 0);
-
+	if (err < 0) {
+		/* -EMSGSIZE implies BUG in dn_fib_nlmsg_size() */
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(skb);
+		goto errout;
+	}
 	err = rtnl_notify(skb, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
 errout:
 	if (err < 0)
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
index fa2f7da..fb58e03 100644
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -265,6 +265,12 @@
 	int err = -EINVAL;
 
 	spin_lock_irqsave(&mac->lock, flags);
+
+	if (unlikely(!mac->running)) {
+		err = -ENODEV;
+		goto out_unlock;
+	}
+
 	switch (mac->txrates.default_rate) {
 	case IEEE80211_CCK_RATE_1MB:
 		data->bitrate.value = 1000000;
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 8640096..5750a2b 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1007,7 +1007,7 @@
 			       RT_CONN_FLAGS(sk),
 			       sk->sk_bound_dev_if,
 			       sk->sk_protocol,
-			       inet->sport, inet->dport, sk);
+			       inet->sport, inet->dport, sk, 0);
 	if (err)
 		return err;
 
diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c
index 7b068a8..0072d79 100644
--- a/net/ipv4/datagram.c
+++ b/net/ipv4/datagram.c
@@ -49,7 +49,7 @@
 	err = ip_route_connect(&rt, usin->sin_addr.s_addr, saddr,
 			       RT_CONN_FLAGS(sk), oif,
 			       sk->sk_protocol,
-			       inet->sport, usin->sin_port, sk);
+			       inet->sport, usin->sin_port, sk, 1);
 	if (err)
 		return err;
 	if ((rt->rt_flags & RTCF_BROADCAST) && !sock_flag(sk, SOCK_BROADCAST)) {
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 480ace9..c402036 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1140,7 +1140,7 @@
 
 	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags);
 	if (nlh == NULL)
-		return -ENOBUFS;
+		return -EMSGSIZE;
 
 	ifm = nlmsg_data(nlh);
 	ifm->ifa_family = AF_INET;
@@ -1167,7 +1167,8 @@
 	return nlmsg_end(skb, nlh);
 
 nla_put_failure:
-	return nlmsg_cancel(skb, nlh);
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
 }
 
 static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
@@ -1225,9 +1226,12 @@
 		goto errout;
 
 	err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0);
-	/* failure implies BUG in inet_nlmsg_size() */
-	BUG_ON(err < 0);
-
+	if (err < 0) {
+		/* -EMSGSIZE implies BUG in inet_nlmsg_size() */
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(skb);
+		goto errout;
+	}
 	err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
 errout:
 	if (err < 0)
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index e63b8a9..be1028c 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -314,9 +314,12 @@
 	err = fib_dump_info(skb, info->pid, seq, event, tb_id,
 			    fa->fa_type, fa->fa_scope, key, dst_len,
 			    fa->fa_tos, fa->fa_info, 0);
-	/* failure implies BUG in fib_nlmsg_size() */
-	BUG_ON(err < 0);
-
+	if (err < 0) {
+		/* -EMSGSIZE implies BUG in fib_nlmsg_size() */
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(skb);
+		goto errout;
+	}
 	err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE,
 			  info->nlh, GFP_KERNEL);
 errout:
@@ -960,7 +963,7 @@
 
 	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*rtm), flags);
 	if (nlh == NULL)
-		return -ENOBUFS;
+		return -EMSGSIZE;
 
 	rtm = nlmsg_data(nlh);
 	rtm->rtm_family = AF_INET;
@@ -1031,7 +1034,8 @@
 	return nlmsg_end(skb, nlh);
 
 nla_put_failure:
-	return nlmsg_cancel(skb, nlh);
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
 }
 
 /*
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 0017ccb..024ae56 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -455,6 +455,8 @@
 			skb = add_grhead(skb, pmc, type, &pgr);
 			first = 0;
 		}
+		if (!skb)
+			return NULL;
 		psrc = (__be32 *)skb_put(skb, sizeof(__be32));
 		*psrc = psf->sf_inaddr;
 		scount++; stotal++;
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 77761ac..8aa7d51 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -153,7 +153,7 @@
 rtattr_failure:
 nlmsg_failure:
 	skb_trim(skb, b - skb->data);
-	return -1;
+	return -EMSGSIZE;
 }
 
 static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
@@ -209,7 +209,7 @@
 	return skb->len;
 nlmsg_failure:
 	skb_trim(skb, previous_tail - skb->data);
-	return -1;
+	return -EMSGSIZE;
 }
 
 static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
@@ -274,11 +274,14 @@
 	if (!rep)
 		goto out;
 
-	if (sk_diag_fill(sk, rep, req->idiag_ext,
-			 NETLINK_CB(in_skb).pid,
-			 nlh->nlmsg_seq, 0, nlh) <= 0)
-		BUG();
-
+	err = sk_diag_fill(sk, rep, req->idiag_ext,
+			   NETLINK_CB(in_skb).pid,
+			   nlh->nlmsg_seq, 0, nlh);
+	if (err < 0) {
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(rep);
+		goto out;
+	}
 	err = netlink_unicast(idiagnl, rep, NETLINK_CB(in_skb).pid,
 			      MSG_DONTWAIT);
 	if (err > 0)
@@ -775,7 +778,7 @@
 			struct inet_timewait_sock *tw;
 
 			inet_twsk_for_each(tw, node,
-				    &hashinfo->ehash[i + hashinfo->ehash_size].chain) {
+				    &head->twchain) {
 
 				if (num < s_num)
 					goto next_dying;
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 8c79c8a..150ace1 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -212,7 +212,7 @@
 	write_lock(&head->lock);
 
 	/* Check TIME-WAIT sockets first. */
-	sk_for_each(sk2, node, &(head + hinfo->ehash_size)->chain) {
+	sk_for_each(sk2, node, &head->twchain) {
 		tw = inet_twsk(sk2);
 
 		if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) {
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index 9f414e3..a73cf93 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -78,8 +78,8 @@
 	if (__sk_del_node_init(sk))
 		sock_prot_dec_use(sk->sk_prot);
 
-	/* Step 3: Hash TW into TIMEWAIT half of established hash table. */
-	inet_twsk_add_node(tw, &(ehead + hashinfo->ehash_size)->chain);
+	/* Step 3: Hash TW into TIMEWAIT chain. */
+	inet_twsk_add_node(tw, &ehead->twchain);
 	atomic_inc(&tw->tw_refcnt);
 
 	write_unlock(&ehead->lock);
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 476cb60..51c8350 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -1008,7 +1008,8 @@
 				goto done;
 			dev = t->dev;
 		}
-		err = unregister_netdevice(dev);
+		unregister_netdevice(dev);
+		err = 0;
 		break;
 
 	default:
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 9d719d6..da8bbd2 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -754,7 +754,8 @@
 				goto done;
 			dev = t->dev;
 		}
-		err = unregister_netdevice(dev);
+		unregister_netdevice(dev);
+		err = 0;
 		break;
 
 	default:
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 47bd3ad1..9b08e7a 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -361,32 +361,6 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_TARGET_TCPMSS
-	tristate "TCPMSS target support"
-	depends on IP_NF_IPTABLES
-	---help---
-	  This option adds a `TCPMSS' target, which allows you to alter the
-	  MSS value of TCP SYN packets, to control the maximum size for that
-	  connection (usually limiting it to your outgoing interface's MTU
-	  minus 40).
-
-	  This is used to overcome criminally braindead ISPs or servers which
-	  block ICMP Fragmentation Needed packets.  The symptoms of this
-	  problem are that everything works fine from your Linux
-	  firewall/router, but machines behind it can never exchange large
-	  packets:
-	  	1) Web browsers connect, then hang with no data received.
-	  	2) Small mail works fine, but large emails hang.
-	  	3) ssh works fine, but scp hangs after initial handshaking.
-
-	  Workaround: activate this option and add a rule to your firewall
-	  configuration like:
-
-	  iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-	  		 -j TCPMSS --clamp-mss-to-pmtu
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 # NAT + specific targets: ip_conntrack
 config IP_NF_NAT
 	tristate "Full NAT"
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 16d177b..6625ec6 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -103,7 +103,6 @@
 obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
 obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
 obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
-obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
 obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
 obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
 
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
index 06e4e8a..c34f48f 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
@@ -50,12 +50,9 @@
     If it's non-zero, we mark only out of window RST segments as INVALID. */
 int ip_ct_tcp_be_liberal __read_mostly = 0;
 
-/* When connection is picked up from the middle, how many packets are required
-   to pass in each direction when we assume we are in sync - if any side uses
-   window scaling, we lost the game. 
-   If it is set to zero, we disable picking up already established 
+/* If it is set to zero, we disable picking up already established
    connections. */
-int ip_ct_tcp_loose __read_mostly = 3;
+int ip_ct_tcp_loose __read_mostly = 1;
 
 /* Max number of the retransmitted packets without receiving an (acceptable) 
    ACK from the destination. If this number is reached, a shorter timer 
@@ -694,11 +691,10 @@
 	    	before(sack, receiver->td_end + 1),
 	    	after(ack, receiver->td_end - MAXACKWINDOW(sender)));
 	
-	if (sender->loose || receiver->loose ||
-	    (before(seq, sender->td_maxend + 1) &&
-	     after(end, sender->td_end - receiver->td_maxwin - 1) &&
-	     before(sack, receiver->td_end + 1) &&
-	     after(ack, receiver->td_end - MAXACKWINDOW(sender)))) {
+	if (before(seq, sender->td_maxend + 1) &&
+	    after(end, sender->td_end - receiver->td_maxwin - 1) &&
+	    before(sack, receiver->td_end + 1) &&
+	    after(ack, receiver->td_end - MAXACKWINDOW(sender))) {
 	    	/*
 		 * Take into account window scaling (RFC 1323).
 		 */
@@ -743,15 +739,13 @@
 				state->retrans = 0;
 			}
 		}
-		/*
-		 * Close the window of disabled window tracking :-)
-		 */
-		if (sender->loose)
-			sender->loose--;
-		
 		res = 1;
 	} else {
-		if (LOG_INVALID(IPPROTO_TCP))
+		res = 0;
+		if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL ||
+		    ip_ct_tcp_be_liberal)
+			res = 1;
+		if (!res && LOG_INVALID(IPPROTO_TCP))
 			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
 			"ip_ct_tcp: %s ",
 			before(seq, sender->td_maxend + 1) ?
@@ -762,8 +756,6 @@
 			: "ACK is over the upper bound (ACKed data not seen yet)"
 			: "SEQ is under the lower bound (already ACKed data retransmitted)"
 			: "SEQ is over the upper bound (over the window of the receiver)");
-
-		res = ip_ct_tcp_be_liberal;
   	}
   
 	DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u "
@@ -1105,8 +1097,6 @@
 
 		tcp_options(skb, iph, th, &conntrack->proto.tcp.seen[0]);
 		conntrack->proto.tcp.seen[1].flags = 0;
-		conntrack->proto.tcp.seen[0].loose = 
-		conntrack->proto.tcp.seen[1].loose = 0;
 	} else if (ip_ct_tcp_loose == 0) {
 		/* Don't try to pick up connections. */
 		return 0;
@@ -1127,11 +1117,11 @@
 			conntrack->proto.tcp.seen[0].td_maxwin;
 		conntrack->proto.tcp.seen[0].td_scale = 0;
 
-		/* We assume SACK. Should we assume window scaling too? */
+		/* We assume SACK and liberal window checking to handle
+		 * window scaling */
 		conntrack->proto.tcp.seen[0].flags =
-		conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM;
-		conntrack->proto.tcp.seen[0].loose = 
-		conntrack->proto.tcp.seen[1].loose = ip_ct_tcp_loose;
+		conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM |
+						     IP_CT_TCP_FLAG_BE_LIBERAL;
 	}
     
 	conntrack->proto.tcp.seen[1].td_end = 0;
diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c
index 9d1a517..5e08c2b 100644
--- a/net/ipv4/netfilter/ip_nat_core.c
+++ b/net/ipv4/netfilter/ip_nat_core.c
@@ -246,8 +246,9 @@
 	if (maniptype == IP_NAT_MANIP_SRC) {
 		if (find_appropriate_src(orig_tuple, tuple, range)) {
 			DEBUGP("get_unique_tuple: Found current src map\n");
-			if (!ip_nat_used_tuple(tuple, conntrack))
-				return;
+			if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM))
+				if (!ip_nat_used_tuple(tuple, conntrack))
+					return;
 		}
 	}
 
@@ -261,6 +262,13 @@
 
 	proto = ip_nat_proto_find_get(orig_tuple->dst.protonum);
 
+	/* Change protocol info to have some randomization */
+	if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) {
+		proto->unique_tuple(tuple, range, maniptype, conntrack);
+		ip_nat_proto_put(proto);
+		return;
+	}
+
 	/* Only bother mapping if it's not already in range and unique */
 	if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)
 	     || proto->in_range(tuple, maniptype, &range->min, &range->max))
diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c
index ee80feb..2e5c4bc 100644
--- a/net/ipv4/netfilter/ip_nat_helper.c
+++ b/net/ipv4/netfilter/ip_nat_helper.c
@@ -183,7 +183,7 @@
 	datalen = (*pskb)->len - iph->ihl*4;
 	if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
 		tcph->check = 0;
-		tcph->check = tcp_v4_check(tcph, datalen,
+		tcph->check = tcp_v4_check(datalen,
 					   iph->saddr, iph->daddr,
 					   csum_partial((char *)tcph,
 					   		datalen, 0));
diff --git a/net/ipv4/netfilter/ip_nat_proto_tcp.c b/net/ipv4/netfilter/ip_nat_proto_tcp.c
index b586d18..14ff24f 100644
--- a/net/ipv4/netfilter/ip_nat_proto_tcp.c
+++ b/net/ipv4/netfilter/ip_nat_proto_tcp.c
@@ -8,6 +8,7 @@
 
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/random.h>
 #include <linux/netfilter.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
@@ -75,6 +76,10 @@
 		range_size = ntohs(range->max.tcp.port) - min + 1;
 	}
 
+	/* Start from random port to avoid prediction */
+	if (range->flags & IP_NAT_RANGE_PROTO_RANDOM)
+		port =  net_random();
+
 	for (i = 0; i < range_size; i++, port++) {
 		*portptr = htons(min + port % range_size);
 		if (!ip_nat_used_tuple(tuple, conntrack)) {
diff --git a/net/ipv4/netfilter/ip_nat_proto_udp.c b/net/ipv4/netfilter/ip_nat_proto_udp.c
index 5ced087..dfd5216 100644
--- a/net/ipv4/netfilter/ip_nat_proto_udp.c
+++ b/net/ipv4/netfilter/ip_nat_proto_udp.c
@@ -8,6 +8,7 @@
 
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/random.h>
 #include <linux/netfilter.h>
 #include <linux/ip.h>
 #include <linux/udp.h>
@@ -74,6 +75,10 @@
 		range_size = ntohs(range->max.udp.port) - min + 1;
 	}
 
+	/* Start from random port to avoid prediction */
+	if (range->flags & IP_NAT_RANGE_PROTO_RANDOM)
+		port = net_random();
+
 	for (i = 0; i < range_size; i++, port++) {
 		*portptr = htons(min + port % range_size);
 		if (!ip_nat_used_tuple(tuple, conntrack))
diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c
index a176aa3..e1c8a05 100644
--- a/net/ipv4/netfilter/ip_nat_rule.c
+++ b/net/ipv4/netfilter/ip_nat_rule.c
@@ -86,7 +86,7 @@
     }
 };
 
-static struct ipt_table nat_table = {
+static struct xt_table nat_table = {
 	.name		= "nat",
 	.valid_hooks	= NAT_VALID_HOOKS,
 	.lock		= RW_LOCK_UNLOCKED,
@@ -99,7 +99,7 @@
 				    const struct net_device *in,
 				    const struct net_device *out,
 				    unsigned int hooknum,
-				    const struct ipt_target *target,
+				    const struct xt_target *target,
 				    const void *targinfo)
 {
 	struct ip_conntrack *ct;
@@ -141,7 +141,7 @@
 				    const struct net_device *in,
 				    const struct net_device *out,
 				    unsigned int hooknum,
-				    const struct ipt_target *target,
+				    const struct xt_target *target,
 				    const void *targinfo)
 {
 	struct ip_conntrack *ct;
@@ -166,7 +166,7 @@
 
 static int ipt_snat_checkentry(const char *tablename,
 			       const void *entry,
-			       const struct ipt_target *target,
+			       const struct xt_target *target,
 			       void *targinfo,
 			       unsigned int hook_mask)
 {
@@ -182,7 +182,7 @@
 
 static int ipt_dnat_checkentry(const char *tablename,
 			       const void *entry,
-			       const struct ipt_target *target,
+			       const struct xt_target *target,
 			       void *targinfo,
 			       unsigned int hook_mask)
 {
@@ -193,6 +193,10 @@
 		printk("DNAT: multiple ranges no longer supported\n");
 		return 0;
 	}
+	if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) {
+		printk("DNAT: port randomization not supported\n");
+		return 0;
+	}
 	return 1;
 }
 
@@ -257,8 +261,9 @@
 	return ret;
 }
 
-static struct ipt_target ipt_snat_reg = {
+static struct xt_target ipt_snat_reg = {
 	.name		= "SNAT",
+	.family		= AF_INET,
 	.target		= ipt_snat_target,
 	.targetsize	= sizeof(struct ip_nat_multi_range_compat),
 	.table		= "nat",
@@ -266,8 +271,9 @@
 	.checkentry	= ipt_snat_checkentry,
 };
 
-static struct ipt_target ipt_dnat_reg = {
+static struct xt_target ipt_dnat_reg = {
 	.name		= "DNAT",
+	.family		= AF_INET,
 	.target		= ipt_dnat_target,
 	.targetsize	= sizeof(struct ip_nat_multi_range_compat),
 	.table		= "nat",
@@ -282,27 +288,27 @@
 	ret = ipt_register_table(&nat_table, &nat_initial_table.repl);
 	if (ret != 0)
 		return ret;
-	ret = ipt_register_target(&ipt_snat_reg);
+	ret = xt_register_target(&ipt_snat_reg);
 	if (ret != 0)
 		goto unregister_table;
 
-	ret = ipt_register_target(&ipt_dnat_reg);
+	ret = xt_register_target(&ipt_dnat_reg);
 	if (ret != 0)
 		goto unregister_snat;
 
 	return ret;
 
  unregister_snat:
-	ipt_unregister_target(&ipt_snat_reg);
+	xt_unregister_target(&ipt_snat_reg);
  unregister_table:
-	ipt_unregister_table(&nat_table);
+	xt_unregister_table(&nat_table);
 
 	return ret;
 }
 
 void ip_nat_rule_cleanup(void)
 {
-	ipt_unregister_target(&ipt_dnat_reg);
-	ipt_unregister_target(&ipt_snat_reg);
+	xt_unregister_target(&ipt_dnat_reg);
+	xt_unregister_target(&ipt_snat_reg);
 	ipt_unregister_table(&nat_table);
 }
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index fc1f153..5a7b3a3 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -216,7 +216,7 @@
 	     unsigned int hook,
 	     const struct net_device *in,
 	     const struct net_device *out,
-	     struct ipt_table *table)
+	     struct xt_table *table)
 {
 	static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
 	u_int16_t offset;
@@ -507,7 +507,7 @@
 static inline int check_match(struct ipt_entry_match *m, const char *name,
 				const struct ipt_ip *ip, unsigned int hookmask)
 {
-	struct ipt_match *match;
+	struct xt_match *match;
 	int ret;
 
 	match = m->u.kernel.match;
@@ -531,7 +531,7 @@
 	    unsigned int hookmask,
 	    unsigned int *i)
 {
-	struct ipt_match *match;
+	struct xt_match *match;
 	int ret;
 
 	match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
@@ -557,7 +557,7 @@
 static inline int check_target(struct ipt_entry *e, const char *name)
 {
  	struct ipt_entry_target *t;
- 	struct ipt_target *target;
+	struct xt_target *target;
  	int ret;
 
 	t = ipt_get_target(e);
@@ -580,7 +580,7 @@
 	    unsigned int *i)
 {
 	struct ipt_entry_target *t;
-	struct ipt_target *target;
+	struct xt_target *target;
 	int ret;
 	unsigned int j;
 
@@ -818,7 +818,7 @@
 	}
 }
 
-static inline struct xt_counters * alloc_counters(struct ipt_table *table)
+static inline struct xt_counters * alloc_counters(struct xt_table *table)
 {
 	unsigned int countersize;
 	struct xt_counters *counters;
@@ -843,7 +843,7 @@
 
 static int
 copy_entries_to_user(unsigned int total_size,
-		     struct ipt_table *table,
+		     struct xt_table *table,
 		     void __user *userptr)
 {
 	unsigned int off, num;
@@ -1046,7 +1046,7 @@
 static int get_info(void __user *user, int *len, int compat)
 {
 	char name[IPT_TABLE_MAXNAMELEN];
-	struct ipt_table *t;
+	struct xt_table *t;
 	int ret;
 
 	if (*len != sizeof(struct ipt_getinfo)) {
@@ -1107,7 +1107,7 @@
 {
 	int ret;
 	struct ipt_get_entries get;
-	struct ipt_table *t;
+	struct xt_table *t;
 
 	if (*len < sizeof(get)) {
 		duprintf("get_entries: %u < %d\n", *len,
@@ -1151,7 +1151,7 @@
 		void __user *counters_ptr)
 {
 	int ret;
-	struct ipt_table *t;
+	struct xt_table *t;
 	struct xt_table_info *oldinfo;
 	struct xt_counters *counters;
 	void *loc_cpu_old_entry;
@@ -1302,7 +1302,7 @@
 	char *name;
 	int size;
 	void *ptmp;
-	struct ipt_table *t;
+	struct xt_table *t;
 	struct xt_table_info *private;
 	int ret = 0;
 	void *loc_cpu_entry;
@@ -1437,7 +1437,7 @@
 	    unsigned int hookmask,
 	    int *size, int *i)
 {
-	struct ipt_match *match;
+	struct xt_match *match;
 
 	match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
 						   m->u.user.revision),
@@ -1466,7 +1466,7 @@
 			   const char *name)
 {
 	struct ipt_entry_target *t;
-	struct ipt_target *target;
+	struct xt_target *target;
 	unsigned int entry_offset;
 	int ret, off, h, j;
 
@@ -1550,7 +1550,7 @@
 	struct xt_table_info *newinfo, unsigned char *base)
 {
 	struct ipt_entry_target *t;
-	struct ipt_target *target;
+	struct xt_target *target;
 	struct ipt_entry *de;
 	unsigned int origsize;
 	int ret, h;
@@ -1795,7 +1795,7 @@
 };
 
 static int compat_copy_entries_to_user(unsigned int total_size,
-		     struct ipt_table *table, void __user *userptr)
+		     struct xt_table *table, void __user *userptr)
 {
 	unsigned int off, num;
 	struct compat_ipt_entry e;
@@ -1869,7 +1869,7 @@
 {
 	int ret;
 	struct compat_ipt_get_entries get;
-	struct ipt_table *t;
+	struct xt_table *t;
 
 
 	if (*len < sizeof(get)) {
@@ -2052,7 +2052,7 @@
 	return 0;
 }
 
-void ipt_unregister_table(struct ipt_table *table)
+void ipt_unregister_table(struct xt_table *table)
 {
 	struct xt_table_info *private;
 	void *loc_cpu_entry;
@@ -2124,7 +2124,7 @@
 }
 
 /* The built-in targets: standard (NULL) and error. */
-static struct ipt_target ipt_standard_target = {
+static struct xt_target ipt_standard_target = {
 	.name		= IPT_STANDARD_TARGET,
 	.targetsize	= sizeof(int),
 	.family		= AF_INET,
@@ -2135,7 +2135,7 @@
 #endif
 };
 
-static struct ipt_target ipt_error_target = {
+static struct xt_target ipt_error_target = {
 	.name		= IPT_ERROR_TARGET,
 	.target		= ipt_error,
 	.targetsize	= IPT_FUNCTION_MAXNAMELEN,
@@ -2158,7 +2158,7 @@
 #endif
 };
 
-static struct ipt_match icmp_matchstruct = {
+static struct xt_match icmp_matchstruct = {
 	.name		= "icmp",
 	.match		= icmp_match,
 	.matchsize	= sizeof(struct ipt_icmp),
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index b1c1116..343c2ab 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -26,6 +26,7 @@
 
 #include <linux/netfilter_arp.h>
 
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_CLUSTERIP.h>
 #include <net/netfilter/nf_conntrack_compat.h>
@@ -247,6 +248,7 @@
 	switch (iph->protocol) {
 	case IPPROTO_TCP:
 	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE:
 	case IPPROTO_SCTP:
 	case IPPROTO_DCCP:
 	case IPPROTO_ICMP:
@@ -329,7 +331,7 @@
 	if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
 	    && (ctinfo == IP_CT_RELATED 
 		|| ctinfo == IP_CT_RELATED+IP_CT_IS_REPLY))
-		return IPT_CONTINUE;
+		return XT_CONTINUE;
 
 	/* ip_conntrack_icmp guarantees us that we only have ICMP_ECHO, 
 	 * TIMESTAMP, INFO_REQUEST or ADDRESS type icmp packets from here
@@ -367,7 +369,7 @@
 	 * actually a unicast IP packet. TCP doesn't like PACKET_MULTICAST */
 	(*pskb)->pkt_type = PACKET_HOST;
 
-	return IPT_CONTINUE;
+	return XT_CONTINUE;
 }
 
 static int
@@ -470,8 +472,9 @@
 	nf_ct_l3proto_module_put(target->family);
 }
 
-static struct ipt_target clusterip_tgt = {
+static struct xt_target clusterip_tgt = {
 	.name		= "CLUSTERIP",
+	.family		= AF_INET,
 	.target		= target,
 	.targetsize	= sizeof(struct ipt_clusterip_tgt_info),
 	.checkentry	= checkentry,
@@ -727,7 +730,7 @@
 {
 	int ret;
 
-	ret = ipt_register_target(&clusterip_tgt);
+	ret = xt_register_target(&clusterip_tgt);
 	if (ret < 0)
 		return ret;
 
@@ -753,7 +756,7 @@
 	nf_unregister_hook(&cip_arp_ops);
 #endif /* CONFIG_PROC_FS */
 cleanup_target:
-	ipt_unregister_target(&clusterip_tgt);
+	xt_unregister_target(&clusterip_tgt);
 	return ret;
 }
 
@@ -765,7 +768,7 @@
 	remove_proc_entry(clusterip_procdir->name, clusterip_procdir->parent);
 #endif
 	nf_unregister_hook(&cip_arp_ops);
-	ipt_unregister_target(&clusterip_tgt);
+	xt_unregister_target(&clusterip_tgt);
 }
 
 module_init(ipt_clusterip_init);
diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c
index b55d670..b5ca593 100644
--- a/net/ipv4/netfilter/ipt_ECN.c
+++ b/net/ipv4/netfilter/ipt_ECN.c
@@ -9,12 +9,14 @@
  * ipt_ECN.c,v 1.5 2002/08/18 19:36:51 laforge Exp
 */
 
+#include <linux/in.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <net/checksum.h>
 
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_ECN.h>
 
@@ -95,7 +97,7 @@
 		if (!set_ect_tcp(pskb, einfo))
 			return NF_DROP;
 
-	return IPT_CONTINUE;
+	return XT_CONTINUE;
 }
 
 static int
@@ -119,7 +121,7 @@
 		return 0;
 	}
 	if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR))
-	    && (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & IPT_INV_PROTO))) {
+	    && (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & XT_INV_PROTO))) {
 		printk(KERN_WARNING "ECN: cannot use TCP operations on a "
 		       "non-tcp rule\n");
 		return 0;
@@ -127,8 +129,9 @@
 	return 1;
 }
 
-static struct ipt_target ipt_ecn_reg = {
+static struct xt_target ipt_ecn_reg = {
 	.name		= "ECN",
+	.family		= AF_INET,
 	.target		= target,
 	.targetsize	= sizeof(struct ipt_ECN_info),
 	.table		= "mangle",
@@ -138,12 +141,12 @@
 
 static int __init ipt_ecn_init(void)
 {
-	return ipt_register_target(&ipt_ecn_reg);
+	return xt_register_target(&ipt_ecn_reg);
 }
 
 static void __exit ipt_ecn_fini(void)
 {
-	ipt_unregister_target(&ipt_ecn_reg);
+	xt_unregister_target(&ipt_ecn_reg);
 }
 
 module_init(ipt_ecn_init);
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
index c96de16..f68370f 100644
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -20,7 +20,7 @@
 #include <net/route.h>
 
 #include <linux/netfilter.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv4/ipt_LOG.h>
 
 MODULE_LICENSE("GPL");
@@ -432,7 +432,7 @@
 
 	ipt_log_packet(PF_INET, hooknum, *pskb, in, out, &li,
 	               loginfo->prefix);
-	return IPT_CONTINUE;
+	return XT_CONTINUE;
 }
 
 static int ipt_log_checkentry(const char *tablename,
@@ -455,8 +455,9 @@
 	return 1;
 }
 
-static struct ipt_target ipt_log_reg = {
+static struct xt_target ipt_log_reg = {
 	.name		= "LOG",
+	.family		= AF_INET,
 	.target		= ipt_log_target,
 	.targetsize	= sizeof(struct ipt_log_info),
 	.checkentry	= ipt_log_checkentry,
@@ -471,8 +472,11 @@
 
 static int __init ipt_log_init(void)
 {
-	if (ipt_register_target(&ipt_log_reg))
-		return -EINVAL;
+	int ret;
+
+	ret = xt_register_target(&ipt_log_reg);
+	if (ret < 0)
+		return ret;
 	if (nf_log_register(PF_INET, &ipt_log_logger) < 0) {
 		printk(KERN_WARNING "ipt_LOG: not logging via system console "
 		       "since somebody else already registered for PF_INET\n");
@@ -486,7 +490,7 @@
 static void __exit ipt_log_fini(void)
 {
 	nf_log_unregister_logger(&ipt_log_logger);
-	ipt_unregister_target(&ipt_log_reg);
+	xt_unregister_target(&ipt_log_reg);
 }
 
 module_init(ipt_log_init);
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
index d669685..91c42ef 100644
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
@@ -25,7 +25,7 @@
 #else
 #include <linux/netfilter_ipv4/ip_nat_rule.h>
 #endif
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
@@ -190,8 +190,9 @@
 	.notifier_call	= masq_inet_event,
 };
 
-static struct ipt_target masquerade = {
+static struct xt_target masquerade = {
 	.name		= "MASQUERADE",
+	.family		= AF_INET,
 	.target		= masquerade_target,
 	.targetsize	= sizeof(struct ip_nat_multi_range_compat),
 	.table		= "nat",
@@ -204,7 +205,7 @@
 {
 	int ret;
 
-	ret = ipt_register_target(&masquerade);
+	ret = xt_register_target(&masquerade);
 
 	if (ret == 0) {
 		/* Register for device down reports */
@@ -218,7 +219,7 @@
 
 static void __exit ipt_masquerade_fini(void)
 {
-	ipt_unregister_target(&masquerade);
+	xt_unregister_target(&masquerade);
 	unregister_netdevice_notifier(&masq_dev_notifier);
 	unregister_inetaddr_notifier(&masq_inet_notifier);	
 }
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c
index 9390e90..b4acc24 100644
--- a/net/ipv4/netfilter/ipt_NETMAP.c
+++ b/net/ipv4/netfilter/ipt_NETMAP.c
@@ -15,6 +15,7 @@
 #include <linux/netdevice.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4.h>
+#include <linux/netfilter/x_tables.h>
 #ifdef CONFIG_NF_NAT_NEEDED
 #include <net/netfilter/nf_nat_rule.h>
 #else
@@ -88,8 +89,9 @@
 	return ip_nat_setup_info(ct, &newrange, hooknum);
 }
 
-static struct ipt_target target_module = { 
+static struct xt_target target_module = {
 	.name 		= MODULENAME,
+	.family		= AF_INET,
 	.target 	= target, 
 	.targetsize	= sizeof(struct ip_nat_multi_range_compat),
 	.table		= "nat",
@@ -101,12 +103,12 @@
 
 static int __init ipt_netmap_init(void)
 {
-	return ipt_register_target(&target_module);
+	return xt_register_target(&target_module);
 }
 
 static void __exit ipt_netmap_fini(void)
 {
-	ipt_unregister_target(&target_module);
+	xt_unregister_target(&target_module);
 }
 
 module_init(ipt_netmap_init);
diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c
index 462eceb..54cd021 100644
--- a/net/ipv4/netfilter/ipt_REDIRECT.c
+++ b/net/ipv4/netfilter/ipt_REDIRECT.c
@@ -18,6 +18,7 @@
 #include <net/protocol.h>
 #include <net/checksum.h>
 #include <linux/netfilter_ipv4.h>
+#include <linux/netfilter/x_tables.h>
 #ifdef CONFIG_NF_NAT_NEEDED
 #include <net/netfilter/nf_nat_rule.h>
 #else
@@ -104,8 +105,9 @@
 	return ip_nat_setup_info(ct, &newrange, hooknum);
 }
 
-static struct ipt_target redirect_reg = {
+static struct xt_target redirect_reg = {
 	.name		= "REDIRECT",
+	.family		= AF_INET,
 	.target		= redirect_target,
 	.targetsize	= sizeof(struct ip_nat_multi_range_compat),
 	.table		= "nat",
@@ -116,12 +118,12 @@
 
 static int __init ipt_redirect_init(void)
 {
-	return ipt_register_target(&redirect_reg);
+	return xt_register_target(&redirect_reg);
 }
 
 static void __exit ipt_redirect_fini(void)
 {
-	ipt_unregister_target(&redirect_reg);
+	xt_unregister_target(&redirect_reg);
 }
 
 module_init(ipt_redirect_init);
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index f0319e5..e4a1ddb 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -22,6 +22,7 @@
 #include <net/tcp.h>
 #include <net/route.h>
 #include <net/dst.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_REJECT.h>
 #ifdef CONFIG_BRIDGE_NETFILTER
@@ -116,7 +117,7 @@
 
 	/* Adjust TCP checksum */
 	tcph->check = 0;
-	tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
+	tcph->check = tcp_v4_check(sizeof(struct tcphdr),
 				   nskb->nh.iph->saddr,
 				   nskb->nh.iph->daddr,
 				   csum_partial((char *)tcph,
@@ -230,7 +231,7 @@
 	} else if (rejinfo->with == IPT_TCP_RESET) {
 		/* Must specify that it's a TCP packet */
 		if (e->ip.proto != IPPROTO_TCP
-		    || (e->ip.invflags & IPT_INV_PROTO)) {
+		    || (e->ip.invflags & XT_INV_PROTO)) {
 			DEBUGP("REJECT: TCP_RESET invalid for non-tcp\n");
 			return 0;
 		}
@@ -238,8 +239,9 @@
 	return 1;
 }
 
-static struct ipt_target ipt_reject_reg = {
+static struct xt_target ipt_reject_reg = {
 	.name		= "REJECT",
+	.family		= AF_INET,
 	.target		= reject,
 	.targetsize	= sizeof(struct ipt_reject_info),
 	.table		= "filter",
@@ -251,12 +253,12 @@
 
 static int __init ipt_reject_init(void)
 {
-	return ipt_register_target(&ipt_reject_reg);
+	return xt_register_target(&ipt_reject_reg);
 }
 
 static void __exit ipt_reject_fini(void)
 {
-	ipt_unregister_target(&ipt_reject_reg);
+	xt_unregister_target(&ipt_reject_reg);
 }
 
 module_init(ipt_reject_init);
diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c
index 3dcf294..a1cdd12 100644
--- a/net/ipv4/netfilter/ipt_SAME.c
+++ b/net/ipv4/netfilter/ipt_SAME.c
@@ -34,6 +34,7 @@
 #include <net/protocol.h>
 #include <net/checksum.h>
 #include <linux/netfilter_ipv4.h>
+#include <linux/netfilter/x_tables.h>
 #ifdef CONFIG_NF_NAT_NEEDED
 #include <net/netfilter/nf_nat_rule.h>
 #else
@@ -186,8 +187,9 @@
 	return ip_nat_setup_info(ct, &newrange, hooknum);
 }
 
-static struct ipt_target same_reg = { 
+static struct xt_target same_reg = {
 	.name		= "SAME",
+	.family		= AF_INET,
 	.target		= same_target,
 	.targetsize	= sizeof(struct ipt_same_info),
 	.table		= "nat",
@@ -199,12 +201,12 @@
 
 static int __init ipt_same_init(void)
 {
-	return ipt_register_target(&same_reg);
+	return xt_register_target(&same_reg);
 }
 
 static void __exit ipt_same_fini(void)
 {
-	ipt_unregister_target(&same_reg);
+	xt_unregister_target(&same_reg);
 }
 
 module_init(ipt_same_init);
diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c
deleted file mode 100644
index 93eb5c3..0000000
--- a/net/ipv4/netfilter/ipt_TCPMSS.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * This is a module which is used for setting the MSS option in TCP packets.
- *
- * Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-
-#include <linux/ip.h>
-#include <net/tcp.h>
-
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_TCPMSS.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
-MODULE_DESCRIPTION("iptables TCP MSS modification module");
-
-static inline unsigned int
-optlen(const u_int8_t *opt, unsigned int offset)
-{
-	/* Beware zero-length options: make finite progress */
-	if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0)
-		return 1;
-	else
-		return opt[offset+1];
-}
-
-static unsigned int
-ipt_tcpmss_target(struct sk_buff **pskb,
-		  const struct net_device *in,
-		  const struct net_device *out,
-		  unsigned int hooknum,
-		  const struct xt_target *target,
-		  const void *targinfo)
-{
-	const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
-	struct tcphdr *tcph;
-	struct iphdr *iph;
-	u_int16_t tcplen, newmss;
-	__be16 newtotlen, oldval;
-	unsigned int i;
-	u_int8_t *opt;
-
-	if (!skb_make_writable(pskb, (*pskb)->len))
-		return NF_DROP;
-
-	iph = (*pskb)->nh.iph;
-	tcplen = (*pskb)->len - iph->ihl*4;
-	tcph = (void *)iph + iph->ihl*4;
-
-	/* Since it passed flags test in tcp match, we know it is is
-	   not a fragment, and has data >= tcp header length.  SYN
-	   packets should not contain data: if they did, then we risk
-	   running over MTU, sending Frag Needed and breaking things
-	   badly. --RR */
-	if (tcplen != tcph->doff*4) {
-		if (net_ratelimit())
-			printk(KERN_ERR
-			       "ipt_tcpmss_target: bad length (%d bytes)\n",
-			       (*pskb)->len);
-		return NF_DROP;
-	}
-
-	if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) {
-		if (dst_mtu((*pskb)->dst) <= sizeof(struct iphdr) +
-					     sizeof(struct tcphdr)) {
-			if (net_ratelimit())
-				printk(KERN_ERR "ipt_tcpmss_target: "
-				       "unknown or invalid path-MTU (%d)\n",
-				       dst_mtu((*pskb)->dst));
-			return NF_DROP; /* or IPT_CONTINUE ?? */
-		}
-
-		newmss = dst_mtu((*pskb)->dst) - sizeof(struct iphdr) -
-						 sizeof(struct tcphdr);
-	} else
-		newmss = tcpmssinfo->mss;
-
- 	opt = (u_int8_t *)tcph;
-	for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) {
-		if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS &&
-		    opt[i+1] == TCPOLEN_MSS) {
-			u_int16_t oldmss;
-
-			oldmss = (opt[i+2] << 8) | opt[i+3];
-
-			if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU &&
-			    oldmss <= newmss)
-				return IPT_CONTINUE;
-
-			opt[i+2] = (newmss & 0xff00) >> 8;
-			opt[i+3] = (newmss & 0x00ff);
-
-			nf_proto_csum_replace2(&tcph->check, *pskb,
-						htons(oldmss), htons(newmss), 0);
-			return IPT_CONTINUE;
-		}
-	}
-
-	/*
-	 * MSS Option not found ?! add it..
-	 */
-	if (skb_tailroom((*pskb)) < TCPOLEN_MSS) {
-		struct sk_buff *newskb;
-
-		newskb = skb_copy_expand(*pskb, skb_headroom(*pskb),
-					 TCPOLEN_MSS, GFP_ATOMIC);
-		if (!newskb)
-			return NF_DROP;
-		kfree_skb(*pskb);
-		*pskb = newskb;
-		iph = (*pskb)->nh.iph;
-		tcph = (void *)iph + iph->ihl*4;
-	}
-
-	skb_put((*pskb), TCPOLEN_MSS);
-
- 	opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
-	memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
-
-	nf_proto_csum_replace2(&tcph->check, *pskb,
-				htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1);
-	opt[0] = TCPOPT_MSS;
-	opt[1] = TCPOLEN_MSS;
-	opt[2] = (newmss & 0xff00) >> 8;
-	opt[3] = (newmss & 0x00ff);
-
-	nf_proto_csum_replace4(&tcph->check, *pskb, 0, *((__be32 *)opt), 0);
-
-	oldval = ((__be16 *)tcph)[6];
-	tcph->doff += TCPOLEN_MSS/4;
-	nf_proto_csum_replace2(&tcph->check, *pskb,
-				oldval, ((__be16 *)tcph)[6], 0);
-
-	newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS);
-	nf_csum_replace2(&iph->check, iph->tot_len, newtotlen);
-	iph->tot_len = newtotlen;
-	return IPT_CONTINUE;
-}
-
-#define TH_SYN 0x02
-
-static inline int find_syn_match(const struct ipt_entry_match *m)
-{
-	const struct ipt_tcp *tcpinfo = (const struct ipt_tcp *)m->data;
-
-	if (strcmp(m->u.kernel.match->name, "tcp") == 0 &&
-	    tcpinfo->flg_cmp & TH_SYN &&
-	    !(tcpinfo->invflags & IPT_TCP_INV_FLAGS))
-		return 1;
-
-	return 0;
-}
-
-/* Must specify -p tcp --syn/--tcp-flags SYN */
-static int
-ipt_tcpmss_checkentry(const char *tablename,
-		      const void *e_void,
-		      const struct xt_target *target,
-		      void *targinfo,
-		      unsigned int hook_mask)
-{
-	const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
-	const struct ipt_entry *e = e_void;
-
-	if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU &&
-	    (hook_mask & ~((1 << NF_IP_FORWARD) |
-			   (1 << NF_IP_LOCAL_OUT) |
-			   (1 << NF_IP_POST_ROUTING))) != 0) {
-		printk("TCPMSS: path-MTU clamping only supported in "
-		       "FORWARD, OUTPUT and POSTROUTING hooks\n");
-		return 0;
-	}
-
-	if (IPT_MATCH_ITERATE(e, find_syn_match))
-		return 1;
-	printk("TCPMSS: Only works on TCP SYN packets\n");
-	return 0;
-}
-
-static struct ipt_target ipt_tcpmss_reg = {
-	.name		= "TCPMSS",
-	.target		= ipt_tcpmss_target,
-	.targetsize	= sizeof(struct ipt_tcpmss_info),
-	.proto		= IPPROTO_TCP,
-	.checkentry	= ipt_tcpmss_checkentry,
-	.me		= THIS_MODULE,
-};
-
-static int __init ipt_tcpmss_init(void)
-{
-	return ipt_register_target(&ipt_tcpmss_reg);
-}
-
-static void __exit ipt_tcpmss_fini(void)
-{
-	ipt_unregister_target(&ipt_tcpmss_reg);
-}
-
-module_init(ipt_tcpmss_init);
-module_exit(ipt_tcpmss_fini);
diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c
index 18e74ac..29b05a6 100644
--- a/net/ipv4/netfilter/ipt_TOS.c
+++ b/net/ipv4/netfilter/ipt_TOS.c
@@ -13,7 +13,7 @@
 #include <linux/ip.h>
 #include <net/checksum.h>
 
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv4/ipt_TOS.h>
 
 MODULE_LICENSE("GPL");
@@ -40,7 +40,7 @@
 		iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos;
 		nf_csum_replace2(&iph->check, htons(oldtos), htons(iph->tos));
 	}
-	return IPT_CONTINUE;
+	return XT_CONTINUE;
 }
 
 static int
@@ -63,8 +63,9 @@
 	return 1;
 }
 
-static struct ipt_target ipt_tos_reg = {
+static struct xt_target ipt_tos_reg = {
 	.name		= "TOS",
+	.family		= AF_INET,
 	.target		= target,
 	.targetsize	= sizeof(struct ipt_tos_target_info),
 	.table		= "mangle",
@@ -74,12 +75,12 @@
 
 static int __init ipt_tos_init(void)
 {
-	return ipt_register_target(&ipt_tos_reg);
+	return xt_register_target(&ipt_tos_reg);
 }
 
 static void __exit ipt_tos_fini(void)
 {
-	ipt_unregister_target(&ipt_tos_reg);
+	xt_unregister_target(&ipt_tos_reg);
 }
 
 module_init(ipt_tos_init);
diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c
index fffe5ca..d2b6fa3 100644
--- a/net/ipv4/netfilter/ipt_TTL.c
+++ b/net/ipv4/netfilter/ipt_TTL.c
@@ -12,7 +12,7 @@
 #include <linux/ip.h>
 #include <net/checksum.h>
 
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv4/ipt_TTL.h>
 
 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
@@ -59,7 +59,7 @@
 		iph->ttl = new_ttl;
 	}
 
-	return IPT_CONTINUE;
+	return XT_CONTINUE;
 }
 
 static int ipt_ttl_checkentry(const char *tablename,
@@ -80,8 +80,9 @@
 	return 1;
 }
 
-static struct ipt_target ipt_TTL = { 
+static struct xt_target ipt_TTL = {
 	.name 		= "TTL",
+	.family		= AF_INET,
 	.target 	= ipt_ttl_target, 
 	.targetsize	= sizeof(struct ipt_TTL_info),
 	.table		= "mangle",
@@ -91,12 +92,12 @@
 
 static int __init ipt_ttl_init(void)
 {
-	return ipt_register_target(&ipt_TTL);
+	return xt_register_target(&ipt_TTL);
 }
 
 static void __exit ipt_ttl_fini(void)
 {
-	ipt_unregister_target(&ipt_TTL);
+	xt_unregister_target(&ipt_TTL);
 }
 
 module_init(ipt_ttl_init);
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
index dbd3478..7af57a3 100644
--- a/net/ipv4/netfilter/ipt_ULOG.c
+++ b/net/ipv4/netfilter/ipt_ULOG.c
@@ -57,7 +57,7 @@
 #include <linux/mm.h>
 #include <linux/moduleparam.h>
 #include <linux/netfilter.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv4/ipt_ULOG.h>
 #include <net/sock.h>
 #include <linux/bitops.h>
@@ -132,7 +132,6 @@
 	ub->qlen = 0;
 	ub->skb = NULL;
 	ub->lastnlh = NULL;
-
 }
 
 
@@ -314,7 +313,7 @@
 
 	ipt_ulog_packet(hooknum, *pskb, in, out, loginfo, NULL);
  
- 	return IPT_CONTINUE;
+	return XT_CONTINUE;
 }
  
 static void ipt_logfn(unsigned int pf,
@@ -363,8 +362,9 @@
 	return 1;
 }
 
-static struct ipt_target ipt_ulog_reg = {
+static struct xt_target ipt_ulog_reg = {
 	.name		= "ULOG",
+	.family		= AF_INET,
 	.target		= ipt_ulog_target,
 	.targetsize	= sizeof(struct ipt_ulog_info),
 	.checkentry	= ipt_ulog_checkentry,
@@ -379,7 +379,7 @@
 
 static int __init ipt_ulog_init(void)
 {
-	int i;
+	int ret, i;
 
 	DEBUGP("ipt_ULOG: init module\n");
 
@@ -400,9 +400,10 @@
 	if (!nflognl)
 		return -ENOMEM;
 
-	if (ipt_register_target(&ipt_ulog_reg) != 0) {
+	ret = xt_register_target(&ipt_ulog_reg);
+	if (ret < 0) {
 		sock_release(nflognl->sk_socket);
-		return -EINVAL;
+		return ret;
 	}
 	if (nflog)
 		nf_log_register(PF_INET, &ipt_ulog_logger);
@@ -419,7 +420,7 @@
 
 	if (nflog)
 		nf_log_unregister_logger(&ipt_ulog_logger);
-	ipt_unregister_target(&ipt_ulog_reg);
+	xt_unregister_target(&ipt_ulog_reg);
 	sock_release(nflognl->sk_socket);
 
 	/* remove pending timers and free allocated skb's */
@@ -435,7 +436,6 @@
 			ub->skb = NULL;
 		}
 	}
-
 }
 
 module_init(ipt_ulog_init);
diff --git a/net/ipv4/netfilter/ipt_addrtype.c b/net/ipv4/netfilter/ipt_addrtype.c
index 7b60eb7..648f555 100644
--- a/net/ipv4/netfilter/ipt_addrtype.c
+++ b/net/ipv4/netfilter/ipt_addrtype.c
@@ -16,7 +16,7 @@
 #include <net/route.h>
 
 #include <linux/netfilter_ipv4/ipt_addrtype.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
@@ -44,8 +44,9 @@
 	return ret;
 }
 
-static struct ipt_match addrtype_match = {
+static struct xt_match addrtype_match = {
 	.name		= "addrtype",
+	.family		= AF_INET,
 	.match		= match,
 	.matchsize	= sizeof(struct ipt_addrtype_info),
 	.me		= THIS_MODULE
@@ -53,12 +54,12 @@
 
 static int __init ipt_addrtype_init(void)
 {
-	return ipt_register_match(&addrtype_match);
+	return xt_register_match(&addrtype_match);
 }
 
 static void __exit ipt_addrtype_fini(void)
 {
-	ipt_unregister_match(&addrtype_match);
+	xt_unregister_match(&addrtype_match);
 }
 
 module_init(ipt_addrtype_init);
diff --git a/net/ipv4/netfilter/ipt_ah.c b/net/ipv4/netfilter/ipt_ah.c
index 1798f86..42f4122 100644
--- a/net/ipv4/netfilter/ipt_ah.c
+++ b/net/ipv4/netfilter/ipt_ah.c
@@ -6,12 +6,13 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/in.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
 
 #include <linux/netfilter_ipv4/ipt_ah.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Yon Uriarte <yon@astaro.de>");
@@ -86,8 +87,9 @@
 	return 1;
 }
 
-static struct ipt_match ah_match = {
+static struct xt_match ah_match = {
 	.name		= "ah",
+	.family		= AF_INET,
 	.match		= match,
 	.matchsize	= sizeof(struct ipt_ah),
 	.proto		= IPPROTO_AH,
@@ -97,12 +99,12 @@
 
 static int __init ipt_ah_init(void)
 {
-	return ipt_register_match(&ah_match);
+	return xt_register_match(&ah_match);
 }
 
 static void __exit ipt_ah_fini(void)
 {
-	ipt_unregister_match(&ah_match);
+	xt_unregister_match(&ah_match);
 }
 
 module_init(ipt_ah_init);
diff --git a/net/ipv4/netfilter/ipt_ecn.c b/net/ipv4/netfilter/ipt_ecn.c
index dafbdec..37508b2 100644
--- a/net/ipv4/netfilter/ipt_ecn.c
+++ b/net/ipv4/netfilter/ipt_ecn.c
@@ -9,10 +9,13 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/in.h>
+#include <linux/ip.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/tcp.h>
 
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_ecn.h>
 
@@ -109,8 +112,9 @@
 	return 1;
 }
 
-static struct ipt_match ecn_match = {
+static struct xt_match ecn_match = {
 	.name		= "ecn",
+	.family		= AF_INET,
 	.match		= match,
 	.matchsize	= sizeof(struct ipt_ecn_info),
 	.checkentry	= checkentry,
@@ -119,12 +123,12 @@
 
 static int __init ipt_ecn_init(void)
 {
-	return ipt_register_match(&ecn_match);
+	return xt_register_match(&ecn_match);
 }
 
 static void __exit ipt_ecn_fini(void)
 {
-	ipt_unregister_match(&ecn_match);
+	xt_unregister_match(&ecn_match);
 }
 
 module_init(ipt_ecn_init);
diff --git a/net/ipv4/netfilter/ipt_iprange.c b/net/ipv4/netfilter/ipt_iprange.c
index 5202edd..05de593 100644
--- a/net/ipv4/netfilter/ipt_iprange.c
+++ b/net/ipv4/netfilter/ipt_iprange.c
@@ -10,7 +10,7 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv4/ipt_iprange.h>
 
 MODULE_LICENSE("GPL");
@@ -63,22 +63,22 @@
 	return 1;
 }
 
-static struct ipt_match iprange_match = {
+static struct xt_match iprange_match = {
 	.name		= "iprange",
+	.family		= AF_INET,
 	.match		= match,
 	.matchsize	= sizeof(struct ipt_iprange_info),
-	.destroy	= NULL,
 	.me		= THIS_MODULE
 };
 
 static int __init ipt_iprange_init(void)
 {
-	return ipt_register_match(&iprange_match);
+	return xt_register_match(&iprange_match);
 }
 
 static void __exit ipt_iprange_fini(void)
 {
-	ipt_unregister_match(&iprange_match);
+	xt_unregister_match(&iprange_match);
 }
 
 module_init(ipt_iprange_init);
diff --git a/net/ipv4/netfilter/ipt_owner.c b/net/ipv4/netfilter/ipt_owner.c
index 78c336f1..9f496ac 100644
--- a/net/ipv4/netfilter/ipt_owner.c
+++ b/net/ipv4/netfilter/ipt_owner.c
@@ -15,7 +15,7 @@
 #include <net/sock.h>
 
 #include <linux/netfilter_ipv4/ipt_owner.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
@@ -68,8 +68,9 @@
 	return 1;
 }
 
-static struct ipt_match owner_match = {
+static struct xt_match owner_match = {
 	.name		= "owner",
+	.family		= AF_INET,
 	.match		= match,
 	.matchsize	= sizeof(struct ipt_owner_info),
 	.hooks		= (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING),
@@ -79,12 +80,12 @@
 
 static int __init ipt_owner_init(void)
 {
-	return ipt_register_match(&owner_match);
+	return xt_register_match(&owner_match);
 }
 
 static void __exit ipt_owner_fini(void)
 {
-	ipt_unregister_match(&owner_match);
+	xt_unregister_match(&owner_match);
 }
 
 module_init(ipt_owner_init);
diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c
index 4db0e73..6b97b67 100644
--- a/net/ipv4/netfilter/ipt_recent.c
+++ b/net/ipv4/netfilter/ipt_recent.c
@@ -12,6 +12,7 @@
  * Copyright 2002-2003, Stephen Frost, 2.5.x port by laforge@netfilter.org
  */
 #include <linux/init.h>
+#include <linux/ip.h>
 #include <linux/moduleparam.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
@@ -24,7 +25,7 @@
 #include <linux/skbuff.h>
 #include <linux/inet.h>
 
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv4/ipt_recent.h>
 
 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
@@ -462,8 +463,9 @@
 };
 #endif /* CONFIG_PROC_FS */
 
-static struct ipt_match recent_match = {
+static struct xt_match recent_match = {
 	.name		= "recent",
+	.family		= AF_INET,
 	.match		= ipt_recent_match,
 	.matchsize	= sizeof(struct ipt_recent_info),
 	.checkentry	= ipt_recent_checkentry,
@@ -479,13 +481,13 @@
 		return -EINVAL;
 	ip_list_hash_size = 1 << fls(ip_list_tot);
 
-	err = ipt_register_match(&recent_match);
+	err = xt_register_match(&recent_match);
 #ifdef CONFIG_PROC_FS
 	if (err)
 		return err;
 	proc_dir = proc_mkdir("ipt_recent", proc_net);
 	if (proc_dir == NULL) {
-		ipt_unregister_match(&recent_match);
+		xt_unregister_match(&recent_match);
 		err = -ENOMEM;
 	}
 #endif
@@ -495,7 +497,7 @@
 static void __exit ipt_recent_exit(void)
 {
 	BUG_ON(!list_empty(&tables));
-	ipt_unregister_match(&recent_match);
+	xt_unregister_match(&recent_match);
 #ifdef CONFIG_PROC_FS
 	remove_proc_entry("ipt_recent", proc_net);
 #endif
diff --git a/net/ipv4/netfilter/ipt_tos.c b/net/ipv4/netfilter/ipt_tos.c
index 5549c39..5d33b51 100644
--- a/net/ipv4/netfilter/ipt_tos.c
+++ b/net/ipv4/netfilter/ipt_tos.c
@@ -8,11 +8,12 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/ip.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
 
 #include <linux/netfilter_ipv4/ipt_tos.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("iptables TOS match module");
@@ -32,8 +33,9 @@
 	return (skb->nh.iph->tos == info->tos) ^ info->invert;
 }
 
-static struct ipt_match tos_match = {
+static struct xt_match tos_match = {
 	.name		= "tos",
+	.family		= AF_INET,
 	.match		= match,
 	.matchsize	= sizeof(struct ipt_tos_info),
 	.me		= THIS_MODULE,
@@ -41,12 +43,12 @@
 
 static int __init ipt_multiport_init(void)
 {
-	return ipt_register_match(&tos_match);
+	return xt_register_match(&tos_match);
 }
 
 static void __exit ipt_multiport_fini(void)
 {
-	ipt_unregister_match(&tos_match);
+	xt_unregister_match(&tos_match);
 }
 
 module_init(ipt_multiport_init);
diff --git a/net/ipv4/netfilter/ipt_ttl.c b/net/ipv4/netfilter/ipt_ttl.c
index a5243bd..d5cd984e 100644
--- a/net/ipv4/netfilter/ipt_ttl.c
+++ b/net/ipv4/netfilter/ipt_ttl.c
@@ -9,11 +9,12 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/ip.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
 
 #include <linux/netfilter_ipv4/ipt_ttl.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
 
 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
 MODULE_DESCRIPTION("IP tables TTL matching module");
@@ -48,8 +49,9 @@
 	return 0;
 }
 
-static struct ipt_match ttl_match = {
+static struct xt_match ttl_match = {
 	.name		= "ttl",
+	.family		= AF_INET,
 	.match		= match,
 	.matchsize	= sizeof(struct ipt_ttl_info),
 	.me		= THIS_MODULE,
@@ -57,13 +59,12 @@
 
 static int __init ipt_ttl_init(void)
 {
-	return ipt_register_match(&ttl_match);
+	return xt_register_match(&ttl_match);
 }
 
 static void __exit ipt_ttl_fini(void)
 {
-	ipt_unregister_match(&ttl_match);
-
+	xt_unregister_match(&ttl_match);
 }
 
 module_init(ipt_ttl_init);
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
index e2e7dd8..51053cb 100644
--- a/net/ipv4/netfilter/iptable_filter.c
+++ b/net/ipv4/netfilter/iptable_filter.c
@@ -74,7 +74,7 @@
     }
 };
 
-static struct ipt_table packet_filter = {
+static struct xt_table packet_filter = {
 	.name		= "filter",
 	.valid_hooks	= FILTER_VALID_HOOKS,
 	.lock		= RW_LOCK_UNLOCKED,
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index af29398..a532e4d 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -103,7 +103,7 @@
     }
 };
 
-static struct ipt_table packet_mangler = {
+static struct xt_table packet_mangler = {
 	.name		= "mangle",
 	.valid_hooks	= MANGLE_VALID_HOOKS,
 	.lock		= RW_LOCK_UNLOCKED,
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
index bcbeb4a..5277550 100644
--- a/net/ipv4/netfilter/iptable_raw.c
+++ b/net/ipv4/netfilter/iptable_raw.c
@@ -79,7 +79,7 @@
 	}
 };
 
-static struct ipt_table packet_raw = { 
+static struct xt_table packet_raw = {
 	.name = "raw", 
 	.valid_hooks =  RAW_VALID_HOOKS, 
 	.lock = RW_LOCK_UNLOCKED, 
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 86a9227..998b255 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -254,8 +254,9 @@
 	if (maniptype == IP_NAT_MANIP_SRC) {
 		if (find_appropriate_src(orig_tuple, tuple, range)) {
 			DEBUGP("get_unique_tuple: Found current src map\n");
-			if (!nf_nat_used_tuple(tuple, ct))
-				return;
+			if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM))
+				if (!nf_nat_used_tuple(tuple, ct))
+					return;
 		}
 	}
 
@@ -269,6 +270,13 @@
 
 	proto = nf_nat_proto_find_get(orig_tuple->dst.protonum);
 
+	/* Change protocol info to have some randomization */
+	if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) {
+		proto->unique_tuple(tuple, range, maniptype, ct);
+		nf_nat_proto_put(proto);
+		return;
+	}
+
 	/* Only bother mapping if it's not already in range and unique */
 	if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
 	     proto->in_range(tuple, maniptype, &range->min, &range->max)) &&
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c
index 98fbfc8..dc6738b 100644
--- a/net/ipv4/netfilter/nf_nat_helper.c
+++ b/net/ipv4/netfilter/nf_nat_helper.c
@@ -176,7 +176,7 @@
 	datalen = (*pskb)->len - iph->ihl*4;
 	if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
 		tcph->check = 0;
-		tcph->check = tcp_v4_check(tcph, datalen,
+		tcph->check = tcp_v4_check(datalen,
 					   iph->saddr, iph->daddr,
 					   csum_partial((char *)tcph,
 					   		datalen, 0));
diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c
index 7e26a7e..439164c 100644
--- a/net/ipv4/netfilter/nf_nat_proto_tcp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c
@@ -8,6 +8,7 @@
 
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/random.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
 
@@ -75,6 +76,9 @@
 		range_size = ntohs(range->max.tcp.port) - min + 1;
 	}
 
+	if (range->flags & IP_NAT_RANGE_PROTO_RANDOM)
+		port =  net_random();
+
 	for (i = 0; i < range_size; i++, port++) {
 		*portptr = htons(min + port % range_size);
 		if (!nf_nat_used_tuple(tuple, ct))
diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c
index ab0ce4c..8cae6e0 100644
--- a/net/ipv4/netfilter/nf_nat_proto_udp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_udp.c
@@ -8,6 +8,7 @@
 
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/random.h>
 #include <linux/ip.h>
 #include <linux/udp.h>
 
@@ -73,6 +74,9 @@
 		range_size = ntohs(range->max.udp.port) - min + 1;
 	}
 
+	if (range->flags & IP_NAT_RANGE_PROTO_RANDOM)
+		port = net_random();
+
 	for (i = 0; i < range_size; i++, port++) {
 		*portptr = htons(min + port % range_size);
 		if (!nf_nat_used_tuple(tuple, ct))
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
index b868ee0..7f95b4e 100644
--- a/net/ipv4/netfilter/nf_nat_rule.c
+++ b/net/ipv4/netfilter/nf_nat_rule.c
@@ -119,7 +119,7 @@
 	}
 };
 
-static struct ipt_table nat_table = {
+static struct xt_table nat_table = {
 	.name		= "nat",
 	.valid_hooks	= NAT_VALID_HOOKS,
 	.lock		= RW_LOCK_UNLOCKED,
@@ -226,6 +226,10 @@
 		printk("DNAT: multiple ranges no longer supported\n");
 		return 0;
 	}
+	if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) {
+		printk("DNAT: port randomization not supported\n");
+		return 0;
+	}
 	return 1;
 }
 
@@ -290,7 +294,7 @@
 	return ret;
 }
 
-static struct ipt_target ipt_snat_reg = {
+static struct xt_target ipt_snat_reg = {
 	.name		= "SNAT",
 	.target		= ipt_snat_target,
 	.targetsize	= sizeof(struct nf_nat_multi_range_compat),
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c
index 00d6dea..5a964a1 100644
--- a/net/ipv4/netfilter/nf_nat_standalone.c
+++ b/net/ipv4/netfilter/nf_nat_standalone.c
@@ -32,12 +32,6 @@
 #define DEBUGP(format, args...)
 #endif
 
-#define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING"  \
-			   : ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" \
-			      : ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT"  \
-			         : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN"  \
-				    : "*ERROR*")))
-
 #ifdef CONFIG_XFRM
 static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
 {
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index a6c63bb..fed6a1e 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -489,7 +489,7 @@
 		}
 
 		security_sk_classify_flow(sk, &fl);
-		err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT));
+		err = ip_route_output_flow(&rt, &fl, sk, 1);
 	}
 	if (err)
 		goto done;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 2daa0dc..baee304 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2635,7 +2635,7 @@
 
 	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags);
 	if (nlh == NULL)
-		return -ENOBUFS;
+		return -EMSGSIZE;
 
 	r = nlmsg_data(nlh);
 	r->rtm_family	 = AF_INET;
@@ -2718,7 +2718,8 @@
 	return nlmsg_end(skb, nlh);
 
 nla_put_failure:
-	return nlmsg_cancel(skb, nlh);
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
 }
 
 int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index b67e0dd..5bd43d7 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2415,10 +2415,11 @@
 					&tcp_hashinfo.ehash_size,
 					NULL,
 					0);
-	tcp_hashinfo.ehash_size = (1 << tcp_hashinfo.ehash_size) >> 1;
-	for (i = 0; i < (tcp_hashinfo.ehash_size << 1); i++) {
+	tcp_hashinfo.ehash_size = 1 << tcp_hashinfo.ehash_size;
+	for (i = 0; i < tcp_hashinfo.ehash_size; i++) {
 		rwlock_init(&tcp_hashinfo.ehash[i].lock);
 		INIT_HLIST_HEAD(&tcp_hashinfo.ehash[i].chain);
+		INIT_HLIST_HEAD(&tcp_hashinfo.ehash[i].twchain);
 	}
 
 	tcp_hashinfo.bhash =
@@ -2475,7 +2476,7 @@
 
 	printk(KERN_INFO "TCP: Hash tables configured "
 	       "(established %d bind %d)\n",
-	       tcp_hashinfo.ehash_size << 1, tcp_hashinfo.bhash_size);
+	       tcp_hashinfo.ehash_size, tcp_hashinfo.bhash_size);
 
 	tcp_register_congestion_control(&tcp_reno);
 }
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index c26076f..c610989 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -936,28 +936,58 @@
 	struct tcp_sock *tp = tcp_sk(sk);
 	unsigned char *ptr = ack_skb->h.raw + TCP_SKB_CB(ack_skb)->sacked;
 	struct tcp_sack_block_wire *sp = (struct tcp_sack_block_wire *)(ptr+2);
+	struct sk_buff *cached_skb;
 	int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3;
 	int reord = tp->packets_out;
 	int prior_fackets;
 	u32 lost_retrans = 0;
 	int flag = 0;
 	int dup_sack = 0;
+	int cached_fack_count;
 	int i;
+	int first_sack_index;
 
 	if (!tp->sacked_out)
 		tp->fackets_out = 0;
 	prior_fackets = tp->fackets_out;
 
+	/* Check for D-SACK. */
+	if (before(ntohl(sp[0].start_seq), TCP_SKB_CB(ack_skb)->ack_seq)) {
+		dup_sack = 1;
+		tp->rx_opt.sack_ok |= 4;
+		NET_INC_STATS_BH(LINUX_MIB_TCPDSACKRECV);
+	} else if (num_sacks > 1 &&
+			!after(ntohl(sp[0].end_seq), ntohl(sp[1].end_seq)) &&
+			!before(ntohl(sp[0].start_seq), ntohl(sp[1].start_seq))) {
+		dup_sack = 1;
+		tp->rx_opt.sack_ok |= 4;
+		NET_INC_STATS_BH(LINUX_MIB_TCPDSACKOFORECV);
+	}
+
+	/* D-SACK for already forgotten data...
+	 * Do dumb counting. */
+	if (dup_sack &&
+			!after(ntohl(sp[0].end_seq), prior_snd_una) &&
+			after(ntohl(sp[0].end_seq), tp->undo_marker))
+		tp->undo_retrans--;
+
+	/* Eliminate too old ACKs, but take into
+	 * account more or less fresh ones, they can
+	 * contain valid SACK info.
+	 */
+	if (before(TCP_SKB_CB(ack_skb)->ack_seq, prior_snd_una - tp->max_window))
+		return 0;
+
 	/* SACK fastpath:
 	 * if the only SACK change is the increase of the end_seq of
 	 * the first block then only apply that SACK block
 	 * and use retrans queue hinting otherwise slowpath */
 	flag = 1;
-	for (i = 0; i< num_sacks; i++) {
-		__u32 start_seq = ntohl(sp[i].start_seq);
-		__u32 end_seq =	 ntohl(sp[i].end_seq);
+	for (i = 0; i < num_sacks; i++) {
+		__be32 start_seq = sp[i].start_seq;
+		__be32 end_seq = sp[i].end_seq;
 
-		if (i == 0){
+		if (i == 0) {
 			if (tp->recv_sack_cache[i].start_seq != start_seq)
 				flag = 0;
 		} else {
@@ -967,39 +997,14 @@
 		}
 		tp->recv_sack_cache[i].start_seq = start_seq;
 		tp->recv_sack_cache[i].end_seq = end_seq;
-
-		/* Check for D-SACK. */
-		if (i == 0) {
-			u32 ack = TCP_SKB_CB(ack_skb)->ack_seq;
-
-			if (before(start_seq, ack)) {
-				dup_sack = 1;
-				tp->rx_opt.sack_ok |= 4;
-				NET_INC_STATS_BH(LINUX_MIB_TCPDSACKRECV);
-			} else if (num_sacks > 1 &&
-				   !after(end_seq, ntohl(sp[1].end_seq)) &&
-				   !before(start_seq, ntohl(sp[1].start_seq))) {
-				dup_sack = 1;
-				tp->rx_opt.sack_ok |= 4;
-				NET_INC_STATS_BH(LINUX_MIB_TCPDSACKOFORECV);
-			}
-
-			/* D-SACK for already forgotten data...
-			 * Do dumb counting. */
-			if (dup_sack &&
-			    !after(end_seq, prior_snd_una) &&
-			    after(end_seq, tp->undo_marker))
-				tp->undo_retrans--;
-
-			/* Eliminate too old ACKs, but take into
-			 * account more or less fresh ones, they can
-			 * contain valid SACK info.
-			 */
-			if (before(ack, prior_snd_una - tp->max_window))
-				return 0;
-		}
+	}
+	/* Clear the rest of the cache sack blocks so they won't match mistakenly. */
+	for (; i < ARRAY_SIZE(tp->recv_sack_cache); i++) {
+		tp->recv_sack_cache[i].start_seq = 0;
+		tp->recv_sack_cache[i].end_seq = 0;
 	}
 
+	first_sack_index = 0;
 	if (flag)
 		num_sacks = 1;
 	else {
@@ -1016,6 +1021,10 @@
 					tmp = sp[j];
 					sp[j] = sp[j+1];
 					sp[j+1] = tmp;
+
+					/* Track where the first SACK block goes to */
+					if (j == first_sack_index)
+						first_sack_index = j+1;
 				}
 
 			}
@@ -1025,20 +1034,22 @@
 	/* clear flag as used for different purpose in following code */
 	flag = 0;
 
+	/* Use SACK fastpath hint if valid */
+	cached_skb = tp->fastpath_skb_hint;
+	cached_fack_count = tp->fastpath_cnt_hint;
+	if (!cached_skb) {
+		cached_skb = sk->sk_write_queue.next;
+		cached_fack_count = 0;
+	}
+
 	for (i=0; i<num_sacks; i++, sp++) {
 		struct sk_buff *skb;
 		__u32 start_seq = ntohl(sp->start_seq);
 		__u32 end_seq = ntohl(sp->end_seq);
 		int fack_count;
 
-		/* Use SACK fastpath hint if valid */
-		if (tp->fastpath_skb_hint) {
-			skb = tp->fastpath_skb_hint;
-			fack_count = tp->fastpath_cnt_hint;
-		} else {
-			skb = sk->sk_write_queue.next;
-			fack_count = 0;
-		}
+		skb = cached_skb;
+		fack_count = cached_fack_count;
 
 		/* Event "B" in the comment above. */
 		if (after(end_seq, tp->high_seq))
@@ -1048,8 +1059,12 @@
 			int in_sack, pcount;
 			u8 sacked;
 
-			tp->fastpath_skb_hint = skb;
-			tp->fastpath_cnt_hint = fack_count;
+			cached_skb = skb;
+			cached_fack_count = fack_count;
+			if (i == first_sack_index) {
+				tp->fastpath_skb_hint = skb;
+				tp->fastpath_cnt_hint = fack_count;
+			}
 
 			/* The retransmission queue is always in order, so
 			 * we can short-circuit the walk early.
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 12de90a..f51d640 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -191,7 +191,7 @@
 	tmp = ip_route_connect(&rt, nexthop, inet->saddr,
 			       RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
 			       IPPROTO_TCP,
-			       inet->sport, usin->sin_port, sk);
+			       inet->sport, usin->sin_port, sk, 1);
 	if (tmp < 0)
 		return tmp;
 
@@ -502,11 +502,11 @@
 	struct tcphdr *th = skb->h.th;
 
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		th->check = ~tcp_v4_check(th, len,
-					  inet->saddr, inet->daddr, 0);
+		th->check = ~tcp_v4_check(len, inet->saddr,
+					  inet->daddr, 0);
 		skb->csum_offset = offsetof(struct tcphdr, check);
 	} else {
-		th->check = tcp_v4_check(th, len, inet->saddr, inet->daddr,
+		th->check = tcp_v4_check(len, inet->saddr, inet->daddr,
 					 csum_partial((char *)th,
 						      th->doff << 2,
 						      skb->csum));
@@ -525,7 +525,7 @@
 	th = skb->h.th;
 
 	th->check = 0;
-	th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0);
+	th->check = ~tcp_v4_check(skb->len, iph->saddr, iph->daddr, 0);
 	skb->csum_offset = offsetof(struct tcphdr, check);
 	skb->ip_summed = CHECKSUM_PARTIAL;
 	return 0;
@@ -747,7 +747,7 @@
 	if (skb) {
 		struct tcphdr *th = skb->h.th;
 
-		th->check = tcp_v4_check(th, skb->len,
+		th->check = tcp_v4_check(skb->len,
 					 ireq->loc_addr,
 					 ireq->rmt_addr,
 					 csum_partial((char *)th, skb->len,
@@ -1514,7 +1514,7 @@
 static __sum16 tcp_v4_checksum_init(struct sk_buff *skb)
 {
 	if (skb->ip_summed == CHECKSUM_COMPLETE) {
-		if (!tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr,
+		if (!tcp_v4_check(skb->len, skb->nh.iph->saddr,
 				  skb->nh.iph->daddr, skb->csum)) {
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 			return 0;
@@ -2051,7 +2051,7 @@
 		}
 		st->state = TCP_SEQ_STATE_TIME_WAIT;
 		inet_twsk_for_each(tw, node,
-				   &tcp_hashinfo.ehash[st->bucket + tcp_hashinfo.ehash_size].chain) {
+				   &tcp_hashinfo.ehash[st->bucket].twchain) {
 			if (tw->tw_family != st->family) {
 				continue;
 			}
@@ -2107,7 +2107,7 @@
 	}
 
 	st->state = TCP_SEQ_STATE_TIME_WAIT;
-	tw = tw_head(&tcp_hashinfo.ehash[st->bucket + tcp_hashinfo.ehash_size].chain);
+	tw = tw_head(&tcp_hashinfo.ehash[st->bucket].twchain);
 	goto get_tw;
 found:
 	cur = sk;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 975f447..58b7111 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -965,7 +965,8 @@
 	u32 in_flight, cwnd;
 
 	/* Don't be strict about the congestion window for the final FIN.  */
-	if (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)
+	if ((TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) &&
+	    tcp_skb_pcount(skb) == 1)
 		return 1;
 
 	in_flight = tcp_packets_in_flight(tp);
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index cfff930..8b54c68 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -629,7 +629,7 @@
 					       { .sport = inet->sport,
 						 .dport = dport } } };
 		security_sk_classify_flow(sk, &fl);
-		err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT));
+		err = ip_route_output_flow(&rt, &fl, sk, 1);
 		if (err)
 			goto out;
 
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
index e23c21d..e54c549 100644
--- a/net/ipv4/xfrm4_mode_tunnel.c
+++ b/net/ipv4/xfrm4_mode_tunnel.c
@@ -23,6 +23,12 @@
 		IP_ECN_set_ce(inner_iph);
 }
 
+static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
+{
+	if (INET_ECN_is_ce(iph->tos))
+		IP6_ECN_set_ce(skb->nh.ipv6h);
+}
+
 /* Add encapsulation header.
  *
  * The top IP header will be constructed per RFC 2401.  The following fields
@@ -36,6 +42,7 @@
 static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
 {
 	struct dst_entry *dst = skb->dst;
+	struct xfrm_dst *xdst = (struct xfrm_dst*)dst;
 	struct iphdr *iph, *top_iph;
 	int flags;
 
@@ -48,15 +55,27 @@
 	top_iph->ihl = 5;
 	top_iph->version = 4;
 
-	/* DS disclosed */
-	top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos);
-
 	flags = x->props.flags;
+
+	/* DS disclosed */
+	if (xdst->route->ops->family == AF_INET) {
+		top_iph->protocol = IPPROTO_IPIP;
+		top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos);
+		top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ?
+			0 : (iph->frag_off & htons(IP_DF));
+	}
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+	else {
+		struct ipv6hdr *ipv6h = (struct ipv6hdr*)iph;
+		top_iph->protocol = IPPROTO_IPV6;
+		top_iph->tos = INET_ECN_encapsulate(iph->tos, ipv6_get_dsfield(ipv6h));
+		top_iph->frag_off = 0;
+	}
+#endif
+
 	if (flags & XFRM_STATE_NOECN)
 		IP_ECN_clear(top_iph);
 
-	top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ?
-		0 : (iph->frag_off & htons(IP_DF));
 	if (!top_iph->frag_off)
 		__ip_select_ident(top_iph, dst->child, 0);
 
@@ -64,7 +83,6 @@
 
 	top_iph->saddr = x->props.saddr.a4;
 	top_iph->daddr = x->id.daddr.a4;
-	top_iph->protocol = IPPROTO_IPIP;
 
 	memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
 	return 0;
@@ -75,8 +93,16 @@
 	struct iphdr *iph = skb->nh.iph;
 	int err = -EINVAL;
 
-	if (iph->protocol != IPPROTO_IPIP)
-		goto out;
+	switch(iph->protocol){
+		case IPPROTO_IPIP:
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+		case IPPROTO_IPV6:
+			break;
+#endif
+		default:
+			goto out;
+	}
+
 	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
 		goto out;
 
@@ -84,10 +110,19 @@
 	    (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
 		goto out;
 
-	if (x->props.flags & XFRM_STATE_DECAP_DSCP)
-		ipv4_copy_dscp(iph, skb->h.ipiph);
-	if (!(x->props.flags & XFRM_STATE_NOECN))
-		ipip_ecn_decapsulate(skb);
+	if (iph->protocol == IPPROTO_IPIP) {
+		if (x->props.flags & XFRM_STATE_DECAP_DSCP)
+			ipv4_copy_dscp(iph, skb->h.ipiph);
+		if (!(x->props.flags & XFRM_STATE_NOECN))
+			ipip_ecn_decapsulate(skb);
+	}
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+	else {
+		if (!(x->props.flags & XFRM_STATE_NOECN))
+			ipip6_ecn_decapsulate(iph, skb);
+		skb->protocol = htons(ETH_P_IPV6);
+	}
+#endif
 	skb->mac.raw = memmove(skb->data - skb->mac_len,
 			       skb->mac.raw, skb->mac_len);
 	skb->nh.raw = skb->data;
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index fb9f69c..699f27c 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -72,13 +72,11 @@
 	struct dst_entry *dst, *dst_prev;
 	struct rtable *rt0 = (struct rtable*)(*dst_p);
 	struct rtable *rt = rt0;
-	__be32 remote = fl->fl4_dst;
-	__be32 local  = fl->fl4_src;
 	struct flowi fl_tunnel = {
 		.nl_u = {
 			.ip4_u = {
-				.saddr = local,
-				.daddr = remote,
+				.saddr = fl->fl4_src,
+				.daddr = fl->fl4_dst,
 				.tos = fl->fl4_tos
 			}
 		}
@@ -94,7 +92,6 @@
 	for (i = 0; i < nx; i++) {
 		struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops);
 		struct xfrm_dst *xdst;
-		int tunnel = 0;
 
 		if (unlikely(dst1 == NULL)) {
 			err = -ENOBUFS;
@@ -116,19 +113,28 @@
 
 		dst1->next = dst_prev;
 		dst_prev = dst1;
-		if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
-			remote = xfrm[i]->id.daddr.a4;
-			local  = xfrm[i]->props.saddr.a4;
-			tunnel = 1;
-		}
+
 		header_len += xfrm[i]->props.header_len;
 		trailer_len += xfrm[i]->props.trailer_len;
 
-		if (tunnel) {
-			fl_tunnel.fl4_src = local;
-			fl_tunnel.fl4_dst = remote;
+		if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL) {
+			unsigned short encap_family = xfrm[i]->props.family;
+			switch(encap_family) {
+			case AF_INET:
+				fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4;
+				fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4;
+				break;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+			case AF_INET6:
+				ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr*)&xfrm[i]->id.daddr.a6);
+				ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr*)&xfrm[i]->props.saddr.a6);
+				break;
+#endif
+			default:
+				BUG_ON(1);
+			}
 			err = xfrm_dst_lookup((struct xfrm_dst **)&rt,
-					      &fl_tunnel, AF_INET);
+					      &fl_tunnel, encap_family);
 			if (err)
 				goto error;
 		} else
@@ -145,6 +151,7 @@
 	i = 0;
 	for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
 		struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
+		struct xfrm_state_afinfo *afinfo;
 		x->u.rt.fl = *fl;
 
 		dst_prev->xfrm = xfrm[i++];
@@ -162,8 +169,18 @@
 		/* Copy neighbout for reachability confirmation */
 		dst_prev->neighbour	= neigh_clone(rt->u.dst.neighbour);
 		dst_prev->input		= rt->u.dst.input;
-		dst_prev->output	= xfrm4_output;
-		if (rt->peer)
+		/* XXX: When IPv6 module can be unloaded, we should manage reference
+		 * to xfrm6_output in afinfo->output. Miyazawa
+		 * */
+		afinfo = xfrm_state_get_afinfo(dst_prev->xfrm->props.family);
+		if (!afinfo) {
+			dst = *dst_p;
+			err = -EAFNOSUPPORT;
+			goto error;
+		}
+		dst_prev->output = afinfo->output;
+		xfrm_state_put_afinfo(afinfo);
+		if (dst_prev->xfrm->props.family == AF_INET && rt->peer)
 			atomic_inc(&rt->peer->refcnt);
 		x->u.rt.peer = rt->peer;
 		/* Sheit... I remember I did this right. Apparently,
@@ -274,7 +291,7 @@
 
 	if (likely(xdst->u.rt.idev))
 		in_dev_put(xdst->u.rt.idev);
-	if (likely(xdst->u.rt.peer))
+	if (dst->xfrm->props.family == AF_INET && likely(xdst->u.rt.peer))
 		inet_putpeer(xdst->u.rt.peer);
 	xfrm_dst_destroy(xdst);
 }
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index 3cc3df0..93e2c06 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -51,6 +51,7 @@
 	.family			= AF_INET,
 	.init_flags		= xfrm4_init_flags,
 	.init_tempsel		= __xfrm4_init_tempsel,
+	.output			= xfrm4_output,
 };
 
 void __init xfrm4_state_init(void)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index e385469..fe5e1d8 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3117,7 +3117,7 @@
 
 	nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags);
 	if (nlh == NULL)
-		return -ENOBUFS;
+		return -EMSGSIZE;
 
 	put_ifaddrmsg(nlh, ifa->prefix_len, ifa->flags, rt_scope(ifa->scope),
 		      ifa->idev->dev->ifindex);
@@ -3137,8 +3137,10 @@
 	}
 
 	if (nla_put(skb, IFA_ADDRESS, 16, &ifa->addr) < 0 ||
-	    put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0)
-		return nlmsg_cancel(skb, nlh);
+	    put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0) {
+		nlmsg_cancel(skb, nlh);
+		return -EMSGSIZE;
+	}
 
 	return nlmsg_end(skb, nlh);
 }
@@ -3155,13 +3157,15 @@
 
 	nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags);
 	if (nlh == NULL)
-		return -ENOBUFS;
+		return -EMSGSIZE;
 
 	put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex);
 	if (nla_put(skb, IFA_MULTICAST, 16, &ifmca->mca_addr) < 0 ||
 	    put_cacheinfo(skb, ifmca->mca_cstamp, ifmca->mca_tstamp,
-			  INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0)
-		return nlmsg_cancel(skb, nlh);
+			  INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0) {
+		nlmsg_cancel(skb, nlh);
+		return -EMSGSIZE;
+	}
 
 	return nlmsg_end(skb, nlh);
 }
@@ -3178,13 +3182,15 @@
 
 	nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags);
 	if (nlh == NULL)
-		return -ENOBUFS;
+		return -EMSGSIZE;
 
 	put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex);
 	if (nla_put(skb, IFA_ANYCAST, 16, &ifaca->aca_addr) < 0 ||
 	    put_cacheinfo(skb, ifaca->aca_cstamp, ifaca->aca_tstamp,
-			  INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0)
-		return nlmsg_cancel(skb, nlh);
+			  INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0) {
+		nlmsg_cancel(skb, nlh);
+		return -EMSGSIZE;
+	}
 
 	return nlmsg_end(skb, nlh);
 }
@@ -3334,9 +3340,12 @@
 
 	err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid,
 				nlh->nlmsg_seq, RTM_NEWADDR, 0);
-	/* failure implies BUG in inet6_ifaddr_msgsize() */
-	BUG_ON(err < 0);
-
+	if (err < 0) {
+		/* -EMSGSIZE implies BUG in inet6_ifaddr_msgsize() */
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(skb);
+		goto errout_ifa;
+	}
 	err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid);
 errout_ifa:
 	in6_ifa_put(ifa);
@@ -3354,9 +3363,12 @@
 		goto errout;
 
 	err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0);
-	/* failure implies BUG in inet6_ifaddr_msgsize() */
-	BUG_ON(err < 0);
-
+	if (err < 0) {
+		/* -EMSGSIZE implies BUG in inet6_ifaddr_msgsize() */
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(skb);
+		goto errout;
+	}
 	err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
 errout:
 	if (err < 0)
@@ -3426,7 +3438,7 @@
 
 	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags);
 	if (nlh == NULL)
-		return -ENOBUFS;
+		return -EMSGSIZE;
 
 	hdr = nlmsg_data(nlh);
 	hdr->ifi_family = AF_INET6;
@@ -3469,7 +3481,8 @@
 	return nlmsg_end(skb, nlh);
 
 nla_put_failure:
-	return nlmsg_cancel(skb, nlh);
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
 }
 
 static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
@@ -3507,9 +3520,12 @@
 		goto errout;
 
 	err = inet6_fill_ifinfo(skb, idev, 0, 0, event, 0);
-	/* failure implies BUG in inet6_if_nlmsg_size() */
-	BUG_ON(err < 0);
-
+	if (err < 0) {
+		/* -EMSGSIZE implies BUG in inet6_if_nlmsg_size() */
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(skb);
+		goto errout;
+	}
 	err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
 errout:
 	if (err < 0)
@@ -3533,7 +3549,7 @@
 
 	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*pmsg), flags);
 	if (nlh == NULL)
-		return -ENOBUFS;
+		return -EMSGSIZE;
 
 	pmsg = nlmsg_data(nlh);
 	pmsg->prefix_family = AF_INET6;
@@ -3558,7 +3574,8 @@
 	return nlmsg_end(skb, nlh);
 
 nla_put_failure:
-	return nlmsg_cancel(skb, nlh);
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
 }
 
 static void inet6_prefix_notify(int event, struct inet6_dev *idev, 
@@ -3572,9 +3589,12 @@
 		goto errout;
 
 	err = inet6_fill_prefix(skb, idev, pinfo, 0, 0, event, 0);
-	/* failure implies BUG in inet6_prefix_nlmsg_size() */
-	BUG_ON(err < 0);
-
+	if (err < 0) {
+		/* -EMSGSIZE implies BUG in inet6_prefix_nlmsg_size() */
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(skb);
+		goto errout;
+	}
 	err = rtnl_notify(skb, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
 errout:
 	if (err < 0)
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 5c94fea..ecde301 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -178,7 +178,7 @@
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+	if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0)
 		goto out;
 
 	/* source address lookup done in ip6_dst_lookup */
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index b7e5bae..e611169 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -79,7 +79,7 @@
 			goto hit; /* You sunk my battleship! */
 	}
 	/* Must check for a TIME_WAIT'er before going to listener hash. */
-	sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) {
+	sk_for_each(sk, node, &head->twchain) {
 		const struct inet_timewait_sock *tw = inet_twsk(sk);
 
 		if(*((__portpair *)&(tw->tw_dport))	== ports	&&
@@ -183,7 +183,7 @@
 	write_lock(&head->lock);
 
 	/* Check TIME-WAIT sockets first. */
-	sk_for_each(sk2, node, &(head + hinfo->ehash_size)->chain) {
+	sk_for_each(sk2, node, &head->twchain) {
 		const struct inet6_timewait_sock *tw6 = inet6_twsk(sk2);
 
 		tw = inet_twsk(sk2);
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 8d91834..2b9e3bb 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -999,7 +999,8 @@
 				break;
 			dev = t->dev;
 		}
-		err = unregister_netdevice(dev);
+		err = 0;
+		unregister_netdevice(dev);
 		break;
 	default:
 		err = -EINVAL;
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 882cde4..e3ec216 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1582,6 +1582,8 @@
 			skb = add_grhead(skb, pmc, type, &pgr);
 			first = 0;
 		}
+		if (!skb)
+			return NULL;
 		psrc = (struct in6_addr *)skb_put(skb, sizeof(*psrc));
 		*psrc = psf->sf_addr;
 		scount++; stotal++;
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c
index be7dd7d..681bb07 100644
--- a/net/ipv6/mip6.c
+++ b/net/ipv6/mip6.c
@@ -89,7 +89,6 @@
 int mip6_mh_filter(struct sock *sk, struct sk_buff *skb)
 {
 	struct ip6_mh *mh;
-	int mhlen;
 
 	if (!pskb_may_pull(skb, (skb->h.raw - skb->data) + 8) ||
 	    !pskb_may_pull(skb, (skb->h.raw - skb->data) + ((skb->h.raw[1] + 1) << 3)))
@@ -103,31 +102,6 @@
 		mip6_param_prob(skb, 0, (&mh->ip6mh_hdrlen) - skb->nh.raw);
 		return -1;
 	}
-	mhlen = (mh->ip6mh_hdrlen + 1) << 3;
-
-	if (skb->ip_summed == CHECKSUM_COMPLETE) {
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
-		if (csum_ipv6_magic(&skb->nh.ipv6h->saddr,
-				    &skb->nh.ipv6h->daddr,
-				    mhlen, IPPROTO_MH,
-				    skb->csum)) {
-			LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH hw checksum failed\n");
-			skb->ip_summed = CHECKSUM_NONE;
-		}
-	}
-	if (skb->ip_summed == CHECKSUM_NONE) {
-		if (csum_ipv6_magic(&skb->nh.ipv6h->saddr,
-				    &skb->nh.ipv6h->daddr,
-				    mhlen, IPPROTO_MH,
-				    skb_checksum(skb, 0, mhlen, 0))) {
-			LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH checksum failed "
-				       "[" NIP6_FMT " > " NIP6_FMT "]\n",
-				       NIP6(skb->nh.ipv6h->saddr),
-				       NIP6(skb->nh.ipv6h->daddr));
-			return -1;
-		}
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
-	}
 
 	if (mh->ip6mh_proto != IPPROTO_NONE) {
 		LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH invalid payload proto = %d\n",
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index adcd613..cd549ae 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -114,6 +114,14 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config IP6_NF_MATCH_MH
+	tristate "MH match support"
+	depends on IP6_NF_IPTABLES
+	help
+	  This module allows one to match MH packets.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config IP6_NF_MATCH_EUI64
 	tristate "EUI64 address check"
 	depends on IP6_NF_IPTABLES
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index ac1dfeb..4513eab 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -19,6 +19,7 @@
 obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
 obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
 obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
+obj-$(CONFIG_IP6_NF_MATCH_MH) += ip6t_mh.o
 
 # objects for l3 independent conntrack
 nf_conntrack_ipv6-objs  :=  nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 99502c5..7083e1c 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -530,7 +530,7 @@
 	    unsigned int hookmask,
 	    unsigned int *i)
 {
-	struct ip6t_match *match;
+	struct xt_match *match;
 	int ret;
 
 	match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
@@ -564,14 +564,14 @@
 	return ret;
 }
 
-static struct ip6t_target ip6t_standard_target;
+static struct xt_target ip6t_standard_target;
 
 static inline int
 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
 	    unsigned int *i)
 {
 	struct ip6t_entry_target *t;
-	struct ip6t_target *target;
+	struct xt_target *target;
 	int ret;
 	unsigned int j;
 
@@ -1348,13 +1348,13 @@
 }
 
 /* The built-in targets: standard (NULL) and error. */
-static struct ip6t_target ip6t_standard_target = {
+static struct xt_target ip6t_standard_target = {
 	.name		= IP6T_STANDARD_TARGET,
 	.targetsize	= sizeof(int),
 	.family		= AF_INET6,
 };
 
-static struct ip6t_target ip6t_error_target = {
+static struct xt_target ip6t_error_target = {
 	.name		= IP6T_ERROR_TARGET,
 	.target		= ip6t_error,
 	.targetsize	= IP6T_FUNCTION_MAXNAMELEN,
@@ -1371,7 +1371,7 @@
 	.get		= do_ip6t_get_ctl,
 };
 
-static struct ip6t_match icmp6_matchstruct = {
+static struct xt_match icmp6_matchstruct = {
 	.name		= "icmp6",
 	.match		= &icmp6_match,
 	.matchsize	= sizeof(struct ip6t_icmp),
diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c
index 435750f..04e5001 100644
--- a/net/ipv6/netfilter/ip6t_HL.c
+++ b/net/ipv6/netfilter/ip6t_HL.c
@@ -9,12 +9,13 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
+#include <linux/ipv6.h>
 
-#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv6/ip6t_HL.h>
 
 MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
-MODULE_DESCRIPTION("IP tables Hop Limit modification module");
+MODULE_DESCRIPTION("IP6 tables Hop Limit modification module");
 MODULE_LICENSE("GPL");
 
 static unsigned int ip6t_hl_target(struct sk_buff **pskb, 
@@ -52,10 +53,9 @@
 			break;
 	}
 
-	if (new_hl != ip6h->hop_limit)
-		ip6h->hop_limit = new_hl;
+	ip6h->hop_limit = new_hl;
 
-	return IP6T_CONTINUE;
+	return XT_CONTINUE;
 }
 
 static int ip6t_hl_checkentry(const char *tablename,
@@ -79,8 +79,9 @@
 	return 1;
 }
 
-static struct ip6t_target ip6t_HL = { 
+static struct xt_target ip6t_HL = {
 	.name 		= "HL", 
+	.family		= AF_INET6,
 	.target		= ip6t_hl_target, 
 	.targetsize	= sizeof(struct ip6t_HL_info),
 	.table		= "mangle",
@@ -90,12 +91,12 @@
 
 static int __init ip6t_hl_init(void)
 {
-	return ip6t_register_target(&ip6t_HL);
+	return xt_register_target(&ip6t_HL);
 }
 
 static void __exit ip6t_hl_fini(void)
 {
-	ip6t_unregister_target(&ip6t_HL);
+	xt_unregister_target(&ip6t_HL);
 }
 
 module_init(ip6t_hl_init);
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
index 33b1faa..5587a77 100644
--- a/net/ipv6/netfilter/ip6t_LOG.c
+++ b/net/ipv6/netfilter/ip6t_LOG.c
@@ -21,6 +21,7 @@
 #include <net/tcp.h>
 #include <net/ipv6.h>
 #include <linux/netfilter.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 
 MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>");
@@ -442,7 +443,7 @@
 
 	ip6t_log_packet(PF_INET6, hooknum, *pskb, in, out, &li,
 	                loginfo->prefix);
-	return IP6T_CONTINUE;
+	return XT_CONTINUE;
 }
 
 
@@ -466,8 +467,9 @@
 	return 1;
 }
 
-static struct ip6t_target ip6t_log_reg = {
+static struct xt_target ip6t_log_reg = {
 	.name 		= "LOG",
+	.family		= AF_INET6,
 	.target 	= ip6t_log_target, 
 	.targetsize	= sizeof(struct ip6t_log_info),
 	.checkentry	= ip6t_log_checkentry, 
@@ -482,8 +484,11 @@
 
 static int __init ip6t_log_init(void)
 {
-	if (ip6t_register_target(&ip6t_log_reg))
-		return -EINVAL;
+	int ret;
+
+	ret = xt_register_target(&ip6t_log_reg);
+	if (ret < 0)
+		return ret;
 	if (nf_log_register(PF_INET6, &ip6t_logger) < 0) {
 		printk(KERN_WARNING "ip6t_LOG: not logging via system console "
 		       "since somebody else already registered for PF_INET6\n");
@@ -497,7 +502,7 @@
 static void __exit ip6t_log_fini(void)
 {
 	nf_log_unregister_logger(&ip6t_logger);
-	ip6t_unregister_target(&ip6t_log_reg);
+	xt_unregister_target(&ip6t_log_reg);
 }
 
 module_init(ip6t_log_init);
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index 311eae8..278349c 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -26,6 +26,7 @@
 #include <net/ip6_fib.h>
 #include <net/ip6_route.h>
 #include <net/flow.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter_ipv6/ip6t_REJECT.h>
 
@@ -234,7 +235,7 @@
 	} else if (rejinfo->with == IP6T_TCP_RESET) {
 		/* Must specify that it's a TCP packet */
 		if (e->ipv6.proto != IPPROTO_TCP
-		    || (e->ipv6.invflags & IP6T_INV_PROTO)) {
+		    || (e->ipv6.invflags & XT_INV_PROTO)) {
 			DEBUGP("ip6t_REJECT: TCP_RESET illegal for non-tcp\n");
 			return 0;
 		}
@@ -242,8 +243,9 @@
 	return 1;
 }
 
-static struct ip6t_target ip6t_reject_reg = {
+static struct xt_target ip6t_reject_reg = {
 	.name		= "REJECT",
+	.family		= AF_INET6,
 	.target		= reject6_target,
 	.targetsize	= sizeof(struct ip6t_reject_info),
 	.table		= "filter",
@@ -255,12 +257,12 @@
 
 static int __init ip6t_reject_init(void)
 {
-	return ip6t_register_target(&ip6t_reject_reg);
+	return xt_register_target(&ip6t_reject_reg);
 }
 
 static void __exit ip6t_reject_fini(void)
 {
-	ip6t_unregister_target(&ip6t_reject_reg);
+	xt_unregister_target(&ip6t_reject_reg);
 }
 
 module_init(ip6t_reject_init);
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c
index 4648664..456c76a 100644
--- a/net/ipv6/netfilter/ip6t_ah.c
+++ b/net/ipv6/netfilter/ip6t_ah.c
@@ -15,6 +15,7 @@
 #include <net/checksum.h>
 #include <net/ipv6.h>
 
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter_ipv6/ip6t_ah.h>
 
@@ -118,8 +119,9 @@
 	return 1;
 }
 
-static struct ip6t_match ah_match = {
+static struct xt_match ah_match = {
 	.name		= "ah",
+	.family		= AF_INET6,
 	.match		= match,
 	.matchsize	= sizeof(struct ip6t_ah),
 	.checkentry	= checkentry,
@@ -128,12 +130,12 @@
 
 static int __init ip6t_ah_init(void)
 {
-	return ip6t_register_match(&ah_match);
+	return xt_register_match(&ah_match);
 }
 
 static void __exit ip6t_ah_fini(void)
 {
-	ip6t_unregister_match(&ah_match);
+	xt_unregister_match(&ah_match);
 }
 
 module_init(ip6t_ah_init);
diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c
index 4f6b84c..967bed7 100644
--- a/net/ipv6/netfilter/ip6t_eui64.c
+++ b/net/ipv6/netfilter/ip6t_eui64.c
@@ -12,6 +12,7 @@
 #include <linux/ipv6.h>
 #include <linux/if_ether.h>
 
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 
 MODULE_DESCRIPTION("IPv6 EUI64 address checking match");
@@ -61,8 +62,9 @@
 	return 0;
 }
 
-static struct ip6t_match eui64_match = {
+static struct xt_match eui64_match = {
 	.name		= "eui64",
+	.family		= AF_INET6,
 	.match		= match,
 	.matchsize	= sizeof(int),
 	.hooks		= (1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) |
@@ -72,12 +74,12 @@
 
 static int __init ip6t_eui64_init(void)
 {
-	return ip6t_register_match(&eui64_match);
+	return xt_register_match(&eui64_match);
 }
 
 static void __exit ip6t_eui64_fini(void)
 {
-	ip6t_unregister_match(&eui64_match);
+	xt_unregister_match(&eui64_match);
 }
 
 module_init(ip6t_eui64_init);
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c
index cd22eaa..5a5da71 100644
--- a/net/ipv6/netfilter/ip6t_frag.c
+++ b/net/ipv6/netfilter/ip6t_frag.c
@@ -14,6 +14,7 @@
 #include <net/checksum.h>
 #include <net/ipv6.h>
 
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter_ipv6/ip6t_frag.h>
 
@@ -135,8 +136,9 @@
 	return 1;
 }
 
-static struct ip6t_match frag_match = {
+static struct xt_match frag_match = {
 	.name		= "frag",
+	.family		= AF_INET6,
 	.match		= match,
 	.matchsize	= sizeof(struct ip6t_frag),
 	.checkentry	= checkentry,
@@ -145,12 +147,12 @@
 
 static int __init ip6t_frag_init(void)
 {
-	return ip6t_register_match(&frag_match);
+	return xt_register_match(&frag_match);
 }
 
 static void __exit ip6t_frag_fini(void)
 {
-	ip6t_unregister_match(&frag_match);
+	xt_unregister_match(&frag_match);
 }
 
 module_init(ip6t_frag_init);
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c
index 3f25bab..d2373c7 100644
--- a/net/ipv6/netfilter/ip6t_hbh.c
+++ b/net/ipv6/netfilter/ip6t_hbh.c
@@ -16,6 +16,7 @@
 
 #include <asm/byteorder.h>
 
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter_ipv6/ip6t_opts.h>
 
diff --git a/net/ipv6/netfilter/ip6t_hl.c b/net/ipv6/netfilter/ip6t_hl.c
index 44a729e..601cc12 100644
--- a/net/ipv6/netfilter/ip6t_hl.c
+++ b/net/ipv6/netfilter/ip6t_hl.c
@@ -8,11 +8,12 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/ipv6.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
 
 #include <linux/netfilter_ipv6/ip6t_hl.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter/x_tables.h>
 
 MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
 MODULE_DESCRIPTION("IP tables Hop Limit matching module");
@@ -48,8 +49,9 @@
 	return 0;
 }
 
-static struct ip6t_match hl_match = {
+static struct xt_match hl_match = {
 	.name		= "hl",
+	.family		= AF_INET6,
 	.match		= match,
 	.matchsize	= sizeof(struct ip6t_hl_info),
 	.me		= THIS_MODULE,
@@ -57,13 +59,12 @@
 
 static int __init ip6t_hl_init(void)
 {
-	return ip6t_register_match(&hl_match);
+	return xt_register_match(&hl_match);
 }
 
 static void __exit ip6t_hl_fini(void)
 {
-	ip6t_unregister_match(&hl_match);
-
+	xt_unregister_match(&hl_match);
 }
 
 module_init(ip6t_hl_init);
diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c
index 3093c39..26ac084 100644
--- a/net/ipv6/netfilter/ip6t_ipv6header.c
+++ b/net/ipv6/netfilter/ip6t_ipv6header.c
@@ -18,6 +18,7 @@
 #include <net/checksum.h>
 #include <net/ipv6.h>
 
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter_ipv6/ip6t_ipv6header.h>
 
@@ -140,8 +141,9 @@
 	return 1;
 }
 
-static struct ip6t_match ip6t_ipv6header_match = {
+static struct xt_match ip6t_ipv6header_match = {
 	.name		= "ipv6header",
+	.family		= AF_INET6,
 	.match		= &ipv6header_match,
 	.matchsize	= sizeof(struct ip6t_ipv6header_info),
 	.checkentry	= &ipv6header_checkentry,
@@ -151,12 +153,12 @@
 
 static int __init ipv6header_init(void)
 {
-	return ip6t_register_match(&ip6t_ipv6header_match);
+	return xt_register_match(&ip6t_ipv6header_match);
 }
 
 static void __exit ipv6header_exit(void)
 {
-	ip6t_unregister_match(&ip6t_ipv6header_match);
+	xt_unregister_match(&ip6t_ipv6header_match);
 }
 
 module_init(ipv6header_init);
diff --git a/net/ipv6/netfilter/ip6t_mh.c b/net/ipv6/netfilter/ip6t_mh.c
new file mode 100644
index 0000000..2c7efc6
--- /dev/null
+++ b/net/ipv6/netfilter/ip6t_mh.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C)2006 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Author:
+ *	Masahide NAKAMURA @USAGI <masahide.nakamura.cz@hitachi.com>
+ *
+ * Based on net/netfilter/xt_tcpudp.c
+ *
+ */
+#include <linux/types.h>
+#include <linux/module.h>
+#include <net/ip.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <net/mip6.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_ipv6/ip6t_mh.h>
+
+MODULE_DESCRIPTION("ip6t_tables match for MH");
+MODULE_LICENSE("GPL");
+
+#ifdef DEBUG_IP_FIREWALL_USER
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+/* Returns 1 if the type is matched by the range, 0 otherwise */
+static inline int
+type_match(u_int8_t min, u_int8_t max, u_int8_t type, int invert)
+{
+	int ret;
+
+	ret = (type >= min && type <= max) ^ invert;
+	return ret;
+}
+
+static int
+match(const struct sk_buff *skb,
+	 const struct net_device *in,
+	 const struct net_device *out,
+	 const struct xt_match *match,
+	 const void *matchinfo,
+	 int offset,
+	 unsigned int protoff,
+	 int *hotdrop)
+{
+	struct ip6_mh _mh, *mh;
+	const struct ip6t_mh *mhinfo = matchinfo;
+
+	/* Must not be a fragment. */
+	if (offset)
+		return 0;
+
+	mh = skb_header_pointer(skb, protoff, sizeof(_mh), &_mh);
+	if (mh == NULL) {
+		/* We've been asked to examine this packet, and we
+		   can't.  Hence, no choice but to drop. */
+		duprintf("Dropping evil MH tinygram.\n");
+		*hotdrop = 1;
+		return 0;
+	}
+
+	return type_match(mhinfo->types[0], mhinfo->types[1], mh->ip6mh_type,
+			  !!(mhinfo->invflags & IP6T_MH_INV_TYPE));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+mh_checkentry(const char *tablename,
+	      const void *entry,
+	      const struct xt_match *match,
+	      void *matchinfo,
+	      unsigned int hook_mask)
+{
+	const struct ip6t_mh *mhinfo = matchinfo;
+
+	/* Must specify no unknown invflags */
+	return !(mhinfo->invflags & ~IP6T_MH_INV_MASK);
+}
+
+static struct xt_match mh_match = {
+	.name		= "mh",
+	.family		= AF_INET6,
+	.checkentry	= mh_checkentry,
+	.match		= match,
+	.matchsize	= sizeof(struct ip6t_mh),
+	.proto		= IPPROTO_MH,
+	.me		= THIS_MODULE,
+};
+
+static int __init ip6t_mh_init(void)
+{
+	return xt_register_match(&mh_match);
+}
+
+static void __exit ip6t_mh_fini(void)
+{
+	xt_unregister_match(&mh_match);
+}
+
+module_init(ip6t_mh_init);
+module_exit(ip6t_mh_fini);
diff --git a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c
index 4eb9bbc..43738bb 100644
--- a/net/ipv6/netfilter/ip6t_owner.c
+++ b/net/ipv6/netfilter/ip6t_owner.c
@@ -16,6 +16,7 @@
 
 #include <linux/netfilter_ipv6/ip6t_owner.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter/x_tables.h>
 
 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
 MODULE_DESCRIPTION("IP6 tables owner matching module");
@@ -69,8 +70,9 @@
 	return 1;
 }
 
-static struct ip6t_match owner_match = {
+static struct xt_match owner_match = {
 	.name		= "owner",
+	.family		= AF_INET6,
 	.match		= match,
 	.matchsize	= sizeof(struct ip6t_owner_info),
 	.hooks		= (1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING),
@@ -80,12 +82,12 @@
 
 static int __init ip6t_owner_init(void)
 {
-	return ip6t_register_match(&owner_match);
+	return xt_register_match(&owner_match);
 }
 
 static void __exit ip6t_owner_fini(void)
 {
-	ip6t_unregister_match(&owner_match);
+	xt_unregister_match(&owner_match);
 }
 
 module_init(ip6t_owner_init);
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c
index 54d7d14..81ab00d 100644
--- a/net/ipv6/netfilter/ip6t_rt.c
+++ b/net/ipv6/netfilter/ip6t_rt.c
@@ -16,6 +16,7 @@
 
 #include <asm/byteorder.h>
 
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter_ipv6/ip6t_rt.h>
 
@@ -221,8 +222,9 @@
 	return 1;
 }
 
-static struct ip6t_match rt_match = {
+static struct xt_match rt_match = {
 	.name		= "rt",
+	.family		= AF_INET6,
 	.match		= match,
 	.matchsize	= sizeof(struct ip6t_rt),
 	.checkentry	= checkentry,
@@ -231,12 +233,12 @@
 
 static int __init ip6t_rt_init(void)
 {
-	return ip6t_register_match(&rt_match);
+	return xt_register_match(&rt_match);
 }
 
 static void __exit ip6t_rt_fini(void)
 {
-	ip6t_unregister_match(&rt_match);
+	xt_unregister_match(&rt_match);
 }
 
 module_init(ip6t_rt_init);
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index 2fc07c7..112a21d 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -19,25 +19,6 @@
 
 #define FILTER_VALID_HOOKS ((1 << NF_IP6_LOCAL_IN) | (1 << NF_IP6_FORWARD) | (1 << NF_IP6_LOCAL_OUT))
 
-/* Standard entry. */
-struct ip6t_standard
-{
-	struct ip6t_entry entry;
-	struct ip6t_standard_target target;
-};
-
-struct ip6t_error_target
-{
-	struct ip6t_entry_target target;
-	char errorname[IP6T_FUNCTION_MAXNAMELEN];
-};
-
-struct ip6t_error
-{
-	struct ip6t_entry entry;
-	struct ip6t_error_target target;
-};
-
 static struct
 {
 	struct ip6t_replace repl;
@@ -92,7 +73,7 @@
     }
 };
 
-static struct ip6t_table packet_filter = {
+static struct xt_table packet_filter = {
 	.name		= "filter",
 	.valid_hooks	= FILTER_VALID_HOOKS,
 	.lock		= RW_LOCK_UNLOCKED,
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index 6250e86..5f5aa0e 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -29,25 +29,6 @@
 #define DEBUGP(x, args...)
 #endif
 
-/* Standard entry. */
-struct ip6t_standard
-{
-	struct ip6t_entry entry;
-	struct ip6t_standard_target target;
-};
-
-struct ip6t_error_target
-{
-	struct ip6t_entry_target target;
-	char errorname[IP6T_FUNCTION_MAXNAMELEN];
-};
-
-struct ip6t_error
-{
-	struct ip6t_entry entry;
-	struct ip6t_error_target target;
-};
-
 static struct
 {
 	struct ip6t_replace repl;
@@ -122,7 +103,7 @@
     }
 };
 
-static struct ip6t_table packet_mangler = {
+static struct xt_table packet_mangler = {
 	.name		= "mangle",
 	.valid_hooks	= MANGLE_VALID_HOOKS,
 	.lock		= RW_LOCK_UNLOCKED,
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c
index b4154da..277bf34 100644
--- a/net/ipv6/netfilter/ip6table_raw.c
+++ b/net/ipv6/netfilter/ip6table_raw.c
@@ -14,25 +14,6 @@
 #define DEBUGP(x, args...)
 #endif
 
-/* Standard entry. */
-struct ip6t_standard
-{
-	struct ip6t_entry entry;
-	struct ip6t_standard_target target;
-};
-
-struct ip6t_error_target
-{
-	struct ip6t_entry_target target;
-	char errorname[IP6T_FUNCTION_MAXNAMELEN];
-};
-
-struct ip6t_error
-{
-	struct ip6t_entry entry;
-	struct ip6t_error_target target;
-};
-
 static struct
 {
 	struct ip6t_replace repl;
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 4ae1b19..c2d8059 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -815,7 +815,7 @@
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+	if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0)
 		goto out;
 
 	if (hlimit < 0) {
@@ -1094,10 +1094,19 @@
 
 static int rawv6_init_sk(struct sock *sk)
 {
-	if (inet_sk(sk)->num == IPPROTO_ICMPV6) {
-		struct raw6_sock *rp = raw6_sk(sk);
+	struct raw6_sock *rp = raw6_sk(sk);
+
+	switch (inet_sk(sk)->num) {
+	case IPPROTO_ICMPV6:
 		rp->checksum = 1;
 		rp->offset   = 2;
+		break;
+	case IPPROTO_MH:
+		rp->checksum = 1;
+		rp->offset   = 4;
+		break;
+	default:
+		break;
 	}
 	return(0);
 }
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 5f0043c..19c906f 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -311,12 +311,21 @@
 static int inline rt6_check_dev(struct rt6_info *rt, int oif)
 {
 	struct net_device *dev = rt->rt6i_dev;
-	if (!oif || dev->ifindex == oif)
+	int ret = 0;
+
+	if (!oif)
 		return 2;
-	if ((dev->flags & IFF_LOOPBACK) &&
-	    rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
-		return 1;
-	return 0;
+	if (dev->flags & IFF_LOOPBACK) {
+		if (!WARN_ON(rt->rt6i_idev == NULL) &&
+		    rt->rt6i_idev->dev->ifindex == oif)
+			ret = 1;
+		else
+			return 0;
+	}
+	if (dev->ifindex == oif)
+		return 2;
+
+	return ret;
 }
 
 static int inline rt6_check_neigh(struct rt6_info *rt)
@@ -2040,7 +2049,7 @@
 
 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*rtm), flags);
 	if (nlh == NULL)
-		return -ENOBUFS;
+		return -EMSGSIZE;
 
 	rtm = nlmsg_data(nlh);
 	rtm->rtm_family = AF_INET6;
@@ -2111,7 +2120,8 @@
 	return nlmsg_end(skb, nlh);
 
 nla_put_failure:
-	return nlmsg_cancel(skb, nlh);
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
 }
 
 int rt6_dump_route(struct rt6_info *rt, void *p_arg)
@@ -2222,9 +2232,12 @@
 		goto errout;
 
 	err = rt6_fill_node(skb, rt, NULL, NULL, 0, event, pid, seq, 0, 0);
-	/* failure implies BUG in rt6_nlmsg_size() */
-	BUG_ON(err < 0);
-
+	if (err < 0) {
+		/* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(skb);
+		goto errout;
+	}
 	err = rtnl_notify(skb, pid, RTNLGRP_IPV6_ROUTE, nlh, gfp_any());
 errout:
 	if (err < 0)
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 77b7b09..47cfead 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -686,7 +686,8 @@
 				goto done;
 			dev = t->dev;
 		}
-		err = unregister_netdevice(dev);
+		unregister_netdevice(dev);
+		err = 0;
 		break;
 
 	default:
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index c25e930..dcb7b00 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -265,7 +265,7 @@
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+	if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0)
 		goto failure;
 
 	if (saddr == NULL) {
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index f52a5c3..15e5195 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -736,7 +736,7 @@
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+	if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0)
 		goto out;
 
 	if (hlimit < 0) {
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
index 5e7d8a7..0bc866c 100644
--- a/net/ipv6/xfrm6_mode_tunnel.c
+++ b/net/ipv6/xfrm6_mode_tunnel.c
@@ -25,6 +25,12 @@
 		IP6_ECN_set_ce(inner_iph);
 }
 
+static inline void ip6ip_ecn_decapsulate(struct sk_buff *skb)
+{
+	if (INET_ECN_is_ce(ipv6_get_dsfield(skb->nh.ipv6h)))
+			IP_ECN_set_ce(skb->h.ipiph);
+}
+
 /* Add encapsulation header.
  *
  * The top IP header will be constructed per RFC 2401.  The following fields
@@ -40,6 +46,7 @@
 static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
 {
 	struct dst_entry *dst = skb->dst;
+	struct xfrm_dst *xdst = (struct xfrm_dst*)dst;
 	struct ipv6hdr *iph, *top_iph;
 	int dsfield;
 
@@ -52,16 +59,24 @@
 	skb->h.ipv6h = top_iph + 1;
 
 	top_iph->version = 6;
-	top_iph->priority = iph->priority;
-	top_iph->flow_lbl[0] = iph->flow_lbl[0];
-	top_iph->flow_lbl[1] = iph->flow_lbl[1];
-	top_iph->flow_lbl[2] = iph->flow_lbl[2];
+	if (xdst->route->ops->family == AF_INET6) {
+		top_iph->priority = iph->priority;
+		top_iph->flow_lbl[0] = iph->flow_lbl[0];
+		top_iph->flow_lbl[1] = iph->flow_lbl[1];
+		top_iph->flow_lbl[2] = iph->flow_lbl[2];
+		top_iph->nexthdr = IPPROTO_IPV6;
+	} else {
+		top_iph->priority = 0;
+		top_iph->flow_lbl[0] = 0;
+		top_iph->flow_lbl[1] = 0;
+		top_iph->flow_lbl[2] = 0;
+		top_iph->nexthdr = IPPROTO_IPIP;
+	}
 	dsfield = ipv6_get_dsfield(top_iph);
 	dsfield = INET_ECN_encapsulate(dsfield, dsfield);
 	if (x->props.flags & XFRM_STATE_NOECN)
 		dsfield &= ~INET_ECN_MASK;
 	ipv6_change_dsfield(top_iph, 0, dsfield);
-	top_iph->nexthdr = IPPROTO_IPV6; 
 	top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT);
 	ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
 	ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
@@ -72,7 +87,8 @@
 {
 	int err = -EINVAL;
 
-	if (skb->nh.raw[IP6CB(skb)->nhoff] != IPPROTO_IPV6)
+	if (skb->nh.raw[IP6CB(skb)->nhoff] != IPPROTO_IPV6
+	    && skb->nh.raw[IP6CB(skb)->nhoff] != IPPROTO_IPIP)
 		goto out;
 	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
 		goto out;
@@ -81,10 +97,16 @@
 	    (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
 		goto out;
 
-	if (x->props.flags & XFRM_STATE_DECAP_DSCP)
-		ipv6_copy_dscp(skb->nh.ipv6h, skb->h.ipv6h);
-	if (!(x->props.flags & XFRM_STATE_NOECN))
-		ipip6_ecn_decapsulate(skb);
+	if (skb->nh.raw[IP6CB(skb)->nhoff] == IPPROTO_IPV6) {
+		if (x->props.flags & XFRM_STATE_DECAP_DSCP)
+			ipv6_copy_dscp(skb->nh.ipv6h, skb->h.ipv6h);
+		if (!(x->props.flags & XFRM_STATE_NOECN))
+			ipip6_ecn_decapsulate(skb);
+	} else {
+		if (!(x->props.flags & XFRM_STATE_NOECN))
+			ip6ip_ecn_decapsulate(skb);
+		skb->protocol = htons(ETH_P_IP);
+	}
 	skb->mac.raw = memmove(skb->data - skb->mac_len,
 			       skb->mac.raw, skb->mac_len);
 	skb->nh.raw = skb->data;
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 8dffd4d..59480e9 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -131,13 +131,11 @@
 	struct dst_entry *dst, *dst_prev;
 	struct rt6_info *rt0 = (struct rt6_info*)(*dst_p);
 	struct rt6_info *rt  = rt0;
-	struct in6_addr *remote = &fl->fl6_dst;
-	struct in6_addr *local  = &fl->fl6_src;
 	struct flowi fl_tunnel = {
 		.nl_u = {
 			.ip6_u = {
-				.saddr = *local,
-				.daddr = *remote
+				.saddr = fl->fl6_src,
+				.daddr = fl->fl6_dst,
 			}
 		}
 	};
@@ -153,7 +151,6 @@
 	for (i = 0; i < nx; i++) {
 		struct dst_entry *dst1 = dst_alloc(&xfrm6_dst_ops);
 		struct xfrm_dst *xdst;
-		int tunnel = 0;
 
 		if (unlikely(dst1 == NULL)) {
 			err = -ENOBUFS;
@@ -177,19 +174,27 @@
 
 		dst1->next = dst_prev;
 		dst_prev = dst1;
-		if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
-			remote = __xfrm6_bundle_addr_remote(xfrm[i], remote);
-			local  = __xfrm6_bundle_addr_local(xfrm[i], local);
-			tunnel = 1;
-		}
+
 		__xfrm6_bundle_len_inc(&header_len, &nfheader_len, xfrm[i]);
 		trailer_len += xfrm[i]->props.trailer_len;
 
-		if (tunnel) {
-			ipv6_addr_copy(&fl_tunnel.fl6_dst, remote);
-			ipv6_addr_copy(&fl_tunnel.fl6_src, local);
+		if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL) {
+			unsigned short encap_family = xfrm[i]->props.family;
+			switch(encap_family) {
+			case AF_INET:
+				fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4;
+				fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4;
+				break;
+			case AF_INET6:
+				ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr*)&xfrm[i]->id.daddr.a6);
+				ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr*)&xfrm[i]->props.saddr.a6);
+				break;
+			default:
+				BUG_ON(1);
+			}
+
 			err = xfrm_dst_lookup((struct xfrm_dst **) &rt,
-					      &fl_tunnel, AF_INET6);
+					      &fl_tunnel, encap_family);
 			if (err)
 				goto error;
 		} else
@@ -208,6 +213,7 @@
 	i = 0;
 	for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
 		struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
+		struct xfrm_state_afinfo *afinfo;
 
 		dst_prev->xfrm = xfrm[i++];
 		dst_prev->dev = rt->u.dst.dev;
@@ -224,7 +230,17 @@
 		/* Copy neighbour for reachability confirmation */
 		dst_prev->neighbour	= neigh_clone(rt->u.dst.neighbour);
 		dst_prev->input		= rt->u.dst.input;
-		dst_prev->output	= xfrm6_output;
+		/* XXX: When IPv4 is implemented as module and can be unloaded,
+		 * we should manage reference to xfrm4_output in afinfo->output.
+		 * Miyazawa
+		 */
+		afinfo = xfrm_state_get_afinfo(dst_prev->xfrm->props.family);
+		if (!afinfo) {
+			dst = *dst_p;
+			goto error;
+		};
+		dst_prev->output = afinfo->output;
+		xfrm_state_put_afinfo(afinfo);
 		/* Sheit... I remember I did this right. Apparently,
 		 * it was magically lost, so this code needs audit */
 		x->u.rt6.rt6i_flags    = rt0->rt6i_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL);
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index 9ddaa9d..60ad5f0 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -171,6 +171,7 @@
 	.init_tempsel		= __xfrm6_init_tempsel,
 	.tmpl_sort		= __xfrm6_tmpl_sort,
 	.state_sort		= __xfrm6_state_sort,
+	.output			= xfrm6_output,
 };
 
 void __init xfrm6_state_init(void)
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
index 76c6615..89f283c 100644
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -2035,19 +2035,27 @@
 
 	ipxitf_cleanup();
 
-	unregister_snap_client(pSNAP_datalink);
-	pSNAP_datalink = NULL;
+	if (pSNAP_datalink) {
+		unregister_snap_client(pSNAP_datalink);
+		pSNAP_datalink = NULL;
+	}
 
-	unregister_8022_client(p8022_datalink);
-	p8022_datalink = NULL;
+	if (p8022_datalink) {
+		unregister_8022_client(p8022_datalink);
+		p8022_datalink = NULL;
+	}
 
 	dev_remove_pack(&ipx_8023_packet_type);
-	destroy_8023_client(p8023_datalink);
-	p8023_datalink = NULL;
+	if (p8023_datalink) {
+		destroy_8023_client(p8023_datalink);
+		p8023_datalink = NULL;
+	}
 
 	dev_remove_pack(&ipx_dix_packet_type);
-	destroy_EII_client(pEII_datalink);
-	pEII_datalink = NULL;
+	if (pEII_datalink) {
+		destroy_EII_client(pEII_datalink);
+		pEII_datalink = NULL;
+	}
 
 	proto_unregister(&ipx_proto);
 	sock_unregister(ipx_family_ops.family);
diff --git a/net/irda/irias_object.c b/net/irda/irias_object.c
index b1ee99a..2a571b4 100644
--- a/net/irda/irias_object.c
+++ b/net/irda/irias_object.c
@@ -91,6 +91,12 @@
 
 	obj->magic = IAS_OBJECT_MAGIC;
 	obj->name = strndup(name, IAS_MAX_CLASSNAME);
+	if (!obj->name) {
+		IRDA_WARNING("%s(), Unable to allocate name!\n",
+			     __FUNCTION__);
+		kfree(obj);
+		return NULL;
+	}
 	obj->id = id;
 
 	/* Locking notes : the attrib spinlock has lower precendence
@@ -101,6 +107,7 @@
 	if (obj->attribs == NULL) {
 		IRDA_WARNING("%s(), Unable to allocate attribs!\n",
 			     __FUNCTION__);
+		kfree(obj->name);
 		kfree(obj);
 		return NULL;
 	}
@@ -357,6 +364,15 @@
 
 	/* Insert value */
 	attrib->value = irias_new_integer_value(value);
+	if (!attrib->name || !attrib->value) {
+		IRDA_WARNING("%s: Unable to allocate attribute!\n",
+			     __FUNCTION__);
+		if (attrib->value)
+			irias_delete_value(attrib->value);
+		kfree(attrib->name);
+		kfree(attrib);
+		return;
+	}
 
 	irias_add_attrib(obj, attrib, owner);
 }
@@ -391,6 +407,15 @@
 	attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
 
 	attrib->value = irias_new_octseq_value( octets, len);
+	if (!attrib->name || !attrib->value) {
+		IRDA_WARNING("%s: Unable to allocate attribute!\n",
+			     __FUNCTION__);
+		if (attrib->value)
+			irias_delete_value(attrib->value);
+		kfree(attrib->name);
+		kfree(attrib);
+		return;
+	}
 
 	irias_add_attrib(obj, attrib, owner);
 }
@@ -424,6 +449,15 @@
 	attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
 
 	attrib->value = irias_new_string_value(value);
+	if (!attrib->name || !attrib->value) {
+		IRDA_WARNING("%s: Unable to allocate attribute!\n",
+			     __FUNCTION__);
+		if (attrib->value)
+			irias_delete_value(attrib->value);
+		kfree(attrib->name);
+		kfree(attrib);
+		return;
+	}
 
 	irias_add_attrib(obj, attrib, owner);
 }
@@ -473,6 +507,12 @@
 	value->type = IAS_STRING;
 	value->charset = CS_ASCII;
 	value->t.string = strndup(string, IAS_MAX_STRING);
+	if (!value->t.string) {
+		IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+		kfree(value);
+		return NULL;
+	}
+
 	value->len = strlen(value->t.string);
 
 	return value;
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c
index 2bb04ac..310776d 100644
--- a/net/irda/irlan/irlan_common.c
+++ b/net/irda/irlan/irlan_common.c
@@ -144,12 +144,18 @@
 	/* Register with IrLMP as a client */
 	ckey = irlmp_register_client(hints, &irlan_client_discovery_indication,
 				     NULL, NULL);
-	
+	if (!ckey)
+		goto err_ckey;
+
 	/* Register with IrLMP as a service */
- 	skey = irlmp_register_service(hints);
+	skey = irlmp_register_service(hints);
+	if (!skey)
+		goto err_skey;
 
 	/* Start the master IrLAN instance (the only one for now) */
- 	new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY);
+	new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY);
+	if (!new)
+		goto err_open;
 
 	/* The master will only open its (listen) control TSAP */
 	irlan_provider_open_ctrl_tsap(new);
@@ -158,6 +164,17 @@
 	irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
 
 	return 0;
+
+err_open:
+	irlmp_unregister_service(skey);
+err_skey:
+	irlmp_unregister_client(ckey);
+err_ckey:
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("irlan", proc_irda);
+#endif /* CONFIG_PROC_FS */
+
+	return -ENOMEM;
 }
 
 static void __exit irlan_cleanup(void) 
diff --git a/net/iucv/Kconfig b/net/iucv/Kconfig
new file mode 100644
index 0000000..f8fcc3d
--- /dev/null
+++ b/net/iucv/Kconfig
@@ -0,0 +1,15 @@
+config IUCV
+	tristate "IUCV support (VM only)"
+	depends on S390
+	help
+	  Select this option if you want to use inter-user communication under
+	  VM or VIF sockets. If you run on z/VM, say "Y" to enable a fast
+	  communication link between VM guests.
+
+config AFIUCV
+	tristate "AF_IUCV support (VM only)"
+	depends on IUCV
+	help
+	  Select this option if you want to use inter-user communication under
+	  VM or VIF sockets. If you run on z/VM, say "Y" to enable a fast
+	  communication link between VM guests.
diff --git a/net/iucv/Makefile b/net/iucv/Makefile
new file mode 100644
index 0000000..7bfdc85
--- /dev/null
+++ b/net/iucv/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for IUCV
+#
+
+obj-$(CONFIG_IUCV)	+= iucv.o
+obj-$(CONFIG_AFIUCV)	+= af_iucv.o
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
new file mode 100644
index 0000000..acc9421
--- /dev/null
+++ b/net/iucv/af_iucv.c
@@ -0,0 +1,1077 @@
+/*
+ *  linux/net/iucv/af_iucv.c
+ *
+ *  IUCV protocol stack for Linux on zSeries
+ *
+ *  Copyright 2006 IBM Corporation
+ *
+ *  Author(s):	Jennifer Hunt <jenhunt@us.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <net/sock.h>
+#include <asm/ebcdic.h>
+#include <asm/cpcmd.h>
+#include <linux/kmod.h>
+
+#include <net/iucv/iucv.h>
+#include <net/iucv/af_iucv.h>
+
+#define CONFIG_IUCV_SOCK_DEBUG 1
+
+#define IPRMDATA 0x80
+#define VERSION "1.0"
+
+static char iucv_userid[80];
+
+static struct proto_ops iucv_sock_ops;
+
+static struct proto iucv_proto = {
+	.name		= "AF_IUCV",
+	.owner		= THIS_MODULE,
+	.obj_size	= sizeof(struct iucv_sock),
+};
+
+/* Call Back functions */
+static void iucv_callback_rx(struct iucv_path *, struct iucv_message *);
+static void iucv_callback_txdone(struct iucv_path *, struct iucv_message *);
+static void iucv_callback_connack(struct iucv_path *, u8 ipuser[16]);
+static int iucv_callback_connreq(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]);
+static void iucv_callback_connrej(struct iucv_path *, u8 ipuser[16]);
+
+static struct iucv_sock_list iucv_sk_list = {
+	.lock = RW_LOCK_UNLOCKED,
+	.autobind_name = ATOMIC_INIT(0)
+};
+
+static struct iucv_handler af_iucv_handler = {
+	.path_pending	  = iucv_callback_connreq,
+	.path_complete	  = iucv_callback_connack,
+	.path_severed	  = iucv_callback_connrej,
+	.message_pending  = iucv_callback_rx,
+	.message_complete = iucv_callback_txdone
+};
+
+static inline void high_nmcpy(unsigned char *dst, char *src)
+{
+       memcpy(dst, src, 8);
+}
+
+static inline void low_nmcpy(unsigned char *dst, char *src)
+{
+       memcpy(&dst[8], src, 8);
+}
+
+/* Timers */
+static void iucv_sock_timeout(unsigned long arg)
+{
+	struct sock *sk = (struct sock *)arg;
+
+	bh_lock_sock(sk);
+	sk->sk_err = ETIMEDOUT;
+	sk->sk_state_change(sk);
+	bh_unlock_sock(sk);
+
+	iucv_sock_kill(sk);
+	sock_put(sk);
+}
+
+static void iucv_sock_clear_timer(struct sock *sk)
+{
+	sk_stop_timer(sk, &sk->sk_timer);
+}
+
+static void iucv_sock_init_timer(struct sock *sk)
+{
+	init_timer(&sk->sk_timer);
+	sk->sk_timer.function = iucv_sock_timeout;
+	sk->sk_timer.data = (unsigned long)sk;
+}
+
+static struct sock *__iucv_get_sock_by_name(char *nm)
+{
+	struct sock *sk;
+	struct hlist_node *node;
+
+	sk_for_each(sk, node, &iucv_sk_list.head)
+		if (!memcmp(&iucv_sk(sk)->src_name, nm, 8))
+			return sk;
+
+	return NULL;
+}
+
+static void iucv_sock_destruct(struct sock *sk)
+{
+	skb_queue_purge(&sk->sk_receive_queue);
+	skb_queue_purge(&sk->sk_write_queue);
+}
+
+/* Cleanup Listen */
+static void iucv_sock_cleanup_listen(struct sock *parent)
+{
+	struct sock *sk;
+
+	/* Close non-accepted connections */
+	while ((sk = iucv_accept_dequeue(parent, NULL))) {
+		iucv_sock_close(sk);
+		iucv_sock_kill(sk);
+	}
+
+	parent->sk_state = IUCV_CLOSED;
+	sock_set_flag(parent, SOCK_ZAPPED);
+}
+
+/* Kill socket */
+static void iucv_sock_kill(struct sock *sk)
+{
+	if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
+		return;
+
+	iucv_sock_unlink(&iucv_sk_list, sk);
+	sock_set_flag(sk, SOCK_DEAD);
+	sock_put(sk);
+}
+
+/* Close an IUCV socket */
+static void iucv_sock_close(struct sock *sk)
+{
+	unsigned char user_data[16];
+	struct iucv_sock *iucv = iucv_sk(sk);
+	int err;
+
+	iucv_sock_clear_timer(sk);
+	lock_sock(sk);
+
+	switch(sk->sk_state) {
+	case IUCV_LISTEN:
+		iucv_sock_cleanup_listen(sk);
+		break;
+
+	case IUCV_CONNECTED:
+	case IUCV_DISCONN:
+		err = 0;
+		if (iucv->path) {
+			low_nmcpy(user_data, iucv->src_name);
+			high_nmcpy(user_data, iucv->dst_name);
+			ASCEBC(user_data, sizeof(user_data));
+			err = iucv_path_sever(iucv->path, user_data);
+			iucv_path_free(iucv->path);
+			iucv->path = NULL;
+		}
+
+		sk->sk_state = IUCV_CLOSED;
+		sk->sk_state_change(sk);
+		sk->sk_err = ECONNRESET;
+		sk->sk_state_change(sk);
+
+		skb_queue_purge(&iucv->send_skb_q);
+
+		sock_set_flag(sk, SOCK_ZAPPED);
+		break;
+
+	default:
+		sock_set_flag(sk, SOCK_ZAPPED);
+		break;
+	};
+
+	release_sock(sk);
+	iucv_sock_kill(sk);
+}
+
+static void iucv_sock_init(struct sock *sk, struct sock *parent)
+{
+	if (parent)
+		sk->sk_type = parent->sk_type;
+}
+
+static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio)
+{
+	struct sock *sk;
+
+	sk = sk_alloc(PF_IUCV, prio, &iucv_proto, 1);
+	if (!sk)
+		return NULL;
+
+	sock_init_data(sock, sk);
+	INIT_LIST_HEAD(&iucv_sk(sk)->accept_q);
+	skb_queue_head_init(&iucv_sk(sk)->send_skb_q);
+	iucv_sk(sk)->send_tag = 0;
+
+	sk->sk_destruct = iucv_sock_destruct;
+	sk->sk_sndtimeo = IUCV_CONN_TIMEOUT;
+	sk->sk_allocation = GFP_DMA;
+
+	sock_reset_flag(sk, SOCK_ZAPPED);
+
+	sk->sk_protocol = proto;
+	sk->sk_state	= IUCV_OPEN;
+
+	iucv_sock_init_timer(sk);
+
+	iucv_sock_link(&iucv_sk_list, sk);
+	return sk;
+}
+
+/* Create an IUCV socket */
+static int iucv_sock_create(struct socket *sock, int protocol)
+{
+	struct sock *sk;
+
+	if (sock->type != SOCK_STREAM)
+		return -ESOCKTNOSUPPORT;
+
+	sock->state = SS_UNCONNECTED;
+	sock->ops = &iucv_sock_ops;
+
+	sk = iucv_sock_alloc(sock, protocol, GFP_KERNEL);
+	if (!sk)
+		return -ENOMEM;
+
+	iucv_sock_init(sk, NULL);
+
+	return 0;
+}
+
+void iucv_sock_link(struct iucv_sock_list *l, struct sock *sk)
+{
+	write_lock_bh(&l->lock);
+	sk_add_node(sk, &l->head);
+	write_unlock_bh(&l->lock);
+}
+
+void iucv_sock_unlink(struct iucv_sock_list *l, struct sock *sk)
+{
+	write_lock_bh(&l->lock);
+	sk_del_node_init(sk);
+	write_unlock_bh(&l->lock);
+}
+
+void iucv_accept_enqueue(struct sock *parent, struct sock *sk)
+{
+	sock_hold(sk);
+	list_add_tail(&iucv_sk(sk)->accept_q, &iucv_sk(parent)->accept_q);
+	iucv_sk(sk)->parent = parent;
+	parent->sk_ack_backlog++;
+}
+
+void iucv_accept_unlink(struct sock *sk)
+{
+	list_del_init(&iucv_sk(sk)->accept_q);
+	iucv_sk(sk)->parent->sk_ack_backlog--;
+	iucv_sk(sk)->parent = NULL;
+	sock_put(sk);
+}
+
+struct sock *iucv_accept_dequeue(struct sock *parent, struct socket *newsock)
+{
+	struct iucv_sock *isk, *n;
+	struct sock *sk;
+
+	list_for_each_entry_safe(isk, n, &iucv_sk(parent)->accept_q, accept_q){
+		sk = (struct sock *) isk;
+		lock_sock(sk);
+
+		if (sk->sk_state == IUCV_CLOSED) {
+			release_sock(sk);
+			iucv_accept_unlink(sk);
+			continue;
+		}
+
+		if (sk->sk_state == IUCV_CONNECTED ||
+		    sk->sk_state == IUCV_SEVERED ||
+		    !newsock) {
+			iucv_accept_unlink(sk);
+			if (newsock)
+				sock_graft(sk, newsock);
+
+			if (sk->sk_state == IUCV_SEVERED)
+				sk->sk_state = IUCV_DISCONN;
+
+			release_sock(sk);
+			return sk;
+		}
+
+		release_sock(sk);
+	}
+	return NULL;
+}
+
+int iucv_sock_wait_state(struct sock *sk, int state, int state2,
+			 unsigned long timeo)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int err = 0;
+
+	add_wait_queue(sk->sk_sleep, &wait);
+	while (sk->sk_state != state && sk->sk_state != state2) {
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		if (!timeo) {
+			err = -EAGAIN;
+			break;
+		}
+
+		if (signal_pending(current)) {
+			err = sock_intr_errno(timeo);
+			break;
+		}
+
+		release_sock(sk);
+		timeo = schedule_timeout(timeo);
+		lock_sock(sk);
+
+		err = sock_error(sk);
+		if (err)
+			break;
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sk_sleep, &wait);
+	return err;
+}
+
+/* Bind an unbound socket */
+static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr,
+			  int addr_len)
+{
+	struct sockaddr_iucv *sa = (struct sockaddr_iucv *) addr;
+	struct sock *sk = sock->sk;
+	struct iucv_sock *iucv;
+	int err;
+
+	/* Verify the input sockaddr */
+	if (!addr || addr->sa_family != AF_IUCV)
+		return -EINVAL;
+
+	lock_sock(sk);
+	if (sk->sk_state != IUCV_OPEN) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	write_lock_bh(&iucv_sk_list.lock);
+
+	iucv = iucv_sk(sk);
+	if (__iucv_get_sock_by_name(sa->siucv_name)) {
+		err = -EADDRINUSE;
+		goto done_unlock;
+	}
+	if (iucv->path) {
+		err = 0;
+		goto done_unlock;
+	}
+
+	/* Bind the socket */
+	memcpy(iucv->src_name, sa->siucv_name, 8);
+
+	/* Copy the user id */
+	memcpy(iucv->src_user_id, iucv_userid, 8);
+	sk->sk_state = IUCV_BOUND;
+	err = 0;
+
+done_unlock:
+	/* Release the socket list lock */
+	write_unlock_bh(&iucv_sk_list.lock);
+done:
+	release_sock(sk);
+	return err;
+}
+
+/* Automatically bind an unbound socket */
+static int iucv_sock_autobind(struct sock *sk)
+{
+	struct iucv_sock *iucv = iucv_sk(sk);
+	char query_buffer[80];
+	char name[12];
+	int err = 0;
+
+	/* Set the userid and name */
+	cpcmd("QUERY USERID", query_buffer, sizeof(query_buffer), &err);
+	if (unlikely(err))
+		return -EPROTO;
+
+	memcpy(iucv->src_user_id, query_buffer, 8);
+
+	write_lock_bh(&iucv_sk_list.lock);
+
+	sprintf(name, "%08x", atomic_inc_return(&iucv_sk_list.autobind_name));
+	while (__iucv_get_sock_by_name(name)) {
+		sprintf(name, "%08x",
+			atomic_inc_return(&iucv_sk_list.autobind_name));
+	}
+
+	write_unlock_bh(&iucv_sk_list.lock);
+
+	memcpy(&iucv->src_name, name, 8);
+
+	return err;
+}
+
+/* Connect an unconnected socket */
+static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
+			     int alen, int flags)
+{
+	struct sockaddr_iucv *sa = (struct sockaddr_iucv *) addr;
+	struct sock *sk = sock->sk;
+	struct iucv_sock *iucv;
+	unsigned char user_data[16];
+	int err;
+
+	if (addr->sa_family != AF_IUCV || alen < sizeof(struct sockaddr_iucv))
+		return -EINVAL;
+
+	if (sk->sk_state != IUCV_OPEN && sk->sk_state != IUCV_BOUND)
+		return -EBADFD;
+
+	if (sk->sk_type != SOCK_STREAM)
+		return -EINVAL;
+
+	iucv = iucv_sk(sk);
+
+	if (sk->sk_state == IUCV_OPEN) {
+		err = iucv_sock_autobind(sk);
+		if (unlikely(err))
+			return err;
+	}
+
+	lock_sock(sk);
+
+	/* Set the destination information */
+	memcpy(iucv_sk(sk)->dst_user_id, sa->siucv_user_id, 8);
+	memcpy(iucv_sk(sk)->dst_name, sa->siucv_name, 8);
+
+	high_nmcpy(user_data, sa->siucv_name);
+	low_nmcpy(user_data, iucv_sk(sk)->src_name);
+	ASCEBC(user_data, sizeof(user_data));
+
+	iucv = iucv_sk(sk);
+	/* Create path. */
+	iucv->path = iucv_path_alloc(IUCV_QUEUELEN_DEFAULT,
+				     IPRMDATA, GFP_KERNEL);
+	err = iucv_path_connect(iucv->path, &af_iucv_handler,
+				sa->siucv_user_id, NULL, user_data, sk);
+	if (err) {
+		iucv_path_free(iucv->path);
+		iucv->path = NULL;
+		err = -ECONNREFUSED;
+		goto done;
+	}
+
+	if (sk->sk_state != IUCV_CONNECTED) {
+		err = iucv_sock_wait_state(sk, IUCV_CONNECTED, IUCV_DISCONN,
+				sock_sndtimeo(sk, flags & O_NONBLOCK));
+	}
+
+	if (sk->sk_state == IUCV_DISCONN) {
+		release_sock(sk);
+		return -ECONNREFUSED;
+	}
+done:
+	release_sock(sk);
+	return err;
+}
+
+/* Move a socket into listening state. */
+static int iucv_sock_listen(struct socket *sock, int backlog)
+{
+	struct sock *sk = sock->sk;
+	int err;
+
+	lock_sock(sk);
+
+	err = -EINVAL;
+	if (sk->sk_state != IUCV_BOUND || sock->type != SOCK_STREAM)
+		goto done;
+
+	sk->sk_max_ack_backlog = backlog;
+	sk->sk_ack_backlog = 0;
+	sk->sk_state = IUCV_LISTEN;
+	err = 0;
+
+done:
+	release_sock(sk);
+	return err;
+}
+
+/* Accept a pending connection */
+static int iucv_sock_accept(struct socket *sock, struct socket *newsock,
+			    int flags)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct sock *sk = sock->sk, *nsk;
+	long timeo;
+	int err = 0;
+
+	lock_sock(sk);
+
+	if (sk->sk_state != IUCV_LISTEN) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
+
+	/* Wait for an incoming connection */
+	add_wait_queue_exclusive(sk->sk_sleep, &wait);
+	while (!(nsk = iucv_accept_dequeue(sk, newsock))){
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (!timeo) {
+			err = -EAGAIN;
+			break;
+		}
+
+		release_sock(sk);
+		timeo = schedule_timeout(timeo);
+		lock_sock(sk);
+
+		if (sk->sk_state != IUCV_LISTEN) {
+			err = -EBADFD;
+			break;
+		}
+
+		if (signal_pending(current)) {
+			err = sock_intr_errno(timeo);
+			break;
+		}
+	}
+
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sk_sleep, &wait);
+
+	if (err)
+		goto done;
+
+	newsock->state = SS_CONNECTED;
+
+done:
+	release_sock(sk);
+	return err;
+}
+
+static int iucv_sock_getname(struct socket *sock, struct sockaddr *addr,
+			     int *len, int peer)
+{
+	struct sockaddr_iucv *siucv = (struct sockaddr_iucv *) addr;
+	struct sock *sk = sock->sk;
+
+	addr->sa_family = AF_IUCV;
+	*len = sizeof(struct sockaddr_iucv);
+
+	if (peer) {
+		memcpy(siucv->siucv_user_id, iucv_sk(sk)->dst_user_id, 8);
+		memcpy(siucv->siucv_name, &iucv_sk(sk)->dst_name, 8);
+	} else {
+		memcpy(siucv->siucv_user_id, iucv_sk(sk)->src_user_id, 8);
+		memcpy(siucv->siucv_name, iucv_sk(sk)->src_name, 8);
+	}
+	memset(&siucv->siucv_port, 0, sizeof(siucv->siucv_port));
+	memset(&siucv->siucv_addr, 0, sizeof(siucv->siucv_addr));
+	memset(siucv->siucv_nodeid, 0, sizeof(siucv->siucv_nodeid));
+
+	return 0;
+}
+
+static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
+			     struct msghdr *msg, size_t len)
+{
+	struct sock *sk = sock->sk;
+	struct iucv_sock *iucv = iucv_sk(sk);
+	struct sk_buff *skb;
+	struct iucv_message txmsg;
+	int err;
+
+	err = sock_error(sk);
+	if (err)
+		return err;
+
+	if (msg->msg_flags & MSG_OOB)
+		return -EOPNOTSUPP;
+
+	lock_sock(sk);
+
+	if (sk->sk_shutdown & SEND_SHUTDOWN) {
+		err = -EPIPE;
+		goto out;
+	}
+
+	if (sk->sk_state == IUCV_CONNECTED){
+		if(!(skb = sock_alloc_send_skb(sk, len,
+				       msg->msg_flags & MSG_DONTWAIT,
+				       &err)))
+			return err;
+
+		if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)){
+			err = -EFAULT;
+			goto fail;
+		}
+
+		txmsg.class = 0;
+		txmsg.tag = iucv->send_tag++;
+		memcpy(skb->cb, &txmsg.tag, 4);
+		skb_queue_tail(&iucv->send_skb_q, skb);
+		err = iucv_message_send(iucv->path, &txmsg, 0, 0,
+					(void *) skb->data, skb->len);
+		if (err) {
+			if (err == 3)
+				printk(KERN_ERR "AF_IUCV msg limit exceeded\n");
+			skb_unlink(skb, &iucv->send_skb_q);
+			err = -EPIPE;
+			goto fail;
+		}
+
+	} else {
+		err = -ENOTCONN;
+		goto out;
+	}
+
+	release_sock(sk);
+	return len;
+
+fail:
+	kfree_skb(skb);
+out:
+	release_sock(sk);
+	return err;
+}
+
+static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+			     struct msghdr *msg, size_t len, int flags)
+{
+	int noblock = flags & MSG_DONTWAIT;
+	struct sock *sk = sock->sk;
+	int target, copied = 0;
+	struct sk_buff *skb;
+	int err = 0;
+
+	if (flags & (MSG_OOB))
+		return -EOPNOTSUPP;
+
+	target = sock_rcvlowat(sk, flags & MSG_WAITALL, len);
+
+	skb = skb_recv_datagram(sk, flags, noblock, &err);
+	if (!skb) {
+		if (sk->sk_shutdown & RCV_SHUTDOWN)
+			return 0;
+		return err;
+	}
+
+	copied = min_t(unsigned int, skb->len, len);
+
+	if (memcpy_toiovec(msg->msg_iov, skb->data, copied)) {
+		skb_queue_head(&sk->sk_receive_queue, skb);
+		if (copied == 0)
+			return -EFAULT;
+	}
+
+	len -= copied;
+
+	/* Mark read part of skb as used */
+	if (!(flags & MSG_PEEK)) {
+		skb_pull(skb, copied);
+
+		if (skb->len) {
+			skb_queue_head(&sk->sk_receive_queue, skb);
+			goto done;
+		}
+
+		kfree_skb(skb);
+	} else
+		skb_queue_head(&sk->sk_receive_queue, skb);
+
+done:
+	return err ? : copied;
+}
+
+static inline unsigned int iucv_accept_poll(struct sock *parent)
+{
+	struct iucv_sock *isk, *n;
+	struct sock *sk;
+
+	list_for_each_entry_safe(isk, n, &iucv_sk(parent)->accept_q, accept_q){
+		sk = (struct sock *) isk;
+
+		if (sk->sk_state == IUCV_CONNECTED)
+			return POLLIN | POLLRDNORM;
+	}
+
+	return 0;
+}
+
+unsigned int iucv_sock_poll(struct file *file, struct socket *sock,
+			    poll_table *wait)
+{
+	struct sock *sk = sock->sk;
+	unsigned int mask = 0;
+
+	poll_wait(file, sk->sk_sleep, wait);
+
+	if (sk->sk_state == IUCV_LISTEN)
+		return iucv_accept_poll(sk);
+
+	if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
+		mask |= POLLERR;
+
+	if (sk->sk_shutdown & RCV_SHUTDOWN)
+		mask |= POLLRDHUP;
+
+	if (sk->sk_shutdown == SHUTDOWN_MASK)
+		mask |= POLLHUP;
+
+	if (!skb_queue_empty(&sk->sk_receive_queue) ||
+			(sk->sk_shutdown & RCV_SHUTDOWN))
+		mask |= POLLIN | POLLRDNORM;
+
+	if (sk->sk_state == IUCV_CLOSED)
+		mask |= POLLHUP;
+
+	if (sock_writeable(sk))
+		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+	else
+		set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+
+	return mask;
+}
+
+static int iucv_sock_shutdown(struct socket *sock, int how)
+{
+	struct sock *sk = sock->sk;
+	struct iucv_sock *iucv = iucv_sk(sk);
+	struct iucv_message txmsg;
+	int err = 0;
+	u8 prmmsg[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
+
+	how++;
+
+	if ((how & ~SHUTDOWN_MASK) || !how)
+		return -EINVAL;
+
+	lock_sock(sk);
+	switch(sk->sk_state) {
+	case IUCV_CLOSED:
+		err = -ENOTCONN;
+		goto fail;
+
+	default:
+		sk->sk_shutdown |= how;
+		break;
+	}
+
+	if (how == SEND_SHUTDOWN || how == SHUTDOWN_MASK) {
+		txmsg.class = 0;
+		txmsg.tag = 0;
+		err = iucv_message_send(iucv->path, &txmsg, IUCV_IPRMDATA, 0,
+					(void *) prmmsg, 8);
+		if (err) {
+			switch(err) {
+			case 1:
+				err = -ENOTCONN;
+				break;
+			case 2:
+				err = -ECONNRESET;
+				break;
+			default:
+				err = -ENOTCONN;
+				break;
+			}
+		}
+	}
+
+	if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) {
+		err = iucv_path_quiesce(iucv_sk(sk)->path, NULL);
+		if (err)
+			err = -ENOTCONN;
+
+		skb_queue_purge(&sk->sk_receive_queue);
+	}
+
+	/* Wake up anyone sleeping in poll */
+	sk->sk_state_change(sk);
+
+fail:
+	release_sock(sk);
+	return err;
+}
+
+static int iucv_sock_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	if (!sk)
+		return 0;
+
+	iucv_sock_close(sk);
+
+	/* Unregister with IUCV base support */
+	if (iucv_sk(sk)->path) {
+		iucv_path_sever(iucv_sk(sk)->path, NULL);
+		iucv_path_free(iucv_sk(sk)->path);
+		iucv_sk(sk)->path = NULL;
+	}
+
+	if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime){
+		lock_sock(sk);
+		err = iucv_sock_wait_state(sk, IUCV_CLOSED, 0,
+					   sk->sk_lingertime);
+		release_sock(sk);
+	}
+
+	sock_orphan(sk);
+	iucv_sock_kill(sk);
+	return err;
+}
+
+/* Callback wrappers - called from iucv base support */
+static int iucv_callback_connreq(struct iucv_path *path,
+				 u8 ipvmid[8], u8 ipuser[16])
+{
+	unsigned char user_data[16];
+	unsigned char nuser_data[16];
+	unsigned char src_name[8];
+	struct hlist_node *node;
+	struct sock *sk, *nsk;
+	struct iucv_sock *iucv, *niucv;
+	int err;
+
+	memcpy(src_name, ipuser, 8);
+	EBCASC(src_name, 8);
+	/* Find out if this path belongs to af_iucv. */
+	read_lock(&iucv_sk_list.lock);
+	iucv = NULL;
+	sk_for_each(sk, node, &iucv_sk_list.head)
+		if (sk->sk_state == IUCV_LISTEN &&
+		    !memcmp(&iucv_sk(sk)->src_name, src_name, 8)) {
+			/*
+			 * Found a listening socket with
+			 * src_name == ipuser[0-7].
+			 */
+			iucv = iucv_sk(sk);
+			break;
+		}
+	read_unlock(&iucv_sk_list.lock);
+	if (!iucv)
+		/* No socket found, not one of our paths. */
+		return -EINVAL;
+
+	bh_lock_sock(sk);
+
+	/* Check if parent socket is listening */
+	low_nmcpy(user_data, iucv->src_name);
+	high_nmcpy(user_data, iucv->dst_name);
+	ASCEBC(user_data, sizeof(user_data));
+	if (sk->sk_state != IUCV_LISTEN) {
+		err = iucv_path_sever(path, user_data);
+		goto fail;
+	}
+
+	/* Check for backlog size */
+	if (sk_acceptq_is_full(sk)) {
+		err = iucv_path_sever(path, user_data);
+		goto fail;
+	}
+
+	/* Create the new socket */
+	nsk = iucv_sock_alloc(NULL, SOCK_STREAM, GFP_ATOMIC);
+	if (!nsk){
+		err = iucv_path_sever(path, user_data);
+		goto fail;
+	}
+
+	niucv = iucv_sk(nsk);
+	iucv_sock_init(nsk, sk);
+
+	/* Set the new iucv_sock */
+	memcpy(niucv->dst_name, ipuser + 8, 8);
+	EBCASC(niucv->dst_name, 8);
+	memcpy(niucv->dst_user_id, ipvmid, 8);
+	memcpy(niucv->src_name, iucv->src_name, 8);
+	memcpy(niucv->src_user_id, iucv->src_user_id, 8);
+	niucv->path = path;
+
+	/* Call iucv_accept */
+	high_nmcpy(nuser_data, ipuser + 8);
+	memcpy(nuser_data + 8, niucv->src_name, 8);
+	ASCEBC(nuser_data + 8, 8);
+
+	path->msglim = IUCV_QUEUELEN_DEFAULT;
+	err = iucv_path_accept(path, &af_iucv_handler, nuser_data, nsk);
+	if (err){
+		err = iucv_path_sever(path, user_data);
+		goto fail;
+	}
+
+	iucv_accept_enqueue(sk, nsk);
+
+	/* Wake up accept */
+	nsk->sk_state = IUCV_CONNECTED;
+	sk->sk_data_ready(sk, 1);
+	err = 0;
+fail:
+	bh_unlock_sock(sk);
+	return 0;
+}
+
+static void iucv_callback_connack(struct iucv_path *path, u8 ipuser[16])
+{
+	struct sock *sk = path->private;
+
+	sk->sk_state = IUCV_CONNECTED;
+	sk->sk_state_change(sk);
+}
+
+static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg)
+{
+	struct sock *sk = path->private;
+	struct sk_buff *skb;
+	int rc;
+
+	if (sk->sk_shutdown & RCV_SHUTDOWN)
+		return;
+
+	skb = alloc_skb(msg->length, GFP_ATOMIC | GFP_DMA);
+	if (!skb) {
+		iucv_message_reject(path, msg);
+		return;
+	}
+
+	if (msg->flags & IPRMDATA) {
+		skb->data = NULL;
+		skb->len = 0;
+	} else {
+		rc = iucv_message_receive(path, msg, 0, skb->data,
+					  msg->length, NULL);
+		if (rc) {
+			kfree_skb(skb);
+			return;
+		}
+
+		skb->h.raw = skb->data;
+		skb->nh.raw = skb->data;
+		skb->len = msg->length;
+	}
+
+	if (sock_queue_rcv_skb(sk, skb))
+		kfree_skb(skb);
+}
+
+static void iucv_callback_txdone(struct iucv_path *path,
+				 struct iucv_message *msg)
+{
+	struct sock *sk = path->private;
+	struct sk_buff *this;
+	struct sk_buff_head *list = &iucv_sk(sk)->send_skb_q;
+	struct sk_buff *list_skb = list->next;
+	unsigned long flags;
+
+	spin_lock_irqsave(&list->lock, flags);
+
+	do {
+		this = list_skb;
+		list_skb = list_skb->next;
+	} while (memcmp(&msg->tag, this->cb, 4));
+
+	spin_unlock_irqrestore(&list->lock, flags);
+
+	skb_unlink(this, &iucv_sk(sk)->send_skb_q);
+	kfree_skb(this);
+}
+
+static void iucv_callback_connrej(struct iucv_path *path, u8 ipuser[16])
+{
+	struct sock *sk = path->private;
+
+	if (!list_empty(&iucv_sk(sk)->accept_q))
+		sk->sk_state = IUCV_SEVERED;
+	else
+		sk->sk_state = IUCV_DISCONN;
+
+	sk->sk_state_change(sk);
+}
+
+static struct proto_ops iucv_sock_ops = {
+	.family		= PF_IUCV,
+	.owner		= THIS_MODULE,
+	.release	= iucv_sock_release,
+	.bind		= iucv_sock_bind,
+	.connect	= iucv_sock_connect,
+	.listen		= iucv_sock_listen,
+	.accept		= iucv_sock_accept,
+	.getname	= iucv_sock_getname,
+	.sendmsg	= iucv_sock_sendmsg,
+	.recvmsg	= iucv_sock_recvmsg,
+	.poll		= iucv_sock_poll,
+	.ioctl		= sock_no_ioctl,
+	.mmap		= sock_no_mmap,
+	.socketpair	= sock_no_socketpair,
+	.shutdown	= iucv_sock_shutdown,
+	.setsockopt	= sock_no_setsockopt,
+	.getsockopt	= sock_no_getsockopt
+};
+
+static struct net_proto_family iucv_sock_family_ops = {
+	.family	= AF_IUCV,
+	.owner	= THIS_MODULE,
+	.create	= iucv_sock_create,
+};
+
+static int afiucv_init(void)
+{
+	int err;
+
+	if (!MACHINE_IS_VM) {
+		printk(KERN_ERR "AF_IUCV connection needs VM as base\n");
+		err = -EPROTONOSUPPORT;
+		goto out;
+	}
+	cpcmd("QUERY USERID", iucv_userid, sizeof(iucv_userid), &err);
+	if (unlikely(err)) {
+		printk(KERN_ERR "AF_IUCV needs the VM userid\n");
+		err = -EPROTONOSUPPORT;
+		goto out;
+	}
+
+	err = iucv_register(&af_iucv_handler, 0);
+	if (err)
+		goto out;
+	err = proto_register(&iucv_proto, 0);
+	if (err)
+		goto out_iucv;
+	err = sock_register(&iucv_sock_family_ops);
+	if (err)
+		goto out_proto;
+	printk(KERN_INFO "AF_IUCV lowlevel driver initialized\n");
+	return 0;
+
+out_proto:
+	proto_unregister(&iucv_proto);
+out_iucv:
+	iucv_unregister(&af_iucv_handler, 0);
+out:
+	return err;
+}
+
+static void __exit afiucv_exit(void)
+{
+	sock_unregister(PF_IUCV);
+	proto_unregister(&iucv_proto);
+	iucv_unregister(&af_iucv_handler, 0);
+
+	printk(KERN_INFO "AF_IUCV lowlevel driver unloaded\n");
+}
+
+module_init(afiucv_init);
+module_exit(afiucv_exit);
+
+MODULE_AUTHOR("Jennifer Hunt <jenhunt@us.ibm.com>");
+MODULE_DESCRIPTION("IUCV Sockets ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NETPROTO(PF_IUCV);
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
new file mode 100644
index 0000000..1b10d57
--- /dev/null
+++ b/net/iucv/iucv.c
@@ -0,0 +1,1619 @@
+/*
+ * IUCV base infrastructure.
+ *
+ * Copyright 2001, 2006 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s):
+ *    Original source:
+ *	Alan Altmark (Alan_Altmark@us.ibm.com)	Sept. 2000
+ *	Xenia Tkatschow (xenia@us.ibm.com)
+ *    2Gb awareness and general cleanup:
+ *	Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
+ *    Rewritten for af_iucv:
+ *	Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *
+ * Documentation used:
+ *    The original source
+ *    CP Programming Service, IBM document # SC24-5760
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/cpu.h>
+#include <net/iucv/iucv.h>
+#include <asm/atomic.h>
+#include <asm/ebcdic.h>
+#include <asm/io.h>
+#include <asm/s390_ext.h>
+#include <asm/s390_rdev.h>
+#include <asm/smp.h>
+
+/*
+ * FLAGS:
+ * All flags are defined in the field IPFLAGS1 of each function
+ * and can be found in CP Programming Services.
+ * IPSRCCLS - Indicates you have specified a source class.
+ * IPTRGCLS - Indicates you have specified a target class.
+ * IPFGPID  - Indicates you have specified a pathid.
+ * IPFGMID  - Indicates you have specified a message ID.
+ * IPNORPY  - Indicates a one-way message. No reply expected.
+ * IPALL    - Indicates that all paths are affected.
+ */
+#define IUCV_IPSRCCLS	0x01
+#define IUCV_IPTRGCLS	0x01
+#define IUCV_IPFGPID	0x02
+#define IUCV_IPFGMID	0x04
+#define IUCV_IPNORPY	0x10
+#define IUCV_IPALL	0x80
+
+static int iucv_bus_match (struct device *dev, struct device_driver *drv)
+{
+	return 0;
+}
+
+struct bus_type iucv_bus = {
+	.name = "iucv",
+	.match = iucv_bus_match,
+};
+
+struct device *iucv_root;
+static int iucv_available;
+
+/* General IUCV interrupt structure */
+struct iucv_irq_data {
+	u16 ippathid;
+	u8  ipflags1;
+	u8  iptype;
+	u32 res2[8];
+};
+
+struct iucv_work {
+	struct list_head list;
+	struct iucv_irq_data data;
+};
+
+static LIST_HEAD(iucv_work_queue);
+static DEFINE_SPINLOCK(iucv_work_lock);
+
+static struct iucv_irq_data *iucv_irq_data;
+static cpumask_t iucv_buffer_cpumask = CPU_MASK_NONE;
+static cpumask_t iucv_irq_cpumask = CPU_MASK_NONE;
+
+static void iucv_tasklet_handler(unsigned long);
+static DECLARE_TASKLET(iucv_tasklet, iucv_tasklet_handler,0);
+
+enum iucv_command_codes {
+	IUCV_QUERY = 0,
+	IUCV_RETRIEVE_BUFFER = 2,
+	IUCV_SEND = 4,
+	IUCV_RECEIVE = 5,
+	IUCV_REPLY = 6,
+	IUCV_REJECT = 8,
+	IUCV_PURGE = 9,
+	IUCV_ACCEPT = 10,
+	IUCV_CONNECT = 11,
+	IUCV_DECLARE_BUFFER = 12,
+	IUCV_QUIESCE = 13,
+	IUCV_RESUME = 14,
+	IUCV_SEVER = 15,
+	IUCV_SETMASK = 16,
+};
+
+/*
+ * Error messages that are used with the iucv_sever function. They get
+ * converted to EBCDIC.
+ */
+static char iucv_error_no_listener[16] = "NO LISTENER";
+static char iucv_error_no_memory[16] = "NO MEMORY";
+static char iucv_error_pathid[16] = "INVALID PATHID";
+
+/*
+ * iucv_handler_list: List of registered handlers.
+ */
+static LIST_HEAD(iucv_handler_list);
+
+/*
+ * iucv_path_table: an array of iucv_path structures.
+ */
+static struct iucv_path **iucv_path_table;
+static unsigned long iucv_max_pathid;
+
+/*
+ * iucv_lock: spinlock protecting iucv_handler_list and iucv_pathid_table
+ */
+static DEFINE_SPINLOCK(iucv_table_lock);
+
+/*
+ * iucv_tasklet_cpu: contains the number of the cpu executing the tasklet.
+ * Needed for iucv_path_sever called from tasklet.
+ */
+static int iucv_tasklet_cpu = -1;
+
+/*
+ * Mutex and wait queue for iucv_register/iucv_unregister.
+ */
+static DEFINE_MUTEX(iucv_register_mutex);
+
+/*
+ * Counter for number of non-smp capable handlers.
+ */
+static int iucv_nonsmp_handler;
+
+/*
+ * IUCV control data structure. Used by iucv_path_accept, iucv_path_connect,
+ * iucv_path_quiesce and iucv_path_sever.
+ */
+struct iucv_cmd_control {
+	u16 ippathid;
+	u8  ipflags1;
+	u8  iprcode;
+	u16 ipmsglim;
+	u16 res1;
+	u8  ipvmid[8];
+	u8  ipuser[16];
+	u8  iptarget[8];
+} __attribute__ ((packed,aligned(8)));
+
+/*
+ * Data in parameter list iucv structure. Used by iucv_message_send,
+ * iucv_message_send2way and iucv_message_reply.
+ */
+struct iucv_cmd_dpl {
+	u16 ippathid;
+	u8  ipflags1;
+	u8  iprcode;
+	u32 ipmsgid;
+	u32 iptrgcls;
+	u8  iprmmsg[8];
+	u32 ipsrccls;
+	u32 ipmsgtag;
+	u32 ipbfadr2;
+	u32 ipbfln2f;
+	u32 res;
+} __attribute__ ((packed,aligned(8)));
+
+/*
+ * Data in buffer iucv structure. Used by iucv_message_receive,
+ * iucv_message_reject, iucv_message_send, iucv_message_send2way
+ * and iucv_declare_cpu.
+ */
+struct iucv_cmd_db {
+	u16 ippathid;
+	u8  ipflags1;
+	u8  iprcode;
+	u32 ipmsgid;
+	u32 iptrgcls;
+	u32 ipbfadr1;
+	u32 ipbfln1f;
+	u32 ipsrccls;
+	u32 ipmsgtag;
+	u32 ipbfadr2;
+	u32 ipbfln2f;
+	u32 res;
+} __attribute__ ((packed,aligned(8)));
+
+/*
+ * Purge message iucv structure. Used by iucv_message_purge.
+ */
+struct iucv_cmd_purge {
+	u16 ippathid;
+	u8  ipflags1;
+	u8  iprcode;
+	u32 ipmsgid;
+	u8  ipaudit[3];
+	u8  res1[5];
+	u32 res2;
+	u32 ipsrccls;
+	u32 ipmsgtag;
+	u32 res3[3];
+} __attribute__ ((packed,aligned(8)));
+
+/*
+ * Set mask iucv structure. Used by iucv_enable_cpu.
+ */
+struct iucv_cmd_set_mask {
+	u8  ipmask;
+	u8  res1[2];
+	u8  iprcode;
+	u32 res2[9];
+} __attribute__ ((packed,aligned(8)));
+
+union iucv_param {
+	struct iucv_cmd_control ctrl;
+	struct iucv_cmd_dpl dpl;
+	struct iucv_cmd_db db;
+	struct iucv_cmd_purge purge;
+	struct iucv_cmd_set_mask set_mask;
+};
+
+/*
+ * Anchor for per-cpu IUCV command parameter block.
+ */
+static union iucv_param *iucv_param;
+
+/**
+ * iucv_call_b2f0
+ * @code: identifier of IUCV call to CP.
+ * @parm: pointer to a struct iucv_parm block
+ *
+ * Calls CP to execute IUCV commands.
+ *
+ * Returns the result of the CP IUCV call.
+ */
+static inline int iucv_call_b2f0(int command, union iucv_param *parm)
+{
+	register unsigned long reg0 asm ("0");
+	register unsigned long reg1 asm ("1");
+	int ccode;
+
+	reg0 = command;
+	reg1 = virt_to_phys(parm);
+	asm volatile(
+		"	.long 0xb2f01000\n"
+		"	ipm	%0\n"
+		"	srl	%0,28\n"
+		: "=d" (ccode), "=m" (*parm), "+d" (reg0), "+a" (reg1)
+		:  "m" (*parm) : "cc");
+	return (ccode == 1) ? parm->ctrl.iprcode : ccode;
+}
+
+/**
+ * iucv_query_maxconn
+ *
+ * Determines the maximum number of connections that may be established.
+ *
+ * Returns the maximum number of connections or -EPERM is IUCV is not
+ * available.
+ */
+static int iucv_query_maxconn(void)
+{
+	register unsigned long reg0 asm ("0");
+	register unsigned long reg1 asm ("1");
+	void *param;
+	int ccode;
+
+	param = kzalloc(sizeof(union iucv_param), GFP_KERNEL|GFP_DMA);
+	if (!param)
+		return -ENOMEM;
+	reg0 = IUCV_QUERY;
+	reg1 = (unsigned long) param;
+	asm volatile (
+		"	.long	0xb2f01000\n"
+		"	ipm	%0\n"
+		"	srl	%0,28\n"
+		: "=d" (ccode), "+d" (reg0), "+d" (reg1) : : "cc");
+	if (ccode == 0)
+		iucv_max_pathid = reg0;
+	kfree(param);
+	return ccode ? -EPERM : 0;
+}
+
+/**
+ * iucv_allow_cpu
+ * @data: unused
+ *
+ * Allow iucv interrupts on this cpu.
+ */
+static void iucv_allow_cpu(void *data)
+{
+	int cpu = smp_processor_id();
+	union iucv_param *parm;
+
+	/*
+	 * Enable all iucv interrupts.
+	 * ipmask contains bits for the different interrupts
+	 *	0x80 - Flag to allow nonpriority message pending interrupts
+	 *	0x40 - Flag to allow priority message pending interrupts
+	 *	0x20 - Flag to allow nonpriority message completion interrupts
+	 *	0x10 - Flag to allow priority message completion interrupts
+	 *	0x08 - Flag to allow IUCV control interrupts
+	 */
+	parm = percpu_ptr(iucv_param, smp_processor_id());
+	memset(parm, 0, sizeof(union iucv_param));
+	parm->set_mask.ipmask = 0xf8;
+	iucv_call_b2f0(IUCV_SETMASK, parm);
+
+	/* Set indication that iucv interrupts are allowed for this cpu. */
+	cpu_set(cpu, iucv_irq_cpumask);
+}
+
+/**
+ * iucv_block_cpu
+ * @data: unused
+ *
+ * Block iucv interrupts on this cpu.
+ */
+static void iucv_block_cpu(void *data)
+{
+	int cpu = smp_processor_id();
+	union iucv_param *parm;
+
+	/* Disable all iucv interrupts. */
+	parm = percpu_ptr(iucv_param, smp_processor_id());
+	memset(parm, 0, sizeof(union iucv_param));
+	iucv_call_b2f0(IUCV_SETMASK, parm);
+
+	/* Clear indication that iucv interrupts are allowed for this cpu. */
+	cpu_clear(cpu, iucv_irq_cpumask);
+}
+
+/**
+ * iucv_declare_cpu
+ * @data: unused
+ *
+ * Declare a interupt buffer on this cpu.
+ */
+static void iucv_declare_cpu(void *data)
+{
+	int cpu = smp_processor_id();
+	union iucv_param *parm;
+	int rc;
+
+	if (cpu_isset(cpu, iucv_buffer_cpumask))
+		return;
+
+	/* Declare interrupt buffer. */
+	parm = percpu_ptr(iucv_param, cpu);
+	memset(parm, 0, sizeof(union iucv_param));
+	parm->db.ipbfadr1 = virt_to_phys(percpu_ptr(iucv_irq_data, cpu));
+	rc = iucv_call_b2f0(IUCV_DECLARE_BUFFER, parm);
+	if (rc) {
+		char *err = "Unknown";
+		switch(rc) {
+		case 0x03:
+			err = "Directory error";
+			break;
+		case 0x0a:
+			err = "Invalid length";
+			break;
+		case 0x13:
+			err = "Buffer already exists";
+			break;
+		case 0x3e:
+			err = "Buffer overlap";
+			break;
+		case 0x5c:
+			err = "Paging or storage error";
+			break;
+		}
+		printk(KERN_WARNING "iucv_register: iucv_declare_buffer "
+		       "on cpu %i returned error 0x%02x (%s)\n", cpu, rc, err);
+		return;
+	}
+
+	/* Set indication that an iucv buffer exists for this cpu. */
+	cpu_set(cpu, iucv_buffer_cpumask);
+
+	if (iucv_nonsmp_handler == 0 || cpus_empty(iucv_irq_cpumask))
+		/* Enable iucv interrupts on this cpu. */
+		iucv_allow_cpu(NULL);
+	else
+		/* Disable iucv interrupts on this cpu. */
+		iucv_block_cpu(NULL);
+}
+
+/**
+ * iucv_retrieve_cpu
+ * @data: unused
+ *
+ * Retrieve interrupt buffer on this cpu.
+ */
+static void iucv_retrieve_cpu(void *data)
+{
+	int cpu = smp_processor_id();
+	union iucv_param *parm;
+
+	if (!cpu_isset(cpu, iucv_buffer_cpumask))
+		return;
+
+	/* Block iucv interrupts. */
+	iucv_block_cpu(NULL);
+
+	/* Retrieve interrupt buffer. */
+	parm = percpu_ptr(iucv_param, cpu);
+	iucv_call_b2f0(IUCV_RETRIEVE_BUFFER, parm);
+
+	/* Clear indication that an iucv buffer exists for this cpu. */
+	cpu_clear(cpu, iucv_buffer_cpumask);
+}
+
+/**
+ * iucv_setmask_smp
+ *
+ * Allow iucv interrupts on all cpus.
+ */
+static void iucv_setmask_mp(void)
+{
+	int cpu;
+
+	for_each_online_cpu(cpu)
+		/* Enable all cpus with a declared buffer. */
+		if (cpu_isset(cpu, iucv_buffer_cpumask) &&
+		    !cpu_isset(cpu, iucv_irq_cpumask))
+			smp_call_function_on(iucv_allow_cpu, NULL, 0, 1, cpu);
+}
+
+/**
+ * iucv_setmask_up
+ *
+ * Allow iucv interrupts on a single cpus.
+ */
+static void iucv_setmask_up(void)
+{
+	cpumask_t cpumask;
+	int cpu;
+
+	/* Disable all cpu but the first in cpu_irq_cpumask. */
+	cpumask = iucv_irq_cpumask;
+	cpu_clear(first_cpu(iucv_irq_cpumask), cpumask);
+	for_each_cpu_mask(cpu, cpumask)
+		smp_call_function_on(iucv_block_cpu, NULL, 0, 1, cpu);
+}
+
+/**
+ * iucv_enable
+ *
+ * This function makes iucv ready for use. It allocates the pathid
+ * table, declares an iucv interrupt buffer and enables the iucv
+ * interrupts. Called when the first user has registered an iucv
+ * handler.
+ */
+static int iucv_enable(void)
+{
+	size_t alloc_size;
+	int cpu, rc;
+
+	rc = -ENOMEM;
+	alloc_size = iucv_max_pathid * sizeof(struct iucv_path);
+	iucv_path_table = kzalloc(alloc_size, GFP_KERNEL);
+	if (!iucv_path_table)
+		goto out;
+	/* Declare per cpu buffers. */
+	rc = -EIO;
+	for_each_online_cpu(cpu)
+		smp_call_function_on(iucv_declare_cpu, NULL, 0, 1, cpu);
+	if (cpus_empty(iucv_buffer_cpumask))
+		/* No cpu could declare an iucv buffer. */
+		goto out_path;
+	return 0;
+
+out_path:
+	kfree(iucv_path_table);
+out:
+	return rc;
+}
+
+/**
+ * iucv_disable
+ *
+ * This function shuts down iucv. It disables iucv interrupts, retrieves
+ * the iucv interrupt buffer and frees the pathid table. Called after the
+ * last user unregister its iucv handler.
+ */
+static void iucv_disable(void)
+{
+	on_each_cpu(iucv_retrieve_cpu, NULL, 0, 1);
+	kfree(iucv_path_table);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static int __cpuinit iucv_cpu_notify(struct notifier_block *self,
+				     unsigned long action, void *hcpu)
+{
+	cpumask_t cpumask;
+	long cpu = (long) hcpu;
+
+	switch (action) {
+	case CPU_UP_PREPARE:
+		if (!percpu_populate(iucv_irq_data,
+				     sizeof(struct iucv_irq_data),
+				     GFP_KERNEL|GFP_DMA, cpu))
+			return NOTIFY_BAD;
+		if (!percpu_populate(iucv_param, sizeof(union iucv_param),
+				     GFP_KERNEL|GFP_DMA, cpu)) {
+			percpu_depopulate(iucv_irq_data, cpu);
+			return NOTIFY_BAD;
+		}
+		break;
+	case CPU_UP_CANCELED:
+	case CPU_DEAD:
+		percpu_depopulate(iucv_param, cpu);
+		percpu_depopulate(iucv_irq_data, cpu);
+		break;
+	case CPU_ONLINE:
+	case CPU_DOWN_FAILED:
+		smp_call_function_on(iucv_declare_cpu, NULL, 0, 1, cpu);
+		break;
+	case CPU_DOWN_PREPARE:
+		cpumask = iucv_buffer_cpumask;
+		cpu_clear(cpu, cpumask);
+		if (cpus_empty(cpumask))
+			/* Can't offline last IUCV enabled cpu. */
+			return NOTIFY_BAD;
+		smp_call_function_on(iucv_retrieve_cpu, NULL, 0, 1, cpu);
+		if (cpus_empty(iucv_irq_cpumask))
+			smp_call_function_on(iucv_allow_cpu, NULL, 0, 1,
+					     first_cpu(iucv_buffer_cpumask));
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block iucv_cpu_notifier = {
+	.notifier_call = iucv_cpu_notify,
+};
+#endif
+
+/**
+ * iucv_sever_pathid
+ * @pathid: path identification number.
+ * @userdata: 16-bytes of user data.
+ *
+ * Sever an iucv path to free up the pathid. Used internally.
+ */
+static int iucv_sever_pathid(u16 pathid, u8 userdata[16])
+{
+	union iucv_param *parm;
+
+	parm = percpu_ptr(iucv_param, smp_processor_id());
+	memset(parm, 0, sizeof(union iucv_param));
+	if (userdata)
+		memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
+	parm->ctrl.ippathid = pathid;
+	return iucv_call_b2f0(IUCV_SEVER, parm);
+}
+
+/**
+ * __iucv_cleanup_pathid
+ * @dummy: unused dummy argument
+ *
+ * Nop function called via smp_call_function to force work items from
+ * pending external iucv interrupts to the work queue.
+ */
+static void __iucv_cleanup_pathid(void *dummy)
+{
+}
+
+/**
+ * iucv_cleanup_pathid
+ * @pathid: 16 bit pathid
+ *
+ * Function called after a path has been severed to find all remaining
+ * work items for the now stale pathid. The caller needs to hold the
+ * iucv_table_lock.
+ */
+static void iucv_cleanup_pathid(u16 pathid)
+{
+	struct iucv_work *p, *n;
+
+	/*
+	 * Path is severed, the pathid can be reused immediatly on
+	 * a iucv connect or a connection pending interrupt.
+	 * iucv_path_connect and connection pending interrupt will
+	 * wait until the iucv_table_lock is released before the
+	 * recycled pathid enters the system.
+	 * Force remaining interrupts to the work queue, then
+	 * scan the work queue for items of this path.
+	 */
+	smp_call_function(__iucv_cleanup_pathid, NULL, 0, 1);
+	spin_lock_irq(&iucv_work_lock);
+	list_for_each_entry_safe(p, n, &iucv_work_queue, list) {
+		/* Remove work items for pathid except connection pending */
+		if (p->data.ippathid == pathid && p->data.iptype != 0x01) {
+			list_del(&p->list);
+			kfree(p);
+		}
+	}
+	spin_unlock_irq(&iucv_work_lock);
+}
+
+/**
+ * iucv_register:
+ * @handler: address of iucv handler structure
+ * @smp: != 0 indicates that the handler can deal with out of order messages
+ *
+ * Registers a driver with IUCV.
+ *
+ * Returns 0 on success, -ENOMEM if the memory allocation for the pathid
+ * table failed, or -EIO if IUCV_DECLARE_BUFFER failed on all cpus.
+ */
+int iucv_register(struct iucv_handler *handler, int smp)
+{
+	int rc;
+
+	if (!iucv_available)
+		return -ENOSYS;
+	mutex_lock(&iucv_register_mutex);
+	if (!smp)
+		iucv_nonsmp_handler++;
+	if (list_empty(&iucv_handler_list)) {
+		rc = iucv_enable();
+		if (rc)
+			goto out_mutex;
+	} else if (!smp && iucv_nonsmp_handler == 1)
+		iucv_setmask_up();
+	INIT_LIST_HEAD(&handler->paths);
+
+	spin_lock_irq(&iucv_table_lock);
+	list_add_tail(&handler->list, &iucv_handler_list);
+	spin_unlock_irq(&iucv_table_lock);
+	rc = 0;
+out_mutex:
+	mutex_unlock(&iucv_register_mutex);
+	return rc;
+}
+
+/**
+ * iucv_unregister
+ * @handler:  address of iucv handler structure
+ * @smp: != 0 indicates that the handler can deal with out of order messages
+ *
+ * Unregister driver from IUCV.
+ */
+void iucv_unregister(struct iucv_handler *handler, int smp)
+{
+	struct iucv_path *p, *n;
+
+	mutex_lock(&iucv_register_mutex);
+	spin_lock_bh(&iucv_table_lock);
+	/* Remove handler from the iucv_handler_list. */
+	list_del_init(&handler->list);
+	/* Sever all pathids still refering to the handler. */
+	list_for_each_entry_safe(p, n, &handler->paths, list) {
+		iucv_sever_pathid(p->pathid, NULL);
+		iucv_path_table[p->pathid] = NULL;
+		list_del(&p->list);
+		iucv_cleanup_pathid(p->pathid);
+		iucv_path_free(p);
+	}
+	spin_unlock_bh(&iucv_table_lock);
+	if (!smp)
+		iucv_nonsmp_handler--;
+	if (list_empty(&iucv_handler_list))
+		iucv_disable();
+	else if (!smp && iucv_nonsmp_handler == 0)
+		iucv_setmask_mp();
+	mutex_unlock(&iucv_register_mutex);
+}
+
+/**
+ * iucv_path_accept
+ * @path: address of iucv path structure
+ * @handler: address of iucv handler structure
+ * @userdata: 16 bytes of data reflected to the communication partner
+ * @private: private data passed to interrupt handlers for this path
+ *
+ * This function is issued after the user received a connection pending
+ * external interrupt and now wishes to complete the IUCV communication path.
+ *
+ * Returns the result of the CP IUCV call.
+ */
+int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler,
+		     u8 userdata[16], void *private)
+{
+	union iucv_param *parm;
+	int rc;
+
+	local_bh_disable();
+	/* Prepare parameter block. */
+	parm = percpu_ptr(iucv_param, smp_processor_id());
+	memset(parm, 0, sizeof(union iucv_param));
+	parm->ctrl.ippathid = path->pathid;
+	parm->ctrl.ipmsglim = path->msglim;
+	if (userdata)
+		memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
+	parm->ctrl.ipflags1 = path->flags;
+
+	rc = iucv_call_b2f0(IUCV_ACCEPT, parm);
+	if (!rc) {
+		path->private = private;
+		path->msglim = parm->ctrl.ipmsglim;
+		path->flags = parm->ctrl.ipflags1;
+	}
+	local_bh_enable();
+	return rc;
+}
+
+/**
+ * iucv_path_connect
+ * @path: address of iucv path structure
+ * @handler: address of iucv handler structure
+ * @userid: 8-byte user identification
+ * @system: 8-byte target system identification
+ * @userdata: 16 bytes of data reflected to the communication partner
+ * @private: private data passed to interrupt handlers for this path
+ *
+ * This function establishes an IUCV path. Although the connect may complete
+ * successfully, you are not able to use the path until you receive an IUCV
+ * Connection Complete external interrupt.
+ *
+ * Returns the result of the CP IUCV call.
+ */
+int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler,
+		      u8 userid[8], u8 system[8], u8 userdata[16],
+		      void *private)
+{
+	union iucv_param *parm;
+	int rc;
+
+	preempt_disable();
+	if (iucv_tasklet_cpu != smp_processor_id())
+		spin_lock_bh(&iucv_table_lock);
+	parm = percpu_ptr(iucv_param, smp_processor_id());
+	memset(parm, 0, sizeof(union iucv_param));
+	parm->ctrl.ipmsglim = path->msglim;
+	parm->ctrl.ipflags1 = path->flags;
+	if (userid) {
+		memcpy(parm->ctrl.ipvmid, userid, sizeof(parm->ctrl.ipvmid));
+		ASCEBC(parm->ctrl.ipvmid, sizeof(parm->ctrl.ipvmid));
+		EBC_TOUPPER(parm->ctrl.ipvmid, sizeof(parm->ctrl.ipvmid));
+	}
+	if (system) {
+		memcpy(parm->ctrl.iptarget, system,
+		       sizeof(parm->ctrl.iptarget));
+		ASCEBC(parm->ctrl.iptarget, sizeof(parm->ctrl.iptarget));
+		EBC_TOUPPER(parm->ctrl.iptarget, sizeof(parm->ctrl.iptarget));
+	}
+	if (userdata)
+		memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
+
+	rc = iucv_call_b2f0(IUCV_CONNECT, parm);
+	if (!rc) {
+		if (parm->ctrl.ippathid < iucv_max_pathid) {
+			path->pathid = parm->ctrl.ippathid;
+			path->msglim = parm->ctrl.ipmsglim;
+			path->flags = parm->ctrl.ipflags1;
+			path->handler = handler;
+			path->private = private;
+			list_add_tail(&path->list, &handler->paths);
+			iucv_path_table[path->pathid] = path;
+		} else {
+			iucv_sever_pathid(parm->ctrl.ippathid,
+					  iucv_error_pathid);
+			rc = -EIO;
+		}
+	}
+	if (iucv_tasklet_cpu != smp_processor_id())
+		spin_unlock_bh(&iucv_table_lock);
+	preempt_enable();
+	return rc;
+}
+
+/**
+ * iucv_path_quiesce:
+ * @path: address of iucv path structure
+ * @userdata: 16 bytes of data reflected to the communication partner
+ *
+ * This function temporarily suspends incoming messages on an IUCV path.
+ * You can later reactivate the path by invoking the iucv_resume function.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16])
+{
+	union iucv_param *parm;
+	int rc;
+
+	local_bh_disable();
+	parm = percpu_ptr(iucv_param, smp_processor_id());
+	memset(parm, 0, sizeof(union iucv_param));
+	if (userdata)
+		memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
+	parm->ctrl.ippathid = path->pathid;
+	rc = iucv_call_b2f0(IUCV_QUIESCE, parm);
+	local_bh_enable();
+	return rc;
+}
+
+/**
+ * iucv_path_resume:
+ * @path: address of iucv path structure
+ * @userdata: 16 bytes of data reflected to the communication partner
+ *
+ * This function resumes incoming messages on an IUCV path that has
+ * been stopped with iucv_path_quiesce.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_path_resume(struct iucv_path *path, u8 userdata[16])
+{
+	union iucv_param *parm;
+	int rc;
+
+	local_bh_disable();
+	parm = percpu_ptr(iucv_param, smp_processor_id());
+	memset(parm, 0, sizeof(union iucv_param));
+	if (userdata)
+		memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
+	parm->ctrl.ippathid = path->pathid;
+	rc = iucv_call_b2f0(IUCV_RESUME, parm);
+	local_bh_enable();
+	return rc;
+}
+
+/**
+ * iucv_path_sever
+ * @path: address of iucv path structure
+ * @userdata: 16 bytes of data reflected to the communication partner
+ *
+ * This function terminates an IUCV path.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_path_sever(struct iucv_path *path, u8 userdata[16])
+{
+	int rc;
+
+
+	preempt_disable();
+	if (iucv_tasklet_cpu != smp_processor_id())
+		spin_lock_bh(&iucv_table_lock);
+	rc = iucv_sever_pathid(path->pathid, userdata);
+	if (!rc) {
+		iucv_path_table[path->pathid] = NULL;
+		list_del_init(&path->list);
+		iucv_cleanup_pathid(path->pathid);
+	}
+	if (iucv_tasklet_cpu != smp_processor_id())
+		spin_unlock_bh(&iucv_table_lock);
+	preempt_enable();
+	return rc;
+}
+
+/**
+ * iucv_message_purge
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @srccls: source class of message
+ *
+ * Cancels a message you have sent.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg,
+		       u32 srccls)
+{
+	union iucv_param *parm;
+	int rc;
+
+	local_bh_disable();
+	parm = percpu_ptr(iucv_param, smp_processor_id());
+	memset(parm, 0, sizeof(union iucv_param));
+	parm->purge.ippathid = path->pathid;
+	parm->purge.ipmsgid = msg->id;
+	parm->purge.ipsrccls = srccls;
+	parm->purge.ipflags1 = IUCV_IPSRCCLS | IUCV_IPFGMID | IUCV_IPFGPID;
+	rc = iucv_call_b2f0(IUCV_PURGE, parm);
+	if (!rc) {
+		msg->audit = (*(u32 *) &parm->purge.ipaudit) >> 8;
+		msg->tag = parm->purge.ipmsgtag;
+	}
+	local_bh_enable();
+	return rc;
+}
+
+/**
+ * iucv_message_receive
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: how the message is received (IUCV_IPBUFLST)
+ * @buffer: address of data buffer or address of struct iucv_array
+ * @size: length of data buffer
+ * @residual:
+ *
+ * This function receives messages that are being sent to you over
+ * established paths. This function will deal with RMDATA messages
+ * embedded in struct iucv_message as well.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
+			 u8 flags, void *buffer, size_t size, size_t *residual)
+{
+	union iucv_param *parm;
+	struct iucv_array *array;
+	u8 *rmmsg;
+	size_t copy;
+	int rc;
+
+	if (msg->flags & IUCV_IPRMDATA) {
+		/*
+		 * Message is 8 bytes long and has been stored to the
+		 * message descriptor itself.
+		 */
+		rc = (size < 8) ? 5 : 0;
+		if (residual)
+			*residual = abs(size - 8);
+		rmmsg = msg->rmmsg;
+		if (flags & IUCV_IPBUFLST) {
+			/* Copy to struct iucv_array. */
+			size = (size < 8) ? size : 8;
+			for (array = buffer; size > 0; array++) {
+				copy = min_t(size_t, size, array->length);
+				memcpy((u8 *)(addr_t) array->address,
+				       rmmsg, copy);
+				rmmsg += copy;
+				size -= copy;
+			}
+		} else {
+			/* Copy to direct buffer. */
+			memcpy(buffer, rmmsg, min_t(size_t, size, 8));
+		}
+		return 0;
+	}
+
+	local_bh_disable();
+	parm = percpu_ptr(iucv_param, smp_processor_id());
+	memset(parm, 0, sizeof(union iucv_param));
+	parm->db.ipbfadr1 = (u32)(addr_t) buffer;
+	parm->db.ipbfln1f = (u32) size;
+	parm->db.ipmsgid = msg->id;
+	parm->db.ippathid = path->pathid;
+	parm->db.iptrgcls = msg->class;
+	parm->db.ipflags1 = (flags | IUCV_IPFGPID |
+			     IUCV_IPFGMID | IUCV_IPTRGCLS);
+	rc = iucv_call_b2f0(IUCV_RECEIVE, parm);
+	if (!rc || rc == 5) {
+		msg->flags = parm->db.ipflags1;
+		if (residual)
+			*residual = parm->db.ipbfln1f;
+	}
+	local_bh_enable();
+	return rc;
+}
+
+/**
+ * iucv_message_reject
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ *
+ * The reject function refuses a specified message. Between the time you
+ * are notified of a message and the time that you complete the message,
+ * the message may be rejected.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg)
+{
+	union iucv_param *parm;
+	int rc;
+
+	local_bh_disable();
+	parm = percpu_ptr(iucv_param, smp_processor_id());
+	memset(parm, 0, sizeof(union iucv_param));
+	parm->db.ippathid = path->pathid;
+	parm->db.ipmsgid = msg->id;
+	parm->db.iptrgcls = msg->class;
+	parm->db.ipflags1 = (IUCV_IPTRGCLS | IUCV_IPFGMID | IUCV_IPFGPID);
+	rc = iucv_call_b2f0(IUCV_REJECT, parm);
+	local_bh_enable();
+	return rc;
+}
+
+/**
+ * iucv_message_reply
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: how the reply is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST)
+ * @reply: address of reply data buffer or address of struct iucv_array
+ * @size: length of reply data buffer
+ *
+ * This function responds to the two-way messages that you receive. You
+ * must identify completely the message to which you wish to reply. ie,
+ * pathid, msgid, and trgcls. Prmmsg signifies the data is moved into
+ * the parameter list.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg,
+		       u8 flags, void *reply, size_t size)
+{
+	union iucv_param *parm;
+	int rc;
+
+	local_bh_disable();
+	parm = percpu_ptr(iucv_param, smp_processor_id());
+	memset(parm, 0, sizeof(union iucv_param));
+	if (flags & IUCV_IPRMDATA) {
+		parm->dpl.ippathid = path->pathid;
+		parm->dpl.ipflags1 = flags;
+		parm->dpl.ipmsgid = msg->id;
+		parm->dpl.iptrgcls = msg->class;
+		memcpy(parm->dpl.iprmmsg, reply, min_t(size_t, size, 8));
+	} else {
+		parm->db.ipbfadr1 = (u32)(addr_t) reply;
+		parm->db.ipbfln1f = (u32) size;
+		parm->db.ippathid = path->pathid;
+		parm->db.ipflags1 = flags;
+		parm->db.ipmsgid = msg->id;
+		parm->db.iptrgcls = msg->class;
+	}
+	rc = iucv_call_b2f0(IUCV_REPLY, parm);
+	local_bh_enable();
+	return rc;
+}
+
+/**
+ * iucv_message_send
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST)
+ * @srccls: source class of message
+ * @buffer: address of send buffer or address of struct iucv_array
+ * @size: length of send buffer
+ *
+ * This function transmits data to another application. Data to be
+ * transmitted is in a buffer and this is a one-way message and the
+ * receiver will not reply to the message.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
+		      u8 flags, u32 srccls, void *buffer, size_t size)
+{
+	union iucv_param *parm;
+	int rc;
+
+	local_bh_disable();
+	parm = percpu_ptr(iucv_param, smp_processor_id());
+	memset(parm, 0, sizeof(union iucv_param));
+	if (flags & IUCV_IPRMDATA) {
+		/* Message of 8 bytes can be placed into the parameter list. */
+		parm->dpl.ippathid = path->pathid;
+		parm->dpl.ipflags1 = flags | IUCV_IPNORPY;
+		parm->dpl.iptrgcls = msg->class;
+		parm->dpl.ipsrccls = srccls;
+		parm->dpl.ipmsgtag = msg->tag;
+		memcpy(parm->dpl.iprmmsg, buffer, 8);
+	} else {
+		parm->db.ipbfadr1 = (u32)(addr_t) buffer;
+		parm->db.ipbfln1f = (u32) size;
+		parm->db.ippathid = path->pathid;
+		parm->db.ipflags1 = flags | IUCV_IPNORPY;
+		parm->db.iptrgcls = msg->class;
+		parm->db.ipsrccls = srccls;
+		parm->db.ipmsgtag = msg->tag;
+	}
+	rc = iucv_call_b2f0(IUCV_SEND, parm);
+	if (!rc)
+		msg->id = parm->db.ipmsgid;
+	local_bh_enable();
+	return rc;
+}
+
+/**
+ * iucv_message_send2way
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: how the message is sent and the reply is received
+ *	   (IUCV_IPRMDATA, IUCV_IPBUFLST, IUCV_IPPRTY, IUCV_ANSLST)
+ * @srccls: source class of message
+ * @buffer: address of send buffer or address of struct iucv_array
+ * @size: length of send buffer
+ * @ansbuf: address of answer buffer or address of struct iucv_array
+ * @asize: size of reply buffer
+ *
+ * This function transmits data to another application. Data to be
+ * transmitted is in a buffer. The receiver of the send is expected to
+ * reply to the message and a buffer is provided into which IUCV moves
+ * the reply to this message.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg,
+			  u8 flags, u32 srccls, void *buffer, size_t size,
+			  void *answer, size_t asize, size_t *residual)
+{
+	union iucv_param *parm;
+	int rc;
+
+	local_bh_disable();
+	parm = percpu_ptr(iucv_param, smp_processor_id());
+	memset(parm, 0, sizeof(union iucv_param));
+	if (flags & IUCV_IPRMDATA) {
+		parm->dpl.ippathid = path->pathid;
+		parm->dpl.ipflags1 = path->flags;	/* priority message */
+		parm->dpl.iptrgcls = msg->class;
+		parm->dpl.ipsrccls = srccls;
+		parm->dpl.ipmsgtag = msg->tag;
+		parm->dpl.ipbfadr2 = (u32)(addr_t) answer;
+		parm->dpl.ipbfln2f = (u32) asize;
+		memcpy(parm->dpl.iprmmsg, buffer, 8);
+	} else {
+		parm->db.ippathid = path->pathid;
+		parm->db.ipflags1 = path->flags;	/* priority message */
+		parm->db.iptrgcls = msg->class;
+		parm->db.ipsrccls = srccls;
+		parm->db.ipmsgtag = msg->tag;
+		parm->db.ipbfadr1 = (u32)(addr_t) buffer;
+		parm->db.ipbfln1f = (u32) size;
+		parm->db.ipbfadr2 = (u32)(addr_t) answer;
+		parm->db.ipbfln2f = (u32) asize;
+	}
+	rc = iucv_call_b2f0(IUCV_SEND, parm);
+	if (!rc)
+		msg->id = parm->db.ipmsgid;
+	local_bh_enable();
+	return rc;
+}
+
+/**
+ * iucv_path_pending
+ * @data: Pointer to external interrupt buffer
+ *
+ * Process connection pending work item. Called from tasklet while holding
+ * iucv_table_lock.
+ */
+struct iucv_path_pending {
+	u16 ippathid;
+	u8  ipflags1;
+	u8  iptype;
+	u16 ipmsglim;
+	u16 res1;
+	u8  ipvmid[8];
+	u8  ipuser[16];
+	u32 res3;
+	u8  ippollfg;
+	u8  res4[3];
+} __attribute__ ((packed));
+
+static void iucv_path_pending(struct iucv_irq_data *data)
+{
+	struct iucv_path_pending *ipp = (void *) data;
+	struct iucv_handler *handler;
+	struct iucv_path *path;
+	char *error;
+
+	BUG_ON(iucv_path_table[ipp->ippathid]);
+	/* New pathid, handler found. Create a new path struct. */
+	error = iucv_error_no_memory;
+	path = iucv_path_alloc(ipp->ipmsglim, ipp->ipflags1, GFP_ATOMIC);
+	if (!path)
+		goto out_sever;
+	path->pathid = ipp->ippathid;
+	iucv_path_table[path->pathid] = path;
+	EBCASC(ipp->ipvmid, 8);
+
+	/* Call registered handler until one is found that wants the path. */
+	list_for_each_entry(handler, &iucv_handler_list, list) {
+		if (!handler->path_pending)
+			continue;
+		/*
+		 * Add path to handler to allow a call to iucv_path_sever
+		 * inside the path_pending function. If the handler returns
+		 * an error remove the path from the handler again.
+		 */
+		list_add(&path->list, &handler->paths);
+		path->handler = handler;
+		if (!handler->path_pending(path, ipp->ipvmid, ipp->ipuser))
+			return;
+		list_del(&path->list);
+		path->handler = NULL;
+	}
+	/* No handler wanted the path. */
+	iucv_path_table[path->pathid] = NULL;
+	iucv_path_free(path);
+	error = iucv_error_no_listener;
+out_sever:
+	iucv_sever_pathid(ipp->ippathid, error);
+}
+
+/**
+ * iucv_path_complete
+ * @data: Pointer to external interrupt buffer
+ *
+ * Process connection complete work item. Called from tasklet while holding
+ * iucv_table_lock.
+ */
+struct iucv_path_complete {
+	u16 ippathid;
+	u8  ipflags1;
+	u8  iptype;
+	u16 ipmsglim;
+	u16 res1;
+	u8  res2[8];
+	u8  ipuser[16];
+	u32 res3;
+	u8  ippollfg;
+	u8  res4[3];
+} __attribute__ ((packed));
+
+static void iucv_path_complete(struct iucv_irq_data *data)
+{
+	struct iucv_path_complete *ipc = (void *) data;
+	struct iucv_path *path = iucv_path_table[ipc->ippathid];
+
+	BUG_ON(!path || !path->handler);
+	if (path->handler->path_complete)
+		path->handler->path_complete(path, ipc->ipuser);
+}
+
+/**
+ * iucv_path_severed
+ * @data: Pointer to external interrupt buffer
+ *
+ * Process connection severed work item. Called from tasklet while holding
+ * iucv_table_lock.
+ */
+struct iucv_path_severed {
+	u16 ippathid;
+	u8  res1;
+	u8  iptype;
+	u32 res2;
+	u8  res3[8];
+	u8  ipuser[16];
+	u32 res4;
+	u8  ippollfg;
+	u8  res5[3];
+} __attribute__ ((packed));
+
+static void iucv_path_severed(struct iucv_irq_data *data)
+{
+	struct iucv_path_severed *ips = (void *) data;
+	struct iucv_path *path = iucv_path_table[ips->ippathid];
+
+	BUG_ON(!path || !path->handler);
+	if (path->handler->path_severed)
+		path->handler->path_severed(path, ips->ipuser);
+	else {
+		iucv_sever_pathid(path->pathid, NULL);
+		iucv_path_table[path->pathid] = NULL;
+		list_del_init(&path->list);
+		iucv_cleanup_pathid(path->pathid);
+		iucv_path_free(path);
+	}
+}
+
+/**
+ * iucv_path_quiesced
+ * @data: Pointer to external interrupt buffer
+ *
+ * Process connection quiesced work item. Called from tasklet while holding
+ * iucv_table_lock.
+ */
+struct iucv_path_quiesced {
+	u16 ippathid;
+	u8  res1;
+	u8  iptype;
+	u32 res2;
+	u8  res3[8];
+	u8  ipuser[16];
+	u32 res4;
+	u8  ippollfg;
+	u8  res5[3];
+} __attribute__ ((packed));
+
+static void iucv_path_quiesced(struct iucv_irq_data *data)
+{
+	struct iucv_path_quiesced *ipq = (void *) data;
+	struct iucv_path *path = iucv_path_table[ipq->ippathid];
+
+	BUG_ON(!path || !path->handler);
+	if (path->handler->path_quiesced)
+		path->handler->path_quiesced(path, ipq->ipuser);
+}
+
+/**
+ * iucv_path_resumed
+ * @data: Pointer to external interrupt buffer
+ *
+ * Process connection resumed work item. Called from tasklet while holding
+ * iucv_table_lock.
+ */
+struct iucv_path_resumed {
+	u16 ippathid;
+	u8  res1;
+	u8  iptype;
+	u32 res2;
+	u8  res3[8];
+	u8  ipuser[16];
+	u32 res4;
+	u8  ippollfg;
+	u8  res5[3];
+} __attribute__ ((packed));
+
+static void iucv_path_resumed(struct iucv_irq_data *data)
+{
+	struct iucv_path_resumed *ipr = (void *) data;
+	struct iucv_path *path = iucv_path_table[ipr->ippathid];
+
+	BUG_ON(!path || !path->handler);
+	if (path->handler->path_resumed)
+		path->handler->path_resumed(path, ipr->ipuser);
+}
+
+/**
+ * iucv_message_complete
+ * @data: Pointer to external interrupt buffer
+ *
+ * Process message complete work item. Called from tasklet while holding
+ * iucv_table_lock.
+ */
+struct iucv_message_complete {
+	u16 ippathid;
+	u8  ipflags1;
+	u8  iptype;
+	u32 ipmsgid;
+	u32 ipaudit;
+	u8  iprmmsg[8];
+	u32 ipsrccls;
+	u32 ipmsgtag;
+	u32 res;
+	u32 ipbfln2f;
+	u8  ippollfg;
+	u8  res2[3];
+} __attribute__ ((packed));
+
+static void iucv_message_complete(struct iucv_irq_data *data)
+{
+	struct iucv_message_complete *imc = (void *) data;
+	struct iucv_path *path = iucv_path_table[imc->ippathid];
+	struct iucv_message msg;
+
+	BUG_ON(!path || !path->handler);
+	if (path->handler->message_complete) {
+		msg.flags = imc->ipflags1;
+		msg.id = imc->ipmsgid;
+		msg.audit = imc->ipaudit;
+		memcpy(msg.rmmsg, imc->iprmmsg, 8);
+		msg.class = imc->ipsrccls;
+		msg.tag = imc->ipmsgtag;
+		msg.length = imc->ipbfln2f;
+		path->handler->message_complete(path, &msg);
+	}
+}
+
+/**
+ * iucv_message_pending
+ * @data: Pointer to external interrupt buffer
+ *
+ * Process message pending work item. Called from tasklet while holding
+ * iucv_table_lock.
+ */
+struct iucv_message_pending {
+	u16 ippathid;
+	u8  ipflags1;
+	u8  iptype;
+	u32 ipmsgid;
+	u32 iptrgcls;
+	union {
+		u32 iprmmsg1_u32;
+		u8  iprmmsg1[4];
+	} ln1msg1;
+	union {
+		u32 ipbfln1f;
+		u8  iprmmsg2[4];
+	} ln1msg2;
+	u32 res1[3];
+	u32 ipbfln2f;
+	u8  ippollfg;
+	u8  res2[3];
+} __attribute__ ((packed));
+
+static void iucv_message_pending(struct iucv_irq_data *data)
+{
+	struct iucv_message_pending *imp = (void *) data;
+	struct iucv_path *path = iucv_path_table[imp->ippathid];
+	struct iucv_message msg;
+
+	BUG_ON(!path || !path->handler);
+	if (path->handler->message_pending) {
+		msg.flags = imp->ipflags1;
+		msg.id = imp->ipmsgid;
+		msg.class = imp->iptrgcls;
+		if (imp->ipflags1 & IUCV_IPRMDATA) {
+			memcpy(msg.rmmsg, imp->ln1msg1.iprmmsg1, 8);
+			msg.length = 8;
+		} else
+			msg.length = imp->ln1msg2.ipbfln1f;
+		msg.reply_size = imp->ipbfln2f;
+		path->handler->message_pending(path, &msg);
+	}
+}
+
+/**
+ * iucv_tasklet_handler:
+ *
+ * This tasklet loops over the queue of irq buffers created by
+ * iucv_external_interrupt, calls the appropriate action handler
+ * and then frees the buffer.
+ */
+static void iucv_tasklet_handler(unsigned long ignored)
+{
+	typedef void iucv_irq_fn(struct iucv_irq_data *);
+	static iucv_irq_fn *irq_fn[] = {
+		[0x01] = iucv_path_pending,
+		[0x02] = iucv_path_complete,
+		[0x03] = iucv_path_severed,
+		[0x04] = iucv_path_quiesced,
+		[0x05] = iucv_path_resumed,
+		[0x06] = iucv_message_complete,
+		[0x07] = iucv_message_complete,
+		[0x08] = iucv_message_pending,
+		[0x09] = iucv_message_pending,
+	};
+	struct iucv_work *p;
+
+	/* Serialize tasklet, iucv_path_sever and iucv_path_connect. */
+	spin_lock(&iucv_table_lock);
+	iucv_tasklet_cpu = smp_processor_id();
+
+	spin_lock_irq(&iucv_work_lock);
+	while (!list_empty(&iucv_work_queue)) {
+		p = list_entry(iucv_work_queue.next, struct iucv_work, list);
+		list_del_init(&p->list);
+		spin_unlock_irq(&iucv_work_lock);
+		irq_fn[p->data.iptype](&p->data);
+		kfree(p);
+		spin_lock_irq(&iucv_work_lock);
+	}
+	spin_unlock_irq(&iucv_work_lock);
+
+	iucv_tasklet_cpu = -1;
+	spin_unlock(&iucv_table_lock);
+}
+
+/**
+ * iucv_external_interrupt
+ * @code: irq code
+ *
+ * Handles external interrupts coming in from CP.
+ * Places the interrupt buffer on a queue and schedules iucv_tasklet_handler().
+ */
+static void iucv_external_interrupt(u16 code)
+{
+	struct iucv_irq_data *p;
+	struct iucv_work *work;
+
+	p = percpu_ptr(iucv_irq_data, smp_processor_id());
+	if (p->ippathid >= iucv_max_pathid) {
+		printk(KERN_WARNING "iucv_do_int: Got interrupt with "
+		       "pathid %d > max_connections (%ld)\n",
+		       p->ippathid, iucv_max_pathid - 1);
+		iucv_sever_pathid(p->ippathid, iucv_error_no_listener);
+		return;
+	}
+	if (p->iptype  < 0x01 || p->iptype > 0x09) {
+		printk(KERN_ERR "iucv_do_int: unknown iucv interrupt\n");
+		return;
+	}
+	work = kmalloc(sizeof(struct iucv_work), GFP_ATOMIC);
+	if (!work) {
+		printk(KERN_WARNING "iucv_external_interrupt: out of memory\n");
+		return;
+	}
+	memcpy(&work->data, p, sizeof(work->data));
+	spin_lock(&iucv_work_lock);
+	list_add_tail(&work->list, &iucv_work_queue);
+	spin_unlock(&iucv_work_lock);
+	tasklet_schedule(&iucv_tasklet);
+}
+
+/**
+ * iucv_init
+ *
+ * Allocates and initializes various data structures.
+ */
+static int iucv_init(void)
+{
+	int rc;
+
+	if (!MACHINE_IS_VM) {
+		rc = -EPROTONOSUPPORT;
+		goto out;
+	}
+	rc = iucv_query_maxconn();
+	if (rc)
+		goto out;
+	rc = register_external_interrupt (0x4000, iucv_external_interrupt);
+	if (rc)
+		goto out;
+	rc = bus_register(&iucv_bus);
+	if (rc)
+		goto out_int;
+	iucv_root = s390_root_dev_register("iucv");
+	if (IS_ERR(iucv_root)) {
+		rc = PTR_ERR(iucv_root);
+		goto out_bus;
+	}
+	/* Note: GFP_DMA used used to get memory below 2G */
+	iucv_irq_data = percpu_alloc(sizeof(struct iucv_irq_data),
+				     GFP_KERNEL|GFP_DMA);
+	if (!iucv_irq_data) {
+		rc = -ENOMEM;
+		goto out_root;
+	}
+	/* Allocate parameter blocks. */
+	iucv_param = percpu_alloc(sizeof(union iucv_param),
+				  GFP_KERNEL|GFP_DMA);
+	if (!iucv_param) {
+		rc = -ENOMEM;
+		goto out_extint;
+	}
+	register_hotcpu_notifier(&iucv_cpu_notifier);
+	ASCEBC(iucv_error_no_listener, 16);
+	ASCEBC(iucv_error_no_memory, 16);
+	ASCEBC(iucv_error_pathid, 16);
+	iucv_available = 1;
+	return 0;
+
+out_extint:
+	percpu_free(iucv_irq_data);
+out_root:
+	s390_root_dev_unregister(iucv_root);
+out_bus:
+	bus_unregister(&iucv_bus);
+out_int:
+	unregister_external_interrupt(0x4000, iucv_external_interrupt);
+out:
+	return rc;
+}
+
+/**
+ * iucv_exit
+ *
+ * Frees everything allocated from iucv_init.
+ */
+static void iucv_exit(void)
+{
+	struct iucv_work *p, *n;
+
+	spin_lock_irq(&iucv_work_lock);
+	list_for_each_entry_safe(p, n, &iucv_work_queue, list)
+		kfree(p);
+	spin_unlock_irq(&iucv_work_lock);
+	unregister_hotcpu_notifier(&iucv_cpu_notifier);
+	percpu_free(iucv_param);
+	percpu_free(iucv_irq_data);
+	s390_root_dev_unregister(iucv_root);
+	bus_unregister(&iucv_bus);
+	unregister_external_interrupt(0x4000, iucv_external_interrupt);
+}
+
+subsys_initcall(iucv_init);
+module_exit(iucv_exit);
+
+/**
+ * Export all public stuff
+ */
+EXPORT_SYMBOL (iucv_bus);
+EXPORT_SYMBOL (iucv_root);
+EXPORT_SYMBOL (iucv_register);
+EXPORT_SYMBOL (iucv_unregister);
+EXPORT_SYMBOL (iucv_path_accept);
+EXPORT_SYMBOL (iucv_path_connect);
+EXPORT_SYMBOL (iucv_path_quiesce);
+EXPORT_SYMBOL (iucv_path_sever);
+EXPORT_SYMBOL (iucv_message_purge);
+EXPORT_SYMBOL (iucv_message_receive);
+EXPORT_SYMBOL (iucv_message_reject);
+EXPORT_SYMBOL (iucv_message_reply);
+EXPORT_SYMBOL (iucv_message_send);
+EXPORT_SYMBOL (iucv_message_send2way);
+
+MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
+MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver");
+MODULE_LICENSE("GPL");
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 5dd5094..b4e4440 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -2345,6 +2345,196 @@
 	return err;
 }
 
+#ifdef CONFIG_NET_KEY_MIGRATE
+static int pfkey_sockaddr_pair_size(sa_family_t family)
+{
+	switch (family) {
+	case AF_INET:
+		return PFKEY_ALIGN8(sizeof(struct sockaddr_in) * 2);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	case AF_INET6:
+		return PFKEY_ALIGN8(sizeof(struct sockaddr_in6) * 2);
+#endif
+	default:
+		return 0;
+	}
+	/* NOTREACHED */
+}
+
+static int parse_sockaddr_pair(struct sadb_x_ipsecrequest *rq,
+			       xfrm_address_t *saddr, xfrm_address_t *daddr,
+			       u16 *family)
+{
+	struct sockaddr *sa = (struct sockaddr *)(rq + 1);
+	if (rq->sadb_x_ipsecrequest_len <
+	    pfkey_sockaddr_pair_size(sa->sa_family))
+		return -EINVAL;
+
+	switch (sa->sa_family) {
+	case AF_INET:
+		{
+			struct sockaddr_in *sin;
+			sin = (struct sockaddr_in *)sa;
+			if ((sin+1)->sin_family != AF_INET)
+				return -EINVAL;
+			memcpy(&saddr->a4, &sin->sin_addr, sizeof(saddr->a4));
+			sin++;
+			memcpy(&daddr->a4, &sin->sin_addr, sizeof(daddr->a4));
+			*family = AF_INET;
+			break;
+		}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	case AF_INET6:
+		{
+			struct sockaddr_in6 *sin6;
+			sin6 = (struct sockaddr_in6 *)sa;
+			if ((sin6+1)->sin6_family != AF_INET6)
+				return -EINVAL;
+			memcpy(&saddr->a6, &sin6->sin6_addr,
+			       sizeof(saddr->a6));
+			sin6++;
+			memcpy(&daddr->a6, &sin6->sin6_addr,
+			       sizeof(daddr->a6));
+			*family = AF_INET6;
+			break;
+		}
+#endif
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len,
+				    struct xfrm_migrate *m)
+{
+	int err;
+	struct sadb_x_ipsecrequest *rq2;
+
+	if (len <= sizeof(struct sadb_x_ipsecrequest) ||
+	    len < rq1->sadb_x_ipsecrequest_len)
+		return -EINVAL;
+
+	/* old endoints */
+	err = parse_sockaddr_pair(rq1, &m->old_saddr, &m->old_daddr,
+				  &m->old_family);
+	if (err)
+		return err;
+
+	rq2 = (struct sadb_x_ipsecrequest *)((u8 *)rq1 + rq1->sadb_x_ipsecrequest_len);
+	len -= rq1->sadb_x_ipsecrequest_len;
+
+	if (len <= sizeof(struct sadb_x_ipsecrequest) ||
+	    len < rq2->sadb_x_ipsecrequest_len)
+		return -EINVAL;
+
+	/* new endpoints */
+	err = parse_sockaddr_pair(rq2, &m->new_saddr, &m->new_daddr,
+				  &m->new_family);
+	if (err)
+		return err;
+
+	if (rq1->sadb_x_ipsecrequest_proto != rq2->sadb_x_ipsecrequest_proto ||
+	    rq1->sadb_x_ipsecrequest_mode != rq2->sadb_x_ipsecrequest_mode ||
+	    rq1->sadb_x_ipsecrequest_reqid != rq2->sadb_x_ipsecrequest_reqid)
+		return -EINVAL;
+
+	m->proto = rq1->sadb_x_ipsecrequest_proto;
+	m->mode = rq1->sadb_x_ipsecrequest_mode - 1;
+	m->reqid = rq1->sadb_x_ipsecrequest_reqid;
+
+	return ((int)(rq1->sadb_x_ipsecrequest_len +
+		      rq2->sadb_x_ipsecrequest_len));
+}
+
+static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
+			 struct sadb_msg *hdr, void **ext_hdrs)
+{
+	int i, len, ret, err = -EINVAL;
+	u8 dir;
+	struct sadb_address *sa;
+	struct sadb_x_policy *pol;
+	struct sadb_x_ipsecrequest *rq;
+	struct xfrm_selector sel;
+	struct xfrm_migrate m[XFRM_MAX_DEPTH];
+
+	if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1],
+	    ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) ||
+	    !ext_hdrs[SADB_X_EXT_POLICY - 1]) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	pol = ext_hdrs[SADB_X_EXT_POLICY - 1];
+	if (!pol) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	if (pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	dir = pol->sadb_x_policy_dir - 1;
+	memset(&sel, 0, sizeof(sel));
+
+	/* set source address info of selector */
+	sa = ext_hdrs[SADB_EXT_ADDRESS_SRC - 1];
+	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;
+	if (sel.sport)
+		sel.sport_mask = ~0;
+
+	/* set destination address info of selector */
+	sa = ext_hdrs[SADB_EXT_ADDRESS_DST - 1],
+	pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr);
+	sel.prefixlen_d = sa->sadb_address_prefixlen;
+	sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
+	sel.dport = ((struct sockaddr_in *)(sa + 1))->sin_port;
+	if (sel.dport)
+		sel.dport_mask = ~0;
+
+	rq = (struct sadb_x_ipsecrequest *)(pol + 1);
+
+	/* extract ipsecrequests */
+	i = 0;
+	len = pol->sadb_x_policy_len * 8 - sizeof(struct sadb_x_policy);
+
+	while (len > 0 && i < XFRM_MAX_DEPTH) {
+		ret = ipsecrequests_to_migrate(rq, len, &m[i]);
+		if (ret < 0) {
+			err = ret;
+			goto out;
+		} else {
+			rq = (struct sadb_x_ipsecrequest *)((u8 *)rq + ret);
+			len -= ret;
+			i++;
+		}
+	}
+
+	if (!i || len > 0) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i);
+
+ out:
+	return err;
+}
+#else
+static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
+			 struct sadb_msg *hdr, void **ext_hdrs)
+{
+	return -ENOPROTOOPT;
+}
+#endif
+
+
 static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
 {
 	unsigned int dir;
@@ -2473,6 +2663,7 @@
 	[SADB_X_SPDFLUSH]	= pfkey_spdflush,
 	[SADB_X_SPDSETIDX]	= pfkey_spdadd,
 	[SADB_X_SPDDELETE2]	= pfkey_spdget,
+	[SADB_X_MIGRATE]	= pfkey_migrate,
 };
 
 static int pfkey_process(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr)
@@ -3118,6 +3309,236 @@
 	return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL);
 }
 
+#ifdef CONFIG_NET_KEY_MIGRATE
+static int set_sadb_address(struct sk_buff *skb, int sasize, int type,
+			    struct xfrm_selector *sel)
+{
+	struct sadb_address *addr;
+	struct sockaddr_in *sin;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	struct sockaddr_in6 *sin6;
+#endif
+	addr = (struct sadb_address *)skb_put(skb, sizeof(struct sadb_address) + sasize);
+	addr->sadb_address_len = (sizeof(struct sadb_address) + sasize)/8;
+	addr->sadb_address_exttype = type;
+	addr->sadb_address_proto = sel->proto;
+	addr->sadb_address_reserved = 0;
+
+	switch (type) {
+	case SADB_EXT_ADDRESS_SRC:
+		if (sel->family == AF_INET) {
+			addr->sadb_address_prefixlen = sel->prefixlen_s;
+			sin = (struct sockaddr_in *)(addr + 1);
+			sin->sin_family = AF_INET;
+			memcpy(&sin->sin_addr.s_addr, &sel->saddr,
+			       sizeof(sin->sin_addr.s_addr));
+			sin->sin_port = 0;
+			memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+		}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		else if (sel->family == AF_INET6) {
+			addr->sadb_address_prefixlen = sel->prefixlen_s;
+			sin6 = (struct sockaddr_in6 *)(addr + 1);
+			sin6->sin6_family = AF_INET6;
+			sin6->sin6_port = 0;
+			sin6->sin6_flowinfo = 0;
+			sin6->sin6_scope_id = 0;
+			memcpy(&sin6->sin6_addr.s6_addr, &sel->saddr,
+			       sizeof(sin6->sin6_addr.s6_addr));
+		}
+#endif
+		break;
+	case SADB_EXT_ADDRESS_DST:
+		if (sel->family == AF_INET) {
+			addr->sadb_address_prefixlen = sel->prefixlen_d;
+			sin = (struct sockaddr_in *)(addr + 1);
+			sin->sin_family = AF_INET;
+			memcpy(&sin->sin_addr.s_addr, &sel->daddr,
+			       sizeof(sin->sin_addr.s_addr));
+			sin->sin_port = 0;
+			memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+		}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		else if (sel->family == AF_INET6) {
+			addr->sadb_address_prefixlen = sel->prefixlen_d;
+			sin6 = (struct sockaddr_in6 *)(addr + 1);
+			sin6->sin6_family = AF_INET6;
+			sin6->sin6_port = 0;
+			sin6->sin6_flowinfo = 0;
+			sin6->sin6_scope_id = 0;
+			memcpy(&sin6->sin6_addr.s6_addr, &sel->daddr,
+			       sizeof(sin6->sin6_addr.s6_addr));
+		}
+#endif
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int set_ipsecrequest(struct sk_buff *skb,
+			    uint8_t proto, uint8_t mode, int level,
+			    uint32_t reqid, uint8_t family,
+			    xfrm_address_t *src, xfrm_address_t *dst)
+{
+	struct sadb_x_ipsecrequest *rq;
+	struct sockaddr_in *sin;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	struct sockaddr_in6 *sin6;
+#endif
+	int size_req;
+
+	size_req = sizeof(struct sadb_x_ipsecrequest) +
+		   pfkey_sockaddr_pair_size(family);
+
+	rq = (struct sadb_x_ipsecrequest *)skb_put(skb, size_req);
+	memset(rq, 0, size_req);
+	rq->sadb_x_ipsecrequest_len = size_req;
+	rq->sadb_x_ipsecrequest_proto = proto;
+	rq->sadb_x_ipsecrequest_mode = mode;
+	rq->sadb_x_ipsecrequest_level = level;
+	rq->sadb_x_ipsecrequest_reqid = reqid;
+
+	switch (family) {
+	case AF_INET:
+		sin = (struct sockaddr_in *)(rq + 1);
+		sin->sin_family = AF_INET;
+		memcpy(&sin->sin_addr.s_addr, src,
+		       sizeof(sin->sin_addr.s_addr));
+		sin++;
+		sin->sin_family = AF_INET;
+		memcpy(&sin->sin_addr.s_addr, dst,
+		       sizeof(sin->sin_addr.s_addr));
+		break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	case AF_INET6:
+		sin6 = (struct sockaddr_in6 *)(rq + 1);
+		sin6->sin6_family = AF_INET6;
+		sin6->sin6_port = 0;
+		sin6->sin6_flowinfo = 0;
+		sin6->sin6_scope_id = 0;
+		memcpy(&sin6->sin6_addr.s6_addr, src,
+		       sizeof(sin6->sin6_addr.s6_addr));
+		sin6++;
+		sin6->sin6_family = AF_INET6;
+		sin6->sin6_port = 0;
+		sin6->sin6_flowinfo = 0;
+		sin6->sin6_scope_id = 0;
+		memcpy(&sin6->sin6_addr.s6_addr, dst,
+		       sizeof(sin6->sin6_addr.s6_addr));
+		break;
+#endif
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_NET_KEY_MIGRATE
+static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
+			      struct xfrm_migrate *m, int num_bundles)
+{
+	int i;
+	int sasize_sel;
+	int size = 0;
+	int size_pol = 0;
+	struct sk_buff *skb;
+	struct sadb_msg *hdr;
+	struct sadb_x_policy *pol;
+	struct xfrm_migrate *mp;
+
+	if (type != XFRM_POLICY_TYPE_MAIN)
+		return 0;
+
+	if (num_bundles <= 0 || num_bundles > XFRM_MAX_DEPTH)
+		return -EINVAL;
+
+	/* selector */
+	sasize_sel = pfkey_sockaddr_size(sel->family);
+	if (!sasize_sel)
+		return -EINVAL;
+	size += (sizeof(struct sadb_address) + sasize_sel) * 2;
+
+	/* policy info */
+	size_pol += sizeof(struct sadb_x_policy);
+
+	/* ipsecrequests */
+	for (i = 0, mp = m; i < num_bundles; i++, mp++) {
+		/* old locator pair */
+		size_pol += sizeof(struct sadb_x_ipsecrequest) +
+			    pfkey_sockaddr_pair_size(mp->old_family);
+		/* new locator pair */
+		size_pol += sizeof(struct sadb_x_ipsecrequest) +
+			    pfkey_sockaddr_pair_size(mp->new_family);
+	}
+
+	size += sizeof(struct sadb_msg) + size_pol;
+
+	/* alloc buffer */
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (skb == NULL)
+		return -ENOMEM;
+
+	hdr = (struct sadb_msg *)skb_put(skb, sizeof(struct sadb_msg));
+	hdr->sadb_msg_version = PF_KEY_V2;
+	hdr->sadb_msg_type = SADB_X_MIGRATE;
+	hdr->sadb_msg_satype = pfkey_proto2satype(m->proto);
+	hdr->sadb_msg_len = size / 8;
+	hdr->sadb_msg_errno = 0;
+	hdr->sadb_msg_reserved = 0;
+	hdr->sadb_msg_seq = 0;
+	hdr->sadb_msg_pid = 0;
+
+	/* selector src */
+	set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_SRC, sel);
+
+	/* selector dst */
+	set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_DST, sel);
+
+	/* policy information */
+	pol = (struct sadb_x_policy *)skb_put(skb, sizeof(struct sadb_x_policy));
+	pol->sadb_x_policy_len = size_pol / 8;
+	pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+	pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
+	pol->sadb_x_policy_dir = dir + 1;
+	pol->sadb_x_policy_id = 0;
+	pol->sadb_x_policy_priority = 0;
+
+	for (i = 0, mp = m; i < num_bundles; i++, mp++) {
+		/* old ipsecrequest */
+		if (set_ipsecrequest(skb, mp->proto, mp->mode + 1,
+				     (mp->reqid ?  IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE),
+				     mp->reqid, mp->old_family,
+				     &mp->old_saddr, &mp->old_daddr) < 0) {
+			return -EINVAL;
+		}
+
+		/* new ipsecrequest */
+		if (set_ipsecrequest(skb, mp->proto, mp->mode + 1,
+				     (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE),
+				     mp->reqid, mp->new_family,
+				     &mp->new_saddr, &mp->new_daddr) < 0) {
+			return -EINVAL;
+		}
+	}
+
+	/* broadcast migrate message to sockets */
+	pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+
+	return 0;
+}
+#else
+static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
+			      struct xfrm_migrate *m, int num_bundles)
+{
+	return -ENOPROTOOPT;
+}
+#endif
+
 static int pfkey_sendmsg(struct kiocb *kiocb,
 			 struct socket *sock, struct msghdr *msg, size_t len)
 {
@@ -3287,6 +3708,7 @@
 	.compile_policy	= pfkey_compile_policy,
 	.new_mapping	= pfkey_send_new_mapping,
 	.notify_policy	= pfkey_send_policy_notify,
+	.migrate	= pfkey_send_migrate,
 };
 
 static void __exit ipsec_pfkey_exit(void)
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 80107d4..748f7f0 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -235,6 +235,19 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config NF_CONNTRACK_SANE
+	tristate "SANE protocol support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && NF_CONNTRACK
+	help
+	  SANE is a protocol for remote access to scanners as implemented
+	  by the 'saned' daemon. Like FTP, it uses separate control and
+	  data connections.
+
+	  With this module you can support SANE on a connection tracking
+	  firewall.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config NF_CONNTRACK_SIP
 	tristate "SIP protocol support (EXPERIMENTAL)"
 	depends on EXPERIMENTAL && NF_CONNTRACK
@@ -382,6 +395,32 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config NETFILTER_XT_TARGET_TCPMSS
+	tristate '"TCPMSS" target support'
+	depends on NETFILTER_XTABLES && (IPV6 || IPV6=n)
+	---help---
+	  This option adds a `TCPMSS' target, which allows you to alter the
+	  MSS value of TCP SYN packets, to control the maximum size for that
+	  connection (usually limiting it to your outgoing interface's MTU
+	  minus 40).
+
+	  This is used to overcome criminally braindead ISPs or servers which
+	  block ICMP Fragmentation Needed packets.  The symptoms of this
+	  problem are that everything works fine from your Linux
+	  firewall/router, but machines behind it can never exchange large
+	  packets:
+	        1) Web browsers connect, then hang with no data received.
+	        2) Small mail works fine, but large emails hang.
+	        3) ssh works fine, but scp hangs after initial handshaking.
+
+	  Workaround: activate this option and add a rule to your firewall
+	  configuration like:
+
+	  iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
+	                 -j TCPMSS --clamp-mss-to-pmtu
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_MATCH_COMMENT
 	tristate  '"comment" match support'
 	depends on NETFILTER_XTABLES
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 5dc5574..b2b5c75 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -29,6 +29,7 @@
 obj-$(CONFIG_NF_CONNTRACK_IRC) += nf_conntrack_irc.o
 obj-$(CONFIG_NF_CONNTRACK_NETBIOS_NS) += nf_conntrack_netbios_ns.o
 obj-$(CONFIG_NF_CONNTRACK_PPTP) += nf_conntrack_pptp.o
+obj-$(CONFIG_NF_CONNTRACK_SANE) += nf_conntrack_sane.o
 obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o
 obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o
 
@@ -44,6 +45,7 @@
 obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
 
 # matches
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 626b001..6fccdcf 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -60,12 +60,9 @@
     If it's non-zero, we mark only out of window RST segments as INVALID. */
 int nf_ct_tcp_be_liberal __read_mostly = 0;
 
-/* When connection is picked up from the middle, how many packets are required
-   to pass in each direction when we assume we are in sync - if any side uses
-   window scaling, we lost the game. 
-   If it is set to zero, we disable picking up already established 
+/* If it is set to zero, we disable picking up already established
    connections. */
-int nf_ct_tcp_loose __read_mostly = 3;
+int nf_ct_tcp_loose __read_mostly = 1;
 
 /* Max number of the retransmitted packets without receiving an (acceptable) 
    ACK from the destination. If this number is reached, a shorter timer 
@@ -650,11 +647,10 @@
 	    	before(sack, receiver->td_end + 1),
 	    	after(ack, receiver->td_end - MAXACKWINDOW(sender)));
 
-	if (sender->loose || receiver->loose ||
-	    (before(seq, sender->td_maxend + 1) &&
-	     after(end, sender->td_end - receiver->td_maxwin - 1) &&
-	     before(sack, receiver->td_end + 1) &&
-	     after(ack, receiver->td_end - MAXACKWINDOW(sender)))) {
+	if (before(seq, sender->td_maxend + 1) &&
+	    after(end, sender->td_end - receiver->td_maxwin - 1) &&
+	    before(sack, receiver->td_end + 1) &&
+	    after(ack, receiver->td_end - MAXACKWINDOW(sender))) {
 	    	/*
 		 * Take into account window scaling (RFC 1323).
 		 */
@@ -699,15 +695,13 @@
 				state->retrans = 0;
 			}
 		}
-		/*
-		 * Close the window of disabled window tracking :-)
-		 */
-		if (sender->loose)
-			sender->loose--;
-
 		res = 1;
 	} else {
-		if (LOG_INVALID(IPPROTO_TCP))
+		res = 0;
+		if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL ||
+		    nf_ct_tcp_be_liberal)
+			res = 1;
+		if (!res && LOG_INVALID(IPPROTO_TCP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 			"nf_ct_tcp: %s ",
 			before(seq, sender->td_maxend + 1) ?
@@ -718,8 +712,6 @@
 			: "ACK is over the upper bound (ACKed data not seen yet)"
 			: "SEQ is under the lower bound (already ACKed data retransmitted)"
 			: "SEQ is over the upper bound (over the window of the receiver)");
-
-		res = nf_ct_tcp_be_liberal;
   	}
   
 	DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u "
@@ -1063,8 +1055,6 @@
 
 		tcp_options(skb, dataoff, th, &conntrack->proto.tcp.seen[0]);
 		conntrack->proto.tcp.seen[1].flags = 0;
-		conntrack->proto.tcp.seen[0].loose = 
-		conntrack->proto.tcp.seen[1].loose = 0;
 	} else if (nf_ct_tcp_loose == 0) {
 		/* Don't try to pick up connections. */
 		return 0;
@@ -1085,11 +1075,11 @@
 			conntrack->proto.tcp.seen[0].td_maxwin;
 		conntrack->proto.tcp.seen[0].td_scale = 0;
 
-		/* We assume SACK. Should we assume window scaling too? */
+		/* We assume SACK and liberal window checking to handle
+		 * window scaling */
 		conntrack->proto.tcp.seen[0].flags =
-		conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM;
-		conntrack->proto.tcp.seen[0].loose = 
-		conntrack->proto.tcp.seen[1].loose = nf_ct_tcp_loose;
+		conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM |
+						     IP_CT_TCP_FLAG_BE_LIBERAL;
 	}
     
 	conntrack->proto.tcp.seen[1].td_end = 0;
diff --git a/net/netfilter/nf_conntrack_sane.c b/net/netfilter/nf_conntrack_sane.c
new file mode 100644
index 0000000..eb2d1dc
--- /dev/null
+++ b/net/netfilter/nf_conntrack_sane.c
@@ -0,0 +1,242 @@
+/* SANE connection tracking helper
+ * (SANE = Scanner Access Now Easy)
+ * For documentation about the SANE network protocol see
+ * http://www.sane-project.org/html/doc015.html
+ */
+
+/* Copyright (C) 2007 Red Hat, Inc.
+ * Author: Michal Schmidt <mschmidt@redhat.com>
+ * Based on the FTP conntrack helper (net/netfilter/nf_conntrack_ftp.c):
+ *  (C) 1999-2001 Paul `Rusty' Russell
+ *  (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ *  (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
+ *  (C) 2003 Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netfilter.h>
+#include <linux/in.h>
+#include <linux/tcp.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_helper.h>
+#include <net/netfilter/nf_conntrack_expect.h>
+#include <linux/netfilter/nf_conntrack_sane.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michal Schmidt <mschmidt@redhat.com>");
+MODULE_DESCRIPTION("SANE connection tracking helper");
+
+static char *sane_buffer;
+
+static DEFINE_SPINLOCK(nf_sane_lock);
+
+#define MAX_PORTS 8
+static u_int16_t ports[MAX_PORTS];
+static unsigned int ports_c;
+module_param_array(ports, ushort, &ports_c, 0400);
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+struct sane_request {
+	__be32 RPC_code;
+#define SANE_NET_START      7   /* RPC code */
+
+	__be32 handle;
+};
+
+struct sane_reply_net_start {
+	__be32 status;
+#define SANE_STATUS_SUCCESS 0
+
+	__be16 zero;
+	__be16 port;
+	/* other fields aren't interesting for conntrack */
+};
+
+static int help(struct sk_buff **pskb,
+		unsigned int protoff,
+		struct nf_conn *ct,
+		enum ip_conntrack_info ctinfo)
+{
+	unsigned int dataoff, datalen;
+	struct tcphdr _tcph, *th;
+	char *sb_ptr;
+	int ret = NF_ACCEPT;
+	int dir = CTINFO2DIR(ctinfo);
+	struct nf_ct_sane_master *ct_sane_info;
+	struct nf_conntrack_expect *exp;
+	struct nf_conntrack_tuple *tuple;
+	struct sane_request *req;
+	struct sane_reply_net_start *reply;
+	int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
+
+	ct_sane_info = &nfct_help(ct)->help.ct_sane_info;
+	/* Until there's been traffic both ways, don't look in packets. */
+	if (ctinfo != IP_CT_ESTABLISHED &&
+	    ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY)
+		return NF_ACCEPT;
+
+	/* Not a full tcp header? */
+	th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph);
+	if (th == NULL)
+		return NF_ACCEPT;
+
+	/* No data? */
+	dataoff = protoff + th->doff * 4;
+	if (dataoff >= (*pskb)->len)
+		return NF_ACCEPT;
+
+	datalen = (*pskb)->len - dataoff;
+
+	spin_lock_bh(&nf_sane_lock);
+	sb_ptr = skb_header_pointer(*pskb, dataoff, datalen, sane_buffer);
+	BUG_ON(sb_ptr == NULL);
+
+	if (dir == IP_CT_DIR_ORIGINAL) {
+		if (datalen != sizeof(struct sane_request))
+			goto out;
+
+		req = (struct sane_request *)sb_ptr;
+		if (req->RPC_code != htonl(SANE_NET_START)) {
+			/* Not an interesting command */
+			ct_sane_info->state = SANE_STATE_NORMAL;
+			goto out;
+		}
+
+		/* We're interested in the next reply */
+		ct_sane_info->state = SANE_STATE_START_REQUESTED;
+		goto out;
+	}
+
+	/* Is it a reply to an uninteresting command? */
+	if (ct_sane_info->state != SANE_STATE_START_REQUESTED)
+		goto out;
+
+	/* It's a reply to SANE_NET_START. */
+	ct_sane_info->state = SANE_STATE_NORMAL;
+
+	if (datalen < sizeof(struct sane_reply_net_start)) {
+		DEBUGP("nf_ct_sane: NET_START reply too short\n");
+		goto out;
+	}
+
+	reply = (struct sane_reply_net_start *)sb_ptr;
+	if (reply->status != htonl(SANE_STATUS_SUCCESS)) {
+		/* saned refused the command */
+		DEBUGP("nf_ct_sane: unsuccessful SANE_STATUS = %u\n",
+			ntohl(reply->status));
+		goto out;
+	}
+
+	/* Invalid saned reply? Ignore it. */
+	if (reply->zero != 0)
+		goto out;
+
+	exp = nf_conntrack_expect_alloc(ct);
+	if (exp == NULL) {
+		ret = NF_DROP;
+		goto out;
+	}
+
+	tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+	nf_conntrack_expect_init(exp, family,
+				 &tuple->src.u3, &tuple->dst.u3,
+				 IPPROTO_TCP,
+				 NULL, &reply->port);
+
+	DEBUGP("nf_ct_sane: expect: ");
+	NF_CT_DUMP_TUPLE(&exp->tuple);
+	NF_CT_DUMP_TUPLE(&exp->mask);
+
+	/* Can't expect this?  Best to drop packet now. */
+	if (nf_conntrack_expect_related(exp) != 0)
+		ret = NF_DROP;
+
+	nf_conntrack_expect_put(exp);
+
+out:
+	spin_unlock_bh(&nf_sane_lock);
+	return ret;
+}
+
+static struct nf_conntrack_helper sane[MAX_PORTS][2];
+static char sane_names[MAX_PORTS][2][sizeof("sane-65535")];
+
+/* don't make this __exit, since it's called from __init ! */
+static void nf_conntrack_sane_fini(void)
+{
+	int i, j;
+
+	for (i = 0; i < ports_c; i++) {
+		for (j = 0; j < 2; j++) {
+			DEBUGP("nf_ct_sane: unregistering helper for pf: %d "
+			       "port: %d\n",
+				sane[i][j].tuple.src.l3num, ports[i]);
+			nf_conntrack_helper_unregister(&sane[i][j]);
+		}
+	}
+
+	kfree(sane_buffer);
+}
+
+static int __init nf_conntrack_sane_init(void)
+{
+	int i, j = -1, ret = 0;
+	char *tmpname;
+
+	sane_buffer = kmalloc(65536, GFP_KERNEL);
+	if (!sane_buffer)
+		return -ENOMEM;
+
+	if (ports_c == 0)
+		ports[ports_c++] = SANE_PORT;
+
+	/* FIXME should be configurable whether IPv4 and IPv6 connections
+		 are tracked or not - YK */
+	for (i = 0; i < ports_c; i++) {
+		sane[i][0].tuple.src.l3num = PF_INET;
+		sane[i][1].tuple.src.l3num = PF_INET6;
+		for (j = 0; j < 2; j++) {
+			sane[i][j].tuple.src.u.tcp.port = htons(ports[i]);
+			sane[i][j].tuple.dst.protonum = IPPROTO_TCP;
+			sane[i][j].mask.src.u.tcp.port = 0xFFFF;
+			sane[i][j].mask.dst.protonum = 0xFF;
+			sane[i][j].max_expected = 1;
+			sane[i][j].timeout = 5 * 60;	/* 5 Minutes */
+			sane[i][j].me = THIS_MODULE;
+			sane[i][j].help = help;
+			tmpname = &sane_names[i][j][0];
+			if (ports[i] == SANE_PORT)
+				sprintf(tmpname, "sane");
+			else
+				sprintf(tmpname, "sane-%d", ports[i]);
+			sane[i][j].name = tmpname;
+
+			DEBUGP("nf_ct_sane: registering helper for pf: %d "
+			       "port: %d\n",
+				sane[i][j].tuple.src.l3num, ports[i]);
+			ret = nf_conntrack_helper_register(&sane[i][j]);
+			if (ret) {
+				printk(KERN_ERR "nf_ct_sane: failed to "
+				       "register helper for pf: %d port: %d\n",
+					sane[i][j].tuple.src.l3num, ports[i]);
+				nf_conntrack_sane_fini();
+				return ret;
+			}
+		}
+	}
+
+	return 0;
+}
+
+module_init(nf_conntrack_sane_init);
+module_exit(nf_conntrack_sane_fini);
diff --git a/net/netfilter/xt_CLASSIFY.c b/net/netfilter/xt_CLASSIFY.c
index 50de965..195e929 100644
--- a/net/netfilter/xt_CLASSIFY.c
+++ b/net/netfilter/xt_CLASSIFY.c
@@ -33,9 +33,7 @@
 {
 	const struct xt_classify_target_info *clinfo = targinfo;
 
-	if ((*pskb)->priority != clinfo->priority)
-		(*pskb)->priority = clinfo->priority;
-
+	(*pskb)->priority = clinfo->priority;
 	return XT_CONTINUE;
 }
 
diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c
index 0534bfa..795c058 100644
--- a/net/netfilter/xt_CONNMARK.c
+++ b/net/netfilter/xt_CONNMARK.c
@@ -61,7 +61,7 @@
 #else
 				nf_conntrack_event_cache(IPCT_MARK, *pskb);
 #endif
-		}
+			}
 			break;
 		case XT_CONNMARK_SAVE:
 			newmark = (*ctmark & ~markinfo->mask) |
@@ -78,8 +78,7 @@
 		case XT_CONNMARK_RESTORE:
 			mark = (*pskb)->mark;
 			diff = (*ctmark ^ mark) & markinfo->mask;
-			if (diff != 0)
-				(*pskb)->mark = mark ^ diff;
+			(*pskb)->mark = mark ^ diff;
 			break;
 		}
 	}
diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c
index a3fe3c3..1ab0db6 100644
--- a/net/netfilter/xt_CONNSECMARK.c
+++ b/net/netfilter/xt_CONNSECMARK.c
@@ -41,8 +41,7 @@
 
 		connsecmark = nf_ct_get_secmark(skb, &ctinfo);
 		if (connsecmark && !*connsecmark)
-			if (*connsecmark != skb->secmark)
-				*connsecmark = skb->secmark;
+			*connsecmark = skb->secmark;
 	}
 }
 
@@ -58,8 +57,7 @@
 
 		connsecmark = nf_ct_get_secmark(skb, &ctinfo);
 		if (connsecmark && *connsecmark)
-			if (skb->secmark != *connsecmark)
-				skb->secmark = *connsecmark;
+			skb->secmark = *connsecmark;
 	}
 }
 
diff --git a/net/netfilter/xt_MARK.c b/net/netfilter/xt_MARK.c
index 0b48547..cfc45af 100644
--- a/net/netfilter/xt_MARK.c
+++ b/net/netfilter/xt_MARK.c
@@ -31,9 +31,7 @@
 {
 	const struct xt_mark_target_info *markinfo = targinfo;
 
-	if((*pskb)->mark != markinfo->mark)
-		(*pskb)->mark = markinfo->mark;
-
+	(*pskb)->mark = markinfo->mark;
 	return XT_CONTINUE;
 }
 
@@ -62,9 +60,7 @@
 		break;
 	}
 
-	if((*pskb)->mark != mark)
-		(*pskb)->mark = mark;
-
+	(*pskb)->mark = mark;
 	return XT_CONTINUE;
 }
 
diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c
index add7521..f1131c3 100644
--- a/net/netfilter/xt_SECMARK.c
+++ b/net/netfilter/xt_SECMARK.c
@@ -47,9 +47,7 @@
 		BUG();
 	}
 
-	if ((*pskb)->secmark != secmark)
-		(*pskb)->secmark = secmark;
-
+	(*pskb)->secmark = secmark;
 	return XT_CONTINUE;
 }
 
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c
new file mode 100644
index 0000000..db7e38c
--- /dev/null
+++ b/net/netfilter/xt_TCPMSS.c
@@ -0,0 +1,296 @@
+/*
+ * This is a module which is used for setting the MSS option in TCP packets.
+ *
+ * Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include <net/ipv6.h>
+#include <net/tcp.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_tcpudp.h>
+#include <linux/netfilter/xt_TCPMSS.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
+MODULE_DESCRIPTION("x_tables TCP MSS modification module");
+MODULE_ALIAS("ipt_TCPMSS");
+MODULE_ALIAS("ip6t_TCPMSS");
+
+static inline unsigned int
+optlen(const u_int8_t *opt, unsigned int offset)
+{
+	/* Beware zero-length options: make finite progress */
+	if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0)
+		return 1;
+	else
+		return opt[offset+1];
+}
+
+static int
+tcpmss_mangle_packet(struct sk_buff **pskb,
+		     const struct xt_tcpmss_info *info,
+		     unsigned int tcphoff,
+		     unsigned int minlen)
+{
+	struct tcphdr *tcph;
+	unsigned int tcplen, i;
+	__be16 oldval;
+	u16 newmss;
+	u8 *opt;
+
+	if (!skb_make_writable(pskb, (*pskb)->len))
+		return -1;
+
+	tcplen = (*pskb)->len - tcphoff;
+	tcph = (struct tcphdr *)((*pskb)->nh.raw + tcphoff);
+
+	/* Since it passed flags test in tcp match, we know it is is
+	   not a fragment, and has data >= tcp header length.  SYN
+	   packets should not contain data: if they did, then we risk
+	   running over MTU, sending Frag Needed and breaking things
+	   badly. --RR */
+	if (tcplen != tcph->doff*4) {
+		if (net_ratelimit())
+			printk(KERN_ERR "xt_TCPMSS: bad length (%u bytes)\n",
+			       (*pskb)->len);
+		return -1;
+	}
+
+	if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
+		if (dst_mtu((*pskb)->dst) <= minlen) {
+			if (net_ratelimit())
+				printk(KERN_ERR "xt_TCPMSS: "
+				       "unknown or invalid path-MTU (%u)\n",
+				       dst_mtu((*pskb)->dst));
+			return -1;
+		}
+		newmss = dst_mtu((*pskb)->dst) - minlen;
+	} else
+		newmss = info->mss;
+
+	opt = (u_int8_t *)tcph;
+	for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) {
+		if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS &&
+		    opt[i+1] == TCPOLEN_MSS) {
+			u_int16_t oldmss;
+
+			oldmss = (opt[i+2] << 8) | opt[i+3];
+
+			if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
+			    oldmss <= newmss)
+				return 0;
+
+			opt[i+2] = (newmss & 0xff00) >> 8;
+			opt[i+3] = (newmss & 0x00ff);
+
+			nf_proto_csum_replace2(&tcph->check, *pskb,
+					       htons(oldmss), htons(newmss), 0);
+			return 0;
+		}
+	}
+
+	/*
+	 * MSS Option not found ?! add it..
+	 */
+	if (skb_tailroom((*pskb)) < TCPOLEN_MSS) {
+		struct sk_buff *newskb;
+
+		newskb = skb_copy_expand(*pskb, skb_headroom(*pskb),
+					 TCPOLEN_MSS, GFP_ATOMIC);
+		if (!newskb)
+			return -1;
+		kfree_skb(*pskb);
+		*pskb = newskb;
+		tcph = (struct tcphdr *)((*pskb)->nh.raw + tcphoff);
+	}
+
+	skb_put((*pskb), TCPOLEN_MSS);
+
+	opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
+	memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
+
+	nf_proto_csum_replace2(&tcph->check, *pskb,
+			       htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1);
+	opt[0] = TCPOPT_MSS;
+	opt[1] = TCPOLEN_MSS;
+	opt[2] = (newmss & 0xff00) >> 8;
+	opt[3] = (newmss & 0x00ff);
+
+	nf_proto_csum_replace4(&tcph->check, *pskb, 0, *((__be32 *)opt), 0);
+
+	oldval = ((__be16 *)tcph)[6];
+	tcph->doff += TCPOLEN_MSS/4;
+	nf_proto_csum_replace2(&tcph->check, *pskb,
+				oldval, ((__be16 *)tcph)[6], 0);
+	return TCPOLEN_MSS;
+}
+
+static unsigned int
+xt_tcpmss_target4(struct sk_buff **pskb,
+		  const struct net_device *in,
+		  const struct net_device *out,
+		  unsigned int hooknum,
+		  const struct xt_target *target,
+		  const void *targinfo)
+{
+	struct iphdr *iph = (*pskb)->nh.iph;
+	__be16 newlen;
+	int ret;
+
+	ret = tcpmss_mangle_packet(pskb, targinfo, iph->ihl * 4,
+				   sizeof(*iph) + sizeof(struct tcphdr));
+	if (ret < 0)
+		return NF_DROP;
+	if (ret > 0) {
+		iph = (*pskb)->nh.iph;
+		newlen = htons(ntohs(iph->tot_len) + ret);
+		nf_csum_replace2(&iph->check, iph->tot_len, newlen);
+		iph->tot_len = newlen;
+	}
+	return XT_CONTINUE;
+}
+
+#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
+static unsigned int
+xt_tcpmss_target6(struct sk_buff **pskb,
+		  const struct net_device *in,
+		  const struct net_device *out,
+		  unsigned int hooknum,
+		  const struct xt_target *target,
+		  const void *targinfo)
+{
+	struct ipv6hdr *ipv6h = (*pskb)->nh.ipv6h;
+	u8 nexthdr;
+	int tcphoff;
+	int ret;
+
+	nexthdr = ipv6h->nexthdr;
+	tcphoff = ipv6_skip_exthdr(*pskb, sizeof(*ipv6h), &nexthdr);
+	if (tcphoff < 0) {
+		WARN_ON(1);
+		return NF_DROP;
+	}
+	ret = tcpmss_mangle_packet(pskb, targinfo, tcphoff,
+				   sizeof(*ipv6h) + sizeof(struct tcphdr));
+	if (ret < 0)
+		return NF_DROP;
+	if (ret > 0) {
+		ipv6h = (*pskb)->nh.ipv6h;
+		ipv6h->payload_len = htons(ntohs(ipv6h->payload_len) + ret);
+	}
+	return XT_CONTINUE;
+}
+#endif
+
+#define TH_SYN 0x02
+
+/* Must specify -p tcp --syn */
+static inline int find_syn_match(const struct xt_entry_match *m)
+{
+	const struct xt_tcp *tcpinfo = (const struct xt_tcp *)m->data;
+
+	if (strcmp(m->u.kernel.match->name, "tcp") == 0 &&
+	    tcpinfo->flg_cmp & TH_SYN &&
+	    !(tcpinfo->invflags & XT_TCP_INV_FLAGS))
+		return 1;
+
+	return 0;
+}
+
+static int
+xt_tcpmss_checkentry4(const char *tablename,
+		      const void *entry,
+		      const struct xt_target *target,
+		      void *targinfo,
+		      unsigned int hook_mask)
+{
+	const struct xt_tcpmss_info *info = targinfo;
+	const struct ipt_entry *e = entry;
+
+	if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
+	    (hook_mask & ~((1 << NF_IP_FORWARD) |
+			   (1 << NF_IP_LOCAL_OUT) |
+			   (1 << NF_IP_POST_ROUTING))) != 0) {
+		printk("xt_TCPMSS: path-MTU clamping only supported in "
+		       "FORWARD, OUTPUT and POSTROUTING hooks\n");
+		return 0;
+	}
+	if (IPT_MATCH_ITERATE(e, find_syn_match))
+		return 1;
+	printk("xt_TCPMSS: Only works on TCP SYN packets\n");
+	return 0;
+}
+
+#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
+static int
+xt_tcpmss_checkentry6(const char *tablename,
+		      const void *entry,
+		      const struct xt_target *target,
+		      void *targinfo,
+		      unsigned int hook_mask)
+{
+	const struct xt_tcpmss_info *info = targinfo;
+	const struct ip6t_entry *e = entry;
+
+	if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
+	    (hook_mask & ~((1 << NF_IP6_FORWARD) |
+			   (1 << NF_IP6_LOCAL_OUT) |
+			   (1 << NF_IP6_POST_ROUTING))) != 0) {
+		printk("xt_TCPMSS: path-MTU clamping only supported in "
+		       "FORWARD, OUTPUT and POSTROUTING hooks\n");
+		return 0;
+	}
+	if (IP6T_MATCH_ITERATE(e, find_syn_match))
+		return 1;
+	printk("xt_TCPMSS: Only works on TCP SYN packets\n");
+	return 0;
+}
+#endif
+
+static struct xt_target xt_tcpmss_reg[] = {
+	{
+		.family		= AF_INET,
+		.name		= "TCPMSS",
+		.checkentry	= xt_tcpmss_checkentry4,
+		.target		= xt_tcpmss_target4,
+		.targetsize	= sizeof(struct xt_tcpmss_info),
+		.proto		= IPPROTO_TCP,
+		.me		= THIS_MODULE,
+	},
+#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
+	{
+		.family		= AF_INET6,
+		.name		= "TCPMSS",
+		.checkentry	= xt_tcpmss_checkentry6,
+		.target		= xt_tcpmss_target6,
+		.targetsize	= sizeof(struct xt_tcpmss_info),
+		.proto		= IPPROTO_TCP,
+		.me		= THIS_MODULE,
+	},
+#endif
+};
+
+static int __init xt_tcpmss_init(void)
+{
+	return xt_register_targets(xt_tcpmss_reg, ARRAY_SIZE(xt_tcpmss_reg));
+}
+
+static void __exit xt_tcpmss_fini(void)
+{
+	xt_unregister_targets(xt_tcpmss_reg, ARRAY_SIZE(xt_tcpmss_reg));
+}
+
+module_init(xt_tcpmss_init);
+module_exit(xt_tcpmss_fini);
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index f28bf69..bd1f7a2 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -414,6 +414,7 @@
 	switch (nexthdr) {
 	case IPPROTO_TCP:
 	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE:
 	case IPPROTO_SCTP:
 	case IPPROTO_DCCP:
 		ports = skb_header_pointer(skb, protoff, sizeof(_ports),
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 6dc01bd..a6fa487 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -60,6 +60,7 @@
 #include <linux/netdevice.h>
 #include <linux/if_packet.h>
 #include <linux/wireless.h>
+#include <linux/kernel.h>
 #include <linux/kmod.h>
 #include <net/ip.h>
 #include <net/protocol.h>
@@ -200,7 +201,8 @@
 #endif
 	struct packet_type	prot_hook;
 	spinlock_t		bind_lock;
-	char			running;	/* prot_hook is attached*/
+	unsigned int		running:1,	/* prot_hook is attached*/
+				auxdata:1;
 	int			ifindex;	/* bound device		*/
 	__be16			num;
 #ifdef CONFIG_PACKET_MULTICAST
@@ -214,6 +216,16 @@
 #endif
 };
 
+struct packet_skb_cb {
+	unsigned int origlen;
+	union {
+		struct sockaddr_pkt pkt;
+		struct sockaddr_ll ll;
+	} sa;
+};
+
+#define PACKET_SKB_CB(__skb)	((struct packet_skb_cb *)((__skb)->cb))
+
 #ifdef CONFIG_PACKET_MMAP
 
 static inline char *packet_lookup_frame(struct packet_sock *po, unsigned int position)
@@ -293,7 +305,7 @@
 	/* drop conntrack reference */
 	nf_reset(skb);
 
-	spkt = (struct sockaddr_pkt*)skb->cb;
+	spkt = &PACKET_SKB_CB(skb)->sa.pkt;
 
 	skb_push(skb, skb->data-skb->mac.raw);
 
@@ -512,7 +524,10 @@
 		skb = nskb;
 	}
 
-	sll = (struct sockaddr_ll*)skb->cb;
+	BUILD_BUG_ON(sizeof(*PACKET_SKB_CB(skb)) + MAX_ADDR_LEN - 8 >
+		     sizeof(skb->cb));
+
+	sll = &PACKET_SKB_CB(skb)->sa.ll;
 	sll->sll_family = AF_PACKET;
 	sll->sll_hatype = dev->type;
 	sll->sll_protocol = skb->protocol;
@@ -523,6 +538,8 @@
 	if (dev->hard_header_parse)
 		sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr);
 
+	PACKET_SKB_CB(skb)->origlen = skb->len;
+
 	if (pskb_trim(skb, snaplen))
 		goto drop_n_acct;
 
@@ -582,11 +599,12 @@
 		else if (skb->pkt_type == PACKET_OUTGOING) {
 			/* Special case: outgoing packets have ll header at head */
 			skb_pull(skb, skb->nh.raw - skb->data);
-			if (skb->ip_summed == CHECKSUM_PARTIAL)
-				status |= TP_STATUS_CSUMNOTREADY;
 		}
 	}
 
+	if (skb->ip_summed == CHECKSUM_PARTIAL)
+		status |= TP_STATUS_CSUMNOTREADY;
+
 	snaplen = skb->len;
 
 	res = run_filter(skb, sk, snaplen);
@@ -1092,7 +1110,7 @@
 	 *	it in now.
 	 */
 
-	sll = (struct sockaddr_ll*)skb->cb;
+	sll = &PACKET_SKB_CB(skb)->sa.ll;
 	if (sock->type == SOCK_PACKET)
 		msg->msg_namelen = sizeof(struct sockaddr_pkt);
 	else
@@ -1117,7 +1135,22 @@
 	sock_recv_timestamp(msg, sk, skb);
 
 	if (msg->msg_name)
-		memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
+		memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa,
+		       msg->msg_namelen);
+
+	if (pkt_sk(sk)->auxdata) {
+		struct tpacket_auxdata aux;
+
+		aux.tp_status = TP_STATUS_USER;
+		if (skb->ip_summed == CHECKSUM_PARTIAL)
+			aux.tp_status |= TP_STATUS_CSUMNOTREADY;
+		aux.tp_len = PACKET_SKB_CB(skb)->origlen;
+		aux.tp_snaplen = skb->len;
+		aux.tp_mac = 0;
+		aux.tp_net = skb->nh.raw - skb->data;
+
+		put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux);
+	}
 
 	/*
 	 *	Free or return the buffer as appropriate. Again this
@@ -1317,6 +1350,7 @@
 packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
 {
 	struct sock *sk = sock->sk;
+	struct packet_sock *po = pkt_sk(sk);
 	int ret;
 
 	if (level != SOL_PACKET)
@@ -1369,6 +1403,18 @@
 		return 0;
 	}
 #endif
+	case PACKET_AUXDATA:
+	{
+		int val;
+
+		if (optlen < sizeof(val))
+			return -EINVAL;
+		if (copy_from_user(&val, optval, sizeof(val)))
+			return -EFAULT;
+
+		po->auxdata = !!val;
+		return 0;
+	}
 	default:
 		return -ENOPROTOOPT;
 	}
@@ -1378,8 +1424,11 @@
 			     char __user *optval, int __user *optlen)
 {
 	int len;
+	int val;
 	struct sock *sk = sock->sk;
 	struct packet_sock *po = pkt_sk(sk);
+	void *data;
+	struct tpacket_stats st;
 
 	if (level != SOL_PACKET)
 		return -ENOPROTOOPT;
@@ -1392,9 +1441,6 @@
 		
 	switch(optname)	{
 	case PACKET_STATISTICS:
-	{
-		struct tpacket_stats st;
-
 		if (len > sizeof(struct tpacket_stats))
 			len = sizeof(struct tpacket_stats);
 		spin_lock_bh(&sk->sk_receive_queue.lock);
@@ -1403,16 +1449,23 @@
 		spin_unlock_bh(&sk->sk_receive_queue.lock);
 		st.tp_packets += st.tp_drops;
 
-		if (copy_to_user(optval, &st, len))
-			return -EFAULT;
+		data = &st;
 		break;
-	}
+	case PACKET_AUXDATA:
+		if (len > sizeof(int))
+			len = sizeof(int);
+		val = po->auxdata;
+
+		data = &val;
+		break;
 	default:
 		return -ENOPROTOOPT;
 	}
 
 	if (put_user(len, optlen))
 		return -EFAULT;
+	if (copy_to_user(optval, data, len))
+		return -EFAULT;
 	return 0;
 }
 
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index 01e6913..4c68c71 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -52,7 +52,7 @@
 
 static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook)
 {
-	struct ipt_target *target;
+	struct xt_target *target;
 	int ret = 0;
 
 	target = xt_request_find_target(AF_INET, t->u.user.name,
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index bc116bd..3b6e6a7 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -209,7 +209,7 @@
 				       dev->name);
 				dev->tx_timeout(dev);
 			}
-			if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo))
+			if (!mod_timer(&dev->watchdog_timer, round_jiffies(jiffies + dev->watchdog_timeo)))
 				dev_hold(dev);
 		}
 	}
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 2567b4c..000e043 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -372,6 +372,20 @@
 	return 0;
 }
 
+static int prio_dump_class_stats(struct Qdisc *sch, unsigned long cl,
+				 struct gnet_dump *d)
+{
+	struct prio_sched_data *q = qdisc_priv(sch);
+	struct Qdisc *cl_q;
+
+	cl_q = q->queues[cl - 1];
+	if (gnet_stats_copy_basic(d, &cl_q->bstats) < 0 ||
+	    gnet_stats_copy_queue(d, &cl_q->qstats) < 0)
+		return -1;
+
+	return 0;
+}
+
 static void prio_walk(struct Qdisc *sch, struct qdisc_walker *arg)
 {
 	struct prio_sched_data *q = qdisc_priv(sch);
@@ -414,6 +428,7 @@
 	.bind_tcf	=	prio_bind,
 	.unbind_tcf	=	prio_put,
 	.dump		=	prio_dump_class,
+	.dump_stats	=	prio_dump_class_stats,
 };
 
 static struct Qdisc_ops prio_qdisc_ops = {
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 459cda2..8284480 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -143,6 +143,7 @@
 		if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
 		    (iph->protocol == IPPROTO_TCP ||
 		     iph->protocol == IPPROTO_UDP ||
+		     iph->protocol == IPPROTO_UDPLITE ||
 		     iph->protocol == IPPROTO_SCTP ||
 		     iph->protocol == IPPROTO_DCCP ||
 		     iph->protocol == IPPROTO_ESP))
@@ -156,6 +157,7 @@
 		h2 = iph->saddr.s6_addr32[3]^iph->nexthdr;
 		if (iph->nexthdr == IPPROTO_TCP ||
 		    iph->nexthdr == IPPROTO_UDP ||
+		    iph->nexthdr == IPPROTO_UDPLITE ||
 		    iph->nexthdr == IPPROTO_SCTP ||
 		    iph->nexthdr == IPPROTO_DCCP ||
 		    iph->nexthdr == IPPROTO_ESP)
diff --git a/net/socket.c b/net/socket.c
index 4e39631..5f374e1 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -407,24 +407,11 @@
 
 static struct socket *sock_from_file(struct file *file, int *err)
 {
-	struct inode *inode;
-	struct socket *sock;
-
 	if (file->f_op == &socket_file_ops)
 		return file->private_data;	/* set in sock_map_fd */
 
-	inode = file->f_path.dentry->d_inode;
-	if (!S_ISSOCK(inode->i_mode)) {
-		*err = -ENOTSOCK;
-		return NULL;
-	}
-
-	sock = SOCKET_I(inode);
-	if (sock->file != file) {
-		printk(KERN_ERR "socki_lookup: socket file changed!\n");
-		sock->file = file;
-	}
-	return sock;
+	*err = -ENOTSOCK;
+	return NULL;
 }
 
 /**
@@ -1527,8 +1514,9 @@
 	struct file *sock_file;
 
 	sock_file = fget_light(fd, &fput_needed);
+	err = -EBADF;
 	if (!sock_file)
-		return -EBADF;
+		goto out;
 
 	sock = sock_from_file(sock_file, &err);
 	if (!sock)
@@ -1555,6 +1543,7 @@
 
 out_put:
 	fput_light(sock_file, fput_needed);
+out:
 	return err;
 }
 
@@ -1586,12 +1575,13 @@
 	int fput_needed;
 
 	sock_file = fget_light(fd, &fput_needed);
+	err = -EBADF;
 	if (!sock_file)
-		return -EBADF;
+		goto out;
 
 	sock = sock_from_file(sock_file, &err);
 	if (!sock)
-		goto out;
+		goto out_put;
 
 	msg.msg_control = NULL;
 	msg.msg_controllen = 0;
@@ -1610,8 +1600,9 @@
 		if (err2 < 0)
 			err = err2;
 	}
-out:
+out_put:
 	fput_light(sock_file, fput_needed);
+out:
 	return err;
 }
 
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 4c16112..c1f8781 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -386,7 +386,7 @@
 		svsk = list_entry(serv->sv_tempsocks.next,
 				  struct svc_sock,
 				  sk_list);
-		svc_delete_socket(svsk);
+		svc_close_socket(svsk);
 	}
 	if (serv->sv_shutdown)
 		serv->sv_shutdown(serv);
@@ -395,7 +395,7 @@
 		svsk = list_entry(serv->sv_permsocks.next,
 				  struct svc_sock,
 				  sk_list);
-		svc_delete_socket(svsk);
+		svc_close_socket(svsk);
 	}
 	
 	cache_clean_deferred(serv);
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index ff1f8bf..cf93cd1 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -62,6 +62,12 @@
  *		after a clear, the socket must be read/accepted
  *		 if this succeeds, it must be set again.
  *	SK_CLOSE can set at any time. It is never cleared.
+ *      sk_inuse contains a bias of '1' until SK_DEAD is set.
+ *             so when sk_inuse hits zero, we know the socket is dead
+ *             and no-one is using it.
+ *      SK_DEAD can only be set while SK_BUSY is held which ensures
+ *             no other thread will be using the socket or will try to
+ *	       set SK_DEAD.
  *
  */
 
@@ -70,6 +76,7 @@
 
 static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *,
 					 int *errp, int pmap_reg);
+static void		svc_delete_socket(struct svc_sock *svsk);
 static void		svc_udp_data_ready(struct sock *, int);
 static int		svc_udp_recvfrom(struct svc_rqst *);
 static int		svc_udp_sendto(struct svc_rqst *);
@@ -329,8 +336,9 @@
 static inline void
 svc_sock_put(struct svc_sock *svsk)
 {
-	if (atomic_dec_and_test(&svsk->sk_inuse) &&
-			test_bit(SK_DEAD, &svsk->sk_flags)) {
+	if (atomic_dec_and_test(&svsk->sk_inuse)) {
+		BUG_ON(! test_bit(SK_DEAD, &svsk->sk_flags));
+
 		dprintk("svc: releasing dead socket\n");
 		if (svsk->sk_sock->file)
 			sockfd_put(svsk->sk_sock);
@@ -520,7 +528,7 @@
 
 	if (!serv)
 		return 0;
-	spin_lock(&serv->sv_lock);
+	spin_lock_bh(&serv->sv_lock);
 	list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) {
 		int onelen = one_sock_name(buf+len, svsk);
 		if (toclose && strcmp(toclose, buf+len) == 0)
@@ -528,12 +536,12 @@
 		else
 			len += onelen;
 	}
-	spin_unlock(&serv->sv_lock);
+	spin_unlock_bh(&serv->sv_lock);
 	if (closesk)
 		/* Should unregister with portmap, but you cannot
 		 * unregister just one protocol...
 		 */
-		svc_delete_socket(closesk);
+		svc_close_socket(closesk);
 	else if (toclose)
 		return -ENOENT;
 	return len;
@@ -683,6 +691,11 @@
 		return svc_deferred_recv(rqstp);
 	}
 
+	if (test_bit(SK_CLOSE, &svsk->sk_flags)) {
+		svc_delete_socket(svsk);
+		return 0;
+	}
+
 	clear_bit(SK_DATA, &svsk->sk_flags);
 	while ((skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) {
 		if (err == -EAGAIN) {
@@ -1176,7 +1189,8 @@
 		       rqstp->rq_sock->sk_server->sv_name,
 		       (sent<0)?"got error":"sent only",
 		       sent, xbufp->len);
-		svc_delete_socket(rqstp->rq_sock);
+		set_bit(SK_CLOSE, &rqstp->rq_sock->sk_flags);
+		svc_sock_enqueue(rqstp->rq_sock);
 		sent = -EAGAIN;
 	}
 	return sent;
@@ -1495,7 +1509,7 @@
 	svsk->sk_odata = inet->sk_data_ready;
 	svsk->sk_owspace = inet->sk_write_space;
 	svsk->sk_server = serv;
-	atomic_set(&svsk->sk_inuse, 0);
+	atomic_set(&svsk->sk_inuse, 1);
 	svsk->sk_lastrecv = get_seconds();
 	spin_lock_init(&svsk->sk_defer_lock);
 	INIT_LIST_HEAD(&svsk->sk_deferred);
@@ -1618,7 +1632,7 @@
 /*
  * Remove a dead socket
  */
-void
+static void
 svc_delete_socket(struct svc_sock *svsk)
 {
 	struct svc_serv	*serv;
@@ -1644,16 +1658,26 @@
 	 * while still attached to a queue, the queue itself
 	 * is about to be destroyed (in svc_destroy).
 	 */
-	if (!test_and_set_bit(SK_DEAD, &svsk->sk_flags))
+	if (!test_and_set_bit(SK_DEAD, &svsk->sk_flags)) {
+		BUG_ON(atomic_read(&svsk->sk_inuse)<2);
+		atomic_dec(&svsk->sk_inuse);
 		if (test_bit(SK_TEMP, &svsk->sk_flags))
 			serv->sv_tmpcnt--;
+	}
 
-	/* This atomic_inc should be needed - svc_delete_socket
-	 * should have the semantic of dropping a reference.
-	 * But it doesn't yet....
-	 */
-	atomic_inc(&svsk->sk_inuse);
 	spin_unlock_bh(&serv->sv_lock);
+}
+
+void svc_close_socket(struct svc_sock *svsk)
+{
+	set_bit(SK_CLOSE, &svsk->sk_flags);
+	if (test_and_set_bit(SK_BUSY, &svsk->sk_flags))
+		/* someone else will have to effect the close */
+		return;
+
+	atomic_inc(&svsk->sk_inuse);
+	svc_delete_socket(svsk);
+	clear_bit(SK_BUSY, &svsk->sk_flags);
 	svc_sock_put(svsk);
 }
 
diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
index 769cdd6..4d90a17 100644
--- a/net/wanrouter/wanmain.c
+++ b/net/wanrouter/wanmain.c
@@ -86,8 +86,8 @@
 
 static struct wan_device *wanrouter_find_device(char *name);
 static int wanrouter_delete_interface(struct wan_device *wandev, char *name);
-void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
-void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
+static void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
+static void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
 
 
 
@@ -104,8 +104,8 @@
  *	Organize Unique Identifiers for encapsulation/decapsulation
  */
 
-static unsigned char wanrouter_oui_ether[] = { 0x00, 0x00, 0x00 };
 #if 0
+static unsigned char wanrouter_oui_ether[] = { 0x00, 0x00, 0x00 };
 static unsigned char wanrouter_oui_802_2[] = { 0x00, 0x80, 0xC2 };
 #endif
 
@@ -246,6 +246,8 @@
 	return 0;
 }
 
+#if 0
+
 /*
  *	Encapsulate packet.
  *
@@ -341,6 +343,7 @@
 	return ethertype;
 }
 
+#endif  /*  0  */
 
 /*
  *	WAN device IOCTL.
@@ -799,23 +802,19 @@
 	return 0;
 }
 
-void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags)
+static void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags)
 {
        	spin_lock_irqsave(lock, *smp_flags);
 }
 
 
-void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags)
+static void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags)
 {
 	spin_unlock_irqrestore(lock, *smp_flags);
 }
 
 EXPORT_SYMBOL(register_wan_device);
 EXPORT_SYMBOL(unregister_wan_device);
-EXPORT_SYMBOL(wanrouter_encapsulate);
-EXPORT_SYMBOL(wanrouter_type_trans);
-EXPORT_SYMBOL(lock_adapter_irq);
-EXPORT_SYMBOL(unlock_adapter_irq);
 
 MODULE_LICENSE("GPL");
 
diff --git a/net/x25/Makefile b/net/x25/Makefile
index 587a71a..a2c34ab 100644
--- a/net/x25/Makefile
+++ b/net/x25/Makefile
@@ -6,5 +6,5 @@
 
 x25-y			:= af_x25.o x25_dev.o x25_facilities.o x25_in.o \
 			   x25_link.o x25_out.o x25_route.o x25_subr.o \
-			   x25_timer.o x25_proc.o
+			   x25_timer.o x25_proc.o x25_forward.o
 x25-$(CONFIG_SYSCTL)	+= sysctl_net_x25.o
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index b5c80b1..b37d894 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -63,6 +63,7 @@
 int sysctl_x25_reset_request_timeout   = X25_DEFAULT_T22;
 int sysctl_x25_clear_request_timeout   = X25_DEFAULT_T23;
 int sysctl_x25_ack_holdback_timeout    = X25_DEFAULT_T2;
+int sysctl_x25_forward                 = 0;
 
 HLIST_HEAD(x25_list);
 DEFINE_RWLOCK(x25_list_lock);
@@ -846,7 +847,7 @@
 	struct x25_address source_addr, dest_addr;
 	struct x25_facilities facilities;
 	struct x25_dte_facilities dte_facilities;
-	int len, rc;
+	int len, addr_len, rc;
 
 	/*
 	 *	Remove the LCI and frame type.
@@ -857,7 +858,8 @@
 	 *	Extract the X.25 addresses and convert them to ASCII strings,
 	 *	and remove them.
 	 */
-	skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr));
+	addr_len = x25_addr_ntoa(skb->data, &source_addr, &dest_addr);
+	skb_pull(skb, addr_len);
 
 	/*
 	 *	Get the length of the facilities, skip past them for the moment
@@ -873,11 +875,28 @@
 	sk = x25_find_listener(&source_addr,skb);
 	skb_push(skb,len);
 
+	if (sk != NULL && sk_acceptq_is_full(sk)) {
+		goto out_sock_put;
+	}
+
 	/*
-	 *	We can't accept the Call Request.
+	 *	We dont have any listeners for this incoming call.
+	 *	Try forwarding it.
 	 */
-	if (sk == NULL || sk_acceptq_is_full(sk))
-		goto out_clear_request;
+	if (sk == NULL) {
+		skb_push(skb, addr_len + X25_STD_MIN_LEN);
+		if (sysctl_x25_forward &&
+				x25_forward_call(&dest_addr, nb, skb, lci) > 0)
+		{
+			/* Call was forwarded, dont process it any more */
+			kfree_skb(skb);
+			rc = 1;
+			goto out;
+		} else {
+			/* No listeners, can't forward, clear the call */
+			goto out_clear_request;
+		}
+	}
 
 	/*
 	 *	Try to reach a compromise on the requested facilities.
@@ -1598,6 +1617,9 @@
 			x25_disconnect(s, ENETUNREACH, 0, 0);
 
 	write_unlock_bh(&x25_list_lock);
+
+	/* Remove any related forwards */
+	x25_clear_forward_by_dev(nb->dev);
 }
 
 static int __init x25_init(void)
diff --git a/net/x25/sysctl_net_x25.c b/net/x25/sysctl_net_x25.c
index aabda59..2b2e7fd 100644
--- a/net/x25/sysctl_net_x25.c
+++ b/net/x25/sysctl_net_x25.c
@@ -73,6 +73,14 @@
 		.extra1 =	&min_timer,
 		.extra2 =	&max_timer,
 	},
+	{
+		.ctl_name =	NET_X25_FORWARD,
+		.procname =	"x25_forward",
+		.data = 	&sysctl_x25_forward,
+		.maxlen = 	sizeof(int),
+		.mode = 	0644,
+		.proc_handler = &proc_dointvec,
+	},
 	{ 0, },
 };
 
diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c
index 328d80f..f099fd6 100644
--- a/net/x25/x25_dev.c
+++ b/net/x25/x25_dev.c
@@ -67,9 +67,18 @@
 		return x25_rx_call_request(skb, nb, lci);
 
 	/*
-	 *	Its not a Call Request, nor is it a control frame.
-	 *      Let caller throw it away.
+	 * 	Its not a Call Request, nor is it a control frame.
+	 *	Can we forward it?
 	 */
+
+	if (x25_forward_data(lci, nb, skb)) {
+		if (frametype == X25_CLEAR_CONFIRMATION) {
+			x25_clear_forward_by_lci(lci);
+		}
+		kfree_skb(skb);
+		return 1;
+	}
+
 /*
 	x25_transmit_clear_request(nb, lci, 0x0D);
 */
diff --git a/net/x25/x25_forward.c b/net/x25/x25_forward.c
new file mode 100644
index 0000000..d339e0c
--- /dev/null
+++ b/net/x25/x25_forward.c
@@ -0,0 +1,163 @@
+/*
+ *	This module:
+ *		This module 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.
+ *
+ *	History
+ *	03-01-2007	Added forwarding for x.25	Andrew Hendry
+ */
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <net/x25.h>
+
+struct list_head x25_forward_list = LIST_HEAD_INIT(x25_forward_list);
+DEFINE_RWLOCK(x25_forward_list_lock);
+
+int x25_forward_call(struct x25_address *dest_addr, struct x25_neigh *from,
+			struct sk_buff *skb, int lci)
+{
+	struct x25_route *rt;
+	struct x25_neigh *neigh_new = NULL;
+	struct list_head *entry;
+	struct x25_forward *x25_frwd, *new_frwd;
+	struct sk_buff *skbn;
+	short same_lci = 0;
+	int rc = 0;
+
+	if ((rt = x25_get_route(dest_addr)) != NULL) {
+
+		if ((neigh_new = x25_get_neigh(rt->dev)) == NULL) {
+			/* This shouldnt happen, if it occurs somehow
+			 * do something sensible
+			 */
+			goto out_put_route;
+		}
+
+		/* Avoid a loop. This is the normal exit path for a
+		 * system with only one x.25 iface and default route
+		 */
+		if (rt->dev == from->dev) {
+			goto out_put_nb;
+		}
+
+		/* Remote end sending a call request on an already
+		 * established LCI? It shouldnt happen, just in case..
+		 */
+		read_lock_bh(&x25_forward_list_lock);
+		list_for_each(entry, &x25_forward_list) {
+			x25_frwd = list_entry(entry, struct x25_forward, node);
+			if (x25_frwd->lci == lci) {
+				printk(KERN_WARNING "X.25: call request for lci which is already registered!, transmitting but not registering new pair\n");
+				same_lci = 1;
+			}
+		}
+		read_unlock_bh(&x25_forward_list_lock);
+
+		/* Save the forwarding details for future traffic */
+		if (!same_lci){
+			if ((new_frwd = kmalloc(sizeof(struct x25_forward),
+							GFP_ATOMIC)) == NULL){
+				rc = -ENOMEM;
+				goto out_put_nb;
+			}
+			new_frwd->lci = lci;
+			new_frwd->dev1 = rt->dev;
+			new_frwd->dev2 = from->dev;
+			write_lock_bh(&x25_forward_list_lock);
+			list_add(&new_frwd->node, &x25_forward_list);
+			write_unlock_bh(&x25_forward_list_lock);
+		}
+
+		/* Forward the call request */
+		if ( (skbn = skb_clone(skb, GFP_ATOMIC)) == NULL){
+			goto out_put_nb;
+		}
+		x25_transmit_link(skbn, neigh_new);
+		rc = 1;
+	}
+
+
+out_put_nb:
+	x25_neigh_put(neigh_new);
+
+out_put_route:
+	x25_route_put(rt);
+	return rc;
+}
+
+
+int x25_forward_data(int lci, struct x25_neigh *from, struct sk_buff *skb) {
+
+	struct x25_forward *frwd;
+	struct list_head *entry;
+	struct net_device *peer = NULL;
+	struct x25_neigh *nb;
+	struct sk_buff *skbn;
+	int rc = 0;
+
+	read_lock_bh(&x25_forward_list_lock);
+	list_for_each(entry, &x25_forward_list) {
+		frwd = list_entry(entry, struct x25_forward, node);
+		if (frwd->lci == lci) {
+			/* The call is established, either side can send */
+			if (from->dev == frwd->dev1) {
+				peer = frwd->dev2;
+			} else {
+				peer = frwd->dev1;
+			}
+			break;
+		}
+	}
+	read_unlock_bh(&x25_forward_list_lock);
+
+	if ( (nb = x25_get_neigh(peer)) == NULL)
+		goto out;
+
+	if ( (skbn = pskb_copy(skb, GFP_ATOMIC)) == NULL){
+		goto out;
+
+	}
+	x25_transmit_link(skbn, nb);
+
+	x25_neigh_put(nb);
+	rc = 1;
+out:
+	return rc;
+}
+
+void x25_clear_forward_by_lci(unsigned int lci)
+{
+	struct x25_forward *fwd;
+	struct list_head *entry, *tmp;
+
+	write_lock_bh(&x25_forward_list_lock);
+
+	list_for_each_safe(entry, tmp, &x25_forward_list) {
+		fwd = list_entry(entry, struct x25_forward, node);
+		if (fwd->lci == lci) {
+			list_del(&fwd->node);
+			kfree(fwd);
+		}
+	}
+	write_unlock_bh(&x25_forward_list_lock);
+}
+
+
+void x25_clear_forward_by_dev(struct net_device *dev)
+{
+	struct x25_forward *fwd;
+	struct list_head *entry, *tmp;
+
+	write_lock_bh(&x25_forward_list_lock);
+
+	list_for_each_safe(entry, tmp, &x25_forward_list) {
+		fwd = list_entry(entry, struct x25_forward, node);
+		if ((fwd->dev1 == dev) || (fwd->dev2 == dev)){
+			list_del(&fwd->node);
+			kfree(fwd);
+		}
+	}
+	write_unlock_bh(&x25_forward_list_lock);
+}
diff --git a/net/x25/x25_proc.c b/net/x25/x25_proc.c
index a11837d..e0470bd 100644
--- a/net/x25/x25_proc.c
+++ b/net/x25/x25_proc.c
@@ -165,6 +165,75 @@
 	return 0;
 } 
 
+static __inline__ struct x25_forward *x25_get_forward_idx(loff_t pos)
+{
+	struct x25_forward *f;
+	struct list_head *entry;
+
+	list_for_each(entry, &x25_forward_list) {
+		f = list_entry(entry, struct x25_forward, node);
+		if (!pos--)
+			goto found;
+	}
+
+	f = NULL;
+found:
+	return f;
+}
+
+static void *x25_seq_forward_start(struct seq_file *seq, loff_t *pos)
+{
+	loff_t l = *pos;
+
+	read_lock_bh(&x25_forward_list_lock);
+	return l ? x25_get_forward_idx(--l) : SEQ_START_TOKEN;
+}
+
+static void *x25_seq_forward_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct x25_forward *f;
+
+	++*pos;
+	if (v == SEQ_START_TOKEN) {
+		f = NULL;
+		if (!list_empty(&x25_forward_list))
+			f = list_entry(x25_forward_list.next,
+					struct x25_forward, node);
+		goto out;
+	}
+	f = v;
+	if (f->node.next != &x25_forward_list)
+		f = list_entry(f->node.next, struct x25_forward, node);
+	else
+		f = NULL;
+out:
+	return f;
+
+}
+
+static void x25_seq_forward_stop(struct seq_file *seq, void *v)
+{
+	read_unlock_bh(&x25_forward_list_lock);
+}
+
+static int x25_seq_forward_show(struct seq_file *seq, void *v)
+{
+	struct x25_forward *f;
+
+	if (v == SEQ_START_TOKEN) {
+		seq_printf(seq, "lci dev1       dev2\n");
+		goto out;
+	}
+
+	f = v;
+
+	seq_printf(seq, "%d %-10s %-10s\n",
+			f->lci, f->dev1->name, f->dev2->name);
+
+out:
+	return 0;
+}
+
 static struct seq_operations x25_seq_route_ops = {
 	.start  = x25_seq_route_start,
 	.next   = x25_seq_route_next,
@@ -179,6 +248,13 @@
 	.show   = x25_seq_socket_show,
 };
 
+static struct seq_operations x25_seq_forward_ops = {
+	.start  = x25_seq_forward_start,
+	.next   = x25_seq_forward_next,
+	.stop   = x25_seq_forward_stop,
+	.show   = x25_seq_forward_show,
+};
+
 static int x25_seq_socket_open(struct inode *inode, struct file *file)
 {
 	return seq_open(file, &x25_seq_socket_ops);
@@ -189,6 +265,11 @@
 	return seq_open(file, &x25_seq_route_ops);
 }
 
+static int x25_seq_forward_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &x25_seq_forward_ops);
+}
+
 static struct file_operations x25_seq_socket_fops = {
 	.owner		= THIS_MODULE,
 	.open		= x25_seq_socket_open,
@@ -205,6 +286,14 @@
 	.release	= seq_release,
 };
 
+static struct file_operations x25_seq_forward_fops = {
+	.owner		= THIS_MODULE,
+	.open		= x25_seq_forward_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
 static struct proc_dir_entry *x25_proc_dir;
 
 int __init x25_proc_init(void)
@@ -225,9 +314,17 @@
 	if (!p)
 		goto out_socket;
 	p->proc_fops = &x25_seq_socket_fops;
+
+	p = create_proc_entry("forward", S_IRUGO, x25_proc_dir);
+	if (!p)
+		goto out_forward;
+	p->proc_fops = &x25_seq_forward_fops;
 	rc = 0;
+
 out:
 	return rc;
+out_forward:
+	remove_proc_entry("socket", x25_proc_dir);
 out_socket:
 	remove_proc_entry("route", x25_proc_dir);
 out_route:
@@ -237,6 +334,7 @@
 
 void __exit x25_proc_exit(void)
 {
+	remove_proc_entry("forward", x25_proc_dir);
 	remove_proc_entry("route", x25_proc_dir);
 	remove_proc_entry("socket", x25_proc_dir);
 	remove_proc_entry("x25", proc_net);
diff --git a/net/x25/x25_route.c b/net/x25/x25_route.c
index 2a3fe98..883a848 100644
--- a/net/x25/x25_route.c
+++ b/net/x25/x25_route.c
@@ -119,6 +119,9 @@
 			__x25_remove_route(rt);
 	}
 	write_unlock_bh(&x25_route_list_lock);
+
+	/* Remove any related forwarding */
+	x25_clear_forward_by_dev(dev);
 }
 
 /*
diff --git a/net/xfrm/Kconfig b/net/xfrm/Kconfig
index 0faab63..577a4f82 100644
--- a/net/xfrm/Kconfig
+++ b/net/xfrm/Kconfig
@@ -24,6 +24,17 @@
 
 	  If unsure, say N.
 
+config XFRM_MIGRATE
+	bool "Transformation migrate database (EXPERIMENTAL)"
+	depends on XFRM && EXPERIMENTAL
+	---help---
+	  A feature to update locator(s) of a given IPsec security
+	  association dynamically.  This feature is required, for
+	  instance, in a Mobile IPv6 environment with IPsec configuration
+	  where mobile nodes change their attachment point to the Internet.
+
+	  If unsure, say N.
+
 config NET_KEY
 	tristate "PF_KEY sockets"
 	select XFRM
@@ -34,4 +45,19 @@
 
 	  Say Y unless you know what you are doing.
 
+config NET_KEY_MIGRATE
+	bool "PF_KEY MIGRATE (EXPERIMENTAL)"
+	depends on NET_KEY && EXPERIMENTAL
+	select XFRM_MIGRATE
+	---help---
+	  Add a PF_KEY MIGRATE message to PF_KEYv2 socket family.
+	  The PF_KEY MIGRATE message is used to dynamically update
+	  locator(s) of a given IPsec security association.
+	  This feature is required, for instance, in a Mobile IPv6
+	  environment with IPsec configuration where mobile nodes
+	  change their attachment point to the Internet.  Detail
+	  information can be found in the internet-draft
+	  <draft-sugimoto-mip6-pfkey-migrate>.
+
+	  If unsure, say N.
 
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
index f1cf340..248f948 100644
--- a/net/xfrm/xfrm_algo.c
+++ b/net/xfrm/xfrm_algo.c
@@ -266,6 +266,23 @@
         }
 },
 {
+	.name = "cbc(camellia)",
+
+	.uinfo = {
+		.encr = {
+			.blockbits = 128,
+			.defkeybits = 128,
+		}
+	},
+
+	.desc = {
+		.sadb_alg_id = SADB_X_EALG_CAMELLIACBC,
+		.sadb_alg_ivlen = 8,
+		.sadb_alg_minbits = 128,
+		.sadb_alg_maxbits = 256
+	}
+},
+{
         .name = "cbc(twofish)",
         .compat = "twofish",
                  
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index b7e537f..fa7ce06 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2236,3 +2236,234 @@
 	xfrm_input_init();
 }
 
+#ifdef CONFIG_XFRM_MIGRATE
+static int xfrm_migrate_selector_match(struct xfrm_selector *sel_cmp,
+				       struct xfrm_selector *sel_tgt)
+{
+	if (sel_cmp->proto == IPSEC_ULPROTO_ANY) {
+		if (sel_tgt->family == sel_cmp->family &&
+		    xfrm_addr_cmp(&sel_tgt->daddr, &sel_cmp->daddr,
+			          sel_cmp->family) == 0 &&
+		    xfrm_addr_cmp(&sel_tgt->saddr, &sel_cmp->saddr,
+				  sel_cmp->family) == 0 &&
+		    sel_tgt->prefixlen_d == sel_cmp->prefixlen_d &&
+		    sel_tgt->prefixlen_s == sel_cmp->prefixlen_s) {
+			return 1;
+		}
+	} else {
+		if (memcmp(sel_tgt, sel_cmp, sizeof(*sel_tgt)) == 0) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static struct xfrm_policy * xfrm_migrate_policy_find(struct xfrm_selector *sel,
+						     u8 dir, u8 type)
+{
+	struct xfrm_policy *pol, *ret = NULL;
+	struct hlist_node *entry;
+	struct hlist_head *chain;
+	u32 priority = ~0U;
+
+	read_lock_bh(&xfrm_policy_lock);
+	chain = policy_hash_direct(&sel->daddr, &sel->saddr, sel->family, dir);
+	hlist_for_each_entry(pol, entry, chain, bydst) {
+		if (xfrm_migrate_selector_match(sel, &pol->selector) &&
+		    pol->type == type) {
+			ret = pol;
+			priority = ret->priority;
+			break;
+		}
+	}
+	chain = &xfrm_policy_inexact[dir];
+	hlist_for_each_entry(pol, entry, chain, bydst) {
+		if (xfrm_migrate_selector_match(sel, &pol->selector) &&
+		    pol->type == type &&
+		    pol->priority < priority) {
+			ret = pol;
+			break;
+		}
+	}
+
+	if (ret)
+		xfrm_pol_hold(ret);
+
+	read_unlock_bh(&xfrm_policy_lock);
+
+	return ret;
+}
+
+static int migrate_tmpl_match(struct xfrm_migrate *m, struct xfrm_tmpl *t)
+{
+	int match = 0;
+
+	if (t->mode == m->mode && t->id.proto == m->proto &&
+	    (m->reqid == 0 || t->reqid == m->reqid)) {
+		switch (t->mode) {
+		case XFRM_MODE_TUNNEL:
+		case XFRM_MODE_BEET:
+			if (xfrm_addr_cmp(&t->id.daddr, &m->old_daddr,
+					  m->old_family) == 0 &&
+			    xfrm_addr_cmp(&t->saddr, &m->old_saddr,
+					  m->old_family) == 0) {
+				match = 1;
+			}
+			break;
+		case XFRM_MODE_TRANSPORT:
+			/* in case of transport mode, template does not store
+			   any IP addresses, hence we just compare mode and
+			   protocol */
+			match = 1;
+			break;
+		default:
+			break;
+		}
+	}
+	return match;
+}
+
+/* update endpoint address(es) of template(s) */
+static int xfrm_policy_migrate(struct xfrm_policy *pol,
+			       struct xfrm_migrate *m, int num_migrate)
+{
+	struct xfrm_migrate *mp;
+	struct dst_entry *dst;
+	int i, j, n = 0;
+
+	write_lock_bh(&pol->lock);
+	if (unlikely(pol->dead)) {
+		/* target policy has been deleted */
+		write_unlock_bh(&pol->lock);
+		return -ENOENT;
+	}
+
+	for (i = 0; i < pol->xfrm_nr; i++) {
+		for (j = 0, mp = m; j < num_migrate; j++, mp++) {
+			if (!migrate_tmpl_match(mp, &pol->xfrm_vec[i]))
+				continue;
+			n++;
+			if (pol->xfrm_vec[i].mode != XFRM_MODE_TUNNEL)
+				continue;
+			/* update endpoints */
+			memcpy(&pol->xfrm_vec[i].id.daddr, &mp->new_daddr,
+			       sizeof(pol->xfrm_vec[i].id.daddr));
+			memcpy(&pol->xfrm_vec[i].saddr, &mp->new_saddr,
+			       sizeof(pol->xfrm_vec[i].saddr));
+			pol->xfrm_vec[i].encap_family = mp->new_family;
+			/* flush bundles */
+			while ((dst = pol->bundles) != NULL) {
+				pol->bundles = dst->next;
+				dst_free(dst);
+			}
+		}
+	}
+
+	write_unlock_bh(&pol->lock);
+
+	if (!n)
+		return -ENODATA;
+
+	return 0;
+}
+
+static int xfrm_migrate_check(struct xfrm_migrate *m, int num_migrate)
+{
+	int i, j;
+
+	if (num_migrate < 1 || num_migrate > XFRM_MAX_DEPTH)
+		return -EINVAL;
+
+	for (i = 0; i < num_migrate; i++) {
+		if ((xfrm_addr_cmp(&m[i].old_daddr, &m[i].new_daddr,
+				   m[i].old_family) == 0) &&
+		    (xfrm_addr_cmp(&m[i].old_saddr, &m[i].new_saddr,
+				   m[i].old_family) == 0))
+			return -EINVAL;
+		if (xfrm_addr_any(&m[i].new_daddr, m[i].new_family) ||
+		    xfrm_addr_any(&m[i].new_saddr, m[i].new_family))
+			return -EINVAL;
+
+		/* check if there is any duplicated entry */
+		for (j = i + 1; j < num_migrate; j++) {
+			if (!memcmp(&m[i].old_daddr, &m[j].old_daddr,
+				    sizeof(m[i].old_daddr)) &&
+			    !memcmp(&m[i].old_saddr, &m[j].old_saddr,
+				    sizeof(m[i].old_saddr)) &&
+			    m[i].proto == m[j].proto &&
+			    m[i].mode == m[j].mode &&
+			    m[i].reqid == m[j].reqid &&
+			    m[i].old_family == m[j].old_family)
+				return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
+		 struct xfrm_migrate *m, int num_migrate)
+{
+	int i, err, nx_cur = 0, nx_new = 0;
+	struct xfrm_policy *pol = NULL;
+	struct xfrm_state *x, *xc;
+	struct xfrm_state *x_cur[XFRM_MAX_DEPTH];
+	struct xfrm_state *x_new[XFRM_MAX_DEPTH];
+	struct xfrm_migrate *mp;
+
+	if ((err = xfrm_migrate_check(m, num_migrate)) < 0)
+		goto out;
+
+	/* Stage 1 - find policy */
+	if ((pol = xfrm_migrate_policy_find(sel, dir, type)) == NULL) {
+		err = -ENOENT;
+		goto out;
+	}
+
+	/* Stage 2 - find and update state(s) */
+	for (i = 0, mp = m; i < num_migrate; i++, mp++) {
+		if ((x = xfrm_migrate_state_find(mp))) {
+			x_cur[nx_cur] = x;
+			nx_cur++;
+			if ((xc = xfrm_state_migrate(x, mp))) {
+				x_new[nx_new] = xc;
+				nx_new++;
+			} else {
+				err = -ENODATA;
+				goto restore_state;
+			}
+		}
+	}
+
+	/* Stage 3 - update policy */
+	if ((err = xfrm_policy_migrate(pol, m, num_migrate)) < 0)
+		goto restore_state;
+
+	/* Stage 4 - delete old state(s) */
+	if (nx_cur) {
+		xfrm_states_put(x_cur, nx_cur);
+		xfrm_states_delete(x_cur, nx_cur);
+	}
+
+	/* Stage 5 - announce */
+	km_migrate(sel, dir, type, m, num_migrate);
+
+	xfrm_pol_put(pol);
+
+	return 0;
+out:
+	return err;
+
+restore_state:
+	if (pol)
+		xfrm_pol_put(pol);
+	if (nx_cur)
+		xfrm_states_put(x_cur, nx_cur);
+	if (nx_new)
+		xfrm_states_delete(x_new, nx_new);
+
+	return err;
+}
+EXPORT_SYMBOL(xfrm_migrate);
+#endif
+
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index fdb08d9..91b0268 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -183,9 +183,6 @@
 
 int __xfrm_state_delete(struct xfrm_state *x);
 
-static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family);
-static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
-
 int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
 void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
 
@@ -831,6 +828,160 @@
 }
 EXPORT_SYMBOL(xfrm_state_add);
 
+#ifdef CONFIG_XFRM_MIGRATE
+struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
+{
+	int err = -ENOMEM;
+	struct xfrm_state *x = xfrm_state_alloc();
+	if (!x)
+		goto error;
+
+	memcpy(&x->id, &orig->id, sizeof(x->id));
+	memcpy(&x->sel, &orig->sel, sizeof(x->sel));
+	memcpy(&x->lft, &orig->lft, sizeof(x->lft));
+	x->props.mode = orig->props.mode;
+	x->props.replay_window = orig->props.replay_window;
+	x->props.reqid = orig->props.reqid;
+	x->props.family = orig->props.family;
+	x->props.saddr = orig->props.saddr;
+
+	if (orig->aalg) {
+		x->aalg = xfrm_algo_clone(orig->aalg);
+		if (!x->aalg)
+			goto error;
+	}
+	x->props.aalgo = orig->props.aalgo;
+
+	if (orig->ealg) {
+		x->ealg = xfrm_algo_clone(orig->ealg);
+		if (!x->ealg)
+			goto error;
+	}
+	x->props.ealgo = orig->props.ealgo;
+
+	if (orig->calg) {
+		x->calg = xfrm_algo_clone(orig->calg);
+		if (!x->calg)
+			goto error;
+	}
+	x->props.calgo = orig->props.calgo;
+
+        if (orig->encap) {
+		x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL);
+		if (!x->encap)
+			goto error;
+	}
+
+	if (orig->coaddr) {
+		x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),
+				    GFP_KERNEL);
+		if (!x->coaddr)
+			goto error;
+	}
+
+	err = xfrm_init_state(x);
+	if (err)
+		goto error;
+
+	x->props.flags = orig->props.flags;
+
+	x->curlft.add_time = orig->curlft.add_time;
+	x->km.state = orig->km.state;
+	x->km.seq = orig->km.seq;
+
+	return x;
+
+ error:
+	if (errp)
+		*errp = err;
+	if (x) {
+		kfree(x->aalg);
+		kfree(x->ealg);
+		kfree(x->calg);
+		kfree(x->encap);
+		kfree(x->coaddr);
+	}
+	kfree(x);
+	return NULL;
+}
+EXPORT_SYMBOL(xfrm_state_clone);
+
+/* xfrm_state_lock is held */
+struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
+{
+	unsigned int h;
+	struct xfrm_state *x;
+	struct hlist_node *entry;
+
+	if (m->reqid) {
+		h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr,
+				  m->reqid, m->old_family);
+		hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
+			if (x->props.mode != m->mode ||
+			    x->id.proto != m->proto)
+				continue;
+			if (m->reqid && x->props.reqid != m->reqid)
+				continue;
+			if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
+					  m->old_family) ||
+			    xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
+					  m->old_family))
+				continue;
+			xfrm_state_hold(x);
+			return x;
+		}
+	} else {
+		h = xfrm_src_hash(&m->old_daddr, &m->old_saddr,
+				  m->old_family);
+		hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) {
+			if (x->props.mode != m->mode ||
+			    x->id.proto != m->proto)
+				continue;
+			if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
+					  m->old_family) ||
+			    xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
+					  m->old_family))
+				continue;
+			xfrm_state_hold(x);
+			return x;
+		}
+	}
+
+        return NULL;
+}
+EXPORT_SYMBOL(xfrm_migrate_state_find);
+
+struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
+				       struct xfrm_migrate *m)
+{
+	struct xfrm_state *xc;
+	int err;
+
+	xc = xfrm_state_clone(x, &err);
+	if (!xc)
+		return NULL;
+
+	memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
+	memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
+
+	/* add state */
+	if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) {
+		/* a care is needed when the destination address of the
+		   state is to be updated as it is a part of triplet */
+		xfrm_state_insert(xc);
+	} else {
+		if ((err = xfrm_state_add(xc)) < 0)
+			goto error;
+	}
+
+	return xc;
+error:
+	kfree(xc);
+	return NULL;
+}
+EXPORT_SYMBOL(xfrm_state_migrate);
+#endif
+
 int xfrm_state_update(struct xfrm_state *x)
 {
 	struct xfrm_state *x1;
@@ -1345,6 +1496,26 @@
 }
 EXPORT_SYMBOL(km_policy_expired);
 
+int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
+	       struct xfrm_migrate *m, int num_migrate)
+{
+	int err = -EINVAL;
+	int ret;
+	struct xfrm_mgr *km;
+
+	read_lock(&xfrm_km_lock);
+	list_for_each_entry(km, &xfrm_km_list, list) {
+		if (km->migrate) {
+			ret = km->migrate(sel, dir, type, m, num_migrate);
+			if (!ret)
+				err = ret;
+		}
+	}
+	read_unlock(&xfrm_km_lock);
+	return err;
+}
+EXPORT_SYMBOL(km_migrate);
+
 int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
 {
 	int err = -EINVAL;
@@ -1458,7 +1629,7 @@
 }
 EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
 
-static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family)
+struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family)
 {
 	struct xfrm_state_afinfo *afinfo;
 	if (unlikely(family >= NPROTO))
@@ -1470,11 +1641,14 @@
 	return afinfo;
 }
 
-static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
+void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
 {
 	read_unlock(&xfrm_state_afinfo_lock);
 }
 
+EXPORT_SYMBOL(xfrm_state_get_afinfo);
+EXPORT_SYMBOL(xfrm_state_put_afinfo);
+
 /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
 void xfrm_state_delete_tunnel(struct xfrm_state *x)
 {
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 82f36d3..079a5d3 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1632,6 +1632,176 @@
 	return 0;
 }
 
+#ifdef CONFIG_XFRM_MIGRATE
+static int verify_user_migrate(struct rtattr **xfrma)
+{
+	struct rtattr *rt = xfrma[XFRMA_MIGRATE-1];
+	struct xfrm_user_migrate *um;
+
+	if (!rt)
+		return -EINVAL;
+
+	if ((rt->rta_len - sizeof(*rt)) < sizeof(*um))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int copy_from_user_migrate(struct xfrm_migrate *ma,
+				  struct rtattr **xfrma, int *num)
+{
+	struct rtattr *rt = xfrma[XFRMA_MIGRATE-1];
+	struct xfrm_user_migrate *um;
+	int i, num_migrate;
+
+	um = RTA_DATA(rt);
+	num_migrate = (rt->rta_len - sizeof(*rt)) / sizeof(*um);
+
+	if (num_migrate <= 0 || num_migrate > XFRM_MAX_DEPTH)
+		return -EINVAL;
+
+	for (i = 0; i < num_migrate; i++, um++, ma++) {
+		memcpy(&ma->old_daddr, &um->old_daddr, sizeof(ma->old_daddr));
+		memcpy(&ma->old_saddr, &um->old_saddr, sizeof(ma->old_saddr));
+		memcpy(&ma->new_daddr, &um->new_daddr, sizeof(ma->new_daddr));
+		memcpy(&ma->new_saddr, &um->new_saddr, sizeof(ma->new_saddr));
+
+		ma->proto = um->proto;
+		ma->mode = um->mode;
+		ma->reqid = um->reqid;
+
+		ma->old_family = um->old_family;
+		ma->new_family = um->new_family;
+	}
+
+	*num = i;
+	return 0;
+}
+
+static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
+			   struct rtattr **xfrma)
+{
+	struct xfrm_userpolicy_id *pi = NLMSG_DATA(nlh);
+	struct xfrm_migrate m[XFRM_MAX_DEPTH];
+	u8 type;
+	int err;
+	int n = 0;
+
+	err = verify_user_migrate((struct rtattr **)xfrma);
+	if (err)
+		return err;
+
+	err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma);
+	if (err)
+		return err;
+
+	err = copy_from_user_migrate((struct xfrm_migrate *)m,
+				     (struct rtattr **)xfrma, &n);
+	if (err)
+		return err;
+
+	if (!n)
+		return 0;
+
+	xfrm_migrate(&pi->sel, pi->dir, type, m, n);
+
+	return 0;
+}
+#else
+static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
+			   struct rtattr **xfrma)
+{
+	return -ENOPROTOOPT;
+}
+#endif
+
+#ifdef CONFIG_XFRM_MIGRATE
+static int copy_to_user_migrate(struct xfrm_migrate *m, struct sk_buff *skb)
+{
+	struct xfrm_user_migrate um;
+
+	memset(&um, 0, sizeof(um));
+	um.proto = m->proto;
+	um.mode = m->mode;
+	um.reqid = m->reqid;
+	um.old_family = m->old_family;
+	memcpy(&um.old_daddr, &m->old_daddr, sizeof(um.old_daddr));
+	memcpy(&um.old_saddr, &m->old_saddr, sizeof(um.old_saddr));
+	um.new_family = m->new_family;
+	memcpy(&um.new_daddr, &m->new_daddr, sizeof(um.new_daddr));
+	memcpy(&um.new_saddr, &m->new_saddr, sizeof(um.new_saddr));
+
+	RTA_PUT(skb, XFRMA_MIGRATE, sizeof(um), &um);
+	return 0;
+
+rtattr_failure:
+	return -1;
+}
+
+static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m,
+			 int num_migrate, struct xfrm_selector *sel,
+			 u8 dir, u8 type)
+{
+	struct xfrm_migrate *mp;
+	struct xfrm_userpolicy_id *pol_id;
+	struct nlmsghdr *nlh;
+	unsigned char *b = skb->tail;
+	int i;
+
+	nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_MIGRATE, sizeof(*pol_id));
+	pol_id = NLMSG_DATA(nlh);
+	nlh->nlmsg_flags = 0;
+
+	/* copy data from selector, dir, and type to the pol_id */
+	memset(pol_id, 0, sizeof(*pol_id));
+	memcpy(&pol_id->sel, sel, sizeof(pol_id->sel));
+	pol_id->dir = dir;
+
+	if (copy_to_user_policy_type(type, skb) < 0)
+		goto nlmsg_failure;
+
+	for (i = 0, mp = m ; i < num_migrate; i++, mp++) {
+		if (copy_to_user_migrate(mp, skb) < 0)
+			goto nlmsg_failure;
+	}
+
+	nlh->nlmsg_len = skb->tail - b;
+	return skb->len;
+nlmsg_failure:
+	skb_trim(skb, b - skb->data);
+	return -1;
+}
+
+static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
+			     struct xfrm_migrate *m, int num_migrate)
+{
+	struct sk_buff *skb;
+	size_t len;
+
+	len = RTA_SPACE(sizeof(struct xfrm_user_migrate) * num_migrate);
+	len += NLMSG_SPACE(sizeof(struct xfrm_userpolicy_id));
+#ifdef CONFIG_XFRM_SUB_POLICY
+	len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type));
+#endif
+	skb = alloc_skb(len, GFP_ATOMIC);
+	if (skb == NULL)
+		return -ENOMEM;
+
+	/* build migrate */
+	if (build_migrate(skb, m, num_migrate, sel, dir, type) < 0)
+		BUG();
+
+	NETLINK_CB(skb).dst_group = XFRMNLGRP_MIGRATE;
+	return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_MIGRATE,
+				 GFP_ATOMIC);
+}
+#else
+static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
+			     struct xfrm_migrate *m, int num_migrate)
+{
+	return -ENOPROTOOPT;
+}
+#endif
 
 #define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type))
 
@@ -1653,6 +1823,7 @@
 	[XFRM_MSG_NEWAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
 	[XFRM_MSG_GETAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
 	[XFRM_MSG_REPORT      - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),
+	[XFRM_MSG_MIGRATE     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
 };
 
 #undef XMSGSIZE
@@ -1679,6 +1850,7 @@
 	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy  },
 	[XFRM_MSG_NEWAE       - XFRM_MSG_BASE] = { .doit = xfrm_new_ae  },
 	[XFRM_MSG_GETAE       - XFRM_MSG_BASE] = { .doit = xfrm_get_ae  },
+	[XFRM_MSG_MIGRATE     - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate    },
 };
 
 static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
@@ -2285,6 +2457,7 @@
 	.compile_policy	= xfrm_compile_policy,
 	.notify_policy	= xfrm_send_policy_notify,
 	.report		= xfrm_send_report,
+	.migrate	= xfrm_send_migrate,
 };
 
 static int __init xfrm_user_init(void)
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index f01f8c0..06c1a37 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -1,7 +1,7 @@
 ####
 # kbuild: Generic definitions
 
-# Convinient variables
+# Convenient variables
 comma   := ,
 squote  := '
 empty   :=
@@ -59,32 +59,40 @@
 # output directory for tests below
 TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/)
 
-# as-option
-# Usage: cflags-y += $(call as-option, -Wa$(comma)-isa=foo,)
+# try-run
+# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
+# Exit code chooses option. "$$TMP" is can be used as temporary file and
+# is automatically cleaned up.
+try-run = $(shell set -e;		\
+	TMP="$(TMPOUT).$$$$.tmp";	\
+	if ($(1)) >/dev/null 2>&1;	\
+	then echo "$(2)";		\
+	else echo "$(3)";		\
+	fi;				\
+	rm -f "$$TMP")
 
-as-option = $(shell if $(CC) $(CFLAGS) $(1) -Wa,-Z -c -o /dev/null \
-	     -xassembler /dev/null > /dev/null 2>&1; then echo "$(1)"; \
-	     else echo "$(2)"; fi ;)
+# as-option
+# Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,)
+
+as-option = $(call try-run,\
+	$(CC) $(CFLAGS) $(1) -c -xassembler /dev/null -o "$$TMP",$(1),$(2))
 
 # as-instr
-# Usage: cflags-y += $(call as-instr, instr, option1, option2)
+# Usage: cflags-y += $(call as-instr,instr,option1,option2)
 
-as-instr = $(shell if echo -e "$(1)" | \
-		      $(CC) $(AFLAGS) -c -xassembler - \
-			    -o $(TMPOUT)astest$$$$.out > /dev/null 2>&1; \
-		   then rm $(TMPOUT)astest$$$$.out; echo "$(2)"; \
-		   else echo "$(3)"; fi)
+as-instr = $(call try-run,\
+	echo -e "$(1)" | $(CC) $(AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3))
 
 # cc-option
-# Usage: cflags-y += $(call cc-option, -march=winchip-c6, -march=i586)
+# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
 
-cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
-             > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
+cc-option = $(call try-run,\
+	$(CC) $(CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",$(1),$(2))
 
 # cc-option-yn
-# Usage: flag := $(call cc-option-yn, -march=winchip-c6)
-cc-option-yn = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
-                > /dev/null 2>&1; then echo "y"; else echo "n"; fi;)
+# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
+cc-option-yn = $(call try-run,\
+	$(CC) $(CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",y,n)
 
 # cc-option-align
 # Prefix align with either -falign or -malign
@@ -92,20 +100,19 @@
 	$(call cc-option,-falign-functions=0,-malign-functions=0))
 
 # cc-version
-# Usage gcc-ver := $(call cc-version, $(CC))
+# Usage gcc-ver := $(call cc-version,$(CC))
 cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC))
 
 # cc-ifversion
 # Usage:  EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1)
-cc-ifversion = $(shell if [ $(call cc-version, $(CC)) $(1) $(2) ]; then \
-                       echo $(3); fi;)
+cc-ifversion = $(shell [ $(call cc-version, $(CC)) $(1) $(2) ] && echo $(3))
 
 # ld-option
 # Usage: ldflags += $(call ld-option, -Wl$(comma)--hash-style=both)
-ld-option = $(shell if $(CC) $(1) -nostdlib -xc /dev/null \
-			     -o $(TMPOUT)ldtest$$$$.out > /dev/null 2>&1; \
-             then rm $(TMPOUT)ldtest$$$$.out; echo "$(1)"; \
-             else echo "$(2)"; fi)
+ld-option = $(call try-run,\
+	$(CC) $(1) -nostdlib -xc /dev/null -o "$$TMP",$(1),$(2))
+
+######
 
 ###
 # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
@@ -113,19 +120,25 @@
 # $(Q)$(MAKE) $(build)=dir
 build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
 
-# Prefix -I with $(srctree) if it is not an absolute path
+# Prefix -I with $(srctree) if it is not an absolute path.
 addtree = $(if $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1)
+
 # Find all -I options and call addtree
 flags = $(foreach o,$($(1)),$(if $(filter -I%,$(o)),$(call addtree,$(o)),$(o)))
 
-# If quiet is set, only print short version of command
+# echo command.
+# Short version is used, if $(quiet) equals `quiet_', otherwise full one.
+echo-cmd = $(if $($(quiet)cmd_$(1)),\
+	echo '  $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
+
+# printing commands
 cmd = @$(echo-cmd) $(cmd_$(1))
 
-# Add $(obj)/ for paths that is not absolute
+# Add $(obj)/ for paths that are not absolute
 objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o)))
 
 ###
-# if_changed      - execute command if any prerequisite is newer than 
+# if_changed      - execute command if any prerequisite is newer than
 #                   target, or command line has changed
 # if_changed_dep  - as if_changed, but uses fixdep to reveal dependencies
 #                   including used config symbols
@@ -133,16 +146,12 @@
 # See Documentation/kbuild/makefiles.txt for more info
 
 ifneq ($(KBUILD_NOCMDDEP),1)
-# Check if both arguments has same arguments. Result in empty string if equal
+# Check if both arguments has same arguments. Result is empty string if equal.
 # User may override this check using make KBUILD_NOCMDDEP=1
 arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
                     $(filter-out $(cmd_$@),   $(cmd_$(1))) )
 endif
 
-# echo command. Short version is $(quiet) equals quiet, otherwise full command
-echo-cmd = $(if $($(quiet)cmd_$(1)), \
-	echo '  $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
-
 # >'< substitution is for echo to work,
 # >$< substitution to preserve $ when reloading .cmd file
 # note: when using inline perl scripts [perl -e '...$$t=1;...']
@@ -153,15 +162,14 @@
 # PHONY targets skipped in both cases.
 any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
 
-# Execute command if command has changed or prerequisitei(s) are updated
+# Execute command if command has changed or prerequisite(s) are updated.
 #
 if_changed = $(if $(strip $(any-prereq) $(arg-check)),                       \
 	@set -e;                                                             \
 	$(echo-cmd) $(cmd_$(1));                                             \
 	echo 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)
 
-# execute the command and also postprocess generated .d dependencies
-# file
+# Execute the command and also postprocess generated .d dependencies file.
 if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ),                  \
 	@set -e;                                                             \
 	$(echo-cmd) $(cmd_$(1));                                             \
@@ -170,8 +178,8 @@
 	mv -f $(dot-target).tmp $(dot-target).cmd)
 
 # Usage: $(call if_changed_rule,foo)
-# will check if $(cmd_foo) changed, or any of the prequisites changed,
-# and if so will execute $(rule_foo)
+# Will check if $(cmd_foo) or any of the prerequisites changed,
+# and if so will execute $(rule_foo).
 if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ),                 \
 	@set -e;                                                             \
 	$(rule_$(1)))
diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh
index 4c723fd..43f75d6 100644
--- a/scripts/gen_initramfs_list.sh
+++ b/scripts/gen_initramfs_list.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 # Copyright (C) Martin Schlemmer <azarah@nosferatu.za.org>
-# Copyright (c) 2006           Sam Ravnborg <sam@ravnborg.org>
+# Copyright (C) 2006 Sam Ravnborg <sam@ravnborg.org>
 #
 # Released under the terms of the GNU GPL
 #
@@ -17,15 +17,15 @@
 Usage:
 $0 [-o <file>] [-u <uid>] [-g <gid>] {-d | <cpio_source>} ...
 	-o <file>      Create gzipped initramfs file named <file> using
-	               gen_init_cpio and gzip
+		       gen_init_cpio and gzip
 	-u <uid>       User ID to map to user ID 0 (root).
-	               <uid> is only meaningful if <cpio_source>
-	               is a directory.
+		       <uid> is only meaningful if <cpio_source>
+		       is a directory.
 	-g <gid>       Group ID to map to group ID 0 (root).
-	               <gid> is only meaningful if <cpio_source>
-	               is a directory.
+		       <gid> is only meaningful if <cpio_source>
+		       is a directory.
 	<cpio_source>  File list or directory for cpio archive.
-	               If <cpio_source> is a .cpio file it will be used
+		       If <cpio_source> is a .cpio file it will be used
 		       as direct input to initramfs.
 	-d             Output the default cpio list.
 
@@ -36,6 +36,12 @@
 EOF
 }
 
+# awk style field access
+# $1 - field number; rest is argument string
+field() {
+	shift $1 ; echo $1
+}
+
 list_default_initramfs() {
 	# echo usr/kinit/kinit
 	:
@@ -119,22 +125,17 @@
 			str="${ftype} ${name} ${location} ${str}"
 			;;
 		"nod")
-			local dev_type=
-			local maj=$(LC_ALL=C ls -l "${location}" | \
-					gawk '{sub(/,/, "", $5); print $5}')
-			local min=$(LC_ALL=C ls -l "${location}" | \
-					gawk '{print $6}')
+			local dev=`LC_ALL=C ls -l "${location}"`
+			local maj=`field 5 ${dev}`
+			local min=`field 6 ${dev}`
+			maj=${maj%,}
 
-			if [ -b "${location}" ]; then
-				dev_type="b"
-			else
-				dev_type="c"
-			fi
-			str="${ftype} ${name} ${str} ${dev_type} ${maj} ${min}"
+			[ -b "${location}" ] && dev="b" || dev="c"
+
+			str="${ftype} ${name} ${str} ${dev} ${maj} ${min}"
 			;;
 		"slink")
-			local target=$(LC_ALL=C ls -l "${location}" | \
-					gawk '{print $11}')
+			local target=`field 11 $(LC_ALL=C ls -l "${location}")`
 			str="${ftype} ${name} ${target} ${str}"
 			;;
 		*)
diff --git a/scripts/makelst b/scripts/makelst
index 34bd723..4fc80f2 100755
--- a/scripts/makelst
+++ b/scripts/makelst
@@ -1,31 +1,31 @@
-#!/bin/bash
+#!/bin/sh
 # A script to dump mixed source code & assembly
 # with correct relocations from System.map
-# Requires the following lines in Rules.make.
-# Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) 
-#            William Stearns <wstearns@pobox.com>
+# Requires the following lines in makefile:
 #%.lst: %.c
 #	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $<
-#	$(TOPDIR)/scripts/makelst $*.o $(TOPDIR)/System.map $(OBJDUMP)
+#	$(srctree)/scripts/makelst $*.o $(objtree)/System.map $(OBJDUMP)
 #
-#    Copyright (C) 2000 IBM Corporation
-#    Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) 
+# Copyright (C) 2000 IBM Corporation
+# Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+#            William Stearns <wstearns@pobox.com>
 #
 
-t1=`$3 --syms $1 | grep .text | grep " F " | head -n 1`
+# awk style field access
+field() {
+  shift $1 ; echo $1
+}
+
+t1=`$3 --syms $1 | grep .text | grep -m1 " F "`
 if [ -n "$t1" ]; then
-  t2=`echo $t1 | gawk '{ print $6 }'`
+  t2=`field 6 $t1`
   if [ ! -r $2 ]; then
     echo "No System.map" >&2
-    t7=0
   else
     t3=`grep $t2 $2`
-    t4=`echo $t3 | gawk '{ print $1 }'`
-    t5=`echo $t1 | gawk '{ print $1 }'`
-    t6=`echo $t4 - $t5 | tr a-f A-F`
-    t7=`( echo  ibase=16 ; echo $t6 ) | bc`
+    t4=`field 1 $t3`
+    t5=`field 1 $t1`
+    t6=`printf "%lu" $((0x$t4 - 0x$t5))`
   fi
-else
-  t7=0
 fi
-$3 -r --source --adjust-vma=$t7 $1
+$3 -r --source --adjust-vma=${t6:-0} $1
diff --git a/security/keys/key.c b/security/keys/key.c
index ac9326c..700400d 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -188,6 +188,7 @@
 
 	spin_lock(&key_serial_lock);
 
+attempt_insertion:
 	parent = NULL;
 	p = &key_serial_tree.rb_node;
 
@@ -202,39 +203,33 @@
 		else
 			goto serial_exists;
 	}
-	goto insert_here;
+
+	/* we've found a suitable hole - arrange for this key to occupy it */
+	rb_link_node(&key->serial_node, parent, p);
+	rb_insert_color(&key->serial_node, &key_serial_tree);
+
+	spin_unlock(&key_serial_lock);
+	return;
 
 	/* we found a key with the proposed serial number - walk the tree from
 	 * that point looking for the next unused serial number */
 serial_exists:
 	for (;;) {
 		key->serial++;
-		if (key->serial < 2)
-			key->serial = 2;
-
-		if (!rb_parent(parent))
-			p = &key_serial_tree.rb_node;
-		else if (rb_parent(parent)->rb_left == parent)
-			p = &(rb_parent(parent)->rb_left);
-		else
-			p = &(rb_parent(parent)->rb_right);
+		if (key->serial < 3) {
+			key->serial = 3;
+			goto attempt_insertion;
+		}
 
 		parent = rb_next(parent);
 		if (!parent)
-			break;
+			goto attempt_insertion;
 
 		xkey = rb_entry(parent, struct key, serial_node);
 		if (key->serial < xkey->serial)
-			goto insert_here;
+			goto attempt_insertion;
 	}
 
-	/* we've found a suitable hole - arrange for this key to occupy it */
-insert_here:
-	rb_link_node(&key->serial_node, parent, p);
-	rb_insert_color(&key->serial_node, &key_serial_tree);
-
-	spin_unlock(&key_serial_lock);
-
 } /* end key_alloc_serial() */
 
 /*****************************************************************************/
diff --git a/sound/Kconfig b/sound/Kconfig
index 9d77300..97532bb 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -76,6 +76,8 @@
 
 source "sound/parisc/Kconfig"
 
+source "sound/soc/Kconfig"
+
 endmenu
 
 menu "Open Sound System"
diff --git a/sound/Makefile b/sound/Makefile
index 9aee54c..b7c7fb7 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -5,7 +5,7 @@
 obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o
 obj-$(CONFIG_SOUND_PRIME) += oss/
 obj-$(CONFIG_DMASOUND) += oss/
-obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/
+obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/
 obj-$(CONFIG_SND_AOA) += aoa/
 
 # This one must be compilable even if sound is configured out
diff --git a/sound/ac97_bus.c b/sound/ac97_bus.c
index 66de2c2..7fa37e1 100644
--- a/sound/ac97_bus.c
+++ b/sound/ac97_bus.c
@@ -26,6 +26,7 @@
 	return 1;
 }
 
+#ifdef CONFIG_PM
 static int ac97_bus_suspend(struct device *dev, pm_message_t state)
 {
 	int ret = 0;
@@ -45,12 +46,15 @@
 
 	return ret;
 }
+#endif /* CONFIG_PM */
 
 struct bus_type ac97_bus_type = {
 	.name		= "ac97",
 	.match		= ac97_bus_match,
+#ifdef CONFIG_PM
 	.suspend	= ac97_bus_suspend,
 	.resume		= ac97_bus_resume,
+#endif /* CONFIG_PM */
 };
 
 static int __init ac97_bus_init(void)
diff --git a/sound/aoa/aoa.h b/sound/aoa/aoa.h
index 378ef1e..541b908 100644
--- a/sound/aoa/aoa.h
+++ b/sound/aoa/aoa.h
@@ -99,7 +99,7 @@
  * that are not assigned yet are passed to the fabric
  * again for reconsideration. */
 extern int
-aoa_fabric_register(struct aoa_fabric *fabric);
+aoa_fabric_register(struct aoa_fabric *fabric, struct device *dev);
 
 /* it is vital to call this when the fabric exits!
  * When calling, the remove_codec will be called
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/snd-aoa-codec-onyx.c
index 0b76507..b00fc48 100644
--- a/sound/aoa/codecs/snd-aoa-codec-onyx.c
+++ b/sound/aoa/codecs/snd-aoa-codec-onyx.c
@@ -825,7 +825,16 @@
 	int err = -ENXIO;
 
 	mutex_lock(&onyx->mutex);
-	/* take codec out of suspend */
+
+	/* reset codec */
+	onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
+	msleep(1);
+	onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1);
+	msleep(1);
+	onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
+	msleep(1);
+
+	/* take codec out of suspend (if it still is after reset) */
 	if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
 		goto out_unlock;
 	onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV));
diff --git a/sound/aoa/core/snd-aoa-alsa.c b/sound/aoa/core/snd-aoa-alsa.c
index b42fdea..17fe689 100644
--- a/sound/aoa/core/snd-aoa-alsa.c
+++ b/sound/aoa/core/snd-aoa-alsa.c
@@ -14,7 +14,7 @@
 
 static struct aoa_card *aoa_card;
 
-int aoa_alsa_init(char *name, struct module *mod)
+int aoa_alsa_init(char *name, struct module *mod, struct device *dev)
 {
 	struct snd_card *alsa_card;
 	int err;
@@ -28,6 +28,7 @@
 		return -ENOMEM;
 	aoa_card = alsa_card->private_data;
 	aoa_card->alsa_card = alsa_card;
+	alsa_card->dev = dev;
 	strlcpy(alsa_card->driver, "AppleOnbdAudio", sizeof(alsa_card->driver));
 	strlcpy(alsa_card->shortname, name, sizeof(alsa_card->shortname));
 	strlcpy(alsa_card->longname, name, sizeof(alsa_card->longname));
@@ -59,7 +60,7 @@
 }
 
 int aoa_snd_device_new(snd_device_type_t type,
-        void * device_data, struct snd_device_ops * ops)
+		       void * device_data, struct snd_device_ops * ops)
 {
 	struct snd_card *card = aoa_get_card();
 	int err;
diff --git a/sound/aoa/core/snd-aoa-alsa.h b/sound/aoa/core/snd-aoa-alsa.h
index 660d2f1..9669e44 100644
--- a/sound/aoa/core/snd-aoa-alsa.h
+++ b/sound/aoa/core/snd-aoa-alsa.h
@@ -10,7 +10,7 @@
 #define __SND_AOA_ALSA_H
 #include "../aoa.h"
 
-extern int aoa_alsa_init(char *name, struct module *mod);
+extern int aoa_alsa_init(char *name, struct module *mod, struct device *dev);
 extern void aoa_alsa_cleanup(void);
 
 #endif /* __SND_AOA_ALSA_H */
diff --git a/sound/aoa/core/snd-aoa-core.c b/sound/aoa/core/snd-aoa-core.c
index ecd2d82..19fdae4 100644
--- a/sound/aoa/core/snd-aoa-core.c
+++ b/sound/aoa/core/snd-aoa-core.c
@@ -82,7 +82,7 @@
 }
 EXPORT_SYMBOL_GPL(aoa_codec_unregister);
 
-int aoa_fabric_register(struct aoa_fabric *new_fabric)
+int aoa_fabric_register(struct aoa_fabric *new_fabric, struct device *dev)
 {
 	struct aoa_codec *c;
 	int err;
@@ -98,7 +98,7 @@
 	if (!new_fabric)
 		return -EINVAL;
 
-	err = aoa_alsa_init(new_fabric->name, new_fabric->owner);
+	err = aoa_alsa_init(new_fabric->name, new_fabric->owner, dev);
 	if (err)
 		return err;
 
diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c
index 172eb95..1b94ba6 100644
--- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c
+++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c
@@ -1014,7 +1014,7 @@
 
 	ldev->gpio.methods->init(&ldev->gpio);
 
-	err = aoa_fabric_register(&layout_fabric);
+	err = aoa_fabric_register(&layout_fabric, &sdev->ofdev.dev);
 	if (err && err != -EALREADY) {
 		printk(KERN_INFO "snd-aoa-fabric-layout: can't use,"
 				 " another fabric is active!\n");
@@ -1034,9 +1034,9 @@
 	list_del(&ldev->list);
 	layouts_list_items--;
  outnodev:
- 	if (sound) of_node_put(sound);
+ 	of_node_put(sound);
  	layout_device = NULL;
- 	if (ldev) kfree(ldev);
+ 	kfree(ldev);
 	return -ENODEV;
 }
 
@@ -1077,8 +1077,6 @@
 {
 	struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
 
-	printk("aoa_fabric_layout_suspend()\n");
-
 	if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
 		ldev->gpio.methods->all_amps_off(&ldev->gpio);
 
@@ -1089,8 +1087,6 @@
 {
 	struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
 
-	printk("aoa_fabric_layout_resume()\n");
-
 	if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
 		ldev->gpio.methods->all_amps_restore(&ldev->gpio);
 
@@ -1107,6 +1103,9 @@
 	.suspend = aoa_fabric_layout_suspend,
 	.resume = aoa_fabric_layout_resume,
 #endif
+	.driver = {
+		.owner = THIS_MODULE,
+	}
 };
 
 static int __init aoa_fabric_layout_init(void)
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
index e593a13..e36f6aa 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c
+++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
@@ -41,8 +41,8 @@
 				       struct dbdma_command_mem *r,
 				       int numcmds)
 {
-	/* one more for rounding */
-	r->size = (numcmds+1) * sizeof(struct dbdma_cmd);
+	/* one more for rounding, one for branch back, one for stop command */
+	r->size = (numcmds + 3) * sizeof(struct dbdma_cmd);
 	/* We use the PCI APIs for now until the generic one gets fixed
 	 * enough or until we get some macio-specific versions
 	 */
@@ -377,11 +377,8 @@
 		if (i2sdev->sound.pcm) {
 			/* Suspend PCM streams */
 			snd_pcm_suspend_all(i2sdev->sound.pcm);
-			/* Probably useless as we handle
-			 * power transitions ourselves */
-			snd_power_change_state(i2sdev->sound.pcm->card,
-					       SNDRV_CTL_POWER_D3hot);
 		}
+
 		/* Notify codecs */
 		list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
 			err = 0;
@@ -390,7 +387,11 @@
 			if (err)
 				ret = err;
 		}
+
+		/* wait until streams are stopped */
+		i2sbus_wait_for_stop_both(i2sdev);
 	}
+
 	return ret;
 }
 
@@ -402,6 +403,9 @@
 	int err, ret = 0;
 
 	list_for_each_entry(i2sdev, &control->list, item) {
+		/* reset i2s bus format etc. */
+		i2sbus_pcm_prepare_both(i2sdev);
+
 		/* Notify codecs so they can re-initialize */
 		list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
 			err = 0;
@@ -410,12 +414,6 @@
 			if (err)
 				ret = err;
 		}
-		/* Notify Alsa */
-		if (i2sdev->sound.pcm) {
-			/* Same comment as above, probably useless */
-			snd_power_change_state(i2sdev->sound.pcm->card,
-					       SNDRV_CTL_POWER_D0);
-		}
 	}
 
 	return ret;
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
index 5eff30b..c6b42f9 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
+++ b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
@@ -125,7 +125,8 @@
 	}
 	/* bus dependent stuff */
 	hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-		   SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME;
+		   SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME |
+		   SNDRV_PCM_INFO_JOINT_DUPLEX;
 
 	CHECK_RATE(5512);
 	CHECK_RATE(8000);
@@ -245,18 +246,78 @@
 	return err;
 }
 
+static void i2sbus_wait_for_stop(struct i2sbus_dev *i2sdev,
+				 struct pcm_info *pi)
+{
+	unsigned long flags;
+	struct completion done;
+	long timeout;
+
+	spin_lock_irqsave(&i2sdev->low_lock, flags);
+	if (pi->dbdma_ring.stopping) {
+		init_completion(&done);
+		pi->stop_completion = &done;
+		spin_unlock_irqrestore(&i2sdev->low_lock, flags);
+		timeout = wait_for_completion_timeout(&done, HZ);
+		spin_lock_irqsave(&i2sdev->low_lock, flags);
+		pi->stop_completion = NULL;
+		if (timeout == 0) {
+			/* timeout expired, stop dbdma forcefully */
+			printk(KERN_ERR "i2sbus_wait_for_stop: timed out\n");
+			/* make sure RUN, PAUSE and S0 bits are cleared */
+			out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
+			pi->dbdma_ring.stopping = 0;
+			timeout = 10;
+			while (in_le32(&pi->dbdma->status) & ACTIVE) {
+				if (--timeout <= 0)
+					break;
+				udelay(1);
+			}
+		}
+	}
+	spin_unlock_irqrestore(&i2sdev->low_lock, flags);
+}
+
+#ifdef CONFIG_PM
+void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev)
+{
+	struct pcm_info *pi;
+
+	get_pcm_info(i2sdev, 0, &pi, NULL);
+	i2sbus_wait_for_stop(i2sdev, pi);
+	get_pcm_info(i2sdev, 1, &pi, NULL);
+	i2sbus_wait_for_stop(i2sdev, pi);
+}
+#endif
+
 static int i2sbus_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params)
 {
 	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
 }
 
-static int i2sbus_hw_free(struct snd_pcm_substream *substream)
+static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
 {
+	struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+	struct pcm_info *pi;
+
+	get_pcm_info(i2sdev, in, &pi, NULL);
+	if (pi->dbdma_ring.stopping)
+		i2sbus_wait_for_stop(i2sdev, pi);
 	snd_pcm_lib_free_pages(substream);
 	return 0;
 }
 
+static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream)
+{
+	return i2sbus_hw_free(substream, 0);
+}
+
+static int i2sbus_record_hw_free(struct snd_pcm_substream *substream)
+{
+	return i2sbus_hw_free(substream, 1);
+}
+
 static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
 {
 	/* whee. Hard work now. The user has selected a bitrate
@@ -264,7 +325,7 @@
 	 * I2S controller appropriately. */
 	struct snd_pcm_runtime *runtime;
 	struct dbdma_cmd *command;
-	int i, periodsize;
+	int i, periodsize, nperiods;
 	dma_addr_t offset;
 	struct bus_info bi;
 	struct codec_info_item *cii;
@@ -274,6 +335,7 @@
 	struct pcm_info *pi, *other;
 	int cnt;
 	int result = 0;
+	unsigned int cmd, stopaddr;
 
 	mutex_lock(&i2sdev->lock);
 
@@ -283,6 +345,13 @@
 		result = -EBUSY;
 		goto out_unlock;
 	}
+	if (pi->dbdma_ring.stopping)
+		i2sbus_wait_for_stop(i2sdev, pi);
+
+	if (!pi->substream || !pi->substream->runtime) {
+		result = -EINVAL;
+		goto out_unlock;
+	}
 
 	runtime = pi->substream->runtime;
 	pi->active = 1;
@@ -297,24 +366,43 @@
 	i2sdev->rate = runtime->rate;
 
 	periodsize = snd_pcm_lib_period_bytes(pi->substream);
+	nperiods = pi->substream->runtime->periods;
 	pi->current_period = 0;
 
 	/* generate dbdma command ring first */
 	command = pi->dbdma_ring.cmds;
+	memset(command, 0, (nperiods + 2) * sizeof(struct dbdma_cmd));
+
+	/* commands to DMA to/from the ring */
+	/*
+	 * For input, we need to do a graceful stop; if we abort
+	 * the DMA, we end up with leftover bytes that corrupt
+	 * the next recording.  To do this we set the S0 status
+	 * bit and wait for the DMA controller to stop.  Each
+	 * command has a branch condition to
+	 * make it branch to a stop command if S0 is set.
+	 * On input we also need to wait for the S7 bit to be
+	 * set before turning off the DMA controller.
+	 * In fact we do the graceful stop for output as well.
+	 */
 	offset = runtime->dma_addr;
-	for (i = 0; i < pi->substream->runtime->periods;
-	     i++, command++, offset += periodsize) {
-		memset(command, 0, sizeof(struct dbdma_cmd));
-		command->command =
-		    cpu_to_le16((in ? INPUT_MORE : OUTPUT_MORE) | INTR_ALWAYS);
+	cmd = (in? INPUT_MORE: OUTPUT_MORE) | BR_IFSET | INTR_ALWAYS;
+	stopaddr = pi->dbdma_ring.bus_cmd_start +
+		(nperiods + 1) * sizeof(struct dbdma_cmd);
+	for (i = 0; i < nperiods; i++, command++, offset += periodsize) {
+		command->command = cpu_to_le16(cmd);
+		command->cmd_dep = cpu_to_le32(stopaddr);
 		command->phy_addr = cpu_to_le32(offset);
 		command->req_count = cpu_to_le16(periodsize);
-		command->xfer_status = cpu_to_le16(0);
 	}
-	/* last one branches back to first */
-	command--;
-	command->command |= cpu_to_le16(BR_ALWAYS);
+
+	/* branch back to beginning of ring */
+	command->command = cpu_to_le16(DBDMA_NOP | BR_ALWAYS);
 	command->cmd_dep = cpu_to_le32(pi->dbdma_ring.bus_cmd_start);
+	command++;
+
+	/* set stop command */
+	command->command = cpu_to_le16(DBDMA_STOP);
 
 	/* ok, let's set the serial format and stuff */
 	switch (runtime->format) {
@@ -435,16 +523,18 @@
 	return result;
 }
 
-static struct dbdma_cmd STOP_CMD = {
-	.command = __constant_cpu_to_le16(DBDMA_STOP),
-};
+#ifdef CONFIG_PM
+void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev)
+{
+	i2sbus_pcm_prepare(i2sdev, 0);
+	i2sbus_pcm_prepare(i2sdev, 1);
+}
+#endif
 
 static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd)
 {
 	struct codec_info_item *cii;
 	struct pcm_info *pi;
-	int timeout;
-	struct dbdma_cmd tmp;
 	int result = 0;
 	unsigned long flags;
 
@@ -464,92 +554,50 @@
 				cii->codec->start(cii, pi->substream);
 		pi->dbdma_ring.running = 1;
 
-		/* reset dma engine */
-		out_le32(&pi->dbdma->control,
-			 0 | (RUN | PAUSE | FLUSH | WAKE) << 16);
-		timeout = 100;
-		while (in_le32(&pi->dbdma->status) & RUN && timeout--)
-			udelay(1);
-		if (timeout <= 0) {
-			printk(KERN_ERR
-			       "i2sbus: error waiting for dma reset\n");
-			result = -ENXIO;
-			goto out_unlock;
+		if (pi->dbdma_ring.stopping) {
+			/* Clear the S0 bit, then see if we stopped yet */
+			out_le32(&pi->dbdma->control, 1 << 16);
+			if (in_le32(&pi->dbdma->status) & ACTIVE) {
+				/* possible race here? */
+				udelay(10);
+				if (in_le32(&pi->dbdma->status) & ACTIVE) {
+					pi->dbdma_ring.stopping = 0;
+					goto out_unlock; /* keep running */
+				}
+			}
 		}
 
+		/* make sure RUN, PAUSE and S0 bits are cleared */
+		out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
+
+		/* set branch condition select register */
+		out_le32(&pi->dbdma->br_sel, (1 << 16) | 1);
+
 		/* write dma command buffer address to the dbdma chip */
 		out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start);
-		/* post PCI write */
-		mb();
-		(void)in_le32(&pi->dbdma->status);
 
-		/* change first command to STOP */
-		tmp = *pi->dbdma_ring.cmds;
-		*pi->dbdma_ring.cmds = STOP_CMD;
-
-		/* set running state, remember that the first command is STOP */
-		out_le32(&pi->dbdma->control, RUN | (RUN << 16));
-		timeout = 100;
-		/* wait for STOP to be executed */
-		while (in_le32(&pi->dbdma->status) & ACTIVE && timeout--)
-			udelay(1);
-		if (timeout <= 0) {
-			printk(KERN_ERR "i2sbus: error waiting for dma stop\n");
-			result = -ENXIO;
-			goto out_unlock;
-		}
-		/* again, write dma command buffer address to the dbdma chip,
-		 * this time of the first real command */
-		*pi->dbdma_ring.cmds = tmp;
-		out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start);
-		/* post write */
-		mb();
-		(void)in_le32(&pi->dbdma->status);
-
-		/* reset dma engine again */
-		out_le32(&pi->dbdma->control,
-			 0 | (RUN | PAUSE | FLUSH | WAKE) << 16);
-		timeout = 100;
-		while (in_le32(&pi->dbdma->status) & RUN && timeout--)
-			udelay(1);
-		if (timeout <= 0) {
-			printk(KERN_ERR
-			       "i2sbus: error waiting for dma reset\n");
-			result = -ENXIO;
-			goto out_unlock;
-		}
-
-		/* wake up the chip with the next descriptor */
-		out_le32(&pi->dbdma->control,
-			 (RUN | WAKE) | ((RUN | WAKE) << 16));
-		/* get the frame count  */
+		/* initialize the frame count and current period */
+		pi->current_period = 0;
 		pi->frame_count = in_le32(&i2sdev->intfregs->frame_count);
 
+		/* set the DMA controller running */
+		out_le32(&pi->dbdma->control, (RUN << 16) | RUN);
+
 		/* off you go! */
 		break;
+
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 		if (!pi->dbdma_ring.running) {
 			result = -EALREADY;
 			goto out_unlock;
 		}
-
-		/* turn off all relevant bits */
-		out_le32(&pi->dbdma->control,
-			 (RUN | WAKE | FLUSH | PAUSE) << 16);
-		{
-			/* FIXME: move to own function */
-			int timeout = 5000;
-			while ((in_le32(&pi->dbdma->status) & RUN)
-			       && --timeout > 0)
-				udelay(1);
-			if (!timeout)
-				printk(KERN_ERR
-				       "i2sbus: timed out turning "
-				       "off dbdma engine!\n");
-		}
-
 		pi->dbdma_ring.running = 0;
+
+		/* Set the S0 bit to make the DMA branch to the stop cmd */
+		out_le32(&pi->dbdma->control, (1 << 16) | 1);
+		pi->dbdma_ring.stopping = 1;
+
 		list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
 			if (cii->codec->stop)
 				cii->codec->stop(cii, pi->substream);
@@ -574,70 +622,82 @@
 	fc = in_le32(&i2sdev->intfregs->frame_count);
 	fc = fc - pi->frame_count;
 
-	return (bytes_to_frames(pi->substream->runtime,
-			pi->current_period *
-			snd_pcm_lib_period_bytes(pi->substream))
-		+ fc) % pi->substream->runtime->buffer_size;
+	if (fc >= pi->substream->runtime->buffer_size)
+		fc %= pi->substream->runtime->buffer_size;
+	return fc;
 }
 
 static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in)
 {
 	struct pcm_info *pi;
-	u32 fc;
-	u32 delta;
+	u32 fc, nframes;
+	u32 status;
+	int timeout, i;
+	int dma_stopped = 0;
+	struct snd_pcm_runtime *runtime;
 
 	spin_lock(&i2sdev->low_lock);
 	get_pcm_info(i2sdev, in, &pi, NULL);
-
-	if (!pi->dbdma_ring.running) {
-		/* there was still an interrupt pending
-		 * while we stopped. or maybe another
-		 * processor (not the one that was stopping
-		 * the DMA engine) was spinning above
-		 * waiting for the lock. */
+	if (!pi->dbdma_ring.running && !pi->dbdma_ring.stopping)
 		goto out_unlock;
-	}
 
-	fc = in_le32(&i2sdev->intfregs->frame_count);
-	/* a counter overflow does not change the calculation. */
-	delta = fc - pi->frame_count;
+	i = pi->current_period;
+	runtime = pi->substream->runtime;
+	while (pi->dbdma_ring.cmds[i].xfer_status) {
+		if (le16_to_cpu(pi->dbdma_ring.cmds[i].xfer_status) & BT)
+			/*
+			 * BT is the branch taken bit.  If it took a branch
+			 * it is because we set the S0 bit to make it
+			 * branch to the stop command.
+			 */
+			dma_stopped = 1;
+		pi->dbdma_ring.cmds[i].xfer_status = 0;
 
-	/* update current_period */
-	while (delta >= pi->substream->runtime->period_size) {
-		pi->current_period++;
-		delta = delta - pi->substream->runtime->period_size;
-	}
-
-	if (unlikely(delta)) {
-		/* Some interrupt came late, so check the dbdma.
-		 * This special case exists to syncronize the frame_count with
-		 * the dbdma transfer, but is hit every once in a while. */
-		int period;
-
-		period = (in_le32(&pi->dbdma->cmdptr)
-		        - pi->dbdma_ring.bus_cmd_start)
-				/ sizeof(struct dbdma_cmd);
-		pi->current_period = pi->current_period
-					% pi->substream->runtime->periods;
-
-		while (pi->current_period != period) {
-			pi->current_period++;
-			pi->current_period %= pi->substream->runtime->periods;
-			/* Set delta to zero, as the frame_count value is too
-			 * high (otherwise the code path will not be executed).
-			 * This corrects the fact that the frame_count is too
-			 * low at the beginning due to buffering. */
-			delta = 0;
+		if (++i >= runtime->periods) {
+			i = 0;
+			pi->frame_count += runtime->buffer_size;
 		}
+		pi->current_period = i;
+
+		/*
+		 * Check the frame count.  The DMA tends to get a bit
+		 * ahead of the frame counter, which confuses the core.
+		 */
+		fc = in_le32(&i2sdev->intfregs->frame_count);
+		nframes = i * runtime->period_size;
+		if (fc < pi->frame_count + nframes)
+			pi->frame_count = fc - nframes;
 	}
 
-	pi->frame_count = fc - delta;
-	pi->current_period %= pi->substream->runtime->periods;
+	if (dma_stopped) {
+		timeout = 1000;
+		for (;;) {
+			status = in_le32(&pi->dbdma->status);
+			if (!(status & ACTIVE) && (!in || (status & 0x80)))
+				break;
+			if (--timeout <= 0) {
+				printk(KERN_ERR "i2sbus: timed out "
+				       "waiting for DMA to stop!\n");
+				break;
+			}
+			udelay(1);
+		}
 
+		/* Turn off DMA controller, clear S0 bit */
+		out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
+
+		pi->dbdma_ring.stopping = 0;
+		if (pi->stop_completion)
+			complete(pi->stop_completion);
+	}
+
+	if (!pi->dbdma_ring.running)
+		goto out_unlock;
 	spin_unlock(&i2sdev->low_lock);
 	/* may call _trigger again, hence needs to be unlocked */
 	snd_pcm_period_elapsed(pi->substream);
 	return;
+
  out_unlock:
 	spin_unlock(&i2sdev->low_lock);
 }
@@ -718,7 +778,7 @@
 	.close =	i2sbus_playback_close,
 	.ioctl =	snd_pcm_lib_ioctl,
 	.hw_params =	i2sbus_hw_params,
-	.hw_free =	i2sbus_hw_free,
+	.hw_free =	i2sbus_playback_hw_free,
 	.prepare =	i2sbus_playback_prepare,
 	.trigger =	i2sbus_playback_trigger,
 	.pointer =	i2sbus_playback_pointer,
@@ -788,7 +848,7 @@
 	.close =	i2sbus_record_close,
 	.ioctl =	snd_pcm_lib_ioctl,
 	.hw_params =	i2sbus_hw_params,
-	.hw_free =	i2sbus_hw_free,
+	.hw_free =	i2sbus_record_hw_free,
 	.prepare =	i2sbus_record_prepare,
 	.trigger =	i2sbus_record_trigger,
 	.pointer =	i2sbus_record_pointer,
@@ -812,7 +872,6 @@
 	module_put(THIS_MODULE);
 }
 
-/* FIXME: this function needs an error handling strategy with labels */
 int
 i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
 		    struct codec_info *ci, void *data)
@@ -880,41 +939,31 @@
 	if (!cii->sdev) {
 		printk(KERN_DEBUG
 		       "i2sbus: failed to get soundbus dev reference\n");
-		kfree(cii);
-		return -ENODEV;
+		err = -ENODEV;
+		goto out_free_cii;
 	}
 
 	if (!try_module_get(THIS_MODULE)) {
 		printk(KERN_DEBUG "i2sbus: failed to get module reference!\n");
-		soundbus_dev_put(dev);
-		kfree(cii);
-		return -EBUSY;
+		err = -EBUSY;
+		goto out_put_sdev;
 	}
 
 	if (!try_module_get(ci->owner)) {
 		printk(KERN_DEBUG
 		       "i2sbus: failed to get module reference to codec owner!\n");
-		module_put(THIS_MODULE);
-		soundbus_dev_put(dev);
-		kfree(cii);
-		return -EBUSY;
+		err = -EBUSY;
+		goto out_put_this_module;
 	}
 
 	if (!dev->pcm) {
-		err = snd_pcm_new(card,
-				  dev->pcmname,
-				  dev->pcmid,
-				  0,
-				  0,
+		err = snd_pcm_new(card, dev->pcmname, dev->pcmid, 0, 0,
 				  &dev->pcm);
 		if (err) {
 			printk(KERN_DEBUG "i2sbus: failed to create pcm\n");
-			kfree(cii);
-			module_put(ci->owner);
-			soundbus_dev_put(dev);
-			module_put(THIS_MODULE);
-			return err;
+			goto out_put_ci_module;
 		}
+		dev->pcm->dev = &dev->ofdev.dev;
 	}
 
 	/* ALSA yet again sucks.
@@ -926,20 +975,12 @@
 			/* eh? */
 			printk(KERN_ERR
 			       "Can't attach same bus to different cards!\n");
-			module_put(ci->owner);
-			kfree(cii);
-			soundbus_dev_put(dev);
-			module_put(THIS_MODULE);
-			return -EINVAL;
+			err = -EINVAL;
+			goto out_put_ci_module;
 		}
-		if ((err =
-		     snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1))) {
-			module_put(ci->owner);
-			kfree(cii);
-			soundbus_dev_put(dev);
-			module_put(THIS_MODULE);
-			return err;
-		}
+		err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1);
+		if (err)
+			goto out_put_ci_module;
 		snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
 				&i2sbus_playback_ops);
 		i2sdev->out.created = 1;
@@ -949,20 +990,11 @@
 		if (dev->pcm->card != card) {
 			printk(KERN_ERR
 			       "Can't attach same bus to different cards!\n");
-			module_put(ci->owner);
-			kfree(cii);
-			soundbus_dev_put(dev);
-			module_put(THIS_MODULE);
-			return -EINVAL;
+			goto out_put_ci_module;
 		}
-		if ((err =
-		     snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1))) {
-			module_put(ci->owner);
-			kfree(cii);
-			soundbus_dev_put(dev);
-			module_put(THIS_MODULE);
-			return err;
-		}
+		err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1);
+		if (err)
+			goto out_put_ci_module;
 		snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE,
 				&i2sbus_record_ops);
 		i2sdev->in.created = 1;
@@ -977,11 +1009,7 @@
 	err = snd_device_register(card, dev->pcm);
 	if (err) {
 		printk(KERN_ERR "i2sbus: error registering new pcm\n");
-		module_put(ci->owner);
-		kfree(cii);
-		soundbus_dev_put(dev);
-		module_put(THIS_MODULE);
-		return err;
+		goto out_put_ci_module;
 	}
 	/* no errors any more, so let's add this to our list */
 	list_add(&cii->list, &dev->codec_list);
@@ -996,6 +1024,15 @@
 		64 * 1024, 64 * 1024);
 
 	return 0;
+ out_put_ci_module:
+	module_put(ci->owner);
+ out_put_this_module:
+	module_put(THIS_MODULE);
+ out_put_sdev:
+	soundbus_dev_put(dev);
+ out_free_cii:
+	kfree(cii);
+	return err;
 }
 
 void i2sbus_detach_codec(struct soundbus_dev *dev, void *data)
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h
index ec20ee6..ff29654 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus.h
+++ b/sound/aoa/soundbus/i2sbus/i2sbus.h
@@ -10,6 +10,7 @@
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
+#include <linux/completion.h>
 
 #include <sound/pcm.h>
 
@@ -34,6 +35,7 @@
 	void *space;
 	int size;
 	u32 running:1;
+	u32 stopping:1;
 };
 
 struct pcm_info {
@@ -45,6 +47,7 @@
 	u32 frame_count;
 	struct dbdma_command_mem dbdma_ring;
 	volatile struct dbdma_regs __iomem *dbdma;
+	struct completion *stop_completion;
 };
 
 enum {
@@ -101,6 +104,9 @@
 extern irqreturn_t
 i2sbus_rx_intr(int irq, void *devid);
 
+extern void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev);
+extern void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev);
+
 /* control specific functions */
 extern int i2sbus_control_init(struct macio_dev* dev,
 			       struct i2sbus_control **c);
diff --git a/sound/arm/aaci.h b/sound/arm/aaci.h
index 0629519..9175ff9 100644
--- a/sound/arm/aaci.h
+++ b/sound/arm/aaci.h
@@ -228,7 +228,7 @@
 
 	/* AC'97 */
 	struct mutex		ac97_sem;
-	ac97_bus_t		*ac97_bus;
+	struct snd_ac97_bus	*ac97_bus;
 
 	u32			maincr;
 	spinlock_t		lock;
diff --git a/sound/core/control.c b/sound/core/control.c
index 0c7bcd6..42bcf27 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -108,7 +108,6 @@
 static int snd_ctl_release(struct inode *inode, struct file *file)
 {
 	unsigned long flags;
-	struct list_head *list;
 	struct snd_card *card;
 	struct snd_ctl_file *ctl;
 	struct snd_kcontrol *control;
@@ -122,12 +121,10 @@
 	list_del(&ctl->list);
 	write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
 	down_write(&card->controls_rwsem);
-	list_for_each(list, &card->controls) {
-		control = snd_kcontrol(list);
+	list_for_each_entry(control, &card->controls, list)
 		for (idx = 0; idx < control->count; idx++)
 			if (control->vd[idx].owner == ctl)
 				control->vd[idx].owner = NULL;
-	}
 	up_write(&card->controls_rwsem);
 	snd_ctl_empty_read_queue(ctl);
 	kfree(ctl);
@@ -140,7 +137,6 @@
 		    struct snd_ctl_elem_id *id)
 {
 	unsigned long flags;
-	struct list_head *flist;
 	struct snd_ctl_file *ctl;
 	struct snd_kctl_event *ev;
 	
@@ -149,14 +145,11 @@
 #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
 	card->mixer_oss_change_count++;
 #endif
-	list_for_each(flist, &card->ctl_files) {
-		struct list_head *elist;
-		ctl = snd_ctl_file(flist);
+	list_for_each_entry(ctl, &card->ctl_files, list) {
 		if (!ctl->subscribed)
 			continue;
 		spin_lock_irqsave(&ctl->read_lock, flags);
-		list_for_each(elist, &ctl->events) {
-			ev = snd_kctl_event(elist);
+		list_for_each_entry(ev, &ctl->events, list) {
 			if (ev->id.numid == id->numid) {
 				ev->mask |= mask;
 				goto _found;
@@ -190,7 +183,8 @@
  *
  * Returns the pointer of the new instance, or NULL on failure.
  */
-struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, unsigned int access)
+static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
+					unsigned int access)
 {
 	struct snd_kcontrol *kctl;
 	unsigned int idx;
@@ -208,8 +202,6 @@
 	return kctl;
 }
 
-EXPORT_SYMBOL(snd_ctl_new);
-
 /**
  * snd_ctl_new1 - create a control instance from the template
  * @ncontrol: the initialization record
@@ -277,11 +269,9 @@
 static unsigned int snd_ctl_hole_check(struct snd_card *card,
 				       unsigned int count)
 {
-	struct list_head *list;
 	struct snd_kcontrol *kctl;
 
-	list_for_each(list, &card->controls) {
-		kctl = snd_kcontrol(list);
+	list_for_each_entry(kctl, &card->controls, list) {
 		if ((kctl->id.numid <= card->last_numid &&
 		     kctl->id.numid + kctl->count > card->last_numid) ||
 		    (kctl->id.numid <= card->last_numid + count - 1 &&
@@ -498,12 +488,10 @@
  */
 struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid)
 {
-	struct list_head *list;
 	struct snd_kcontrol *kctl;
 
 	snd_assert(card != NULL && numid != 0, return NULL);
-	list_for_each(list, &card->controls) {
-		kctl = snd_kcontrol(list);
+	list_for_each_entry(kctl, &card->controls, list) {
 		if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid)
 			return kctl;
 	}
@@ -527,14 +515,12 @@
 struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
 				     struct snd_ctl_elem_id *id)
 {
-	struct list_head *list;
 	struct snd_kcontrol *kctl;
 
 	snd_assert(card != NULL && id != NULL, return NULL);
 	if (id->numid != 0)
 		return snd_ctl_find_numid(card, id->numid);
-	list_for_each(list, &card->controls) {
-		kctl = snd_kcontrol(list);
+	list_for_each_entry(kctl, &card->controls, list) {
 		if (kctl->id.iface != id->iface)
 			continue;
 		if (kctl->id.device != id->device)
@@ -1182,7 +1168,6 @@
 {
 	struct snd_ctl_file *ctl;
 	struct snd_card *card;
-	struct list_head *list;
 	struct snd_kctl_ioctl *p;
 	void __user *argp = (void __user *)arg;
 	int __user *ip = argp;
@@ -1232,8 +1217,7 @@
 #endif
 	}
 	down_read(&snd_ioctl_rwsem);
-	list_for_each(list, &snd_control_ioctls) {
-		p = list_entry(list, struct snd_kctl_ioctl, list);
+	list_for_each_entry(p, &snd_control_ioctls, list) {
 		err = p->fioctl(card, ctl, cmd, arg);
 		if (err != -ENOIOCTLCMD) {
 			up_read(&snd_ioctl_rwsem);
@@ -1357,13 +1341,11 @@
 static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn,
 				     struct list_head *lists)
 {
-	struct list_head *list;
 	struct snd_kctl_ioctl *p;
 
 	snd_assert(fcn != NULL, return -EINVAL);
 	down_write(&snd_ioctl_rwsem);
-	list_for_each(list, lists) {
-		p = list_entry(list, struct snd_kctl_ioctl, list);
+	list_for_each_entry(p, lists, list) {
 		if (p->fioctl == fcn) {
 			list_del(&p->list);
 			up_write(&snd_ioctl_rwsem);
@@ -1453,7 +1435,6 @@
 static int snd_ctl_dev_disconnect(struct snd_device *device)
 {
 	struct snd_card *card = device->device_data;
-	struct list_head *flist;
 	struct snd_ctl_file *ctl;
 	int err, cardnum;
 
@@ -1462,8 +1443,7 @@
 	snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
 
 	down_read(&card->controls_rwsem);
-	list_for_each(flist, &card->ctl_files) {
-		ctl = snd_ctl_file(flist);
+	list_for_each_entry(ctl, &card->ctl_files, list) {
 		wake_up(&ctl->change_sleep);
 		kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
 	}
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index ab48962..9311ca3 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -392,7 +392,7 @@
 static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	struct snd_ctl_file *ctl;
-	struct list_head *list;
+	struct snd_kctl_ioctl *p;
 	void __user *argp = compat_ptr(arg);
 	int err;
 
@@ -427,8 +427,7 @@
 	}
 
 	down_read(&snd_ioctl_rwsem);
-	list_for_each(list, &snd_control_compat_ioctls) {
-		struct snd_kctl_ioctl *p = list_entry(list, struct snd_kctl_ioctl, list);
+	list_for_each_entry(p, &snd_control_compat_ioctls, list) {
 		if (p->fioctl) {
 			err = p->fioctl(ctl->card, ctl, cmd, arg);
 			if (err != -ENOIOCTLCMD) {
diff --git a/sound/core/device.c b/sound/core/device.c
index ccb2581..5858b02 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -79,13 +79,11 @@
  */
 int snd_device_free(struct snd_card *card, void *device_data)
 {
-	struct list_head *list;
 	struct snd_device *dev;
 	
 	snd_assert(card != NULL, return -ENXIO);
 	snd_assert(device_data != NULL, return -ENXIO);
-	list_for_each(list, &card->devices) {
-		dev = snd_device(list);
+	list_for_each_entry(dev, &card->devices, list) {
 		if (dev->device_data != device_data)
 			continue;
 		/* unlink */
@@ -124,13 +122,11 @@
  */
 int snd_device_disconnect(struct snd_card *card, void *device_data)
 {
-	struct list_head *list;
 	struct snd_device *dev;
 
 	snd_assert(card != NULL, return -ENXIO);
 	snd_assert(device_data != NULL, return -ENXIO);
-	list_for_each(list, &card->devices) {
-		dev = snd_device(list);
+	list_for_each_entry(dev, &card->devices, list) {
 		if (dev->device_data != device_data)
 			continue;
 		if (dev->state == SNDRV_DEV_REGISTERED &&
@@ -161,14 +157,12 @@
  */
 int snd_device_register(struct snd_card *card, void *device_data)
 {
-	struct list_head *list;
 	struct snd_device *dev;
 	int err;
 
 	snd_assert(card != NULL, return -ENXIO);
 	snd_assert(device_data != NULL, return -ENXIO);
-	list_for_each(list, &card->devices) {
-		dev = snd_device(list);
+	list_for_each_entry(dev, &card->devices, list) {
 		if (dev->device_data != device_data)
 			continue;
 		if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
@@ -192,13 +186,11 @@
  */
 int snd_device_register_all(struct snd_card *card)
 {
-	struct list_head *list;
 	struct snd_device *dev;
 	int err;
 	
 	snd_assert(card != NULL, return -ENXIO);
-	list_for_each(list, &card->devices) {
-		dev = snd_device(list);
+	list_for_each_entry(dev, &card->devices, list) {
 		if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
 			if ((err = dev->ops->dev_register(dev)) < 0)
 				return err;
@@ -215,12 +207,10 @@
 int snd_device_disconnect_all(struct snd_card *card)
 {
 	struct snd_device *dev;
-	struct list_head *list;
 	int err = 0;
 
 	snd_assert(card != NULL, return -ENXIO);
-	list_for_each(list, &card->devices) {
-		dev = snd_device(list);
+	list_for_each_entry(dev, &card->devices, list) {
 		if (snd_device_disconnect(card, dev->device_data) < 0)
 			err = -ENXIO;
 	}
@@ -234,7 +224,6 @@
 int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd)
 {
 	struct snd_device *dev;
-	struct list_head *list;
 	int err;
 	unsigned int range_low, range_high;
 
@@ -242,8 +231,7 @@
 	range_low = cmd * SNDRV_DEV_TYPE_RANGE_SIZE;
 	range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1;
       __again:
-	list_for_each(list, &card->devices) {
-		dev = snd_device(list);		
+	list_for_each_entry(dev, &card->devices, list) {
 		if (dev->type >= range_low && dev->type <= range_high) {
 			if ((err = snd_device_free(card, dev->device_data)) < 0)
 				return err;
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 46b4768..39c03f3 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -47,14 +47,11 @@
 
 static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device)
 {
-	struct list_head *p;
 	struct snd_hwdep *hwdep;
 
-	list_for_each(p, &snd_hwdep_devices) {
-		hwdep = list_entry(p, struct snd_hwdep, list);
+	list_for_each_entry(hwdep, &snd_hwdep_devices, list)
 		if (hwdep->card == card && hwdep->device == device)
 			return hwdep;
-	}
 	return NULL;
 }
 
@@ -159,15 +156,16 @@
 	int err = -ENXIO;
 	struct snd_hwdep *hw = file->private_data;
 	struct module *mod = hw->card->module;
+
 	mutex_lock(&hw->open_mutex);
-	if (hw->ops.release) {
+	if (hw->ops.release)
 		err = hw->ops.release(hw, file);
-		wake_up(&hw->open_wait);
-	}
 	if (hw->used > 0)
 		hw->used--;
-	snd_card_file_remove(hw->card, file);
 	mutex_unlock(&hw->open_mutex);
+	wake_up(&hw->open_wait);
+
+	snd_card_file_remove(hw->card, file);
 	module_put(mod);
 	return err;
 }
@@ -468,15 +466,12 @@
 static void snd_hwdep_proc_read(struct snd_info_entry *entry,
 				struct snd_info_buffer *buffer)
 {
-	struct list_head *p;
 	struct snd_hwdep *hwdep;
 
 	mutex_lock(&register_mutex);
-	list_for_each(p, &snd_hwdep_devices) {
-		hwdep = list_entry(p, struct snd_hwdep, list);
+	list_for_each_entry(hwdep, &snd_hwdep_devices, list)
 		snd_iprintf(buffer, "%02i-%02i: %s\n",
 			    hwdep->card->number, hwdep->device, hwdep->name);
-	}
 	mutex_unlock(&register_mutex);
 }
 
diff --git a/sound/core/init.c b/sound/core/init.c
index a4cc6b1..db61037 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -114,22 +114,28 @@
 	if (idx < 0) {
 		int idx2;
 		for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
+			/* idx == -1 == 0xffff means: take any free slot */
 			if (~snd_cards_lock & idx & 1<<idx2) {
 				idx = idx2;
 				if (idx >= snd_ecards_limit)
 					snd_ecards_limit = idx + 1;
 				break;
 			}
-	} else if (idx < snd_ecards_limit) {
-		if (snd_cards_lock & (1 << idx))
-			err = -ENODEV;	/* invalid */
-	} else if (idx < SNDRV_CARDS)
-		snd_ecards_limit = idx + 1; /* increase the limit */
-	else
-		err = -ENODEV;
+	} else {
+		 if (idx < snd_ecards_limit) {
+			if (snd_cards_lock & (1 << idx))
+				err = -EBUSY;	/* invalid */
+		} else {
+			if (idx < SNDRV_CARDS)
+				snd_ecards_limit = idx + 1; /* increase the limit */
+			else
+				err = -ENODEV;
+		}
+	}
 	if (idx < 0 || err < 0) {
 		mutex_unlock(&snd_card_mutex);
-		snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i)\n", idx, snd_ecards_limit - 1);
+		snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n",
+			 idx, snd_ecards_limit - 1, err);
 		goto __error;
 	}
 	snd_cards_lock |= 1 << idx;		/* lock it */
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index bc0bd09..f057430 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -406,19 +406,17 @@
  */
 size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id)
 {
-	struct list_head *p;
 	struct snd_mem_list *mem;
 
 	snd_assert(dmab, return 0);
 
 	mutex_lock(&list_mutex);
-	list_for_each(p, &mem_list_head) {
-		mem = list_entry(p, struct snd_mem_list, list);
+	list_for_each_entry(mem, &mem_list_head, list) {
 		if (mem->id == id &&
 		    (mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL ||
 		     ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) {
 			struct device *dev = dmab->dev.dev;
-			list_del(p);
+			list_del(&mem->list);
 			*dmab = mem->buffer;
 			if (dmab->dev.dev == NULL)
 				dmab->dev.dev = dev;
@@ -488,7 +486,6 @@
 {
 	int len = 0;
 	long pages = snd_allocated_pages >> (PAGE_SHIFT-12);
-	struct list_head *p;
 	struct snd_mem_list *mem;
 	int devno;
 	static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" };
@@ -498,8 +495,7 @@
 			"pages  : %li bytes (%li pages per %likB)\n",
 			pages * PAGE_SIZE, pages, PAGE_SIZE / 1024);
 	devno = 0;
-	list_for_each(p, &mem_list_head) {
-		mem = list_entry(p, struct snd_mem_list, list);
+	list_for_each_entry(mem, &mem_list_head, list) {
 		devno++;
 		len += snprintf(page + len, count - len,
 				"buffer %d : ID %08x : type %s\n",
diff --git a/sound/core/misc.c b/sound/core/misc.c
index 03fc711..6db86a7 100644
--- a/sound/core/misc.c
+++ b/sound/core/misc.c
@@ -78,3 +78,31 @@
 
 EXPORT_SYMBOL(snd_verbose_printd);
 #endif
+
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+/**
+ * snd_pci_quirk_lookup - look up a PCI SSID quirk list
+ * @pci: pci_dev handle
+ * @list: quirk list, terminated by a null entry
+ *
+ * Look through the given quirk list and finds a matching entry
+ * with the same PCI SSID.  When subdevice is 0, all subdevice
+ * values may match.
+ *
+ * Returns the matched entry pointer, or NULL if nothing matched.
+ */
+const struct snd_pci_quirk *
+snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list)
+{
+	const struct snd_pci_quirk *q;
+
+	for (q = list; q->subvendor; q++)
+		if (q->subvendor == pci->subsystem_vendor &&
+		    (!q->subdevice || q->subdevice == pci->subsystem_device))
+			return q;
+	return NULL;
+}
+
+EXPORT_SYMBOL(snd_pci_quirk_lookup);
+#endif
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 8e01898..2743414 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -45,11 +45,9 @@
 
 static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
 {
-	struct list_head *p;
 	struct snd_pcm *pcm;
 
-	list_for_each(p, &snd_pcm_devices) {
-		pcm = list_entry(p, struct snd_pcm, list);
+	list_for_each_entry(pcm, &snd_pcm_devices, list) {
 		if (pcm->card == card && pcm->device == device)
 			return pcm;
 	}
@@ -782,7 +780,6 @@
 	struct snd_pcm_runtime *runtime;
 	struct snd_ctl_file *kctl;
 	struct snd_card *card;
-	struct list_head *list;
 	int prefer_subdevice = -1;
 	size_t size;
 
@@ -795,8 +792,7 @@
 
 	card = pcm->card;
 	down_read(&card->controls_rwsem);
-	list_for_each(list, &card->ctl_files) {
-		kctl = snd_ctl_file(list);
+	list_for_each_entry(kctl, &card->ctl_files, list) {
 		if (kctl->pid == current->pid) {
 			prefer_subdevice = kctl->prefer_pcm_subdevice;
 			if (prefer_subdevice != -1)
@@ -941,9 +937,10 @@
 {
 	int cidx, err;
 	struct snd_pcm_substream *substream;
-	struct list_head *list;
+	struct snd_pcm_notify *notify;
 	char str[16];
 	struct snd_pcm *pcm = device->device_data;
+	struct device *dev;
 
 	snd_assert(pcm != NULL && device != NULL, return -ENXIO);
 	mutex_lock(&register_mutex);
@@ -966,11 +963,18 @@
 			devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
 			break;
 		}
-		if ((err = snd_register_device(devtype, pcm->card,
-					       pcm->device,
-					       &snd_pcm_f_ops[cidx],
-					       pcm, str)) < 0)
-		{
+		/* device pointer to use, pcm->dev takes precedence if
+		 * it is assigned, otherwise fall back to card's device
+		 * if possible */
+		dev = pcm->dev;
+		if (!dev)
+			dev = snd_card_get_device_link(pcm->card);
+		/* register pcm */
+		err = snd_register_device_for_dev(devtype, pcm->card,
+						  pcm->device,
+						  &snd_pcm_f_ops[cidx],
+						  pcm, str, dev);
+		if (err < 0) {
 			list_del(&pcm->list);
 			mutex_unlock(&register_mutex);
 			return err;
@@ -980,11 +984,10 @@
 		for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
 			snd_pcm_timer_init(substream);
 	}
-	list_for_each(list, &snd_pcm_notify_list) {
-		struct snd_pcm_notify *notify;
-		notify = list_entry(list, struct snd_pcm_notify, list);
+
+	list_for_each_entry(notify, &snd_pcm_notify_list, list)
 		notify->n_register(pcm);
-	}
+
 	mutex_unlock(&register_mutex);
 	return 0;
 }
@@ -1027,7 +1030,7 @@
 
 int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
 {
-	struct list_head *p;
+	struct snd_pcm *pcm;
 
 	snd_assert(notify != NULL &&
 		   notify->n_register != NULL &&
@@ -1036,13 +1039,12 @@
 	mutex_lock(&register_mutex);
 	if (nfree) {
 		list_del(&notify->list);
-		list_for_each(p, &snd_pcm_devices)
-			notify->n_unregister(list_entry(p,
-							struct snd_pcm, list));
+		list_for_each_entry(pcm, &snd_pcm_devices, list)
+			notify->n_unregister(pcm);
 	} else {
 		list_add_tail(&notify->list, &snd_pcm_notify_list);
-		list_for_each(p, &snd_pcm_devices)
-			notify->n_register(list_entry(p, struct snd_pcm, list));
+		list_for_each_entry(pcm, &snd_pcm_devices, list)
+			notify->n_register(pcm);
 	}
 	mutex_unlock(&register_mutex);
 	return 0;
@@ -1058,12 +1060,10 @@
 static void snd_pcm_proc_read(struct snd_info_entry *entry,
 			      struct snd_info_buffer *buffer)
 {
-	struct list_head *p;
 	struct snd_pcm *pcm;
 
 	mutex_lock(&register_mutex);
-	list_for_each(p, &snd_pcm_devices) {
-		pcm = list_entry(p, struct snd_pcm, list);
+	list_for_each_entry(pcm, &snd_pcm_devices, list) {
 		snd_iprintf(buffer, "%02i-%02i: %s : %s",
 			    pcm->card->number, pcm->device, pcm->id, pcm->name);
 		if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index b336797..9fefcaa 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -781,6 +781,11 @@
 {
         unsigned int k;
 	int changed = 0;
+
+	if (!count) {
+		i->empty = 1;
+		return -EINVAL;
+	}
         for (k = 0; k < count; k++) {
 		if (mask && !(mask & (1 << k)))
 			continue;
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
index be030cb..95b1b2f 100644
--- a/sound/core/pcm_memory.c
+++ b/sound/core/pcm_memory.c
@@ -101,6 +101,8 @@
 {
 	snd_pcm_lib_preallocate_dma_free(substream);
 #ifdef CONFIG_SND_VERBOSE_PROCFS
+	snd_info_free_entry(substream->proc_prealloc_max_entry);
+	substream->proc_prealloc_max_entry = NULL;
 	snd_info_free_entry(substream->proc_prealloc_entry);
 	substream->proc_prealloc_entry = NULL;
 #endif
@@ -142,6 +144,18 @@
 }
 
 /*
+ * read callback for prealloc_max proc file
+ *
+ * prints the maximum allowed size in kB.
+ */
+static void snd_pcm_lib_preallocate_max_proc_read(struct snd_info_entry *entry,
+						  struct snd_info_buffer *buffer)
+{
+	struct snd_pcm_substream *substream = entry->private_data;
+	snd_iprintf(buffer, "%lu\n", (unsigned long) substream->dma_max / 1024);
+}
+
+/*
  * write callback for prealloc proc file
  *
  * accepts the preallocation size in kB.
@@ -203,6 +217,15 @@
 		}
 	}
 	substream->proc_prealloc_entry = entry;
+	if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc_max", substream->proc_root)) != NULL) {
+		entry->c.text.read = snd_pcm_lib_preallocate_max_proc_read;
+		entry->private_data = substream;
+		if (snd_info_register(entry) < 0) {
+			snd_info_free_entry(entry);
+			entry = NULL;
+		}
+	}
+	substream->proc_prealloc_max_entry = entry;
 }
 
 #else /* !CONFIG_SND_VERBOSE_PROCFS */
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 0f055bf..7e6ceec 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -61,14 +61,11 @@
 
 static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device)
 {
-	struct list_head *p;
 	struct snd_rawmidi *rawmidi;
 
-	list_for_each(p, &snd_rawmidi_devices) {
-		rawmidi = list_entry(p, struct snd_rawmidi, list);
+	list_for_each_entry(rawmidi, &snd_rawmidi_devices, list)
 		if (rawmidi->card == card && rawmidi->device == device)
 			return rawmidi;
-	}
 	return NULL;
 }
 
@@ -389,7 +386,6 @@
 	struct snd_rawmidi *rmidi;
 	struct snd_rawmidi_file *rawmidi_file;
 	wait_queue_t wait;
-	struct list_head *list;
 	struct snd_ctl_file *kctl;
 
 	if (maj == snd_major) {
@@ -426,8 +422,7 @@
 	while (1) {
 		subdevice = -1;
 		down_read(&card->controls_rwsem);
-		list_for_each(list, &card->ctl_files) {
-			kctl = snd_ctl_file(list);
+		list_for_each_entry(kctl, &card->ctl_files, list) {
 			if (kctl->pid == current->pid) {
 				subdevice = kctl->prefer_rawmidi_subdevice;
 				if (subdevice != -1)
@@ -575,7 +570,6 @@
 	struct snd_rawmidi *rmidi;
 	struct snd_rawmidi_str *pstr;
 	struct snd_rawmidi_substream *substream;
-	struct list_head *list;
 
 	mutex_lock(&register_mutex);
 	rmidi = snd_rawmidi_search(card, info->device);
@@ -589,8 +583,7 @@
 		return -ENOENT;
 	if (info->subdevice >= pstr->substream_count)
 		return -ENXIO;
-	list_for_each(list, &pstr->substreams) {
-		substream = list_entry(list, struct snd_rawmidi_substream, list);
+	list_for_each_entry(substream, &pstr->substreams, list) {
 		if ((unsigned int)substream->number == info->subdevice)
 			return snd_rawmidi_info(substream, info);
 	}
@@ -1313,14 +1306,14 @@
 	struct snd_rawmidi *rmidi;
 	struct snd_rawmidi_substream *substream;
 	struct snd_rawmidi_runtime *runtime;
-	struct list_head *list;
 
 	rmidi = entry->private_data;
 	snd_iprintf(buffer, "%s\n\n", rmidi->name);
 	mutex_lock(&rmidi->open_mutex);
 	if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) {
-		list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) {
-			substream = list_entry(list, struct snd_rawmidi_substream, list);
+		list_for_each_entry(substream,
+				    &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams,
+				    list) {
 			snd_iprintf(buffer,
 				    "Output %d\n"
 				    "  Tx bytes     : %lu\n",
@@ -1339,8 +1332,9 @@
 		}
 	}
 	if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT) {
-		list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) {
-			substream = list_entry(list, struct snd_rawmidi_substream, list);
+		list_for_each_entry(substream,
+				    &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams,
+				    list) {
 			snd_iprintf(buffer,
 				    "Input %d\n"
 				    "  Rx bytes     : %lu\n",
@@ -1625,13 +1619,10 @@
 void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream,
 			 struct snd_rawmidi_ops *ops)
 {
-	struct list_head *list;
 	struct snd_rawmidi_substream *substream;
 	
-	list_for_each(list, &rmidi->streams[stream].substreams) {
-		substream = list_entry(list, struct snd_rawmidi_substream, list);
+	list_for_each_entry(substream, &rmidi->streams[stream].substreams, list)
 		substream->ops = ops;
-	}
 }
 
 /*
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 532a660..bb9dd9f 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -659,7 +659,6 @@
 	int err = 0, num_ev = 0;
 	struct snd_seq_event event_saved;
 	struct snd_seq_client_port *src_port;
-	struct list_head *p;
 	struct snd_seq_port_subs_info *grp;
 
 	src_port = snd_seq_port_use_ptr(client, event->source.port);
@@ -674,8 +673,7 @@
 		read_lock(&grp->list_lock);
 	else
 		down_read(&grp->list_mutex);
-	list_for_each(p, &grp->list_head) {
-		subs = list_entry(p, struct snd_seq_subscribers, src_list);
+	list_for_each_entry(subs, &grp->list_head, src_list) {
 		event->dest = subs->info.dest;
 		if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP)
 			/* convert time according to flag with subscription */
@@ -709,15 +707,14 @@
 {
 	int num_ev = 0, err = 0;
 	struct snd_seq_client *dest_client;
-	struct list_head *p;
+	struct snd_seq_client_port *port;
 
 	dest_client = get_event_dest_client(event, SNDRV_SEQ_FILTER_BROADCAST);
 	if (dest_client == NULL)
 		return 0; /* no matching destination */
 
 	read_lock(&dest_client->ports_lock);
-	list_for_each(p, &dest_client->ports_list_head) {
-		struct snd_seq_client_port *port = list_entry(p, struct snd_seq_client_port, list);
+	list_for_each_entry(port, &dest_client->ports_list_head, list) {
 		event->dest.port = port->addr.port;
 		/* pass NULL as source client to avoid error bounce */
 		err = snd_seq_deliver_single_event(NULL, event,
@@ -2473,11 +2470,10 @@
 static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer,
 				    struct snd_seq_client *client)
 {
-	struct list_head *l;
+	struct snd_seq_client_port *p;
 
 	mutex_lock(&client->ports_mutex);
-	list_for_each(l, &client->ports_list_head) {
-		struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);
+	list_for_each_entry(p, &client->ports_list_head, list) {
 		snd_iprintf(buffer, "  Port %3d : \"%s\" (%c%c%c%c)\n",
 			    p->addr.port, p->name,
 			    FLAG_PERM_RD(p->capability),
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index b79d011..37852cd 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -106,11 +106,10 @@
 static void snd_seq_device_info(struct snd_info_entry *entry,
 				struct snd_info_buffer *buffer)
 {
-	struct list_head *head;
+	struct ops_list *ops;
 
 	mutex_lock(&ops_mutex);
-	list_for_each(head, &opslist) {
-		struct ops_list *ops = list_entry(head, struct ops_list, list);
+	list_for_each_entry(ops, &opslist, list) {
 		snd_iprintf(buffer, "snd-%s%s%s%s,%d\n",
 				ops->id,
 				ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""),
@@ -143,7 +142,7 @@
 void snd_seq_device_load_drivers(void)
 {
 #ifdef CONFIG_KMOD
-	struct list_head *head;
+	struct ops_list *ops;
 
 	/* Calling request_module during module_init()
 	 * may cause blocking.
@@ -155,8 +154,7 @@
 		return;
 
 	mutex_lock(&ops_mutex);
-	list_for_each(head, &opslist) {
-		struct ops_list *ops = list_entry(head, struct ops_list, list);
+	list_for_each_entry(ops, &opslist, list) {
 		if (! (ops->driver & DRIVER_LOADED) &&
 		    ! (ops->driver & DRIVER_REQUESTED)) {
 			ops->used++;
@@ -314,8 +312,8 @@
 int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
 				   int argsize)
 {
-	struct list_head *head;
 	struct ops_list *ops;
+	struct snd_seq_device *dev;
 
 	if (id == NULL || entry == NULL ||
 	    entry->init_device == NULL || entry->free_device == NULL)
@@ -341,8 +339,7 @@
 	ops->argsize = argsize;
 
 	/* initialize existing devices if necessary */
-	list_for_each(head, &ops->dev_list) {
-		struct snd_seq_device *dev = list_entry(head, struct snd_seq_device, list);
+	list_for_each_entry(dev, &ops->dev_list, list) {
 		init_device(dev, ops);
 	}
 	mutex_unlock(&ops->reg_mutex);
@@ -394,8 +391,8 @@
  */
 int snd_seq_device_unregister_driver(char *id)
 {
-	struct list_head *head;
 	struct ops_list *ops;
+	struct snd_seq_device *dev;
 
 	ops = find_driver(id, 0);
 	if (ops == NULL)
@@ -411,8 +408,7 @@
 	/* close and release all devices associated with this driver */
 	mutex_lock(&ops->reg_mutex);
 	ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */
-	list_for_each(head, &ops->dev_list) {
-		struct snd_seq_device *dev = list_entry(head, struct snd_seq_device, list);
+	list_for_each_entry(dev, &ops->dev_list, list) {
 		free_device(dev, ops);
 	}
 
@@ -512,11 +508,10 @@
  */
 static struct ops_list * find_driver(char *id, int create_if_empty)
 {
-	struct list_head *head;
+	struct ops_list *ops;
 
 	mutex_lock(&ops_mutex);
-	list_for_each(head, &opslist) {
-		struct ops_list *ops = list_entry(head, struct ops_list, list);
+	list_for_each_entry(ops, &opslist, list) {
 		if (strcmp(ops->id, id) == 0) {
 			ops->used++;
 			mutex_unlock(&ops_mutex);
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 8c64b58..eefd1cf 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -59,14 +59,12 @@
 struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client,
 						 int num)
 {
-	struct list_head *p;
 	struct snd_seq_client_port *port;
 
 	if (client == NULL)
 		return NULL;
 	read_lock(&client->ports_lock);
-	list_for_each(p, &client->ports_list_head) {
-		port = list_entry(p, struct snd_seq_client_port, list);
+	list_for_each_entry(port, &client->ports_list_head, list) {
 		if (port->addr.port == num) {
 			if (port->closing)
 				break; /* deleting now */
@@ -85,14 +83,12 @@
 						       struct snd_seq_port_info *pinfo)
 {
 	int num;
-	struct list_head *p;
 	struct snd_seq_client_port *port, *found;
 
 	num = pinfo->addr.port;
 	found = NULL;
 	read_lock(&client->ports_lock);
-	list_for_each(p, &client->ports_list_head) {
-		port = list_entry(p, struct snd_seq_client_port, list);
+	list_for_each_entry(port, &client->ports_list_head, list) {
 		if (port->addr.port < num)
 			continue;
 		if (port->addr.port == num) {
@@ -131,8 +127,7 @@
 						int port)
 {
 	unsigned long flags;
-	struct snd_seq_client_port *new_port;
-	struct list_head *l;
+	struct snd_seq_client_port *new_port, *p;
 	int num = -1;
 	
 	/* sanity check */
@@ -161,15 +156,14 @@
 	num = port >= 0 ? port : 0;
 	mutex_lock(&client->ports_mutex);
 	write_lock_irqsave(&client->ports_lock, flags);
-	list_for_each(l, &client->ports_list_head) {
-		struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);
+	list_for_each_entry(p, &client->ports_list_head, list) {
 		if (p->addr.port > num)
 			break;
 		if (port < 0) /* auto-probe mode */
 			num = p->addr.port + 1;
 	}
 	/* insert the new port */
-	list_add_tail(&new_port->list, l);
+	list_add_tail(&new_port->list, &p->list);
 	client->num_ports++;
 	new_port->addr.port = num;	/* store the port number in the port */
 	write_unlock_irqrestore(&client->ports_lock, flags);
@@ -251,9 +245,9 @@
 				list_del(&subs->dest_list);
 			else
 				list_del(&subs->src_list);
+			up_write(&agrp->list_mutex);
 			unsubscribe_port(c, aport, agrp, &subs->info, 1);
 			kfree(subs);
-			up_write(&agrp->list_mutex);
 			snd_seq_port_unlock(aport);
 			snd_seq_client_unlock(c);
 		}
@@ -287,16 +281,14 @@
 int snd_seq_delete_port(struct snd_seq_client *client, int port)
 {
 	unsigned long flags;
-	struct list_head *l;
-	struct snd_seq_client_port *found = NULL;
+	struct snd_seq_client_port *found = NULL, *p;
 
 	mutex_lock(&client->ports_mutex);
 	write_lock_irqsave(&client->ports_lock, flags);
-	list_for_each(l, &client->ports_list_head) {
-		struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);
+	list_for_each_entry(p, &client->ports_list_head, list) {
 		if (p->addr.port == port) {
 			/* ok found.  delete from the list at first */
-			list_del(l);
+			list_del(&p->list);
 			client->num_ports--;
 			found = p;
 			break;
@@ -314,7 +306,8 @@
 int snd_seq_delete_all_ports(struct snd_seq_client *client)
 {
 	unsigned long flags;
-	struct list_head deleted_list, *p, *n;
+	struct list_head deleted_list;
+	struct snd_seq_client_port *port, *tmp;
 	
 	/* move the port list to deleted_list, and
 	 * clear the port list in the client data.
@@ -331,9 +324,8 @@
 	write_unlock_irqrestore(&client->ports_lock, flags);
 
 	/* remove each port in deleted_list */
-	list_for_each_safe(p, n, &deleted_list) {
-		struct snd_seq_client_port *port = list_entry(p, struct snd_seq_client_port, list);
-		list_del(p);
+	list_for_each_entry_safe(port, tmp, &deleted_list, list) {
+		list_del(&port->list);
 		snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port);
 		port_delete(client, port);
 	}
@@ -500,8 +492,7 @@
 {
 	struct snd_seq_port_subs_info *src = &src_port->c_src;
 	struct snd_seq_port_subs_info *dest = &dest_port->c_dest;
-	struct snd_seq_subscribers *subs;
-	struct list_head *p;
+	struct snd_seq_subscribers *subs, *s;
 	int err, src_called = 0;
 	unsigned long flags;
 	int exclusive;
@@ -525,13 +516,11 @@
 		if (src->exclusive || dest->exclusive)
 			goto __error;
 		/* check whether already exists */
-		list_for_each(p, &src->list_head) {
-			struct snd_seq_subscribers *s = list_entry(p, struct snd_seq_subscribers, src_list);
+		list_for_each_entry(s, &src->list_head, src_list) {
 			if (match_subs_info(info, &s->info))
 				goto __error;
 		}
-		list_for_each(p, &dest->list_head) {
-			struct snd_seq_subscribers *s = list_entry(p, struct snd_seq_subscribers, dest_list);
+		list_for_each_entry(s, &dest->list_head, dest_list) {
 			if (match_subs_info(info, &s->info))
 				goto __error;
 		}
@@ -582,7 +571,6 @@
 	struct snd_seq_port_subs_info *src = &src_port->c_src;
 	struct snd_seq_port_subs_info *dest = &dest_port->c_dest;
 	struct snd_seq_subscribers *subs;
-	struct list_head *p;
 	int err = -ENOENT;
 	unsigned long flags;
 
@@ -590,8 +578,7 @@
 	down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING);
 
 	/* look for the connection */
-	list_for_each(p, &src->list_head) {
-		subs = list_entry(p, struct snd_seq_subscribers, src_list);
+	list_for_each_entry(subs, &src->list_head, src_list) {
 		if (match_subs_info(info, &subs->info)) {
 			write_lock_irqsave(&src->list_lock, flags);
 			// write_lock(&dest->list_lock);  // no lock yet
@@ -620,12 +607,10 @@
 struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
 							  struct snd_seq_addr *dest_addr)
 {
-	struct list_head *p;
 	struct snd_seq_subscribers *s, *found = NULL;
 
 	down_read(&src_grp->list_mutex);
-	list_for_each(p, &src_grp->list_head) {
-		s = list_entry(p, struct snd_seq_subscribers, src_list);
+	list_for_each_entry(s, &src_grp->list_head, src_list) {
 		if (addr_match(dest_addr, &s->info.dest)) {
 			found = s;
 			break;
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
index 0cfa06c..972f934 100644
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -81,13 +81,11 @@
 					 struct snd_seq_event *ev)
 {
 	struct snd_virmidi *vmidi;
-	struct list_head *list;
 	unsigned char msg[4];
 	int len;
 
 	read_lock(&rdev->filelist_lock);
-	list_for_each(list, &rdev->filelist) {
-		vmidi = list_entry(list, struct snd_virmidi, list);
+	list_for_each_entry(vmidi, &rdev->filelist, list) {
 		if (!vmidi->trigger)
 			continue;
 		if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 82a61c6..4084de0 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -219,26 +219,27 @@
 #endif
 
 /**
- * snd_register_device - Register the ALSA device file for the card
+ * snd_register_device_for_dev - Register the ALSA device file for the card
  * @type: the device type, SNDRV_DEVICE_TYPE_XXX
  * @card: the card instance
  * @dev: the device index
  * @f_ops: the file operations
  * @private_data: user pointer for f_ops->open()
  * @name: the device file name
+ * @device: the &struct device to link this new device to
  *
  * Registers an ALSA device file for the given card.
  * The operators have to be set in reg parameter.
  *
- * Retrurns zero if successful, or a negative error code on failure.
+ * Returns zero if successful, or a negative error code on failure.
  */
-int snd_register_device(int type, struct snd_card *card, int dev,
-			const struct file_operations *f_ops, void *private_data,
-			const char *name)
+int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
+				const struct file_operations *f_ops,
+				void *private_data,
+				const char *name, struct device *device)
 {
 	int minor;
 	struct snd_minor *preg;
-	struct device *device = snd_card_get_device_link(card);
 
 	snd_assert(name, return -EINVAL);
 	preg = kmalloc(sizeof *preg, GFP_KERNEL);
@@ -272,7 +273,7 @@
 	return 0;
 }
 
-EXPORT_SYMBOL(snd_register_device);
+EXPORT_SYMBOL(snd_register_device_for_dev);
 
 /* find the matching minor record
  * return the index of snd_minor, or -1 if not found
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 10a79ae..3e06383 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -35,9 +35,6 @@
 #include <sound/minors.h>
 #include <sound/initval.h>
 #include <linux/kmod.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
-#endif
 
 #if defined(CONFIG_SND_HPET) || defined(CONFIG_SND_HPET_MODULE)
 #define DEFAULT_TIMER_LIMIT 3
@@ -130,11 +127,8 @@
 static struct snd_timer *snd_timer_find(struct snd_timer_id *tid)
 {
 	struct snd_timer *timer = NULL;
-	struct list_head *p;
 
-	list_for_each(p, &snd_timer_list) {
-		timer = list_entry(p, struct snd_timer, device_list);
-
+	list_for_each_entry(timer, &snd_timer_list, device_list) {
 		if (timer->tmr_class != tid->dev_class)
 			continue;
 		if ((timer->tmr_class == SNDRV_TIMER_CLASS_CARD ||
@@ -184,13 +178,10 @@
 {
 	struct snd_timer *timer;
 	struct snd_timer_instance *master;
-	struct list_head *p, *q;
 
 	/* FIXME: it's really dumb to look up all entries.. */
-	list_for_each(p, &snd_timer_list) {
-		timer = list_entry(p, struct snd_timer, device_list);
-		list_for_each(q, &timer->open_list_head) {
-			master = list_entry(q, struct snd_timer_instance, open_list);
+	list_for_each_entry(timer, &snd_timer_list, device_list) {
+		list_for_each_entry(master, &timer->open_list_head, open_list) {
 			if (slave->slave_class == master->slave_class &&
 			    slave->slave_id == master->slave_id) {
 				list_del(&slave->open_list);
@@ -214,16 +205,13 @@
  */
 static void snd_timer_check_master(struct snd_timer_instance *master)
 {
-	struct snd_timer_instance *slave;
-	struct list_head *p, *n;
+	struct snd_timer_instance *slave, *tmp;
 
 	/* check all pending slaves */
-	list_for_each_safe(p, n, &snd_timer_slave_list) {
-		slave = list_entry(p, struct snd_timer_instance, open_list);
+	list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) {
 		if (slave->slave_class == master->slave_class &&
 		    slave->slave_id == master->slave_id) {
-			list_del(p);
-			list_add_tail(p, &master->slave_list_head);
+			list_move_tail(&slave->open_list, &master->slave_list_head);
 			spin_lock_irq(&slave_active_lock);
 			slave->master = master;
 			slave->timer = master->timer;
@@ -317,8 +305,7 @@
 int snd_timer_close(struct snd_timer_instance *timeri)
 {
 	struct snd_timer *timer = NULL;
-	struct list_head *p, *n;
-	struct snd_timer_instance *slave;
+	struct snd_timer_instance *slave, *tmp;
 
 	snd_assert(timeri != NULL, return -ENXIO);
 
@@ -353,12 +340,11 @@
 		    timer->hw.close)
 			timer->hw.close(timer);
 		/* remove slave links */
-		list_for_each_safe(p, n, &timeri->slave_list_head) {
-			slave = list_entry(p, struct snd_timer_instance, open_list);
+		list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
+					 open_list) {
 			spin_lock_irq(&slave_active_lock);
 			_snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION);
-			list_del(p);
-			list_add_tail(p, &snd_timer_slave_list);
+			list_move_tail(&slave->open_list, &snd_timer_slave_list);
 			slave->master = NULL;
 			slave->timer = NULL;
 			spin_unlock_irq(&slave_active_lock);
@@ -394,7 +380,6 @@
 	unsigned long flags;
 	unsigned long resolution = 0;
 	struct snd_timer_instance *ts;
-	struct list_head *n;
 	struct timespec tstamp;
 
 	getnstimeofday(&tstamp);
@@ -413,11 +398,9 @@
 	if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
 		return;
 	spin_lock_irqsave(&timer->lock, flags);
-	list_for_each(n, &ti->slave_active_head) {
-		ts = list_entry(n, struct snd_timer_instance, active_list);
+	list_for_each_entry(ts, &ti->slave_active_head, active_list)
 		if (ts->ccallback)
 			ts->ccallback(ti, event + 100, &tstamp, resolution);
-	}
 	spin_unlock_irqrestore(&timer->lock, flags);
 }
 
@@ -593,10 +576,8 @@
 {
 	struct snd_timer_instance *ti;
 	unsigned long ticks = ~0UL;
-	struct list_head *p;
 
-	list_for_each(p, &timer->active_list_head) {
-		ti = list_entry(p, struct snd_timer_instance, active_list);
+	list_for_each_entry(ti, &timer->active_list_head, active_list) {
 		if (ti->flags & SNDRV_TIMER_IFLG_START) {
 			ti->flags &= ~SNDRV_TIMER_IFLG_START;
 			ti->flags |= SNDRV_TIMER_IFLG_RUNNING;
@@ -661,9 +642,9 @@
  */
 void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
 {
-	struct snd_timer_instance *ti, *ts;
+	struct snd_timer_instance *ti, *ts, *tmp;
 	unsigned long resolution, ticks;
-	struct list_head *p, *q, *n, *ack_list_head;
+	struct list_head *p, *ack_list_head;
 	unsigned long flags;
 	int use_tasklet = 0;
 
@@ -679,12 +660,12 @@
 		resolution = timer->hw.resolution;
 
 	/* loop for all active instances
-	 * Here we cannot use list_for_each because the active_list of a
+	 * Here we cannot use list_for_each_entry because the active_list of a
 	 * processed instance is relinked to done_list_head before the callback
 	 * is called.
 	 */
-	list_for_each_safe(p, n, &timer->active_list_head) {
-		ti = list_entry(p, struct snd_timer_instance, active_list);
+	list_for_each_entry_safe(ti, tmp, &timer->active_list_head,
+				 active_list) {
 		if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING))
 			continue;
 		ti->pticks += ticks_left;
@@ -700,7 +681,7 @@
 		} else {
 			ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
 			if (--timer->running)
-				list_del(p);
+				list_del(&ti->active_list);
 		}
 		if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) ||
 		    (ti->flags & SNDRV_TIMER_IFLG_FAST))
@@ -709,8 +690,7 @@
 			ack_list_head = &timer->sack_list_head;
 		if (list_empty(&ti->ack_list))
 			list_add_tail(&ti->ack_list, ack_list_head);
-		list_for_each(q, &ti->slave_active_head) {
-			ts = list_entry(q, struct snd_timer_instance, active_list);
+		list_for_each_entry(ts, &ti->slave_active_head, active_list) {
 			ts->pticks = ti->pticks;
 			ts->resolution = resolution;
 			if (list_empty(&ts->ack_list))
@@ -844,7 +824,6 @@
 {
 	struct snd_timer *timer = dev->device_data;
 	struct snd_timer *timer1;
-	struct list_head *p;
 
 	snd_assert(timer != NULL && timer->hw.start != NULL &&
 		   timer->hw.stop != NULL, return -ENXIO);
@@ -853,8 +832,7 @@
 	    	return -EINVAL;
 
 	mutex_lock(&register_mutex);
-	list_for_each(p, &snd_timer_list) {
-		timer1 = list_entry(p, struct snd_timer, device_list);
+	list_for_each_entry(timer1, &snd_timer_list, device_list) {
 		if (timer1->tmr_class > timer->tmr_class)
 			break;
 		if (timer1->tmr_class < timer->tmr_class)
@@ -877,7 +855,7 @@
 		mutex_unlock(&register_mutex);
 		return -EBUSY;
 	}
-	list_add_tail(&timer->device_list, p);
+	list_add_tail(&timer->device_list, &timer1->device_list);
 	mutex_unlock(&register_mutex);
 	return 0;
 }
@@ -896,7 +874,6 @@
 	unsigned long flags;
 	unsigned long resolution = 0;
 	struct snd_timer_instance *ti, *ts;
-	struct list_head *p, *n;
 
 	if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE))
 		return;
@@ -911,15 +888,12 @@
 		else
 			resolution = timer->hw.resolution;
 	}
-	list_for_each(p, &timer->active_list_head) {
-		ti = list_entry(p, struct snd_timer_instance, active_list);
+	list_for_each_entry(ti, &timer->active_list_head, active_list) {
 		if (ti->ccallback)
 			ti->ccallback(ti, event, tstamp, resolution);
-		list_for_each(n, &ti->slave_active_head) {
-			ts = list_entry(n, struct snd_timer_instance, active_list);
+		list_for_each_entry(ts, &ti->slave_active_head, active_list)
 			if (ts->ccallback)
 				ts->ccallback(ts, event, tstamp, resolution);
-		}
 	}
 	spin_unlock_irqrestore(&timer->lock, flags);
 }
@@ -1057,11 +1031,9 @@
 {
 	struct snd_timer *timer;
 	struct snd_timer_instance *ti;
-	struct list_head *p, *q;
 
 	mutex_lock(&register_mutex);
-	list_for_each(p, &snd_timer_list) {
-		timer = list_entry(p, struct snd_timer, device_list);
+	list_for_each_entry(timer, &snd_timer_list, device_list) {
 		switch (timer->tmr_class) {
 		case SNDRV_TIMER_CLASS_GLOBAL:
 			snd_iprintf(buffer, "G%i: ", timer->tmr_device);
@@ -1088,14 +1060,12 @@
 		if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
 			snd_iprintf(buffer, " SLAVE");
 		snd_iprintf(buffer, "\n");
-		list_for_each(q, &timer->open_list_head) {
-			ti = list_entry(q, struct snd_timer_instance, open_list);
+		list_for_each_entry(ti, &timer->open_list_head, open_list)
 			snd_iprintf(buffer, "  Client %s : %s\n",
 				    ti->owner ? ti->owner : "unknown",
 				    ti->flags & (SNDRV_TIMER_IFLG_START |
 						 SNDRV_TIMER_IFLG_RUNNING)
 				    ? "running" : "stopped");
-		}
 	}
 	mutex_unlock(&register_mutex);
 }
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig
index 40ebd2f..83529b0 100644
--- a/sound/drivers/Kconfig
+++ b/sound/drivers/Kconfig
@@ -109,4 +109,15 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-mpu401.
 
+config SND_PORTMAN2X4
+	tristate "Portman 2x4 driver"
+	depends on SND && PARPORT
+	select SND_RAWMIDI
+	help
+	  Say Y here to include support for Midiman Portman 2x4 parallel
+	  port MIDI device.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-portman2x4.
+
 endmenu
diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile
index c9bad6d..0411264 100644
--- a/sound/drivers/Makefile
+++ b/sound/drivers/Makefile
@@ -6,6 +6,7 @@
 snd-dummy-objs := dummy.o
 snd-mtpav-objs := mtpav.o
 snd-mts64-objs := mts64.o
+snd-portman2x4-objs := portman2x4.o
 snd-serial-u16550-objs := serial-u16550.o
 snd-virmidi-objs := virmidi.o
 
@@ -15,5 +16,6 @@
 obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o
 obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o
 obj-$(CONFIG_SND_MTS64) += snd-mts64.o
+obj-$(CONFIG_SND_PORTMAN2X4) += snd-portman2x4.o
 
 obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index 42001ef..8339bad 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -501,7 +501,7 @@
 	return change;
 }
 
-static DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0);
 
 #define DUMMY_CAPSRC(xname, xindex, addr) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c
new file mode 100644
index 0000000..6c48772
--- /dev/null
+++ b/sound/drivers/portman2x4.c
@@ -0,0 +1,876 @@
+/*
+ *   Driver for Midiman Portman2x4 parallel port midi interface
+ *
+ *   Copyright (c) by Levent Guendogdu <levon@feature-it.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * ChangeLog
+ * Jan 24 2007 Matthias Koenig <mkoenig@suse.de>
+ *      - cleanup and rewrite
+ * Sep 30 2004 Tobias Gehrig <tobias@gehrig.tk>
+ *      - source code cleanup
+ * Sep 03 2004 Tobias Gehrig <tobias@gehrig.tk>
+ *      - fixed compilation problem with alsa 1.0.6a (removed MODULE_CLASSES,
+ *        MODULE_PARM_SYNTAX and changed MODULE_DEVICES to
+ *        MODULE_SUPPORTED_DEVICE)
+ * Mar 24 2004 Tobias Gehrig <tobias@gehrig.tk>
+ *      - added 2.6 kernel support
+ * Mar 18 2004 Tobias Gehrig <tobias@gehrig.tk>
+ *      - added parport_unregister_driver to the startup routine if the driver fails to detect a portman
+ *      - added support for all 4 output ports in portman_putmidi
+ * Mar 17 2004 Tobias Gehrig <tobias@gehrig.tk>
+ *      - added checks for opened input device in interrupt handler
+ * Feb 20 2004 Tobias Gehrig <tobias@gehrig.tk>
+ *      - ported from alsa 0.5 to 1.0
+ */
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/parport.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/rawmidi.h>
+#include <sound/control.h>
+
+#define CARD_NAME "Portman 2x4"
+#define DRIVER_NAME "portman"
+#define PLATFORM_DRIVER "snd_portman2x4"
+
+static int index[SNDRV_CARDS]  = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS]   = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+static struct platform_device *platform_devices[SNDRV_CARDS]; 
+static int device_count;
+
+module_param_array(index, int, NULL, S_IRUGO);
+MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
+module_param_array(id, charp, NULL, S_IRUGO);
+MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
+module_param_array(enable, bool, NULL, S_IRUGO);
+MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
+
+MODULE_AUTHOR("Levent Guendogdu, Tobias Gehrig, Matthias Koenig");
+MODULE_DESCRIPTION("Midiman Portman2x4");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Midiman,Portman2x4}}");
+
+/*********************************************************************
+ * Chip specific
+ *********************************************************************/
+#define PORTMAN_NUM_INPUT_PORTS 2
+#define PORTMAN_NUM_OUTPUT_PORTS 4
+
+struct portman {
+	spinlock_t reg_lock;
+	struct snd_card *card;
+	struct snd_rawmidi *rmidi;
+	struct pardevice *pardev;
+	int pardev_claimed;
+
+	int open_count;
+	int mode[PORTMAN_NUM_INPUT_PORTS];
+	struct snd_rawmidi_substream *midi_input[PORTMAN_NUM_INPUT_PORTS];
+};
+
+static int portman_free(struct portman *pm)
+{
+	kfree(pm);
+	return 0;
+}
+
+static int __devinit portman_create(struct snd_card *card, 
+				    struct pardevice *pardev, 
+				    struct portman **rchip)
+{
+	struct portman *pm;
+
+	*rchip = NULL;
+
+	pm = kzalloc(sizeof(struct portman), GFP_KERNEL);
+	if (pm == NULL) 
+		return -ENOMEM;
+
+	/* Init chip specific data */
+	spin_lock_init(&pm->reg_lock);
+	pm->card = card;
+	pm->pardev = pardev;
+
+	*rchip = pm;
+
+	return 0;
+}
+
+/*********************************************************************
+ * HW related constants
+ *********************************************************************/
+
+/* Standard PC parallel port status register equates. */
+#define	PP_STAT_BSY   	0x80	/* Busy status.  Inverted. */
+#define	PP_STAT_ACK   	0x40	/* Acknowledge.  Non-Inverted. */
+#define	PP_STAT_POUT  	0x20	/* Paper Out.    Non-Inverted. */
+#define	PP_STAT_SEL   	0x10	/* Select.       Non-Inverted. */
+#define	PP_STAT_ERR   	0x08	/* Error.        Non-Inverted. */
+
+/* Standard PC parallel port command register equates. */
+#define	PP_CMD_IEN  	0x10	/* IRQ Enable.   Non-Inverted. */
+#define	PP_CMD_SELI 	0x08	/* Select Input. Inverted. */
+#define	PP_CMD_INIT 	0x04	/* Init Printer. Non-Inverted. */
+#define	PP_CMD_FEED 	0x02	/* Auto Feed.    Inverted. */
+#define	PP_CMD_STB      0x01	/* Strobe.       Inverted. */
+
+/* Parallel Port Command Register as implemented by PCP2x4. */
+#define	INT_EN	 	PP_CMD_IEN	/* Interrupt enable. */
+#define	STROBE	        PP_CMD_STB	/* Command strobe. */
+
+/* The parallel port command register field (b1..b3) selects the 
+ * various "registers" within the PC/P 2x4.  These are the internal
+ * address of these "registers" that must be written to the parallel
+ * port command register.
+ */
+#define	RXDATA0		(0 << 1)	/* PCP RxData channel 0. */
+#define	RXDATA1		(1 << 1)	/* PCP RxData channel 1. */
+#define	GEN_CTL		(2 << 1)	/* PCP General Control Register. */
+#define	SYNC_CTL 	(3 << 1)	/* PCP Sync Control Register. */
+#define	TXDATA0		(4 << 1)	/* PCP TxData channel 0. */
+#define	TXDATA1		(5 << 1)	/* PCP TxData channel 1. */
+#define	TXDATA2		(6 << 1)	/* PCP TxData channel 2. */
+#define	TXDATA3		(7 << 1)	/* PCP TxData channel 3. */
+
+/* Parallel Port Status Register as implemented by PCP2x4. */
+#define	ESTB		PP_STAT_POUT	/* Echoed strobe. */
+#define	INT_REQ         PP_STAT_ACK	/* Input data int request. */
+#define	BUSY            PP_STAT_ERR	/* Interface Busy. */
+
+/* Parallel Port Status Register BUSY and SELECT lines are multiplexed
+ * between several functions.  Depending on which 2x4 "register" is
+ * currently selected (b1..b3), the BUSY and SELECT lines are
+ * assigned as follows:
+ *
+ *   SELECT LINE:                                                    A3 A2 A1
+ *                                                                   --------
+ */
+#define	RXAVAIL		PP_STAT_SEL	/* Rx Available, channel 0.   0 0 0 */
+//  RXAVAIL1    PP_STAT_SEL             /* Rx Available, channel 1.   0 0 1 */
+#define	SYNC_STAT	PP_STAT_SEL	/* Reserved - Sync Status.    0 1 0 */
+//                                      /* Reserved.                  0 1 1 */
+#define	TXEMPTY		PP_STAT_SEL	/* Tx Empty, channel 0.       1 0 0 */
+//      TXEMPTY1        PP_STAT_SEL     /* Tx Empty, channel 1.       1 0 1 */
+//  TXEMPTY2    PP_STAT_SEL             /* Tx Empty, channel 2.       1 1 0 */
+//  TXEMPTY3    PP_STAT_SEL             /* Tx Empty, channel 3.       1 1 1 */
+
+/*   BUSY LINE:                                                      A3 A2 A1
+ *                                                                   --------
+ */
+#define	RXDATA		PP_STAT_BSY	/* Rx Input Data, channel 0.  0 0 0 */
+//      RXDATA1         PP_STAT_BSY     /* Rx Input Data, channel 1.  0 0 1 */
+#define	SYNC_DATA       PP_STAT_BSY	/* Reserved - Sync Data.      0 1 0 */
+					/* Reserved.                  0 1 1 */
+#define	DATA_ECHO       PP_STAT_BSY	/* Parallel Port Data Echo.   1 0 0 */
+#define	A0_ECHO         PP_STAT_BSY	/* Address 0 Echo.            1 0 1 */
+#define	A1_ECHO         PP_STAT_BSY	/* Address 1 Echo.            1 1 0 */
+#define	A2_ECHO         PP_STAT_BSY	/* Address 2 Echo.            1 1 1 */
+
+#define PORTMAN2X4_MODE_INPUT_TRIGGERED	 0x01
+
+/*********************************************************************
+ * Hardware specific functions
+ *********************************************************************/
+static inline void portman_write_command(struct portman *pm, u8 value)
+{
+	parport_write_control(pm->pardev->port, value);
+}
+
+static inline u8 portman_read_command(struct portman *pm)
+{
+	return parport_read_control(pm->pardev->port);
+}
+
+static inline u8 portman_read_status(struct portman *pm)
+{
+	return parport_read_status(pm->pardev->port);
+}
+
+static inline u8 portman_read_data(struct portman *pm)
+{
+	return parport_read_data(pm->pardev->port);
+}
+
+static inline void portman_write_data(struct portman *pm, u8 value)
+{
+	parport_write_data(pm->pardev->port, value);
+}
+
+static void portman_write_midi(struct portman *pm, 
+			       int port, u8 mididata)
+{
+	int command = ((port + 4) << 1);
+
+	/* Get entering data byte and port number in BL and BH respectively.
+	 * Set up Tx Channel address field for use with PP Cmd Register.
+	 * Store address field in BH register.
+	 * Inputs:      AH = Output port number (0..3).
+	 *              AL = Data byte.
+	 *    command = TXDATA0 | INT_EN;
+	 * Align port num with address field (b1...b3),
+	 * set address for TXDatax, Strobe=0
+	 */
+	command |= INT_EN;
+
+	/* Disable interrupts so that the process is not interrupted, then 
+	 * write the address associated with the current Tx channel to the 
+	 * PP Command Reg.  Do not set the Strobe signal yet.
+	 */
+
+	do {
+		portman_write_command(pm, command);
+
+		/* While the address lines settle, write parallel output data to 
+		 * PP Data Reg.  This has no effect until Strobe signal is asserted.
+		 */
+
+		portman_write_data(pm, mididata);
+		
+		/* If PCP channel's TxEmpty is set (TxEmpty is read through the PP
+		 * Status Register), then go write data.  Else go back and wait.
+		 */
+	} while ((portman_read_status(pm) & TXEMPTY) != TXEMPTY);
+
+	/* TxEmpty is set.  Maintain PC/P destination address and assert
+	 * Strobe through the PP Command Reg.  This will Strobe data into
+	 * the PC/P transmitter and set the PC/P BUSY signal.
+	 */
+
+	portman_write_command(pm, command | STROBE);
+
+	/* Wait for strobe line to settle and echo back through hardware.
+	 * Once it has echoed back, assume that the address and data lines
+	 * have settled!
+	 */
+
+	while ((portman_read_status(pm) & ESTB) == 0)
+		cpu_relax();
+
+	/* Release strobe and immediately re-allow interrupts. */
+	portman_write_command(pm, command);
+
+	while ((portman_read_status(pm) & ESTB) == ESTB)
+		cpu_relax();
+
+	/* PC/P BUSY is now set.  We must wait until BUSY resets itself.
+	 * We'll reenable ints while we're waiting.
+	 */
+
+	while ((portman_read_status(pm) & BUSY) == BUSY)
+		cpu_relax();
+
+	/* Data sent. */
+}
+
+
+/*
+ *  Read MIDI byte from port
+ *  Attempt to read input byte from specified hardware input port (0..).
+ *  Return -1 if no data
+ */
+static int portman_read_midi(struct portman *pm, int port)
+{
+	unsigned char midi_data = 0;
+	unsigned char cmdout;	/* Saved address+IE bit. */
+
+	/* Make sure clocking edge is down before starting... */
+	portman_write_data(pm, 0);	/* Make sure edge is down. */
+
+	/* Set destination address to PCP. */
+	cmdout = (port << 1) | INT_EN;	/* Address + IE + No Strobe. */
+	portman_write_command(pm, cmdout);
+
+	while ((portman_read_status(pm) & ESTB) == ESTB)
+		cpu_relax();	/* Wait for strobe echo. */
+
+	/* After the address lines settle, check multiplexed RxAvail signal.
+	 * If data is available, read it.
+	 */
+	if ((portman_read_status(pm) & RXAVAIL) == 0)
+		return -1;	/* No data. */
+
+	/* Set the Strobe signal to enable the Rx clocking circuitry. */
+	portman_write_command(pm, cmdout | STROBE);	/* Write address+IE+Strobe. */
+
+	while ((portman_read_status(pm) & ESTB) == 0)
+		cpu_relax(); /* Wait for strobe echo. */
+
+	/* The first data bit (msb) is already sitting on the input line. */
+	midi_data = (portman_read_status(pm) & 128);
+	portman_write_data(pm, 1);	/* Cause rising edge, which shifts data. */
+
+	/* Data bit 6. */
+	portman_write_data(pm, 0);	/* Cause falling edge while data settles. */
+	midi_data |= (portman_read_status(pm) >> 1) & 64;
+	portman_write_data(pm, 1);	/* Cause rising edge, which shifts data. */
+
+	/* Data bit 5. */
+	portman_write_data(pm, 0);	/* Cause falling edge while data settles. */
+	midi_data |= (portman_read_status(pm) >> 2) & 32;
+	portman_write_data(pm, 1);	/* Cause rising edge, which shifts data. */
+
+	/* Data bit 4. */
+	portman_write_data(pm, 0);	/* Cause falling edge while data settles. */
+	midi_data |= (portman_read_status(pm) >> 3) & 16;
+	portman_write_data(pm, 1);	/* Cause rising edge, which shifts data. */
+
+	/* Data bit 3. */
+	portman_write_data(pm, 0);	/* Cause falling edge while data settles. */
+	midi_data |= (portman_read_status(pm) >> 4) & 8;
+	portman_write_data(pm, 1);	/* Cause rising edge, which shifts data. */
+
+	/* Data bit 2. */
+	portman_write_data(pm, 0);	/* Cause falling edge while data settles. */
+	midi_data |= (portman_read_status(pm) >> 5) & 4;
+	portman_write_data(pm, 1);	/* Cause rising edge, which shifts data. */
+
+	/* Data bit 1. */
+	portman_write_data(pm, 0);	/* Cause falling edge while data settles. */
+	midi_data |= (portman_read_status(pm) >> 6) & 2;
+	portman_write_data(pm, 1);	/* Cause rising edge, which shifts data. */
+
+	/* Data bit 0. */
+	portman_write_data(pm, 0);	/* Cause falling edge while data settles. */
+	midi_data |= (portman_read_status(pm) >> 7) & 1;
+	portman_write_data(pm, 1);	/* Cause rising edge, which shifts data. */
+	portman_write_data(pm, 0);	/* Return data clock low. */
+
+
+	/* De-assert Strobe and return data. */
+	portman_write_command(pm, cmdout);	/* Output saved address+IE. */
+
+	/* Wait for strobe echo. */
+	while ((portman_read_status(pm) & ESTB) == ESTB)
+		cpu_relax();
+
+	return (midi_data & 255);	/* Shift back and return value. */
+}
+
+/*
+ *  Checks if any input data on the given channel is available
+ *  Checks RxAvail 
+ */
+static int portman_data_avail(struct portman *pm, int channel)
+{
+	int command = INT_EN;
+	switch (channel) {
+	case 0:
+		command |= RXDATA0;
+		break;
+	case 1:
+		command |= RXDATA1;
+		break;
+	}
+	/* Write hardware (assumme STROBE=0) */
+	portman_write_command(pm, command);
+	/* Check multiplexed RxAvail signal */
+	if ((portman_read_status(pm) & RXAVAIL) == RXAVAIL)
+		return 1;	/* Data available */
+
+	/* No Data available */
+	return 0;
+}
+
+
+/*
+ *  Flushes any input
+ */
+static void portman_flush_input(struct portman *pm, unsigned char port)
+{
+	/* Local variable for counting things */
+	unsigned int i = 0;
+	unsigned char command = 0;
+
+	switch (port) {
+	case 0:
+		command = RXDATA0;
+		break;
+	case 1:
+		command = RXDATA1;
+		break;
+	default:
+		snd_printk(KERN_WARNING
+			   "portman_flush_input() Won't flush port %i\n",
+			   port);
+		return;
+	}
+
+	/* Set address for specified channel in port and allow to settle. */
+	portman_write_command(pm, command);
+
+	/* Assert the Strobe and wait for echo back. */
+	portman_write_command(pm, command | STROBE);
+
+	/* Wait for ESTB */
+	while ((portman_read_status(pm) & ESTB) == 0)
+		cpu_relax();
+
+	/* Output clock cycles to the Rx circuitry. */
+	portman_write_data(pm, 0);
+
+	/* Flush 250 bits... */
+	for (i = 0; i < 250; i++) {
+		portman_write_data(pm, 1);
+		portman_write_data(pm, 0);
+	}
+
+	/* Deassert the Strobe signal of the port and wait for it to settle. */
+	portman_write_command(pm, command | INT_EN);
+
+	/* Wait for settling */
+	while ((portman_read_status(pm) & ESTB) == ESTB)
+		cpu_relax();
+}
+
+static int portman_probe(struct parport *p)
+{
+	/* Initialize the parallel port data register.  Will set Rx clocks
+	 * low in case we happen to be addressing the Rx ports at this time.
+	 */
+	/* 1 */
+	parport_write_data(p, 0);
+
+	/* Initialize the parallel port command register, thus initializing
+	 * hardware handshake lines to midi box:
+	 *
+	 *                                  Strobe = 0
+	 *                                  Interrupt Enable = 0            
+	 */
+	/* 2 */
+	parport_write_control(p, 0);
+
+	/* Check if Portman PC/P 2x4 is out there. */
+	/* 3 */
+	parport_write_control(p, RXDATA0);	/* Write Strobe=0 to command reg. */
+
+	/* Check for ESTB to be clear */
+	/* 4 */
+	if ((parport_read_status(p) & ESTB) == ESTB)
+		return 1;	/* CODE 1 - Strobe Failure. */
+
+	/* Set for RXDATA0 where no damage will be done. */
+	/* 5 */
+	parport_write_control(p, RXDATA0 + STROBE);	/* Write Strobe=1 to command reg. */
+
+	/* 6 */
+	if ((parport_read_status(p) & ESTB) != ESTB)
+		return 1;	/* CODE 1 - Strobe Failure. */
+
+	/* 7 */
+	parport_write_control(p, 0);	/* Reset Strobe=0. */
+
+	/* Check if Tx circuitry is functioning properly.  If initialized 
+	 * unit TxEmpty is false, send out char and see if if goes true.
+	 */
+	/* 8 */
+	parport_write_control(p, TXDATA0);	/* Tx channel 0, strobe off. */
+
+	/* If PCP channel's TxEmpty is set (TxEmpty is read through the PP
+	 * Status Register), then go write data.  Else go back and wait.
+	 */
+	/* 9 */
+	if ((parport_read_status(p) & TXEMPTY) == 0)
+		return 2;
+
+	/* Return OK status. */
+	return 0;
+}
+
+static int portman_device_init(struct portman *pm)
+{
+	portman_flush_input(pm, 0);
+	portman_flush_input(pm, 1);
+
+	return 0;
+}
+
+/*********************************************************************
+ * Rawmidi
+ *********************************************************************/
+static int snd_portman_midi_open(struct snd_rawmidi_substream *substream)
+{
+	return 0;
+}
+
+static int snd_portman_midi_close(struct snd_rawmidi_substream *substream)
+{
+	return 0;
+}
+
+static void snd_portman_midi_input_trigger(struct snd_rawmidi_substream *substream,
+					   int up)
+{
+	struct portman *pm = substream->rmidi->private_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pm->reg_lock, flags);
+	if (up)
+		pm->mode[substream->number] |= PORTMAN2X4_MODE_INPUT_TRIGGERED;
+	else
+		pm->mode[substream->number] &= ~PORTMAN2X4_MODE_INPUT_TRIGGERED;
+	spin_unlock_irqrestore(&pm->reg_lock, flags);
+}
+
+static void snd_portman_midi_output_trigger(struct snd_rawmidi_substream *substream,
+					    int up)
+{
+	struct portman *pm = substream->rmidi->private_data;
+	unsigned long flags;
+	unsigned char byte;
+
+	spin_lock_irqsave(&pm->reg_lock, flags);
+	if (up) {
+		while ((snd_rawmidi_transmit(substream, &byte, 1) == 1))
+			portman_write_midi(pm, substream->number, byte);
+	}
+	spin_unlock_irqrestore(&pm->reg_lock, flags);
+}
+
+static struct snd_rawmidi_ops snd_portman_midi_output = {
+	.open =		snd_portman_midi_open,
+	.close =	snd_portman_midi_close,
+	.trigger =	snd_portman_midi_output_trigger,
+};
+
+static struct snd_rawmidi_ops snd_portman_midi_input = {
+	.open =		snd_portman_midi_open,
+	.close =	snd_portman_midi_close,
+	.trigger =	snd_portman_midi_input_trigger,
+};
+
+/* Create and initialize the rawmidi component */
+static int __devinit snd_portman_rawmidi_create(struct snd_card *card)
+{
+	struct portman *pm = card->private_data;
+	struct snd_rawmidi *rmidi;
+	struct snd_rawmidi_substream *substream;
+	int err;
+	
+	err = snd_rawmidi_new(card, CARD_NAME, 0, 
+			      PORTMAN_NUM_OUTPUT_PORTS, 
+			      PORTMAN_NUM_INPUT_PORTS, 
+			      &rmidi);
+	if (err < 0) 
+		return err;
+
+	rmidi->private_data = pm;
+	strcpy(rmidi->name, CARD_NAME);
+	rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
+		            SNDRV_RAWMIDI_INFO_INPUT |
+                            SNDRV_RAWMIDI_INFO_DUPLEX;
+
+	pm->rmidi = rmidi;
+
+	/* register rawmidi ops */
+	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, 
+			    &snd_portman_midi_output);
+	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, 
+			    &snd_portman_midi_input);
+
+	/* name substreams */
+	/* output */
+	list_for_each_entry(substream,
+			    &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams,
+			    list) {
+		sprintf(substream->name,
+			"Portman2x4 %d", substream->number+1);
+	}
+	/* input */
+	list_for_each_entry(substream,
+			    &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams,
+			    list) {
+		pm->midi_input[substream->number] = substream;
+		sprintf(substream->name,
+			"Portman2x4 %d", substream->number+1);
+	}
+
+	return err;
+}
+
+/*********************************************************************
+ * parport stuff
+ *********************************************************************/
+static void snd_portman_interrupt(int irq, void *userdata)
+{
+	unsigned char midivalue = 0;
+	struct portman *pm = ((struct snd_card*)userdata)->private_data;
+
+	spin_lock(&pm->reg_lock);
+
+	/* While any input data is waiting */
+	while ((portman_read_status(pm) & INT_REQ) == INT_REQ) {
+		/* If data available on channel 0, 
+		   read it and stuff it into the queue. */
+		if (portman_data_avail(pm, 0)) {
+			/* Read Midi */
+			midivalue = portman_read_midi(pm, 0);
+			/* put midi into queue... */
+			if (pm->mode[0] & PORTMAN2X4_MODE_INPUT_TRIGGERED)
+				snd_rawmidi_receive(pm->midi_input[0],
+						    &midivalue, 1);
+
+		}
+		/* If data available on channel 1, 
+		   read it and stuff it into the queue. */
+		if (portman_data_avail(pm, 1)) {
+			/* Read Midi */
+			midivalue = portman_read_midi(pm, 1);
+			/* put midi into queue... */
+			if (pm->mode[1] & PORTMAN2X4_MODE_INPUT_TRIGGERED)
+				snd_rawmidi_receive(pm->midi_input[1],
+						    &midivalue, 1);
+		}
+
+	}
+
+	spin_unlock(&pm->reg_lock);
+}
+
+static int __devinit snd_portman_probe_port(struct parport *p)
+{
+	struct pardevice *pardev;
+	int res;
+
+	pardev = parport_register_device(p, DRIVER_NAME,
+					 NULL, NULL, NULL,
+					 0, NULL);
+	if (!pardev)
+		return -EIO;
+	
+	if (parport_claim(pardev)) {
+		parport_unregister_device(pardev);
+		return -EIO;
+	}
+
+	res = portman_probe(p);
+
+	parport_release(pardev);
+	parport_unregister_device(pardev);
+
+	return res;
+}
+
+static void __devinit snd_portman_attach(struct parport *p)
+{
+	struct platform_device *device;
+
+	device = platform_device_alloc(PLATFORM_DRIVER, device_count);
+	if (!device) 
+		return;
+
+	/* Temporary assignment to forward the parport */
+	platform_set_drvdata(device, p);
+
+	if (platform_device_register(device) < 0) {
+		platform_device_put(device);
+		return;
+	}
+
+	/* Since we dont get the return value of probe
+	 * We need to check if device probing succeeded or not */
+	if (!platform_get_drvdata(device)) {
+		platform_device_unregister(device);
+		return;
+	}
+
+	/* register device in global table */
+	platform_devices[device_count] = device;
+	device_count++;
+}
+
+static void snd_portman_detach(struct parport *p)
+{
+	/* nothing to do here */
+}
+
+static struct parport_driver portman_parport_driver = {
+	.name   = "portman2x4",
+	.attach = snd_portman_attach,
+	.detach = snd_portman_detach
+};
+
+/*********************************************************************
+ * platform stuff
+ *********************************************************************/
+static void snd_portman_card_private_free(struct snd_card *card)
+{
+	struct portman *pm = card->private_data;
+	struct pardevice *pardev = pm->pardev;
+
+	if (pardev) {
+		if (pm->pardev_claimed)
+			parport_release(pardev);
+		parport_unregister_device(pardev);
+	}
+
+	portman_free(pm);
+}
+
+static int __devinit snd_portman_probe(struct platform_device *pdev)
+{
+	struct pardevice *pardev;
+	struct parport *p;
+	int dev = pdev->id;
+	struct snd_card *card = NULL;
+	struct portman *pm = NULL;
+	int err;
+
+	p = platform_get_drvdata(pdev);
+	platform_set_drvdata(pdev, NULL);
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!enable[dev]) 
+		return -ENOENT;
+
+	if ((err = snd_portman_probe_port(p)) < 0)
+		return err;
+
+	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+	if (card == NULL) {
+		snd_printd("Cannot create card\n");
+		return -ENOMEM;
+	}
+	strcpy(card->driver, DRIVER_NAME);
+	strcpy(card->shortname, CARD_NAME);
+	sprintf(card->longname,  "%s at 0x%lx, irq %i", 
+		card->shortname, p->base, p->irq);
+
+	pardev = parport_register_device(p,                     /* port */
+					 DRIVER_NAME,           /* name */
+					 NULL,                  /* preempt */
+					 NULL,                  /* wakeup */
+					 snd_portman_interrupt, /* ISR */
+					 PARPORT_DEV_EXCL,      /* flags */
+					 (void *)card);         /* private */
+	if (pardev == NULL) {
+		snd_printd("Cannot register pardevice\n");
+		err = -EIO;
+		goto __err;
+	}
+
+	if ((err = portman_create(card, pardev, &pm)) < 0) {
+		snd_printd("Cannot create main component\n");
+		parport_unregister_device(pardev);
+		goto __err;
+	}
+	card->private_data = pm;
+	card->private_free = snd_portman_card_private_free;
+	
+	if ((err = snd_portman_rawmidi_create(card)) < 0) {
+		snd_printd("Creating Rawmidi component failed\n");
+		goto __err;
+	}
+
+	/* claim parport */
+	if (parport_claim(pardev)) {
+		snd_printd("Cannot claim parport 0x%lx\n", pardev->port->base);
+		err = -EIO;
+		goto __err;
+	}
+	pm->pardev_claimed = 1;
+
+	/* init device */
+	if ((err = portman_device_init(pm)) < 0)
+		goto __err;
+
+	platform_set_drvdata(pdev, card);
+
+	/* At this point card will be usable */
+	if ((err = snd_card_register(card)) < 0) {
+		snd_printd("Cannot register card\n");
+		goto __err;
+	}
+
+	snd_printk(KERN_INFO "Portman 2x4 on 0x%lx\n", p->base);
+	return 0;
+
+__err:
+	snd_card_free(card);
+	return err;
+}
+
+static int snd_portman_remove(struct platform_device *pdev)
+{
+	struct snd_card *card = platform_get_drvdata(pdev);
+
+	if (card)
+		snd_card_free(card);
+
+	return 0;
+}
+
+
+static struct platform_driver snd_portman_driver = {
+	.probe  = snd_portman_probe,
+	.remove = snd_portman_remove,
+	.driver = {
+		.name = PLATFORM_DRIVER
+	}
+};
+
+/*********************************************************************
+ * module init stuff
+ *********************************************************************/
+static void snd_portman_unregister_all(void)
+{
+	int i;
+
+	for (i = 0; i < SNDRV_CARDS; ++i) {
+		if (platform_devices[i]) {
+			platform_device_unregister(platform_devices[i]);
+			platform_devices[i] = NULL;
+		}
+	}		
+	platform_driver_unregister(&snd_portman_driver);
+	parport_unregister_driver(&portman_parport_driver);
+}
+
+static int __init snd_portman_module_init(void)
+{
+	int err;
+
+	if ((err = platform_driver_register(&snd_portman_driver)) < 0)
+		return err;
+
+	if (parport_register_driver(&portman_parport_driver) != 0) {
+		platform_driver_unregister(&snd_portman_driver);
+		return -EIO;
+	}
+
+	if (device_count == 0) {
+		snd_portman_unregister_all();
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void __exit snd_portman_module_exit(void)
+{
+	snd_portman_unregister_all();
+}
+
+module_init(snd_portman_module_init);
+module_exit(snd_portman_module_exit);
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index 74028b2..3a86a58 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -117,13 +117,13 @@
 #define SERIAL_MODE_INPUT_TRIGGERED	(1 << 2)
 #define SERIAL_MODE_OUTPUT_TRIGGERED	(1 << 3)
 
-typedef struct _snd_uart16550 {
+struct snd_uart16550 {
 	struct snd_card *card;
 	struct snd_rawmidi *rmidi;
 	struct snd_rawmidi_substream *midi_output[SNDRV_SERIAL_MAX_OUTS];
 	struct snd_rawmidi_substream *midi_input[SNDRV_SERIAL_MAX_INS];
 
-	int filemode;		//open status of file
+	int filemode;		/* open status of file */
 
 	spinlock_t open_lock;
 
@@ -140,39 +140,39 @@
 	unsigned char old_divisor_msb;
 	unsigned char old_line_ctrl_reg;
 
-	// parameter for using of write loop
-	short int fifo_limit;	//used in uart16550
-        short int fifo_count;	//used in uart16550
+	/* parameter for using of write loop */
+	short int fifo_limit;	/* used in uart16550 */
+        short int fifo_count;	/* used in uart16550 */
 
-	// type of adaptor
+	/* type of adaptor */
 	int adaptor;
 
-	// inputs
+	/* inputs */
 	int prev_in;
 	unsigned char rstatus;
 
-	// outputs
+	/* outputs */
 	int prev_out;
 	unsigned char prev_status[SNDRV_SERIAL_MAX_OUTS];
 
-	// write buffer and its writing/reading position
+	/* write buffer and its writing/reading position */
 	unsigned char tx_buff[TX_BUFF_SIZE];
 	int buff_in_count;
         int buff_in;
         int buff_out;
         int drop_on_full;
 
-	// wait timer
+	/* wait timer */
 	unsigned int timer_running:1;
 	struct timer_list buffer_timer;
 
-} snd_uart16550_t;
+};
 
 static struct platform_device *devices[SNDRV_CARDS];
 
-static inline void snd_uart16550_add_timer(snd_uart16550_t *uart)
+static inline void snd_uart16550_add_timer(struct snd_uart16550 *uart)
 {
-	if (! uart->timer_running) {
+	if (!uart->timer_running) {
 		/* timer 38600bps * 10bit * 16byte */
 		uart->buffer_timer.expires = jiffies + (HZ+255)/256;
 		uart->timer_running = 1;
@@ -180,7 +180,7 @@
 	}
 }
 
-static inline void snd_uart16550_del_timer(snd_uart16550_t *uart)
+static inline void snd_uart16550_del_timer(struct snd_uart16550 *uart)
 {
 	if (uart->timer_running) {
 		del_timer(&uart->buffer_timer);
@@ -189,10 +189,10 @@
 }
 
 /* This macro is only used in snd_uart16550_io_loop */
-static inline void snd_uart16550_buffer_output(snd_uart16550_t *uart)
+static inline void snd_uart16550_buffer_output(struct snd_uart16550 *uart)
 {
 	unsigned short buff_out = uart->buff_out;
-	if( uart->buff_in_count > 0 ) {
+	if (uart->buff_in_count > 0) {
 		outb(uart->tx_buff[buff_out], uart->base + UART_TX);
 		uart->fifo_count++;
 		buff_out++;
@@ -206,7 +206,7 @@
  * We don't want to interrupt this, 
  * as we're already handling an interrupt 
  */
-static void snd_uart16550_io_loop(snd_uart16550_t * uart)
+static void snd_uart16550_io_loop(struct snd_uart16550 * uart)
 {
 	unsigned char c, status;
 	int substream;
@@ -220,9 +220,8 @@
 		c = inb(uart->base + UART_RX);
 
 		/* keep track of last status byte */
-		if (c & 0x80) {
+		if (c & 0x80)
 			uart->rstatus = c;
-		}
 
 		/* handle stream switch */
 		if (uart->adaptor == SNDRV_SERIAL_GENERIC) {
@@ -230,14 +229,16 @@
 				if (c <= SNDRV_SERIAL_MAX_INS && c > 0)
 					substream = c - 1;
 				if (c != 0xf5)
-					uart->rstatus = 0; /* prevent future bytes from being interpreted as streams */
-			}
-			else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) {
-				snd_rawmidi_receive(uart->midi_input[substream], &c, 1);
-			}
-		} else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) {
+					/* prevent future bytes from being
+					   interpreted as streams */
+					uart->rstatus = 0;
+			} else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN)
+				   && uart->midi_input[substream])
+				snd_rawmidi_receive(uart->midi_input[substream],
+						    &c, 1);
+		} else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) &&
+			   uart->midi_input[substream])
 			snd_rawmidi_receive(uart->midi_input[substream], &c, 1);
-		}
 
 		if (status & UART_LSR_OE)
 			snd_printk("%s: Overrun on device at 0x%lx\n",
@@ -250,21 +251,20 @@
 	/* no need of check SERIAL_MODE_OUTPUT_OPEN because if not,
 	   buffer is never filled. */
 	/* Check write status */
-	if (status & UART_LSR_THRE) {
+	if (status & UART_LSR_THRE)
 		uart->fifo_count = 0;
-	}
 	if (uart->adaptor == SNDRV_SERIAL_MS124W_SA
 	   || uart->adaptor == SNDRV_SERIAL_GENERIC) {
 		/* Can't use FIFO, must send only when CTS is true */
 		status = inb(uart->base + UART_MSR);
-		while( (uart->fifo_count == 0) && (status & UART_MSR_CTS) &&
-		      (uart->buff_in_count > 0) ) {
+		while (uart->fifo_count == 0 && (status & UART_MSR_CTS) &&
+		       uart->buff_in_count > 0) {
 		       snd_uart16550_buffer_output(uart);
-		       status = inb( uart->base + UART_MSR );
+		       status = inb(uart->base + UART_MSR);
 		}
 	} else {
 		/* Write loop */
-		while (uart->fifo_count < uart->fifo_limit	/* Can we write ? */
+		while (uart->fifo_count < uart->fifo_limit /* Can we write ? */
 		       && uart->buff_in_count > 0)	/* Do we want to? */
 			snd_uart16550_buffer_output(uart);
 	}
@@ -294,15 +294,16 @@
  */
 static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id)
 {
-	snd_uart16550_t *uart;
+	struct snd_uart16550 *uart;
 
-	uart = (snd_uart16550_t *) dev_id;
+	uart = dev_id;
 	spin_lock(&uart->open_lock);
 	if (uart->filemode == SERIAL_MODE_NOT_OPENED) {
 		spin_unlock(&uart->open_lock);
 		return IRQ_NONE;
 	}
-	inb(uart->base + UART_IIR);		/* indicate to the UART that the interrupt has been serviced */
+	/* indicate to the UART that the interrupt has been serviced */
+	inb(uart->base + UART_IIR);
 	snd_uart16550_io_loop(uart);
 	spin_unlock(&uart->open_lock);
 	return IRQ_HANDLED;
@@ -312,9 +313,9 @@
 static void snd_uart16550_buffer_timer(unsigned long data)
 {
 	unsigned long flags;
-	snd_uart16550_t *uart;
+	struct snd_uart16550 *uart;
 
-	uart = (snd_uart16550_t *)data;
+	uart = (struct snd_uart16550 *)data;
 	spin_lock_irqsave(&uart->open_lock, flags);
 	snd_uart16550_del_timer(uart);
 	snd_uart16550_io_loop(uart);
@@ -326,7 +327,7 @@
  *  return 0 if found
  *  return negative error if not found
  */
-static int __init snd_uart16550_detect(snd_uart16550_t *uart)
+static int __init snd_uart16550_detect(struct snd_uart16550 *uart)
 {
 	unsigned long io_base = uart->base;
 	int ok;
@@ -343,7 +344,8 @@
 		return -EBUSY;
 	}
 
-	ok = 1;			/* uart detected unless one of the following tests should fail */
+	/* uart detected unless one of the following tests should fail */
+	ok = 1;
 	/* 8 data-bits, 1 stop-bit, parity off, DLAB = 0 */
 	outb(UART_LCR_WLEN8, io_base + UART_LCR); /* Line Control Register */
 	c = inb(io_base + UART_IER);
@@ -368,7 +370,7 @@
 	return ok;
 }
 
-static void snd_uart16550_do_open(snd_uart16550_t * uart)
+static void snd_uart16550_do_open(struct snd_uart16550 * uart)
 {
 	char byte;
 
@@ -460,7 +462,7 @@
 	inb(uart->base + UART_RX);	/* Clear any pre-existing receive interrupt */
 }
 
-static void snd_uart16550_do_close(snd_uart16550_t * uart)
+static void snd_uart16550_do_close(struct snd_uart16550 * uart)
 {
 	if (uart->irq < 0)
 		snd_uart16550_del_timer(uart);
@@ -514,7 +516,7 @@
 static int snd_uart16550_input_open(struct snd_rawmidi_substream *substream)
 {
 	unsigned long flags;
-	snd_uart16550_t *uart = substream->rmidi->private_data;
+	struct snd_uart16550 *uart = substream->rmidi->private_data;
 
 	spin_lock_irqsave(&uart->open_lock, flags);
 	if (uart->filemode == SERIAL_MODE_NOT_OPENED)
@@ -528,7 +530,7 @@
 static int snd_uart16550_input_close(struct snd_rawmidi_substream *substream)
 {
 	unsigned long flags;
-	snd_uart16550_t *uart = substream->rmidi->private_data;
+	struct snd_uart16550 *uart = substream->rmidi->private_data;
 
 	spin_lock_irqsave(&uart->open_lock, flags);
 	uart->filemode &= ~SERIAL_MODE_INPUT_OPEN;
@@ -539,24 +541,24 @@
 	return 0;
 }
 
-static void snd_uart16550_input_trigger(struct snd_rawmidi_substream *substream, int up)
+static void snd_uart16550_input_trigger(struct snd_rawmidi_substream *substream,
+					int up)
 {
 	unsigned long flags;
-	snd_uart16550_t *uart = substream->rmidi->private_data;
+	struct snd_uart16550 *uart = substream->rmidi->private_data;
 
 	spin_lock_irqsave(&uart->open_lock, flags);
-	if (up) {
+	if (up)
 		uart->filemode |= SERIAL_MODE_INPUT_TRIGGERED;
-	} else {
+	else
 		uart->filemode &= ~SERIAL_MODE_INPUT_TRIGGERED;
-	}
 	spin_unlock_irqrestore(&uart->open_lock, flags);
 }
 
 static int snd_uart16550_output_open(struct snd_rawmidi_substream *substream)
 {
 	unsigned long flags;
-	snd_uart16550_t *uart = substream->rmidi->private_data;
+	struct snd_uart16550 *uart = substream->rmidi->private_data;
 
 	spin_lock_irqsave(&uart->open_lock, flags);
 	if (uart->filemode == SERIAL_MODE_NOT_OPENED)
@@ -570,7 +572,7 @@
 static int snd_uart16550_output_close(struct snd_rawmidi_substream *substream)
 {
 	unsigned long flags;
-	snd_uart16550_t *uart = substream->rmidi->private_data;
+	struct snd_uart16550 *uart = substream->rmidi->private_data;
 
 	spin_lock_irqsave(&uart->open_lock, flags);
 	uart->filemode &= ~SERIAL_MODE_OUTPUT_OPEN;
@@ -581,18 +583,20 @@
 	return 0;
 };
 
-static inline int snd_uart16550_buffer_can_write( snd_uart16550_t *uart, int Num )
+static inline int snd_uart16550_buffer_can_write(struct snd_uart16550 *uart,
+						 int Num)
 {
-	if( uart->buff_in_count + Num < TX_BUFF_SIZE )
+	if (uart->buff_in_count + Num < TX_BUFF_SIZE)
 		return 1;
 	else
 		return 0;
 }
 
-static inline int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned char byte)
+static inline int snd_uart16550_write_buffer(struct snd_uart16550 *uart,
+					     unsigned char byte)
 {
 	unsigned short buff_in = uart->buff_in;
-	if( uart->buff_in_count < TX_BUFF_SIZE ) {
+	if (uart->buff_in_count < TX_BUFF_SIZE) {
 		uart->tx_buff[buff_in] = byte;
 		buff_in++;
 		buff_in &= TX_BUFF_MASK;
@@ -605,12 +609,14 @@
 		return 0;
 }
 
-static int snd_uart16550_output_byte(snd_uart16550_t *uart, struct snd_rawmidi_substream *substream, unsigned char midi_byte)
+static int snd_uart16550_output_byte(struct snd_uart16550 *uart,
+				     struct snd_rawmidi_substream *substream,
+				     unsigned char midi_byte)
 {
-	if (uart->buff_in_count == 0                            /* Buffer empty? */
+	if (uart->buff_in_count == 0                    /* Buffer empty? */
 	    && ((uart->adaptor != SNDRV_SERIAL_MS124W_SA &&
 	    uart->adaptor != SNDRV_SERIAL_GENERIC) ||
-		(uart->fifo_count == 0                               /* FIFO empty? */
+		(uart->fifo_count == 0                  /* FIFO empty? */
 		 && (inb(uart->base + UART_MSR) & UART_MSR_CTS)))) { /* CTS? */
 
 	        /* Tx Buffer Empty - try to write immediately */
@@ -623,12 +629,13 @@
 			        uart->fifo_count++;
 				outb(midi_byte, uart->base + UART_TX);
 			} else {
-			        /* Cannot write (buffer empty) - put char in buffer */
+			        /* Cannot write (buffer empty) -
+				 * put char in buffer */
 				snd_uart16550_write_buffer(uart, midi_byte);
 			}
 		}
 	} else {
-		if( !snd_uart16550_write_buffer(uart, midi_byte) ) {
+		if (!snd_uart16550_write_buffer(uart, midi_byte)) {
 			snd_printk("%s: Buffer overrun on device at 0x%lx\n",
 				   uart->rmidi->name, uart->base);
 			return 0;
@@ -642,9 +649,9 @@
 {
 	unsigned long flags;
 	unsigned char midi_byte, addr_byte;
-	snd_uart16550_t *uart = substream->rmidi->private_data;
+	struct snd_uart16550 *uart = substream->rmidi->private_data;
 	char first;
-	static unsigned long lasttime=0;
+	static unsigned long lasttime = 0;
 	
 	/* Interupts are disabled during the updating of the tx_buff,
 	 * since it is 'bad' to have two processes updating the same
@@ -653,7 +660,7 @@
 
 	spin_lock_irqsave(&uart->open_lock, flags);
 
-	if (uart->irq < 0)	//polling
+	if (uart->irq < 0)	/* polling */
 		snd_uart16550_io_loop(uart);
 
 	if (uart->adaptor == SNDRV_SERIAL_MS124W_MB) {
@@ -671,7 +678,8 @@
 			/* select any combination of the four ports */
 			addr_byte = (substream->number << 4) | 0x08;
 			/* ...except none */
-			if (addr_byte == 0x08) addr_byte = 0xf8;
+			if (addr_byte == 0x08)
+				addr_byte = 0xf8;
 #endif
 			snd_uart16550_output_byte(uart, substream, addr_byte);
 			/* send midi byte */
@@ -679,31 +687,42 @@
 		}
 	} else {
 		first = 0;
-		while( 1 == snd_rawmidi_transmit_peek(substream, &midi_byte, 1) ) {
-			/* Also send F5 after 3 seconds with no data to handle device disconnect */
-			if (first == 0 && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS ||
-				uart->adaptor == SNDRV_SERIAL_GENERIC) &&
-			   (uart->prev_out != substream->number || jiffies-lasttime > 3*HZ)) {
+		while (snd_rawmidi_transmit_peek(substream, &midi_byte, 1) == 1) {
+			/* Also send F5 after 3 seconds with no data
+			 * to handle device disconnect */
+			if (first == 0 &&
+			    (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS ||
+			     uart->adaptor == SNDRV_SERIAL_GENERIC) &&
+			    (uart->prev_out != substream->number ||
+			     jiffies-lasttime > 3*HZ)) {
 
-				if( snd_uart16550_buffer_can_write( uart, 3 ) ) {
+				if (snd_uart16550_buffer_can_write(uart, 3)) {
 					/* Roland Soundcanvas part selection */
-					/* If this substream of the data is different previous
-					   substream in this uart, send the change part event */
+					/* If this substream of the data is
+					 * different previous substream
+					 * in this uart, send the change part
+					 * event
+					 */
 					uart->prev_out = substream->number;
 					/* change part */
-					snd_uart16550_output_byte(uart, substream, 0xf5);
+					snd_uart16550_output_byte(uart, substream,
+								  0xf5);
 					/* data */
-					snd_uart16550_output_byte(uart, substream, uart->prev_out + 1);
-					/* If midi_byte is a data byte, send the previous status byte */
-					if ((midi_byte < 0x80) && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS))
+					snd_uart16550_output_byte(uart, substream,
+								  uart->prev_out + 1);
+					/* If midi_byte is a data byte,
+					 * send the previous status byte */
+					if (midi_byte < 0x80 &&
+					    uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS)
 						snd_uart16550_output_byte(uart, substream, uart->prev_status[uart->prev_out]);
-				} else if( !uart->drop_on_full )
+				} else if (!uart->drop_on_full)
 					break;
 
 			}
 
 			/* send midi byte */
-			if( !snd_uart16550_output_byte(uart, substream, midi_byte) && !uart->drop_on_full )
+			if (!snd_uart16550_output_byte(uart, substream, midi_byte) &&
+			    !uart->drop_on_full )
 				break;
 
 			if (midi_byte >= 0x80 && midi_byte < 0xf0)
@@ -717,17 +736,17 @@
 	spin_unlock_irqrestore(&uart->open_lock, flags);
 }
 
-static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream, int up)
+static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream,
+					 int up)
 {
 	unsigned long flags;
-	snd_uart16550_t *uart = substream->rmidi->private_data;
+	struct snd_uart16550 *uart = substream->rmidi->private_data;
 
 	spin_lock_irqsave(&uart->open_lock, flags);
-	if (up) {
+	if (up)
 		uart->filemode |= SERIAL_MODE_OUTPUT_TRIGGERED;
-	} else {
+	else
 		uart->filemode &= ~SERIAL_MODE_OUTPUT_TRIGGERED;
-	}
 	spin_unlock_irqrestore(&uart->open_lock, flags);
 	if (up)
 		snd_uart16550_output_write(substream);
@@ -747,10 +766,10 @@
 	.trigger =	snd_uart16550_input_trigger,
 };
 
-static int snd_uart16550_free(snd_uart16550_t *uart)
+static int snd_uart16550_free(struct snd_uart16550 *uart)
 {
 	if (uart->irq >= 0)
-		free_irq(uart->irq, (void *)uart);
+		free_irq(uart->irq, uart);
 	release_and_free_resource(uart->res_base);
 	kfree(uart);
 	return 0;
@@ -758,7 +777,7 @@
 
 static int snd_uart16550_dev_free(struct snd_device *device)
 {
-	snd_uart16550_t *uart = device->device_data;
+	struct snd_uart16550 *uart = device->device_data;
 	return snd_uart16550_free(uart);
 }
 
@@ -769,12 +788,12 @@
 				       unsigned int base,
 				       int adaptor,
 				       int droponfull,
-				       snd_uart16550_t **ruart)
+				       struct snd_uart16550 **ruart)
 {
 	static struct snd_device_ops ops = {
 		.dev_free =	snd_uart16550_dev_free,
 	};
-	snd_uart16550_t *uart;
+	struct snd_uart16550 *uart;
 	int err;
 
 
@@ -795,7 +814,7 @@
 
 	if (irq >= 0 && irq != SNDRV_AUTO_IRQ) {
 		if (request_irq(irq, snd_uart16550_interrupt,
-				IRQF_DISABLED, "Serial MIDI", (void *) uart)) {
+				IRQF_DISABLED, "Serial MIDI", uart)) {
 			snd_printk("irq %d busy. Using Polling.\n", irq);
 		} else {
 			uart->irq = irq;
@@ -843,23 +862,28 @@
 
 static void __init snd_uart16550_substreams(struct snd_rawmidi_str *stream)
 {
-	struct list_head *list;
+	struct snd_rawmidi_substream *substream;
 
-	list_for_each(list, &stream->substreams) {
-		struct snd_rawmidi_substream *substream = list_entry(list, struct snd_rawmidi_substream, list);
+	list_for_each_entry(substream, &stream->substreams, list) {
 		sprintf(substream->name, "Serial MIDI %d", substream->number + 1);
 	}
 }
 
-static int __init snd_uart16550_rmidi(snd_uart16550_t *uart, int device, int outs, int ins, struct snd_rawmidi **rmidi)
+static int __init snd_uart16550_rmidi(struct snd_uart16550 *uart, int device,
+				      int outs, int ins,
+				      struct snd_rawmidi **rmidi)
 {
 	struct snd_rawmidi *rrawmidi;
 	int err;
 
-	if ((err = snd_rawmidi_new(uart->card, "UART Serial MIDI", device, outs, ins, &rrawmidi)) < 0)
+	err = snd_rawmidi_new(uart->card, "UART Serial MIDI", device,
+			      outs, ins, &rrawmidi);
+	if (err < 0)
 		return err;
-	snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_uart16550_input);
-	snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_uart16550_output);
+	snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+			    &snd_uart16550_input);
+	snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+			    &snd_uart16550_output);
 	strcpy(rrawmidi->name, "Serial MIDI");
 	snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
 	snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]);
@@ -875,7 +899,7 @@
 static int __init snd_serial_probe(struct platform_device *devptr)
 {
 	struct snd_card *card;
-	snd_uart16550_t *uart;
+	struct snd_uart16550 *uart;
 	int err;
 	int dev = devptr->id;
 
@@ -929,7 +953,8 @@
 					&uart)) < 0)
 		goto _err;
 
-	if ((err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi)) < 0)
+	err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi);
+	if (err < 0)
 		goto _err;
 
 	sprintf(card->longname, "%s at 0x%lx, irq %d speed %d div %d outs %d ins %d adaptor %s droponfull %d",
diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c
index 1613ed8..f63152a 100644
--- a/sound/drivers/vx/vx_mixer.c
+++ b/sound/drivers/vx/vx_mixer.c
@@ -716,7 +716,7 @@
 	return 0;
 }
 
-static DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0);
 
 static struct snd_kcontrol_new vx_control_audio_gain = {
 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
diff --git a/sound/i2c/Makefile b/sound/i2c/Makefile
index 816a2e7..45902d4 100644
--- a/sound/i2c/Makefile
+++ b/sound/i2c/Makefile
@@ -16,3 +16,4 @@
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_INTERWAVE_STB) += snd-tea6330t.o snd-i2c.o
 obj-$(CONFIG_SND_ICE1712) += snd-cs8427.o snd-i2c.o
+obj-$(CONFIG_SND_ICE1724) += snd-i2c.o
diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile
index 2fe023ef..77a8a7c 100644
--- a/sound/i2c/other/Makefile
+++ b/sound/i2c/other/Makefile
@@ -6,11 +6,11 @@
 snd-ak4114-objs := ak4114.o
 snd-ak4117-objs := ak4117.o
 snd-ak4xxx-adda-objs := ak4xxx-adda.o
+snd-pt2258-objs := pt2258.o
 snd-tea575x-tuner-objs := tea575x-tuner.o
 
 # Module Dependency
 obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o
 obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o
-obj-$(CONFIG_SND_ICE1724) += snd-ak4xxx-adda.o
-obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o
+obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4xxx-adda.o snd-pt2258.o
 obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o
diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c
index d2f2c50..adbfd58 100644
--- a/sound/i2c/other/ak4114.c
+++ b/sound/i2c/other/ak4114.c
@@ -42,8 +42,8 @@
 	ak4114->write(ak4114->private_data, reg, val);
 	if (reg <= AK4114_REG_INT1_MASK)
 		ak4114->regmap[reg] = val;
-	else if (reg >= AK4114_REG_RXCSB0 && reg <= AK4114_REG_TXCSB4)
-		ak4114->txcsb[reg-AK4114_REG_RXCSB0] = val;
+	else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4)
+		ak4114->txcsb[reg-AK4114_REG_TXCSB0] = val;
 }
 
 static inline unsigned char reg_read(struct ak4114 *ak4114, unsigned char reg)
@@ -66,10 +66,8 @@
 {
 	chip->init = 1;	/* don't schedule new work */
 	mb();
-	if (chip->workqueue != NULL) {
-		flush_workqueue(chip->workqueue);
-		destroy_workqueue(chip->workqueue);
-	}
+	cancel_delayed_work(&chip->work);
+	flush_scheduled_work();
 	kfree(chip);
 }
 
@@ -82,7 +80,7 @@
 
 int snd_ak4114_create(struct snd_card *card,
 		      ak4114_read_t *read, ak4114_write_t *write,
-		      unsigned char pgm[7], unsigned char txcsb[5],
+		      const unsigned char pgm[7], const unsigned char txcsb[5],
 		      void *private_data, struct ak4114 **r_ak4114)
 {
 	struct ak4114 *chip;
@@ -100,18 +98,13 @@
 	chip->read = read;
 	chip->write = write;
 	chip->private_data = private_data;
+	INIT_DELAYED_WORK(&chip->work, ak4114_stats);
 
 	for (reg = 0; reg < 7; reg++)
 		chip->regmap[reg] = pgm[reg];
 	for (reg = 0; reg < 5; reg++)
 		chip->txcsb[reg] = txcsb[reg];
 
-	chip->workqueue = create_workqueue("snd-ak4114");
-	if (chip->workqueue == NULL) {
-		kfree(chip);
-		return -ENOMEM;
-	}
-
 	snd_ak4114_reinit(chip);
 
 	chip->rcs0 = reg_read(chip, AK4114_REG_RCS0) & ~(AK4114_QINT | AK4114_CINT);
@@ -134,7 +127,8 @@
 	if (reg <= AK4114_REG_INT1_MASK)
 		reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val);
 	else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4)
-		reg_write(chip, reg, (chip->txcsb[reg] & ~mask) | val);
+		reg_write(chip, reg,
+			  (chip->txcsb[reg-AK4114_REG_TXCSB0] & ~mask) | val);
 }
 
 void snd_ak4114_reinit(struct ak4114 *chip)
@@ -143,7 +137,7 @@
 
 	chip->init = 1;
 	mb();
-	flush_workqueue(chip->workqueue);
+	flush_scheduled_work();
 	/* bring the chip to reset state and powerdown state */
 	reg_write(chip, AK4114_REG_PWRDN, old & ~(AK4114_RST|AK4114_PWN));
 	udelay(200);
@@ -158,8 +152,7 @@
 	reg_write(chip, AK4114_REG_PWRDN, old | AK4114_RST | AK4114_PWN);
 	/* bring up statistics / event queing */
 	chip->init = 0;
-	INIT_DELAYED_WORK(&chip->work, ak4114_stats);
-	queue_delayed_work(chip->workqueue, &chip->work, HZ / 10);
+	schedule_delayed_work(&chip->work, HZ / 10);
 }
 
 static unsigned int external_rate(unsigned char rcs1)
@@ -568,7 +561,7 @@
 	if (chip->init)
 		return;
 	snd_ak4114_check_rate_and_errors(chip, 0);
-	queue_delayed_work(chip->workqueue, &chip->work, HZ / 10);
+	schedule_delayed_work(&chip->work, HZ / 10);
 }
 
 EXPORT_SYMBOL(snd_ak4114_create);
diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c
index 4e45952..c022f29 100644
--- a/sound/i2c/other/ak4117.c
+++ b/sound/i2c/other/ak4117.c
@@ -74,7 +74,7 @@
 }
 
 int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write,
-		      unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117)
+		      const unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117)
 {
 	struct ak4117 *chip;
 	int err = 0;
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index 5da49e2..8805110 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -140,7 +140,7 @@
  * Used for AK4524 input/ouput attenuation, AK4528, and
  * AK5365 input attenuation
  */
-static unsigned char vol_cvt_datt[128] = {
+static const unsigned char vol_cvt_datt[128] = {
 	0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04,
 	0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06,
 	0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a,
@@ -162,17 +162,17 @@
 /*
  * dB tables
  */
-static DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
-static DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
-static DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
-static DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
+static const DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
 
 /*
  * initialize all the ak4xxx chips
  */
 void snd_akm4xxx_init(struct snd_akm4xxx *ak)
 {
-	static unsigned char inits_ak4524[] = {
+	static const unsigned char inits_ak4524[] = {
 		0x00, 0x07, /* 0: all power up */
 		0x01, 0x00, /* 1: ADC/DAC reset */
 		0x02, 0x60, /* 2: 24bit I2S */
@@ -184,7 +184,7 @@
 		0x07, 0x00, /* 7: DAC right muted */
 		0xff, 0xff
 	};
-	static unsigned char inits_ak4528[] = {
+	static const unsigned char inits_ak4528[] = {
 		0x00, 0x07, /* 0: all power up */
 		0x01, 0x00, /* 1: ADC/DAC reset */
 		0x02, 0x60, /* 2: 24bit I2S */
@@ -194,7 +194,7 @@
 		0x05, 0x00, /* 5: ADC right muted */
 		0xff, 0xff
 	};
-	static unsigned char inits_ak4529[] = {
+	static const unsigned char inits_ak4529[] = {
 		0x09, 0x01, /* 9: ATS=0, RSTN=1 */
 		0x0a, 0x3f, /* A: all power up, no zero/overflow detection */
 		0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */
@@ -210,7 +210,7 @@
 		0x08, 0x55, /* 8: deemphasis all off */
 		0xff, 0xff
 	};
-	static unsigned char inits_ak4355[] = {
+	static const unsigned char inits_ak4355[] = {
 		0x01, 0x02, /* 1: reset and soft-mute */
 		0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
 			     * disable DZF, sharp roll-off, RSTN#=0 */
@@ -227,7 +227,7 @@
 		0x01, 0x01, /* 1: un-reset, unmute */
 		0xff, 0xff
 	};
-	static unsigned char inits_ak4358[] = {
+	static const unsigned char inits_ak4358[] = {
 		0x01, 0x02, /* 1: reset and soft-mute */
 		0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
 			     * disable DZF, sharp roll-off, RSTN#=0 */
@@ -246,7 +246,7 @@
 		0x01, 0x01, /* 1: un-reset, unmute */
 		0xff, 0xff
 	};
-	static unsigned char inits_ak4381[] = {
+	static const unsigned char inits_ak4381[] = {
 		0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
 		0x01, 0x02, /* 1: de-emphasis off, normal speed,
 			     * sharp roll-off, DZF off */
@@ -259,7 +259,8 @@
 	};
 
 	int chip, num_chips;
-	unsigned char *ptr, reg, data, *inits;
+	const unsigned char *ptr, *inits;
+	unsigned char reg, data;
 
 	memset(ak->images, 0, sizeof(ak->images));
 	memset(ak->volumes, 0, sizeof(ak->volumes));
@@ -513,6 +514,66 @@
 	return change;
 }
 
+#define AK5365_NUM_INPUTS 5
+
+static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_info *uinfo)
+{
+	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+	int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
+	const char **input_names;
+	int  num_names, idx;
+
+	input_names = ak->adc_info[mixer_ch].input_names;
+
+	num_names = 0;
+	while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
+		++num_names;
+	
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = num_names;
+	idx = uinfo->value.enumerated.item;
+	if (idx >= num_names)
+		return -EINVAL;
+	strncpy(uinfo->value.enumerated.name, input_names[idx],
+		sizeof(uinfo->value.enumerated.name));
+	return 0;
+}
+
+static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+	int chip = AK_GET_CHIP(kcontrol->private_value);
+	int addr = AK_GET_ADDR(kcontrol->private_value);
+	int mask = AK_GET_MASK(kcontrol->private_value);
+	unsigned char val;
+
+	val = snd_akm4xxx_get(ak, chip, addr) & mask;
+	ucontrol->value.enumerated.item[0] = val;
+	return 0;
+}
+
+static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+	int chip = AK_GET_CHIP(kcontrol->private_value);
+	int addr = AK_GET_ADDR(kcontrol->private_value);
+	int mask = AK_GET_MASK(kcontrol->private_value);
+	unsigned char oval, val;
+
+	oval = snd_akm4xxx_get(ak, chip, addr);
+	val = oval & ~mask;
+	val |= ucontrol->value.enumerated.item[0] & mask;
+	if (val != oval) {
+		snd_akm4xxx_write(ak, chip, addr, val);
+		return 1;
+	}
+	return 0;
+}
+
 /*
  * build AK4xxx controls
  */
@@ -647,9 +708,10 @@
 
 		if (ak->type == SND_AK5365 && (idx % 2) == 0) {
 			if (! ak->adc_info || 
-			    ! ak->adc_info[mixer_ch].switch_name)
+			    ! ak->adc_info[mixer_ch].switch_name) {
 				knew.name = "Capture Switch";
-			else
+				knew.index = mixer_ch + ak->idx_offset * 2;
+			} else
 				knew.name = ak->adc_info[mixer_ch].switch_name;
 			knew.info = ak4xxx_switch_info;
 			knew.get = ak4xxx_switch_get;
@@ -662,6 +724,26 @@
 			err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
 			if (err < 0)
 				return err;
+
+			memset(&knew, 0, sizeof(knew));
+			knew.name = ak->adc_info[mixer_ch].selector_name;
+			if (!knew.name) {
+				knew.name = "Capture Channel";
+				knew.index = mixer_ch + ak->idx_offset * 2;
+			}
+
+			knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+			knew.info = ak4xxx_capture_source_info;
+			knew.get = ak4xxx_capture_source_get;
+			knew.put = ak4xxx_capture_source_put;
+			knew.access = 0;
+			/* input selector control: reg. 1, bits 0-2.
+			 * mis-use 'shift' to pass mixer_ch */
+			knew.private_value
+				= AK_COMPOSE(idx/2, 1, mixer_ch, 0x07);
+			err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
+			if (err < 0)
+				return err;
 		}
 
 		idx += num_stereo;
diff --git a/sound/i2c/other/pt2258.c b/sound/i2c/other/pt2258.c
new file mode 100644
index 0000000..e91cc3b
--- /dev/null
+++ b/sound/i2c/other/pt2258.c
@@ -0,0 +1,233 @@
+/*
+ *   ALSA Driver for the PT2258 volume controller.
+ *
+ *	Copyright (c) 2006  Jochen Voss <voss@seehuhn.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */      
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+#include <sound/i2c.h>
+#include <sound/pt2258.h>
+
+MODULE_AUTHOR("Jochen Voss <voss@seehuhn.de>");
+MODULE_DESCRIPTION("PT2258 volume controller (Princeton Technology Corp.)");
+MODULE_LICENSE("GPL");
+
+#define PT2258_CMD_RESET 0xc0
+#define PT2258_CMD_UNMUTE 0xf8
+#define PT2258_CMD_MUTE 0xf9
+
+static const unsigned char pt2258_channel_code[12] = {
+	0x80, 0x90,		/* channel 1: -10dB, -1dB */
+	0x40, 0x50,		/* channel 2: -10dB, -1dB */
+	0x00, 0x10,		/* channel 3: -10dB, -1dB */
+	0x20, 0x30,		/* channel 4: -10dB, -1dB */
+	0x60, 0x70,		/* channel 5: -10dB, -1dB */
+	0xa0, 0xb0		/* channel 6: -10dB, -1dB */
+};
+
+int snd_pt2258_reset(struct snd_pt2258 *pt)
+{
+	unsigned char bytes[2];
+	int i;
+
+	/* reset chip */
+	bytes[0] = PT2258_CMD_RESET;
+	snd_i2c_lock(pt->i2c_bus);
+	if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
+		goto __error;
+	snd_i2c_unlock(pt->i2c_bus);
+
+	/* mute all channels */
+	pt->mute = 1;
+	bytes[0] = PT2258_CMD_MUTE;
+	snd_i2c_lock(pt->i2c_bus);
+	if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
+		goto __error;
+	snd_i2c_unlock(pt->i2c_bus);
+
+	/* set all channels to 0dB */
+	for (i = 0; i < 6; ++i)
+		pt->volume[i] = 0;
+	bytes[0] = 0xd0;
+	bytes[1] = 0xe0;
+	snd_i2c_lock(pt->i2c_bus);
+	if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
+		goto __error;
+	snd_i2c_unlock(pt->i2c_bus);
+
+	return 0;
+
+      __error:
+	snd_i2c_unlock(pt->i2c_bus);
+	snd_printk(KERN_ERR "PT2258 reset failed\n");
+	return -EIO;
+}
+
+static int pt2258_stereo_volume_info(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 79;
+	return 0;
+}
+
+static int pt2258_stereo_volume_get(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pt2258 *pt = kcontrol->private_data;
+	int base = kcontrol->private_value;
+
+	/* chip does not support register reads */
+	ucontrol->value.integer.value[0] = 79 - pt->volume[base];
+	ucontrol->value.integer.value[1] = 79 - pt->volume[base + 1];
+	return 0;
+}
+
+static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pt2258 *pt = kcontrol->private_data;
+	int base = kcontrol->private_value;
+	unsigned char bytes[2];
+	int val0, val1;
+
+	val0 = 79 - ucontrol->value.integer.value[0];
+	val1 = 79 - ucontrol->value.integer.value[1];
+	if (val0 == pt->volume[base] && val1 == pt->volume[base + 1])
+		return 0;
+
+	pt->volume[base] = val0;
+	bytes[0] = pt2258_channel_code[2 * base] | (val0 / 10);
+	bytes[1] = pt2258_channel_code[2 * base + 1] | (val0 % 10);
+	snd_i2c_lock(pt->i2c_bus);
+	if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
+		goto __error;
+	snd_i2c_unlock(pt->i2c_bus);
+
+	pt->volume[base + 1] = val1;
+	bytes[0] = pt2258_channel_code[2 * base + 2] | (val1 / 10);
+	bytes[1] = pt2258_channel_code[2 * base + 3] | (val1 % 10);
+	snd_i2c_lock(pt->i2c_bus);
+	if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
+		goto __error;
+	snd_i2c_unlock(pt->i2c_bus);
+
+	return 1;
+
+      __error:
+	snd_i2c_unlock(pt->i2c_bus);
+	snd_printk(KERN_ERR "PT2258 access failed\n");
+	return -EIO;
+}
+
+static int pt2258_switch_info(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_info *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 pt2258_switch_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pt2258 *pt = kcontrol->private_data;
+
+	ucontrol->value.integer.value[0] = !pt->mute;
+	return 0;
+}
+
+static int pt2258_switch_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pt2258 *pt = kcontrol->private_data;
+	unsigned char bytes[2];
+	int val;
+
+	val = !ucontrol->value.integer.value[0];
+	if (pt->mute == val)
+		return 0;
+
+	pt->mute = val;
+	bytes[0] = val ? PT2258_CMD_MUTE : PT2258_CMD_UNMUTE;
+	snd_i2c_lock(pt->i2c_bus);
+	if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
+		goto __error;
+	snd_i2c_unlock(pt->i2c_bus);
+
+	return 1;
+
+      __error:
+	snd_i2c_unlock(pt->i2c_bus);
+	snd_printk(KERN_ERR "PT2258 access failed 2\n");
+	return -EIO;
+}
+
+static const DECLARE_TLV_DB_SCALE(pt2258_db_scale, -7900, 100, 0);
+
+int snd_pt2258_build_controls(struct snd_pt2258 *pt)
+{
+	struct snd_kcontrol_new knew;
+	char *names[3] = {
+		"Mic Loopback Playback Volume",
+		"Line Loopback Playback Volume",
+		"CD Loopback Playback Volume"
+	};
+	int i, err;
+
+	for (i = 0; i < 3; ++i) {
+		memset(&knew, 0, sizeof(knew));
+		knew.name = names[i];
+		knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+		knew.count = 1;
+		knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+		    SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+		knew.private_value = 2 * i;
+		knew.info = pt2258_stereo_volume_info;
+		knew.get = pt2258_stereo_volume_get;
+		knew.put = pt2258_stereo_volume_put;
+		knew.tlv.p = pt2258_db_scale;
+
+		err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt));
+		if (err < 0)
+			return err;
+	}
+
+	memset(&knew, 0, sizeof(knew));
+	knew.name = "Loopback Switch";
+	knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	knew.info = pt2258_switch_info;
+	knew.get = pt2258_switch_get;
+	knew.put = pt2258_switch_put;
+	knew.access = 0;
+	err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+EXPORT_SYMBOL(snd_pt2258_reset);
+EXPORT_SYMBOL(snd_pt2258_build_controls);
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index 57371f1..4e3a972 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -358,6 +358,7 @@
 config SND_SB16_CSP
 	bool "Sound Blaster 16/AWE CSP support"
 	depends on (SND_SB16 || SND_SBAWE) && (BROKEN || !PPC)
+	select FW_LOADER
 	help
 	  Say Y here to include support for the CSP core.  This special
 	  coprocessor can do variable tasks like various compression and
@@ -390,6 +391,7 @@
 config SND_WAVEFRONT
 	tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)"
 	depends on SND
+	select FW_LOADER
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
 	select SND_CS4231_LIB
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
index b524e0d..ec9209c 100644
--- a/sound/isa/ad1816a/ad1816a_lib.c
+++ b/sound/isa/ad1816a/ad1816a_lib.c
@@ -906,11 +906,11 @@
 	return change;
 }
 
-static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
 
 static struct snd_kcontrol_new snd_ad1816a_controls[] __devinitdata = {
 AD1816A_DOUBLE("Master Playback Switch", AD1816A_MASTER_ATT, 15, 7, 1, 1),
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
index 666b3bc..8094282 100644
--- a/sound/isa/ad1848/ad1848_lib.c
+++ b/sound/isa/ad1848/ad1848_lib.c
@@ -1223,9 +1223,9 @@
 
 EXPORT_SYMBOL(snd_ad1848_add_ctl_elem);
 
-static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
 
 static struct ad1848_mix_elem snd_ad1848_controls[] = {
 AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1),
diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c
index b680fdd..8ced5e8 100644
--- a/sound/isa/gus/gus_main.c
+++ b/sound/isa/gus/gus_main.c
@@ -294,10 +294,10 @@
 		gus->mix_cntrl_reg |= 4;	/* enable MIC */
 	}
 	dma1 = gus->gf1.dma1;
-	dma1 = dma1 < 0 ? -dma1 : dma1;
+	dma1 = abs(dma1);
 	dma1 = dmas[dma1 & 7];
 	dma2 = gus->gf1.dma2;
-	dma2 = dma2 < 0 ? -dma2 : dma2;
+	dma2 = abs(dma2);
 	dma2 = dmas[dma2 & 7];
 	dma1 |= gus->equal_dma ? 0x40 : (dma2 << 3);
 
@@ -306,7 +306,7 @@
 		return -EINVAL;
 	}
 	irq = gus->gf1.irq;
-	irq = irq < 0 ? -irq : irq;
+	irq = abs(irq);
 	irq = irqs[irq & 0x0f];
 	if (irq == 0) {
 		snd_printk(KERN_ERR "Error! IRQ isn't defined.\n");
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index 419b4eb..1e30713 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -486,8 +486,8 @@
 	return change;
 }
 
-static DECLARE_TLV_DB_SCALE(db_scale_master, -3000, 200, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_master, -3000, 200, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
 
 static struct snd_kcontrol_new snd_opl3sa2_controls[] = {
 OPL3SA2_DOUBLE("Master Playback Switch", 0, 0x07, 0x08, 7, 7, 1, 1),
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c
index fcd6380..3d9d7e0 100644
--- a/sound/isa/sb/sb16_csp.c
+++ b/sound/isa/sb/sb16_csp.c
@@ -161,10 +161,13 @@
  */
 static void snd_sb_csp_free(struct snd_hwdep *hwdep)
 {
+	int i;
 	struct snd_sb_csp *p = hwdep->private_data;
 	if (p) {
 		if (p->running & SNDRV_SB_CSP_ST_RUNNING)
 			snd_sb_csp_stop(p);
+		for (i = 0; i < ARRAY_SIZE(p->csp_programs); ++i)
+			release_firmware(p->csp_programs[i]);
 		kfree(p);
 	}
 }
@@ -687,8 +690,50 @@
 	return err;
 }
 
+#define FIRMWARE_IN_THE_KERNEL
+
+#ifdef FIRMWARE_IN_THE_KERNEL
 #include "sb16_csp_codecs.h"
 
+static const struct firmware snd_sb_csp_static_programs[] = {
+	{ .data = mulaw_main, .size = sizeof mulaw_main },
+	{ .data = alaw_main, .size = sizeof alaw_main },
+	{ .data = ima_adpcm_init, .size = sizeof ima_adpcm_init },
+	{ .data = ima_adpcm_playback, .size = sizeof ima_adpcm_playback },
+	{ .data = ima_adpcm_capture, .size = sizeof ima_adpcm_capture },
+};
+#endif
+
+static int snd_sb_csp_firmware_load(struct snd_sb_csp *p, int index, int flags)
+{
+	static const char *const names[] = {
+		"sb16/mulaw_main.csp",
+		"sb16/alaw_main.csp",
+		"sb16/ima_adpcm_init.csp",
+		"sb16/ima_adpcm_playback.csp",
+		"sb16/ima_adpcm_capture.csp",
+	};
+	const struct firmware *program;
+	int err;
+
+	BUILD_BUG_ON(ARRAY_SIZE(names) != CSP_PROGRAM_COUNT);
+	program = p->csp_programs[index];
+	if (!program) {
+		err = request_firmware(&program, names[index],
+				       p->chip->card->dev);
+		if (err >= 0)
+			p->csp_programs[index] = program;
+		else {
+#ifdef FIRMWARE_IN_THE_KERNEL
+			program = &snd_sb_csp_static_programs[index];
+#else
+			return err;
+#endif
+		}
+	}
+	return snd_sb_csp_load(p, program->data, program->size, flags);
+}
+
 /*
  * autoload hardware codec if necessary
  * return 0 if CSP is loaded and ready to run (p->running != 0)
@@ -708,27 +753,27 @@
 	} else {
 		switch (pcm_sfmt) {
 		case SNDRV_PCM_FORMAT_MU_LAW:
-			err = snd_sb_csp_load(p, &mulaw_main[0], sizeof(mulaw_main), 0);
+			err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_MULAW, 0);
 			p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW;
 			p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE;
 			break;
 		case SNDRV_PCM_FORMAT_A_LAW:
-			err = snd_sb_csp_load(p, &alaw_main[0], sizeof(alaw_main), 0);
+			err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ALAW, 0);
 			p->acc_format = SNDRV_PCM_FMTBIT_A_LAW;
 			p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE;
 			break;
 		case SNDRV_PCM_FORMAT_IMA_ADPCM:
-			err = snd_sb_csp_load(p, &ima_adpcm_init[0], sizeof(ima_adpcm_init),
-					      SNDRV_SB_CSP_LOAD_INITBLOCK);
+			err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ADPCM_INIT,
+						       SNDRV_SB_CSP_LOAD_INITBLOCK);
 			if (err)
 				break;
 			if (play_rec_mode == SNDRV_SB_CSP_MODE_DSP_WRITE) {
-				err = snd_sb_csp_load(p, &ima_adpcm_playback[0],
-						      sizeof(ima_adpcm_playback), 0);
+				err = snd_sb_csp_firmware_load
+					(p, CSP_PROGRAM_ADPCM_PLAYBACK, 0);
 				p->mode = SNDRV_SB_CSP_MODE_DSP_WRITE;
 			} else {
-				err = snd_sb_csp_load(p, &ima_adpcm_capture[0],
-						      sizeof(ima_adpcm_capture), 0);
+				err = snd_sb_csp_firmware_load
+					(p, CSP_PROGRAM_ADPCM_CAPTURE, 0);
 				p->mode = SNDRV_SB_CSP_MODE_DSP_READ;
 			}
 			p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM;
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
index 85db535..e2fdd5f 100644
--- a/sound/isa/wavefront/wavefront.c
+++ b/sound/isa/wavefront/wavefront.c
@@ -402,6 +402,7 @@
 	init_waitqueue_head(&acard->wavefront.interrupt_sleeper);
 	spin_lock_init(&acard->wavefront.midi.open);
 	spin_lock_init(&acard->wavefront.midi.virtual);
+	acard->wavefront.card = card;
 	card->private_free = snd_wavefront_free;
 
 	return card;
diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c
index 4f0846f..15331ed 100644
--- a/sound/isa/wavefront/wavefront_fx.c
+++ b/sound/isa/wavefront/wavefront_fx.c
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/wait.h>
+#include <linux/firmware.h>
 #include <sound/core.h>
 #include <sound/snd_wavefront.h>
 #include <sound/initval.h>
@@ -32,325 +33,17 @@
 #define FX_MSB_TRANSFER 0x02    /* transfer after DSP MSB byte written */
 #define FX_AUTO_INCR    0x04    /* auto-increment DSP address after transfer */
 
-/* weird stuff, derived from port I/O tracing with dosemu */
+#define WAIT_IDLE	0xff
 
-static unsigned char page_zero[] __devinitdata = {
-0x01, 0x7c, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00,
-0x11, 0x00, 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x13, 0x00, 0x00,
-0x00, 0x14, 0x02, 0x76, 0x00, 0x60, 0x00, 0x80, 0x02, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x19,
-0x01, 0x1a, 0x01, 0x20, 0x01, 0x40, 0x01, 0x17, 0x00, 0x00, 0x01,
-0x80, 0x01, 0x20, 0x00, 0x10, 0x01, 0xa0, 0x03, 0xd1, 0x00, 0x00,
-0x01, 0xf2, 0x02, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf4, 0x02,
-0xe0, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17,
-0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x00, 0x00,
-0x40, 0x00, 0x00, 0x00, 0x71, 0x02, 0x00, 0x00, 0x60, 0x00, 0x00,
-0x00, 0x92, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb3, 0x02,
-0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x40,
-0x00, 0x80, 0x00, 0xf5, 0x00, 0x20, 0x00, 0x70, 0x00, 0xa0, 0x02,
-0x11, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
-0x02, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x17, 0x00, 0x1b, 0x00,
-0x1d, 0x02, 0xdf
-};
+#define FIRMWARE_IN_THE_KERNEL
 
-static unsigned char page_one[] __devinitdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x19, 0x00,
-0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd8, 0x00, 0x00,
-0x02, 0x20, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01,
-0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x60,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x80, 0x00,
-0x00, 0x02, 0xfb, 0x02, 0xa0, 0x00, 0x00, 0x00, 0x1b, 0x02, 0xd7,
-0x00, 0x00, 0x02, 0xf7, 0x03, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00,
-0x1c, 0x03, 0x3c, 0x00, 0x00, 0x03, 0x3f, 0x00, 0x00, 0x03, 0xc0,
-0x00, 0x00, 0x03, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x5d, 0x00,
-0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x03, 0xc0,
-0x00, 0x00, 0x03, 0x9e, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03,
-0xbe, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-0xdb, 0x00, 0x00, 0x02, 0xdb, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00,
-0x02, 0xfb, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x40, 0x02, 0xfb, 0x02,
-0x60, 0x00, 0x1b
+#ifdef FIRMWARE_IN_THE_KERNEL
+#include "yss225.c"
+static const struct firmware yss225_registers_firmware = {
+	.data = (u8 *)yss225_registers,
+	.size = sizeof yss225_registers
 };
-
-static unsigned char page_two[] __devinitdata = {
-0xc4, 0x00, 0x44, 0x07, 0x44, 0x00, 0x40, 0x25, 0x01, 0x06, 0xc4,
-0x07, 0x40, 0x25, 0x01, 0x00, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x07,
-0x05, 0x05, 0x05, 0x04, 0x07, 0x05, 0x04, 0x07, 0x05, 0x44, 0x46,
-0x44, 0x46, 0x46, 0x07, 0x05, 0x44, 0x46, 0x05, 0x46, 0x05, 0x46,
-0x05, 0x46, 0x05, 0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07,
-0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07, 0x44, 0x05, 0x05,
-0x05, 0x44, 0x05, 0x05, 0x05, 0x46, 0x05, 0x46, 0x05, 0x46, 0x05,
-0x46, 0x05, 0x46, 0x07, 0x46, 0x07, 0x44
-};
-
-static unsigned char page_three[] __devinitdata = {
-0x07, 0x40, 0x00, 0x00, 0x00, 0x47, 0x00, 0x40, 0x00, 0x40, 0x06,
-0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
-0xc0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00,
-0x60, 0x00, 0x70, 0x00, 0x40, 0x00, 0x40, 0x00, 0x42, 0x00, 0x40,
-0x00, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
-0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
-0x00, 0x42, 0x00, 0x40, 0x00, 0x42, 0x00, 0x02, 0x00, 0x02, 0x00,
-0x02, 0x00, 0x42, 0x00, 0xc0, 0x00, 0x40
-};
-
-static unsigned char page_four[] __devinitdata = {
-0x63, 0x03, 0x26, 0x02, 0x2c, 0x00, 0x24, 0x00, 0x2e, 0x02, 0x02,
-0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
-0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x60, 0x00,
-0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60,
-0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00,
-0x20, 0x00, 0x22, 0x02, 0x22, 0x02, 0x20, 0x00, 0x60, 0x00, 0x22,
-0x02, 0x62, 0x02, 0x20, 0x01, 0x21, 0x01
-};
-
-static unsigned char page_six[] __devinitdata = {
-0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00,
-0x00, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0e,
-0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x00,
-0x16, 0x00, 0x00, 0x18, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x1c, 0x00,
-0x00, 0x1e, 0x00, 0x00, 0x20, 0x00, 0x00, 0x22, 0x00, 0x00, 0x24,
-0x00, 0x00, 0x26, 0x00, 0x00, 0x28, 0x00, 0x00, 0x2a, 0x00, 0x00,
-0x2c, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x30, 0x00, 0x00, 0x32, 0x00,
-0x00, 0x34, 0x00, 0x00, 0x36, 0x00, 0x00, 0x38, 0x00, 0x00, 0x3a,
-0x00, 0x00, 0x3c, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x40, 0x00, 0x00,
-0x42, 0x03, 0x00, 0x44, 0x01, 0x00, 0x46, 0x0a, 0x21, 0x48, 0x0d,
-0x23, 0x4a, 0x23, 0x1b, 0x4c, 0x37, 0x8f, 0x4e, 0x45, 0x77, 0x50,
-0x52, 0xe2, 0x52, 0x1c, 0x92, 0x54, 0x1c, 0x52, 0x56, 0x07, 0x00,
-0x58, 0x2f, 0xc6, 0x5a, 0x0b, 0x00, 0x5c, 0x30, 0x06, 0x5e, 0x17,
-0x00, 0x60, 0x3d, 0xda, 0x62, 0x29, 0x00, 0x64, 0x3e, 0x41, 0x66,
-0x39, 0x00, 0x68, 0x4c, 0x48, 0x6a, 0x49, 0x00, 0x6c, 0x4c, 0x6c,
-0x6e, 0x11, 0xd2, 0x70, 0x16, 0x0c, 0x72, 0x00, 0x00, 0x74, 0x00,
-0x80, 0x76, 0x0f, 0x00, 0x78, 0x00, 0x80, 0x7a, 0x13, 0x00, 0x7c,
-0x80, 0x00, 0x7e, 0x80, 0x80
-};
-
-static unsigned char page_seven[] __devinitdata = {
-0x0f, 0xff, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
-0x08, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f,
-0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff,
-0x0f, 0xff, 0x0f, 0xff, 0x02, 0xe9, 0x06, 0x8c, 0x06, 0x8c, 0x0f,
-0xff, 0x1a, 0x75, 0x0d, 0x8b, 0x04, 0xe9, 0x0b, 0x16, 0x1a, 0x38,
-0x0d, 0xc8, 0x04, 0x6f, 0x0b, 0x91, 0x0f, 0xff, 0x06, 0x40, 0x06,
-0x40, 0x02, 0x8f, 0x0f, 0xff, 0x06, 0x62, 0x06, 0x62, 0x02, 0x7b,
-0x0f, 0xff, 0x06, 0x97, 0x06, 0x97, 0x02, 0x52, 0x0f, 0xff, 0x06,
-0xf6, 0x06, 0xf6, 0x02, 0x19, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55,
-0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x14,
-0xda, 0x0d, 0x93, 0x04, 0xda, 0x05, 0x93, 0x14, 0xda, 0x0d, 0x93,
-0x04, 0xda, 0x05, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x02, 0x00
-};
-
-static unsigned char page_zero_v2[] __devinitdata = {
-0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static unsigned char page_one_v2[] __devinitdata = {
-0x01, 0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static unsigned char page_two_v2[] __devinitdata = {
-0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00
-};
-static unsigned char page_three_v2[] __devinitdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00
-};
-static unsigned char page_four_v2[] __devinitdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00
-};
-
-static unsigned char page_seven_v2[] __devinitdata = {
-0x0f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static unsigned char mod_v2[] __devinitdata = {
-0x01, 0x00, 0x02, 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 0x02, 0x02,
-0x00, 0x01, 0x03, 0x02, 0x00, 0x01, 0x04, 0x02, 0x00, 0x01, 0x05,
-0x02, 0x00, 0x01, 0x06, 0x02, 0x00, 0x01, 0x07, 0x02, 0x00, 0xb0,
-0x20, 0xb1, 0x20, 0xb2, 0x20, 0xb3, 0x20, 0xb4, 0x20, 0xb5, 0x20,
-0xb6, 0x20, 0xb7, 0x20, 0xf0, 0x20, 0xf1, 0x20, 0xf2, 0x20, 0xf3,
-0x20, 0xf4, 0x20, 0xf5, 0x20, 0xf6, 0x20, 0xf7, 0x20, 0x10, 0xff,
-0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x14, 0xff, 0x15, 0xff, 0x16,
-0xff, 0x17, 0xff, 0x20, 0xff, 0x21, 0xff, 0x22, 0xff, 0x23, 0xff,
-0x24, 0xff, 0x25, 0xff, 0x26, 0xff, 0x27, 0xff, 0x30, 0x00, 0x31,
-0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00,
-0x37, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44,
-0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x50, 0x00, 0x51, 0x00,
-0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57,
-0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00,
-0x65, 0x00, 0x66, 0x00, 0x67, 0x00, 0x70, 0xc0, 0x71, 0xc0, 0x72,
-0xc0, 0x73, 0xc0, 0x74, 0xc0, 0x75, 0xc0, 0x76, 0xc0, 0x77, 0xc0,
-0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85,
-0x00, 0x86, 0x00, 0x87, 0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00,
-0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0xa0,
-0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00,
-0xa6, 0x00, 0xa7, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3,
-0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xd0, 0x00,
-0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6,
-0x00, 0xd7, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe3, 0x00,
-0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0x01, 0x00, 0x02,
-0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x03,
-0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x05, 0x02, 0x01, 0x01,
-0x06, 0x02, 0x01, 0x01, 0x07, 0x02, 0x01
-};
-static unsigned char coefficients[] __devinitdata = {
-0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x03,
-0x11, 0x00, 0x4d, 0x01, 0x32, 0x07, 0x46, 0x00, 0x00, 0x07, 0x49,
-0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x01,
-0x40, 0x02, 0x40, 0x01, 0x41, 0x02, 0x60, 0x07, 0x40, 0x00, 0x00,
-0x07, 0x41, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00, 0x07, 0x4a, 0x00,
-0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x4a, 0x01, 0x20, 0x07, 0x47,
-0x00, 0x00, 0x07, 0x4a, 0x00, 0x00, 0x07, 0x7c, 0x00, 0x00, 0x07,
-0x7e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1c, 0x07, 0x7c, 0x00, 0x00,
-0x07, 0x7e, 0x00, 0x00, 0x07, 0x44, 0x00, 0x00, 0x00, 0x44, 0x01,
-0x00, 0x07, 0x44, 0x00, 0x00, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43,
-0x00, 0x00, 0x00, 0x42, 0x01, 0x1a, 0x00, 0x43, 0x01, 0x20, 0x07,
-0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00,
-0x07, 0x41, 0x00, 0x00, 0x01, 0x40, 0x02, 0x40, 0x01, 0x41, 0x02,
-0x60, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x44,
-0x0f, 0xff, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07,
-0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x51, 0x06, 0x40,
-0x07, 0x50, 0x06, 0x40, 0x07, 0x4f, 0x03, 0x81, 0x07, 0x53, 0x1a,
-0x76, 0x07, 0x54, 0x0d, 0x8b, 0x07, 0x55, 0x04, 0xe9, 0x07, 0x56,
-0x0b, 0x17, 0x07, 0x57, 0x1a, 0x38, 0x07, 0x58, 0x0d, 0xc9, 0x07,
-0x59, 0x04, 0x6f, 0x07, 0x5a, 0x0b, 0x91, 0x07, 0x73, 0x14, 0xda,
-0x07, 0x74, 0x0d, 0x93, 0x07, 0x75, 0x04, 0xd9, 0x07, 0x76, 0x05,
-0x93, 0x07, 0x77, 0x14, 0xda, 0x07, 0x78, 0x0d, 0x93, 0x07, 0x79,
-0x04, 0xd9, 0x07, 0x7a, 0x05, 0x93, 0x07, 0x5e, 0x03, 0x68, 0x07,
-0x5c, 0x04, 0x31, 0x07, 0x5d, 0x04, 0x31, 0x07, 0x62, 0x03, 0x52,
-0x07, 0x60, 0x04, 0x76, 0x07, 0x61, 0x04, 0x76, 0x07, 0x66, 0x03,
-0x2e, 0x07, 0x64, 0x04, 0xda, 0x07, 0x65, 0x04, 0xda, 0x07, 0x6a,
-0x02, 0xf6, 0x07, 0x68, 0x05, 0x62, 0x07, 0x69, 0x05, 0x62, 0x06,
-0x46, 0x0a, 0x22, 0x06, 0x48, 0x0d, 0x24, 0x06, 0x6e, 0x11, 0xd3,
-0x06, 0x70, 0x15, 0xcb, 0x06, 0x52, 0x20, 0x93, 0x06, 0x54, 0x20,
-0x54, 0x06, 0x4a, 0x27, 0x1d, 0x06, 0x58, 0x2f, 0xc8, 0x06, 0x5c,
-0x30, 0x07, 0x06, 0x4c, 0x37, 0x90, 0x06, 0x60, 0x3d, 0xdb, 0x06,
-0x64, 0x3e, 0x42, 0x06, 0x4e, 0x45, 0x78, 0x06, 0x68, 0x4c, 0x48,
-0x06, 0x6c, 0x4c, 0x6c, 0x06, 0x50, 0x52, 0xe2, 0x06, 0x42, 0x02,
-0xba
-};
-static unsigned char coefficients2[] __devinitdata = {
-0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x45, 0x0f,
-0xff, 0x07, 0x48, 0x0f, 0xff, 0x07, 0x7b, 0x04, 0xcc, 0x07, 0x7d,
-0x04, 0xcc, 0x07, 0x7c, 0x00, 0x00, 0x07, 0x7e, 0x00, 0x00, 0x07,
-0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00,
-0x07, 0x4a, 0x00, 0x00, 0x07, 0x4c, 0x00, 0x00, 0x07, 0x4e, 0x00, 0x00
-};
-static unsigned char coefficients3[] __devinitdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00, 0x51, 0x00,
-0x51, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xcc,
-0x00, 0xcc, 0x00, 0xf5, 0x00, 0xf5, 0x01, 0x1e, 0x01, 0x1e, 0x01,
-0x47, 0x01, 0x47, 0x01, 0x70, 0x01, 0x70, 0x01, 0x99, 0x01, 0x99,
-0x01, 0xc2, 0x01, 0xc2, 0x01, 0xeb, 0x01, 0xeb, 0x02, 0x14, 0x02,
-0x14, 0x02, 0x3d, 0x02, 0x3d, 0x02, 0x66, 0x02, 0x66, 0x02, 0x8f,
-0x02, 0x8f, 0x02, 0xb8, 0x02, 0xb8, 0x02, 0xe1, 0x02, 0xe1, 0x03,
-0x0a, 0x03, 0x0a, 0x03, 0x33, 0x03, 0x33, 0x03, 0x5c, 0x03, 0x5c,
-0x03, 0x85, 0x03, 0x85, 0x03, 0xae, 0x03, 0xae, 0x03, 0xd7, 0x03,
-0xd7, 0x04, 0x00, 0x04, 0x00, 0x04, 0x28, 0x04, 0x28, 0x04, 0x51,
-0x04, 0x51, 0x04, 0x7a, 0x04, 0x7a, 0x04, 0xa3, 0x04, 0xa3, 0x04,
-0xcc, 0x04, 0xcc, 0x04, 0xf5, 0x04, 0xf5, 0x05, 0x1e, 0x05, 0x1e,
-0x05, 0x47, 0x05, 0x47, 0x05, 0x70, 0x05, 0x70, 0x05, 0x99, 0x05,
-0x99, 0x05, 0xc2, 0x05, 0xc2, 0x05, 0xeb, 0x05, 0xeb, 0x06, 0x14,
-0x06, 0x14, 0x06, 0x3d, 0x06, 0x3d, 0x06, 0x66, 0x06, 0x66, 0x06,
-0x8f, 0x06, 0x8f, 0x06, 0xb8, 0x06, 0xb8, 0x06, 0xe1, 0x06, 0xe1,
-0x07, 0x0a, 0x07, 0x0a, 0x07, 0x33, 0x07, 0x33, 0x07, 0x5c, 0x07,
-0x5c, 0x07, 0x85, 0x07, 0x85, 0x07, 0xae, 0x07, 0xae, 0x07, 0xd7,
-0x07, 0xd7, 0x08, 0x00, 0x08, 0x00, 0x08, 0x28, 0x08, 0x28, 0x08,
-0x51, 0x08, 0x51, 0x08, 0x7a, 0x08, 0x7a, 0x08, 0xa3, 0x08, 0xa3,
-0x08, 0xcc, 0x08, 0xcc, 0x08, 0xf5, 0x08, 0xf5, 0x09, 0x1e, 0x09,
-0x1e, 0x09, 0x47, 0x09, 0x47, 0x09, 0x70, 0x09, 0x70, 0x09, 0x99,
-0x09, 0x99, 0x09, 0xc2, 0x09, 0xc2, 0x09, 0xeb, 0x09, 0xeb, 0x0a,
-0x14, 0x0a, 0x14, 0x0a, 0x3d, 0x0a, 0x3d, 0x0a, 0x66, 0x0a, 0x66,
-0x0a, 0x8f, 0x0a, 0x8f, 0x0a, 0xb8, 0x0a, 0xb8, 0x0a, 0xe1, 0x0a,
-0xe1, 0x0b, 0x0a, 0x0b, 0x0a, 0x0b, 0x33, 0x0b, 0x33, 0x0b, 0x5c,
-0x0b, 0x5c, 0x0b, 0x85, 0x0b, 0x85, 0x0b, 0xae, 0x0b, 0xae, 0x0b,
-0xd7, 0x0b, 0xd7, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x28, 0x0c, 0x28,
-0x0c, 0x51, 0x0c, 0x51, 0x0c, 0x7a, 0x0c, 0x7a, 0x0c, 0xa3, 0x0c,
-0xa3, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xf5, 0x0c, 0xf5, 0x0d, 0x1e,
-0x0d, 0x1e, 0x0d, 0x47, 0x0d, 0x47, 0x0d, 0x70, 0x0d, 0x70, 0x0d,
-0x99, 0x0d, 0x99, 0x0d, 0xc2, 0x0d, 0xc2, 0x0d, 0xeb, 0x0d, 0xeb,
-0x0e, 0x14, 0x0e, 0x14, 0x0e, 0x3d, 0x0e, 0x3d, 0x0e, 0x66, 0x0e,
-0x66, 0x0e, 0x8f, 0x0e, 0x8f, 0x0e, 0xb8, 0x0e, 0xb8, 0x0e, 0xe1,
-0x0e, 0xe1, 0x0f, 0x0a, 0x0f, 0x0a, 0x0f, 0x33, 0x0f, 0x33, 0x0f,
-0x5c, 0x0f, 0x5c, 0x0f, 0x85, 0x0f, 0x85, 0x0f, 0xae, 0x0f, 0xae,
-0x0f, 0xd7, 0x0f, 0xd7, 0x0f, 0xff, 0x0f, 0xff
-};
+#endif
 
 static int
 wavefront_fx_idle (snd_wavefront_t *dev)
@@ -555,465 +248,56 @@
    of the port I/O done, using the Yamaha faxback document as a guide
    to add more logic to the code. Its really pretty weird.
 
-   There was an alternative approach of just dumping the whole I/O
+   This is the approach of just dumping the whole I/O
    sequence as a series of port/value pairs and a simple loop
-   that output it. However, I hope that eventually I'll get more
-   control over what this code does, and so I tried to stick with
-   a somewhat "algorithmic" approach.
+   that outputs it.
 */
 
-
 int __devinit
 snd_wavefront_fx_start (snd_wavefront_t *dev)
-
 {
-	unsigned int i, j;
+	unsigned int i;
+	int err;
+	const struct firmware *firmware;
 
-	/* Set all bits for all channels on the MOD unit to zero */
-	/* XXX But why do this twice ? */
+	if (dev->fx_initialized)
+		return 0;
 
-	for (j = 0; j < 2; j++) {
-		for (i = 0x10; i <= 0xff; i++) {
-	    
-			if (!wavefront_fx_idle (dev)) {
-				return (-1);
+	err = request_firmware(&firmware, "yamaha/yss225_registers.bin",
+			       dev->card->dev);
+	if (err < 0) {
+#ifdef FIRMWARE_IN_THE_KERNEL
+		firmware = &yss225_registers_firmware;
+#else
+		err = -1;
+		goto out;
+#endif
+	}
+
+	for (i = 0; i + 1 < firmware->size; i += 2) {
+		if (firmware->data[i] >= 8 && firmware->data[i] < 16) {
+			outb(firmware->data[i + 1],
+			     dev->base + firmware->data[i]);
+		} else if (firmware->data[i] == WAIT_IDLE) {
+			if (!wavefront_fx_idle(dev)) {
+				err = -1;
+				goto out;
 			}
-	    
-			outb (i, dev->fx_mod_addr);
-			outb (0x0, dev->fx_mod_data);
+		} else {
+			snd_printk(KERN_ERR "invalid address"
+				   " in register data\n");
+			err = -1;
+			goto out;
 		}
 	}
 
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x02, dev->fx_op);                        /* mute on */
+	dev->fx_initialized = 1;
+	err = 0;
 
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x07, dev->fx_dsp_page);
-	outb (0x44, dev->fx_dsp_addr);
-	outb (0x00, dev->fx_dsp_msb);
-	outb (0x00, dev->fx_dsp_lsb);
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x07, dev->fx_dsp_page);
-	outb (0x42, dev->fx_dsp_addr);
-	outb (0x00, dev->fx_dsp_msb);
-	outb (0x00, dev->fx_dsp_lsb);
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x07, dev->fx_dsp_page);
-	outb (0x43, dev->fx_dsp_addr);
-	outb (0x00, dev->fx_dsp_msb);
-	outb (0x00, dev->fx_dsp_lsb);
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x07, dev->fx_dsp_page);
-	outb (0x7c, dev->fx_dsp_addr);
-	outb (0x00, dev->fx_dsp_msb);
-	outb (0x00, dev->fx_dsp_lsb);
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x07, dev->fx_dsp_page);
-	outb (0x7e, dev->fx_dsp_addr);
-	outb (0x00, dev->fx_dsp_msb);
-	outb (0x00, dev->fx_dsp_lsb);
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x07, dev->fx_dsp_page);
-	outb (0x46, dev->fx_dsp_addr);
-	outb (0x00, dev->fx_dsp_msb);
-	outb (0x00, dev->fx_dsp_lsb);
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x07, dev->fx_dsp_page);
-	outb (0x49, dev->fx_dsp_addr);
-	outb (0x00, dev->fx_dsp_msb);
-	outb (0x00, dev->fx_dsp_lsb);
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x07, dev->fx_dsp_page);
-	outb (0x47, dev->fx_dsp_addr);
-	outb (0x00, dev->fx_dsp_msb);
-	outb (0x00, dev->fx_dsp_lsb);
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x07, dev->fx_dsp_page);
-	outb (0x4a, dev->fx_dsp_addr);
-	outb (0x00, dev->fx_dsp_msb);
-	outb (0x00, dev->fx_dsp_lsb);
-
-	/* either because of stupidity by TB's programmers, or because it
-	   actually does something, rezero the MOD page.
-	*/
-	for (i = 0x10; i <= 0xff; i++) {
-	
-		if (!wavefront_fx_idle (dev)) {
-			return (-1);
-		}
-	
-		outb (i, dev->fx_mod_addr);
-		outb (0x0, dev->fx_mod_data);
-	}
-	/* load page zero */
-
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
-	outb (0x00, dev->fx_dsp_page);
-	outb (0x00, dev->fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_zero); i += 2) {
-		outb (page_zero[i], dev->fx_dsp_msb);
-		outb (page_zero[i+1], dev->fx_dsp_lsb);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	/* Now load page one */
-
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
-	outb (0x01, dev->fx_dsp_page);
-	outb (0x00, dev->fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_one); i += 2) {
-		outb (page_one[i], dev->fx_dsp_msb);
-		outb (page_one[i+1], dev->fx_dsp_lsb);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-    
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
-	outb (0x02, dev->fx_dsp_page);
-	outb (0x00, dev->fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_two); i++) {
-		outb (page_two[i], dev->fx_dsp_lsb);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-    
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
-	outb (0x03, dev->fx_dsp_page);
-	outb (0x00, dev->fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_three); i++) {
-		outb (page_three[i], dev->fx_dsp_lsb);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-    
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
-	outb (0x04, dev->fx_dsp_page);
-	outb (0x00, dev->fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_four); i++) {
-		outb (page_four[i], dev->fx_dsp_lsb);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	/* Load memory area (page six) */
-    
-	outb (FX_LSB_TRANSFER, dev->fx_lcr); 
-	outb (0x06, dev->fx_dsp_page); 
-
-	for (i = 0; i < sizeof (page_six); i += 3) {
-		outb (page_six[i], dev->fx_dsp_addr);
-		outb (page_six[i+1], dev->fx_dsp_msb);
-		outb (page_six[i+2], dev->fx_dsp_lsb);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-    
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
-	outb (0x07, dev->fx_dsp_page);
-	outb (0x00, dev->fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_seven); i += 2) {
-		outb (page_seven[i], dev->fx_dsp_msb);
-		outb (page_seven[i+1], dev->fx_dsp_lsb);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	/* Now setup the MOD area. We do this algorithmically in order to
-	   save a little data space. It could be done in the same fashion
-	   as the "pages".
-	*/
-
-	for (i = 0x00; i <= 0x0f; i++) {
-		outb (0x01, dev->fx_mod_addr);
-		outb (i, dev->fx_mod_data);
-		if (!wavefront_fx_idle (dev)) return (-1);
-		outb (0x02, dev->fx_mod_addr);
-		outb (0x00, dev->fx_mod_data);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	for (i = 0xb0; i <= 0xbf; i++) {
-		outb (i, dev->fx_mod_addr);
-		outb (0x20, dev->fx_mod_data);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	for (i = 0xf0; i <= 0xff; i++) {
-		outb (i, dev->fx_mod_addr);
-		outb (0x20, dev->fx_mod_data);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	for (i = 0x10; i <= 0x1d; i++) {
-		outb (i, dev->fx_mod_addr);
-		outb (0xff, dev->fx_mod_data);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	outb (0x1e, dev->fx_mod_addr);
-	outb (0x40, dev->fx_mod_data);
-	if (!wavefront_fx_idle (dev)) return (-1);
-
-	for (i = 0x1f; i <= 0x2d; i++) {
-		outb (i, dev->fx_mod_addr);
-		outb (0xff, dev->fx_mod_data);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	outb (0x2e, dev->fx_mod_addr);
-	outb (0x00, dev->fx_mod_data);
-	if (!wavefront_fx_idle (dev)) return (-1);
-
-	for (i = 0x2f; i <= 0x3e; i++) {
-		outb (i, dev->fx_mod_addr);
-		outb (0x00, dev->fx_mod_data);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	outb (0x3f, dev->fx_mod_addr);
-	outb (0x20, dev->fx_mod_data);
-	if (!wavefront_fx_idle (dev)) return (-1);
-
-	for (i = 0x40; i <= 0x4d; i++) {
-		outb (i, dev->fx_mod_addr);
-		outb (0x00, dev->fx_mod_data);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	outb (0x4e, dev->fx_mod_addr);
-	outb (0x0e, dev->fx_mod_data);
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x4f, dev->fx_mod_addr);
-	outb (0x0e, dev->fx_mod_data);
-	if (!wavefront_fx_idle (dev)) return (-1);
-
-
-	for (i = 0x50; i <= 0x6b; i++) {
-		outb (i, dev->fx_mod_addr);
-		outb (0x00, dev->fx_mod_data);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	outb (0x6c, dev->fx_mod_addr);
-	outb (0x40, dev->fx_mod_data);
-	if (!wavefront_fx_idle (dev)) return (-1);
-
-	outb (0x6d, dev->fx_mod_addr);
-	outb (0x00, dev->fx_mod_data);
-	if (!wavefront_fx_idle (dev)) return (-1);
-
-	outb (0x6e, dev->fx_mod_addr);
-	outb (0x40, dev->fx_mod_data);
-	if (!wavefront_fx_idle (dev)) return (-1);
-
-	outb (0x6f, dev->fx_mod_addr);
-	outb (0x40, dev->fx_mod_data);
-	if (!wavefront_fx_idle (dev)) return (-1);
-
-	for (i = 0x70; i <= 0x7f; i++) {
-		outb (i, dev->fx_mod_addr);
-		outb (0xc0, dev->fx_mod_data);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-    
-	for (i = 0x80; i <= 0xaf; i++) {
-		outb (i, dev->fx_mod_addr);
-		outb (0x00, dev->fx_mod_data);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	for (i = 0xc0; i <= 0xdd; i++) {
-		outb (i, dev->fx_mod_addr);
-		outb (0x00, dev->fx_mod_data);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	outb (0xde, dev->fx_mod_addr);
-	outb (0x10, dev->fx_mod_data);
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0xdf, dev->fx_mod_addr);
-	outb (0x10, dev->fx_mod_data);
-	if (!wavefront_fx_idle (dev)) return (-1);
-
-	for (i = 0xe0; i <= 0xef; i++) {
-		outb (i, dev->fx_mod_addr);
-		outb (0x00, dev->fx_mod_data);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	for (i = 0x00; i <= 0x0f; i++) {
-		outb (0x01, dev->fx_mod_addr);
-		outb (i, dev->fx_mod_data);
-		outb (0x02, dev->fx_mod_addr);
-		outb (0x01, dev->fx_mod_data);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	outb (0x02, dev->fx_op); /* mute on */
-
-	/* Now set the coefficients and so forth for the programs above */
-
-	for (i = 0; i < sizeof (coefficients); i += 4) {
-		outb (coefficients[i], dev->fx_dsp_page);
-		outb (coefficients[i+1], dev->fx_dsp_addr);
-		outb (coefficients[i+2], dev->fx_dsp_msb);
-		outb (coefficients[i+3], dev->fx_dsp_lsb);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	/* Some settings (?) that are too small to bundle into loops */
-
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x1e, dev->fx_mod_addr);
-	outb (0x14, dev->fx_mod_data);
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0xde, dev->fx_mod_addr);
-	outb (0x20, dev->fx_mod_data);
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0xdf, dev->fx_mod_addr);
-	outb (0x20, dev->fx_mod_data);
-    
-	/* some more coefficients */
-
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x06, dev->fx_dsp_page);
-	outb (0x78, dev->fx_dsp_addr);
-	outb (0x00, dev->fx_dsp_msb);
-	outb (0x40, dev->fx_dsp_lsb);
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x07, dev->fx_dsp_page);
-	outb (0x03, dev->fx_dsp_addr);
-	outb (0x0f, dev->fx_dsp_msb);
-	outb (0xff, dev->fx_dsp_lsb);
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x07, dev->fx_dsp_page);
-	outb (0x0b, dev->fx_dsp_addr);
-	outb (0x0f, dev->fx_dsp_msb);
-	outb (0xff, dev->fx_dsp_lsb);
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x07, dev->fx_dsp_page);
-	outb (0x02, dev->fx_dsp_addr);
-	outb (0x00, dev->fx_dsp_msb);
-	outb (0x00, dev->fx_dsp_lsb);
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x07, dev->fx_dsp_page);
-	outb (0x0a, dev->fx_dsp_addr);
-	outb (0x00, dev->fx_dsp_msb);
-	outb (0x00, dev->fx_dsp_lsb);
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x07, dev->fx_dsp_page);
-	outb (0x46, dev->fx_dsp_addr);
-	outb (0x00, dev->fx_dsp_msb);
-	outb (0x00, dev->fx_dsp_lsb);
-	if (!wavefront_fx_idle (dev)) return (-1);
-	outb (0x07, dev->fx_dsp_page);
-	outb (0x49, dev->fx_dsp_addr);
-	outb (0x00, dev->fx_dsp_msb);
-	outb (0x00, dev->fx_dsp_lsb);
-    
-	/* Now, for some strange reason, lets reload every page
-	   and all the coefficients over again. I have *NO* idea
-	   why this is done. I do know that no sound is produced
-	   is this phase is omitted.
-	*/
-
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
-	outb (0x00, dev->fx_dsp_page);  
-	outb (0x10, dev->fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_zero_v2); i += 2) {
-		outb (page_zero_v2[i], dev->fx_dsp_msb);
-		outb (page_zero_v2[i+1], dev->fx_dsp_lsb);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-    
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
-	outb (0x01, dev->fx_dsp_page);
-	outb (0x10, dev->fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_one_v2); i += 2) {
-		outb (page_one_v2[i], dev->fx_dsp_msb);
-		outb (page_one_v2[i+1], dev->fx_dsp_lsb);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-    
-	if (!wavefront_fx_idle (dev)) return (-1);
-	if (!wavefront_fx_idle (dev)) return (-1);
-    
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
-	outb (0x02, dev->fx_dsp_page);
-	outb (0x10, dev->fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_two_v2); i++) {
-		outb (page_two_v2[i], dev->fx_dsp_lsb);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
-	outb (0x03, dev->fx_dsp_page);
-	outb (0x10, dev->fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_three_v2); i++) {
-		outb (page_three_v2[i], dev->fx_dsp_lsb);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-    
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
-	outb (0x04, dev->fx_dsp_page);
-	outb (0x10, dev->fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_four_v2); i++) {
-		outb (page_four_v2[i], dev->fx_dsp_lsb);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-    
-	outb (FX_LSB_TRANSFER, dev->fx_lcr);
-	outb (0x06, dev->fx_dsp_page);
-
-	/* Page six v.2 is algorithmic */
-    
-	for (i = 0x10; i <= 0x3e; i += 2) {
-		outb (i, dev->fx_dsp_addr);
-		outb (0x00, dev->fx_dsp_msb);
-		outb (0x00, dev->fx_dsp_lsb);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr);
-	outb (0x07, dev->fx_dsp_page);
-	outb (0x10, dev->fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_seven_v2); i += 2) {
-		outb (page_seven_v2[i], dev->fx_dsp_msb);
-		outb (page_seven_v2[i+1], dev->fx_dsp_lsb);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	for (i = 0x00; i < sizeof(mod_v2); i += 2) {
-		outb (mod_v2[i], dev->fx_mod_addr);
-		outb (mod_v2[i+1], dev->fx_mod_data);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	for (i = 0; i < sizeof (coefficients2); i += 4) {
-		outb (coefficients2[i], dev->fx_dsp_page);
-		outb (coefficients2[i+1], dev->fx_dsp_addr);
-		outb (coefficients2[i+2], dev->fx_dsp_msb);
-		outb (coefficients2[i+3], dev->fx_dsp_lsb);
-		if (!wavefront_fx_idle (dev)) return (-1);
-	}
-
-	for (i = 0; i < sizeof (coefficients3); i += 2) {
-		int x;
-
-		outb (0x07, dev->fx_dsp_page);
-		x = (i % 4) ? 0x4e : 0x4c;
-		outb (x, dev->fx_dsp_addr);
-		outb (coefficients3[i], dev->fx_dsp_msb);
-		outb (coefficients3[i+1], dev->fx_dsp_lsb);
-	}
-
-	outb (0x00, dev->fx_op); /* mute off */
-	if (!wavefront_fx_idle (dev)) return (-1);
-
-	return (0);
+out:
+#ifdef FIRMWARE_IN_THE_KERNEL
+	if (firmware != &yss225_registers_firmware)
+#endif
+		release_firmware(firmware);
+	return err;
 }
diff --git a/sound/isa/wavefront/yss225.c b/sound/isa/wavefront/yss225.c
new file mode 100644
index 0000000..9f6be3f
--- /dev/null
+++ b/sound/isa/wavefront/yss225.c
@@ -0,0 +1,2739 @@
+/*
+ *  Copyright (c) 1998-2002 by Paul Davis <pbd@op.net>
+ *
+ *  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
+ */
+
+/* weird stuff, derived from port I/O tracing with dosemu */
+
+static const struct {
+	unsigned char addr;
+	unsigned char data;
+} yss225_registers[] __devinitdata = {
+/* Set all bits for all channels on the MOD unit to zero */
+{ WAIT_IDLE }, { 0xe, 0x10 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x11 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x12 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x13 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x14 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x15 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x16 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x17 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x18 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x19 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x20 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x21 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x22 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x23 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x24 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x25 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x26 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x27 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x28 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x29 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x30 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x31 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x32 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x33 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x34 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x35 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x36 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x37 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x38 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x39 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x40 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x41 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x42 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x43 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x44 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x45 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x46 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x47 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x48 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x49 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x50 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x51 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x52 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x53 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x54 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x55 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x56 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x57 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x58 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x59 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x60 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x61 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x62 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x63 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x64 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x65 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x66 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x67 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x68 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x69 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x70 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x71 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x72 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x73 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x74 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x75 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x76 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x77 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x78 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x79 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x80 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x81 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x82 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x83 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x84 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x85 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x86 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x87 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x88 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x89 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x90 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x91 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x92 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x93 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x94 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x95 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x96 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x97 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x98 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x99 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xaa }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xab }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xac }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xad }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xae }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xaf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xba }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbe }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xca }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xce }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xda }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xea }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xeb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xec }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xed }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xee }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xef }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfa }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfe }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xff }, { 0xf, 0x00 },
+
+/* XXX But why do this twice? */
+{ WAIT_IDLE }, { 0xe, 0x10 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x11 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x12 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x13 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x14 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x15 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x16 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x17 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x18 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x19 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x20 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x21 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x22 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x23 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x24 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x25 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x26 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x27 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x28 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x29 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x30 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x31 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x32 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x33 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x34 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x35 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x36 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x37 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x38 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x39 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x40 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x41 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x42 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x43 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x44 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x45 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x46 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x47 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x48 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x49 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x50 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x51 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x52 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x53 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x54 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x55 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x56 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x57 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x58 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x59 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x60 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x61 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x62 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x63 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x64 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x65 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x66 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x67 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x68 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x69 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x70 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x71 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x72 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x73 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x74 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x75 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x76 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x77 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x78 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x79 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x80 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x81 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x82 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x83 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x84 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x85 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x86 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x87 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x88 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x89 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x90 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x91 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x92 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x93 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x94 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x95 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x96 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x97 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x98 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x99 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xaa }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xab }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xac }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xad }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xae }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xaf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xba }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbe }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xca }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xce }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xda }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xea }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xeb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xec }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xed }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xee }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xef }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfa }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfe }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xff }, { 0xf, 0x00 },
+
+/* mute on */
+{ WAIT_IDLE }, { 0x8, 0x02 },
+
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 },
+
+/* either because of stupidity by TB's programmers, or because it
+   actually does something, rezero the MOD page. */
+{ WAIT_IDLE }, { 0xe, 0x10 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x11 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x12 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x13 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x14 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x15 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x16 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x17 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x18 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x19 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x20 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x21 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x22 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x23 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x24 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x25 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x26 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x27 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x28 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x29 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x30 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x31 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x32 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x33 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x34 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x35 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x36 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x37 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x38 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x39 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x40 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x41 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x42 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x43 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x44 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x45 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x46 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x47 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x48 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x49 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x50 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x51 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x52 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x53 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x54 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x55 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x56 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x57 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x58 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x59 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x60 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x61 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x62 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x63 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x64 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x65 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x66 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x67 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x68 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x69 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x70 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x71 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x72 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x73 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x74 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x75 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x76 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x77 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x78 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x79 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x80 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x81 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x82 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x83 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x84 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x85 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x86 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x87 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x88 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x89 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x90 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x91 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x92 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x93 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x94 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x95 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x96 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x97 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x98 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x99 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xaa }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xab }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xac }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xad }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xae }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xaf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xba }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbe }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xca }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xce }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xda }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xea }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xeb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xec }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xed }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xee }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xef }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfa }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfe }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xff }, { 0xf, 0x00 },
+
+/* load page zero */
+{ 0x9, 0x05 }, { 0xb, 0x00 }, { 0xa, 0x00 },
+
+{ 0xd, 0x01 }, { 0xc, 0x7c }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1e }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0xf5 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x11 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x32 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x13 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x14 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x76 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x18 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x19 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0x1a }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0x17 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0x80 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x10 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0xa0 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0xd1 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0xf2 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x13 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0xf4 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xe0 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x15 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x16 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x17 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x50 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x71 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x92 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0xb3 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0xa0 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0xd4 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0xf5 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x70 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0xa0 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x11 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x16 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x10 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x17 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1d }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xdf }, { WAIT_IDLE },
+
+/* Now load page one */
+{ 0x9, 0x05 }, { 0xb, 0x01 }, { 0xa, 0x00 },
+
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x19 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1f }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0xd8 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x19 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x18 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0xfa }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1a }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x80 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xfb }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xa0 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xd7 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xf7 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1c }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0x3c }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0x3f }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0xdf }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0x5d }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0x7d }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0x9e }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0xbe }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xdb }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xdb }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xe0 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xfb }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xfb }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE },
+
+{ 0x9, 0x05 }, { 0xb, 0x02 }, { 0xa, 0x00 },
+
+{ 0xc, 0xc4 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x25 }, { WAIT_IDLE },
+{ 0xc, 0x01 }, { WAIT_IDLE },
+{ 0xc, 0x06 }, { WAIT_IDLE },
+{ 0xc, 0xc4 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x25 }, { WAIT_IDLE },
+{ 0xc, 0x01 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x04 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x04 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+
+{ 0x9, 0x05 }, { 0xb, 0x03 }, { 0xa, 0x00 },
+
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x47 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x06 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x80 }, { WAIT_IDLE },
+{ 0xc, 0x80 }, { WAIT_IDLE },
+{ 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x70 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x42 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x42 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x42 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x42 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+
+{ 0x9, 0x05 }, { 0xb, 0x04 }, { 0xa, 0x00 },
+
+{ 0xc, 0x63 }, { WAIT_IDLE },
+{ 0xc, 0x03 }, { WAIT_IDLE },
+{ 0xc, 0x26 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x2c }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x24 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x2e }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x01 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x22 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x22 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x22 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x62 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x01 }, { WAIT_IDLE },
+{ 0xc, 0x21 }, { WAIT_IDLE },
+{ 0xc, 0x01 }, { WAIT_IDLE },
+
+/* Load memory area (page six) */
+{ 0x9, 0x01 }, { 0xb, 0x06 },
+
+{ 0xa, 0x00 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x02 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x04 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x06 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x08 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x0a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x0c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x0e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x10 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x12 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x14 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x16 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x18 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x1a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x1c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x1e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x20 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x22 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x24 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x26 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x28 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x2a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x2c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x2e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x30 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x32 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x34 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x36 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x38 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x3a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x3c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x3e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x42 }, { 0xd, 0x03 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x44 }, { 0xd, 0x01 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x46 }, { 0xd, 0x0a }, { 0xc, 0x21 }, { WAIT_IDLE },
+{ 0xa, 0x48 }, { 0xd, 0x0d }, { 0xc, 0x23 }, { WAIT_IDLE },
+{ 0xa, 0x4a }, { 0xd, 0x23 }, { 0xc, 0x1b }, { WAIT_IDLE },
+{ 0xa, 0x4c }, { 0xd, 0x37 }, { 0xc, 0x8f }, { WAIT_IDLE },
+{ 0xa, 0x4e }, { 0xd, 0x45 }, { 0xc, 0x77 }, { WAIT_IDLE },
+{ 0xa, 0x50 }, { 0xd, 0x52 }, { 0xc, 0xe2 }, { WAIT_IDLE },
+{ 0xa, 0x52 }, { 0xd, 0x1c }, { 0xc, 0x92 }, { WAIT_IDLE },
+{ 0xa, 0x54 }, { 0xd, 0x1c }, { 0xc, 0x52 }, { WAIT_IDLE },
+{ 0xa, 0x56 }, { 0xd, 0x07 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x58 }, { 0xd, 0x2f }, { 0xc, 0xc6 }, { WAIT_IDLE },
+{ 0xa, 0x5a }, { 0xd, 0x0b }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x5c }, { 0xd, 0x30 }, { 0xc, 0x06 }, { WAIT_IDLE },
+{ 0xa, 0x5e }, { 0xd, 0x17 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x60 }, { 0xd, 0x3d }, { 0xc, 0xda }, { WAIT_IDLE },
+{ 0xa, 0x62 }, { 0xd, 0x29 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x64 }, { 0xd, 0x3e }, { 0xc, 0x41 }, { WAIT_IDLE },
+{ 0xa, 0x66 }, { 0xd, 0x39 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x68 }, { 0xd, 0x4c }, { 0xc, 0x48 }, { WAIT_IDLE },
+{ 0xa, 0x6a }, { 0xd, 0x49 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x6c }, { 0xd, 0x4c }, { 0xc, 0x6c }, { WAIT_IDLE },
+{ 0xa, 0x6e }, { 0xd, 0x11 }, { 0xc, 0xd2 }, { WAIT_IDLE },
+{ 0xa, 0x70 }, { 0xd, 0x16 }, { 0xc, 0x0c }, { WAIT_IDLE },
+{ 0xa, 0x72 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x74 }, { 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE },
+{ 0xa, 0x76 }, { 0xd, 0x0f }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x78 }, { 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE },
+{ 0xa, 0x7a }, { 0xd, 0x13 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x7c }, { 0xd, 0x80 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x7e }, { 0xd, 0x80 }, { 0xc, 0x80 }, { WAIT_IDLE },
+
+{ 0x9, 0x05 }, { 0xb, 0x07 }, { 0xa, 0x00 },
+
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xe9 }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0x8c }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0x8c }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x1a }, { 0xc, 0x75 }, { WAIT_IDLE },
+{ 0xd, 0x0d }, { 0xc, 0x8b }, { WAIT_IDLE },
+{ 0xd, 0x04 }, { 0xc, 0xe9 }, { WAIT_IDLE },
+{ 0xd, 0x0b }, { 0xc, 0x16 }, { WAIT_IDLE },
+{ 0xd, 0x1a }, { 0xc, 0x38 }, { WAIT_IDLE },
+{ 0xd, 0x0d }, { 0xc, 0xc8 }, { WAIT_IDLE },
+{ 0xd, 0x04 }, { 0xc, 0x6f }, { WAIT_IDLE },
+{ 0xd, 0x0b }, { 0xc, 0x91 }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x8f }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0x62 }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0x62 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x7b }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0x97 }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0x97 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x52 }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0xf6 }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0xf6 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x19 }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE },
+{ 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE },
+{ 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE },
+{ 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE },
+{ 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE },
+{ 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE },
+{ 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+
+/* Now setup the MOD area. */
+{ 0xe, 0x01 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x02 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x03 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x04 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x05 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x06 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x07 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x08 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x09 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0a }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0b }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0c }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0d }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0e }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0f }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+
+{ 0xe, 0xb0 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb1 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb2 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb3 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb4 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb5 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb6 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb7 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb8 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb9 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xba }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xbb }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xbc }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xbd }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xbe }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xbf }, { 0xf, 0x20 }, { WAIT_IDLE },
+
+{ 0xe, 0xf0 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf1 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf2 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf3 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf4 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf5 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf6 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf7 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf8 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf9 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xfa }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xfb }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xfc }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xfd }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xfe }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xff }, { 0xf, 0x20 }, { WAIT_IDLE },
+
+{ 0xe, 0x10 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x11 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x12 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x13 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x14 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x15 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x16 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x17 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x18 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x19 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x1a }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x1b }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x1c }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x1d }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x1e }, { 0xf, 0x40 }, { WAIT_IDLE },
+{ 0xe, 0x1f }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x20 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x21 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x22 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x23 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x24 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x25 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x26 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x27 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x28 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x29 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x2a }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x2b }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x2c }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x2d }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x2e }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x2f }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x30 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x31 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x32 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x33 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x34 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x35 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x36 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x37 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x38 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x39 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x3a }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x3b }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x3c }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x3d }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x3e }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x3f }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0x40 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x41 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x42 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x43 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x44 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x45 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x46 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x47 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x48 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x49 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x4a }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x4b }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x4c }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x4d }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x4e }, { 0xf, 0x0e }, { WAIT_IDLE },
+{ 0xe, 0x4f }, { 0xf, 0x0e }, { WAIT_IDLE },
+{ 0xe, 0x50 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x51 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x52 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x53 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x54 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x55 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x56 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x57 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x58 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x59 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x5a }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x5b }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x5c }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x5d }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x5e }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x5f }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x60 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x61 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x62 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x63 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x64 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x65 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x66 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x67 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x68 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x69 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x6a }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x6b }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x6c }, { 0xf, 0x40 }, { WAIT_IDLE },
+{ 0xe, 0x6d }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x6e }, { 0xf, 0x40 }, { WAIT_IDLE },
+{ 0xe, 0x6f }, { 0xf, 0x40 }, { WAIT_IDLE },
+{ 0xe, 0x70 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x71 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x72 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x73 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x74 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x75 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x76 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x77 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x78 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x79 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x7a }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x7b }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x7c }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x7d }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x7e }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x7f }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x80 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x81 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x82 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x83 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x84 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x85 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x86 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x87 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x88 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x89 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x8a }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x8b }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x8c }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x8d }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x8e }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x8f }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x90 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x91 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x92 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x93 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x94 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x95 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x96 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x97 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x98 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x99 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x9a }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x9b }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x9c }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x9d }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x9e }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x9f }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa0 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa1 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa2 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa3 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa4 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa5 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa6 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa7 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa8 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa9 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xaa }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xab }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xac }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xad }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xae }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xaf }, { 0xf, 0x00 }, { WAIT_IDLE },
+
+{ 0xe, 0xc0 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc1 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc2 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc3 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc4 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc5 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc6 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc7 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc8 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc9 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xca }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xcb }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xcc }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xcd }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xce }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xcf }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd0 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd1 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd2 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd3 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd4 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd5 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd6 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd7 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd8 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd9 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xda }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xdb }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xdc }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xdd }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xde }, { 0xf, 0x10 }, { WAIT_IDLE },
+{ 0xe, 0xdf }, { 0xf, 0x10 }, { WAIT_IDLE },
+{ 0xe, 0xe0 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe1 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe2 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe3 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe4 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe5 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe6 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe7 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe8 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe9 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xea }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xeb }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xec }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xed }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xee }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xef }, { 0xf, 0x00 }, { WAIT_IDLE },
+
+{ 0xe, 0x01 }, { 0xf, 0x00 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x01 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x02 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x03 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x04 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x05 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x06 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x07 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x08 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x09 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0a }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0b }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0c }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0d }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0e }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0f }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+
+/* mute on */
+{ 0x8, 0x02 },
+
+/* Now set the coefficients and so forth for the programs above */
+{ 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x00 }, { 0xa, 0x4b }, { 0xd, 0x03 }, { 0xc, 0x11 }, { WAIT_IDLE },
+{ 0xb, 0x00 }, { 0xa, 0x4d }, { 0xd, 0x01 }, { 0xc, 0x32 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x01 }, { 0xa, 0x40 }, { 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xb, 0x01 }, { 0xa, 0x41 }, { 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x00 }, { 0xa, 0x47 }, { 0xd, 0x01 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x00 }, { 0xa, 0x4a }, { 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x00 }, { 0xa, 0x00 }, { 0xd, 0x01 }, { 0xc, 0x1c }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x00 }, { 0xa, 0x44 }, { 0xd, 0x01 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x00 }, { 0xa, 0x42 }, { 0xd, 0x01 }, { 0xc, 0x1a }, { WAIT_IDLE },
+{ 0xb, 0x00 }, { 0xa, 0x43 }, { 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x01 }, { 0xa, 0x40 }, { 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xb, 0x01 }, { 0xa, 0x41 }, { 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x51 }, { 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x50 }, { 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x4f }, { 0xd, 0x03 }, { 0xc, 0x81 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x53 }, { 0xd, 0x1a }, { 0xc, 0x76 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x54 }, { 0xd, 0x0d }, { 0xc, 0x8b }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x55 }, { 0xd, 0x04 }, { 0xc, 0xe9 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x56 }, { 0xd, 0x0b }, { 0xc, 0x17 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x57 }, { 0xd, 0x1a }, { 0xc, 0x38 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x58 }, { 0xd, 0x0d }, { 0xc, 0xc9 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x59 }, { 0xd, 0x04 }, { 0xc, 0x6f }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x5a }, { 0xd, 0x0b }, { 0xc, 0x91 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x73 }, { 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x74 }, { 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x75 }, { 0xd, 0x04 }, { 0xc, 0xd9 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x76 }, { 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x77 }, { 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x78 }, { 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x79 }, { 0xd, 0x04 }, { 0xc, 0xd9 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x7a }, { 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x5e }, { 0xd, 0x03 }, { 0xc, 0x68 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x5c }, { 0xd, 0x04 }, { 0xc, 0x31 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x5d }, { 0xd, 0x04 }, { 0xc, 0x31 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x62 }, { 0xd, 0x03 }, { 0xc, 0x52 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x60 }, { 0xd, 0x04 }, { 0xc, 0x76 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x61 }, { 0xd, 0x04 }, { 0xc, 0x76 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x66 }, { 0xd, 0x03 }, { 0xc, 0x2e }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x64 }, { 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x65 }, { 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x6a }, { 0xd, 0x02 }, { 0xc, 0xf6 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x68 }, { 0xd, 0x05 }, { 0xc, 0x62 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x69 }, { 0xd, 0x05 }, { 0xc, 0x62 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x46 }, { 0xd, 0x0a }, { 0xc, 0x22 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x48 }, { 0xd, 0x0d }, { 0xc, 0x24 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x6e }, { 0xd, 0x11 }, { 0xc, 0xd3 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x70 }, { 0xd, 0x15 }, { 0xc, 0xcb }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x52 }, { 0xd, 0x20 }, { 0xc, 0x93 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x54 }, { 0xd, 0x20 }, { 0xc, 0x54 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x4a }, { 0xd, 0x27 }, { 0xc, 0x1d }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x58 }, { 0xd, 0x2f }, { 0xc, 0xc8 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x5c }, { 0xd, 0x30 }, { 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x4c }, { 0xd, 0x37 }, { 0xc, 0x90 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x60 }, { 0xd, 0x3d }, { 0xc, 0xdb }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x64 }, { 0xd, 0x3e }, { 0xc, 0x42 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x4e }, { 0xd, 0x45 }, { 0xc, 0x78 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x68 }, { 0xd, 0x4c }, { 0xc, 0x48 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x6c }, { 0xd, 0x4c }, { 0xc, 0x6c }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x50 }, { 0xd, 0x52 }, { 0xc, 0xe2 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x42 }, { 0xd, 0x02 }, { 0xc, 0xba }, { WAIT_IDLE },
+
+/* Some settings (?) */
+{ WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x14 },
+{ WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x20 },
+{ WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x20 },
+
+/* some more coefficients */
+{ WAIT_IDLE }, { 0xb, 0x06 }, { 0xa, 0x78 }, { 0xd, 0x00 }, { 0xc, 0x40 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x03 }, { 0xd, 0x0f }, { 0xc, 0xff },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x0b }, { 0xd, 0x0f }, { 0xc, 0xff },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x02 }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x0a }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 },
+
+/* Now, for some strange reason, lets reload every page
+   and all the coefficients over again. I have *NO* idea
+   why this is done. I do know that no sound is produced
+   is this phase is omitted. */
+{ 0x9, 0x05 }, { 0xb, 0x00 }, { 0xa, 0x10 },
+
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+
+{ 0x9, 0x05 }, { 0xb, 0x01 }, { 0xa, 0x10 },
+
+{ 0xd, 0x01 }, { 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0xfa }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1a }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+
+{ WAIT_IDLE }, { WAIT_IDLE },
+
+{ 0x9, 0x05 }, { 0xb, 0x02 }, { 0xa, 0x10 },
+
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+
+{ 0x9, 0x05 }, { 0xb, 0x03 }, { 0xa, 0x10 },
+
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+
+{ 0x9, 0x05 }, { 0xb, 0x04 }, { 0xa, 0x10 },
+
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+
+/* Page six v.2 */
+{ 0x9, 0x01 }, { 0xb, 0x06 },
+
+{ 0xa, 0x10 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x12 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x14 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x16 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x18 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x1a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x1c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x1e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x20 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x22 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x24 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x26 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x28 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x2a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x2c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x2e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x30 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x32 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x34 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x36 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x38 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x3a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x3c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x3e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+
+{ 0x9, 0x05 }, { 0xb, 0x07 }, { 0xa, 0x10 },
+
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+
+{ 0xe, 0x01 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x02 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x03 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x04 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x05 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x06 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x07 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xb0 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb1 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb2 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb3 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb4 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb5 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb6 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb7 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf0 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf1 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf2 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf3 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf4 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf5 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf6 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf7 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0x10 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x11 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x12 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x13 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x14 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x15 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x16 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x17 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x20 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x21 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x22 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x23 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x24 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x25 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x26 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x27 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x30 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x31 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x32 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x33 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x34 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x35 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x36 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x37 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x40 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x41 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x42 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x43 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x44 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x45 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x46 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x47 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x50 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x51 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x52 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x53 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x54 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x55 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x56 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x57 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x60 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x61 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x62 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x63 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x64 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x65 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x66 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x67 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x70 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x71 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x72 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x73 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x74 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x75 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x76 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x77 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x80 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x81 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x82 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x83 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x84 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x85 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x86 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x87 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x90 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x91 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x92 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x93 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x94 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x95 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x96 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x97 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa0 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa1 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa2 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa3 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa4 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa5 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa6 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa7 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc0 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc1 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc2 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc3 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc4 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc5 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc6 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc7 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd0 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd1 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd2 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd3 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd4 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd5 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd6 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd7 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe0 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe1 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe2 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe3 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe4 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe5 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe6 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe7 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x02 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x03 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x04 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x05 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x06 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x07 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+
+{ 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x45 }, { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x48 }, { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x7b }, { 0xd, 0x04 }, { 0xc, 0xcc }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x7d }, { 0xd, 0x04 }, { 0xc, 0xcc }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x28 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x28 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x51 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x51 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x7a },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x7a },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0xa3 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0xa3 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0xcc },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0xcc },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0xf5 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0xf5 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x1e },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x1e },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x47 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x47 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x70 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x70 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x99 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x99 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0xc2 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0xc2 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0xeb },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0xeb },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x14 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x14 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x3d },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x3d },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x66 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x66 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x8f },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x8f },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0xb8 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0xb8 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0xe1 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0xe1 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x0a },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x0a },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x33 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x33 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x5c },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x5c },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x85 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x85 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0xae },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0xae },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0xd7 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0xd7 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x00 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x00 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x28 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x28 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x51 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x51 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x7a },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x7a },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0xa3 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0xa3 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0xcc },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0xcc },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0xf5 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0xf5 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x1e },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x1e },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x47 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x47 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x70 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x70 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x99 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x99 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0xc2 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0xc2 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0xeb },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0xeb },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x14 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x14 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x3d },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x3d },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x66 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x66 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x8f },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x8f },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0xb8 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0xb8 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0xe1 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0xe1 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x0a },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x0a },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x33 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x33 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x5c },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x5c },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x85 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x85 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0xae },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0xae },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0xd7 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0xd7 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x00 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x00 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x28 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x28 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x51 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x51 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x7a },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x7a },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0xa3 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0xa3 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0xcc },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0xcc },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0xf5 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0xf5 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x1e },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x1e },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x47 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x47 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x70 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x70 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x99 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x99 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0xc2 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0xc2 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0xeb },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0xeb },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x14 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x14 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x3d },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x3d },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x66 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x66 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x8f },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x8f },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0xb8 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0xb8 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0xe1 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0xe1 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x0a },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x0a },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x33 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x33 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x5c },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x5c },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x85 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x85 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0xae },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0xae },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0xd7 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0xd7 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x00 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x00 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x28 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x28 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x51 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x51 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x7a },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x7a },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0xa3 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0xa3 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0xcc },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0xcc },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0xf5 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0xf5 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x1e },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x1e },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x47 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x47 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x70 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x70 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x99 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x99 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0xc2 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0xc2 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0xeb },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0xeb },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x14 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x14 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x3d },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x3d },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x66 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x66 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x8f },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x8f },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0xb8 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0xb8 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0xe1 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0xe1 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x0a },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x0a },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x33 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x33 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x5c },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x5c },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x85 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x85 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0xae },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0xae },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0xd7 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0xd7 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0xff },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0xff },
+
+/* mute off */
+{ 0x8, 0x00 }, { WAIT_IDLE }
+};
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 8a6b180..1bcfb3a 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -236,7 +236,7 @@
 config SND_DARLA20
 	tristate "(Echoaudio) Darla20"
 	depends on SND
-	depends on FW_LOADER
+	select FW_LOADER
 	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Echoaudio Darla.
@@ -247,7 +247,7 @@
 config SND_GINA20
 	tristate "(Echoaudio) Gina20"
 	depends on SND
-	depends on FW_LOADER
+	select FW_LOADER
 	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Echoaudio Gina.
@@ -258,7 +258,7 @@
 config SND_LAYLA20
 	tristate "(Echoaudio) Layla20"
 	depends on SND
-	depends on FW_LOADER
+	select FW_LOADER
 	select SND_RAWMIDI
 	select SND_PCM
 	help
@@ -270,7 +270,7 @@
 config SND_DARLA24
 	tristate "(Echoaudio) Darla24"
 	depends on SND
-	depends on FW_LOADER
+	select FW_LOADER
 	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Echoaudio Darla24.
@@ -281,7 +281,7 @@
 config SND_GINA24
 	tristate "(Echoaudio) Gina24"
 	depends on SND
-	depends on FW_LOADER
+	select FW_LOADER
 	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Echoaudio Gina24.
@@ -292,7 +292,7 @@
 config SND_LAYLA24
 	tristate "(Echoaudio) Layla24"
 	depends on SND
-	depends on FW_LOADER
+	select FW_LOADER
 	select SND_RAWMIDI
 	select SND_PCM
 	help
@@ -304,7 +304,7 @@
 config SND_MONA
 	tristate "(Echoaudio) Mona"
 	depends on SND
-	depends on FW_LOADER
+	select FW_LOADER
 	select SND_RAWMIDI
 	select SND_PCM
 	help
@@ -316,7 +316,7 @@
 config SND_MIA
 	tristate "(Echoaudio) Mia"
 	depends on SND
-	depends on FW_LOADER
+	select FW_LOADER
 	select SND_RAWMIDI
 	select SND_PCM
 	help
@@ -328,7 +328,7 @@
 config SND_ECHO3G
 	tristate "(Echoaudio) 3G cards"
 	depends on SND
-	depends on FW_LOADER
+	select FW_LOADER
 	select SND_RAWMIDI
 	select SND_PCM
 	help
@@ -340,7 +340,7 @@
 config SND_INDIGO
 	tristate "(Echoaudio) Indigo"
 	depends on SND
-	depends on FW_LOADER
+	select FW_LOADER
 	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Echoaudio Indigo.
@@ -351,7 +351,7 @@
 config SND_INDIGOIO
 	tristate "(Echoaudio) Indigo IO"
 	depends on SND
-	depends on FW_LOADER
+	select FW_LOADER
 	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Echoaudio Indigo IO.
@@ -362,7 +362,7 @@
 config SND_INDIGODJ
 	tristate "(Echoaudio) Indigo DJ"
 	depends on SND
-	depends on FW_LOADER
+	select FW_LOADER
 	select SND_PCM
 	help
 	  Say 'Y' or 'M' to include support for Echoaudio Indigo DJ.
@@ -373,6 +373,7 @@
 config SND_EMU10K1
 	tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)"
 	depends on SND
+	select FW_LOADER
 	select SND_HWDEP
 	select SND_RAWMIDI
 	select SND_AC97_CODEC
@@ -575,6 +576,7 @@
 config SND_KORG1212
 	tristate "Korg 1212 IO"
 	depends on SND
+	select FW_LOADER
 	select SND_PCM
 	help
 	  Say Y here to include support for Korg 1212IO soundcards.
@@ -585,6 +587,7 @@
 config SND_MAESTRO3
 	tristate "ESS Allegro/Maestro3"
 	depends on SND
+	select FW_LOADER
 	select SND_AC97_CODEC
 	help
 	  Say Y here to include support for soundcards based on ESS Maestro 3
@@ -629,7 +632,7 @@
 config SND_RIPTIDE
 	tristate "Conexant Riptide"
 	depends on SND
-	depends on FW_LOADER
+	select FW_LOADER
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
 	select SND_AC97_CODEC
@@ -734,6 +737,7 @@
 config SND_YMFPCI
 	tristate "Yamaha YMF724/740/744/754"
 	depends on SND
+	select FW_LOADER
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
 	select SND_AC97_CODEC
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index d2994cb..74ed810 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -111,7 +111,7 @@
 { 0x41445372, 0xffffffff, "AD1981A",		patch_ad1981a,	NULL },
 { 0x41445374, 0xffffffff, "AD1981B",		patch_ad1981b,	NULL },
 { 0x41445375, 0xffffffff, "AD1985",		patch_ad1985,	NULL },
-{ 0x41445378, 0xffffffff, "AD1986",		patch_ad1985,	NULL },
+{ 0x41445378, 0xffffffff, "AD1986",		patch_ad1986,	NULL },
 { 0x414c4300, 0xffffff00, "ALC100,100P", 	NULL,		NULL },
 { 0x414c4710, 0xfffffff0, "ALC200,200P",	NULL,		NULL },
 { 0x414c4721, 0xffffffff, "ALC650D",		NULL,	NULL }, /* already patched */
@@ -194,6 +194,13 @@
 
 
 static void update_power_regs(struct snd_ac97 *ac97);
+#ifdef CONFIG_SND_AC97_POWER_SAVE
+#define ac97_is_power_save_mode(ac97) \
+	((ac97->scaps & AC97_SCAP_POWER_SAVE) && power_save)
+#else
+#define ac97_is_power_save_mode(ac97) 0
+#endif
+
 
 /*
  *  I/O routines
@@ -982,8 +989,8 @@
 {
 	if (ac97) {
 #ifdef CONFIG_SND_AC97_POWER_SAVE
-		if (ac97->power_workq)
-			destroy_workqueue(ac97->power_workq);
+		cancel_delayed_work(&ac97->power_work);
+		flush_scheduled_work();
 #endif
 		snd_ac97_proc_done(ac97);
 		if (ac97->bus)
@@ -1184,13 +1191,13 @@
 /*
  * set dB information
  */
-static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
 
-static unsigned int *find_db_scale(unsigned int maxval)
+static const unsigned int *find_db_scale(unsigned int maxval)
 {
 	switch (maxval) {
 	case 0x0f: return db_scale_4bit;
@@ -1200,8 +1207,8 @@
 	return NULL;
 }
 
-static void set_tlv_db_scale(struct snd_kcontrol *kctl, unsigned int *tlv)
-{	
+static void set_tlv_db_scale(struct snd_kcontrol *kctl, const unsigned int *tlv)
+{
 	kctl->tlv.p = tlv;
 	if (tlv)
 		kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
@@ -1989,7 +1996,6 @@
 	mutex_init(&ac97->reg_mutex);
 	mutex_init(&ac97->page_mutex);
 #ifdef CONFIG_SND_AC97_POWER_SAVE
-	ac97->power_workq = create_workqueue("ac97");
 	INIT_DELAYED_WORK(&ac97->power_work, do_update_power);
 #endif
 
@@ -2275,15 +2281,13 @@
 	udelay(100);
 	power |= AC97_PD_PR2 | AC97_PD_PR3;	/* Analog Mixer powerdown */
 	snd_ac97_write(ac97, AC97_POWERDOWN, power);
-#ifdef CONFIG_SND_AC97_POWER_SAVE
-	if (power_save) {
+	if (ac97_is_power_save_mode(ac97)) {
 		udelay(100);
 		/* AC-link powerdown, internal Clk disable */
 		/* FIXME: this may cause click noises on some boards */
 		power |= AC97_PD_PR4 | AC97_PD_PR5;
 		snd_ac97_write(ac97, AC97_POWERDOWN, power);
 	}
-#endif
 }
 
 
@@ -2337,14 +2341,16 @@
 		}
 	}
 
-	if (power_save && !powerup && ac97->power_workq)
+	if (ac97_is_power_save_mode(ac97) && !powerup)
 		/* adjust power-down bits after two seconds delay
 		 * (for avoiding loud click noises for many (OSS) apps
 		 *  that open/close frequently)
 		 */
-		queue_delayed_work(ac97->power_workq, &ac97->power_work, HZ*2);
-	else
+		schedule_delayed_work(&ac97->power_work, HZ*2);
+	else {
+		cancel_delayed_work(&ac97->power_work);
 		update_power_regs(ac97);
+	}
 
 	return 0;
 }
@@ -2357,19 +2363,15 @@
 	unsigned int power_up, bits;
 	int i;
 
+	power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC);
+	power_up |= (1 << PWIDX_MIC);
+	if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
+		power_up |= (1 << PWIDX_SURR);
+	if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
+		power_up |= (1 << PWIDX_CLFE);
 #ifdef CONFIG_SND_AC97_POWER_SAVE
-	if (power_save)
+	if (ac97_is_power_save_mode(ac97))
 		power_up = ac97->power_up;
-	else {
-#endif
-		power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC);
-		power_up |= (1 << PWIDX_MIC);
-		if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
-			power_up |= (1 << PWIDX_SURR);
-		if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
-			power_up |= (1 << PWIDX_CLFE);
-#ifdef CONFIG_SND_AC97_POWER_SAVE
-	}
 #endif
 	if (power_up) {
 		if (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2) {
@@ -2414,6 +2416,10 @@
 		return;
 	if (ac97->build_ops->suspend)
 		ac97->build_ops->suspend(ac97);
+#ifdef CONFIG_SND_AC97_POWER_SAVE
+	cancel_delayed_work(&ac97->power_work);
+	flush_scheduled_work();
+#endif
 	snd_ac97_powerdown(ac97);
 }
 
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index e813968..641d0c8 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -54,7 +54,7 @@
 
 /* replace with a new TLV */
 static void reset_tlv(struct snd_ac97 *ac97, const char *name,
-		      unsigned int *tlv)
+		      const unsigned int *tlv)
 {
 	struct snd_ctl_elem_id sid;
 	struct snd_kcontrol *kctl;
@@ -190,14 +190,28 @@
 	return ac97->channel_mode >= 2;
 }
 
-static inline int is_shared_linein(struct snd_ac97 *ac97)
+/* system has shared jacks with surround out enabled */
+static inline int is_shared_surrout(struct snd_ac97 *ac97)
 {
-	return ! ac97->indep_surround && is_surround_on(ac97);
+	return !ac97->indep_surround && is_surround_on(ac97);
 }
 
+/* system has shared jacks with center/lfe out enabled */
+static inline int is_shared_clfeout(struct snd_ac97 *ac97)
+{
+	return !ac97->indep_surround && is_clfe_on(ac97);
+}
+
+/* system has shared jacks with line in enabled */
+static inline int is_shared_linein(struct snd_ac97 *ac97)
+{
+	return !ac97->indep_surround && !is_surround_on(ac97);
+}
+
+/* system has shared jacks with mic in enabled */
 static inline int is_shared_micin(struct snd_ac97 *ac97)
 {
-	return ! ac97->indep_surround && is_clfe_on(ac97);
+	return !ac97->indep_surround && !is_clfe_on(ac97);
 }
 
 
@@ -941,6 +955,9 @@
 {
 	int err;
 
+	/* the register bit is writable, but the function is not implemented: */
+	snd_ac97_remove_ctl(ac97, "PCM Out Path & Mute", NULL);
+
 	snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Sigmatel Surround Playback");
 	if ((err = patch_build_controls(ac97, &snd_ac97_stac9708_bias_control, 1)) < 0)
 		return err;
@@ -1552,7 +1569,7 @@
 	AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */
 };
 
-static DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0);
 
 static int patch_ad1885_specific(struct snd_ac97 * ac97)
 {
@@ -1609,19 +1626,22 @@
 	return 0;
 }
 
-/* MISC bits */
+/* MISC bits (AD1888/AD1980/AD1985 register 0x76) */
 #define AC97_AD198X_MBC		0x0003	/* mic boost */
 #define AC97_AD198X_MBC_20	0x0000	/* +20dB */
 #define AC97_AD198X_MBC_10	0x0001	/* +10dB */
 #define AC97_AD198X_MBC_30	0x0002	/* +30dB */
 #define AC97_AD198X_VREFD	0x0004	/* VREF high-Z */
-#define AC97_AD198X_VREFH	0x0008	/* 2.25V, 3.7V */
-#define AC97_AD198X_VREF_0	0x000c	/* 0V */
+#define AC97_AD198X_VREFH	0x0008	/* 0=2.25V, 1=3.7V */
+#define AC97_AD198X_VREF_0	0x000c	/* 0V (AD1985 only) */
+#define AC97_AD198X_VREF_MASK	(AC97_AD198X_VREFH | AC97_AD198X_VREFD)
+#define AC97_AD198X_VREF_SHIFT	2
 #define AC97_AD198X_SRU		0x0010	/* sample rate unlock */
 #define AC97_AD198X_LOSEL	0x0020	/* LINE_OUT amplifiers input select */
 #define AC97_AD198X_2MIC	0x0040	/* 2-channel mic select */
 #define AC97_AD198X_SPRD	0x0080	/* SPREAD enable */
-#define AC97_AD198X_DMIX0	0x0100	/* downmix mode: 0 = 6-to-4, 1 = 6-to-2 downmix */
+#define AC97_AD198X_DMIX0	0x0100	/* downmix mode: */
+					/*  0 = 6-to-4, 1 = 6-to-2 downmix */
 #define AC97_AD198X_DMIX1	0x0200	/* downmix mode: 1 = enabled */
 #define AC97_AD198X_HPSEL	0x0400	/* headphone amplifier input select */
 #define AC97_AD198X_CLDIS	0x0800	/* center/lfe disable */
@@ -1630,6 +1650,83 @@
 #define AC97_AD198X_AC97NC	0x4000	/* AC97 no compatible mode */
 #define AC97_AD198X_DACZ	0x8000	/* DAC zero-fill mode */
 
+/* MISC 1 bits (AD1986 register 0x76) */
+#define AC97_AD1986_MBC		0x0003	/* mic boost */
+#define AC97_AD1986_MBC_20	0x0000	/* +20dB */
+#define AC97_AD1986_MBC_10	0x0001	/* +10dB */
+#define AC97_AD1986_MBC_30	0x0002	/* +30dB */
+#define AC97_AD1986_LISEL0	0x0004	/* LINE_IN select bit 0 */
+#define AC97_AD1986_LISEL1	0x0008	/* LINE_IN select bit 1 */
+#define AC97_AD1986_LISEL_MASK	(AC97_AD1986_LISEL1 | AC97_AD1986_LISEL0)
+#define AC97_AD1986_LISEL_LI	0x0000  /* LINE_IN pins as LINE_IN source */
+#define AC97_AD1986_LISEL_SURR	0x0004  /* SURROUND pins as LINE_IN source */
+#define AC97_AD1986_LISEL_MIC	0x0008  /* MIC_1/2 pins as LINE_IN source */
+#define AC97_AD1986_SRU		0x0010	/* sample rate unlock */
+#define AC97_AD1986_SOSEL	0x0020	/* SURROUND_OUT amplifiers input sel */
+#define AC97_AD1986_2MIC	0x0040	/* 2-channel mic select */
+#define AC97_AD1986_SPRD	0x0080	/* SPREAD enable */
+#define AC97_AD1986_DMIX0	0x0100	/* downmix mode: */
+					/*  0 = 6-to-4, 1 = 6-to-2 downmix */
+#define AC97_AD1986_DMIX1	0x0200	/* downmix mode: 1 = enabled */
+#define AC97_AD1986_CLDIS	0x0800	/* center/lfe disable */
+#define AC97_AD1986_SODIS	0x1000	/* SURROUND_OUT disable */
+#define AC97_AD1986_MSPLT	0x2000	/* mute split (read only 1) */
+#define AC97_AD1986_AC97NC	0x4000	/* AC97 no compatible mode (r/o 1) */
+#define AC97_AD1986_DACZ	0x8000	/* DAC zero-fill mode */
+
+/* MISC 2 bits (AD1986 register 0x70) */
+#define AC97_AD_MISC2		0x70	/* Misc Control Bits 2 (AD1986) */
+
+#define AC97_AD1986_CVREF0	0x0004	/* C/LFE VREF_OUT 2.25V */
+#define AC97_AD1986_CVREF1	0x0008	/* C/LFE VREF_OUT 0V */
+#define AC97_AD1986_CVREF2	0x0010	/* C/LFE VREF_OUT 3.7V */
+#define AC97_AD1986_CVREF_MASK \
+	(AC97_AD1986_CVREF2 | AC97_AD1986_CVREF1 | AC97_AD1986_CVREF0)
+#define AC97_AD1986_JSMAP	0x0020	/* Jack Sense Mapping 1 = alternate */
+#define AC97_AD1986_MMDIS	0x0080	/* Mono Mute Disable */
+#define AC97_AD1986_MVREF0	0x0400	/* MIC VREF_OUT 2.25V */
+#define AC97_AD1986_MVREF1	0x0800	/* MIC VREF_OUT 0V */
+#define AC97_AD1986_MVREF2	0x1000	/* MIC VREF_OUT 3.7V */
+#define AC97_AD1986_MVREF_MASK \
+	(AC97_AD1986_MVREF2 | AC97_AD1986_MVREF1 | AC97_AD1986_MVREF0)
+
+/* MISC 3 bits (AD1986 register 0x7a) */
+#define AC97_AD_MISC3		0x7a	/* Misc Control Bits 3 (AD1986) */
+
+#define AC97_AD1986_MMIX	0x0004	/* Mic Mix, left/right */
+#define AC97_AD1986_GPO		0x0008	/* General Purpose Out */
+#define AC97_AD1986_LOHPEN	0x0010	/* LINE_OUT headphone drive */
+#define AC97_AD1986_LVREF0	0x0100	/* LINE_OUT VREF_OUT 2.25V */
+#define AC97_AD1986_LVREF1	0x0200	/* LINE_OUT VREF_OUT 0V */
+#define AC97_AD1986_LVREF2	0x0400	/* LINE_OUT VREF_OUT 3.7V */
+#define AC97_AD1986_LVREF_MASK \
+	(AC97_AD1986_LVREF2 | AC97_AD1986_LVREF1 | AC97_AD1986_LVREF0)
+#define AC97_AD1986_JSINVA	0x0800	/* Jack Sense Invert SENSE_A */
+#define AC97_AD1986_LOSEL	0x1000	/* LINE_OUT amplifiers input select */
+#define AC97_AD1986_HPSEL0	0x2000	/* Headphone amplifiers */
+					/*   input select Surround DACs */
+#define AC97_AD1986_HPSEL1	0x4000	/* Headphone amplifiers input */
+					/*   select C/LFE DACs */
+#define AC97_AD1986_JSINVB	0x8000	/* Jack Sense Invert SENSE_B */
+
+/* Serial Config bits (AD1986 register 0x74) (incomplete) */
+#define AC97_AD1986_OMS0	0x0100	/* Optional Mic Selector bit 0 */
+#define AC97_AD1986_OMS1	0x0200	/* Optional Mic Selector bit 1 */
+#define AC97_AD1986_OMS2	0x0400	/* Optional Mic Selector bit 2 */
+#define AC97_AD1986_OMS_MASK \
+	(AC97_AD1986_OMS2 | AC97_AD1986_OMS1 | AC97_AD1986_OMS0)
+#define AC97_AD1986_OMS_M	0x0000  /* MIC_1/2 pins are MIC sources */
+#define AC97_AD1986_OMS_L	0x0100  /* LINE_IN pins are MIC sources */
+#define AC97_AD1986_OMS_C	0x0200  /* Center/LFE pins are MCI sources */
+#define AC97_AD1986_OMS_MC	0x0400  /* Mix of MIC and C/LFE pins */
+					/*   are MIC sources */
+#define AC97_AD1986_OMS_ML	0x0500  /* MIX of MIC and LINE_IN pins */
+					/*   are MIC sources */
+#define AC97_AD1986_OMS_LC	0x0600  /* MIX of LINE_IN and C/LFE pins */
+					/*   are MIC sources */
+#define AC97_AD1986_OMS_MLC	0x0700  /* MIX of MIC, LINE_IN, C/LFE pins */
+					/*   are MIC sources */
+
 
 static int snd_ac97_ad198x_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
@@ -1952,8 +2049,80 @@
 	return 0;
 }
 
+static int snd_ac97_ad1985_vrefout_info(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_info *uinfo)
+{
+	static char *texts[4] = {"High-Z", "3.7 V", "2.25 V", "0 V"};
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 4;
+	if (uinfo->value.enumerated.item > 3)
+		uinfo->value.enumerated.item = 3;
+	strcpy(uinfo->value.enumerated.name,
+	       texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_ac97_ad1985_vrefout_get(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	static const int reg2ctrl[4] = {2, 0, 1, 3};
+	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+	unsigned short val;
+	val = (ac97->regs[AC97_AD_MISC] & AC97_AD198X_VREF_MASK)
+	      >> AC97_AD198X_VREF_SHIFT;
+	ucontrol->value.enumerated.item[0] = reg2ctrl[val];
+	return 0;
+}
+
+static int snd_ac97_ad1985_vrefout_put(struct snd_kcontrol *kcontrol, 
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	static const int ctrl2reg[4] = {1, 2, 0, 3};
+	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+	unsigned short val;
+
+	if (ucontrol->value.enumerated.item[0] > 3
+	    || ucontrol->value.enumerated.item[0] < 0)
+		return -EINVAL;
+	val = ctrl2reg[ucontrol->value.enumerated.item[0]]
+	      << AC97_AD198X_VREF_SHIFT;
+	return snd_ac97_update_bits(ac97, AC97_AD_MISC,
+				    AC97_AD198X_VREF_MASK, val);
+}
+
 static const struct snd_kcontrol_new snd_ac97_ad1985_controls[] = {
-	AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0)
+	AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Exchange Front/Surround",
+		.info = snd_ac97_ad1888_lohpsel_info,
+		.get = snd_ac97_ad1888_lohpsel_get,
+		.put = snd_ac97_ad1888_lohpsel_put
+	},
+	AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1),
+	AC97_SINGLE("Spread Front to Surround and Center/LFE",
+		    AC97_AD_MISC, 7, 1, 0),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Downmix",
+		.info = snd_ac97_ad1888_downmix_info,
+		.get = snd_ac97_ad1888_downmix_get,
+		.put = snd_ac97_ad1888_downmix_put
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "V_REFOUT",
+		.info = snd_ac97_ad1985_vrefout_info,
+		.get = snd_ac97_ad1985_vrefout_get,
+		.put = snd_ac97_ad1985_vrefout_put
+	},
+	AC97_SURROUND_JACK_MODE_CTL,
+	AC97_CHANNEL_MODE_CTL,
+
+	AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0),
+	AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0),
 };
 
 static void ad1985_update_jacks(struct snd_ac97 *ac97)
@@ -1967,9 +2136,16 @@
 {
 	int err;
 
-	if ((err = patch_ad1980_specific(ac97)) < 0)
+	/* rename 0x04 as "Master" and 0x02 as "Master Surround" */
+	snd_ac97_rename_vol_ctl(ac97, "Master Playback",
+				"Master Surround Playback");
+	snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback");
+
+	if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0)
 		return err;
-	return patch_build_controls(ac97, snd_ac97_ad1985_controls, ARRAY_SIZE(snd_ac97_ad1985_controls));
+
+	return patch_build_controls(ac97, snd_ac97_ad1985_controls,
+				    ARRAY_SIZE(snd_ac97_ad1985_controls));
 }
 
 static struct snd_ac97_build_ops patch_ad1985_build_ops = {
@@ -1989,24 +2165,311 @@
 	ac97->build_ops = &patch_ad1985_build_ops;
 	misc = snd_ac97_read(ac97, AC97_AD_MISC);
 	/* switch front/surround line-out/hp-out */
-	/* center/LFE, mic in 3.75V mode */
 	/* AD-compatible mode */
 	/* Stereo mutes enabled */
-	/* in accordance with ADI driver: misc | 0x5c28 */
 	snd_ac97_write_cache(ac97, AC97_AD_MISC, misc |
-			     AC97_AD198X_VREFH |
 			     AC97_AD198X_LOSEL |
 			     AC97_AD198X_HPSEL |
-			     AC97_AD198X_CLDIS |
-			     AC97_AD198X_LODIS |
 			     AC97_AD198X_MSPLT |
 			     AC97_AD198X_AC97NC);
 	ac97->flags |= AC97_STEREO_MUTES;
+
+	/* update current jack configuration */
+	ad1985_update_jacks(ac97);
+
 	/* 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;
 }
 
+static int snd_ac97_ad1986_bool_info(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_ac97_ad1986_lososel_get(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+	unsigned short val;
+
+	val = ac97->regs[AC97_AD_MISC3];
+	ucontrol->value.integer.value[0] = (val & AC97_AD1986_LOSEL) != 0;
+	return 0;
+}
+
+static int snd_ac97_ad1986_lososel_put(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+	int ret0;
+	int ret1;
+	int sprd = (ac97->regs[AC97_AD_MISC] & AC97_AD1986_SPRD) != 0;
+
+	ret0 = snd_ac97_update_bits(ac97, AC97_AD_MISC3, AC97_AD1986_LOSEL,
+					ucontrol->value.integer.value[0] != 0
+				    ? AC97_AD1986_LOSEL : 0);
+	if (ret0 < 0)
+		return ret0;
+
+	/* SOSEL is set to values of "Spread" or "Exchange F/S" controls */
+	ret1 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SOSEL,
+				    (ucontrol->value.integer.value[0] != 0
+				     || sprd)
+				    ? AC97_AD1986_SOSEL : 0);
+	if (ret1 < 0)
+		return ret1;
+
+	return (ret0 > 0 || ret1 > 0) ? 1 : 0;
+}
+
+static int snd_ac97_ad1986_spread_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+	unsigned short val;
+
+	val = ac97->regs[AC97_AD_MISC];
+	ucontrol->value.integer.value[0] = (val & AC97_AD1986_SPRD) != 0;
+	return 0;
+}
+
+static int snd_ac97_ad1986_spread_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+	int ret0;
+	int ret1;
+	int sprd = (ac97->regs[AC97_AD_MISC3] & AC97_AD1986_LOSEL) != 0;
+
+	ret0 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SPRD,
+					ucontrol->value.integer.value[0] != 0
+				    ? AC97_AD1986_SPRD : 0);
+	if (ret0 < 0)
+		return ret0;
+
+	/* SOSEL is set to values of "Spread" or "Exchange F/S" controls */
+	ret1 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SOSEL,
+				    (ucontrol->value.integer.value[0] != 0
+				     || sprd)
+				    ? AC97_AD1986_SOSEL : 0);
+	if (ret1 < 0)
+		return ret1;
+
+	return (ret0 > 0 || ret1 > 0) ? 1 : 0;
+}
+
+static int snd_ac97_ad1986_miclisel_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.integer.value[0] = ac97->spec.ad18xx.swap_mic_linein;
+	return 0;
+}
+
+static int snd_ac97_ad1986_miclisel_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+	unsigned char swap = ucontrol->value.integer.value[0] != 0;
+
+	if (swap != ac97->spec.ad18xx.swap_mic_linein) {
+		ac97->spec.ad18xx.swap_mic_linein = swap;
+		if (ac97->build_ops->update_jacks)
+			ac97->build_ops->update_jacks(ac97);
+		return 1;
+	}
+	return 0;
+}
+
+static int snd_ac97_ad1986_vrefout_get(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	/* Use MIC_1/2 V_REFOUT as the "get" value */
+	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+	unsigned short val;
+	unsigned short reg = ac97->regs[AC97_AD_MISC2];
+	if ((reg & AC97_AD1986_MVREF0) != 0)
+		val = 2;
+	else if ((reg & AC97_AD1986_MVREF1) != 0)
+		val = 3;
+	else if ((reg & AC97_AD1986_MVREF2) != 0)
+		val = 1;
+	else
+		val = 0;
+	ucontrol->value.enumerated.item[0] = val;
+	return 0;
+}
+
+static int snd_ac97_ad1986_vrefout_put(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+	unsigned short cval;
+	unsigned short lval;
+	unsigned short mval;
+	int cret;
+	int lret;
+	int mret;
+
+	switch (ucontrol->value.enumerated.item[0])
+	{
+	case 0: /* High-Z */
+		cval = 0;
+		lval = 0;
+		mval = 0;
+		break;
+	case 1: /* 3.7 V */
+		cval = AC97_AD1986_CVREF2;
+		lval = AC97_AD1986_LVREF2;
+		mval = AC97_AD1986_MVREF2;
+		break;
+	case 2: /* 2.25 V */
+		cval = AC97_AD1986_CVREF0;
+		lval = AC97_AD1986_LVREF0;
+		mval = AC97_AD1986_MVREF0;
+		break;
+	case 3: /* 0 V */
+		cval = AC97_AD1986_CVREF1;
+		lval = AC97_AD1986_LVREF1;
+		mval = AC97_AD1986_MVREF1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	cret = snd_ac97_update_bits(ac97, AC97_AD_MISC2,
+				    AC97_AD1986_CVREF_MASK, cval);
+	if (cret < 0)
+		return cret;
+	lret = snd_ac97_update_bits(ac97, AC97_AD_MISC3,
+				    AC97_AD1986_LVREF_MASK, lval);
+	if (lret < 0)
+		return lret;
+	mret = snd_ac97_update_bits(ac97, AC97_AD_MISC2,
+				    AC97_AD1986_MVREF_MASK, mval);
+	if (mret < 0)
+		return mret;
+
+	return (cret > 0 || lret > 0 || mret > 0) ? 1 : 0;
+}
+
+static const struct snd_kcontrol_new snd_ac97_ad1986_controls[] = {
+	AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Exchange Front/Surround",
+		.info = snd_ac97_ad1986_bool_info,
+		.get = snd_ac97_ad1986_lososel_get,
+		.put = snd_ac97_ad1986_lososel_put
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Exchange Mic/Line In",
+		.info = snd_ac97_ad1986_bool_info,
+		.get = snd_ac97_ad1986_miclisel_get,
+		.put = snd_ac97_ad1986_miclisel_put
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Spread Front to Surround and Center/LFE",
+		.info = snd_ac97_ad1986_bool_info,
+		.get = snd_ac97_ad1986_spread_get,
+		.put = snd_ac97_ad1986_spread_put
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Downmix",
+		.info = snd_ac97_ad1888_downmix_info,
+		.get = snd_ac97_ad1888_downmix_get,
+		.put = snd_ac97_ad1888_downmix_put
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "V_REFOUT",
+		.info = snd_ac97_ad1985_vrefout_info,
+		.get = snd_ac97_ad1986_vrefout_get,
+		.put = snd_ac97_ad1986_vrefout_put
+	},
+	AC97_SURROUND_JACK_MODE_CTL,
+	AC97_CHANNEL_MODE_CTL,
+
+	AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0),
+	AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0)
+};
+
+static void ad1986_update_jacks(struct snd_ac97 *ac97)
+{
+	unsigned short misc_val = 0;
+	unsigned short ser_val;
+
+	/* disable SURROUND and CENTER/LFE if not surround mode */
+	if (! is_surround_on(ac97))
+		misc_val |= AC97_AD1986_SODIS;
+	if (! is_clfe_on(ac97))
+		misc_val |= AC97_AD1986_CLDIS;
+
+	/* select line input (default=LINE_IN, SURROUND or MIC_1/2) */
+	if (is_shared_linein(ac97))
+		misc_val |= AC97_AD1986_LISEL_SURR;
+	else if (ac97->spec.ad18xx.swap_mic_linein != 0)
+		misc_val |= AC97_AD1986_LISEL_MIC;
+	snd_ac97_update_bits(ac97, AC97_AD_MISC,
+			     AC97_AD1986_SODIS | AC97_AD1986_CLDIS |
+			     AC97_AD1986_LISEL_MASK,
+			     misc_val);
+
+	/* select microphone input (MIC_1/2, Center/LFE or LINE_IN) */
+	if (is_shared_micin(ac97))
+		ser_val = AC97_AD1986_OMS_C;
+	else if (ac97->spec.ad18xx.swap_mic_linein != 0)
+		ser_val = AC97_AD1986_OMS_L;
+	else
+		ser_val = AC97_AD1986_OMS_M;
+	snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG,
+			     AC97_AD1986_OMS_MASK,
+			     ser_val);
+}
+
+static int patch_ad1986_specific(struct snd_ac97 *ac97)
+{
+	int err;
+
+	if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0)
+		return err;
+
+	return patch_build_controls(ac97, snd_ac97_ad1986_controls,
+				    ARRAY_SIZE(snd_ac97_ad1985_controls));
+}
+
+static struct snd_ac97_build_ops patch_ad1986_build_ops = {
+	.build_post_spdif = patch_ad198x_post_spdif,
+	.build_specific = patch_ad1986_specific,
+#ifdef CONFIG_PM
+	.resume = ad18xx_resume,
+#endif
+	.update_jacks = ad1986_update_jacks,
+};
+
+int patch_ad1986(struct snd_ac97 * ac97)
+{
+	patch_ad1881(ac97);
+	ac97->build_ops = &patch_ad1986_build_ops;
+	ac97->flags |= AC97_STEREO_MUTES;
+
+	/* update current jack configuration */
+	ad1986_update_jacks(ac97);
+
+	return 0;
+}
+
+
 /*
  * realtek ALC65x/850 codecs
  */
@@ -2014,12 +2477,12 @@
 {
 	int shared;
 	
-	/* shared Line-In */
-	shared = is_shared_linein(ac97);
+	/* shared Line-In / Surround Out */
+	shared = is_shared_surrout(ac97);
 	snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 9,
 			     shared ? (1 << 9) : 0);
-	/* update shared Mic */
-	shared = is_shared_micin(ac97);
+	/* update shared Mic In / Center/LFE Out */
+	shared = is_shared_clfeout(ac97);
 	/* disable/enable vref */
 	snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
 			     shared ? (1 << 12) : 0);
@@ -2064,7 +2527,7 @@
 	/* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */
 };
 
-static DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0);
 
 static int patch_alc650_specific(struct snd_ac97 * ac97)
 {
@@ -2149,12 +2612,12 @@
 {
 	int shared;
 	
-	/* shared Line-In */
-	shared = is_shared_linein(ac97);
+	/* shared Line-In / Surround Out */
+	shared = is_shared_surrout(ac97);
 	ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 9,
 			      shared ? (1 << 9) : 0, 0);
-	/* update shared mic */
-	shared = is_shared_micin(ac97);
+	/* update shared Mic In / Center/LFE Out */
+	shared = is_shared_clfeout(ac97);
 	/* misc control; vrefout disable */
 	snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
 			     shared ? (1 << 12) : 0);
@@ -2264,7 +2727,8 @@
 		if (ac97->subsystem_vendor == 0x1462 &&
 		    (ac97->subsystem_device == 0x0131 || /* MSI S270 laptop */
 		     ac97->subsystem_device == 0x0161 || /* LG K1 Express */
-		     ac97->subsystem_device == 0x0351))  /* MSI L725 laptop */
+		     ac97->subsystem_device == 0x0351 || /* MSI L725 laptop */
+		     ac97->subsystem_device == 0x0061))  /* MSI S250 laptop */
 			val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */
 		else
 			val |= (1 << 1); /* Pin 47 is spdif input pin */
@@ -2297,16 +2761,16 @@
 {
 	int shared;
 	
-	/* shared Line-In */
-	shared = is_shared_linein(ac97);
+	/* shared Line-In / Surround Out */
+	shared = is_shared_surrout(ac97);
 	/* SURR 1kOhm (bit4), Amp (bit5) */
 	snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5),
 			     shared ? (1<<5) : (1<<4));
 	/* LINE-IN = 0, SURROUND = 2 */
 	snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12,
 			     shared ? (2<<12) : (0<<12));
-	/* update shared mic */
-	shared = is_shared_micin(ac97);
+	/* update shared Mic In / Center/LFE Out */
+	shared = is_shared_clfeout(ac97);
 	/* Vref disable (bit12), 1kOhm (bit13) */
 	snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13),
 			     shared ? (1<<12) : (1<<13));
@@ -2379,9 +2843,9 @@
  */
 static void cm9738_update_jacks(struct snd_ac97 *ac97)
 {
-	/* shared Line-In */
+	/* shared Line-In / Surround Out */
 	snd_ac97_update_bits(ac97, AC97_CM9738_VENDOR_CTRL, 1 << 10,
-			     is_shared_linein(ac97) ? (1 << 10) : 0);
+			     is_shared_surrout(ac97) ? (1 << 10) : 0);
 }
 
 static const struct snd_kcontrol_new snd_ac97_cm9738_controls[] = {
@@ -2463,12 +2927,12 @@
 
 static void cm9739_update_jacks(struct snd_ac97 *ac97)
 {
-	/* shared Line-In */
+	/* shared Line-In / Surround Out */
 	snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 1 << 10,
-			     is_shared_linein(ac97) ? (1 << 10) : 0);
-	/* shared Mic */
+			     is_shared_surrout(ac97) ? (1 << 10) : 0);
+	/* shared Mic In / Center/LFE Out **/
 	snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000,
-			     is_shared_micin(ac97) ? 0x1000 : 0x2000);
+			     is_shared_clfeout(ac97) ? 0x1000 : 0x2000);
 }
 
 static const struct snd_kcontrol_new snd_ac97_cm9739_controls[] = {
@@ -2580,8 +3044,8 @@
 
 	val |= surr_on[ac97->spec.dev_flags][is_surround_on(ac97)];
 	val |= clfe_on[ac97->spec.dev_flags][is_clfe_on(ac97)];
-	val |= surr_shared[ac97->spec.dev_flags][is_shared_linein(ac97)];
-	val |= clfe_shared[ac97->spec.dev_flags][is_shared_micin(ac97)];
+	val |= surr_shared[ac97->spec.dev_flags][is_shared_surrout(ac97)];
+	val |= clfe_shared[ac97->spec.dev_flags][is_shared_clfeout(ac97)];
 
 	snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3c88, val);
 }
@@ -2821,6 +3285,7 @@
 	snd_ac97_write_cache(ac97, 0x5c, 0x20);
 	ac97->ext_id |= AC97_EI_SPDIF;	/* force the detection of spdif */
 	ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
+	ac97->build_ops = &patch_vt1616_ops;
 	return 0;
 }
 
@@ -2828,12 +3293,12 @@
  */
 static void it2646_update_jacks(struct snd_ac97 *ac97)
 {
-	/* shared Line-In */
+	/* shared Line-In / Surround Out */
 	snd_ac97_update_bits(ac97, 0x76, 1 << 9,
-			     is_shared_linein(ac97) ? (1<<9) : 0);
-	/* shared Mic */
+			     is_shared_surrout(ac97) ? (1<<9) : 0);
+	/* shared Mic / Center/LFE Out */
 	snd_ac97_update_bits(ac97, 0x76, 1 << 10,
-			     is_shared_micin(ac97) ? (1<<10) : 0);
+			     is_shared_clfeout(ac97) ? (1<<10) : 0);
 }
 
 static const struct snd_kcontrol_new snd_ac97_controls_it2646[] = {
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h
index 7419792..94340da 100644
--- a/sound/pci/ac97/ac97_patch.h
+++ b/sound/pci/ac97/ac97_patch.h
@@ -48,6 +48,7 @@
 int patch_ad1981a(struct snd_ac97 * ac97);
 int patch_ad1981b(struct snd_ac97 * ac97);
 int patch_ad1985(struct snd_ac97 * ac97);
+int patch_ad1986(struct snd_ac97 * ac97);
 int patch_alc650(struct snd_ac97 * ac97);
 int patch_alc655(struct snd_ac97 * ac97);
 int patch_alc850(struct snd_ac97 * ac97);
diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c
index c153cb7..dc26820 100644
--- a/sound/pci/ac97/ak4531_codec.c
+++ b/sound/pci/ac97/ak4531_codec.c
@@ -267,9 +267,9 @@
 	return change;
 }
 
-static DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0);
 
 static struct snd_kcontrol_new snd_ak4531_controls[] = {
 
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index 9f406fb..8afcb98 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -444,7 +444,7 @@
 }
 
 static int snd_als300_pcm_hw_params(struct snd_pcm_substream *substream,
-					snd_pcm_hw_params_t * hw_params)
+				    struct snd_pcm_hw_params *hw_params)
 {
 	return snd_pcm_lib_malloc_pages(substream,
 					params_buffer_bytes(hw_params));
@@ -673,7 +673,7 @@
 	snd_als300_dbgcallleave();
 }
 
-static int __devinit snd_als300_create(snd_card_t *card,
+static int __devinit snd_als300_create(struct snd_card *card,
 				       struct pci_dev *pci, int chip_type,
 				       struct snd_als300 **rchip)
 {
@@ -681,7 +681,7 @@
 	void *irq_handler;
 	int err;
 
-	static snd_device_ops_t ops = {
+	static struct snd_device_ops ops = {
 		.dev_free = snd_als300_dev_free,
 	};
 	*rchip = NULL;
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 476c343..7d8053b 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -45,6 +45,7 @@
 static int ac97_clock = 48000;
 static char *ac97_quirk;
 static int spdif_aclink = 1;
+static int ac97_codec = -1;
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for ATI IXP controller.");
@@ -54,6 +55,8 @@
 MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz).");
 module_param(ac97_quirk, charp, 0444);
 MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
+module_param(ac97_codec, int, 0444);
+MODULE_PARM_DESC(ac97_codec, "Specify codec instead of probing.");
 module_param(spdif_aclink, bool, 0444);
 MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link.");
 
@@ -293,6 +296,10 @@
 
 MODULE_DEVICE_TABLE(pci, snd_atiixp_ids);
 
+static struct snd_pci_quirk atiixp_quirks[] __devinitdata = {
+	SND_PCI_QUIRK(0x15bd, 0x3100, "DFI RS482", 0),
+	{ } /* terminator */
+};
 
 /*
  * lowlevel functions
@@ -553,11 +560,33 @@
 	     ATI_REG_ISR_CODEC2_NOT_READY)
 #define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME)
 
+static int ac97_probing_bugs(struct pci_dev *pci)
+{
+	const struct snd_pci_quirk *q;
+
+	q = snd_pci_quirk_lookup(pci, atiixp_quirks);
+	if (q) {
+		snd_printdd(KERN_INFO "Atiixp quirk for %s.  "
+			    "Forcing codec %d\n", q->name, q->value);
+		return q->value;
+	}
+	/* this hardware doesn't need workarounds.  Probe for codec */
+	return -1;
+}
+
 static int snd_atiixp_codec_detect(struct atiixp *chip)
 {
 	int timeout;
 
 	chip->codec_not_ready_bits = 0;
+	if (ac97_codec == -1)
+		ac97_codec = ac97_probing_bugs(chip->pci);
+	if (ac97_codec >= 0) {
+		chip->codec_not_ready_bits |= 
+			CODEC_CHECK_BITS ^ (1 << (ac97_codec + 10));
+		return 0;
+	}
+
 	atiixp_write(chip, IER, CODEC_CHECK_BITS);
 	/* wait for the interrupts */
 	timeout = 50;
@@ -1396,7 +1425,7 @@
 		ac97.private_data = chip;
 		ac97.pci = chip->pci;
 		ac97.num = i;
-		ac97.scaps = AC97_SCAP_SKIP_MODEM;
+		ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE;
 		if (! chip->spdif_over_aclink)
 			ac97.scaps |= AC97_SCAP_NO_SPDIF;
 		if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index cc2e6b9..904023f 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -1090,7 +1090,7 @@
 		ac97.private_data = chip;
 		ac97.pci = chip->pci;
 		ac97.num = i;
-		ac97.scaps = AC97_SCAP_SKIP_AUDIO;
+		ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE;
 		if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
 			chip->ac97[i] = NULL; /* to be sure */
 			snd_printdd("atiixp-modem: codec %d not available for modem\n", i);
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index f61f052..ea6712b 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -1382,7 +1382,6 @@
 	snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf);
 	snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */
 	chip->spdif_enable = 0; /* Set digital SPDIF output off */
-	chip->capture_source = 3; /* Set CAPTURE_SOURCE */
 	//snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */
 	//snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */
 
@@ -1402,8 +1401,22 @@
 		snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */
 		snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */
 	}
-        snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */
-	chip->capture_source = 3; /* Set CAPTURE_SOURCE */
+	if (chip->details->i2c_adc == 1) {
+	        /* Select MIC, Line in, TAD in, AUX in */
+	        snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4);
+		/* Default to CAPTURE_SOURCE to i2s in */
+		chip->capture_source = 3;
+	} else if (chip->details->ac97 == 1) {
+	        /* Default to AC97 in */
+	        snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x444400e4);
+		/* Default to CAPTURE_SOURCE to AC97 in */
+		chip->capture_source = 4;
+	} else {
+	        /* Select MIC, Line in, TAD in, AUX in */
+	        snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4);
+		/* Default to Set CAPTURE_SOURCE to i2s in */
+		chip->capture_source = 3;
+	}
 
         if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */
 		/* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */
@@ -1605,6 +1618,8 @@
 	snd_ca0106_proc_init(chip);
 #endif
 
+	snd_card_set_dev(card, &pci->dev);
+
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
 		return err;
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 9855f52..b913a1f 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -74,8 +74,8 @@
 
 #include "ca0106.h"
 
-static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
-static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
+static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
 
 static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_info *uinfo)
@@ -482,19 +482,6 @@
 	.private_value = ((chid) << 8) | (reg)			\
 }
 
-#define I2C_VOLUME(xname,chid) \
-{								\
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
-	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |		\
-	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,		\
-	.info =  snd_ca0106_i2c_volume_info,			\
-	.get =   snd_ca0106_i2c_volume_get,			\
-	.put =   snd_ca0106_i2c_volume_put,			\
-	.tlv = { .p = snd_ca0106_db_scale2 },			\
-	.private_value = chid					\
-}
-
-
 static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
 	CA_VOLUME("Analog Front Playback Volume",
 		  CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2),
@@ -517,11 +504,6 @@
         CA_VOLUME("CAPTURE feedback Playback Volume",
 		  1, CAPTURE_CONTROL),
 
-        I2C_VOLUME("Phone Capture Volume", 0),
-        I2C_VOLUME("Mic Capture Volume", 1),
-        I2C_VOLUME("Line in Capture Volume", 2),
-        I2C_VOLUME("Aux Capture Volume", 3),
-
 	{
 		.access =	SNDRV_CTL_ELEM_ACCESS_READ,
 		.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
@@ -539,14 +521,14 @@
 	},
 	{
 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name =		"Digital Capture Source",
+		.name =		"Digital Source Capture Enum",
 		.info =		snd_ca0106_capture_source_info,
 		.get =		snd_ca0106_capture_source_get,
 		.put =		snd_ca0106_capture_source_put
 	},
 	{
 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name =		"Capture Source",
+		.name =		"Analog Source Capture Enum",
 		.info =		snd_ca0106_i2c_capture_source_info,
 		.get =		snd_ca0106_i2c_capture_source_get,
 		.put =		snd_ca0106_i2c_capture_source_put
@@ -561,6 +543,25 @@
 	},
 };
 
+#define I2C_VOLUME(xname,chid) \
+{								\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |		\
+	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,		\
+	.info =  snd_ca0106_i2c_volume_info,			\
+	.get =   snd_ca0106_i2c_volume_get,			\
+	.put =   snd_ca0106_i2c_volume_put,			\
+	.tlv = { .p = snd_ca0106_db_scale2 },			\
+	.private_value = chid					\
+}
+
+static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata = {
+        I2C_VOLUME("Phone Capture Volume", 0),
+        I2C_VOLUME("Mic Capture Volume", 1),
+        I2C_VOLUME("Line in Capture Volume", 2),
+        I2C_VOLUME("Aux Capture Volume", 3),
+};
+
 static int __devinit remove_ctl(struct snd_card *card, const char *name)
 {
 	struct snd_ctl_elem_id id;
@@ -645,6 +646,11 @@
 			return err;
 	}
 	if (emu->details->i2c_adc == 1) {
+		for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_i2c_adc_ctls); i++) {
+			err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_i2c_adc_ctls[i], emu));
+			if (err < 0)
+				return err;
+		}
 		if (emu->details->gpio_type == 1)
 			err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu));
 		else  /* gpio_type == 2 */
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index 8e5519d..44cf546 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -1055,7 +1055,7 @@
 	return change;
 }
 
-static DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0);
 
 static struct snd_kcontrol_new snd_cs4281_fm_vol = 
 {
diff --git a/sound/pci/echoaudio/darla20.c b/sound/pci/echoaudio/darla20.c
index b7108e2..8e7fe03 100644
--- a/sound/pci/echoaudio/darla20.c
+++ b/sound/pci/echoaudio/darla20.c
@@ -47,6 +47,7 @@
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/darla24.c b/sound/pci/echoaudio/darla24.c
index e59a982..a13c623 100644
--- a/sound/pci/echoaudio/darla24.c
+++ b/sound/pci/echoaudio/darla24.c
@@ -51,6 +51,7 @@
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/echo3g.c b/sound/pci/echoaudio/echo3g.c
index 12099fe..8fb1582 100644
--- a/sound/pci/echoaudio/echo3g.c
+++ b/sound/pci/echoaudio/echo3g.c
@@ -58,6 +58,7 @@
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c
index d26a1d1..48eb7c5 100644
--- a/sound/pci/echoaudio/echo3g_dsp.c
+++ b/sound/pci/echoaudio/echo3g_dsp.c
@@ -39,7 +39,7 @@
 static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq,
 			     char force);
 
-#include <linux/irq.h>
+#include <linux/interrupt.h>
 
 static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
 {
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 047e0b5..6a428b8 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -34,6 +34,7 @@
 MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard.");
 
 static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999};
+static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1);
 
 static int get_firmware(const struct firmware **fw_entry,
 			const struct firmware *frm, struct echoaudio *chip)
@@ -1011,17 +1012,21 @@
 static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = {
 	.name = "Line Playback Volume",
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
 	.info = snd_echo_output_gain_info,
 	.get = snd_echo_output_gain_get,
 	.put = snd_echo_output_gain_put,
+	.tlv = {.p = db_scale_output_gain},
 };
 #else
 static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = {
 	.name = "PCM Playback Volume",
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
 	.info = snd_echo_output_gain_info,
 	.get = snd_echo_output_gain_get,
 	.put = snd_echo_output_gain_put,
+	.tlv = {.p = db_scale_output_gain},
 };
 #endif
 
@@ -1080,12 +1085,16 @@
 	return changed;
 }
 
+static const DECLARE_TLV_DB_SCALE(db_scale_input_gain, -2500, 50, 0);
+
 static struct snd_kcontrol_new snd_echo_line_input_gain __devinitdata = {
 	.name = "Line Capture Volume",
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
 	.info = snd_echo_input_gain_info,
 	.get = snd_echo_input_gain_get,
 	.put = snd_echo_input_gain_put,
+	.tlv = {.p = db_scale_input_gain},
 };
 
 #endif /* ECHOCARD_HAS_INPUT_GAIN */
@@ -1277,9 +1286,11 @@
 static struct snd_kcontrol_new snd_echo_monitor_mixer __devinitdata = {
 	.name = "Monitor Mixer Volume",
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
 	.info = snd_echo_mixer_info,
 	.get = snd_echo_mixer_get,
 	.put = snd_echo_mixer_put,
+	.tlv = {.p = db_scale_output_gain},
 };
 
 #endif /* ECHOCARD_HAS_MONITOR */
@@ -1343,9 +1354,11 @@
 static struct snd_kcontrol_new snd_echo_vmixer __devinitdata = {
 	.name = "VMixer Volume",
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
 	.info = snd_echo_vmixer_info,
 	.get = snd_echo_vmixer_get,
 	.put = snd_echo_vmixer_put,
+	.tlv = {.p = db_scale_output_gain},
 };
 
 #endif /* ECHOCARD_HAS_VMIXER */
@@ -1753,9 +1766,12 @@
 static struct snd_kcontrol_new snd_echo_vumeters __devinitdata = {
 	.name = "VU-meters",
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.access = SNDRV_CTL_ELEM_ACCESS_READ |
+		  SNDRV_CTL_ELEM_ACCESS_VOLATILE |
+		  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
 	.info = snd_echo_vumeters_info,
 	.get = snd_echo_vumeters_get,
+	.tlv = {.p = db_scale_output_gain},
 };
 
 
diff --git a/sound/pci/echoaudio/gina20.c b/sound/pci/echoaudio/gina20.c
index 29d6d12..af4d320 100644
--- a/sound/pci/echoaudio/gina20.c
+++ b/sound/pci/echoaudio/gina20.c
@@ -51,6 +51,7 @@
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/gina24.c b/sound/pci/echoaudio/gina24.c
index e464d72..9ff454a 100644
--- a/sound/pci/echoaudio/gina24.c
+++ b/sound/pci/echoaudio/gina24.c
@@ -57,6 +57,7 @@
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/indigo.c b/sound/pci/echoaudio/indigo.c
index bfd2467..37eb726 100644
--- a/sound/pci/echoaudio/indigo.c
+++ b/sound/pci/echoaudio/indigo.c
@@ -49,6 +49,7 @@
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/indigodj.c b/sound/pci/echoaudio/indigodj.c
index 8ed7ff1..dc8b918 100644
--- a/sound/pci/echoaudio/indigodj.c
+++ b/sound/pci/echoaudio/indigodj.c
@@ -49,6 +49,7 @@
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/indigoio.c b/sound/pci/echoaudio/indigoio.c
index a8788e9..eadf326 100644
--- a/sound/pci/echoaudio/indigoio.c
+++ b/sound/pci/echoaudio/indigoio.c
@@ -50,6 +50,7 @@
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/layla20.c b/sound/pci/echoaudio/layla20.c
index e503d74..6cede49 100644
--- a/sound/pci/echoaudio/layla20.c
+++ b/sound/pci/echoaudio/layla20.c
@@ -56,6 +56,7 @@
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/layla24.c b/sound/pci/echoaudio/layla24.c
index d4581fd..44f7354 100644
--- a/sound/pci/echoaudio/layla24.c
+++ b/sound/pci/echoaudio/layla24.c
@@ -58,6 +58,7 @@
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/mia.c b/sound/pci/echoaudio/mia.c
index be40c64..dc172d0 100644
--- a/sound/pci/echoaudio/mia.c
+++ b/sound/pci/echoaudio/mia.c
@@ -56,6 +56,7 @@
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/mona.c b/sound/pci/echoaudio/mona.c
index 5dc512a..c856ed5 100644
--- a/sound/pci/echoaudio/mona.c
+++ b/sound/pci/echoaudio/mona.c
@@ -55,6 +55,7 @@
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 972ec40..80aa585 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -3,8 +3,10 @@
  *                   Creative Labs, Inc.
  *  Routines for control of EMU10K1 chips
  *
- *  Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
+ *  Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
  *      Added support for Audigy 2 Value.
+ *  	Added EMU 1010 support.
+ *  	General bug fixes and enhancements.
  *
  *
  *  BUGS:
@@ -41,8 +43,10 @@
 
 #include <sound/core.h>
 #include <sound/emu10k1.h>
+#include <linux/firmware.h>
 #include "p16v.h"
 #include "tina2.h"
+#include "p17v.h"
 
 
 /*************************************************************************
@@ -117,11 +121,28 @@
 		0x0622,
 		0x1400,
 };
+
+static unsigned int i2c_adc_init[][2] = {
+	{ 0x17, 0x00 }, /* Reset */
+	{ 0x07, 0x00 }, /* Timeout */
+	{ 0x0b, 0x22 },  /* Interface control */
+	{ 0x0c, 0x22 },  /* Master mode control */
+	{ 0x0d, 0x08 },  /* Powerdown control */
+	{ 0x0e, 0xcf },  /* Attenuation Left  0x01 = -103dB, 0xff = 24dB */
+	{ 0x0f, 0xcf },  /* Attenuation Right 0.5dB steps */
+	{ 0x10, 0x7b },  /* ALC Control 1 */
+	{ 0x11, 0x00 },  /* ALC Control 2 */
+	{ 0x12, 0x32 },  /* ALC Control 3 */
+	{ 0x13, 0x00 },  /* Noise gate control */
+	{ 0x14, 0xa6 },  /* Limiter control */
+	{ 0x15, ADC_MUX_2 },  /* ADC Mixer control. Mic for Audigy 2 ZS Notebook */
+};
 	
 static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
 {
 	unsigned int silent_page;
 	int ch;
+	u32 tmp;
 
 	/* disable audio and lock cache */
 	outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE,
@@ -160,8 +181,6 @@
 
 	if (emu->card_capabilities->ca0151_chip) { /* audigy2 */
 		/* Hacks for Alice3 to work independent of haP16V driver */
-		u32 tmp;
-
 		//Setup SRCMulti_I2S SamplingRate
 		tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
 		tmp &= 0xfffff1ff;
@@ -181,8 +200,6 @@
 	}
 	if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */
 		/* Hacks for Alice3 to work independent of haP16V driver */
-		u32 tmp;
-
 		snd_printk(KERN_INFO "Audigy2 value: Special config.\n");
 		//Setup SRCMulti_I2S SamplingRate
 		tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
@@ -211,7 +228,7 @@
 		int size, n;
 
 		size = ARRAY_SIZE(spi_dac_init);
-		for (n=0; n < size; n++)
+		for (n = 0; n < size; n++)
 			snd_emu10k1_spi_write(emu, spi_dac_init[n]);
 
 		snd_emu10k1_ptr20_write(emu, 0x60, 0, 0x10);
@@ -228,6 +245,23 @@
 		outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */
 
 	}
+	if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */
+		int size, n;
+
+		snd_emu10k1_ptr20_write(emu, P17V_I2S_SRC_SEL, 0, 0x2020205f);
+		tmp = inl(emu->port + A_IOCFG);
+		outl(tmp | 0x4, emu->port + A_IOCFG);  /* Set bit 2 for mic input */
+		tmp = inl(emu->port + A_IOCFG);
+		size = ARRAY_SIZE(i2c_adc_init);
+		for (n = 0; n < size; n++)
+			snd_emu10k1_i2c_write(emu, i2c_adc_init[n][0], i2c_adc_init[n][1]);
+		for (n=0; n < 4; n++) {
+			emu->i2c_capture_volume[n][0]= 0xcf;
+			emu->i2c_capture_volume[n][1]= 0xcf;
+		}
+
+	}
+
 	
 	snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr);
 	snd_emu10k1_ptr_write(emu, TCB, 0, 0);	/* taken from original driver */
@@ -239,6 +273,10 @@
 		snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page);
 	}
 
+	if (emu->card_capabilities->emu1010) {
+		outl(HCFG_AUTOMUTE_ASYNC |
+			HCFG_EMU32_SLAVE |
+			HCFG_AUDIOENABLE, emu->port + HCFG);
 	/*
 	 *  Hokay, setup HCFG
 	 *   Mute Disable Audio = 0
@@ -246,7 +284,7 @@
 	 *   Lock Sound Memory = 0
 	 *   Auto Mute = 1
 	 */
-	if (emu->audigy) {
+	} else if (emu->audigy) {
 		if (emu->revision == 4) /* audigy2 */
 			outl(HCFG_AUDIOENABLE |
 			     HCFG_AC3ENABLE_CDSPDIF |
@@ -265,8 +303,10 @@
 		outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
 
 	if (enable_ir) {	/* enable IR for SB Live */
-		if ( emu->card_capabilities->emu1212m) {
-			;  /* Disable all access to A_IOCFG for the emu1212m */
+		if (emu->card_capabilities->emu1010) {
+			;  /* Disable all access to A_IOCFG for the emu1010 */
+		} else if (emu->card_capabilities->i2c_adc) {
+			;  /* Disable A_IOCFG for Audigy 2 ZS Notebook */
 		} else if (emu->audigy) {
 			unsigned int reg = inl(emu->port + A_IOCFG);
 			outl(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG);
@@ -284,8 +324,10 @@
  		}
 	}
 	
-	if ( emu->card_capabilities->emu1212m) {
-		;  /* Disable all access to A_IOCFG for the emu1212m */
+	if (emu->card_capabilities->emu1010) {
+		;  /* Disable all access to A_IOCFG for the emu1010 */
+	} else if (emu->card_capabilities->i2c_adc) {
+		;  /* Disable A_IOCFG for Audigy 2 ZS Notebook */
 	} else if (emu->audigy) {	/* enable analog output */
 		unsigned int reg = inl(emu->port + A_IOCFG);
 		outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG);
@@ -302,8 +344,10 @@
 	outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG);
 
 	/* Enable analog/digital outs on audigy */
-	if ( emu->card_capabilities->emu1212m) {
-		;  /* Disable all access to A_IOCFG for the emu1212m */
+	if (emu->card_capabilities->emu1010) {
+		;  /* Disable all access to A_IOCFG for the emu1010 */
+	} else if (emu->card_capabilities->i2c_adc) {
+		;  /* Disable A_IOCFG for Audigy 2 ZS Notebook */
 	} else if (emu->audigy) {
 		outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG);
  
@@ -596,133 +640,423 @@
 	return 0;
 }
 
-static int snd_emu1212m_fpga_write(struct snd_emu10k1 * emu, int reg, int value)
+static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * filename)
 {
-	if (reg<0 || reg>0x3f)
-		return 1;
-	reg+=0x40; /* 0x40 upwards are registers. */
-	if (value<0 || value>0x3f) /* 0 to 0x3f are values */
-		return 1;
-	outl(reg, emu->port + A_IOCFG);
-	outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
-	outl(value, emu->port + A_IOCFG);
-	outl(value | 0x80 , emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
+	int err;
+	int n, i;
+	int reg;
+	int value;
+	const struct firmware *fw_entry;
 
+	if ((err = request_firmware(&fw_entry, filename, &emu->pci->dev)) != 0) {
+		snd_printk(KERN_ERR "firmware: %s not found. Err=%d\n",filename, err);
+		return err;
+	}
+	snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size);
+	if (fw_entry->size != 0x133a4) {
+		snd_printk(KERN_ERR "firmware: %s wrong size.\n",filename);
+		return -EINVAL;
+	}
+
+	/* The FPGA is a Xilinx Spartan IIE XC2S50E */
+	/* GPIO7 -> FPGA PGMN
+	 * GPIO6 -> FPGA CCLK
+	 * GPIO5 -> FPGA DIN
+	 * FPGA CONFIG OFF -> FPGA PGMN
+	 */
+	outl(0x00, emu->port + A_IOCFG); /* Set PGMN low for 1uS. */
+	udelay(1);
+	outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */
+	udelay(100); /* Allow FPGA memory to clean */
+	for(n = 0; n < fw_entry->size; n++) {
+		value=fw_entry->data[n];	
+		for(i = 0; i < 8; i++) {
+			reg = 0x80;
+			if (value & 0x1)
+				reg = reg | 0x20;
+			value = value >> 1;   
+			outl(reg, emu->port + A_IOCFG);
+			outl(reg | 0x40, emu->port + A_IOCFG);
+		}
+	}
+	/* After programming, set GPIO bit 4 high again. */
+	outl(0x10, emu->port + A_IOCFG);
+	
+
+        release_firmware(fw_entry);
 	return 0;
 }
 
-static int snd_emu1212m_fpga_read(struct snd_emu10k1 * emu, int reg, int *value)
-{
-	if (reg<0 || reg>0x3f)
-		return 1;
-	reg+=0x40; /* 0x40 upwards are registers. */
-	outl(reg, emu->port + A_IOCFG);
-	outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
-	*value = inl(emu->port + A_IOCFG);
-
-	return 0;
-}
-
-static int snd_emu1212m_fpga_netlist_write(struct snd_emu10k1 * emu, int reg, int value)
-{
-	snd_emu1212m_fpga_write(emu, 0x00, ((reg >> 8) & 0x3f) );
-	snd_emu1212m_fpga_write(emu, 0x01, (reg & 0x3f) );
-	snd_emu1212m_fpga_write(emu, 0x02, ((value >> 8) & 0x3f) );
-	snd_emu1212m_fpga_write(emu, 0x03, (value & 0x3f) );
-
-	return 0;
-}
-
-static int snd_emu10k1_emu1212m_init(struct snd_emu10k1 * emu)
+static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
 {
 	unsigned int i;
-	int tmp;
+	int tmp,tmp2;
+	int reg;
+	int err;
+	const char *hana_filename = "emu/hana.fw";
+	const char *dock_filename = "emu/audio_dock.fw";
 
-	snd_printk(KERN_ERR "emu1212m: Special config.\n");
+	snd_printk(KERN_INFO "emu1010: Special config.\n");
+	/* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave,
+	 * Lock Sound Memory Cache, Lock Tank Memory Cache,
+	 * Mute all codecs.
+	 */
 	outl(0x0005a00c, emu->port + HCFG);
-	outl(0x0005a004, emu->port + HCFG);
+	/* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave,
+	 * Lock Tank Memory Cache,
+	 * Mute all codecs.
+	 */
+	outl(0x0005a004, emu->port + HCFG); 
+	/* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave,
+	 * Mute all codecs.
+	 */
 	outl(0x0005a000, emu->port + HCFG);
+	/* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave,
+	 * Mute all codecs.
+	 */
 	outl(0x0005a000, emu->port + HCFG);
 
-	snd_emu1212m_fpga_read(emu, 0x22, &tmp );
-	snd_emu1212m_fpga_read(emu, 0x23, &tmp );
-	snd_emu1212m_fpga_read(emu, 0x24, &tmp );
-	snd_emu1212m_fpga_write(emu, 0x04, 0x01 );
-	snd_emu1212m_fpga_read(emu, 0x0b, &tmp );
-	snd_emu1212m_fpga_write(emu, 0x0b, 0x01 );
-	snd_emu1212m_fpga_read(emu, 0x10, &tmp );
-	snd_emu1212m_fpga_write(emu, 0x10, 0x00 );
-	snd_emu1212m_fpga_read(emu, 0x11, &tmp );
-	snd_emu1212m_fpga_write(emu, 0x11, 0x30 );
-	snd_emu1212m_fpga_read(emu, 0x13, &tmp );
-	snd_emu1212m_fpga_write(emu, 0x13, 0x0f );
-	snd_emu1212m_fpga_read(emu, 0x11, &tmp );
-	snd_emu1212m_fpga_write(emu, 0x11, 0x30 );
-	snd_emu1212m_fpga_read(emu, 0x0a, &tmp );
-	snd_emu1212m_fpga_write(emu, 0x0a, 0x10 );
-	snd_emu1212m_fpga_write(emu, 0x0c, 0x19 );
-	snd_emu1212m_fpga_write(emu, 0x12, 0x0c );
-	snd_emu1212m_fpga_write(emu, 0x09, 0x0f );
-	snd_emu1212m_fpga_write(emu, 0x06, 0x00 );
-	snd_emu1212m_fpga_write(emu, 0x05, 0x00 );
-	snd_emu1212m_fpga_write(emu, 0x0e, 0x12 );
-	snd_emu1212m_fpga_netlist_write(emu, 0x0000, 0x0200);
-	snd_emu1212m_fpga_netlist_write(emu, 0x0001, 0x0201);
-	snd_emu1212m_fpga_netlist_write(emu, 0x0002, 0x0500);
-	snd_emu1212m_fpga_netlist_write(emu, 0x0003, 0x0501);
-	snd_emu1212m_fpga_netlist_write(emu, 0x0004, 0x0400);
-	snd_emu1212m_fpga_netlist_write(emu, 0x0005, 0x0401);
-	snd_emu1212m_fpga_netlist_write(emu, 0x0006, 0x0402);
-	snd_emu1212m_fpga_netlist_write(emu, 0x0007, 0x0403);
-	snd_emu1212m_fpga_netlist_write(emu, 0x0008, 0x0404);
-	snd_emu1212m_fpga_netlist_write(emu, 0x0009, 0x0405);
-	snd_emu1212m_fpga_netlist_write(emu, 0x000a, 0x0406);
-	snd_emu1212m_fpga_netlist_write(emu, 0x000b, 0x0407);
-	snd_emu1212m_fpga_netlist_write(emu, 0x000c, 0x0100);
-	snd_emu1212m_fpga_netlist_write(emu, 0x000d, 0x0104);
-	snd_emu1212m_fpga_netlist_write(emu, 0x000e, 0x0200);
-	snd_emu1212m_fpga_netlist_write(emu, 0x000f, 0x0201);
-	for (i=0;i < 0x20;i++) {
-		snd_emu1212m_fpga_netlist_write(emu, 0x0100+i, 0x0000);
-	}
-	for (i=0;i < 4;i++) {
-		snd_emu1212m_fpga_netlist_write(emu, 0x0200+i, 0x0000);
-	}
-	for (i=0;i < 7;i++) {
-		snd_emu1212m_fpga_netlist_write(emu, 0x0300+i, 0x0000);
-	}
-	for (i=0;i < 7;i++) {
-		snd_emu1212m_fpga_netlist_write(emu, 0x0400+i, 0x0000);
-	}
-	snd_emu1212m_fpga_netlist_write(emu, 0x0500, 0x0108);
-	snd_emu1212m_fpga_netlist_write(emu, 0x0501, 0x010c);
-	snd_emu1212m_fpga_netlist_write(emu, 0x0600, 0x0110);
-	snd_emu1212m_fpga_netlist_write(emu, 0x0601, 0x0114);
-	snd_emu1212m_fpga_netlist_write(emu, 0x0700, 0x0118);
-	snd_emu1212m_fpga_netlist_write(emu, 0x0701, 0x011c);
-	snd_emu1212m_fpga_write(emu, 0x07, 0x01 );
+	/* Disable 48Volt power to Audio Dock */
+	snd_emu1010_fpga_write(emu,  EMU_HANA_DOCK_PWR,  0 );
 
-	snd_emu1212m_fpga_read(emu, 0x21, &tmp );
+	/* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */
+	snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
+	snd_printdd("reg1=0x%x\n",reg);
+	if (reg == 0x55) {
+		/* FPGA netlist already present so clear it */
+		/* Return to programming mode */
 
-	outl(0x0000a000, emu->port + HCFG);
+		snd_emu1010_fpga_write(emu,  EMU_HANA_FPGA_CONFIG, 0x02 );
+	}
+	snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
+	snd_printdd("reg2=0x%x\n",reg);
+	if (reg == 0x55) {
+		/* FPGA failed to return to programming mode */
+		return -ENODEV;
+	}
+	snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg);
+	if ((err = snd_emu1010_load_firmware(emu, hana_filename)) != 0) {
+		snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", hana_filename);
+		return err;
+	}
+
+	/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
+	snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
+	if (reg != 0x55) {
+		/* FPGA failed to be programmed */
+		snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg=0x%x\n", reg);
+		return -ENODEV;
+	}
+
+	snd_printk(KERN_INFO "emu1010: Hana Firmware loaded\n");
+	snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp );
+	snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2 );
+	snd_printk("Hana ver:%d.%d\n",tmp ,tmp2);
+	/* Enable 48Volt power to Audio Dock */
+	snd_emu1010_fpga_write(emu,  EMU_HANA_DOCK_PWR,  EMU_HANA_DOCK_PWR_ON );
+
+	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg );
+	snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg);
+	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg );
+	snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg);
+	snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp ); 
+	/* ADAT input. */
+	snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x01 );
+	snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp );
+	/* Set no attenuation on Audio Dock pads. */
+	snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00 );
+	emu->emu1010.adc_pads = 0x00;
+	snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp );
+	/* Unmute Audio dock DACs, Headphone source DAC-4. */
+	snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 );
+	snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 );
+	snd_emu1010_fpga_read(emu, EMU_HANA_DAC_PADS, &tmp );
+	/* DAC PADs. */
+	snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, 0x0f );
+	emu->emu1010.dac_pads = 0x0f;
+	snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp );
+	snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 );
+	snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp );
+	/* SPDIF Format. Set Consumer mode, 24bit, copy enable */
+	snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 );
+	/* MIDI routing */
+	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 );
+	/* Unknown. */
+	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c );
+	/* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); // IRQ Enable: All on */
+	/* IRQ Enable: All off */
+	snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00 );
+
+	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg );
+	snd_printk(KERN_INFO "emu1010: Card options3=0x%x\n",reg);
+	/* Default WCLK set to 48kHz. */
+	snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00 );
+	/* Word Clock source, Internal 48kHz x1 */
+	snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K );
+	//snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X );
+	/* Audio Dock LEDs. */
+	snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 );
+
+#if 0
+	/* For 96kHz */
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_0, EMU_SRC_HAMOA_ADC_LEFT1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_1, EMU_SRC_HAMOA_ADC_RIGHT1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_4, EMU_SRC_HAMOA_ADC_LEFT2);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_5, EMU_SRC_HAMOA_ADC_RIGHT2);
+#endif
+#if 0
+	/* For 192kHz */
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_0, EMU_SRC_HAMOA_ADC_LEFT1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_1, EMU_SRC_HAMOA_ADC_RIGHT1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_2, EMU_SRC_HAMOA_ADC_LEFT2);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_3, EMU_SRC_HAMOA_ADC_RIGHT2);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_4, EMU_SRC_HAMOA_ADC_LEFT3);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_5, EMU_SRC_HAMOA_ADC_RIGHT3);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_6, EMU_SRC_HAMOA_ADC_LEFT4);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_7, EMU_SRC_HAMOA_ADC_RIGHT4);
+#endif
+#if 1
+	/* For 48kHz */
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_0, EMU_SRC_DOCK_MIC_A1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_1, EMU_SRC_DOCK_MIC_B1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_2, EMU_SRC_HAMOA_ADC_LEFT2);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_3, EMU_SRC_HAMOA_ADC_LEFT2);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_4, EMU_SRC_DOCK_ADC1_LEFT1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_5, EMU_SRC_DOCK_ADC1_RIGHT1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_6, EMU_SRC_DOCK_ADC2_LEFT1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_7, EMU_SRC_DOCK_ADC2_RIGHT1);
+#endif
+#if 0
+	/* Original */
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_4, EMU_SRC_HANA_ADAT);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_5, EMU_SRC_HANA_ADAT + 1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_6, EMU_SRC_HANA_ADAT + 2);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_7, EMU_SRC_HANA_ADAT + 3);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_8, EMU_SRC_HANA_ADAT + 4);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_9, EMU_SRC_HANA_ADAT + 5);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_A, EMU_SRC_HANA_ADAT + 6);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_B, EMU_SRC_HANA_ADAT + 7);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_C, EMU_SRC_DOCK_MIC_A1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_D, EMU_SRC_DOCK_MIC_B1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_E, EMU_SRC_HAMOA_ADC_LEFT2);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_F, EMU_SRC_HAMOA_ADC_LEFT2);
+#endif
+	for (i = 0;i < 0x20; i++ ) {
+		/* AudioDock Elink <-  Silence */
+		snd_emu1010_fpga_link_dst_src_write(emu, 0x0100+i, EMU_SRC_SILENCE);
+	}
+	for (i = 0;i < 4; i++) {
+		/* Hana SPDIF Out <- Silence */
+		snd_emu1010_fpga_link_dst_src_write(emu, 0x0200+i, EMU_SRC_SILENCE);
+	}
+	for (i = 0;i < 7; i++) {
+		/* Hamoa DAC <- Silence */
+		snd_emu1010_fpga_link_dst_src_write(emu, 0x0300+i, EMU_SRC_SILENCE);
+	}
+	for (i = 0;i < 7; i++) {
+		/* Hana ADAT Out <- Silence */
+		snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_HANA_ADAT + i, EMU_SRC_SILENCE);
+	}
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE_I2S0_LEFT, EMU_SRC_DOCK_ADC1_LEFT1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE_I2S0_RIGHT, EMU_SRC_DOCK_ADC1_RIGHT1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE_I2S1_LEFT, EMU_SRC_DOCK_ADC2_LEFT1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE_I2S1_RIGHT, EMU_SRC_DOCK_ADC2_RIGHT1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE_I2S2_LEFT, EMU_SRC_DOCK_ADC3_LEFT1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE_I2S2_RIGHT, EMU_SRC_DOCK_ADC3_RIGHT1);
+	snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x01 ); // Unmute all
+
+	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp );
+	
+	/* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave,
+	 * Lock Sound Memory Cache, Lock Tank Memory Cache,
+	 * Mute all codecs.
+	 */
+	outl(0x0000a000, emu->port + HCFG); 
+	/* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave,
+	 * Lock Sound Memory Cache, Lock Tank Memory Cache,
+	 * Un-Mute all codecs.
+	 */
 	outl(0x0000a001, emu->port + HCFG);
+ 
 	/* Initial boot complete. Now patches */
 
-	snd_emu1212m_fpga_read(emu, 0x21, &tmp );
-	snd_emu1212m_fpga_write(emu, 0x0c, 0x19 );
-	snd_emu1212m_fpga_write(emu, 0x12, 0x0c );
-	snd_emu1212m_fpga_write(emu, 0x0c, 0x19 );
-	snd_emu1212m_fpga_write(emu, 0x12, 0x0c );
-	snd_emu1212m_fpga_read(emu, 0x0a, &tmp );
-	snd_emu1212m_fpga_write(emu, 0x0a, 0x10 );
+	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp );
+	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */
+	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */
+	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */
+	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */
+	snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); 
+	snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif  (or 0x11 for aes/ebu) */
 
-	snd_emu1212m_fpga_read(emu, 0x20, &tmp );
-	snd_emu1212m_fpga_read(emu, 0x21, &tmp );
+	/* Delay to allow Audio Dock to settle */
+	msleep(100);
+	snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */
+	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg ); /* OPTIONS: Which cards are attached to the EMU */
+	/* FIXME: The loading of this should be able to happen any time,
+	 * as the user can plug/unplug it at any time
+	 */
+	if (reg & (EMU_HANA_OPTION_DOCK_ONLINE | EMU_HANA_OPTION_DOCK_OFFLINE) ) {
+		/* Audio Dock attached */
+		/* Return to Audio Dock programming mode */
+		snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n");
+		snd_emu1010_fpga_write(emu,  EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK );
+		if ((err = snd_emu1010_load_firmware(emu, dock_filename)) != 0) {
+			return err;
+		}
+		snd_emu1010_fpga_write(emu,  EMU_HANA_FPGA_CONFIG, 0 );
+		snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg );
+		snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg);
+		/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
+		snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
+		snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg);
+		if (reg != 0x55) {
+			/* FPGA failed to be programmed */
+			snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg);
+			return 0;
+			return -ENODEV;
+		}
+		snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n");
+		snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp );
+		snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2 );
+		snd_printk("Audio Dock ver:%d.%d\n",tmp ,tmp2);
+	}
+#if 0
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32B + 2); /* ALICE2 bus 0xa2 */
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32B + 3); /* ALICE2 bus 0xa3 */
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 2); /* ALICE2 bus 0xb2 */
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); /* ALICE2 bus 0xb3 */
+#endif
+	/* Default outputs */
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
+	emu->emu1010.output_source[0] = 21;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+	emu->emu1010.output_source[1] = 22;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2);
+	emu->emu1010.output_source[2] = 23;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3);
+	emu->emu1010.output_source[3] = 24;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4);
+	emu->emu1010.output_source[4] = 25;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5);
+	emu->emu1010.output_source[5] = 26;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_DOCK_DAC4_LEFT1, EMU_SRC_ALICE_EMU32A + 6);
+	emu->emu1010.output_source[6] = 27;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_DOCK_DAC4_RIGHT1, EMU_SRC_ALICE_EMU32A + 7);
+	emu->emu1010.output_source[7] = 28;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_DOCK_PHONES_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
+	emu->emu1010.output_source[8] = 21;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_DOCK_PHONES_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+	emu->emu1010.output_source[9] = 22;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_DOCK_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
+	emu->emu1010.output_source[10] = 21;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_DOCK_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+	emu->emu1010.output_source[11] = 22;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
+	emu->emu1010.output_source[12] = 21;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+	emu->emu1010.output_source[13] = 22;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
+	emu->emu1010.output_source[14] = 21;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+	emu->emu1010.output_source[15] = 22;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_HANA_ADAT, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
+	emu->emu1010.output_source[16] = 21;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_HANA_ADAT + 1, EMU_SRC_ALICE_EMU32A + 1);
+	emu->emu1010.output_source[17] = 22;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_HANA_ADAT + 2, EMU_SRC_ALICE_EMU32A + 2);
+	emu->emu1010.output_source[18] = 23;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_HANA_ADAT + 3, EMU_SRC_ALICE_EMU32A + 3);
+	emu->emu1010.output_source[19] = 24;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_HANA_ADAT + 4, EMU_SRC_ALICE_EMU32A + 4);
+	emu->emu1010.output_source[20] = 25;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_HANA_ADAT + 5, EMU_SRC_ALICE_EMU32A + 5);
+	emu->emu1010.output_source[21] = 26;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_HANA_ADAT + 6, EMU_SRC_ALICE_EMU32A + 6);
+	emu->emu1010.output_source[22] = 27;
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_HANA_ADAT + 7, EMU_SRC_ALICE_EMU32A + 7);
+	emu->emu1010.output_source[23] = 28;
 
-	snd_emu1212m_fpga_netlist_write(emu, 0x0300, 0x0312);
-	snd_emu1212m_fpga_netlist_write(emu, 0x0301, 0x0313);
-	snd_emu1212m_fpga_netlist_write(emu, 0x0200, 0x0302);
-	snd_emu1212m_fpga_netlist_write(emu, 0x0201, 0x0303);
+	/* TEMP: Select SPDIF in/out */
+	snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */
+
+	/* TEMP: Select 48kHz SPDIF out */
+	snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x0); /* Mute all */
+	snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x0); /* Default fallback clock 48kHz */
+	/* Word Clock source, Internal 48kHz x1 */
+	snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K );
+	//snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X );
+	emu->emu1010.internal_clock = 1; /* 48000 */
+	snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12);/* Set LEDs on Audio Dock */
+	snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x1); /* Unmute all */
+	//snd_emu1010_fpga_write(emu, 0x7, 0x0); /* Mute all */
+	//snd_emu1010_fpga_write(emu, 0x7, 0x1); /* Unmute all */
+	//snd_emu1010_fpga_write(emu, 0xe, 0x12); /* Set LEDs on Audio Dock */
 
 	return 0;
 }
@@ -747,6 +1081,10 @@
 		}
 		snd_emu10k1_free_efx(emu);
        	}
+	if (emu->card_capabilities->emu1010) {
+		/* Disable 48Volt power to Audio Dock */
+		snd_emu1010_fpga_write(emu,  EMU_HANA_DOCK_PWR,  0 );
+	}
 	if (emu->memhdr)
 		snd_util_memhdr_free(emu->memhdr);
 	if (emu->silent_page.area)
@@ -838,10 +1176,11 @@
 	 .adc_1361t = 1,  /* 24 bit capture instead of 16bit */
 	 .ac97_chip = 1} ,
 	/* Audigy 2 ZS Notebook Cardbus card.*/
-	/* Tested by James@superbug.co.uk 22th December 2005 */
+	/* Tested by James@superbug.co.uk 6th November 2006 */
 	/* Audio output 7.1/Headphones working.
 	 * Digital output working. (AC3 not checked, only PCM)
-	 * Audio inputs not tested.
+	 * Audio Mic/Line inputs working.
+	 * Digital input not tested.
 	 */ 
 	/* DSP: Tina2
 	 * DAC: Wolfson WM8768/WM8568
@@ -849,6 +1188,25 @@
 	 * AC97: None
 	 * CA0151: None
 	 */
+	/* Tested by James@superbug.co.uk 4th April 2006 */
+	/* A_IOCFG bits
+	 * Output
+	 * 0: Not Used
+	 * 1: 0 = Mute all the 7.1 channel out. 1 = unmute.
+	 * 2: Analog input 0 = line in, 1 = mic in
+	 * 3: Not Used
+	 * 4: Digital output 0 = off, 1 = on.
+	 * 5: Not Used
+	 * 6: Not Used
+	 * 7: Not Used
+	 * Input
+	 *      All bits 1 (0x3fxx) means nothing plugged in.
+	 * 8-9: 0 = Line in/Mic, 2 = Optical in, 3 = Nothing.
+	 * A-B: 0 = Headphones, 2 = Optical out, 3 = Nothing.
+	 * C-D: 2 = Front/Rear/etc, 3 = nothing.
+	 * E-F: Always 0
+	 *
+	 */
 	{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102,
 	 .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]", 
 	 .id = "Audigy2",
@@ -856,6 +1214,7 @@
 	 .ca0108_chip = 1,
 	 .ca_cardbus_chip = 1,
 	 .spi_dac = 1,
+	 .i2c_adc = 1,
 	 .spk71 = 1} ,
 	{.vendor = 0x1102, .device = 0x0008, 
 	 .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", 
@@ -865,11 +1224,12 @@
 	 .ac97_chip = 1} ,
 	/* Tested by James@superbug.co.uk 8th July 2005. No sound available yet. */
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102,
-	 .driver = "Audigy2", .name = "E-mu 1212m [4001]", 
-	 .id = "EMU1212m",
+	 .driver = "Audigy2", .name = "E-mu 1010 [4001]", 
+	 .id = "EMU1010",
 	 .emu10k2_chip = 1,
 	 .ca0102_chip = 1,
-	 .emu1212m = 1} ,
+	 .spk71 = 1,
+	 .emu1010 = 1} ,
 	/* Tested by James@superbug.co.uk 3rd July 2005 */
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102,
 	 .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", 
@@ -1297,8 +1657,8 @@
 	} else if (emu->card_capabilities->ca_cardbus_chip) {
 		if ((err = snd_emu10k1_cardbus_init(emu)) < 0)
 			goto error;
- 	} else if (emu->card_capabilities->emu1212m) {
- 		if ((err = snd_emu10k1_emu1212m_init(emu)) < 0) {
+ 	} else if (emu->card_capabilities->emu1010) {
+ 		if ((err = snd_emu10k1_emu1010_init(emu)) < 0) {
  			snd_emu10k1_free(emu);
  			return err;
  		}
@@ -1446,8 +1806,8 @@
 		snd_emu10k1_ecard_init(emu);
 	else if (emu->card_capabilities->ca_cardbus_chip)
 		snd_emu10k1_cardbus_init(emu);
-	else if (emu->card_capabilities->emu1212m)
- 		snd_emu10k1_emu1212m_init(emu);
+	else if (emu->card_capabilities->emu1010)
+ 		snd_emu10k1_emu1010_init(emu);
 	else
 		snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE);
 	snd_emu10k1_init(emu, emu->enable_ir, 1);
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 2199b42..bb0fec7 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -460,7 +460,7 @@
 	u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size);
 	int i;
 	
-	for(i=0; i < runtime->periods; i++) {
+	for(i = 0; i < runtime->periods; i++) {
 		*table_base++=runtime->dma_addr+(i*period_size_bytes);
 		*table_base++=period_size_bytes<<16;
 	}
@@ -1042,8 +1042,8 @@
 		if (sscanf(line, "%x %x %x", &reg, &channel_id, &val) != 3)
 			continue;
 
-		if ((reg < 0x49) && (reg >=0) && (val <= 0xffffffff) 
-		    && (channel_id >=0) && (channel_id <= 2) )
+		if ((reg < 0x49) && (reg >= 0) && (val <= 0xffffffff) 
+		    && (channel_id >= 0) && (channel_id <= 2) )
 			snd_emu10k1x_ptr_write(emu, reg, channel_id, val);
 	}
 }
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 13cd6ce..c02012c 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -3,6 +3,9 @@
  *                   Creative Labs, Inc.
  *  Routines for effect processor FX8010
  *
+ *  Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
+ *  	Added EMU 1010 support.
+ *
  *  BUGS:
  *    --
  *
@@ -293,7 +296,7 @@
 };
 
 /* EMU10k1/EMU10k2 DSP control db gain */
-static DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
+static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
 
 static const u32 onoff_table[2] = {
 	0x00000000, 0x00000001
@@ -652,13 +655,66 @@
 	return NULL;
 }
 
+#define MAX_TLV_SIZE	256
+
+static unsigned int *copy_tlv(const unsigned int __user *_tlv)
+{
+	unsigned int data[2];
+	unsigned int *tlv;
+
+	if (!_tlv)
+		return NULL;
+	if (copy_from_user(data, _tlv, sizeof(data)))
+		return NULL;
+	if (data[1] >= MAX_TLV_SIZE)
+		return NULL;
+	tlv = kmalloc(data[1] * 4 + sizeof(data), GFP_KERNEL);
+	if (!tlv)
+		return NULL;
+	memcpy(tlv, data, sizeof(data));
+	if (copy_from_user(tlv + 2, _tlv + 2, data[1])) {
+		kfree(tlv);
+		return NULL;
+	}
+	return tlv;
+}
+
+static int copy_gctl(struct snd_emu10k1 *emu,
+		     struct snd_emu10k1_fx8010_control_gpr *gctl,
+		     struct snd_emu10k1_fx8010_control_gpr __user *_gctl,
+		     int idx)
+{
+	struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
+
+	if (emu->support_tlv)
+		return copy_from_user(gctl, &_gctl[idx], sizeof(*gctl));
+	octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
+	if (copy_from_user(gctl, &octl[idx], sizeof(*octl)))
+		return -EFAULT;
+	gctl->tlv = NULL;
+	return 0;
+}
+
+static int copy_gctl_to_user(struct snd_emu10k1 *emu,
+		     struct snd_emu10k1_fx8010_control_gpr __user *_gctl,
+		     struct snd_emu10k1_fx8010_control_gpr *gctl,
+		     int idx)
+{
+	struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
+
+	if (emu->support_tlv)
+		return copy_to_user(&_gctl[idx], gctl, sizeof(*gctl));
+	
+	octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
+	return copy_to_user(&octl[idx], gctl, sizeof(*octl));
+}
+
 static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
 				       struct snd_emu10k1_fx8010_code *icode)
 {
 	unsigned int i;
 	struct snd_ctl_elem_id __user *_id;
 	struct snd_ctl_elem_id id;
-	struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
 	struct snd_emu10k1_fx8010_control_gpr *gctl;
 	int err;
 	
@@ -673,9 +729,8 @@
 	if (! gctl)
 		return -ENOMEM;
 	err = 0;
-	for (i = 0, _gctl = icode->gpr_add_controls;
-	     i < icode->gpr_add_control_count; i++, _gctl++) {
-		if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
+	for (i = 0; i < icode->gpr_add_control_count; i++) {
+		if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) {
 			err = -EFAULT;
 			goto __error;
 		}
@@ -694,10 +749,9 @@
 			goto __error;
 		}
 	}
-	for (i = 0, _gctl = icode->gpr_list_controls;
-	     i < icode->gpr_list_control_count; i++, _gctl++) {
+	for (i = 0; i < icode->gpr_list_control_count; i++) {
 	     	/* FIXME: we need to check the WRITE access */
-		if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
+		if (copy_gctl(emu, gctl, icode->gpr_list_controls, i)) {
 			err = -EFAULT;
 			goto __error;
 		}
@@ -715,13 +769,14 @@
 	kctl->private_value = 0;
 	list_del(&ctl->list);
 	kfree(ctl);
+	if (kctl->tlv.p)
+		kfree(kctl->tlv.p);
 }
 
 static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
 				    struct snd_emu10k1_fx8010_code *icode)
 {
 	unsigned int i, j;
-	struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
 	struct snd_emu10k1_fx8010_control_gpr *gctl;
 	struct snd_emu10k1_fx8010_ctl *ctl, *nctl;
 	struct snd_kcontrol_new knew;
@@ -737,9 +792,8 @@
 		goto __error;
 	}
 
-	for (i = 0, _gctl = icode->gpr_add_controls;
-	     i < icode->gpr_add_control_count; i++, _gctl++) {
-		if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
+	for (i = 0; i < icode->gpr_add_control_count; i++) {
+		if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) {
 			err = -EFAULT;
 			goto __error;
 		}
@@ -760,11 +814,10 @@
 		knew.device = gctl->id.device;
 		knew.subdevice = gctl->id.subdevice;
 		knew.info = snd_emu10k1_gpr_ctl_info;
-		if (gctl->tlv.p) {
-			knew.tlv.p = gctl->tlv.p;
+		knew.tlv.p = copy_tlv(gctl->tlv);
+		if (knew.tlv.p)
 			knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
 				SNDRV_CTL_ELEM_ACCESS_TLV_READ;
-		} 
 		knew.get = snd_emu10k1_gpr_ctl_get;
 		knew.put = snd_emu10k1_gpr_ctl_put;
 		memset(nctl, 0, sizeof(*nctl));
@@ -782,12 +835,14 @@
 			ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
 			if (ctl == NULL) {
 				err = -ENOMEM;
+				kfree(knew.tlv.p);
 				goto __error;
 			}
 			knew.private_value = (unsigned long)ctl;
 			*ctl = *nctl;
 			if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) {
 				kfree(ctl);
+				kfree(knew.tlv.p);
 				goto __error;
 			}
 			kctl->private_free = snd_emu10k1_ctl_private_free;
@@ -838,7 +893,6 @@
 	unsigned int i = 0, j;
 	unsigned int total = 0;
 	struct snd_emu10k1_fx8010_control_gpr *gctl;
-	struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
 	struct snd_emu10k1_fx8010_ctl *ctl;
 	struct snd_ctl_elem_id *id;
 	struct list_head *list;
@@ -847,11 +901,11 @@
 	if (! gctl)
 		return -ENOMEM;
 
-	_gctl = icode->gpr_list_controls;	
 	list_for_each(list, &emu->fx8010.gpr_ctl) {
 		ctl = emu10k1_gpr_ctl(list);
 		total++;
-		if (_gctl && i < icode->gpr_list_control_count) {
+		if (icode->gpr_list_controls &&
+		    i < icode->gpr_list_control_count) {
 			memset(gctl, 0, sizeof(*gctl));
 			id = &ctl->kcontrol->id;
 			gctl->id.iface = id->iface;
@@ -868,11 +922,11 @@
 			gctl->min = ctl->min;
 			gctl->max = ctl->max;
 			gctl->translation = ctl->translation;
-			if (copy_to_user(_gctl, gctl, sizeof(*gctl))) {
+			if (copy_gctl_to_user(emu, icode->gpr_list_controls,
+					      gctl, i)) {
 				kfree(gctl);
 				return -EFAULT;
 			}
-			_gctl++;
 			i++;
 		}
 	}
@@ -1023,7 +1077,7 @@
 	ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
 	ctl->min = 0;
 	ctl->max = 100;
-	ctl->tlv.p = snd_emu10k1_db_scale1;
+	ctl->tlv = snd_emu10k1_db_scale1;
 	ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;	
 }
 
@@ -1038,7 +1092,7 @@
 	ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
 	ctl->min = 0;
 	ctl->max = 100;
-	ctl->tlv.p = snd_emu10k1_db_scale1;
+	ctl->tlv = snd_emu10k1_db_scale1;
 	ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
 }
 
@@ -1069,6 +1123,21 @@
 	ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
 }
 
+static int snd_emu10k1_audigy_dsp_convert_32_to_2x16(
+				struct snd_emu10k1_fx8010_code *icode,
+				u32 *ptr, int tmp, int bit_shifter16,
+				int reg_in, int reg_out)
+{
+	A_OP(icode, ptr, iACC3, A_GPR(tmp + 1), reg_in, A_C_00000000, A_C_00000000);
+	A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp + 1), A_GPR(bit_shifter16 - 1), A_C_00000000);
+	A_OP(icode, ptr, iTSTNEG, A_GPR(tmp + 2), A_GPR(tmp), A_C_80000000, A_GPR(bit_shifter16 - 2));
+	A_OP(icode, ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_C_80000000, A_C_00000000);
+	A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp), A_GPR(bit_shifter16 - 3), A_C_00000000);
+	A_OP(icode, ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A_GPR(tmp), A_C_00010000);
+	A_OP(icode, ptr, iANDXOR, reg_out, A_GPR(tmp), A_C_ffffffff, A_GPR(tmp + 2));
+	A_OP(icode, ptr, iACC3, reg_out + 1, A_GPR(tmp + 1), A_C_00000000, A_C_00000000);
+	return 1;
+}
 
 /*
  * initial DSP configuration for Audigy
@@ -1077,6 +1146,7 @@
 static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
 {
 	int err, i, z, gpr, nctl;
+	int bit_shifter16;
 	const int playback = 10;
 	const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
 	const int stereo_mix = capture + 2;
@@ -1114,17 +1184,14 @@
 	ptr = 0;
 	nctl = 0;
 	gpr = stereo_mix + 10;
+	gpr_map[gpr++] = 0x00007fff;
+	gpr_map[gpr++] = 0x00008000;
+	gpr_map[gpr++] = 0x0000ffff;
+	bit_shifter16 = gpr;
 
 	/* stop FX processor */
 	snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
 
-#if 0
-	/* FIX: jcd test */
-	for (z = 0; z < 80; z=z+2) {
-		A_OP(icode, &ptr, iACC3, A_EXTOUT(z), A_FXBUS(FXBUS_PCM_LEFT_FRONT), A_C_00000000, A_C_00000000); /* left */
-		A_OP(icode, &ptr, iACC3, A_EXTOUT(z+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT), A_C_00000000, A_C_00000000); /* right */
-	}
-#endif /* jcd test */
 #if 1
 	/* PCM front Playback Volume (independent from stereo mix) */
 	A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
@@ -1182,13 +1249,20 @@
 	A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
 	snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0);
 	gpr += 2;
-
+      
 	/*
 	 * inputs
 	 */
 #define A_ADD_VOLUME_IN(var,vol,input) \
 A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
 
+	/* emu1212 DSP 0 and DSP 1 Capture */
+	if (emu->card_capabilities->emu1010) {
+		A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0));
+		A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1));
+		snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0);
+		gpr += 2;
+	}
 	/* AC'97 Playback Volume - used only for mic (renamed later) */
 	A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L);
 	A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R);
@@ -1429,6 +1503,13 @@
 
 	/* digital outputs */
 	/* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */
+	if (emu->card_capabilities->emu1010) {
+		/* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */
+		snd_printk("EMU outputs on\n");
+		for (z = 0; z < 8; z++) {
+			A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
+		}
+	}
 
 	/* IEC958 Optical Raw Playback Switch */ 
 	gpr_map[gpr++] = 0;
@@ -1466,9 +1547,57 @@
 	A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
 #endif
 
-	/* EFX capture - capture the 16 EXTINs */
-	for (z = 0; z < 16; z++) {
-		A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
+	if (emu->card_capabilities->emu1010) {
+		snd_printk("EMU inputs on\n");
+		/* Capture 8 channels of S32_LE sound */
+		
+		/* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */
+		/* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */
+		/* A_P16VIN(0) is delayed by one sample,
+		 * so all other A_P16VIN channels will need to also be delayed
+		 */
+		/* Left ADC in. 1 of 2 */
+		snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) );
+		/* Right ADC in 1 of 2 */
+		gpr_map[gpr++] = 0x00000000;
+		snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) );
+		A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000);
+		gpr_map[gpr++] = 0x00000000;
+		snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) );
+		A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), A_C_00000000, A_C_00000000);
+		gpr_map[gpr++] = 0x00000000;
+		snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(6) );
+		A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000);
+		/* For 96kHz mode */
+		/* Left ADC in. 2 of 2 */
+		gpr_map[gpr++] = 0x00000000;
+		snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) );
+		A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000);
+		/* Right ADC in 2 of 2 */
+		gpr_map[gpr++] = 0x00000000;
+		snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) );
+		A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000);
+		gpr_map[gpr++] = 0x00000000;
+		snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xc) );
+		A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), A_C_00000000, A_C_00000000);
+		gpr_map[gpr++] = 0x00000000;
+		snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) );
+		A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000);
+
+#if 0
+		for (z = 4; z < 8; z++) {
+			A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
+		}
+		for (z = 0xc; z < 0x10; z++) {
+			A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
+		}
+#endif
+	} else {
+		/* EFX capture - capture the 16 EXTINs */
+		/* Capture 16 channels of S16_LE sound */
+		for (z = 0; z < 16; z++) {
+			A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
+		}
 	}
 	
 #endif /* JCD test */
@@ -1488,7 +1617,9 @@
 	seg = snd_enter_user();
 	icode->gpr_add_control_count = nctl;
 	icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
+	emu->support_tlv = 1; /* support TLV */
 	err = snd_emu10k1_icode_poke(emu, icode);
+	emu->support_tlv = 0; /* clear again */
 	snd_leave_user(seg);
 
  __err:
@@ -2105,7 +2236,9 @@
 	seg = snd_enter_user();
 	icode->gpr_add_control_count = i;
 	icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
+	emu->support_tlv = 1; /* support TLV */
 	err = snd_emu10k1_icode_poke(emu, icode);
+	emu->support_tlv = 0; /* clear again */
 	snd_leave_user(seg);
 	if (err >= 0)
 		err = snd_emu10k1_ipcm_poke(emu, ipcm);
@@ -2138,7 +2271,7 @@
 		snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP);
 }
 
-#if 0 // FIXME: who use them?
+#if 0 /* FIXME: who use them? */
 int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output)
 {
 	if (output < 0 || output >= 6)
@@ -2249,6 +2382,9 @@
 	int res;
 	
 	switch (cmd) {
+	case SNDRV_EMU10K1_IOCTL_PVERSION:
+		emu->support_tlv = 1;
+		return put_user(SNDRV_EMU10K1_VERSION, (int __user *)argp);
 	case SNDRV_EMU10K1_IOCTL_INFO:
 		info = kmalloc(sizeof(*info), GFP_KERNEL);
 		if (!info)
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index c31f3d0..4db6e1c 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -5,6 +5,9 @@
  *  Routines for control of EMU10K1 chips / mixer routines
  *  Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com>
  *
+ *  Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
+ *  	Added EMU 1010 support.
+ *
  *  BUGS:
  *    --
  *
@@ -32,9 +35,15 @@
 #include <linux/init.h>
 #include <sound/core.h>
 #include <sound/emu10k1.h>
+#include <linux/delay.h>
+#include <sound/tlv.h>
+
+#include "p17v.h"
 
 #define AC97_ID_STAC9758	0x83847658
 
+static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */
+
 static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
@@ -68,6 +77,669 @@
 	return 0;
 }
 
+static char *emu1010_src_texts[] = { 
+	"Silence",
+	"Dock Mic A",
+	"Dock Mic B",
+	"Dock ADC1 Left",
+	"Dock ADC1 Right",
+	"Dock ADC2 Left",
+	"Dock ADC2 Right",
+	"Dock ADC3 Left",
+	"Dock ADC3 Right",
+	"0202 ADC Left",
+	"0202 ADC Right",
+	"0202 SPDIF Left",
+	"0202 SPDIF Right",
+	"ADAT 0",
+	"ADAT 1",
+	"ADAT 2",
+	"ADAT 3",
+	"ADAT 4",
+	"ADAT 5",
+	"ADAT 6",
+	"ADAT 7",
+	"DSP 0",
+	"DSP 1",
+	"DSP 2",
+	"DSP 3",
+	"DSP 4",
+	"DSP 5",
+	"DSP 6",
+	"DSP 7",
+	"DSP 8",
+	"DSP 9",
+	"DSP 10",
+	"DSP 11",
+	"DSP 12",
+	"DSP 13",
+	"DSP 14",
+	"DSP 15",
+	"DSP 16",
+	"DSP 17",
+	"DSP 18",
+	"DSP 19",
+	"DSP 20",
+	"DSP 21",
+	"DSP 22",
+	"DSP 23",
+	"DSP 24",
+	"DSP 25",
+	"DSP 26",
+	"DSP 27",
+	"DSP 28",
+	"DSP 29",
+	"DSP 30",
+	"DSP 31",
+};
+
+static unsigned int emu1010_src_regs[] = {
+	EMU_SRC_SILENCE,/* 0 */
+	EMU_SRC_DOCK_MIC_A1, /* 1 */
+	EMU_SRC_DOCK_MIC_B1, /* 2 */
+	EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */
+	EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */
+	EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */
+	EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */
+	EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */
+	EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */
+	EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */
+	EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */
+	EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */
+	EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */
+	EMU_SRC_HANA_ADAT, /* 13 */
+	EMU_SRC_HANA_ADAT+1, /* 14 */
+	EMU_SRC_HANA_ADAT+2, /* 15 */
+	EMU_SRC_HANA_ADAT+3, /* 16 */
+	EMU_SRC_HANA_ADAT+4, /* 17 */
+	EMU_SRC_HANA_ADAT+5, /* 18 */
+	EMU_SRC_HANA_ADAT+6, /* 19 */
+	EMU_SRC_HANA_ADAT+7, /* 20 */
+	EMU_SRC_ALICE_EMU32A, /* 21 */
+	EMU_SRC_ALICE_EMU32A+1, /* 22 */
+	EMU_SRC_ALICE_EMU32A+2, /* 23 */
+	EMU_SRC_ALICE_EMU32A+3, /* 24 */
+	EMU_SRC_ALICE_EMU32A+4, /* 25 */
+	EMU_SRC_ALICE_EMU32A+5, /* 26 */
+	EMU_SRC_ALICE_EMU32A+6, /* 27 */
+	EMU_SRC_ALICE_EMU32A+7, /* 28 */
+	EMU_SRC_ALICE_EMU32A+8, /* 29 */
+	EMU_SRC_ALICE_EMU32A+9, /* 30 */
+	EMU_SRC_ALICE_EMU32A+0xa, /* 31 */
+	EMU_SRC_ALICE_EMU32A+0xb, /* 32 */
+	EMU_SRC_ALICE_EMU32A+0xc, /* 33 */
+	EMU_SRC_ALICE_EMU32A+0xd, /* 34 */
+	EMU_SRC_ALICE_EMU32A+0xe, /* 35 */
+	EMU_SRC_ALICE_EMU32A+0xf, /* 36 */
+	EMU_SRC_ALICE_EMU32B, /* 37 */
+	EMU_SRC_ALICE_EMU32B+1, /* 38 */
+	EMU_SRC_ALICE_EMU32B+2, /* 39 */
+	EMU_SRC_ALICE_EMU32B+3, /* 40 */
+	EMU_SRC_ALICE_EMU32B+4, /* 41 */
+	EMU_SRC_ALICE_EMU32B+5, /* 42 */
+	EMU_SRC_ALICE_EMU32B+6, /* 43 */
+	EMU_SRC_ALICE_EMU32B+7, /* 44 */
+	EMU_SRC_ALICE_EMU32B+8, /* 45 */
+	EMU_SRC_ALICE_EMU32B+9, /* 46 */
+	EMU_SRC_ALICE_EMU32B+0xa, /* 47 */
+	EMU_SRC_ALICE_EMU32B+0xb, /* 48 */
+	EMU_SRC_ALICE_EMU32B+0xc, /* 49 */
+	EMU_SRC_ALICE_EMU32B+0xd, /* 50 */
+	EMU_SRC_ALICE_EMU32B+0xe, /* 51 */
+	EMU_SRC_ALICE_EMU32B+0xf, /* 52 */
+};
+
+static unsigned int emu1010_output_dst[] = {
+	EMU_DST_DOCK_DAC1_LEFT1, /* 0 */
+	EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */
+	EMU_DST_DOCK_DAC2_LEFT1, /* 2 */
+	EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */
+	EMU_DST_DOCK_DAC3_LEFT1, /* 4 */
+	EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */
+	EMU_DST_DOCK_DAC4_LEFT1, /* 6 */
+	EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */
+	EMU_DST_DOCK_PHONES_LEFT1, /* 8 */
+	EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */
+	EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */
+	EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */
+	EMU_DST_HANA_SPDIF_LEFT1, /* 12 */
+	EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */
+	EMU_DST_HAMOA_DAC_LEFT1, /* 14 */
+	EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */
+	EMU_DST_HANA_ADAT, /* 16 */
+	EMU_DST_HANA_ADAT+1, /* 17 */
+	EMU_DST_HANA_ADAT+2, /* 18 */
+	EMU_DST_HANA_ADAT+3, /* 19 */
+	EMU_DST_HANA_ADAT+4, /* 20 */
+	EMU_DST_HANA_ADAT+5, /* 21 */
+	EMU_DST_HANA_ADAT+6, /* 22 */
+	EMU_DST_HANA_ADAT+7, /* 23 */
+};
+
+static unsigned int emu1010_input_dst[] = {
+	EMU_DST_ALICE2_EMU32_0,
+	EMU_DST_ALICE2_EMU32_1,
+	EMU_DST_ALICE2_EMU32_2,
+	EMU_DST_ALICE2_EMU32_3,
+	EMU_DST_ALICE2_EMU32_4,
+	EMU_DST_ALICE2_EMU32_5,
+	EMU_DST_ALICE2_EMU32_6,
+	EMU_DST_ALICE2_EMU32_7,
+	EMU_DST_ALICE2_EMU32_8,
+	EMU_DST_ALICE2_EMU32_9,
+	EMU_DST_ALICE2_EMU32_A,
+	EMU_DST_ALICE2_EMU32_B,
+	EMU_DST_ALICE2_EMU32_C,
+	EMU_DST_ALICE2_EMU32_D,
+	EMU_DST_ALICE2_EMU32_E,
+	EMU_DST_ALICE2_EMU32_F,
+	EMU_DST_ALICE_I2S0_LEFT,
+	EMU_DST_ALICE_I2S0_RIGHT,
+	EMU_DST_ALICE_I2S1_LEFT,
+	EMU_DST_ALICE_I2S1_RIGHT,
+	EMU_DST_ALICE_I2S2_LEFT,
+	EMU_DST_ALICE_I2S2_RIGHT,
+};
+
+static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 53;
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+	strcpy(uinfo->value.enumerated.name, emu1010_src_texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+	int channel;
+
+	channel = (kcontrol->private_value) & 0xff;
+	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
+	return 0;
+}
+
+static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+	int change = 0;
+	unsigned int val;
+	int channel;
+
+	channel = (kcontrol->private_value) & 0xff;
+	if (emu->emu1010.output_source[channel] != ucontrol->value.enumerated.item[0]) {
+		val = emu->emu1010.output_source[channel] = ucontrol->value.enumerated.item[0];
+		change = 1;
+		snd_emu1010_fpga_link_dst_src_write(emu,
+			emu1010_output_dst[channel], emu1010_src_regs[val]);
+	}
+	return change;
+}
+
+static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+	int channel;
+
+	channel = (kcontrol->private_value) & 0xff;
+	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
+	return 0;
+}
+
+static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+	int change = 0;
+	unsigned int val;
+	int channel;
+
+	channel = (kcontrol->private_value) & 0xff;
+	if (emu->emu1010.input_source[channel] != ucontrol->value.enumerated.item[0]) {
+		val = emu->emu1010.input_source[channel] = ucontrol->value.enumerated.item[0];
+		change = 1;
+		snd_emu1010_fpga_link_dst_src_write(emu,
+			emu1010_input_dst[channel], emu1010_src_regs[val]);
+	}
+	return change;
+}
+
+#define EMU1010_SOURCE_OUTPUT(xname,chid) \
+{								\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
+	.info =  snd_emu1010_input_output_source_info,		\
+	.get =   snd_emu1010_output_source_get,			\
+	.put =   snd_emu1010_output_source_put,			\
+	.private_value = chid					\
+}
+
+static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = {
+	EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
+	EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
+	EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
+	EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
+	EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
+	EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
+	EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6),
+	EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7),
+	EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8),
+	EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9),
+	EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa),
+	EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb),
+	EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc),
+	EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd),
+	EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe),
+	EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf),
+	EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10),
+	EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11),
+	EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12),
+	EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13),
+	EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14),
+	EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15),
+	EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16),
+	EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17),
+};
+
+#define EMU1010_SOURCE_INPUT(xname,chid) \
+{								\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
+	.info =  snd_emu1010_input_output_source_info,		\
+	.get =   snd_emu1010_input_source_get,			\
+	.put =   snd_emu1010_input_source_put,			\
+	.private_value = chid					\
+}
+
+static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = {
+	EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0),
+	EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1),
+	EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2),
+	EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3),
+	EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4),
+	EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5),
+	EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6),
+	EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7),
+	EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8),
+	EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9),
+	EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa),
+	EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb),
+	EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc),
+	EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd),
+	EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe),
+	EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf),
+	EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10),
+	EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11),
+	EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12),
+	EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13),
+	EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14),
+	EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15),
+};
+
+
+
+
+static int snd_emu1010_adc_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+	unsigned int mask = kcontrol->private_value & 0xff;
+	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
+	return 0;
+}
+
+static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+	unsigned int mask = kcontrol->private_value & 0xff;
+	unsigned int val, cache;
+	val = ucontrol->value.integer.value[0];
+	cache = emu->emu1010.adc_pads;
+	if (val == 1) 
+		cache = cache | mask;
+	else
+		cache = cache & ~mask;
+	if (cache != emu->emu1010.adc_pads) {
+		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
+	        emu->emu1010.adc_pads = cache;
+	}
+
+	return 0;
+}
+
+
+
+#define EMU1010_ADC_PADS(xname,chid) \
+{								\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
+	.info =  snd_emu1010_adc_pads_info,			\
+	.get =   snd_emu1010_adc_pads_get,			\
+	.put =   snd_emu1010_adc_pads_put,			\
+	.private_value = chid					\
+}
+
+static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = {
+	EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1),
+	EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2),
+	EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3),
+	EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1),
+};
+
+static int snd_emu1010_dac_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+	unsigned int mask = kcontrol->private_value & 0xff;
+	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
+	return 0;
+}
+
+static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+	unsigned int mask = kcontrol->private_value & 0xff;
+	unsigned int val, cache;
+	val = ucontrol->value.integer.value[0];
+	cache = emu->emu1010.dac_pads;
+	if (val == 1) 
+		cache = cache | mask;
+	else
+		cache = cache & ~mask;
+	if (cache != emu->emu1010.dac_pads) {
+		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
+	        emu->emu1010.dac_pads = cache;
+	}
+
+	return 0;
+}
+
+
+
+#define EMU1010_DAC_PADS(xname,chid) \
+{								\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
+	.info =  snd_emu1010_dac_pads_info,			\
+	.get =   snd_emu1010_dac_pads_get,			\
+	.put =   snd_emu1010_dac_pads_put,			\
+	.private_value = chid					\
+}
+
+static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = {
+	EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1),
+	EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2),
+	EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3),
+	EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4),
+	EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1),
+};
+
+
+static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_info *uinfo)
+{
+	static char *texts[2] = {
+		"44100", "48000"
+	};
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item > 1)
+                uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
+	return 0;
+}
+
+static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+	unsigned int val;
+	int change = 0;
+
+	val = ucontrol->value.enumerated.item[0] ;
+	change = (emu->emu1010.internal_clock != val);
+	if (change) {
+		emu->emu1010.internal_clock = val;
+		switch (val) {
+		case 0:
+			/* 44100 */
+			/* Mute all */
+			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
+			/* Default fallback clock 48kHz */
+			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
+			/* Word Clock source, Internal 44.1kHz x1 */
+			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
+			EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
+			/* Set LEDs on Audio Dock */
+			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
+				EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
+			/* Allow DLL to settle */
+			msleep(10);
+			/* Unmute all */
+			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
+			break;
+		case 1:
+			/* 48000 */
+			/* Mute all */
+			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
+			/* Default fallback clock 48kHz */
+			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
+			/* Word Clock source, Internal 48kHz x1 */
+			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
+				EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
+			/* Set LEDs on Audio Dock */
+			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
+				EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
+			/* Allow DLL to settle */
+			msleep(10);
+			/* Unmute all */
+			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
+			break;
+		}
+	}
+        return change;
+}
+
+static struct snd_kcontrol_new snd_emu1010_internal_clock =
+{
+	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =         "Clock Internal Rate",
+	.count =	1,
+	.info =         snd_emu1010_internal_clock_info,
+	.get =          snd_emu1010_internal_clock_get,
+	.put =          snd_emu1010_internal_clock_put
+};
+
+static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_info *uinfo)
+{
+#if 0
+	static char *texts[4] = {
+		"Unknown1", "Unknown2", "Mic", "Line"
+	};
+#endif
+	static char *texts[2] = {
+		"Mic", "Line"
+	};
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item > 1)
+                uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
+	return 0;
+}
+
+static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+	unsigned int source_id;
+	unsigned int ngain, ogain;
+	u32 gpio;
+	int change = 0;
+	unsigned long flags;
+	u32 source;
+	/* If the capture source has changed,
+	 * update the capture volume from the cached value
+	 * for the particular source.
+	 */
+	source_id = ucontrol->value.enumerated.item[0]; /* Use 2 and 3 */
+	change = (emu->i2c_capture_source != source_id);
+	if (change) {
+		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
+		spin_lock_irqsave(&emu->emu_lock, flags);
+		gpio = inl(emu->port + A_IOCFG);
+		if (source_id==0)
+			outl(gpio | 0x4, emu->port + A_IOCFG);
+		else
+			outl(gpio & ~0x4, emu->port + A_IOCFG);
+		spin_unlock_irqrestore(&emu->emu_lock, flags);
+
+		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
+		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
+		if (ngain != ogain)
+			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
+		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
+		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
+		if (ngain != ogain)
+			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
+
+		source = 1 << (source_id + 2);
+		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
+		emu->i2c_capture_source = source_id;
+	}
+        return change;
+}
+
+static struct snd_kcontrol_new snd_audigy_i2c_capture_source =
+{
+		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name =		"Capture Source",
+		.info =		snd_audigy_i2c_capture_source_info,
+		.get =		snd_audigy_i2c_capture_source_get,
+		.put =		snd_audigy_i2c_capture_source_put
+};
+
+static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 255;
+	return 0;
+}
+
+static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+	int source_id;
+
+	source_id = kcontrol->private_value;
+
+	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
+	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
+	return 0;
+}
+
+static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+	unsigned int ogain;
+	unsigned int ngain;
+	int source_id;
+	int change = 0;
+
+	source_id = kcontrol->private_value;
+	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
+	ngain = ucontrol->value.integer.value[0];
+	if (ngain > 0xff)
+		return 0;
+	if (ogain != ngain) {
+		if (emu->i2c_capture_source == source_id)
+			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
+		emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0];
+		change = 1;
+	}
+	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
+	ngain = ucontrol->value.integer.value[1];
+	if (ngain > 0xff)
+		return 0;
+	if (ogain != ngain) {
+		if (emu->i2c_capture_source == source_id)
+			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
+		emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1];
+		change = 1;
+	}
+
+	return change;
+}
+
+#define I2C_VOLUME(xname,chid) \
+{								\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |		\
+	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,		\
+	.info =  snd_audigy_i2c_volume_info,			\
+	.get =   snd_audigy_i2c_volume_get,			\
+	.put =   snd_audigy_i2c_volume_put,			\
+	.tlv = { .p = snd_audigy_db_scale2 },			\
+	.private_value = chid					\
+}
+
+
+static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = {
+	I2C_VOLUME("Mic Capture Volume", 0),
+	I2C_VOLUME("Line Capture Volume", 0)
+};
+
 #if 0
 static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
@@ -668,7 +1340,9 @@
 	int change = 0;
 
 	spin_lock_irqsave(&emu->reg_lock, flags);
-	if (emu->audigy) {
+	if ( emu->card_capabilities->i2c_adc) {
+		/* Do nothing for Audigy 2 ZS Notebook */
+	} else if (emu->audigy) {
 		reg = inl(emu->port + A_IOCFG);
 		val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0;
 		change = (reg & A_IOCFG_GPOUT0) != val;
@@ -806,6 +1480,24 @@
 		"AMic Playback Volume", "Mic Playback Volume",
 		NULL
 	};
+	static char *audigy_rename_ctls_i2c_adc[] = {
+		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
+		"Line Capture Volume", "Analog Mix Capture Volume",
+		"Wave Playback Volume", "OLD PCM Playback Volume",
+		"Wave Master Playback Volume", "Master Playback Volume",
+		"AMic Playback Volume", "Old Mic Playback Volume",
+		"CD Capture Volume", "IEC958 Optical Capture Volume",
+		NULL
+	};
+	static char *audigy_remove_ctls_i2c_adc[] = {
+		/* On the Audigy2 ZS Notebook
+		 * Capture via WM8775  */
+		"Mic Capture Volume",
+		"Analog Mix Capture Volume",
+		"Aux Capture Volume",
+		"IEC958 Optical Capture Volume",
+		NULL
+	};
 	static char *audigy_remove_ctls_1361t_adc[] = {
 		/* On the Audigy2 the AC97 playback is piped into
 		 * the Philips ADC for 24bit capture */
@@ -890,6 +1582,7 @@
 			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);
+				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
 			}
 			/* remove unused AC97 controls */
 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
@@ -898,6 +1591,10 @@
 		}
 		for (; *c; c++)
 			remove_ctl(card, *c);
+	} else if (emu->card_capabilities->i2c_adc) {
+		c = audigy_remove_ctls_i2c_adc;
+		for (; *c; c++)
+			remove_ctl(card, *c);
 	} else {
 	no_ac97:
 		if (emu->card_capabilities->ecard)
@@ -911,6 +1608,8 @@
 	if (emu->audigy)
 		if (emu->card_capabilities->adc_1361t)
 			c = audigy_rename_ctls_1361t_adc;
+		else if (emu->card_capabilities->i2c_adc)
+			c = audigy_rename_ctls_i2c_adc;
 		else
 			c = audigy_rename_ctls;
 	else
@@ -1021,7 +1720,7 @@
 			return err;
 	}
 
-	if ( emu->card_capabilities->emu1212m) {
+	if ( emu->card_capabilities->emu1010) {
 		;  /* Disable the snd_audigy_spdif_shared_spdif */
 	} else if (emu->audigy) {
 		if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
@@ -1045,6 +1744,48 @@
 		if ((err = snd_p16v_mixer(emu)))
 			return err;
 	}
+
+	if ( emu->card_capabilities->emu1010) {
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) {
+			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], emu));
+			if (err < 0)
+				return err;
+		}
+		for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
+			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], emu));
+			if (err < 0)
+				return err;
+		}
+		for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) {
+			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
+			if (err < 0)
+				return err;
+		}
+		for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) {
+			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
+			if (err < 0)
+				return err;
+		}
+		err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_internal_clock, emu));
+		if (err < 0)
+			return err;
+	}
+
+	if ( emu->card_capabilities->i2c_adc) {
+		int i;
+
+		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
+		if (err < 0)
+			return err;
+
+		for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) {
+			err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu));
+			if (err < 0)
+				return err;
+		}
+	}
 		
 	return 0;
 }
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index 717e92e..ab4f5df 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -147,7 +147,7 @@
 					      1,
 					      &epcm->extra);
 		if (err < 0) {
-			// printk("pcm_channel_alloc: failed extra: voices=%d, frame=%d\n", voices, frame);
+			/* printk("pcm_channel_alloc: failed extra: voices=%d, frame=%d\n", voices, frame); */
 			for (i = 0; i < voices; i++) {
 				snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]);
 				epcm->voices[i] = NULL;
@@ -339,7 +339,7 @@
 		}
 	}
 
-	// setup routing
+	/* setup routing */
 	if (emu->audigy) {
 		snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
 				      snd_emu10k1_compose_audigy_fxrt1(send_routing));
@@ -353,12 +353,15 @@
 	} else
 		snd_emu10k1_ptr_write(emu, FXRT, voice,
 				      snd_emu10k1_compose_send_routing(send_routing));
-	// Stop CA
-	// Assumption that PT is already 0 so no harm overwriting
+	/* Stop CA */
+	/* Assumption that PT is already 0 so no harm overwriting */
 	snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]);
 	snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24));
 	snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24));
-	pitch_target = emu10k1_calc_pitch_target(runtime->rate);
+	if (emu->card_capabilities->emu1010)
+		pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
+	else 
+		pitch_target = emu10k1_calc_pitch_target(runtime->rate);
 	if (extra)
 		snd_emu10k1_ptr_write(emu, CCCA, voice, start_addr |
 			      emu10k1_select_interprom(pitch_target) |
@@ -367,14 +370,14 @@
 		snd_emu10k1_ptr_write(emu, CCCA, voice, (start_addr + ccis) |
 			      emu10k1_select_interprom(pitch_target) |
 			      (w_16 ? 0 : CCCA_8BITSELECT));
-	// Clear filter delay memory
+	/* Clear filter delay memory */
 	snd_emu10k1_ptr_write(emu, Z1, voice, 0);
 	snd_emu10k1_ptr_write(emu, Z2, voice, 0);
-	// invalidate maps
+	/* invalidate maps */
 	silent_page = ((unsigned int)emu->silent_page.addr << 1) | MAP_PTI_MASK;
 	snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page);
 	snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page);
-	// modulation envelope
+	/* modulation envelope */
 	snd_emu10k1_ptr_write(emu, CVCF, voice, 0xffff);
 	snd_emu10k1_ptr_write(emu, VTFT, voice, 0xffff);
 	snd_emu10k1_ptr_write(emu, ATKHLDM, voice, 0);
@@ -385,12 +388,12 @@
 	snd_emu10k1_ptr_write(emu, TREMFRQ, voice, 0);
 	snd_emu10k1_ptr_write(emu, FM2FRQ2, voice, 0);
 	snd_emu10k1_ptr_write(emu, ENVVAL, voice, 0x8000);
-	// volume envelope
+	/* volume envelope */
 	snd_emu10k1_ptr_write(emu, ATKHLDV, voice, 0x7f7f);
 	snd_emu10k1_ptr_write(emu, ENVVOL, voice, 0x0000);
-	// filter envelope
+	/* filter envelope */
 	snd_emu10k1_ptr_write(emu, PEFE_FILTERAMOUNT, voice, 0x7f);
-	// pitch envelope
+	/* pitch envelope */
 	snd_emu10k1_ptr_write(emu, PEFE_PITCHAMOUNT, voice, 0);
 
 	spin_unlock_irqrestore(&emu->reg_lock, flags);
@@ -468,7 +471,7 @@
 		snd_emu10k1_voice_free(epcm->emu, epcm->extra);
 		epcm->extra = NULL;
 	}
-	for (i=0; i < NUM_EFX_PLAYBACK; i++) {
+	for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
 		if (epcm->voices[i]) {
 			snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]);
 			epcm->voices[i] = NULL;
@@ -637,7 +640,7 @@
 	stereo = (!extra && runtime->channels == 2);
 	sample = snd_pcm_format_width(runtime->format) == 16 ? 0 : 0x80808080;
 	ccis = emu10k1_ccis(stereo, sample == 0);
-	// set cs to 2 * number of cache registers beside the invalidated
+	/* set cs to 2 * number of cache registers beside the invalidated */
 	cs = (sample == 0) ? (32-ccis) : (64-ccis+1) >> 1;
 	if (cs > 16) cs = 16;
 	for (i = 0; i < cs; i++) {
@@ -646,14 +649,14 @@
 			snd_emu10k1_ptr_write(emu, CD0 + i, voice + 1, sample);
 		}
 	}
-	// reset cache
+	/* reset cache */
 	snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, 0);
 	snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice, cra);
 	if (stereo) {
 		snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice + 1, 0);
 		snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice + 1, cra);
 	}
-	// fill cache
+	/* fill cache */
 	snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, ccis);
 	if (stereo) {
 		snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice+1, ccis);
@@ -698,7 +701,10 @@
 	voice = evoice->number;
 
 	pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8;
-	pitch_target = emu10k1_calc_pitch_target(runtime->rate);
+	if (emu->card_capabilities->emu1010)
+		pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
+	else 
+		pitch_target = emu10k1_calc_pitch_target(runtime->rate);
 	snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target);
 	if (master || evoice->epcm->type == PLAYBACK_EFX)
 		snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target);
@@ -732,7 +738,7 @@
 	struct snd_emu10k1_pcm_mixer *mix;
 	int result = 0;
 
-	// printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream));
+	/* printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream)); */
 	spin_lock(&emu->reg_lock);
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
@@ -778,10 +784,10 @@
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
-		// hmm this should cause full and half full interrupt to be raised?  
+		/* hmm this should cause full and half full interrupt to be raised? */
 		outl(epcm->capture_ipr, emu->port + IPR);
 		snd_emu10k1_intr_enable(emu, epcm->capture_inte);
-		// printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs);
+		/* printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs); */
 		switch (epcm->type) {
 		case CAPTURE_AC97ADC:
 			snd_emu10k1_ptr_write(emu, ADCCR, 0, epcm->capture_cr_val);
@@ -790,6 +796,7 @@
 			if (emu->audigy) {
 				snd_emu10k1_ptr_write(emu, A_FXWC1, 0, epcm->capture_cr_val);
 				snd_emu10k1_ptr_write(emu, A_FXWC2, 0, epcm->capture_cr_val2);
+				snd_printdd("cr_val=0x%x, cr_val2=0x%x\n", epcm->capture_cr_val, epcm->capture_cr_val2);
 			} else
 				snd_emu10k1_ptr_write(emu, FXWC, 0, epcm->capture_cr_val);
 			break;
@@ -851,7 +858,7 @@
 			ptr -= runtime->buffer_size;
 	}
 #endif
-	// printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size);
+	/* printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size); */
 	return ptr;
 }
 
@@ -868,7 +875,7 @@
 	spin_lock(&emu->reg_lock);
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
-		// prepare voices
+		/* prepare voices */
 		for (i = 0; i < NUM_EFX_PLAYBACK; i++) {	
 			snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[i]);
 		}
@@ -917,7 +924,7 @@
 	if (!epcm->running)
 		return 0;
 	if (epcm->first_ptr) {
-		udelay(50);	// hack, it takes awhile until capture is started
+		udelay(50);	/* hack, it takes awhile until capture is started */
 		epcm->first_ptr = 0;
 	}
 	ptr = snd_emu10k1_ptr_read(emu, epcm->capture_idx_reg, 0) & 0x0000ffff;
@@ -972,6 +979,28 @@
 	.fifo_size =		0,
 };
 
+static struct snd_pcm_hardware snd_emu10k1_capture_efx =
+{
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_RESUME |
+				 SNDRV_PCM_INFO_MMAP_VALID),
+	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | 
+				 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | 
+				 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+	.rate_min =		44100,
+	.rate_max =		192000,
+	.channels_min =		8,
+	.channels_max =		8,
+	.buffer_bytes_max =	(64*1024),
+	.period_bytes_min =	384,
+	.period_bytes_max =	(64*1024),
+	.periods_min =		2,
+	.periods_max =		2,
+	.fifo_size =		0,
+};
+
 /*
  *
  */
@@ -1016,7 +1045,7 @@
 	struct snd_emu10k1_pcm_mixer *mix;
 	int i;
 
-	for (i=0; i < NUM_EFX_PLAYBACK; i++) {
+	for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
 		mix = &emu->efx_pcm_mixer[i];
 		mix->epcm = NULL;
 		snd_emu10k1_pcm_efx_mixer_notify(emu, i, 0);
@@ -1045,7 +1074,7 @@
 	runtime->private_free = snd_emu10k1_pcm_free_substream;
 	runtime->hw = snd_emu10k1_efx_playback;
 	
-	for (i=0; i < NUM_EFX_PLAYBACK; i++) {
+	for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
 		mix = &emu->efx_pcm_mixer[i];
 		mix->send_routing[0][0] = i;
 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
@@ -1199,15 +1228,69 @@
 	epcm->capture_idx_reg = FXIDX;
 	substream->runtime->private_data = epcm;
 	substream->runtime->private_free = snd_emu10k1_pcm_free_substream;
-	runtime->hw = snd_emu10k1_capture;
+	runtime->hw = snd_emu10k1_capture_efx;
 	runtime->hw.rates = SNDRV_PCM_RATE_48000;
 	runtime->hw.rate_min = runtime->hw.rate_max = 48000;
 	spin_lock_irq(&emu->reg_lock);
-	runtime->hw.channels_min = runtime->hw.channels_max = 0;
-	for (idx = 0; idx < nefx; idx++) {
-		if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) {
-			runtime->hw.channels_min++;
-			runtime->hw.channels_max++;
+	if (emu->card_capabilities->emu1010) {
+		/* TODO 
+		 * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE
+		 * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+		 * SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+		 * SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000
+		 * rate_min = 44100,
+		 * rate_max = 192000,
+		 * channels_min = 8,
+		 * channels_max = 8,
+		 * Need to add mixer control to fix sample rate
+		 *                 
+		 * There are 16 mono channels of 16bits each.
+		 * 24bit Audio uses 2x channels over 16bit
+		 * 96kHz uses 2x channels over 48kHz
+		 * 192kHz uses 4x channels over 48kHz
+		 * So, for 48kHz 24bit, one has 8 channels
+		 * for 96kHz 24bit, one has 4 channels
+		 * for 192kHz 24bit, one has 2 channels
+		 */
+#if 1
+		switch (emu->emu1010.internal_clock) {
+		case 0:
+			/* For 44.1kHz */
+			runtime->hw.rates = SNDRV_PCM_RATE_44100;
+			runtime->hw.rate_min = runtime->hw.rate_max = 44100;
+			runtime->hw.channels_min = runtime->hw.channels_max = 8;
+			break;
+		case 1:
+			/* For 48kHz */
+			runtime->hw.rates = SNDRV_PCM_RATE_48000;
+			runtime->hw.rate_min = runtime->hw.rate_max = 48000;
+			runtime->hw.channels_min = runtime->hw.channels_max = 8;
+			break;
+		};
+#endif
+#if 0
+		/* For 96kHz */
+		runtime->hw.rates = SNDRV_PCM_RATE_96000;
+		runtime->hw.rate_min = runtime->hw.rate_max = 96000;
+		runtime->hw.channels_min = runtime->hw.channels_max = 4;
+#endif
+#if 0
+		/* For 192kHz */
+		runtime->hw.rates = SNDRV_PCM_RATE_192000;
+		runtime->hw.rate_min = runtime->hw.rate_max = 192000;
+		runtime->hw.channels_min = runtime->hw.channels_max = 2;
+#endif
+		runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE;
+		/* efx_voices_mask[0] is expected to be zero
+ 		 * efx_voices_mask[1] is expected to have 16bits set
+		 */
+	} else {
+		runtime->hw.channels_min = runtime->hw.channels_max = 0;
+		for (idx = 0; idx < nefx; idx++) {
+			if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) {
+				runtime->hw.channels_min++;
+				runtime->hw.channels_max++;
+			}
 		}
 	}
 	epcm->capture_cr_val = emu->efx_voices_mask[0];
@@ -1460,7 +1543,7 @@
 						   unsigned int count,
 						   unsigned int tram_shift)
 {
-	// printk("tram_poke1: dst_left = 0x%p, dst_right = 0x%p, src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count);
+	/* printk("tram_poke1: dst_left = 0x%p, dst_right = 0x%p, src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count); */
 	if ((tram_shift & 1) == 0) {
 		while (count--) {
 			*dst_left-- = *src++;
@@ -1537,7 +1620,7 @@
 	struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
 	unsigned int i;
 	
-	// printk("prepare: etram_pages = 0x%p, dma_area = 0x%x, buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2);
+	/* printk("prepare: etram_pages = 0x%p, dma_area = 0x%x, buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2); */
 	memset(&pcm->pcm_rec, 0, sizeof(pcm->pcm_rec));
 	pcm->pcm_rec.hw_buffer_size = pcm->buffer_size * 2; /* byte size */
 	pcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c
index b939e03..2c15859 100644
--- a/sound/pci/emu10k1/emuproc.c
+++ b/sound/pci/emu10k1/emuproc.c
@@ -3,6 +3,9 @@
  *                   Creative Labs, Inc.
  *  Routines for control of EMU10K1 chips / proc interface routines
  *
+ *  Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
+ *  	Added EMU 1010 support.
+ *
  *  BUGS:
  *    --
  *
@@ -255,7 +258,7 @@
 	unsigned int val, tmp, n;
 	val = snd_emu10k1_ptr20_read(emu, CAPTURE_RATE_STATUS, 0);
 	tmp = (val >> 16) & 0x8;
-	for (n=0;n<4;n++) {
+	for (n = 0; n < 4; n++) {
 		tmp = val >> (16 + (n*4));
 		if (tmp & 0x8) snd_iprintf(buffer, "Channel %d: Rate=%d\n", n, samplerate[tmp & 0x7]);
 		else snd_iprintf(buffer, "Channel %d: No input\n", n);
@@ -372,6 +375,27 @@
 }
 
 #ifdef CONFIG_SND_DEBUG
+static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry,
+				     struct snd_info_buffer *buffer)
+{
+	struct snd_emu10k1 *emu = entry->private_data;
+	unsigned long value;
+	unsigned long flags;
+	unsigned long regs;
+	int i;
+	snd_iprintf(buffer, "EMU1010 Registers:\n\n");
+
+	for(i = 0; i < 0x30; i+=1) {
+		spin_lock_irqsave(&emu->emu_lock, flags);
+		regs=i+0x40; /* 0x40 upwards are registers. */
+		outl(regs, emu->port + A_IOCFG);
+		outl(regs | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
+		value = inl(emu->port + A_IOCFG);
+		spin_unlock_irqrestore(&emu->emu_lock, flags);
+		snd_iprintf(buffer, "%02X: %08lX, %02lX\n", i, value, (value >> 8) & 0x7f);
+	}
+}
+
 static void snd_emu_proc_io_reg_read(struct snd_info_entry *entry,
 				     struct snd_info_buffer *buffer)
 {
@@ -398,7 +422,7 @@
 	while (!snd_info_get_line(buffer, line, sizeof(line))) {
 		if (sscanf(line, "%x %x", &reg, &val) != 2)
 			continue;
-		if ((reg < 0x40) && (reg >=0) && (val <= 0xffffffff) ) {
+		if ((reg < 0x40) && (reg >= 0) && (val <= 0xffffffff) ) {
 			spin_lock_irqsave(&emu->emu_lock, flags);
 			outl(val, emu->port + (reg & 0xfffffffc));
 			spin_unlock_irqrestore(&emu->emu_lock, flags);
@@ -474,7 +498,7 @@
 	while (!snd_info_get_line(buffer, line, sizeof(line))) {
 		if (sscanf(line, "%x %x %x", &reg, &channel_id, &val) != 3)
 			continue;
-		if ((reg < 0xa0) && (reg >=0) && (val <= 0xffffffff) && (channel_id >=0) && (channel_id <= 3) )
+		if ((reg < 0xa0) && (reg >= 0) && (val <= 0xffffffff) && (channel_id >= 0) && (channel_id <= 3) )
 			snd_ptr_write(emu, iobase, reg, channel_id, val);
 	}
 }
@@ -531,6 +555,10 @@
 {
 	struct snd_info_entry *entry;
 #ifdef CONFIG_SND_DEBUG
+	if ((emu->card_capabilities->emu1010) &&
+	     snd_card_proc_new(emu->card, "emu1010_regs", &entry)) {
+		snd_info_set_text_ops(entry, emu, snd_emu_proc_emu1010_reg_read);
+	}
 	if (! snd_card_proc_new(emu->card, "io_regs", &entry)) {
 		snd_info_set_text_ops(entry, emu, snd_emu_proc_io_reg_read);
 		entry->c.text.write = snd_emu_proc_io_reg_write;
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c
index 029e785..116e1c8 100644
--- a/sound/pci/emu10k1/io.c
+++ b/sound/pci/emu10k1/io.c
@@ -30,6 +30,7 @@
 #include <sound/core.h>
 #include <sound/emu10k1.h>
 #include <linux/delay.h>
+#include "p17v.h"
 
 unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
 {
@@ -167,6 +168,109 @@
 	return 0;
 }
 
+/* The ADC does not support i2c read, so only write is implemented */
+int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
+				u32 reg,
+				u32 value)
+{
+	u32 tmp;
+	int timeout = 0;
+	int status;
+	int retry;
+	if ((reg > 0x7f) || (value > 0x1ff)) {
+		snd_printk(KERN_ERR "i2c_write: invalid values.\n");
+		return -EINVAL;
+	}
+
+	tmp = reg << 25 | value << 16;
+	// snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value);
+	/* Not sure what this I2C channel controls. */
+	/* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */
+
+	/* This controls the I2C connected to the WM8775 ADC Codec */
+	snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
+	tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */
+
+	for (retry = 0; retry < 10; retry++) {
+		/* Send the data to i2c */
+		//tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0);
+		//tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
+		tmp = 0;
+		tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
+		snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
+
+		/* Wait till the transaction ends */
+		while (1) {
+			udelay(10);
+			status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
+                	// snd_printk("I2C:status=0x%x\n", status);
+			timeout++;
+			if ((status & I2C_A_ADC_START) == 0)
+				break;
+
+			if (timeout > 1000) {
+                		snd_printk("emu10k1:I2C:timeout status=0x%x\n", status);
+				break;
+			}
+		}
+		//Read back and see if the transaction is successful
+		if ((status & I2C_A_ADC_ABORT) == 0)
+			break;
+	}
+
+	if (retry == 10) {
+		snd_printk(KERN_ERR "Writing to ADC failed!\n");
+		return -EINVAL;
+	}
+    
+    	return 0;
+}
+
+int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value)
+{
+	if (reg < 0 || reg > 0x3f)
+		return 1;
+	reg += 0x40; /* 0x40 upwards are registers. */
+	if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */
+		return 1;
+	outl(reg, emu->port + A_IOCFG);
+	udelay(10);
+	outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
+	udelay(10);
+	outl(value, emu->port + A_IOCFG);
+	udelay(10);
+	outl(value | 0x80 , emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
+
+	return 0;
+}
+
+int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value)
+{
+	if (reg < 0 || reg > 0x3f)
+		return 1;
+	reg += 0x40; /* 0x40 upwards are registers. */
+	outl(reg, emu->port + A_IOCFG);
+	udelay(10);
+	outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
+	udelay(10);
+	*value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
+
+	return 0;
+}
+
+/* Each Destination has one and only one Source,
+ * but one Source can feed any number of Destinations simultaneously.
+ */
+int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src)
+{
+	snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
+	snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
+	snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
+	snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
+
+	return 0;
+}
+
 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
 {
 	unsigned long flags;
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c
index 4e0f954..465f8d5 100644
--- a/sound/pci/emu10k1/p16v.c
+++ b/sound/pci/emu10k1/p16v.c
@@ -253,7 +253,7 @@
 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
 	//struct snd_pcm_runtime *runtime = substream->runtime;
 	//struct snd_emu10k1_pcm *epcm = runtime->private_data;
-	emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0;
+	emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use = 0;
 	/* FIXME: maybe zero others */
 	return 0;
 }
@@ -264,7 +264,7 @@
 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
 	//struct snd_pcm_runtime *runtime = substream->runtime;
 	//struct snd_emu10k1_pcm *epcm = runtime->private_data;
-	emu->p16v_capture_voice.use=0;
+	emu->p16v_capture_voice.use = 0;
 	/* FIXME: maybe zero others */
 	return 0;
 }
@@ -349,7 +349,7 @@
 	  break;
 	}
 	/* FIXME: Check emu->buffer.size before actually writing to it. */
-	for(i=0; i < runtime->periods; i++) {
+	for(i = 0; i < runtime->periods; i++) {
 		table_base[i*2]=runtime->dma_addr+(i*period_size_bytes);
 		table_base[(i*2)+1]=period_size_bytes<<16;
 	}
@@ -394,7 +394,7 @@
 	/* FIXME: Check emu->buffer.size before actually writing to it. */
 	snd_emu10k1_ptr20_write(emu, 0x13, channel, 0);
 	snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr);
-	snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes
+	snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size) << 16); // buffer size in bytes
 	snd_emu10k1_ptr20_write(emu, CAPTURE_POINTER, channel, 0);
 	//snd_emu10k1_ptr20_write(emu, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC or Line in */
 	//snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<<channel));
@@ -437,7 +437,7 @@
         struct snd_pcm_substream *s;
 	u32 basic = 0;
 	u32 inte = 0;
-	int running=0;
+	int running = 0;
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
@@ -445,7 +445,7 @@
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	default:
-		running=0;
+		running = 0;
 		break;
 	}
         snd_pcm_group_for_each(pos, substream) {
@@ -785,7 +785,7 @@
 	}
         return change;
 }
-static DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1);
+static const DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1);
 
 #define P16V_VOL(xname,xreg,xhl) { \
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
diff --git a/sound/pci/emu10k1/p17v.h b/sound/pci/emu10k1/p17v.h
index 7ddb5be..4ef5f68 100644
--- a/sound/pci/emu10k1/p17v.h
+++ b/sound/pci/emu10k1/p17v.h
@@ -43,6 +43,53 @@
 #define P17V_I2C_ADDR		0x3d	/* I2C Address */
 #define P17V_I2C_0		0x3e	/* I2C Data */
 #define P17V_I2C_1		0x3f	/* I2C Data */
+/* I2C values */
+#define I2C_A_ADC_ADD_MASK	0x000000fe	/*The address is a 7 bit address */
+#define I2C_A_ADC_RW_MASK	0x00000001	/*bit mask for R/W */
+#define I2C_A_ADC_TRANS_MASK	0x00000010  	/*Bit mask for I2c address DAC value  */
+#define I2C_A_ADC_ABORT_MASK	0x00000020	/*Bit mask for I2C transaction abort flag */
+#define I2C_A_ADC_LAST_MASK	0x00000040	/*Bit mask for Last word transaction */
+#define I2C_A_ADC_BYTE_MASK	0x00000080	/*Bit mask for Byte Mode */
+
+#define I2C_A_ADC_ADD		0x00000034	/*This is the Device address for ADC  */
+#define I2C_A_ADC_READ		0x00000001	/*To perform a read operation */
+#define I2C_A_ADC_START		0x00000100	/*Start I2C transaction */
+#define I2C_A_ADC_ABORT		0x00000200	/*I2C transaction abort */
+#define I2C_A_ADC_LAST		0x00000400	/*I2C last transaction */
+#define I2C_A_ADC_BYTE		0x00000800	/*I2C one byte mode */
+
+#define I2C_D_ADC_REG_MASK	0xfe000000  	/*ADC address register */ 
+#define I2C_D_ADC_DAT_MASK	0x01ff0000  	/*ADC data register */
+
+#define ADC_TIMEOUT		0x00000007	/*ADC Timeout Clock Disable */
+#define ADC_IFC_CTRL		0x0000000b	/*ADC Interface Control */
+#define ADC_MASTER		0x0000000c	/*ADC Master Mode Control */
+#define ADC_POWER		0x0000000d	/*ADC PowerDown Control */
+#define ADC_ATTEN_ADCL		0x0000000e	/*ADC Attenuation ADCL */
+#define ADC_ATTEN_ADCR		0x0000000f	/*ADC Attenuation ADCR */
+#define ADC_ALC_CTRL1		0x00000010	/*ADC ALC Control 1 */
+#define ADC_ALC_CTRL2		0x00000011	/*ADC ALC Control 2 */
+#define ADC_ALC_CTRL3		0x00000012	/*ADC ALC Control 3 */
+#define ADC_NOISE_CTRL		0x00000013	/*ADC Noise Gate Control */
+#define ADC_LIMIT_CTRL		0x00000014	/*ADC Limiter Control */
+#define ADC_MUX			0x00000015  	/*ADC Mux offset */
+#if 0
+/* FIXME: Not tested yet. */
+#define ADC_GAIN_MASK		0x000000ff	//Mask for ADC Gain
+#define ADC_ZERODB		0x000000cf	//Value to set ADC to 0dB
+#define ADC_MUTE_MASK		0x000000c0	//Mask for ADC mute
+#define ADC_MUTE		0x000000c0	//Value to mute ADC
+#define ADC_OSR			0x00000008	//Mask for ADC oversample rate select
+#define ADC_TIMEOUT_DISABLE	0x00000008	//Value and mask to disable Timeout clock
+#define ADC_HPF_DISABLE		0x00000100	//Value and mask to disable High pass filter
+#define ADC_TRANWIN_MASK	0x00000070	//Mask for Length of Transient Window
+#endif
+
+#define ADC_MUX_MASK		0x0000000f	//Mask for ADC Mux
+#define ADC_MUX_0		0x00000001	//Value to select Unknown at ADC Mux (Not used)
+#define ADC_MUX_1		0x00000002	//Value to select Unknown at ADC Mux (Not used)
+#define ADC_MUX_2		0x00000004	//Value to select Mic at ADC Mux
+#define ADC_MUX_3		0x00000008	//Value to select Line-In at ADC Mux
 
 #define P17V_START_AUDIO	0x40	/* Start Audio bit */
 /* 41 - 47: Reserved */
diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c
index 94eca82..1db50fe 100644
--- a/sound/pci/emu10k1/voice.c
+++ b/sound/pci/emu10k1/voice.c
@@ -83,7 +83,7 @@
 	if (first_voice == last_voice)
 		return -ENOMEM;
 	
-	for (i=0; i < number; i++) {
+	for (i = 0; i < number; i++) {
 		voice = &emu->voices[(first_voice + i) % NUM_G];
 		// printk("voice alloc - %i, %i of %i\n", voice->number, idx-first_voice+1, number);
 		voice->use = 1;
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index a84f6b2..425b167 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -413,8 +413,6 @@
 	} u;
 
 	struct pci_dev *pci;
-	unsigned short subsystem_vendor_id;
-	unsigned short subsystem_device_id;
 	struct snd_card *card;
 	struct snd_pcm *pcm1;	/* DAC1/ADC PCM */
 	struct snd_pcm *pcm2;	/* DAC2 PCM */
@@ -1607,11 +1605,26 @@
 	ensoniq->u.es1371.ac97 = NULL;
 }
 
-static struct {
+struct es1371_quirk {
 	unsigned short vid;		/* vendor ID */
 	unsigned short did;		/* device ID */
 	unsigned char rev;		/* revision */
-} es1371_spdif_present[] __devinitdata = {
+};
+
+static int __devinit es1371_quirk_lookup(struct ensoniq *ensoniq,
+					 struct es1371_quirk *list)
+{
+	while (list->vid != (unsigned short)PCI_ANY_ID) {
+		if (ensoniq->pci->vendor == list->vid &&
+		    ensoniq->pci->device == list->did &&
+		    ensoniq->rev == list->rev)
+			return 1;
+		list++;
+	}
+	return 0;
+}
+
+static struct es1371_quirk es1371_spdif_present[] __devinitdata = {
 	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C },
 	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D },
 	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E },
@@ -1620,12 +1633,19 @@
 	{ .vid = PCI_ANY_ID, .did = PCI_ANY_ID }
 };
 
-static int snd_ensoniq_1371_mixer(struct ensoniq * ensoniq, int has_spdif, int has_line)
+static struct snd_pci_quirk ens1373_line_quirk[] __devinitdata = {
+	SND_PCI_QUIRK_ID(0x1274, 0x2000), /* GA-7DXR */
+	SND_PCI_QUIRK_ID(0x1458, 0xa000), /* GA-8IEXP */
+	{ } /* end */
+};
+
+static int __devinit snd_ensoniq_1371_mixer(struct ensoniq *ensoniq,
+					    int has_spdif, int has_line)
 {
 	struct snd_card *card = ensoniq->card;
 	struct snd_ac97_bus *pbus;
 	struct snd_ac97_template ac97;
-	int err, idx;
+	int err;
 	static struct snd_ac97_bus_ops ops = {
 		.write = snd_es1371_codec_write,
 		.read = snd_es1371_codec_read,
@@ -1641,33 +1661,28 @@
 	ac97.scaps = AC97_SCAP_AUDIO;
 	if ((err = snd_ac97_mixer(pbus, &ac97, &ensoniq->u.es1371.ac97)) < 0)
 		return err;
-	for (idx = 0; es1371_spdif_present[idx].vid != (unsigned short)PCI_ANY_ID; idx++)
-		if ((ensoniq->pci->vendor == es1371_spdif_present[idx].vid &&
-		     ensoniq->pci->device == es1371_spdif_present[idx].did &&
-		     ensoniq->rev == es1371_spdif_present[idx].rev) || has_spdif > 0) {
-		    	struct snd_kcontrol *kctl;
-			int i, index = 0; 
+	if (has_spdif > 0 ||
+	    (!has_spdif && es1371_quirk_lookup(ensoniq, es1371_spdif_present))) {
+		struct snd_kcontrol *kctl;
+		int i, index = 0;
 
-                        if (has_spdif < 0)
-                                break;
+		ensoniq->spdif_default = ensoniq->spdif_stream =
+			SNDRV_PCM_DEFAULT_CON_SPDIF;
+		outl(ensoniq->spdif_default, ES_REG(ensoniq, CHANNEL_STATUS));
 
-			ensoniq->spdif_default = ensoniq->spdif_stream =
-				SNDRV_PCM_DEFAULT_CON_SPDIF;
-			outl(ensoniq->spdif_default, ES_REG(ensoniq, CHANNEL_STATUS));
+		if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SPDIF)
+			index++;
 
-		    	if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SPDIF)
-			    	index++;
-
-			for (i = 0; i < (int)ARRAY_SIZE(snd_es1371_mixer_spdif); i++) {
-				kctl = snd_ctl_new1(&snd_es1371_mixer_spdif[i], ensoniq);
-				if (! kctl)
-					return -ENOMEM;
-				kctl->id.index = index;
-				if ((err = snd_ctl_add(card, kctl)) < 0)
-					return err;
-			}
-			break;
+		for (i = 0; i < ARRAY_SIZE(snd_es1371_mixer_spdif); i++) {
+			kctl = snd_ctl_new1(&snd_es1371_mixer_spdif[i], ensoniq);
+			if (!kctl)
+				return -ENOMEM;
+			kctl->id.index = index;
+			err = snd_ctl_add(card, kctl);
+			if (err < 0)
+				return err;
 		}
+	}
 	if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SDAC) {
 		/* mirror rear to front speakers */
 		ensoniq->cssr &= ~(ES_1373_REAR_BIT27|ES_1373_REAR_BIT24);
@@ -1676,12 +1691,10 @@
 		if (err < 0)
 			return err;
 	}
-	if (((ensoniq->subsystem_vendor_id == 0x1274) &&
-	    (ensoniq->subsystem_device_id == 0x2000)) || /* GA-7DXR */
-	    ((ensoniq->subsystem_vendor_id == 0x1458) &&
-	    (ensoniq->subsystem_device_id == 0xa000)) || /* GA-8IEXP */
-	    has_line > 0) {
-		 err = snd_ctl_add(card, snd_ctl_new1(&snd_ens1373_line, ensoniq));
+	if (has_line > 0 ||
+	    snd_pci_quirk_lookup(ensoniq->pci, ens1373_line_quirk)) {
+		 err = snd_ctl_add(card, snd_ctl_new1(&snd_ens1373_line,
+						      ensoniq));
 		 if (err < 0)
 			 return err;
 	}
@@ -1956,21 +1969,15 @@
 }
 
 #ifdef CHIP1371
-static struct {
-	unsigned short svid;		/* subsystem vendor ID */
-	unsigned short sdid;		/* subsystem device ID */
-} es1371_amplifier_hack[] = {
-	{ .svid = 0x107b, .sdid = 0x2150 },	/* Gateway Solo 2150 */
-	{ .svid = 0x13bd, .sdid = 0x100c },	/* EV1938 on Mebius PC-MJ100V */
-	{ .svid = 0x1102, .sdid = 0x5938 },	/* Targa Xtender300 */
-	{ .svid = 0x1102, .sdid = 0x8938 },	/* IPC Topnote G notebook */
-	{ .svid = PCI_ANY_ID, .sdid = PCI_ANY_ID }
+static struct snd_pci_quirk es1371_amplifier_hack[] __devinitdata = {
+	SND_PCI_QUIRK_ID(0x107b, 0x2150),	/* Gateway Solo 2150 */
+	SND_PCI_QUIRK_ID(0x13bd, 0x100c),	/* EV1938 on Mebius PC-MJ100V */
+	SND_PCI_QUIRK_ID(0x1102, 0x5938),	/* Targa Xtender300 */
+	SND_PCI_QUIRK_ID(0x1102, 0x8938),	/* IPC Topnote G notebook */
+	{ } /* end */
 };
-static struct {
-	unsigned short vid;		/* vendor ID */
-	unsigned short did;		/* device ID */
-	unsigned char rev;		/* revision */
-} es1371_ac97_reset_hack[] = {
+
+static struct es1371_quirk es1371_ac97_reset_hack[] = {
 	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C },
 	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D },
 	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E },
@@ -1984,7 +1991,6 @@
 {
 #ifdef CHIP1371
 	int idx;
-	struct pci_dev *pci = ensoniq->pci;
 #endif
 	/* this code was part of snd_ensoniq_create before intruduction
 	  * of suspend/resume
@@ -1999,16 +2005,12 @@
 	outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
 	outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL));
 	outl(0, ES_REG(ensoniq, 1371_LEGACY));
-	for (idx = 0; es1371_ac97_reset_hack[idx].vid != (unsigned short)PCI_ANY_ID; idx++)
-		if (pci->vendor == es1371_ac97_reset_hack[idx].vid &&
-		    pci->device == es1371_ac97_reset_hack[idx].did &&
-		    ensoniq->rev == es1371_ac97_reset_hack[idx].rev) {
-			outl(ensoniq->cssr, ES_REG(ensoniq, STATUS));
-			/* need to delay around 20ms(bleech) to give
-			some CODECs enough time to wakeup */
-			msleep(20);
-			break;
-		}
+	if (es1371_quirk_lookup(ensoniq, es1371_ac97_reset_hack)) {
+	    outl(ensoniq->cssr, ES_REG(ensoniq, STATUS));
+	    /* need to delay around 20ms(bleech) to give
+	       some CODECs enough time to wakeup */
+	    msleep(20);
+	}
 	/* AC'97 warm reset to start the bitclk */
 	outl(ensoniq->ctrl | ES_1371_SYNC_RES, ES_REG(ensoniq, CONTROL));
 	inl(ES_REG(ensoniq, CONTROL));
@@ -2112,11 +2114,7 @@
 				     struct ensoniq ** rensoniq)
 {
 	struct ensoniq *ensoniq;
-	unsigned short cmdw;
 	unsigned char cmdb;
-#ifdef CHIP1371
-	int idx;
-#endif
 	int err;
 	static struct snd_device_ops ops = {
 		.dev_free =	snd_ensoniq_dev_free,
@@ -2159,10 +2157,6 @@
 	pci_set_master(pci);
 	pci_read_config_byte(pci, PCI_REVISION_ID, &cmdb);
 	ensoniq->rev = cmdb;
-	pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &cmdw);
-	ensoniq->subsystem_vendor_id = cmdw;
-	pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &cmdw);
-	ensoniq->subsystem_device_id = cmdw;
 #ifdef CHIP1370
 #if 0
 	ensoniq->ctrl = ES_1370_CDC_EN | ES_1370_SERR_DISABLE |
@@ -2175,19 +2169,11 @@
 	ensoniq->ctrl = 0;
 	ensoniq->sctrl = 0;
 	ensoniq->cssr = 0;
-	for (idx = 0; es1371_amplifier_hack[idx].svid != (unsigned short)PCI_ANY_ID; idx++)
-		if (ensoniq->subsystem_vendor_id == es1371_amplifier_hack[idx].svid &&
-		    ensoniq->subsystem_device_id == es1371_amplifier_hack[idx].sdid) {
-			ensoniq->ctrl |= ES_1371_GPIO_OUT(1);	/* turn amplifier on */
-			break;
-		}
-	for (idx = 0; es1371_ac97_reset_hack[idx].vid != (unsigned short)PCI_ANY_ID; idx++)
-		if (pci->vendor == es1371_ac97_reset_hack[idx].vid &&
-		    pci->device == es1371_ac97_reset_hack[idx].did &&
-		    ensoniq->rev == es1371_ac97_reset_hack[idx].rev) {
-			ensoniq->cssr |= ES_1371_ST_AC97_RST;
-			break;
-		}
+	if (snd_pci_quirk_lookup(pci, es1371_amplifier_hack))
+		ensoniq->ctrl |= ES_1371_GPIO_OUT(1);	/* turn amplifier on */
+
+	if (es1371_quirk_lookup(ensoniq, es1371_ac97_reset_hack))
+		ensoniq->cssr |= ES_1371_ST_AC97_RST;
 #endif
 
 	snd_ensoniq_chip_init(ensoniq);
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 66ac26c..fec29a1 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -1344,7 +1344,7 @@
 	8, 15, TLV_DB_SCALE_ITEM(-750, 150, 0),
 };
 
-static DECLARE_TLV_DB_SCALE(db_scale_capture, 0, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_capture, 0, 150, 0);
 
 static struct snd_kcontrol_new snd_es1938_controls[] = {
 ES1938_DOUBLE_TLV("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0,
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index b7b361c..6dc578b 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -1157,7 +1157,7 @@
 	return snd_fm801_update_bits(chip, FM801_REC_SRC, 7, val);
 }
 
-static DECLARE_TLV_DB_SCALE(db_scale_dsp, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -3450, 150, 0);
 
 #define FM801_CONTROLS ARRAY_SIZE(snd_fm801_controls)
 
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index dbacba6..60d7b05 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -1,5 +1,14 @@
 snd-hda-intel-objs := hda_intel.o
-snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o patch_atihdmi.o
+snd-hda-codec-objs := hda_codec.o \
+	hda_generic.o \
+	patch_realtek.o \
+	patch_cmedia.o \
+	patch_analog.o \
+	patch_sigmatel.o \
+	patch_si3054.o \
+	patch_atihdmi.o \
+	patch_conexant.o \
+	patch_via.o
 ifdef CONFIG_PROC_FS
 snd-hda-codec-objs += hda_proc.o
 endif
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 18bbc87..8f34fb4 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -52,6 +52,7 @@
 static struct hda_vendor_id hda_vendor_ids[] = {
 	{ 0x10ec, "Realtek" },
 	{ 0x1057, "Motorola" },
+	{ 0x1106, "VIA" },
 	{ 0x11d4, "Analog Devices" },
 	{ 0x13f6, "C-Media" },
 	{ 0x14f1, "Conexant" },
@@ -262,7 +263,7 @@
 	unsol->queue[wp] = res;
 	unsol->queue[wp + 1] = res_ex;
 
-	queue_work(unsol->workq, &unsol->work);
+	schedule_work(&unsol->work);
 
 	return 0;
 }
@@ -309,12 +310,6 @@
 		snd_printk(KERN_ERR "hda_codec: can't allocate unsolicited queue\n");
 		return -ENOMEM;
 	}
-	unsol->workq = create_singlethread_workqueue("hda_codec");
-	if (! unsol->workq) {
-		snd_printk(KERN_ERR "hda_codec: can't create workqueue\n");
-		kfree(unsol);
-		return -ENOMEM;
-	}
 	INIT_WORK(&unsol->work, process_unsol_events);
 	unsol->bus = bus;
 	bus->unsol = unsol;
@@ -333,7 +328,7 @@
 	if (! bus)
 		return 0;
 	if (bus->unsol) {
-		destroy_workqueue(bus->unsol->workq);
+		flush_scheduled_work();
 		kfree(bus->unsol);
 	}
 	list_for_each_safe(p, n, &bus->codec_list) {
@@ -1714,6 +1709,8 @@
 /**
  * snd_hda_check_board_config - compare the current codec with the config table
  * @codec: the HDA codec
+ * @num_configs: number of config enums
+ * @models: array of model name strings
  * @tbl: configuration table, terminated by null entries
  *
  * Compares the modelname or PCI subsystem id of the current codec with the
@@ -1722,33 +1719,44 @@
  *
  * If no entries are matching, the function returns a negative value.
  */
-int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl)
+int snd_hda_check_board_config(struct hda_codec *codec,
+			       int num_configs, const char **models,
+			       const struct snd_pci_quirk *tbl)
 {
-	const struct hda_board_config *c;
-
-	if (codec->bus->modelname) {
-		for (c = tbl; c->modelname || c->pci_subvendor; c++) {
-			if (c->modelname &&
-			    ! strcmp(codec->bus->modelname, c->modelname)) {
-				snd_printd(KERN_INFO "hda_codec: model '%s' is selected\n", c->modelname);
-				return c->config;
+	if (codec->bus->modelname && models) {
+		int i;
+		for (i = 0; i < num_configs; i++) {
+			if (models[i] &&
+			    !strcmp(codec->bus->modelname, models[i])) {
+				snd_printd(KERN_INFO "hda_codec: model '%s' is "
+					   "selected\n", models[i]);
+				return i;
 			}
 		}
 	}
 
-	if (codec->bus->pci) {
-		u16 subsystem_vendor, subsystem_device;
-		pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
-		pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_ID, &subsystem_device);
-		for (c = tbl; c->modelname || c->pci_subvendor; c++) {
-			if (c->pci_subvendor == subsystem_vendor &&
-			    (! c->pci_subdevice /* all match */||
-			     (c->pci_subdevice == subsystem_device))) {
-				snd_printdd(KERN_INFO "hda_codec: PCI %x:%x, codec config %d is selected\n",
-					    subsystem_vendor, subsystem_device, c->config);
-				return c->config;
-			}
+	if (!codec->bus->pci || !tbl)
+		return -1;
+
+	tbl = snd_pci_quirk_lookup(codec->bus->pci, tbl);
+	if (!tbl)
+		return -1;
+	if (tbl->value >= 0 && tbl->value < num_configs) {
+#ifdef CONFIG_SND_DEBUG_DETECT
+		char tmp[10];
+		const char *model = NULL;
+		if (models)
+			model = models[tbl->value];
+		if (!model) {
+			sprintf(tmp, "#%d", tbl->value);
+			model = tmp;
 		}
+		snd_printdd(KERN_INFO "hda_codec: model '%s' is selected "
+			    "for config %x:%x (%s)\n",
+			    model, tbl->subvendor, tbl->subdevice,
+			    (tbl->name ? tbl->name : "Unknown device"));
+#endif
+		return tbl->value;
 	}
 	return -1;
 }
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 1a7e821..b9a8e23 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -199,7 +199,7 @@
 
 /* STATESTS int mask: SD2,SD1,SD0 */
 #define STATESTS_INT_MASK	0x07
-#define AZX_MAX_CODECS		4
+#define AZX_MAX_CODECS		3
 
 /* SD_CTL bits */
 #define SD_CTL_STREAM_RESET	0x01	/* stream reset bit */
@@ -1285,7 +1285,7 @@
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 					      snd_dma_pci_data(chip->pci),
-					      1024 * 64, 1024 * 128);
+					      1024 * 64, 1024 * 1024);
 	chip->pcm[pcm_dev] = pcm;
 	if (chip->pcm_devs < pcm_dev + 1)
 		chip->pcm_devs = pcm_dev + 1;
@@ -1391,6 +1391,7 @@
 		return -1;
 	}
 	chip->irq = chip->pci->irq;
+	pci_intx(chip->pci, !chip->msi);
 	return 0;
 }
 
@@ -1502,6 +1503,31 @@
 }
 
 /*
+ * white/black-listing for position_fix
+ */
+static const struct snd_pci_quirk position_fix_list[] __devinitdata = {
+	SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE),
+	{}
+};
+
+static int __devinit check_position_fix(struct azx *chip, int fix)
+{
+	const struct snd_pci_quirk *q;
+
+	if (fix == POS_FIX_AUTO) {
+		q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
+		if (q) {
+			snd_printdd(KERN_INFO
+				    "hda_intel: position_fix set to %d "
+				    "for device %04x:%04x\n",
+				    q->value, q->subvendor, q->subdevice);
+			return q->value;
+		}
+	}
+	return fix;
+}
+
+/*
  * constructor
  */
 static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
@@ -1535,7 +1561,8 @@
 	chip->driver_type = driver_type;
 	chip->msi = enable_msi;
 
-	chip->position_fix = position_fix;
+	chip->position_fix = check_position_fix(chip, position_fix);
+
 	chip->single_cmd = single_cmd;
 
 #if BITS_PER_LONG != 64
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 9ca1baf..39718d6 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -173,14 +173,9 @@
 /*
  * Misc
  */
-struct hda_board_config {
-	const char *modelname;
-	int config;
-	unsigned short pci_subvendor;
-	unsigned short pci_subdevice;
-};
-
-int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl);
+int snd_hda_check_board_config(struct hda_codec *codec, int num_configs,
+			       const char **modelnames,
+			       const struct snd_pci_quirk *pci_list);
 int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew);
 
 /*
@@ -204,7 +199,6 @@
 	unsigned int rp, wp;
 
 	/* workqueue */
-	struct workqueue_struct *workq;
 	struct work_struct work;
 	struct hda_bus *bus;
 };
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h
index 0b66879..9f9e9ae 100644
--- a/sound/pci/hda/hda_patch.h
+++ b/sound/pci/hda/hda_patch.h
@@ -14,6 +14,10 @@
 extern struct hda_codec_preset snd_hda_preset_si3054[];
 /* ATI HDMI codecs */
 extern struct hda_codec_preset snd_hda_preset_atihdmi[];
+/* Conexant audio codec */
+extern struct hda_codec_preset snd_hda_preset_conexant[];
+/* VIA codecs */
+extern struct hda_codec_preset snd_hda_preset_via[];
 
 static const struct hda_codec_preset *hda_preset_tables[] = {
 	snd_hda_preset_realtek,
@@ -22,5 +26,7 @@
 	snd_hda_preset_sigmatel,
 	snd_hda_preset_si3054,
 	snd_hda_preset_atihdmi,
+	snd_hda_preset_conexant,
+	snd_hda_preset_via,
 	NULL
 };
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 076365b..38977bc 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -782,54 +782,63 @@
 
 /* eapd initialization */
 static struct hda_verb ad1986a_eapd_init_verbs[] = {
-	{0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00},
+	{0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
 	{}
 };
 
-/* models */
-enum { AD1986A_6STACK, AD1986A_3STACK, AD1986A_LAPTOP, AD1986A_LAPTOP_EAPD };
+/* Ultra initialization */
+static struct hda_verb ad1986a_ultra_init[] = {
+	/* eapd initialization */
+	{ 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
+	/* CLFE -> Mic in */
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 },
+	{ 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+	{ 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
+	{ } /* end */
+};
 
-static struct hda_board_config ad1986a_cfg_tbl[] = {
-	{ .modelname = "6stack",	.config = AD1986A_6STACK },
-	{ .modelname = "3stack",	.config = AD1986A_3STACK },
-	{ .pci_subvendor = 0x10de, .pci_subdevice = 0xcb84,
-	  .config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x817f,
-	  .config = AD1986A_3STACK }, /* ASUS P5P-L2 */
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x81b3,
-	  .config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x81cb,
-	  .config = AD1986A_3STACK }, /* ASUS M2NPV-VM */
-	{ .modelname = "laptop",	.config = AD1986A_LAPTOP },
-	{ .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e,
-	  .config = AD1986A_LAPTOP }, /* FSC V2060 */
-	{ .pci_subvendor = 0x17c0, .pci_subdevice = 0x2017,
-	  .config = AD1986A_LAPTOP }, /* Samsung M50 */
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x818f,
-	  .config = AD1986A_LAPTOP }, /* ASUS P5GV-MX */
-	{ .modelname = "laptop-eapd",	.config = AD1986A_LAPTOP_EAPD },
-	{ .pci_subvendor = 0x144d, .pci_subdevice = 0xc023,
-	  .config = AD1986A_LAPTOP_EAPD }, /* Samsung X60 Chane */
-	{ .pci_subvendor = 0x144d, .pci_subdevice = 0xc024,
-	  .config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */
-	{ .pci_subvendor = 0x144d, .pci_subdevice = 0xc026,
-	  .config = AD1986A_LAPTOP_EAPD }, /* Samsung X11-T2300 Culesa */
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1153,
-	  .config = AD1986A_LAPTOP_EAPD }, /* ASUS M9 */
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1213,
-	  .config = AD1986A_LAPTOP_EAPD }, /* ASUS A6J */
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x11f7,
-	  .config = AD1986A_LAPTOP_EAPD }, /* ASUS U5A */
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1263,
-	  .config = AD1986A_LAPTOP_EAPD }, /* ASUS U5F */
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1297,
-	  .config = AD1986A_LAPTOP_EAPD }, /* ASUS Z62F */
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x12b3,
-	  .config = AD1986A_LAPTOP_EAPD }, /* ASUS V1j */
-	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x30af,
-	  .config = AD1986A_LAPTOP_EAPD }, /* HP Compaq Presario B2800 */
-	{ .pci_subvendor = 0x17aa, .pci_subdevice = 0x2066,
-	  .config = AD1986A_LAPTOP_EAPD }, /* Lenovo 3000 N100-07684JU */
+/* models */
+enum {
+	AD1986A_6STACK,
+	AD1986A_3STACK,
+	AD1986A_LAPTOP,
+	AD1986A_LAPTOP_EAPD,
+	AD1986A_ULTRA,
+	AD1986A_MODELS
+};
+
+static const char *ad1986a_models[AD1986A_MODELS] = {
+	[AD1986A_6STACK]	= "6stack",
+	[AD1986A_3STACK]	= "3stack",
+	[AD1986A_LAPTOP]	= "laptop",
+	[AD1986A_LAPTOP_EAPD]	= "laptop-eapd",
+	[AD1986A_ULTRA]		= "ultra",
+};
+
+static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
+	SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
+	SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
+	SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
+	SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
+	SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
+	SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
+	SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
+	SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
+	SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
+	SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP),
 	{}
 };
 
@@ -861,7 +870,9 @@
 	codec->patch_ops = ad198x_patch_ops;
 
 	/* override some parameters */
-	board_config = snd_hda_check_board_config(codec, ad1986a_cfg_tbl);
+	board_config = snd_hda_check_board_config(codec, AD1986A_MODELS,
+						  ad1986a_models,
+						  ad1986a_cfg_tbl);
 	switch (board_config) {
 	case AD1986A_3STACK:
 		spec->num_mixers = 2;
@@ -891,6 +902,15 @@
 		spec->multiout.dig_out_nid = 0;
 		spec->input_mux = &ad1986a_laptop_eapd_capture_source;
 		break;
+	case AD1986A_ULTRA:
+		spec->mixers[0] = ad1986a_laptop_eapd_mixers;
+		spec->num_init_verbs = 2;
+		spec->init_verbs[1] = ad1986a_ultra_init;
+		spec->multiout.max_channels = 2;
+		spec->multiout.num_dacs = 1;
+		spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
+		spec->multiout.dig_out_nid = 0;
+		break;
 	}
 
 	return 0;
@@ -1391,20 +1411,27 @@
 };
 
 /* models */
-enum { AD1981_BASIC, AD1981_HP, AD1981_THINKPAD };
+enum {
+	AD1981_BASIC,
+	AD1981_HP,
+	AD1981_THINKPAD,
+	AD1981_MODELS
+};
 
-static struct hda_board_config ad1981_cfg_tbl[] = {
-	{ .modelname = "hp", .config = AD1981_HP },
+static const char *ad1981_models[AD1981_MODELS] = {
+	[AD1981_HP]		= "hp",
+	[AD1981_THINKPAD]	= "thinkpad",
+	[AD1981_BASIC]		= "basic",
+};
+
+static struct snd_pci_quirk ad1981_cfg_tbl[] = {
 	/* All HP models */
-	{ .pci_subvendor = 0x103c, .config = AD1981_HP },
-	{ .pci_subvendor = 0x30b0, .pci_subdevice = 0x103c,
-	  .config = AD1981_HP }, /* HP nx6320 (reversed SSID, H/W bug) */
-	{ .modelname = "thinkpad", .config = AD1981_THINKPAD },
+	SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP),
+	/* HP nx6320 (reversed SSID, H/W bug) */
+	SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
 	/* Lenovo Thinkpad T60/X60/Z6xx */
-	{ .pci_subvendor = 0x17aa, .config = AD1981_THINKPAD },
-	{ .pci_subvendor = 0x1014, .pci_subdevice = 0x0597,
-	  .config = AD1981_THINKPAD }, /* Z60m/t */
-	{ .modelname = "basic", .config = AD1981_BASIC },
+	SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD),
+	SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
 	{}
 };
 
@@ -1437,7 +1464,9 @@
 	codec->patch_ops = ad198x_patch_ops;
 
 	/* override some parameters */
-	board_config = snd_hda_check_board_config(codec, ad1981_cfg_tbl);
+	board_config = snd_hda_check_board_config(codec, AD1981_MODELS,
+						  ad1981_models,
+						  ad1981_cfg_tbl);
 	switch (board_config) {
 	case AD1981_HP:
 		spec->mixers[0] = ad1981_hp_mixers;
@@ -2565,15 +2594,14 @@
 /*
  */
 
-static struct hda_board_config ad1988_cfg_tbl[] = {
-	{ .modelname = "6stack",	.config = AD1988_6STACK },
-	{ .modelname = "6stack-dig",	.config = AD1988_6STACK_DIG },
-	{ .modelname = "3stack",	.config = AD1988_3STACK },
-	{ .modelname = "3stack-dig",	.config = AD1988_3STACK_DIG },
-	{ .modelname = "laptop",	.config = AD1988_LAPTOP },
-	{ .modelname = "laptop-dig",	.config = AD1988_LAPTOP_DIG },
-	{ .modelname = "auto",		.config = AD1988_AUTO },
-	{}
+static const char *ad1988_models[AD1988_MODEL_LAST] = {
+	[AD1988_6STACK]		= "6stack",
+	[AD1988_6STACK_DIG]	= "6stack-dig",
+	[AD1988_3STACK]		= "3stack",
+	[AD1988_3STACK_DIG]	= "3stack-dig",
+	[AD1988_LAPTOP]		= "laptop",
+	[AD1988_LAPTOP_DIG]	= "laptop-dig",
+	[AD1988_AUTO]		= "auto",
 };
 
 static int patch_ad1988(struct hda_codec *codec)
@@ -2591,8 +2619,9 @@
 	if (is_rev2(codec))
 		snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n");
 
-	board_config = snd_hda_check_board_config(codec, ad1988_cfg_tbl);
-	if (board_config < 0 || board_config >= AD1988_MODEL_LAST) {
+	board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
+						  ad1988_models, NULL);
+	if (board_config < 0) {
 		printk(KERN_INFO "hda_codec: Unknown model for AD1988, trying auto-probe from BIOS...\n");
 		board_config = AD1988_AUTO;
 	}
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index d38ce22..5b9d3a3 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -40,6 +40,7 @@
 	CMI_FULL_DIG,	/* back 6-jack + front-panel 2-jack + digital I/O */
 	CMI_ALLOUT,	/* back 5-jack + front-panel 2-jack + digital out */
 	CMI_AUTO,	/* let driver guess it */
+	CMI_MODELS
 };
 
 struct cmi_spec {
@@ -603,14 +604,17 @@
 /*
  */
 
-static struct hda_board_config cmi9880_cfg_tbl[] = {
-	{ .modelname = "minimal", .config = CMI_MINIMAL },
-	{ .modelname = "min_fp", .config = CMI_MIN_FP },
-	{ .modelname = "full", .config = CMI_FULL },
-	{ .modelname = "full_dig", .config = CMI_FULL_DIG },
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x813d, .config = CMI_FULL_DIG }, /* ASUS P5AD2 */
-	{ .modelname = "allout", .config = CMI_ALLOUT },
-	{ .modelname = "auto", .config = CMI_AUTO },
+static const char *cmi9880_models[CMI_MODELS] = {
+	[CMI_MINIMAL]	= "minimal",
+	[CMI_MIN_FP]	= "min_fp",
+	[CMI_FULL]	= "full",
+	[CMI_FULL_DIG]	= "full_dig",
+	[CMI_ALLOUT]	= "allout",
+	[CMI_AUTO]	= "auto",
+};
+
+static struct snd_pci_quirk cmi9880_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", CMI_FULL_DIG),
 	{} /* terminator */
 };
 
@@ -633,7 +637,9 @@
 		return -ENOMEM;
 
 	codec->spec = spec;
-	spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl);
+	spec->board_config = snd_hda_check_board_config(codec, CMI_MODELS,
+							cmi9880_models,
+							cmi9880_cfg_tbl);
 	if (spec->board_config < 0) {
 		snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n");
 		spec->board_config = CMI_AUTO; /* try everything */
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
new file mode 100644
index 0000000..73f4668
--- /dev/null
+++ b/sound/pci/hda/patch_conexant.c
@@ -0,0 +1,1311 @@
+/*
+ * HD audio interface patch for Conexant HDA audio codec
+ *
+ * Copyright (c) 2006 Pototskiy Akex <alex.pototskiy@gmail.com>
+ * 		      Takashi Iwai <tiwai@suse.de>
+ * 		      Tobin Davis  <tdavis@dsl-only.net>
+ *
+ *  This driver 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 driver is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+#define CXT_PIN_DIR_IN              0x00
+#define CXT_PIN_DIR_OUT             0x01
+#define CXT_PIN_DIR_INOUT           0x02
+#define CXT_PIN_DIR_IN_NOMICBIAS    0x03
+#define CXT_PIN_DIR_INOUT_NOMICBIAS 0x04
+
+#define CONEXANT_HP_EVENT	0x37
+#define CONEXANT_MIC_EVENT	0x38
+
+
+
+struct conexant_spec {
+
+	struct snd_kcontrol_new *mixers[5];
+	int num_mixers;
+
+	const struct hda_verb *init_verbs[5];	/* initialization verbs
+						 * don't forget NULL
+						 * termination!
+						 */
+	unsigned int num_init_verbs;
+
+	/* playback */
+	struct hda_multi_out multiout;	/* playback set-up
+					 * max_channels, dacs must be set
+					 * dig_out_nid and hp_nid are optional
+					 */
+	unsigned int cur_eapd;
+	unsigned int need_dac_fix;
+
+	/* capture */
+	unsigned int num_adc_nids;
+	hda_nid_t *adc_nids;
+	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
+
+	/* capture source */
+	const struct hda_input_mux *input_mux;
+	hda_nid_t *capsrc_nids;
+	unsigned int cur_mux[3];
+
+	/* channel model */
+	const struct hda_channel_mode *channel_mode;
+	int num_channel_mode;
+
+	/* PCM information */
+	struct hda_pcm pcm_rec[2];	/* used in build_pcms() */
+
+	struct mutex amp_mutex;	/* PCM volume/mute control mutex */
+	unsigned int spdif_route;
+
+	/* dynamic controls, init_verbs and input_mux */
+	struct auto_pin_cfg autocfg;
+	unsigned int num_kctl_alloc, num_kctl_used;
+	struct snd_kcontrol_new *kctl_alloc;
+	struct hda_input_mux private_imux;
+	hda_nid_t private_dac_nids[4];
+
+};
+
+static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      struct snd_pcm_substream *substream)
+{
+	struct conexant_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+}
+
+static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+					 struct hda_codec *codec,
+					 unsigned int stream_tag,
+					 unsigned int format,
+					 struct snd_pcm_substream *substream)
+{
+	struct conexant_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
+						stream_tag,
+						format, substream);
+}
+
+static int conexant_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+					 struct hda_codec *codec,
+					 struct snd_pcm_substream *substream)
+{
+	struct conexant_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+}
+
+/*
+ * Digital out
+ */
+static int conexant_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+					  struct hda_codec *codec,
+					  struct snd_pcm_substream *substream)
+{
+	struct conexant_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int conexant_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+					 struct hda_codec *codec,
+					 struct snd_pcm_substream *substream)
+{
+	struct conexant_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+/*
+ * Analog capture
+ */
+static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      unsigned int stream_tag,
+				      unsigned int format,
+				      struct snd_pcm_substream *substream)
+{
+	struct conexant_spec *spec = codec->spec;
+	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+				   stream_tag, 0, format);
+	return 0;
+}
+
+static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      struct snd_pcm_substream *substream)
+{
+	struct conexant_spec *spec = codec->spec;
+	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+				   0, 0, 0);
+	return 0;
+}
+
+
+
+static struct hda_pcm_stream conexant_pcm_analog_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0, /* fill later */
+	.ops = {
+		.open = conexant_playback_pcm_open,
+		.prepare = conexant_playback_pcm_prepare,
+		.cleanup = conexant_playback_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream conexant_pcm_analog_capture = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0, /* fill later */
+	.ops = {
+		.prepare = conexant_capture_pcm_prepare,
+		.cleanup = conexant_capture_pcm_cleanup
+	},
+};
+
+
+static struct hda_pcm_stream conexant_pcm_digital_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0, /* fill later */
+	.ops = {
+		.open = conexant_dig_playback_pcm_open,
+		.close = conexant_dig_playback_pcm_close
+	},
+};
+
+static struct hda_pcm_stream conexant_pcm_digital_capture = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in alc_build_pcms */
+};
+
+static int conexant_build_pcms(struct hda_codec *codec)
+{
+	struct conexant_spec *spec = codec->spec;
+	struct hda_pcm *info = spec->pcm_rec;
+
+	codec->num_pcms = 1;
+	codec->pcm_info = info;
+
+	info->name = "CONEXANT Analog";
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_analog_playback;
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
+		spec->multiout.max_channels;
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+		spec->multiout.dac_nids[0];
+	info->stream[SNDRV_PCM_STREAM_CAPTURE] = conexant_pcm_analog_capture;
+	info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
+	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
+
+	if (spec->multiout.dig_out_nid) {
+		info++;
+		codec->num_pcms++;
+		info->name = "Conexant Digital";
+		info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+			conexant_pcm_digital_playback;
+		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+			spec->multiout.dig_out_nid;
+		if (spec->dig_in_nid) {
+			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+				conexant_pcm_digital_capture;
+			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
+				spec->dig_in_nid;
+		}
+	}
+
+	return 0;
+}
+
+static int conexant_mux_enum_info(struct snd_kcontrol *kcontrol,
+	       			  struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+
+	return snd_hda_input_mux_info(spec->input_mux, uinfo);
+}
+
+static int conexant_mux_enum_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+	ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
+	return 0;
+}
+
+static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+	return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+				     spec->capsrc_nids[adc_idx],
+				     &spec->cur_mux[adc_idx]);
+}
+
+static int conexant_init(struct hda_codec *codec)
+{
+	struct conexant_spec *spec = codec->spec;
+	int i;
+
+	for (i = 0; i < spec->num_init_verbs; i++)
+		snd_hda_sequence_write(codec, spec->init_verbs[i]);
+	return 0;
+}
+
+static void conexant_free(struct hda_codec *codec)
+{
+        struct conexant_spec *spec = codec->spec;
+        unsigned int i;
+
+        if (spec->kctl_alloc) {
+                for (i = 0; i < spec->num_kctl_used; i++)
+                        kfree(spec->kctl_alloc[i].name);
+                kfree(spec->kctl_alloc);
+        }
+
+	kfree(codec->spec);
+}
+
+#ifdef CONFIG_PM
+static int conexant_resume(struct hda_codec *codec)
+{
+	struct conexant_spec *spec = codec->spec;
+	int i;
+
+	codec->patch_ops.init(codec);
+	for (i = 0; i < spec->num_mixers; i++)
+		snd_hda_resume_ctls(codec, spec->mixers[i]);
+	if (spec->multiout.dig_out_nid)
+		snd_hda_resume_spdif_out(codec);
+	if (spec->dig_in_nid)
+		snd_hda_resume_spdif_in(codec);
+	return 0;
+}
+#endif
+
+static int conexant_build_controls(struct hda_codec *codec)
+{
+	struct conexant_spec *spec = codec->spec;
+	unsigned int i;
+	int err;
+
+	for (i = 0; i < spec->num_mixers; i++) {
+		err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
+		if (err < 0)
+			return err;
+	}
+	if (spec->multiout.dig_out_nid) {
+		err = snd_hda_create_spdif_out_ctls(codec,
+						    spec->multiout.dig_out_nid);
+		if (err < 0)
+			return err;
+	} 
+	if (spec->dig_in_nid) {
+		err = snd_hda_create_spdif_in_ctls(codec,spec->dig_in_nid);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static struct hda_codec_ops conexant_patch_ops = {
+	.build_controls = conexant_build_controls,
+	.build_pcms = conexant_build_pcms,
+	.init = conexant_init,
+	.free = conexant_free,
+#ifdef CONFIG_PM
+	.resume = conexant_resume,
+#endif
+};
+
+/*
+ * EAPD control
+ * the private value = nid | (invert << 8)
+ */
+
+static int conexant_eapd_info(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_info *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 conexant_eapd_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+	int invert = (kcontrol->private_value >> 8) & 1;
+	if (invert)
+		ucontrol->value.integer.value[0] = !spec->cur_eapd;
+	else
+		ucontrol->value.integer.value[0] = spec->cur_eapd;
+	return 0;
+}
+
+static int conexant_eapd_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+	int invert = (kcontrol->private_value >> 8) & 1;
+	hda_nid_t nid = kcontrol->private_value & 0xff;
+	unsigned int eapd;
+	eapd = ucontrol->value.integer.value[0];
+	if (invert)
+		eapd = !eapd;
+	if (eapd == spec->cur_eapd && !codec->in_resume)
+		return 0;
+	spec->cur_eapd = eapd;
+	snd_hda_codec_write(codec, nid,
+			    0, AC_VERB_SET_EAPD_BTLENABLE,
+			    eapd ? 0x02 : 0x00);
+	return 1;
+}
+
+/* controls for test mode */
+#ifdef CONFIG_SND_DEBUG
+
+static int conexant_ch_mode_info(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+	return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
+				    spec->num_channel_mode);
+}
+
+static int conexant_ch_mode_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+	return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
+				   spec->num_channel_mode,
+				   spec->multiout.max_channels);
+}
+
+static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+	int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
+				      spec->num_channel_mode,
+				      &spec->multiout.max_channels);
+	if (err >= 0 && spec->need_dac_fix)
+		spec->multiout.num_dacs = spec->multiout.max_channels / 2;
+	return err;
+}
+
+#define CXT_PIN_MODE(xname, nid, dir) \
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+	  .info = conexant_ch_mode_info, \
+	  .get = conexant_ch_mode_get, \
+	  .put = conexant_ch_mode_put, \
+	  .private_value = nid | (dir<<16) }
+
+static int cxt_gpio_data_info(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_info *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 cxt_gpio_data_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value & 0xffff;
+	unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+	long *valp = ucontrol->value.integer.value;
+	unsigned int val = snd_hda_codec_read(codec, nid, 0,
+					      AC_VERB_GET_GPIO_DATA, 0x00);
+
+	*valp = (val & mask) != 0;
+	return 0;
+}
+
+static int cxt_gpio_data_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value & 0xffff;
+	unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+	long val = *ucontrol->value.integer.value;
+	unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
+						    AC_VERB_GET_GPIO_DATA,
+						    0x00);
+	unsigned int old_data = gpio_data;
+
+	/* Set/unset the masked GPIO bit(s) as needed */
+	if (val == 0)
+		gpio_data &= ~mask;
+	else
+		gpio_data |= mask;
+	if (gpio_data == old_data && !codec->in_resume)
+		return 0;
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_GPIO_DATA, gpio_data);
+	return 1;
+}
+
+#define CXT_GPIO_DATA_SWITCH(xname, nid, mask) \
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+	  .info = cxt_gpio_data_info, \
+	  .get = cxt_gpio_data_get, \
+	  .put = cxt_gpio_data_put, \
+	  .private_value = nid | (mask<<16) }
+
+static int cxt_spdif_ctrl_info(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_info *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 cxt_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value & 0xffff;
+	unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+	long *valp = ucontrol->value.integer.value;
+	unsigned int val = snd_hda_codec_read(codec, nid, 0,
+					      AC_VERB_GET_DIGI_CONVERT, 0x00);
+
+	*valp = (val & mask) != 0;
+	return 0;
+}
+
+static int cxt_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value & 0xffff;
+	unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+	long val = *ucontrol->value.integer.value;
+	unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
+						    AC_VERB_GET_DIGI_CONVERT,
+						    0x00);
+	unsigned int old_data = ctrl_data;
+
+	/* Set/unset the masked control bit(s) as needed */
+	if (val == 0)
+		ctrl_data &= ~mask;
+	else
+		ctrl_data |= mask;
+	if (ctrl_data == old_data && !codec->in_resume)
+		return 0;
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
+			    ctrl_data);
+	return 1;
+}
+
+#define CXT_SPDIF_CTRL_SWITCH(xname, nid, mask) \
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+	  .info = cxt_spdif_ctrl_info, \
+	  .get = cxt_spdif_ctrl_get, \
+	  .put = cxt_spdif_ctrl_put, \
+	  .private_value = nid | (mask<<16) }
+
+#endif /* CONFIG_SND_DEBUG */
+
+/* Conexant 5045 specific */
+
+static hda_nid_t cxt5045_dac_nids[1] = { 0x19 };
+static hda_nid_t cxt5045_adc_nids[1] = { 0x1a };
+static hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a };
+#define CXT5045_SPDIF_OUT	0x13
+
+static struct hda_channel_mode cxt5045_modes[1] = {
+	{ 2, NULL },
+};
+
+static struct hda_input_mux cxt5045_capture_source = {
+	.num_items = 2,
+	.items = {
+		{ "ExtMic", 0x1 },
+		{ "LineIn", 0x2 },
+	}
+};
+
+/* turn on/off EAPD (+ mute HP) as a master switch */
+static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+
+	if (!conexant_eapd_put(kcontrol, ucontrol))
+		return 0;
+
+	/* toggle HP mute appropriately */
+	snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0,
+				 0x80, spec->cur_eapd ? 0 : 0x80);
+	snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0,
+				 0x80, spec->cur_eapd ? 0 : 0x80);
+	return 1;
+}
+
+/* bind volumes of both NID 0x10 and 0x11 */
+static int cxt5045_hp_master_vol_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	long *valp = ucontrol->value.integer.value;
+	int change;
+
+	change = snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0,
+					  0x7f, valp[0] & 0x7f);
+	change |= snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0,
+					   0x7f, valp[1] & 0x7f);
+	snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0,
+				 0x7f, valp[0] & 0x7f);
+	snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0,
+				 0x7f, valp[1] & 0x7f);
+	return change;
+}
+
+
+/* mute internal speaker if HP is plugged */
+static void cxt5045_hp_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x11, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0,
+				 0x80, present ? 0x80 : 0);
+	snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0,
+				 0x80, present ? 0x80 : 0);
+}
+
+/* unsolicited event for HP jack sensing */
+static void cxt5045_hp_unsol_event(struct hda_codec *codec,
+				   unsigned int res)
+{
+	res >>= 26;
+	switch (res) {
+	case CONEXANT_HP_EVENT:
+		cxt5045_hp_automute(codec);
+		break;
+	}
+}
+
+static struct snd_kcontrol_new cxt5045_mixers[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.info = conexant_mux_enum_info,
+		.get = conexant_mux_enum_get,
+		.put = conexant_mux_enum_put
+	},
+	HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x17, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x17, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x02, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Volume",
+		.info = snd_hda_mixer_amp_volume_info,
+		.get = snd_hda_mixer_amp_volume_get,
+		.put = cxt5045_hp_master_vol_put,
+		.private_value = HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = conexant_eapd_info,
+		.get = conexant_eapd_get,
+		.put = cxt5045_hp_master_sw_put,
+		.private_value = 0x11,
+	},
+
+	{}
+};
+
+static struct hda_verb cxt5045_init_verbs[] = {
+	/* Line in, Mic */
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
+	/* HP, Amp  */
+	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{0x1A, AC_VERB_SET_CONNECT_SEL,0x01},
+	{0x1A, AC_VERB_SET_AMP_GAIN_MUTE,
+	 AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00},
+	{0x1A, AC_VERB_SET_AMP_GAIN_MUTE,
+	 AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03},
+	/* Record selector: Front mic */
+	{0x14, AC_VERB_SET_CONNECT_SEL,0x03},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE,
+	 AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
+	/* SPDIF route: PCM */
+	{ 0x13, AC_VERB_SET_CONNECT_SEL, 0x0 },
+	/* pin sensing on HP and Mic jacks */
+	{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
+	/* EAPD */
+	{0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */
+	{ } /* end */
+};
+
+#ifdef CONFIG_SND_DEBUG
+/* Test configuration for debugging, modelled after the ALC260 test
+ * configuration.
+ */
+static struct hda_input_mux cxt5045_test_capture_source = {
+	.num_items = 5,
+	.items = {
+		{ "MIXER", 0x0 },
+		{ "MIC1 pin", 0x1 },
+		{ "LINE1 pin", 0x2 },
+		{ "HP-OUT pin", 0x3 },
+		{ "CD pin", 0x4 },
+        },
+};
+
+static struct snd_kcontrol_new cxt5045_test_mixer[] = {
+
+	/* Output controls */
+	HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x19, 0x00, HDA_OUTPUT),
+	HDA_CODEC_MUTE("OutAmp-1 Switch", 0x19,0x00, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Speaker Playback Switch", 0x10, 0x0, HDA_OUTPUT),
+	
+	/* Modes for retasking pin widgets */
+	CXT_PIN_MODE("HP-OUT pin mode", 0x11, CXT_PIN_DIR_INOUT),
+	CXT_PIN_MODE("LINE1 pin mode", 0x12, CXT_PIN_DIR_INOUT),
+
+	/* Loopback mixer controls */
+	HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x17, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("MIC1 Playback Switch", 0x17, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("LINE loopback Playback Volume", 0x17, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("LINE loopback Playback Switch", 0x17, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x17, 0x03, HDA_INPUT),
+	HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x17, 0x03, HDA_INPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x17, 0x04, HDA_INPUT),
+
+	/* Controls for GPIO pins, assuming they exist and are configured as outputs */
+	CXT_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
+#if 0   /* limit this to one GPIO pin for now */	
+	CXT_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
+	CXT_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
+	CXT_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
+#endif
+	CXT_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x13, 0x01),
+
+	HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Input Source",
+		.info = conexant_mux_enum_info,
+		.get = conexant_mux_enum_get,
+		.put = conexant_mux_enum_put,
+	},
+
+	{ } /* end */
+};
+
+static struct hda_verb cxt5045_test_init_verbs[] = {
+	/* Enable all GPIOs as outputs with an initial value of 0 */
+	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
+	{0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+	{0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
+
+	/* Enable retasking pins as output, initially without power amp */
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+	/* Disable digital (SPDIF) pins initially, but users can enable
+	 * them via a mixer switch.  In the case of SPDIF-out, this initverb
+	 * payload also sets the generation to 0, output to be in "consumer"
+	 * PCM format, copyright asserted, no pre-emphasis and no validity
+	 * control.
+	 */
+	{0x13, AC_VERB_SET_DIGI_CONVERT_1, 0},
+
+	/* Start with output sum widgets muted and their output gains at min */
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+
+	/* Unmute retasking pin widget output buffers since the default
+	 * state appears to be output.  As the pin mode is changed by the
+	 * user the pin mode control will take care of enabling the pin's
+	 * input/output buffers as needed.
+	 */
+	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+	/* Mute capture amp left and right */
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+
+	/* Set ADC connection select to match default mixer setting (mic1
+	 * pin)
+	 */
+	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+	/* Mute all inputs to mixer widget (even unconnected ones) */
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Mixer pin */
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Mic1 pin */
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* Line pin */
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* HP pin */
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
+
+	{ }
+};
+#endif
+
+
+/* initialize jack-sensing, too */
+static int cxt5045_init(struct hda_codec *codec)
+{
+	conexant_init(codec);
+	cxt5045_hp_automute(codec);
+	return 0;
+}
+
+
+enum {
+	CXT5045_LAPTOP,	/* Laptops w/ EAPD support */
+#ifdef CONFIG_SND_DEBUG
+	CXT5045_TEST,
+#endif
+	CXT5045_MODELS
+};
+
+static const char *cxt5045_models[CXT5045_MODELS] = {
+	[CXT5045_LAPTOP]	= "laptop",
+#ifdef CONFIG_SND_DEBUG
+	[CXT5045_TEST]		= "test",
+#endif
+};
+
+static struct snd_pci_quirk cxt5045_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP),
+	{}
+};
+
+static int patch_cxt5045(struct hda_codec *codec)
+{
+	struct conexant_spec *spec;
+	int board_config;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (!spec)
+		return -ENOMEM;
+	mutex_init(&spec->amp_mutex);
+	codec->spec = spec;
+
+	spec->multiout.max_channels = 2;
+	spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids);
+	spec->multiout.dac_nids = cxt5045_dac_nids;
+	spec->multiout.dig_out_nid = CXT5045_SPDIF_OUT;
+	spec->num_adc_nids = 1;
+	spec->adc_nids = cxt5045_adc_nids;
+	spec->capsrc_nids = cxt5045_capsrc_nids;
+	spec->input_mux = &cxt5045_capture_source;
+	spec->num_mixers = 1;
+	spec->mixers[0] = cxt5045_mixers;
+	spec->num_init_verbs = 1;
+	spec->init_verbs[0] = cxt5045_init_verbs;
+	spec->spdif_route = 0;
+	spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes),
+	spec->channel_mode = cxt5045_modes,
+
+
+	codec->patch_ops = conexant_patch_ops;
+	codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
+
+	board_config = snd_hda_check_board_config(codec, CXT5045_MODELS,
+						  cxt5045_models,
+						  cxt5045_cfg_tbl);
+	switch (board_config) {
+	case CXT5045_LAPTOP:
+		spec->input_mux = &cxt5045_capture_source;
+		spec->num_init_verbs = 2;
+		spec->init_verbs[1] = cxt5045_init_verbs;
+		spec->mixers[0] = cxt5045_mixers;
+		codec->patch_ops.init = cxt5045_init;
+		break;
+#ifdef CONFIG_SND_DEBUG
+	case CXT5045_TEST:
+		spec->input_mux = &cxt5045_test_capture_source;
+		spec->mixers[0] = cxt5045_test_mixer;
+		spec->init_verbs[0] = cxt5045_test_init_verbs;
+#endif	
+	}
+	return 0;
+}
+
+
+/* Conexant 5047 specific */
+
+static hda_nid_t cxt5047_dac_nids[1] = { 0x10 };
+static hda_nid_t cxt5047_adc_nids[1] = { 0x12 };
+static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a };
+#define CXT5047_SPDIF_OUT	0x11
+
+static struct hda_channel_mode cxt5047_modes[1] = {
+	{ 2, NULL },
+};
+
+static struct hda_input_mux cxt5047_capture_source = {
+	.num_items = 2,
+	.items = {
+		{ "ExtMic", 0x1 },
+		{ "IntMic", 0x2 },
+	}
+};
+
+static struct hda_input_mux cxt5047_hp_capture_source = {
+	.num_items = 1,
+	.items = {
+		{ "ExtMic", 0x1 },
+	}
+};
+
+/* turn on/off EAPD (+ mute HP) as a master switch */
+static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+
+	if (!conexant_eapd_put(kcontrol, ucontrol))
+		return 0;
+
+	/* toggle HP mute appropriately */
+	snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0,
+				 0x80, spec->cur_eapd ? 0 : 0x80);
+	snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0,
+				 0x80, spec->cur_eapd ? 0 : 0x80);
+	return 1;
+}
+
+#if 0
+/* bind volumes of both NID 0x13 and 0x1d */
+static int cxt5047_hp_master_vol_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	long *valp = ucontrol->value.integer.value;
+	int change;
+
+	change = snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0,
+					  0x7f, valp[0] & 0x7f);
+	change |= snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0,
+					   0x7f, valp[1] & 0x7f);
+	snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0,
+				 0x7f, valp[0] & 0x7f);
+	snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0,
+				 0x7f, valp[1] & 0x7f);
+	return change;
+}
+#endif
+
+/* mute internal speaker if HP is plugged */
+static void cxt5047_hp_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x13, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0,
+				 0x80, present ? 0x80 : 0);
+	snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0,
+				 0x80, present ? 0x80 : 0);
+}
+
+/* toggle input of built-in and mic jack appropriately */
+static void cxt5047_hp_automic(struct hda_codec *codec)
+{
+	static struct hda_verb mic_jack_on[] = {
+		{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+		{0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+		{}
+	};
+	static struct hda_verb mic_jack_off[] = {
+		{0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+		{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+		{}
+	};
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x08, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	if (present)
+		snd_hda_sequence_write(codec, mic_jack_on);
+	else
+		snd_hda_sequence_write(codec, mic_jack_off);
+}
+
+/* unsolicited event for HP jack sensing */
+static void cxt5047_hp_unsol_event(struct hda_codec *codec,
+				  unsigned int res)
+{
+	res >>= 26;
+	switch (res) {
+	case CONEXANT_HP_EVENT:
+		cxt5047_hp_automute(codec);
+		break;
+	case CONEXANT_MIC_EVENT:
+		cxt5047_hp_automic(codec);
+		break;
+	}
+}
+
+static struct snd_kcontrol_new cxt5047_mixers[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.info = conexant_mux_enum_info,
+		.get = conexant_mux_enum_get,
+		.put = conexant_mux_enum_put
+	},
+	HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT),
+	HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT),
+	HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = conexant_eapd_info,
+		.get = conexant_eapd_get,
+		.put = cxt5047_hp_master_sw_put,
+		.private_value = 0x13,
+	},
+
+	{}
+};
+
+static struct snd_kcontrol_new cxt5047_hp_mixers[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.info = conexant_mux_enum_info,
+		.get = conexant_mux_enum_get,
+		.put = conexant_mux_enum_put
+	},
+	HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19,0x02,HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT),
+	HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT),
+	HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = conexant_eapd_info,
+		.get = conexant_eapd_get,
+		.put = cxt5047_hp_master_sw_put,
+		.private_value = 0x13,
+	},
+	{ } /* end */
+};
+
+static struct hda_verb cxt5047_init_verbs[] = {
+	/* Line in, Mic, Built-in Mic */
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
+	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
+	/* HP, Amp  */
+	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{0x1A, AC_VERB_SET_CONNECT_SEL,0x03},
+	{0x1A, AC_VERB_SET_AMP_GAIN_MUTE,
+	 AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00},
+	{0x1A, AC_VERB_SET_AMP_GAIN_MUTE,
+	 AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03},
+	/* Record selector: Front mic */
+	{0x12, AC_VERB_SET_CONNECT_SEL,0x03},
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE,
+	 AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
+	/* SPDIF route: PCM */
+	{ 0x18, AC_VERB_SET_CONNECT_SEL, 0x0 },
+	{ } /* end */
+};
+
+/* configuration for Toshiba Laptops */
+static struct hda_verb cxt5047_toshiba_init_verbs[] = {
+	{0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */
+	/* pin sensing on HP and Mic jacks */
+	{0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
+	{}
+};
+
+/* configuration for HP Laptops */
+static struct hda_verb cxt5047_hp_init_verbs[] = {
+	/* pin sensing on HP and Mic jacks */
+	{0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
+	{}
+};
+
+/* Test configuration for debugging, modelled after the ALC260 test
+ * configuration.
+ */
+#ifdef CONFIG_SND_DEBUG
+static struct hda_input_mux cxt5047_test_capture_source = {
+	.num_items = 5,
+	.items = {
+		{ "MIXER", 0x0 },
+		{ "LINE1 pin", 0x1 },
+		{ "MIC1 pin", 0x2 },
+		{ "MIC2 pin", 0x3 },
+		{ "CD pin", 0x4 },
+        },
+};
+
+static struct snd_kcontrol_new cxt5047_test_mixer[] = {
+
+	/* Output only controls */
+	HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x00, HDA_OUTPUT),
+	HDA_CODEC_MUTE("OutAmp-1 Switch", 0x10,0x00, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("OutAmp-2 Volume", 0x1c, 0x00, HDA_OUTPUT),
+	HDA_CODEC_MUTE("OutAmp-2 Switch", 0x1c, 0x00, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Speaker Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("HeadPhone Playback Volume", 0x13, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("HeadPhone Playback Switch", 0x13, 0x0, HDA_OUTPUT),
+
+	/* Modes for retasking pin widgets */
+	CXT_PIN_MODE("LINE1 pin mode", 0x14, CXT_PIN_DIR_INOUT),
+	CXT_PIN_MODE("MIC1 pin mode", 0x15, CXT_PIN_DIR_INOUT),
+
+	/* Loopback mixer controls */
+	HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x19, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("MIC1 Playback Switch", 0x19, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x19, 0x03, HDA_INPUT),
+	HDA_CODEC_MUTE("MIC2 Playback Switch", 0x19, 0x03, HDA_INPUT),
+	HDA_CODEC_VOLUME("LINE Playback Volume", 0x19, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("LINE Playback Switch", 0x19, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x19, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x19, 0x04, HDA_INPUT),
+
+#if 0   
+	/* Controls for GPIO pins, assuming they exist and are configured as outputs */
+	CXT_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
+	CXT_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
+	CXT_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
+	CXT_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
+#endif
+	CXT_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x18, 0x01),
+
+	HDA_CODEC_VOLUME("Capture Volume", 0x19, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x19, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Input Source",
+		.info = conexant_mux_enum_info,
+		.get = conexant_mux_enum_get,
+		.put = conexant_mux_enum_put,
+	},
+
+	{ } /* end */
+};
+
+static struct hda_verb cxt5047_test_init_verbs[] = {
+	/* Enable all GPIOs as outputs with an initial value of 0 */
+	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
+	{0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+	{0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
+
+	/* Enable retasking pins as output, initially without power amp */
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+	/* Disable digital (SPDIF) pins initially, but users can enable
+	 * them via a mixer switch.  In the case of SPDIF-out, this initverb
+	 * payload also sets the generation to 0, output to be in "consumer"
+	 * PCM format, copyright asserted, no pre-emphasis and no validity
+	 * control.
+	 */
+	{0x18, AC_VERB_SET_DIGI_CONVERT_1, 0},
+
+	/* Ensure mic1, mic2, line1 pin widgets take input from the 
+	 * OUT1 sum bus when acting as an output.
+	 */
+	{0x1a, AC_VERB_SET_CONNECT_SEL, 0},
+	{0x1b, AC_VERB_SET_CONNECT_SEL, 0},
+
+	/* Start with output sum widgets muted and their output gains at min */
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+
+	/* Unmute retasking pin widget output buffers since the default
+	 * state appears to be output.  As the pin mode is changed by the
+	 * user the pin mode control will take care of enabling the pin's
+	 * input/output buffers as needed.
+	 */
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+	/* Mute capture amp left and right */
+	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+
+	/* Set ADC connection select to match default mixer setting (mic1
+	 * pin)
+	 */
+	{0x12, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+	/* Mute all inputs to mixer widget (even unconnected ones) */
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
+
+	{ }
+};
+#endif
+
+
+/* initialize jack-sensing, too */
+static int cxt5047_hp_init(struct hda_codec *codec)
+{
+	conexant_init(codec);
+	cxt5047_hp_automute(codec);
+	cxt5047_hp_automic(codec);
+	return 0;
+}
+
+
+enum {
+	CXT5047_LAPTOP,		/* Laptops w/o EAPD support */
+	CXT5047_LAPTOP_HP,	/* Some HP laptops */
+	CXT5047_LAPTOP_EAPD,	/* Laptops with EAPD support */
+#ifdef CONFIG_SND_DEBUG
+	CXT5047_TEST,
+#endif
+	CXT5047_MODELS
+};
+
+static const char *cxt5047_models[CXT5047_MODELS] = {
+	[CXT5047_LAPTOP]	= "laptop",
+	[CXT5047_LAPTOP_HP]	= "laptop-hp",
+	[CXT5047_LAPTOP_EAPD]	= "laptop-eapd",
+#ifdef CONFIG_SND_DEBUG
+	[CXT5047_TEST]		= "test",
+#endif
+};
+
+static struct snd_pci_quirk cxt5047_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP),
+	SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP),
+	SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP),
+	SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD),
+	{}
+};
+
+static int patch_cxt5047(struct hda_codec *codec)
+{
+	struct conexant_spec *spec;
+	int board_config;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (!spec)
+		return -ENOMEM;
+	mutex_init(&spec->amp_mutex);
+	codec->spec = spec;
+
+	spec->multiout.max_channels = 2;
+	spec->multiout.num_dacs = ARRAY_SIZE(cxt5047_dac_nids);
+	spec->multiout.dac_nids = cxt5047_dac_nids;
+	spec->multiout.dig_out_nid = CXT5047_SPDIF_OUT;
+	spec->num_adc_nids = 1;
+	spec->adc_nids = cxt5047_adc_nids;
+	spec->capsrc_nids = cxt5047_capsrc_nids;
+	spec->input_mux = &cxt5047_capture_source;
+	spec->num_mixers = 1;
+	spec->mixers[0] = cxt5047_mixers;
+	spec->num_init_verbs = 1;
+	spec->init_verbs[0] = cxt5047_init_verbs;
+	spec->spdif_route = 0;
+	spec->num_channel_mode = ARRAY_SIZE(cxt5047_modes),
+	spec->channel_mode = cxt5047_modes,
+
+	codec->patch_ops = conexant_patch_ops;
+	codec->patch_ops.unsol_event = cxt5047_hp_unsol_event;
+
+	board_config = snd_hda_check_board_config(codec, CXT5047_MODELS,
+						  cxt5047_models,
+						  cxt5047_cfg_tbl);
+	switch (board_config) {
+	case CXT5047_LAPTOP:
+		break;
+	case CXT5047_LAPTOP_HP:
+		spec->input_mux = &cxt5047_hp_capture_source;
+		spec->num_init_verbs = 2;
+		spec->init_verbs[1] = cxt5047_hp_init_verbs;
+		spec->mixers[0] = cxt5047_hp_mixers;
+		codec->patch_ops.init = cxt5047_hp_init;
+		break;
+	case CXT5047_LAPTOP_EAPD:
+		spec->num_init_verbs = 2;
+		spec->init_verbs[1] = cxt5047_toshiba_init_verbs;
+		break;
+#ifdef CONFIG_SND_DEBUG
+	case CXT5047_TEST:
+		spec->input_mux = &cxt5047_test_capture_source;
+		spec->mixers[0] = cxt5047_test_mixer;
+		spec->init_verbs[0] = cxt5047_test_init_verbs;
+#endif	
+	}
+	return 0;
+}
+
+struct hda_codec_preset snd_hda_preset_conexant[] = {
+	{ .id = 0x14f15045, .name = "CXT5045", .patch = patch_cxt5045 },
+	{ .id = 0x14f15047, .name = "CXT5047", .patch = patch_cxt5047 },
+	{} /* terminator */
+};
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4e0c3c1..145682b 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -32,6 +32,10 @@
 #include "hda_codec.h"
 #include "hda_local.h"
 
+#define ALC880_FRONT_EVENT		0x01
+#define ALC880_DCVOL_EVENT		0x02
+#define ALC880_HP_EVENT			0x04
+#define ALC880_MIC_EVENT		0x08
 
 /* ALC880 board config type */
 enum {
@@ -48,7 +52,10 @@
 	ALC880_ASUS_DIG,
 	ALC880_ASUS_W1V,
 	ALC880_ASUS_DIG2,
+	ALC880_FUJITSU,
 	ALC880_UNIWILL_DIG,
+	ALC880_UNIWILL,
+	ALC880_UNIWILL_P53,
 	ALC880_CLEVO,
 	ALC880_TCL_S700,
 	ALC880_LG,
@@ -77,8 +84,12 @@
 /* ALC262 models */
 enum {
 	ALC262_BASIC,
+	ALC262_HIPPO,
+	ALC262_HIPPO_1,
 	ALC262_FUJITSU,
 	ALC262_HP_BPC,
+	ALC262_HP_BPC_D7000_WL,
+	ALC262_HP_BPC_D7000_WF,
 	ALC262_BENQ_ED8,
 	ALC262_AUTO,
 	ALC262_MODEL_LAST /* last tag */
@@ -91,16 +102,30 @@
 	ALC861_3ST_DIG,
 	ALC861_6ST_DIG,
 	ALC861_UNIWILL_M31,
+	ALC861_TOSHIBA,
+	ALC861_ASUS,
+	ALC861_ASUS_LAPTOP,
 	ALC861_AUTO,
 	ALC861_MODEL_LAST,
 };
 
+/* ALC861-VD models */
+enum {
+	ALC660VD_3ST,
+	ALC861VD_3ST,
+	ALC861VD_3ST_DIG,
+	ALC861VD_6ST_DIG,
+	ALC861VD_AUTO,
+	ALC861VD_MODEL_LAST,
+};
+
 /* ALC882 models */
 enum {
 	ALC882_3ST_DIG,
 	ALC882_6ST_DIG,
 	ALC882_ARIMA,
 	ALC882_AUTO,
+	ALC885_MACPRO,
 	ALC882_MODEL_LAST,
 };
 
@@ -110,8 +135,12 @@
 	ALC883_3ST_6ch_DIG,
 	ALC883_3ST_6ch,
 	ALC883_6ST_DIG,
+	ALC883_TARGA_DIG,
+	ALC883_TARGA_2ch_DIG,
 	ALC888_DEMO_BOARD,
 	ALC883_ACER,
+	ALC883_MEDION,
+	ALC883_LAPTOP_EAPD,
 	ALC883_AUTO,
 	ALC883_MODEL_LAST,
 };
@@ -1015,6 +1044,60 @@
 	{ } /* end */
 };
 
+/* Uniwill */
+static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
+	HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Channel Mode",
+		.info = alc_ch_mode_info,
+		.get = alc_ch_mode_get,
+		.put = alc_ch_mode_put,
+	},
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
+	HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	{ } /* end */
+};
+
 /*
  * build control elements
  */
@@ -1248,6 +1331,159 @@
 	{ }
 };
 
+/*
+ * Uniwill pin configuration:
+ * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
+ * line = 0x1a
+ */
+static struct hda_verb alc880_uniwill_init_verbs[] = {
+	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
+	/* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
+	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+
+	{ }
+};
+
+/*
+* Uniwill P53
+* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19, 
+ */
+static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
+	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
+
+	{ }
+};
+
+static struct hda_verb alc880_beep_init_verbs[] = {
+	{ 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
+	{ }
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc880_uniwill_automute(struct hda_codec *codec)
+{
+ 	unsigned int present;
+
+ 	present = snd_hda_codec_read(codec, 0x14, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
+				 0x80, present ? 0x80 : 0);
+	snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
+				 0x80, present ? 0x80 : 0);
+	snd_hda_codec_amp_update(codec, 0x16, 0, HDA_OUTPUT, 0,
+				 0x80, present ? 0x80 : 0);
+	snd_hda_codec_amp_update(codec, 0x16, 1, HDA_OUTPUT, 0,
+				 0x80, present ? 0x80 : 0);
+
+	present = snd_hda_codec_read(codec, 0x18, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_write(codec, 0x0b, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+			    0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
+}
+
+static void alc880_uniwill_unsol_event(struct hda_codec *codec,
+				       unsigned int res)
+{
+	/* Looks like the unsol event is incompatible with the standard
+	 * definition.  4bit tag is placed at 28 bit!
+	 */
+	if ((res >> 28) == ALC880_HP_EVENT ||
+	    (res >> 28) == ALC880_MIC_EVENT)
+		alc880_uniwill_automute(codec);
+}
+
+static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
+{
+ 	unsigned int present;
+
+ 	present = snd_hda_codec_read(codec, 0x14, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+
+	snd_hda_codec_amp_update(codec, 0x15, 0, HDA_INPUT, 0,
+				 0x80, present ? 0x80 : 0);
+	snd_hda_codec_amp_update(codec, 0x15, 1, HDA_INPUT, 0,
+				 0x80, present ? 0x80 : 0);
+}
+
+static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+	
+	present = snd_hda_codec_read(codec, 0x21, 0,
+				     AC_VERB_GET_VOLUME_KNOB_CONTROL, 0) & 0x7f;
+
+	snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0,
+				 0x7f, present);
+	snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0,
+				 0x7f,  present);
+
+	snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0,
+				 0x7f,  present);
+	snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0,
+				 0x7f, present);
+
+}
+static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
+					   unsigned int res)
+{
+	/* Looks like the unsol event is incompatible with the standard
+	 * definition.  4bit tag is placed at 28 bit!
+	 */
+	if ((res >> 28) == ALC880_HP_EVENT)
+		alc880_uniwill_p53_hp_automute(codec);
+	if ((res >> 28) == ALC880_DCVOL_EVENT) 
+		alc880_uniwill_p53_dcvol_automute(codec);
+}
+
 /* FIXME! */
 /*
  * F1734 pin configuration:
@@ -2125,159 +2361,112 @@
 /*
  */
 
-static struct hda_board_config alc880_cfg_tbl[] = {
-	/* Back 3 jack, front 2 jack */
-	{ .modelname = "3stack", .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe200, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe201, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe202, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe203, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe204, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe205, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe206, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe207, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe208, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe209, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe20a, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe20b, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe20c, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe20d, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe20e, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe212, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe213, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe234, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe306, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe307, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe404, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xa101, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x107b, .pci_subdevice = 0x3031, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x107b, .pci_subdevice = 0x4036, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x107b, .pci_subdevice = 0x4037, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x107b, .pci_subdevice = 0x4038, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST },
-	/* TCL S700 */
-	{ .modelname = "tcl", .config = ALC880_TCL_S700 },
-	{ .pci_subvendor = 0x19db, .pci_subdevice = 0x4188, .config = ALC880_TCL_S700 },
-
-	/* Back 3 jack, front 2 jack (Internal add Aux-In) */
-	{ .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST },
-	{ .pci_subvendor = 0x104d, .pci_subdevice = 0x81d6, .config = ALC880_3ST }, 
-	{ .pci_subvendor = 0x104d, .pci_subdevice = 0x81a0, .config = ALC880_3ST },
-
-	/* Back 3 jack plus 1 SPDIF out jack, front 2 jack */
-	{ .modelname = "3stack-digout", .config = ALC880_3ST_DIG },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG },
-	{ .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG },
-
-	/* Clevo laptops */
-	{ .modelname = "clevo", .config = ALC880_CLEVO },
-	{ .pci_subvendor = 0x1558, .pci_subdevice = 0x0520,
-	  .config = ALC880_CLEVO }, /* Clevo m520G NB */
-	{ .pci_subvendor = 0x1558, .pci_subdevice = 0x0660,
-	  .config = ALC880_CLEVO }, /* Clevo m665n */
-
-	/* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xd402, .config = ALC880_3ST_DIG },
-	{ .pci_subvendor = 0x1025, .pci_subdevice = 0xe309, .config = ALC880_3ST_DIG },
-
-	/* Back 5 jack, front 2 jack */
-	{ .modelname = "5stack", .config = ALC880_5ST },
-	{ .pci_subvendor = 0x107b, .pci_subdevice = 0x3033, .config = ALC880_5ST },
-	{ .pci_subvendor = 0x107b, .pci_subdevice = 0x4039, .config = ALC880_5ST },
-	{ .pci_subvendor = 0x107b, .pci_subdevice = 0x3032, .config = ALC880_5ST },
-	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x2a09, .config = ALC880_5ST },
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x814e, .config = ALC880_5ST },
-
-	/* Back 5 jack plus 1 SPDIF out jack, front 2 jack */
-	{ .modelname = "5stack-digout", .config = ALC880_5ST_DIG },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe224, .config = ALC880_5ST_DIG },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe400, .config = ALC880_5ST_DIG },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe401, .config = ALC880_5ST_DIG },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe402, .config = ALC880_5ST_DIG },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xd400, .config = ALC880_5ST_DIG },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xd401, .config = ALC880_5ST_DIG },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG },
-	{ .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG },
-	{ .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG },
-	{ .pci_subvendor = 0xa0a0, .pci_subdevice = 0x0560,
-	  .config = ALC880_5ST_DIG }, /* Aopen i915GMm-HFS */
-	/* { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, */ /* conflict with 6stack */
-	{ .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG },
-	/* note subvendor = 0 below */
-	/* { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG }, */
-
-	{ .modelname = "w810", .config = ALC880_W810 },
-	{ .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 },
-
-	{ .modelname = "z71v", .config = ALC880_Z71V },
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V },
-
-	{ .modelname = "6stack", .config = ALC880_6ST },
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x8196, .config = ALC880_6ST }, /* ASUS P5GD1-HVM */
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x81b4, .config = ALC880_6ST },
-	{ .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_6ST }, /* Acer APFV */
-	{ .pci_subvendor = 0x1458, .pci_subdevice = 0xa102, .config = ALC880_6ST }, /* Gigabyte K8N51 */
-
-	{ .modelname = "6stack-digout", .config = ALC880_6ST_DIG },
-	{ .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG },
-	{ .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG },
-	{ .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG },
-	{ .pci_subvendor = 0x1039, .pci_subdevice = 0x1234, .config = ALC880_6ST_DIG },
-	{ .pci_subvendor = 0x1025, .pci_subdevice = 0x0077, .config = ALC880_6ST_DIG },
-	{ .pci_subvendor = 0x1025, .pci_subdevice = 0x0078, .config = ALC880_6ST_DIG },
-	{ .pci_subvendor = 0x1025, .pci_subdevice = 0x0087, .config = ALC880_6ST_DIG },
-	{ .pci_subvendor = 0x1297, .pci_subdevice = 0xc790, .config = ALC880_6ST_DIG }, /* Shuttle ST20G5 */
-	{ .pci_subvendor = 0x1509, .pci_subdevice = 0x925d, .config = ALC880_6ST_DIG }, /* FIC P4M-915GD1 */
-	{ .pci_subvendor = 0x1695, .pci_subdevice = 0x4012, .config = ALC880_5ST_DIG }, /* Epox EP-5LDA+ GLi */
-
-	{ .modelname = "asus", .config = ALC880_ASUS },
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG },
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG },
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG },
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG },
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG },
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS },
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x10c2, .config = ALC880_ASUS_DIG }, /* Asus W6A */
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG },
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS },
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG },
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS },
-	{ .modelname = "asus-w1v", .config = ALC880_ASUS_W1V },
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V },
-	{ .modelname = "asus-dig", .config = ALC880_ASUS_DIG },
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x8181, .config = ALC880_ASUS_DIG }, /* ASUS P4GPL-X */
-	{ .modelname = "asus-dig2", .config = ALC880_ASUS_DIG2 },
-	{ .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 },
-
-	{ .modelname = "uniwill", .config = ALC880_UNIWILL_DIG },
-	{ .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG },	
-
-	{ .modelname = "F1734", .config = ALC880_F1734 },
-	{ .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 },
-	{ .pci_subvendor = 0x1584, .pci_subdevice = 0x9054, .config = ALC880_F1734 },
-
-	{ .modelname = "lg", .config = ALC880_LG },
-	{ .pci_subvendor = 0x1854, .pci_subdevice = 0x003b, .config = ALC880_LG },
-	{ .pci_subvendor = 0x1854, .pci_subdevice = 0x0068, .config = ALC880_LG },
-
-	{ .modelname = "lg-lw", .config = ALC880_LG_LW },
-	{ .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW },
-	{ .pci_subvendor = 0x1854, .pci_subdevice = 0x0077, .config = ALC880_LG_LW },
-
+static const char *alc880_models[ALC880_MODEL_LAST] = {
+	[ALC880_3ST]		= "3stack",
+	[ALC880_TCL_S700]	= "tcl",
+	[ALC880_3ST_DIG]	= "3stack-digout",
+	[ALC880_CLEVO]		= "clevo",
+	[ALC880_5ST]		= "5stack",
+	[ALC880_5ST_DIG]	= "5stack-digout",
+	[ALC880_W810]		= "w810",
+	[ALC880_Z71V]		= "z71v",
+	[ALC880_6ST]		= "6stack",
+	[ALC880_6ST_DIG]	= "6stack-digout",
+	[ALC880_ASUS]		= "asus",
+	[ALC880_ASUS_W1V]	= "asus-w1v",
+	[ALC880_ASUS_DIG]	= "asus-dig",
+	[ALC880_ASUS_DIG2]	= "asus-dig2",
+	[ALC880_UNIWILL_DIG]	= "uniwill",
+	[ALC880_UNIWILL_P53]	= "uniwill-p53",
+	[ALC880_FUJITSU]	= "fujitsu",
+	[ALC880_F1734]		= "F1734",
+	[ALC880_LG]		= "lg",
+	[ALC880_LG_LW]		= "lg-lw",
 #ifdef CONFIG_SND_DEBUG
-	{ .modelname = "test", .config = ALC880_TEST },
+	[ALC880_TEST]		= "test",
 #endif
-	{ .modelname = "auto", .config = ALC880_AUTO },
+	[ALC880_AUTO]		= "auto",
+};
+
+static struct snd_pci_quirk alc880_cfg_tbl[] = {
+	/* Broken BIOS configuration */
+	SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
+
+	SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
+	SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
+	SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
+	SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
+	SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
+	SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
+	SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
+	SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
+	SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
+
+	SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
+	SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
+
+	SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
+	SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
+	SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
+	SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
+	SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
+	SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
+	SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
+	/* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
+	SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
+	SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
+	SND_PCI_QUIRK(0x1043, 0x814e, "ASUS", ALC880_ASUS),
+	SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
+	SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
+	SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
+	SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS),
+
+	SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
+	SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
+	SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
+	SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
+	SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
+	SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
+	SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
+	SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
+	SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
+	SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
+	SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
+	SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
+	SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
+	SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
+	SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
+	SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
+	SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
+	SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
+
+	SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
+	SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
+	SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
+	SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
+
+	SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
+	SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
+	SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
+	SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
+
+	SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
+	SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
+	SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
+	SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
+
+	SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST),
 
 	{}
 };
@@ -2438,7 +2627,8 @@
 	},
 	[ALC880_UNIWILL_DIG] = {
 		.mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
-		.init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs },
+		.init_verbs = { alc880_volume_init_verbs,
+				alc880_pin_asus_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
 		.dac_nids = alc880_asus_dac_nids,
 		.dig_out_nid = ALC880_DIGOUT_NID,
@@ -2447,6 +2637,46 @@
 		.need_dac_fix = 1,
 		.input_mux = &alc880_capture_source,
 	},
+	[ALC880_UNIWILL] = {
+		.mixers = { alc880_uniwill_mixer },
+		.init_verbs = { alc880_volume_init_verbs,
+				alc880_uniwill_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
+		.dac_nids = alc880_asus_dac_nids,
+		.dig_out_nid = ALC880_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+		.channel_mode = alc880_threestack_modes,
+		.need_dac_fix = 1,
+		.input_mux = &alc880_capture_source,
+		.unsol_event = alc880_uniwill_unsol_event,
+		.init_hook = alc880_uniwill_automute,
+	},
+	[ALC880_UNIWILL_P53] = {
+		.mixers = { alc880_uniwill_p53_mixer },
+		.init_verbs = { alc880_volume_init_verbs,
+				alc880_uniwill_p53_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
+		.dac_nids = alc880_asus_dac_nids,
+		.num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
+		.channel_mode = alc880_threestack_modes,
+		.input_mux = &alc880_capture_source,
+		.unsol_event = alc880_uniwill_p53_unsol_event,
+		.init_hook = alc880_uniwill_p53_hp_automute,
+	},
+	[ALC880_FUJITSU] = {
+		.mixers = { alc880_fujitsu_mixer, 
+			    alc880_pcbeep_mixer, },
+		.init_verbs = { alc880_volume_init_verbs,
+				alc880_uniwill_p53_init_verbs,
+	       			alc880_beep_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc880_dac_nids),
+		.dac_nids = alc880_dac_nids,
+		.num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
+		.channel_mode = alc880_2_jack_modes,
+		.input_mux = &alc880_capture_source,
+		.unsol_event = alc880_uniwill_p53_unsol_event,
+		.init_hook = alc880_uniwill_p53_hp_automute,
+	},
 	[ALC880_CLEVO] = {
 		.mixers = { alc880_three_stack_mixer },
 		.init_verbs = { alc880_volume_init_verbs,
@@ -2841,8 +3071,10 @@
 
 	codec->spec = spec;
 
-	board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl);
-	if (board_config < 0 || board_config >= ALC880_MODEL_LAST) {
+	board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
+						  alc880_models,
+						  alc880_cfg_tbl);
+	if (board_config < 0) {
 		printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
 		       "trying auto-probe from BIOS...\n");
 		board_config = ALC880_AUTO;
@@ -3090,11 +3322,20 @@
  * and the output jack.  If this turns out to be the case for all such
  * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
  * to ALC_PIN_DIR_INOUT_NOMICBIAS.
+ *
+ * The C20x Tablet series have a mono internal speaker which is controlled
+ * via the chip's Mono sum widget and pin complex, so include the necessary
+ * controls for such models.  On models without a "mono speaker" the control
+ * won't do anything.
  */
 static struct snd_kcontrol_new alc260_acer_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
 	ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
+	HDA_CODEC_VOLUME_MONO("Mono Speaker Playback Volume", 0x0a, 1, 0x0,
+			      HDA_OUTPUT),
+	HDA_BIND_MUTE_MONO("Mono Speaker Playback Switch", 0x0a, 1, 2,
+			   HDA_INPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
@@ -3409,11 +3650,11 @@
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
 	/* Line In jack is connected to Line1 pin */
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	/* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
+	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	/* Ensure all other unused pins are disabled and muted. */
 	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
@@ -3441,6 +3682,8 @@
 
 	/* Unmute Line-out pin widget amp left and right (no equiv mixer ctrl) */
 	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	/* Unmute mono pin widget amp output (no equiv mixer ctrl) */
+	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	/* Unmute Mic1 and Line1 pin widget input buffers since they start as
 	 * inputs. If the pin mode is changed by the user the pin mode control
 	 * will take care of enabling the pin's input/output buffers as needed.
@@ -3928,33 +4171,33 @@
 /*
  * ALC260 configurations
  */
-static struct hda_board_config alc260_cfg_tbl[] = {
-	{ .modelname = "basic", .config = ALC260_BASIC },
-	{ .pci_subvendor = 0x104d, .pci_subdevice = 0x81bb,
-	  .config = ALC260_BASIC }, /* Sony VAIO */
-	{ .pci_subvendor = 0x104d, .pci_subdevice = 0x81cc,
-	  .config = ALC260_BASIC }, /* Sony VAIO VGN-S3HP */
-	{ .pci_subvendor = 0x104d, .pci_subdevice = 0x81cd,
-	  .config = ALC260_BASIC }, /* Sony VAIO */
-	{ .pci_subvendor = 0x152d, .pci_subdevice = 0x0729,
-	  .config = ALC260_BASIC }, /* CTL Travel Master U553W */
-	{ .modelname = "hp", .config = ALC260_HP },
-	{ .modelname = "hp-3013", .config = ALC260_HP_3013 },
-	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP_3013 },
-	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP },
-	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP_3013 },
-	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 },
-	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, .config = ALC260_HP },
-	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3015, .config = ALC260_HP },
-	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3016, .config = ALC260_HP },
-	{ .modelname = "fujitsu", .config = ALC260_FUJITSU_S702X },
-	{ .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702X },
-	{ .modelname = "acer", .config = ALC260_ACER },
-	{ .pci_subvendor = 0x1025, .pci_subdevice = 0x008f, .config = ALC260_ACER },
+static const char *alc260_models[ALC260_MODEL_LAST] = {
+	[ALC260_BASIC]		= "basic",
+	[ALC260_HP]		= "hp",
+	[ALC260_HP_3013]	= "hp-3013",
+	[ALC260_FUJITSU_S702X]	= "fujitsu",
+	[ALC260_ACER]		= "acer",
 #ifdef CONFIG_SND_DEBUG
-	{ .modelname = "test", .config = ALC260_TEST },
+	[ALC260_TEST]		= "test",
 #endif
-	{ .modelname = "auto", .config = ALC260_AUTO },
+	[ALC260_AUTO]		= "auto",
+};
+
+static struct snd_pci_quirk alc260_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
+	SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
+	SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
+	SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP),
+	SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013),
+	SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
+	SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
+	SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
+	SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
+	SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
+	SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
+	SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
+	SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
+	SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
 	{}
 };
 
@@ -4053,8 +4296,10 @@
 
 	codec->spec = spec;
 
-	board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl);
-	if (board_config < 0 || board_config >= ALC260_MODEL_LAST) {
+	board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
+						  alc260_models,
+						  alc260_cfg_tbl);
+	if (board_config < 0) {
 		snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
 			   "trying auto-probe from BIOS...\n");
 		board_config = ALC260_AUTO;
@@ -4207,8 +4452,10 @@
 	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
 	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
 	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
@@ -4313,6 +4560,100 @@
 	{ } 
 };
 
+/* Mac Pro test */
+static struct snd_kcontrol_new alc882_macpro_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
+	{ } /* end */
+};
+
+static struct hda_verb alc882_macpro_init_verbs[] = {
+	/* Front mixer: unmute input/output amp left and right (volume = 0) */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	/* Front Pin: output 0 (0x0c) */
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+	/* Front Mic pin: input vref at 80% */
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Speaker:  output */
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
+	/* Headphone output (output 0 - 0x0c) */
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+	/* FIXME: use matrix-type input source selection */
+	/* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+	/* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+	/* Input mixer2 */
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+	/* Input mixer3 */
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+	/* ADC1: mute amp left and right */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+	/* ADC2: mute amp left and right */
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+	/* ADC3: mute amp left and right */
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+	{ }
+};
+static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
+{
+	unsigned int gpiostate, gpiomask, gpiodir;
+
+	gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
+				       AC_VERB_GET_GPIO_DATA, 0);
+
+	if (!muted)
+		gpiostate |= (1 << pin);
+	else
+		gpiostate &= ~(1 << pin);
+
+	gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
+				      AC_VERB_GET_GPIO_MASK, 0);
+	gpiomask |= (1 << pin);
+
+	gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
+				     AC_VERB_GET_GPIO_DIRECTION, 0);
+	gpiodir |= (1 << pin);
+
+
+	snd_hda_codec_write(codec, codec->afg, 0,
+			    AC_VERB_SET_GPIO_MASK, gpiomask);
+	snd_hda_codec_write(codec, codec->afg, 0,
+			    AC_VERB_SET_GPIO_DIRECTION, gpiodir);
+
+	msleep(1);
+
+	snd_hda_codec_write(codec, codec->afg, 0,
+			    AC_VERB_SET_GPIO_DATA, gpiostate);
+}
+
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
@@ -4435,19 +4776,20 @@
 /*
  * configuration and preset
  */
-static struct hda_board_config alc882_cfg_tbl[] = {
-	{ .modelname = "3stack-dig", .config = ALC882_3ST_DIG },
-	{ .modelname = "6stack-dig", .config = ALC882_6ST_DIG },
-	{ .pci_subvendor = 0x1462, .pci_subdevice = 0x6668,
-	  .config = ALC882_6ST_DIG }, /* MSI  */
-	{ .pci_subvendor = 0x105b, .pci_subdevice = 0x6668,
-	  .config = ALC882_6ST_DIG }, /* Foxconn */
-	{ .pci_subvendor = 0x1019, .pci_subdevice = 0x6668,
-	  .config = ALC882_6ST_DIG }, /* ECS to Intel*/
-	{ .modelname = "arima", .config = ALC882_ARIMA },
-	{ .pci_subvendor = 0x161f, .pci_subdevice = 0x2054,
-	  .config = ALC882_ARIMA }, /* Arima W820Di1 */
-	{ .modelname = "auto", .config = ALC882_AUTO },
+static const char *alc882_models[ALC882_MODEL_LAST] = {
+	[ALC882_3ST_DIG]	= "3stack-dig",
+	[ALC882_6ST_DIG]	= "6stack-dig",
+	[ALC882_ARIMA]		= "arima",
+	[ALC885_MACPRO]		= "macpro",
+	[ALC882_AUTO]		= "auto",
+};
+
+static struct snd_pci_quirk alc882_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
+	SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
+	SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
+	SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
+	SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
 	{}
 };
 
@@ -4484,6 +4826,17 @@
 		.channel_mode = alc882_sixstack_modes,
 		.input_mux = &alc882_capture_source,
 	},
+	[ALC885_MACPRO] = {
+		.mixers = { alc882_macpro_mixer },
+		.init_verbs = { alc882_macpro_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc882_dac_nids),
+		.dac_nids = alc882_dac_nids,
+		.dig_out_nid = ALC882_DIGOUT_NID,
+		.dig_in_nid = ALC882_DIGIN_NID,
+		.num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+		.channel_mode = alc882_ch_modes,
+		.input_mux = &alc882_capture_source,
+	},
 };
 
 
@@ -4584,7 +4937,9 @@
 
 	codec->spec = spec;
 
-	board_config = snd_hda_check_board_config(codec, alc882_cfg_tbl);
+	board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
+						  alc882_models,
+						  alc882_cfg_tbl);
 
 	if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
 		printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
@@ -4609,6 +4964,11 @@
 	if (board_config != ALC882_AUTO)
 		setup_preset(spec, &alc882_presets[board_config]);
 
+	if (board_config == ALC885_MACPRO) {
+		alc882_gpio_mute(codec, 0, 0);
+		alc882_gpio_mute(codec, 1, 0);
+	}
+
 	spec->stream_name_analog = "ALC882 Analog";
 	spec->stream_analog_playback = &alc882_pcm_analog_playback;
 	spec->stream_analog_capture = &alc882_pcm_analog_capture;
@@ -4767,6 +5127,13 @@
 	{ 8, alc883_sixstack_ch8_init },
 };
 
+static struct hda_verb alc883_medion_eapd_verbs[] = {
+        /* eanable EAPD on medion laptop */
+	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+	{0x20, AC_VERB_SET_PROC_COEF, 0x3070},
+	{ }
+};
+
 /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
  *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
  */
@@ -4788,8 +5155,10 @@
 	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
 	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
 	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
@@ -4818,8 +5187,10 @@
 	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
 	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
 	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
@@ -4854,8 +5225,10 @@
 	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
 	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
 	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
@@ -4875,6 +5248,101 @@
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 1,
+		.info = alc883_mux_enum_info,
+		.get = alc883_mux_enum_get,
+		.put = alc883_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new alc883_tagra_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = alc883_mux_enum_info,
+		.get = alc883_mux_enum_get,
+		.put = alc883_mux_enum_put,
+	},
+	{ } /* end */
+};	
+
+static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = alc883_mux_enum_info,
+		.get = alc883_mux_enum_get,
+		.put = alc883_mux_enum_put,
+	},
+	{ } /* end */
+};	
+
 static struct snd_kcontrol_new alc883_chmode_mixer[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -4963,6 +5431,45 @@
 	{ }
 };
 
+static struct hda_verb alc883_tagra_verbs[] = {
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	
+	{0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
+	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
+	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+
+	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+	{0x01, AC_VERB_SET_GPIO_MASK, 0x03}, 
+	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03}, 
+	{0x01, AC_VERB_SET_GPIO_DATA, 0x03}, 
+
+	{ } /* end */
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc883_tagra_automute(struct hda_codec *codec)
+{
+ 	unsigned int present;
+
+ 	present = snd_hda_codec_read(codec, 0x14, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0,
+				 0x80, present ? 0x80 : 0);
+	snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
+				 0x80, present ? 0x80 : 0);
+	snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA, present ? 1 : 3);
+}
+
+static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+	if ((res >> 26) == ALC880_HP_EVENT)
+		alc883_tagra_automute(codec);
+}
+
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
@@ -5057,32 +5564,42 @@
 /*
  * configuration and preset
  */
-static struct hda_board_config alc883_cfg_tbl[] = {
-	{ .modelname = "3stack-dig", .config = ALC883_3ST_2ch_DIG },
-	{ .modelname = "3stack-6ch-dig", .config = ALC883_3ST_6ch_DIG },
-	{ .pci_subvendor = 0x1019, .pci_subdevice = 0x6668,
-	  .config = ALC883_3ST_6ch_DIG }, /* ECS to Intel*/
-	{ .modelname = "3stack-6ch", .config = ALC883_3ST_6ch },
-	{ .pci_subvendor = 0x108e, .pci_subdevice = 0x534d,
-	  .config = ALC883_3ST_6ch },
-        { .pci_subvendor = 0x8086, .pci_subdevice = 0xd601,
-          .config = ALC883_3ST_6ch }, /* D102GGC */
-	{ .modelname = "6stack-dig", .config = ALC883_6ST_DIG },
-	{ .pci_subvendor = 0x1462, .pci_subdevice = 0x6668,
-	  .config = ALC883_6ST_DIG }, /* MSI  */
-	{ .pci_subvendor = 0x1462, .pci_subdevice = 0x7280,
-	  .config = ALC883_6ST_DIG }, /* MSI K9A Platinum (MS-7280) */
-	{ .pci_subvendor = 0x105b, .pci_subdevice = 0x6668,
-	  .config = ALC883_6ST_DIG }, /* Foxconn */
-	{ .modelname = "6stack-dig-demo", .config = ALC888_DEMO_BOARD },
-	{ .modelname = "acer", .config = ALC883_ACER },
-	{ .pci_subvendor = 0x1025, .pci_subdevice = 0/*0x0102*/,
-	  .config = ALC883_ACER },
-	{ .pci_subvendor = 0x1025, .pci_subdevice = 0x0102,
-	  .config = ALC883_ACER },
-	{ .pci_subvendor = 0x1025, .pci_subdevice = 0x009f,
-	  .config = ALC883_ACER },
-	{ .modelname = "auto", .config = ALC883_AUTO },
+static const char *alc883_models[ALC883_MODEL_LAST] = {
+	[ALC883_3ST_2ch_DIG]	= "3stack-dig",
+	[ALC883_3ST_6ch_DIG]	= "3stack-6ch-dig",
+	[ALC883_3ST_6ch]	= "3stack-6ch",
+	[ALC883_6ST_DIG]	= "6stack-dig",
+	[ALC883_TARGA_DIG]	= "targa-dig",
+	[ALC883_TARGA_2ch_DIG]	= "targa-2ch-dig",
+	[ALC888_DEMO_BOARD]	= "6stack-dig-demo",
+	[ALC883_ACER]		= "acer",
+	[ALC883_MEDION]		= "medion",
+	[ALC883_LAPTOP_EAPD]	= "laptop-eapd",
+	[ALC883_AUTO]		= "auto",
+};
+
+static struct snd_pci_quirk alc883_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
+	SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
+	SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
+	SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
+	SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
+	SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
+	SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
+	SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
+	SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
+	SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
+	SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
+	SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
+	SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
+	SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
+	SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
+	SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
+	SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER),
+	SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
+	SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
 	{}
 };
 
@@ -5139,6 +5656,35 @@
 		.channel_mode = alc883_sixstack_modes,
 		.input_mux = &alc883_capture_source,
 	},
+	[ALC883_TARGA_DIG] = {
+		.mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
+		.init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
+		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
+		.dac_nids = alc883_dac_nids,
+		.dig_out_nid = ALC883_DIGOUT_NID,
+		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+		.adc_nids = alc883_adc_nids,
+		.num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+		.channel_mode = alc883_3ST_6ch_modes,
+		.need_dac_fix = 1,
+		.input_mux = &alc883_capture_source,
+		.unsol_event = alc883_tagra_unsol_event,
+		.init_hook = alc883_tagra_automute,
+	},
+	[ALC883_TARGA_2ch_DIG] = {
+		.mixers = { alc883_tagra_2ch_mixer},
+		.init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
+		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
+		.dac_nids = alc883_dac_nids,
+		.dig_out_nid = ALC883_DIGOUT_NID,
+		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+		.adc_nids = alc883_adc_nids,
+		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+		.channel_mode = alc883_3ST_2ch_modes,
+		.input_mux = &alc883_capture_source,
+		.unsol_event = alc883_tagra_unsol_event,
+		.init_hook = alc883_tagra_automute,
+	},
 	[ALC888_DEMO_BOARD] = {
 		.mixers = { alc883_base_mixer, alc883_chmode_mixer },
 		.init_verbs = { alc883_init_verbs },
@@ -5169,6 +5715,31 @@
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
 	},
+	[ALC883_MEDION] = {
+		.mixers = { alc883_fivestack_mixer,
+			    alc883_chmode_mixer },
+		.init_verbs = { alc883_init_verbs,
+				alc883_medion_eapd_verbs },
+		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
+		.dac_nids = alc883_dac_nids,
+		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+		.adc_nids = alc883_adc_nids,
+		.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+		.channel_mode = alc883_sixstack_modes,
+		.input_mux = &alc883_capture_source,
+	},
+	[ALC883_LAPTOP_EAPD] = {
+		.mixers = { alc883_base_mixer,
+			    alc883_chmode_mixer },
+		.init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
+		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
+		.dac_nids = alc883_dac_nids,
+		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+		.adc_nids = alc883_adc_nids,
+		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+		.channel_mode = alc883_3ST_2ch_modes,
+		.input_mux = &alc883_capture_source,
+	},
 };
 
 
@@ -5277,8 +5848,10 @@
 
 	codec->spec = spec;
 
-	board_config = snd_hda_check_board_config(codec, alc883_cfg_tbl);
-	if (board_config < 0 || board_config >= ALC883_MODEL_LAST) {
+	board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
+						  alc883_models,
+						  alc883_cfg_tbl);
+	if (board_config < 0) {
 		printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
 		       "trying auto-probe from BIOS...\n");
 		board_config = ALC883_AUTO;
@@ -5355,6 +5928,24 @@
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+	/* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
+	   HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */
+	/*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+	{ } /* end */
+};
+
 static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -5377,6 +5968,30 @@
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
+	HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	{ } /* end */
+};
+
 #define alc262_capture_mixer		alc882_capture_mixer
 #define alc262_capture_alt_mixer	alc882_capture_alt_mixer
 
@@ -5459,6 +6074,103 @@
 	{ }
 };
 
+static struct hda_verb alc262_hippo_unsol_verbs[] = {
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{}
+};
+
+static struct hda_verb alc262_hippo1_unsol_verbs[] = {
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
+	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+
+	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{}
+};
+
+/* mute/unmute internal speaker according to the hp jack and mute state */
+static void alc262_hippo_automute(struct hda_codec *codec, int force)
+{
+	struct alc_spec *spec = codec->spec;
+	unsigned int mute;
+
+	if (force || ! spec->sense_updated) {
+		unsigned int present;
+		/* need to execute and sync at first */
+		snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
+		present = snd_hda_codec_read(codec, 0x15, 0,
+				    	 AC_VERB_GET_PIN_SENSE, 0);
+		spec->jack_present = (present & 0x80000000) != 0;
+		spec->sense_updated = 1;
+	}
+	if (spec->jack_present) {
+		/* mute internal speaker */
+		snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
+					 0x80, 0x80);
+		snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
+					 0x80, 0x80);
+	} else {
+		/* unmute internal speaker if necessary */
+		mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
+		snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
+					 0x80, mute & 0x80);
+		mute = snd_hda_codec_amp_read(codec, 0x15, 1, HDA_OUTPUT, 0);
+		snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
+					 0x80, mute & 0x80);
+	}
+}
+
+/* unsolicited event for HP jack sensing */
+static void alc262_hippo_unsol_event(struct hda_codec *codec,
+				       unsigned int res)
+{
+	if ((res >> 26) != ALC880_HP_EVENT)
+		return;
+	alc262_hippo_automute(codec, 1);
+}
+
+static void alc262_hippo1_automute(struct hda_codec *codec, int force)
+{
+	struct alc_spec *spec = codec->spec;
+	unsigned int mute;
+
+	if (force || ! spec->sense_updated) {
+		unsigned int present;
+		/* need to execute and sync at first */
+		snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
+		present = snd_hda_codec_read(codec, 0x1b, 0,
+				    	 AC_VERB_GET_PIN_SENSE, 0);
+		spec->jack_present = (present & 0x80000000) != 0;
+		spec->sense_updated = 1;
+	}
+	if (spec->jack_present) {
+		/* mute internal speaker */
+		snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
+					 0x80, 0x80);
+		snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
+					 0x80, 0x80);
+	} else {
+		/* unmute internal speaker if necessary */
+		mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
+		snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
+					 0x80, mute & 0x80);
+		mute = snd_hda_codec_amp_read(codec, 0x1b, 1, HDA_OUTPUT, 0);
+		snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
+					 0x80, mute & 0x80);
+	}
+}
+
+/* unsolicited event for HP jack sensing */
+static void alc262_hippo1_unsol_event(struct hda_codec *codec,
+				       unsigned int res)
+{
+	if ((res >> 26) != ALC880_HP_EVENT)
+		return;
+	alc262_hippo1_automute(codec, 1);
+}
+
 /*
  * fujitsu model
  *  0x14 = headphone/spdif-out, 0x15 = internal speaker
@@ -5809,6 +6521,100 @@
 	{ }
 };
 
+static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
+	/*
+	 * Unmute ADC0-2 and set the default input to mic-in
+	 */
+	{0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+	 * mixer widget
+	 * Note: PASD motherboards uses the Line In 2 as the input for front
+	 * panel mic (mic 2)
+	 */
+	/* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)},
+	/*
+	 * Set up output mixers (0x0c - 0x0e)
+	 */
+	/* set vol=0 to output mixers */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+	/* set up input amps for analog loopback */
+	/* Amp Indices: DAC = 0, mixer = 1 */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },	/* HP */
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },	/* Mono */
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },	/* rear MIC */
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },	/* Line in */
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },	/* Front MIC */
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },	/* Line out */
+	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },	/* CD in */
+
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+
+	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+
+	/* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
+	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+
+	/* FIXME: use matrix-type input source selection */
+	/* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+	/* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
+        /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))},  */
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
+	/* Input mixer2 */
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+        /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
+	/* Input mixer3 */
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+        /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
+
+	{ }
+};
+
 /* pcm configuration: identiacal with ALC880 */
 #define alc262_pcm_analog_playback	alc880_pcm_analog_playback
 #define alc262_pcm_analog_capture	alc880_pcm_analog_capture
@@ -5866,26 +6672,35 @@
 /*
  * configuration and preset
  */
-static struct hda_board_config alc262_cfg_tbl[] = {
-	{ .modelname = "basic", .config = ALC262_BASIC },
-	{ .modelname = "fujitsu", .config = ALC262_FUJITSU },
-	{ .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397,
-	  .config = ALC262_FUJITSU },
-	{ .modelname = "hp-bpc", .config = ALC262_HP_BPC },
-	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x280c,
-	  .config = ALC262_HP_BPC }, /* xw4400 */
-	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x2801,
-	  .config = ALC262_HP_BPC }, /* q965 */
-	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3014,
-	  .config = ALC262_HP_BPC }, /* xw6400 */
-	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3015,
-	  .config = ALC262_HP_BPC }, /* xw8400 */
-	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x12fe,
-	  .config = ALC262_HP_BPC }, /* xw9400 */
-	{ .modelname = "benq", .config = ALC262_BENQ_ED8 },
-	{ .pci_subvendor = 0x17ff, .pci_subdevice = 0x0560,
-	  .config = ALC262_BENQ_ED8 },
-	{ .modelname = "auto", .config = ALC262_AUTO },
+static const char *alc262_models[ALC262_MODEL_LAST] = {
+	[ALC262_BASIC]		= "basic",
+	[ALC262_HIPPO]		= "hippo",
+	[ALC262_HIPPO_1]	= "hippo_1",
+	[ALC262_FUJITSU]	= "fujitsu",
+	[ALC262_HP_BPC]		= "hp-bpc",
+	[ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
+	[ALC262_BENQ_ED8]	= "benq",
+	[ALC262_AUTO]		= "auto",
+};
+
+static struct snd_pci_quirk alc262_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
+	SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
+	SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
+	SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
+	SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
+	SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
+	SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
+	SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
+	SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
+	SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
+	SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
+	SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
+	SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
+	SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
+	SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
+	SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
+	SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
 	{}
 };
 
@@ -5900,6 +6715,30 @@
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
 	},
+	[ALC262_HIPPO] = {
+		.mixers = { alc262_base_mixer },
+		.init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
+		.num_dacs = ARRAY_SIZE(alc262_dac_nids),
+		.dac_nids = alc262_dac_nids,
+		.hp_nid = 0x03,
+		.dig_out_nid = ALC262_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc262_modes),
+		.channel_mode = alc262_modes,
+		.input_mux = &alc262_capture_source,
+		.unsol_event = alc262_hippo_unsol_event,
+	},
+	[ALC262_HIPPO_1] = {
+		.mixers = { alc262_hippo1_mixer },
+		.init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
+		.num_dacs = ARRAY_SIZE(alc262_dac_nids),
+		.dac_nids = alc262_dac_nids,
+		.hp_nid = 0x02,
+		.dig_out_nid = ALC262_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc262_modes),
+		.channel_mode = alc262_modes,
+		.input_mux = &alc262_capture_source,
+		.unsol_event = alc262_hippo1_unsol_event,
+	},
 	[ALC262_FUJITSU] = {
 		.mixers = { alc262_fujitsu_mixer },
 		.init_verbs = { alc262_init_verbs, alc262_fujitsu_unsol_verbs },
@@ -5922,6 +6761,27 @@
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_HP_capture_source,
 	},	
+	[ALC262_HP_BPC_D7000_WF] = {
+		.mixers = { alc262_HP_BPC_WildWest_mixer },
+		.init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc262_dac_nids),
+		.dac_nids = alc262_dac_nids,
+		.hp_nid = 0x03,
+		.num_channel_mode = ARRAY_SIZE(alc262_modes),
+		.channel_mode = alc262_modes,
+		.input_mux = &alc262_HP_capture_source,
+	},	
+	[ALC262_HP_BPC_D7000_WL] = {
+		.mixers = { alc262_HP_BPC_WildWest_mixer,
+			    alc262_HP_BPC_WildWest_option_mixer },
+		.init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc262_dac_nids),
+		.dac_nids = alc262_dac_nids,
+		.hp_nid = 0x03,
+		.num_channel_mode = ARRAY_SIZE(alc262_modes),
+		.channel_mode = alc262_modes,
+		.input_mux = &alc262_HP_capture_source,
+	},	
 	[ALC262_BENQ_ED8] = {
 		.mixers = { alc262_base_mixer },
 		.init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
@@ -5940,7 +6800,7 @@
 	int board_config;
 	int err;
 
-	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
 		return -ENOMEM;
 
@@ -5956,9 +6816,11 @@
 	}
 #endif
 
-	board_config = snd_hda_check_board_config(codec, alc262_cfg_tbl);
-	
-	if (board_config < 0 || board_config >= ALC262_MODEL_LAST) {
+	board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
+						  alc262_models,
+						  alc262_cfg_tbl);
+
+	if (board_config < 0) {
 		printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
 		       "trying auto-probe from BIOS...\n");
 		board_config = ALC262_AUTO;
@@ -6078,6 +6940,44 @@
 	{ 4, alc861_uniwill_m31_ch4_init },
 };
 
+/* Set mic1 and line-in as input and unmute the mixer */
+static struct hda_verb alc861_asus_ch2_init[] = {
+	/* set pin widget 1Ah (line in) for input */
+	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+	/* set pin widget 18h (mic1/2) for input, for mic also enable the vref */
+	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+
+	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
+#if 0
+	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
+	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
+#endif
+	{ } /* end */
+};
+/* Set mic1 nad line-in as output and mute mixer */
+static struct hda_verb alc861_asus_ch6_init[] = {
+	/* set pin widget 1Ah (line in) for output (Back Surround)*/
+	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	/* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
+	/* set pin widget 18h (mic1) for output (CLFE)*/
+	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	/* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
+	{ 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
+	{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
+
+	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
+#if 0
+	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
+	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
+#endif
+	{ } /* end */
+};
+
+static struct hda_channel_mode alc861_asus_modes[2] = {
+	{ 2, alc861_asus_ch2_init },
+	{ 6, alc861_asus_ch6_init },
+};
+
 /* patch-ALC861 */
 
 static struct snd_kcontrol_new alc861_base_mixer[] = {
@@ -6154,7 +7054,29 @@
                 .private_value = ARRAY_SIZE(alc861_threestack_modes),
 	},
 	{ } /* end */
-};			
+};
+
+static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
+        /* output mixer control */
+	HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
+	
+        /*Capture mixer control */
+	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.count = 1,
+		.info = alc_mux_enum_info,
+		.get = alc_mux_enum_get,
+		.put = alc_mux_enum_put,
+	},
+
+	{ } /* end */
+};	
+
 static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
         /* output mixer control */
 	HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
@@ -6196,7 +7118,58 @@
 	},
 	{ } /* end */
 };			
-	
+
+static struct snd_kcontrol_new alc861_asus_mixer[] = {
+        /* output mixer control */
+	HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
+
+	/* Input mixer control */
+	HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT), /* was HDA_INPUT (why?) */
+ 
+	/* Capture mixer control */
+	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.count = 1,
+		.info = alc_mux_enum_info,
+		.get = alc_mux_enum_get,
+		.put = alc_mux_enum_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Channel Mode",
+		.info = alc_ch_mode_info,
+		.get = alc_ch_mode_get,
+		.put = alc_ch_mode_put,
+                .private_value = ARRAY_SIZE(alc861_asus_modes),
+	},
+	{ }
+};
+
+/* additional mixer */
+static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
+	{ }
+};
+
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
@@ -6217,7 +7190,7 @@
 	/* port-E for HP out (front panel) */
 	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
 	/* route front PCM to HP */
-	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 },
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
 	/* port-F for mic-in (front panel) with vref */
 	{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
 	/* port-G for CLFE (rear panel) */
@@ -6281,7 +7254,7 @@
 	/* port-E for HP out (front panel) */
 	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
 	/* route front PCM to HP */
-	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 },
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
 	/* port-F for mic-in (front panel) with vref */
 	{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
 	/* port-G for CLFE (rear panel) */
@@ -6341,7 +7314,7 @@
 	/* port-E for HP out (front panel) */
 	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, // this has to be set to VREF80
 	/* route front PCM to HP */
-	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 },
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
 	/* port-F for mic-in (front panel) with vref */
 	{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
 	/* port-G for CLFE (rear panel) */
@@ -6385,6 +7358,74 @@
 	{ }
 };
 
+static struct hda_verb alc861_asus_init_verbs[] = {
+	/*
+	 * Unmute ADC0 and set the default input to mic-in
+	 */
+	/* port-A for surround (rear panel) | according to codec#0 this is the HP jack*/
+	{ 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
+	/* route front PCM to HP */
+	{ 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
+	/* port-B for mic-in (rear panel) with vref */
+	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+	/* port-C for line-in (rear panel) */
+	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+	/* port-D for Front */
+	{ 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	{ 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
+	/* port-E for HP out (front panel) */
+	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, /* this has to be set to VREF80 */
+	/* route front PCM to HP */
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+	/* port-F for mic-in (front panel) with vref */
+	{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+	/* port-G for CLFE (rear panel) */
+	{ 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	/* port-H for side (rear panel) */
+	{ 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	/* CD-in */
+	{ 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+	/* route front mic to ADC1*/
+	{0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	/* Unmute DAC0~3 & spdif out*/
+	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	/* Unmute Mixer 14 (mic) 1c (Line in)*/
+	{0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+        {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+        {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	
+	/* Unmute Stereo Mixer 15 */
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c          }, /* Output 0~12 step */
+
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, /* hp used DAC 3 (Front) */
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+	{ }
+};
+
+/* additional init verbs for ASUS laptops */
+static struct hda_verb alc861_asus_laptop_init_verbs[] = {
+	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
+	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
+	{ }
+};
+
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
@@ -6437,6 +7478,39 @@
 	{ }
 };
 
+static struct hda_verb alc861_toshiba_init_verbs[] = {
+	{0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+        
+	{ }
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc861_toshiba_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x0f, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_amp_update(codec, 0x16, 0, HDA_INPUT, 0,
+				 0x80, present ? 0x80 : 0);
+	snd_hda_codec_amp_update(codec, 0x16, 1, HDA_INPUT, 0,
+				 0x80, present ? 0x80 : 0);
+	snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_INPUT, 3,
+				 0x80, present ? 0 : 0x80);
+	snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_INPUT, 3,
+				 0x80, present ? 0 : 0x80);
+}
+
+static void alc861_toshiba_unsol_event(struct hda_codec *codec,
+				       unsigned int res)
+{
+	/* Looks like the unsol event is incompatible with the standard
+	 * definition.  6bit tag is placed at 26 bit!
+	 */
+	if ((res >> 26) == ALC880_HP_EVENT)
+		alc861_toshiba_automute(codec);
+}
+
 /* pcm configuration: identiacal with ALC880 */
 #define alc861_pcm_analog_playback	alc880_pcm_analog_playback
 #define alc861_pcm_analog_capture	alc880_pcm_analog_capture
@@ -6710,19 +7784,29 @@
 /*
  * configuration and preset
  */
-static struct hda_board_config alc861_cfg_tbl[] = {
-	{ .modelname = "3stack", .config = ALC861_3ST },
-	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xd600,
-	  .config = ALC861_3ST },
-	{ .modelname = "3stack-660", .config = ALC660_3ST },
-	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x81e7,
-	  .config = ALC660_3ST },
-	{ .modelname = "3stack-dig", .config = ALC861_3ST_DIG },
-	{ .modelname = "6stack-dig", .config = ALC861_6ST_DIG },
-	{ .modelname = "uniwill-m31", .config = ALC861_UNIWILL_M31},
-	{ .pci_subvendor = 0x1584, .pci_subdevice = 0x9072,
-	  .config = ALC861_UNIWILL_M31 },
-	{ .modelname = "auto", .config = ALC861_AUTO },
+static const char *alc861_models[ALC861_MODEL_LAST] = {
+	[ALC861_3ST]		= "3stack",
+	[ALC660_3ST]		= "3stack-660",
+	[ALC861_3ST_DIG]	= "3stack-dig",
+	[ALC861_6ST_DIG]	= "6stack-dig",
+	[ALC861_UNIWILL_M31]	= "uniwill-m31",
+	[ALC861_TOSHIBA]	= "toshiba",
+	[ALC861_ASUS]		= "asus",
+	[ALC861_ASUS_LAPTOP]	= "asus-laptop",
+	[ALC861_AUTO]		= "auto",
+};
+
+static struct snd_pci_quirk alc861_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
+	SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
+	SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
+	SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
+	SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660_3ST),
+	SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
+	SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA),
+	SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
+	SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
+	SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
 	{}
 };
 
@@ -6789,8 +7873,48 @@
 		.adc_nids = alc861_adc_nids,
 		.input_mux = &alc861_capture_source,
 	},
-
-};	
+	[ALC861_TOSHIBA] = {
+		.mixers = { alc861_toshiba_mixer },
+		.init_verbs = { alc861_base_init_verbs, alc861_toshiba_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc861_dac_nids),
+		.dac_nids = alc861_dac_nids,
+		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+		.channel_mode = alc883_3ST_2ch_modes,
+		.num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+		.adc_nids = alc861_adc_nids,
+		.input_mux = &alc861_capture_source,
+		.unsol_event = alc861_toshiba_unsol_event,
+		.init_hook = alc861_toshiba_automute,
+	},
+	[ALC861_ASUS] = {
+		.mixers = { alc861_asus_mixer },
+		.init_verbs = { alc861_asus_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc861_dac_nids),
+		.dac_nids = alc861_dac_nids,
+		.dig_out_nid = ALC861_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
+		.channel_mode = alc861_asus_modes,
+		.need_dac_fix = 1,
+		.hp_nid = 0x06,
+		.num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+		.adc_nids = alc861_adc_nids,
+		.input_mux = &alc861_capture_source,
+	},
+	[ALC861_ASUS_LAPTOP] = {
+		.mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
+		.init_verbs = { alc861_asus_init_verbs,
+				alc861_asus_laptop_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc861_dac_nids),
+		.dac_nids = alc861_dac_nids,
+		.dig_out_nid = ALC861_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+		.channel_mode = alc883_3ST_2ch_modes,
+		.need_dac_fix = 1,
+		.num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+		.adc_nids = alc861_adc_nids,
+		.input_mux = &alc861_capture_source,
+	},
+};
 
 
 static int patch_alc861(struct hda_codec *codec)
@@ -6799,15 +7923,17 @@
 	int board_config;
 	int err;
 
-	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
 		return -ENOMEM;
 
 	codec->spec = spec;	
 
-        board_config = snd_hda_check_board_config(codec, alc861_cfg_tbl);
+        board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
+						  alc861_models,
+						  alc861_cfg_tbl);
 
-	if (board_config < 0 || board_config >= ALC861_MODEL_LAST) {
+	if (board_config < 0) {
 		printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
 		       "trying auto-probe from BIOS...\n");
 		board_config = ALC861_AUTO;
@@ -6846,19 +7972,706 @@
 }
 
 /*
+ * ALC861-VD support
+ *
+ * Based on ALC882
+ *
+ * In addition, an independent DAC
+ */
+#define ALC861VD_DIGOUT_NID	0x06
+
+static hda_nid_t alc861vd_dac_nids[4] = {
+	/* front, surr, clfe, side surr */
+	0x02, 0x03, 0x04, 0x05
+};
+
+/* dac_nids for ALC660vd are in a different order - according to
+ * Realtek's driver.
+ * This should probably tesult in a different mixer for 6stack models
+ * of ALC660vd codecs, but for now there is only 3stack mixer
+ * - and it is the same as in 861vd.
+ * adc_nids in ALC660vd are (is) the same as in 861vd
+ */
+static hda_nid_t alc660vd_dac_nids[3] = {
+	/* front, rear, clfe, rear_surr */
+	0x02, 0x04, 0x03
+};
+
+static hda_nid_t alc861vd_adc_nids[1] = {
+	/* ADC0 */
+	0x09,
+};
+
+/* input MUX */
+/* FIXME: should be a matrix-type input source selection */
+static struct hda_input_mux alc861vd_capture_source = {
+	.num_items = 4,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "Front Mic", 0x1 },
+		{ "Line", 0x2 },
+		{ "CD", 0x4 },
+	},
+};
+
+#define alc861vd_mux_enum_info alc_mux_enum_info
+#define alc861vd_mux_enum_get alc_mux_enum_get
+
+static int alc861vd_mux_enum_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	const struct hda_input_mux *imux = spec->input_mux;
+	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	static hda_nid_t capture_mixers[1] = { 0x22 };
+	hda_nid_t nid = capture_mixers[adc_idx];
+	unsigned int *cur_val = &spec->cur_mux[adc_idx];
+	unsigned int i, idx;
+
+	idx = ucontrol->value.enumerated.item[0];
+	if (idx >= imux->num_items)
+		idx = imux->num_items - 1;
+	if (*cur_val == idx && ! codec->in_resume)
+		return 0;
+	for (i = 0; i < imux->num_items; i++) {
+		unsigned int v = (i == idx) ? 0x7000 : 0x7080;
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+				    v | (imux->items[i].index << 8));
+	}
+	*cur_val = idx;
+	return 1;
+}
+
+/*
+ * 2ch mode
+ */
+static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
+	{ 2, NULL }
+};
+
+/*
+ * 6ch mode
+ */
+static struct hda_verb alc861vd_6stack_ch6_init[] = {
+	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
+	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{ } /* end */
+};
+
+/*
+ * 8ch mode
+ */
+static struct hda_verb alc861vd_6stack_ch8_init[] = {
+	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{ } /* end */
+};
+
+static struct hda_channel_mode alc861vd_6stack_modes[2] = {
+	{ 6, alc861vd_6stack_ch6_init },
+	{ 8, alc861vd_6stack_ch8_init },
+};
+
+static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Channel Mode",
+		.info = alc_ch_mode_info,
+		.get = alc_ch_mode_get,
+		.put = alc_ch_mode_put,
+	},
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new alc861vd_capture_mixer[] = {
+	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
+
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 *FIXME: the controls appear in the "playback" view!
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 1,
+		.info = alc861vd_mux_enum_info,
+		.get = alc861vd_mux_enum_get,
+		.put = alc861vd_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
+ *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
+ */
+static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
+				HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
+				HDA_OUTPUT),
+	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+
+	{ } /* end */
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb alc861vd_volume_init_verbs[] = {
+	/*
+	 * Unmute ADC0 and set the default input to mic-in
+	 */
+	{0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
+	 * the analog-loopback mixer widget
+	 */
+	/* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+	/* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(8)},
+
+	/*
+	 * Set up output mixers (0x02 - 0x05)
+	 */
+	/* set vol=0 to output mixers */
+	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+	/* set up input amps for analog loopback */
+	/* Amp Indices: DAC = 0, mixer = 1 */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+
+	{ }
+};
+
+/*
+ * 3-stack pin configuration:
+ * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
+ */
+static struct hda_verb alc861vd_3stack_init_verbs[] = {
+	/*
+	 * Set pin mode and muting
+	 */
+	/* set front pin widgets 0x14 for output */
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+	/* Mic (rear) pin: input vref at 80% */
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Front Mic pin: input vref at 80% */
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Line In pin: input */
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Line-2 In: Headphone output (output 0 - 0x0c) */
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+	/* CD pin widget for input */
+	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+	{ }
+};
+
+/*
+ * 6-stack pin configuration:
+ */
+static struct hda_verb alc861vd_6stack_init_verbs[] = {
+	/*
+	 * Set pin mode and muting
+	 */
+	/* set front pin widgets 0x14 for output */
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+	/* Rear Pin: output 1 (0x0d) */
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+	/* CLFE Pin: output 2 (0x0e) */
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
+	/* Side Pin: output 3 (0x0f) */
+	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+
+	/* Mic (rear) pin: input vref at 80% */
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Front Mic pin: input vref at 80% */
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Line In pin: input */
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Line-2 In: Headphone output (output 0 - 0x0c) */
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+	/* CD pin widget for input */
+	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+	{ }
+};
+
+/* pcm configuration: identiacal with ALC880 */
+#define alc861vd_pcm_analog_playback	alc880_pcm_analog_playback
+#define alc861vd_pcm_analog_capture	alc880_pcm_analog_capture
+#define alc861vd_pcm_digital_playback	alc880_pcm_digital_playback
+#define alc861vd_pcm_digital_capture	alc880_pcm_digital_capture
+
+/*
+ * configuration and preset
+ */
+static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
+	[ALC660VD_3ST]		= "3stack-660",
+	[ALC861VD_3ST]		= "3stack",
+	[ALC861VD_3ST_DIG]	= "3stack-digout",
+	[ALC861VD_6ST_DIG]	= "6stack-digout",
+	[ALC861VD_AUTO]		= "auto",
+};
+
+static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
+	SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
+	SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
+
+	SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_3ST),
+	{}
+};
+
+static struct alc_config_preset alc861vd_presets[] = {
+	[ALC660VD_3ST] = {
+		.mixers = { alc861vd_3st_mixer },
+		.init_verbs = { alc861vd_volume_init_verbs,
+				 alc861vd_3stack_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
+		.dac_nids = alc660vd_dac_nids,
+		.num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
+		.adc_nids = alc861vd_adc_nids,
+		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+		.channel_mode = alc861vd_3stack_2ch_modes,
+		.input_mux = &alc861vd_capture_source,
+	},
+	[ALC861VD_3ST] = {
+		.mixers = { alc861vd_3st_mixer },
+		.init_verbs = { alc861vd_volume_init_verbs,
+				 alc861vd_3stack_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
+		.dac_nids = alc861vd_dac_nids,
+		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+		.channel_mode = alc861vd_3stack_2ch_modes,
+		.input_mux = &alc861vd_capture_source,
+	},
+	[ALC861VD_3ST_DIG] = {
+		.mixers = { alc861vd_3st_mixer },
+		.init_verbs = { alc861vd_volume_init_verbs,
+		 		 alc861vd_3stack_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
+		.dac_nids = alc861vd_dac_nids,
+		.dig_out_nid = ALC861VD_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+		.channel_mode = alc861vd_3stack_2ch_modes,
+		.input_mux = &alc861vd_capture_source,
+	},
+	[ALC861VD_6ST_DIG] = {
+		.mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
+		.init_verbs = { alc861vd_volume_init_verbs,
+				alc861vd_6stack_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
+		.dac_nids = alc861vd_dac_nids,
+		.dig_out_nid = ALC861VD_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
+		.channel_mode = alc861vd_6stack_modes,
+		.input_mux = &alc861vd_capture_source,
+	},
+};
+
+/*
+ * BIOS auto configuration
+ */
+static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
+				hda_nid_t nid, int pin_type, int dac_idx)
+{
+	/* set as output */
+	snd_hda_codec_write(codec, nid, 0,
+				AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
+	snd_hda_codec_write(codec, nid, 0,
+				AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+}
+
+static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	int i;
+
+	for (i = 0; i <= HDA_SIDE; i++) {
+		hda_nid_t nid = spec->autocfg.line_out_pins[i];
+		if (nid)
+			alc861vd_auto_set_output_and_unmute(codec, nid,
+								PIN_OUT, i);
+	}
+}
+
+
+static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	hda_nid_t pin;
+
+	pin = spec->autocfg.hp_pins[0];
+	if (pin) /* connect to front and  use dac 0 */
+		alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+}
+
+#define alc861vd_is_input_pin(nid)	alc880_is_input_pin(nid)
+#define ALC861VD_PIN_CD_NID		ALC880_PIN_CD_NID
+
+static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	int i;
+
+	for (i = 0; i < AUTO_PIN_LAST; i++) {
+		hda_nid_t nid = spec->autocfg.input_pins[i];
+		if (alc861vd_is_input_pin(nid)) {
+			snd_hda_codec_write(codec, nid, 0,
+					AC_VERB_SET_PIN_WIDGET_CONTROL,
+					i <= AUTO_PIN_FRONT_MIC ?
+							PIN_VREF80 : PIN_IN);
+			if (nid != ALC861VD_PIN_CD_NID)
+				snd_hda_codec_write(codec, nid, 0,
+						AC_VERB_SET_AMP_GAIN_MUTE,
+						AMP_OUT_MUTE);
+		}
+	}
+}
+
+#define alc861vd_idx_to_mixer_vol(nid)		((nid) + 0x02)
+#define alc861vd_idx_to_mixer_switch(nid)	((nid) + 0x0c)
+
+/* add playback controls from the parsed DAC table */
+/* Based on ALC880 version. But ALC861VD has separate,
+ * different NIDs for mute/unmute switch and volume control */
+static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
+					     const struct auto_pin_cfg *cfg)
+{
+	char name[32];
+	static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
+	hda_nid_t nid_v, nid_s;
+	int i, err;
+
+	for (i = 0; i < cfg->line_outs; i++) {
+		if (! spec->multiout.dac_nids[i])
+			continue;
+		nid_v = alc861vd_idx_to_mixer_vol(
+				alc880_dac_to_idx(
+					spec->multiout.dac_nids[i]));
+		nid_s = alc861vd_idx_to_mixer_switch(
+				alc880_dac_to_idx(
+					spec->multiout.dac_nids[i]));
+
+		if (i == 2) {
+			/* Center/LFE */
+			if ((err = add_control(spec, ALC_CTL_WIDGET_VOL,
+						"Center Playback Volume",
+						HDA_COMPOSE_AMP_VAL(nid_v, 1,
+							0, HDA_OUTPUT))) < 0)
+				return err;
+			if ((err = add_control(spec, ALC_CTL_WIDGET_VOL,
+						"LFE Playback Volume",
+						HDA_COMPOSE_AMP_VAL(nid_v, 2,
+							0, HDA_OUTPUT))) < 0)
+				return err;
+			if ((err = add_control(spec, ALC_CTL_BIND_MUTE,
+						"Center Playback Switch",
+						HDA_COMPOSE_AMP_VAL(nid_s, 1,
+						2, HDA_INPUT))) < 0)
+				return err;
+			if ((err = add_control(spec, ALC_CTL_BIND_MUTE,
+						"LFE Playback Switch",
+						HDA_COMPOSE_AMP_VAL(nid_s, 2,
+						2, HDA_INPUT))) < 0)
+				return err;
+		} else {
+			sprintf(name, "%s Playback Volume", chname[i]);
+			if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+						HDA_COMPOSE_AMP_VAL(nid_v, 3,
+							0, HDA_OUTPUT))) < 0)
+				return err;
+			sprintf(name, "%s Playback Switch", chname[i]);
+			if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name,
+						HDA_COMPOSE_AMP_VAL(nid_v, 3,
+							2, HDA_INPUT))) < 0)
+				return err;
+		}
+	}
+	return 0;
+}
+
+/* add playback controls for speaker and HP outputs */
+/* Based on ALC880 version. But ALC861VD has separate,
+ * different NIDs for mute/unmute switch and volume control */
+static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
+					hda_nid_t pin, const char *pfx)
+{
+	hda_nid_t nid_v, nid_s;
+	int err;
+	char name[32];
+
+	if (! pin)
+		return 0;
+
+	if (alc880_is_fixed_pin(pin)) {
+		nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
+		/* specify the DAC as the extra output */
+		if (! spec->multiout.hp_nid)
+			spec->multiout.hp_nid = nid_v;
+		else
+			spec->multiout.extra_out_nid[0] = nid_v;
+		/* control HP volume/switch on the output mixer amp */
+		nid_v = alc861vd_idx_to_mixer_vol(
+				alc880_fixed_pin_idx(pin));
+		nid_s = alc861vd_idx_to_mixer_switch(
+				alc880_fixed_pin_idx(pin));
+
+		sprintf(name, "%s Playback Volume", pfx);
+		if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+				HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
+							HDA_OUTPUT))) < 0)
+			return err;
+		sprintf(name, "%s Playback Switch", pfx);
+		if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name,
+				HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
+							HDA_INPUT))) < 0)
+			return err;
+	} else if (alc880_is_multi_pin(pin)) {
+		/* set manual connection */
+		/* we have only a switch on HP-out PIN */
+		sprintf(name, "%s Playback Switch", pfx);
+		if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+				HDA_COMPOSE_AMP_VAL(pin, 3, 0,
+							HDA_OUTPUT))) < 0)
+			return err;
+	}
+	return 0;
+}
+
+/* parse the BIOS configuration and set up the alc_spec
+ * return 1 if successful, 0 if the proper config is not found,
+ * or a negative error code
+ * Based on ALC880 version - had to change it to override
+ * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
+static int alc861vd_parse_auto_config(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	int err;
+	static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
+
+	if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
+						alc861vd_ignore)) < 0)
+		return err;
+	if (! spec->autocfg.line_outs)
+		return 0; /* can't find valid BIOS pin config */
+
+	if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
+		(err = alc861vd_auto_create_multi_out_ctls(spec,
+			&spec->autocfg)) < 0 ||
+		(err = alc861vd_auto_create_extra_out(spec,
+			spec->autocfg.speaker_pins[0], "Speaker")) < 0 ||
+		(err = alc861vd_auto_create_extra_out(spec,
+			spec->autocfg.hp_pins[0], "Headphone")) < 0 ||
+		(err = alc880_auto_create_analog_input_ctls(spec,
+			&spec->autocfg)) < 0)
+		return err;
+
+	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+	if (spec->autocfg.dig_out_pin)
+		spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
+
+	if (spec->kctl_alloc)
+		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+	spec->init_verbs[spec->num_init_verbs++]
+		= alc861vd_volume_init_verbs;
+
+	spec->num_mux_defs = 1;
+	spec->input_mux = &spec->private_imux;
+
+	return 1;
+}
+
+/* additional initialization for auto-configuration model */
+static void alc861vd_auto_init(struct hda_codec *codec)
+{
+	alc861vd_auto_init_multi_out(codec);
+	alc861vd_auto_init_hp_out(codec);
+	alc861vd_auto_init_analog_input(codec);
+}
+
+static int patch_alc861vd(struct hda_codec *codec)
+{
+	struct alc_spec *spec;
+	int err, board_config;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
+						  alc861vd_models,
+						  alc861vd_cfg_tbl);
+
+	if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
+		printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
+			"ALC861VD, trying auto-probe from BIOS...\n");
+		board_config = ALC861VD_AUTO;
+	}
+
+	if (board_config == ALC861VD_AUTO) {
+		/* automatic parse from the BIOS config */
+		err = alc861vd_parse_auto_config(codec);
+		if (err < 0) {
+			alc_free(codec);
+			return err;
+		} else if (! err) {
+			printk(KERN_INFO
+			       "hda_codec: Cannot set up configuration "
+			       "from BIOS.  Using base mode...\n");
+			board_config = ALC861VD_3ST;
+		}
+	}
+
+	if (board_config != ALC861VD_AUTO)
+		setup_preset(spec, &alc861vd_presets[board_config]);
+
+	spec->stream_name_analog = "ALC861VD Analog";
+	spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
+	spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
+
+	spec->stream_name_digital = "ALC861VD Digital";
+	spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
+	spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
+
+	spec->adc_nids = alc861vd_adc_nids;
+	spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
+
+	spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
+	spec->num_mixers++;
+
+	codec->patch_ops = alc_patch_ops;
+
+	if (board_config == ALC861VD_AUTO)
+		spec->init_hook = alc861vd_auto_init;
+
+	return 0;
+}
+
+/*
  * patch entries
  */
 struct hda_codec_preset snd_hda_preset_realtek[] = {
 	{ .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
 	{ .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
- 	{ .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
+	{ .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
+		.patch = patch_alc861 },
+	{ .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
+	{ .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
+	{ .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
+	{ .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
 	{ .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
 	{ .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
 	{ .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
 	{ .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
-	{ .id = 0x10ec0861, .rev = 0x100300, .name = "ALC861",
-	  .patch = patch_alc861 },
-        { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
-	  .patch = patch_alc861 },
 	{} /* terminator */
 };
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index fe51ef3..6f4a392 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -37,14 +37,37 @@
 #define NUM_CONTROL_ALLOC	32
 #define STAC_HP_EVENT		0x37
 
-#define STAC_REF		0
-#define STAC_D945GTP3		1
-#define STAC_D945GTP5		2
-#define STAC_MACMINI		3
-#define STAC_922X_MODELS	4	/* number of 922x models */
-#define STAC_D965_3ST		4
-#define STAC_D965_5ST		5
-#define STAC_927X_MODELS	6	/* number of 922x models */
+enum {
+	STAC_REF,
+	STAC_9200_MODELS
+};
+
+enum {
+	STAC_9205_REF,
+	STAC_9205_MODELS
+};
+
+enum {
+	STAC_925x_REF,
+	STAC_M2_2,
+	STAC_MA6,
+	STAC_925x_MODELS
+};
+
+enum {
+	STAC_D945_REF,
+	STAC_D945GTP3,
+	STAC_D945GTP5,
+	STAC_MACMINI,
+	STAC_922X_MODELS
+};
+
+enum {
+	STAC_D965_REF,
+	STAC_D965_3ST,
+	STAC_D965_5ST,
+	STAC_927X_MODELS
+};
 
 struct sigmatel_spec {
 	struct snd_kcontrol_new *mixers[4];
@@ -67,6 +90,9 @@
 	unsigned int num_adcs;
 	hda_nid_t *mux_nids;
 	unsigned int num_muxes;
+	hda_nid_t *dmic_nids;
+	unsigned int num_dmics;
+	hda_nid_t dmux_nid;
 	hda_nid_t dig_in_nid;
 
 	/* pin widgets */
@@ -80,6 +106,8 @@
 	struct snd_kcontrol_new *mixer;
 
 	/* capture source */
+	struct hda_input_mux *dinput_mux;
+	unsigned int cur_dmux;
 	struct hda_input_mux *input_mux;
 	unsigned int cur_mux[3];
 
@@ -92,6 +120,7 @@
 	struct auto_pin_cfg autocfg;
 	unsigned int num_kctl_alloc, num_kctl_used;
 	struct snd_kcontrol_new *kctl_alloc;
+	struct hda_input_mux private_dimux;
 	struct hda_input_mux private_imux;
 };
 
@@ -107,6 +136,18 @@
         0x02,
 };
 
+static hda_nid_t stac925x_adc_nids[1] = {
+        0x03,
+};
+
+static hda_nid_t stac925x_mux_nids[1] = {
+        0x0f,
+};
+
+static hda_nid_t stac925x_dac_nids[1] = {
+        0x02,
+};
+
 static hda_nid_t stac922x_adc_nids[2] = {
         0x06, 0x07,
 };
@@ -131,11 +172,20 @@
         0x19, 0x1a
 };
 
+static hda_nid_t stac9205_dmic_nids[3] = {
+        0x17, 0x18, 0
+};
+
 static hda_nid_t stac9200_pin_nids[8] = {
 	0x08, 0x09, 0x0d, 0x0e, 
 	0x0f, 0x10, 0x11, 0x12,
 };
 
+static hda_nid_t stac925x_pin_nids[8] = {
+	0x07, 0x08, 0x0a, 0x0b, 
+	0x0c, 0x0d, 0x10, 0x11,
+};
+
 static hda_nid_t stac922x_pin_nids[10] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0f, 0x10, 0x11, 0x15, 0x1b,
@@ -154,6 +204,34 @@
 	
 };
 
+static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+	return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
+}
+
+static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+
+	ucontrol->value.enumerated.item[0] = spec->cur_dmux;
+	return 0;
+}
+
+static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+
+	return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
+				     spec->dmux_nid, &spec->cur_dmux);
+}
+
 static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
@@ -187,6 +265,12 @@
 	{}
 };
 
+static struct hda_verb stac925x_core_init[] = {
+	/* set dac0mux for dac converter */
+	{ 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{}
+};
+
 static struct hda_verb stac922x_core_init[] = {
 	/* set master volume and direct control */	
 	{ 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
@@ -232,6 +316,23 @@
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new stac925x_mixer[] = {
+	HDA_CODEC_VOLUME("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Master Playback Switch", 0xe, 0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Input Source",
+		.count = 1,
+		.info = stac92xx_mux_enum_info,
+		.get = stac92xx_mux_enum_get,
+		.put = stac92xx_mux_enum_put,
+	},
+	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
+	{ } /* end */
+};
+
 /* This needs to be generated dynamically based on sequence */
 static struct snd_kcontrol_new stac922x_mixer[] = {
 	{
@@ -263,7 +364,7 @@
 	{ } /* end */
 };
 
-static snd_kcontrol_new_t stac927x_mixer[] = {
+static struct snd_kcontrol_new stac927x_mixer[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Input Source",
@@ -278,7 +379,15 @@
 	{ } /* end */
 };
 
-static snd_kcontrol_new_t stac9205_mixer[] = {
+static struct snd_kcontrol_new stac9205_mixer[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Digital Input Source",
+		.count = 1,
+		.info = stac92xx_dmux_enum_info,
+		.get = stac92xx_dmux_enum_get,
+		.put = stac92xx_dmux_enum_put,
+	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Input Source",
@@ -327,22 +436,64 @@
 	0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
 };
 
-static unsigned int *stac9200_brd_tbl[] = {
-	ref9200_pin_configs,
+static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
+	[STAC_REF] = ref9200_pin_configs,
 };
 
-static struct hda_board_config stac9200_cfg_tbl[] = {
-	{ .modelname = "ref",
-	  .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2668,	/* DFI LanParty */
-	  .config = STAC_REF },
+static const char *stac9200_models[STAC_9200_MODELS] = {
+	[STAC_REF] = "ref",
+};
+
+static struct snd_pci_quirk stac9200_cfg_tbl[] = {
+	/* SigmaTel reference board */
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+		      "DFI LanParty", STAC_REF),
 	/* Dell laptops have BIOS problem */
-	{ .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01b5,
-	  .config = STAC_REF },	/* Dell Inspiron 630m */
-	{ .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01c2,
-	  .config = STAC_REF },	/* Dell Latitude D620 */
-	{ .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01cb,
-	  .config = STAC_REF },	/* Dell Latitude 120L */
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
+		      "Dell Inspiron 630m", STAC_REF),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
+		      "Dell Latitude D620", STAC_REF),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
+		      "Dell Latitude 120L", STAC_REF),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
+		      "Dell Latitude D820", STAC_REF),
+	{} /* terminator */
+};
+
+static unsigned int ref925x_pin_configs[8] = {
+	0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
+	0x90a70320, 0x02214210, 0x400003f1, 0x9033032e,
+};
+
+static unsigned int stac925x_MA6_pin_configs[8] = {
+	0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
+	0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
+};
+
+static unsigned int stac925xM2_2_pin_configs[8] = {
+	0x40c003f3, 0x424503f2, 0x041800f4, 0x02a19020,
+	0x50a103F0, 0x90100210, 0x400003f1, 0x9033032e,
+};
+
+static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
+	[STAC_REF] = ref925x_pin_configs,
+	[STAC_M2_2] = stac925xM2_2_pin_configs,
+	[STAC_MA6] = stac925x_MA6_pin_configs,
+};
+
+static const char *stac925x_models[STAC_925x_MODELS] = {
+	[STAC_REF] = "ref",
+	[STAC_M2_2] = "m2-2",
+	[STAC_MA6] = "m6",
+};
+
+static struct snd_pci_quirk stac925x_cfg_tbl[] = {
+	/* SigmaTel reference board */
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
+	SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
+	SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
+	SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
+	SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
 	{} /* terminator */
 };
 
@@ -365,100 +516,80 @@
 };
 
 static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
-	[STAC_REF] =	ref922x_pin_configs,
+	[STAC_D945_REF] = ref922x_pin_configs,
 	[STAC_D945GTP3] = d945gtp3_pin_configs,
 	[STAC_D945GTP5] = d945gtp5_pin_configs,
 	[STAC_MACMINI] = d945gtp5_pin_configs,
 };
 
-static struct hda_board_config stac922x_cfg_tbl[] = {
-	{ .modelname = "5stack", .config = STAC_D945GTP5 },
-	{ .modelname = "3stack", .config = STAC_D945GTP3 },
-	{ .modelname = "ref",
-	  .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2668,	/* DFI LanParty */
-	  .config = STAC_REF },		/* SigmaTel reference board */
-         /* Intel 945G based systems */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x0101,
-	  .config = STAC_D945GTP3 },	/* Intel D945GTP - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x0202,
-	  .config = STAC_D945GTP3 },	/* Intel D945GNT - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x0606,
-	  .config = STAC_D945GTP3 },	/* Intel D945GTP - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x0601,
-	  .config = STAC_D945GTP3 },	/* Intel D945GTP - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x0111,
-	  .config = STAC_D945GTP3 },	/* Intel D945GZP - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x1115,
-	  .config = STAC_D945GTP3 },	/* Intel D945GPM - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x1116,
-	  .config = STAC_D945GTP3 },	/* Intel D945GBO - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x1117,
-	  .config = STAC_D945GTP3 },	/* Intel D945GPM - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x1118,
-	  .config = STAC_D945GTP3 },	/* Intel D945GPM - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x1119,
-	  .config = STAC_D945GTP3 },	/* Intel D945GPM - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x8826,
-	  .config = STAC_D945GTP3 },	/* Intel D945GPM - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x5049,
-	  .config = STAC_D945GTP3 },	/* Intel D945GCZ - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x5055,
-	  .config = STAC_D945GTP3 },	/* Intel D945GCZ - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x5048,
-	  .config = STAC_D945GTP3 },	/* Intel D945GPB - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x0110,
-	  .config = STAC_D945GTP3 },	/* Intel D945GLR - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x0404,
-	  .config = STAC_D945GTP5 },	/* Intel D945GTP - 5 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x0303,
-	  .config = STAC_D945GTP5 },	/* Intel D945GNT - 5 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x0013,
-	  .config = STAC_D945GTP5 },	/* Intel D955XBK - 5 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x0417,
-	  .config = STAC_D945GTP5 },	/* Intel D975XBK - 5 Stack */
-	  /* Intel 945P based systems */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x0b0b,
-	  .config = STAC_D945GTP3 },	/* Intel D945PSN - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x0112,
-	  .config = STAC_D945GTP3 },	/* Intel D945PLN - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x0d0d,
-	  .config = STAC_D945GTP3 },	/* Intel D945PLM - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x0909,
-	  .config = STAC_D945GTP3 },	/* Intel D945PAW - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x0505,
-	  .config = STAC_D945GTP3 },	/* Intel D945PLM - 3 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x0707,
-	  .config = STAC_D945GTP5 },	/* Intel D945PSV - 5 Stack */
-	  /* other systems  */
-	{ .pci_subvendor = 0x8384,
-	  .pci_subdevice = 0x7680,
-	  .config = STAC_MACMINI },	/* Apple Mac Mini (early 2006) */
+static const char *stac922x_models[STAC_922X_MODELS] = {
+	[STAC_D945_REF]	= "ref",
+	[STAC_D945GTP5]	= "5stack",
+	[STAC_D945GTP3]	= "3stack",
+	[STAC_MACMINI]	= "macmini",
+};
+
+static struct snd_pci_quirk stac922x_cfg_tbl[] = {
+	/* SigmaTel reference board */
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+		      "DFI LanParty", STAC_D945_REF),
+	/* Intel 945G based systems */
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
+		      "Intel D945G", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
+		      "Intel D945G", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
+		      "Intel D945G", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
+		      "Intel D945G", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
+		      "Intel D945G", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
+		      "Intel D945G", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
+		      "Intel D945G", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
+		      "Intel D945G", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
+		      "Intel D945G", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
+		      "Intel D945G", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
+		      "Intel D945G", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
+		      "Intel D945G", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
+		      "Intel D945G", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
+		      "Intel D945G", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
+		      "Intel D945G", STAC_D945GTP3),
+	/* Intel D945G 5-stack systems */
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
+		      "Intel D945G", STAC_D945GTP5),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
+		      "Intel D945G", STAC_D945GTP5),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
+		      "Intel D945G", STAC_D945GTP5),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
+		      "Intel D945G", STAC_D945GTP5),
+	/* Intel 945P based systems */
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
+		      "Intel D945P", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
+		      "Intel D945P", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
+		      "Intel D945P", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
+		      "Intel D945P", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
+		      "Intel D945P", STAC_D945GTP3),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
+		      "Intel D945P", STAC_D945GTP5),
+	/* other systems  */
+	/* Apple Mac Mini (early 2006) */
+	SND_PCI_QUIRK(0x8384, 0x7680,
+		      "Mac Mini", STAC_MACMINI),
 	{} /* terminator */
 };
 
@@ -484,120 +615,72 @@
 };
 
 static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
-	[STAC_REF] =	ref927x_pin_configs,
+	[STAC_D965_REF] = ref927x_pin_configs,
 	[STAC_D965_3ST] = d965_3st_pin_configs,
 	[STAC_D965_5ST] = d965_5st_pin_configs,
 };
 
-static struct hda_board_config stac927x_cfg_tbl[] = {
-	{ .modelname = "5stack", .config = STAC_D965_5ST },
-	{ .modelname = "3stack", .config = STAC_D965_3ST },
-	{ .modelname = "ref",
-	  .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2668,	/* DFI LanParty */
-	  .config = STAC_REF },		/* SigmaTel reference board */
+static const char *stac927x_models[STAC_927X_MODELS] = {
+	[STAC_D965_REF]	= "ref",
+	[STAC_D965_3ST]	= "3stack",
+	[STAC_D965_5ST] = "5stack",
+};
+
+static struct snd_pci_quirk stac927x_cfg_tbl[] = {
+	/* SigmaTel reference board */
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+		      "DFI LanParty", STAC_D965_REF),
 	 /* Intel 946 based systems */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x3d01,
-	  .config = STAC_D965_3ST }, /* D946  configuration */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0xa301,
-	  .config = STAC_D965_3ST }, /* Intel D946GZT - 3 stack  */
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
 	/* 965 based 3 stack systems */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2116,
-	  .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2115,
-	  .config = STAC_D965_3ST }, /* Intel DQ965WC - 3 Stack  */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2114,
-	  .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2113,
-	  .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2112,
-	  .config = STAC_D965_3ST }, /* Intel DG965MS - 3 Stack  */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2111,
-	  .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2110,
-	  .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2009,
-	  .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2008,
-	  .config = STAC_D965_3ST }, /* Intel DQ965GF - 3 Stack  */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2007,
-	  .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2006,
-	  .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2005,
-	  .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2004,
-	  .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2003,
-	  .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2002,
-	  .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2001,
-	  .config = STAC_D965_3ST }, /* Intel DQ965GF - 3 Stack */
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
 	/* 965 based 5 stack systems */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2301,
-	  .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2302,
-	  .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2303,
-	  .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2304,
-	  .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2305,
-	  .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2501,
-	  .config = STAC_D965_5ST }, /* Intel DG965MQ - 5 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2502,
-	  .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2503,
-	  .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
-	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2504,
-	  .config = STAC_D965_5ST }, /* Intel DQ965GF - 5 Stack */
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
 	{} /* terminator */
 };
 
 static unsigned int ref9205_pin_configs[12] = {
 	0x40000100, 0x40000100, 0x01016011, 0x01014010,
-	0x01813122, 0x01a19021, 0x40000100, 0x40000100, 
-	0x40000100, 0x40000100, 0x01441030, 0x01c41030
+	0x01813122, 0x01a19021, 0x40000100, 0x40000100,
+	0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
 };
 
-static unsigned int *stac9205_brd_tbl[] = {
+static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
 	ref9205_pin_configs,
 };
 
-static struct hda_board_config stac9205_cfg_tbl[] = {
-	{ .modelname = "ref",
-	  .pci_subvendor = PCI_VENDOR_ID_INTEL,
-	  .pci_subdevice = 0x2668,	/* DFI LanParty */
-	  .config = STAC_REF },		/* SigmaTel reference board */
+static const char *stac9205_models[STAC_9205_MODELS] = {
+	[STAC_9205_REF] = "ref",
+};
+
+static struct snd_pci_quirk stac9205_cfg_tbl[] = {
+	/* SigmaTel reference board */
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+		      "DFI LanParty", STAC_9205_REF),
 	{} /* terminator */
 };
 
@@ -1154,6 +1237,58 @@
 	return 0;
 }
 
+/* labels for dmic mux inputs */
+static const char *stac92xx_dmic_labels[5] = {
+	"Analog Inputs", "Digital Mic 1", "Digital Mic 2",
+	"Digital Mic 3", "Digital Mic 4"
+};
+
+/* create playback/capture controls for input pins on dmic capable codecs */
+static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
+						const struct auto_pin_cfg *cfg)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	struct hda_input_mux *dimux = &spec->private_dimux;
+	hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
+	int i, j;
+
+	dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
+	dimux->items[dimux->num_items].index = 0;
+	dimux->num_items++;
+
+	for (i = 0; i < spec->num_dmics; i++) {
+		int index;
+		int num_cons;
+		unsigned int def_conf;
+
+		def_conf = snd_hda_codec_read(codec,
+					      spec->dmic_nids[i],
+					      0,
+					      AC_VERB_GET_CONFIG_DEFAULT,
+					      0);
+		if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
+			continue;
+
+		num_cons = snd_hda_get_connections(codec,
+				spec->dmux_nid,
+				con_lst,
+				HDA_MAX_NUM_INPUTS);
+		for (j = 0; j < num_cons; j++)
+			if (con_lst[j] == spec->dmic_nids[i]) {
+				index = j;
+				goto found;
+			}
+		continue;
+found:
+		dimux->items[dimux->num_items].label =
+			stac92xx_dmic_labels[dimux->num_items];
+		dimux->items[dimux->num_items].index = index;
+		dimux->num_items++;
+	}
+
+	return 0;
+}
+
 /* create playback/capture controls for input pins */
 static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
 {
@@ -1238,7 +1373,9 @@
 	struct sigmatel_spec *spec = codec->spec;
 	int err;
 
-	if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
+	if ((err = snd_hda_parse_pin_def_config(codec,
+						&spec->autocfg,
+						spec->dmic_nids)) < 0)
 		return err;
 	if (! spec->autocfg.line_outs)
 		return 0; /* can't find valid pin config */
@@ -1254,6 +1391,11 @@
 	    (err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
 		return err;
 
+	if (spec->num_dmics > 0)
+		if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
+						&spec->autocfg)) < 0)
+			return err;
+
 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 	if (spec->multiout.max_channels > 2)
 		spec->surr_switch = 1;
@@ -1267,6 +1409,7 @@
 		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 
 	spec->input_mux = &spec->private_imux;
+	spec->dinput_mux = &spec->private_dimux;
 
 	return 1;
 }
@@ -1366,6 +1509,7 @@
 		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 
 	spec->input_mux = &spec->private_imux;
+	spec->dinput_mux = &spec->private_dimux;
 
 	return 1;
 }
@@ -1448,6 +1592,11 @@
 			stac92xx_auto_set_pinctl(codec, nid, pinctl);
 		}
 	}
+	if (spec->num_dmics > 0)
+		for (i = 0; i < spec->num_dmics; i++)
+			stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
+						 AC_PINCTL_IN_EN);
+
 	if (cfg->dig_out_pin)
 		stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
 					 AC_PINCTL_OUT_EN);
@@ -1598,7 +1747,9 @@
 	codec->spec = spec;
 	spec->num_pins = 8;
 	spec->pin_nids = stac9200_pin_nids;
-	spec->board_config = snd_hda_check_board_config(codec, stac9200_cfg_tbl);
+	spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
+							stac9200_models,
+							stac9200_cfg_tbl);
 	if (spec->board_config < 0) {
 		snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
 		err = stac92xx_save_bios_config_regs(codec);
@@ -1618,6 +1769,7 @@
 	spec->adc_nids = stac9200_adc_nids;
 	spec->mux_nids = stac9200_mux_nids;
 	spec->num_muxes = 1;
+	spec->num_dmics = 0;
 
 	spec->init = stac9200_core_init;
 	spec->mixer = stac9200_mixer;
@@ -1633,6 +1785,56 @@
 	return 0;
 }
 
+static int patch_stac925x(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec;
+	int err;
+
+	spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+	spec->num_pins = 8;
+	spec->pin_nids = stac925x_pin_nids;
+	spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
+							stac925x_models,
+							stac925x_cfg_tbl);
+	if (spec->board_config < 0) {
+		snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x, using BIOS defaults\n");
+		err = stac92xx_save_bios_config_regs(codec);
+		if (err < 0) {
+			stac92xx_free(codec);
+			return err;
+		}
+		spec->pin_configs = spec->bios_pin_configs;
+	} else if (stac925x_brd_tbl[spec->board_config] != NULL){
+		spec->pin_configs = stac925x_brd_tbl[spec->board_config];
+		stac92xx_set_config_regs(codec);
+	}
+
+	spec->multiout.max_channels = 2;
+	spec->multiout.num_dacs = 1;
+	spec->multiout.dac_nids = stac925x_dac_nids;
+	spec->adc_nids = stac925x_adc_nids;
+	spec->mux_nids = stac925x_mux_nids;
+	spec->num_muxes = 1;
+	spec->num_dmics = 0;
+
+	spec->init = stac925x_core_init;
+	spec->mixer = stac925x_mixer;
+
+	err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
+	if (err < 0) {
+		stac92xx_free(codec);
+		return err;
+	}
+
+	codec->patch_ops = stac92xx_patch_ops;
+
+	return 0;
+}
+
 static int patch_stac922x(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
@@ -1645,7 +1847,9 @@
 	codec->spec = spec;
 	spec->num_pins = 10;
 	spec->pin_nids = stac922x_pin_nids;
-	spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl);
+	spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
+							stac922x_models,
+							stac922x_cfg_tbl);
 	if (spec->board_config < 0) {
 		snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
 			"using BIOS defaults\n");
@@ -1663,6 +1867,7 @@
 	spec->adc_nids = stac922x_adc_nids;
 	spec->mux_nids = stac922x_mux_nids;
 	spec->num_muxes = 2;
+	spec->num_dmics = 0;
 
 	spec->init = stac922x_core_init;
 	spec->mixer = stac922x_mixer;
@@ -1695,7 +1900,9 @@
 	codec->spec = spec;
 	spec->num_pins = 14;
 	spec->pin_nids = stac927x_pin_nids;
-	spec->board_config = snd_hda_check_board_config(codec, stac927x_cfg_tbl);
+	spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
+							stac927x_models,
+							stac927x_cfg_tbl);
 	if (spec->board_config < 0) {
                 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n");
 		err = stac92xx_save_bios_config_regs(codec);
@@ -1714,6 +1921,7 @@
 		spec->adc_nids = stac927x_adc_nids;
 		spec->mux_nids = stac927x_mux_nids;
 		spec->num_muxes = 3;
+		spec->num_dmics = 0;
 		spec->init = d965_core_init;
 		spec->mixer = stac9227_mixer;
 		break;
@@ -1721,6 +1929,7 @@
 		spec->adc_nids = stac927x_adc_nids;
 		spec->mux_nids = stac927x_mux_nids;
 		spec->num_muxes = 3;
+		spec->num_dmics = 0;
 		spec->init = d965_core_init;
 		spec->mixer = stac9227_mixer;
 		break;
@@ -1728,6 +1937,7 @@
 		spec->adc_nids = stac927x_adc_nids;
 		spec->mux_nids = stac927x_mux_nids;
 		spec->num_muxes = 3;
+		spec->num_dmics = 0;
 		spec->init = stac927x_core_init;
 		spec->mixer = stac927x_mixer;
 	}
@@ -1757,7 +1967,9 @@
 	codec->spec = spec;
 	spec->num_pins = 14;
 	spec->pin_nids = stac9205_pin_nids;
-	spec->board_config = snd_hda_check_board_config(codec, stac9205_cfg_tbl);
+	spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
+							stac9205_models,
+							stac9205_cfg_tbl);
 	if (spec->board_config < 0) {
 		snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
 		err = stac92xx_save_bios_config_regs(codec);
@@ -1773,13 +1985,28 @@
 
 	spec->adc_nids = stac9205_adc_nids;
 	spec->mux_nids = stac9205_mux_nids;
-	spec->num_muxes = 3;
+	spec->num_muxes = 2;
+	spec->dmic_nids = stac9205_dmic_nids;
+	spec->num_dmics = 2;
+	spec->dmux_nid = 0x1d;
 
 	spec->init = stac9205_core_init;
 	spec->mixer = stac9205_mixer;
 
 	spec->multiout.dac_nids = spec->dac_nids;
 
+	/* Configure GPIO0 as EAPD output */
+	snd_hda_codec_write(codec, codec->afg, 0,
+			    AC_VERB_SET_GPIO_DIRECTION, 0x00000001);
+	/* Configure GPIO0 as CMOS */
+	snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000);
+	/* Assert GPIO0 high */
+	snd_hda_codec_write(codec, codec->afg, 0,
+			    AC_VERB_SET_GPIO_DATA, 0x00000001);
+	/* Enable GPIO0 */
+	snd_hda_codec_write(codec, codec->afg, 0,
+			    AC_VERB_SET_GPIO_MASK, 0x00000001);
+
 	err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
 	if (err < 0) {
 		stac92xx_free(codec);
@@ -1963,18 +2190,19 @@
        /* Unknown. id=0x83847661 and subsys=0x104D1200. */
        STAC9872K_VAIO,
        /* AR Series. id=0x83847664 and subsys=104D1300 */
-       CXD9872AKD_VAIO 
-     };
+       CXD9872AKD_VAIO,
+       STAC_9872_MODELS,
+};
 
-static struct hda_board_config stac9872_cfg_tbl[] = {
-	{ .modelname = "vaio", .config = CXD9872RD_VAIO },
-	{ .modelname = "vaio-ar", .config = CXD9872AKD_VAIO },
-	{ .pci_subvendor = 0x104d, .pci_subdevice = 0x81e6,
-	  .config = CXD9872RD_VAIO },
-	{ .pci_subvendor = 0x104d, .pci_subdevice = 0x81ef,
-	  .config = CXD9872RD_VAIO },
-	{ .pci_subvendor = 0x104d, .pci_subdevice = 0x81fd,
-	  .config = CXD9872AKD_VAIO },
+static const char *stac9872_models[STAC_9872_MODELS] = {
+	[CXD9872RD_VAIO]	= "vaio",
+	[CXD9872AKD_VAIO]	= "vaio-ar",
+};
+
+static struct snd_pci_quirk stac9872_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
+	SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
+	SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
 	{}
 };
 
@@ -1983,7 +2211,9 @@
 	struct sigmatel_spec *spec;
 	int board_config;
 
-	board_config = snd_hda_check_board_config(codec, stac9872_cfg_tbl);
+	board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
+						  stac9872_models,
+						  stac9872_cfg_tbl);
 	if (board_config < 0)
 		/* unknown config, let generic-parser do its job... */
 		return snd_hda_parse_generic_codec(codec);
@@ -2055,6 +2285,12 @@
  	{ .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
  	{ .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
  	{ .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
+	{ .id = 0x83847632, .name = "STAC9202",  .patch = patch_stac925x },
+	{ .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
+	{ .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
+	{ .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
+	{ .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
+	{ .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
  	/* The following does not take into account .id=0x83847661 when subsys =
  	 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
  	 * currently not fully supported.
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
new file mode 100644
index 0000000..4c839b0
--- /dev/null
+++ b/sound/pci/hda/patch_via.c
@@ -0,0 +1,1396 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for VIA VT1708 codec
+ *
+ * Copyright (c) 2006 Lydia Wang <lydiawang@viatech.com>
+ *                    Takashi Iwai <tiwai@suse.de>
+ *
+ *  This driver 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 driver 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
+ */
+
+/* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */
+/*                                                                           */
+/* 2006-03-03  Lydia Wang  Create the basic patch to support VT1708 codec    */
+/* 2006-03-14  Lydia Wang  Modify hard code for some pin widget nid          */
+/* 2006-08-02  Lydia Wang  Add support to VT1709 codec                       */
+/* 2006-09-08  Lydia Wang  Fix internal loopback recording source select bug */
+/*                                                                           */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+
+/* amp values */
+#define AMP_VAL_IDX_SHIFT	19
+#define AMP_VAL_IDX_MASK	(0x0f<<19)
+
+#define NUM_CONTROL_ALLOC	32
+#define NUM_VERB_ALLOC		32
+
+/* Pin Widget NID */
+#define VT1708_HP_NID		0x13
+#define VT1708_DIGOUT_NID	0x14
+#define VT1708_DIGIN_NID	0x16
+
+#define VT1709_HP_DAC_NID	0x28
+#define VT1709_DIGOUT_NID	0x13
+#define VT1709_DIGIN_NID	0x17
+
+#define IS_VT1708_VENDORID(x)		((x) >= 0x11061708 && (x) <= 0x1106170b)
+#define IS_VT1709_10CH_VENDORID(x)	((x) >= 0x1106e710 && (x) <= 0x1106e713)
+#define IS_VT1709_6CH_VENDORID(x)	((x) >= 0x1106e714 && (x) <= 0x1106e717)
+
+
+enum {
+	VIA_CTL_WIDGET_VOL,
+	VIA_CTL_WIDGET_MUTE,
+};
+
+enum {
+	AUTO_SEQ_FRONT,
+	AUTO_SEQ_SURROUND,
+	AUTO_SEQ_CENLFE,
+	AUTO_SEQ_SIDE
+};
+
+static struct snd_kcontrol_new vt1708_control_templates[] = {
+	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
+	HDA_CODEC_MUTE(NULL, 0, 0, 0),
+};
+
+
+struct via_spec {
+	/* codec parameterization */
+	struct snd_kcontrol_new *mixers[3];
+	unsigned int num_mixers;
+
+	struct hda_verb *init_verbs;
+
+	char *stream_name_analog;
+	struct hda_pcm_stream *stream_analog_playback;
+	struct hda_pcm_stream *stream_analog_capture;
+
+	char *stream_name_digital;
+	struct hda_pcm_stream *stream_digital_playback;
+	struct hda_pcm_stream *stream_digital_capture;
+
+	/* playback */
+	struct hda_multi_out multiout;
+
+	/* capture */
+	unsigned int num_adc_nids;
+	hda_nid_t *adc_nids;
+	hda_nid_t dig_in_nid;
+
+	/* capture source */
+	const struct hda_input_mux *input_mux;
+	unsigned int cur_mux[3];
+
+	/* PCM information */
+	struct hda_pcm pcm_rec[2];
+
+	/* dynamic controls, init_verbs and input_mux */
+	struct auto_pin_cfg autocfg;
+	unsigned int num_kctl_alloc, num_kctl_used;
+	struct snd_kcontrol_new *kctl_alloc;
+	struct hda_input_mux private_imux;
+	hda_nid_t private_dac_nids[4];	
+};
+
+static hda_nid_t vt1708_adc_nids[2] = {
+	/* ADC1-2 */
+	0x15, 0x27
+};
+
+static hda_nid_t vt1709_adc_nids[3] = {
+	/* ADC1-2 */
+	0x14, 0x15, 0x16
+};
+
+/* add dynamic controls */
+static int via_add_control(struct via_spec *spec, int type, const char *name,
+			   unsigned long val)
+{
+	struct snd_kcontrol_new *knew;
+
+	if (spec->num_kctl_used >= spec->num_kctl_alloc) {
+		int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
+
+		/* array + terminator */
+		knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
+		if (!knew)
+			return -ENOMEM;
+		if (spec->kctl_alloc) {
+			memcpy(knew, spec->kctl_alloc,
+			       sizeof(*knew) * spec->num_kctl_alloc);
+			kfree(spec->kctl_alloc);
+		}
+		spec->kctl_alloc = knew;
+		spec->num_kctl_alloc = num;
+	}
+
+	knew = &spec->kctl_alloc[spec->num_kctl_used];
+	*knew = vt1708_control_templates[type];
+	knew->name = kstrdup(name, GFP_KERNEL);
+
+	if (!knew->name)
+		return -ENOMEM;
+	knew->private_value = val;
+	spec->num_kctl_used++;
+	return 0;
+}
+
+/* create input playback/capture controls for the given pin */
+static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
+				const char *ctlname, int idx, int mix_nid)
+{
+	char name[32];
+	int err;
+
+	sprintf(name, "%s Playback Volume", ctlname);
+	err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+			      HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
+	if (err < 0)
+		return err;
+	sprintf(name, "%s Playback Switch", ctlname);
+	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+			      HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static void via_auto_set_output_and_unmute(struct hda_codec *codec,
+					   hda_nid_t nid, int pin_type,
+					   int dac_idx)
+{
+	/* set as output */
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    pin_type);
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+			    AMP_OUT_UNMUTE);
+}
+
+
+static void via_auto_init_multi_out(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int i;
+
+	for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
+		hda_nid_t nid = spec->autocfg.line_out_pins[i];
+		if (nid)
+			via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
+	}
+}
+
+static void via_auto_init_hp_out(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	hda_nid_t pin;
+
+	pin = spec->autocfg.hp_pins[0];
+	if (pin) /* connect to front */
+		via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+}
+
+static void via_auto_init_analog_input(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int i;
+
+	for (i = 0; i < AUTO_PIN_LAST; i++) {
+		hda_nid_t nid = spec->autocfg.input_pins[i];
+
+		snd_hda_codec_write(codec, nid, 0,
+				    AC_VERB_SET_PIN_WIDGET_CONTROL,
+				    (i <= AUTO_PIN_FRONT_MIC ?
+				     PIN_VREF50 : PIN_IN));
+
+	}
+}
+/*
+ * input MUX handling
+ */
+static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct via_spec *spec = codec->spec;
+	return snd_hda_input_mux_info(spec->input_mux, uinfo);
+}
+
+static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct via_spec *spec = codec->spec;
+	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+	ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
+	return 0;
+}
+
+static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct via_spec *spec = codec->spec;
+	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	unsigned int vendor_id = codec->vendor_id;
+
+	/* AIW0  lydia 060801 add for correct sw0 input select */
+	if (IS_VT1708_VENDORID(vendor_id) && (adc_idx == 0))
+		return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+					     0x18, &spec->cur_mux[adc_idx]);
+	else if ((IS_VT1709_10CH_VENDORID(vendor_id) ||
+		  IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0) )
+		return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+					     0x19, &spec->cur_mux[adc_idx]);
+	else
+		return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+					     spec->adc_nids[adc_idx],
+					     &spec->cur_mux[adc_idx]);
+}
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt1708_capture_mixer[] = {
+	HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 * FIXME: the controls appear in the "playback" view!
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 1,
+		.info = via_mux_enum_info,
+		.get = via_mux_enum_get,
+		.put = via_mux_enum_put,
+	},
+	{ } /* end */
+};
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb vt1708_volume_init_verbs[] = {
+	/*
+	 * Unmute ADC0-1 and set the default input to mic-in
+	 */
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+	 * mixer widget
+	 */
+	/* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+	/*
+	 * Set up output mixers (0x19 - 0x1b)
+	 */
+	/* set vol=0 to output mixers */
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	
+	/* Setup default input to PW4 */
+	{0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
+	/* Set mic as default input of sw0 */
+	{0x18, AC_VERB_SET_CONNECT_SEL, 0x2},
+	/* PW9 Output enable */
+	{0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+};
+
+static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
+				 struct hda_codec *codec,
+				 struct snd_pcm_substream *substream)
+{
+	struct via_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+}
+
+static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+				    struct hda_codec *codec,
+				    unsigned int stream_tag,
+				    unsigned int format,
+				    struct snd_pcm_substream *substream)
+{
+	struct via_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
+						stream_tag, format, substream);
+}
+
+static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				    struct hda_codec *codec,
+				    struct snd_pcm_substream *substream)
+{
+	struct via_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+}
+
+/*
+ * Digital out
+ */
+static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+				     struct hda_codec *codec,
+				     struct snd_pcm_substream *substream)
+{
+	struct via_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      struct snd_pcm_substream *substream)
+{
+	struct via_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+/*
+ * Analog capture
+ */
+static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+				   struct hda_codec *codec,
+				   unsigned int stream_tag,
+				   unsigned int format,
+				   struct snd_pcm_substream *substream)
+{
+	struct via_spec *spec = codec->spec;
+
+	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+				   stream_tag, 0, format);
+	return 0;
+}
+
+static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				   struct hda_codec *codec,
+				   struct snd_pcm_substream *substream)
+{
+	struct via_spec *spec = codec->spec;
+	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+				   0, 0, 0);
+	return 0;
+}
+
+static struct hda_pcm_stream vt1708_pcm_analog_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 8,
+	.nid = 0x10, /* NID to query formats and rates */
+	.ops = {
+		.open = via_playback_pcm_open,
+		.prepare = via_playback_pcm_prepare,
+		.cleanup = via_playback_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream vt1708_pcm_analog_capture = {
+	.substreams = 2,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0x15, /* NID to query formats and rates */
+	.ops = {
+		.prepare = via_capture_pcm_prepare,
+		.cleanup = via_capture_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream vt1708_pcm_digital_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in via_build_pcms */
+	.ops = {
+		.open = via_dig_playback_pcm_open,
+		.close = via_dig_playback_pcm_close
+	},
+};
+
+static struct hda_pcm_stream vt1708_pcm_digital_capture = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+};
+
+static int via_build_controls(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int err;
+	int i;
+
+	for (i = 0; i < spec->num_mixers; i++) {
+		err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
+		if (err < 0)
+			return err;
+	}
+
+	if (spec->multiout.dig_out_nid) {
+		err = snd_hda_create_spdif_out_ctls(codec,
+						    spec->multiout.dig_out_nid);
+		if (err < 0)
+			return err;
+	}
+	if (spec->dig_in_nid) {
+		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static int via_build_pcms(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	struct hda_pcm *info = spec->pcm_rec;
+
+	codec->num_pcms = 1;
+	codec->pcm_info = info;
+
+	info->name = spec->stream_name_analog;
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
+	info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
+	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
+
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
+		spec->multiout.max_channels;
+
+	if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
+		codec->num_pcms++;
+		info++;
+		info->name = spec->stream_name_digital;
+		if (spec->multiout.dig_out_nid) {
+			info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+				*(spec->stream_digital_playback);
+			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+				spec->multiout.dig_out_nid;
+		}
+		if (spec->dig_in_nid) {
+			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+				*(spec->stream_digital_capture);
+			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
+				spec->dig_in_nid;
+		}
+	}
+
+	return 0;
+}
+
+static void via_free(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	unsigned int i;
+
+	if (!spec)
+		return;
+
+	if (spec->kctl_alloc) {
+		for (i = 0; i < spec->num_kctl_used; i++)
+			kfree(spec->kctl_alloc[i].name);
+		kfree(spec->kctl_alloc);
+	}
+
+	kfree(codec->spec);
+}
+
+static int via_init(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	snd_hda_sequence_write(codec, spec->init_verbs);
+ 	return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * resume
+ */
+static int via_resume(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int i;
+
+	via_init(codec);
+	for (i = 0; i < spec->num_mixers; i++)
+		snd_hda_resume_ctls(codec, spec->mixers[i]);
+	if (spec->multiout.dig_out_nid)
+		snd_hda_resume_spdif_out(codec);
+	if (spec->dig_in_nid)
+		snd_hda_resume_spdif_in(codec);
+
+	return 0;
+}
+#endif
+
+/*
+ */
+static struct hda_codec_ops via_patch_ops = {
+	.build_controls = via_build_controls,
+	.build_pcms = via_build_pcms,
+	.init = via_init,
+	.free = via_free,
+#ifdef CONFIG_PM
+	.resume = via_resume,
+#endif
+};
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
+				     const struct auto_pin_cfg *cfg)
+{
+	int i;
+	hda_nid_t nid;
+
+	spec->multiout.num_dacs = cfg->line_outs;
+
+	spec->multiout.dac_nids = spec->private_dac_nids;
+ 	
+	for(i = 0; i < 4; i++) {
+		nid = cfg->line_out_pins[i];
+		if (nid) {
+			/* config dac list */
+			switch (i) {
+			case AUTO_SEQ_FRONT:
+				spec->multiout.dac_nids[i] = 0x10;
+				break;
+			case AUTO_SEQ_CENLFE:
+				spec->multiout.dac_nids[i] = 0x12;
+				break;
+			case AUTO_SEQ_SURROUND:
+				spec->multiout.dac_nids[i] = 0x13;
+				break;
+			case AUTO_SEQ_SIDE:
+				spec->multiout.dac_nids[i] = 0x11;
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
+					     const struct auto_pin_cfg *cfg)
+{
+	char name[32];
+	static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+	hda_nid_t nid, nid_vol = 0;
+	int i, err;
+
+	for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
+		nid = cfg->line_out_pins[i];
+
+		if (!nid)
+			continue;
+		
+		if (i != AUTO_SEQ_FRONT)
+			nid_vol = 0x1b - i + 1;
+
+		if (i == AUTO_SEQ_CENLFE) {
+			/* Center/LFE */
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+					      "Center Playback Volume",
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+					      "LFE Playback Volume",
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+					      "Center Playback Switch",
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+					      "LFE Playback Switch",
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		} else if (i == AUTO_SEQ_FRONT){
+			/* add control to mixer index 0 */
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+					      "Master Front Playback Volume",
+					      HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT));
+			if (err < 0)
+				return err;
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+					      "Master Front Playback Switch",
+					      HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT));
+			if (err < 0)
+				return err;
+			
+			/* add control to PW3 */
+			sprintf(name, "%s Playback Volume", chname[i]);
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+					      HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			sprintf(name, "%s Playback Switch", chname[i]);
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+					      HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		} else {
+			sprintf(name, "%s Playback Volume", chname[i]);
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			sprintf(name, "%s Playback Switch", chname[i]);
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		}
+	}
+
+	return 0;
+}
+
+static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+	int err;
+
+	if (!pin)
+		return 0;
+
+	spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
+
+	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+			      "Headphone Playback Volume",
+			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+	if (err < 0)
+		return err;
+	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+			      "Headphone Playback Switch",
+			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
+						const struct auto_pin_cfg *cfg)
+{
+	static char *labels[] = {
+		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
+	};
+	struct hda_input_mux *imux = &spec->private_imux;
+	int i, err, idx = 0;
+
+	/* for internal loopback recording select */
+	imux->items[imux->num_items].label = "Stereo Mixer";
+	imux->items[imux->num_items].index = idx;
+	imux->num_items++;
+
+	for (i = 0; i < AUTO_PIN_LAST; i++) {
+		if (!cfg->input_pins[i])
+			continue;
+
+		switch (cfg->input_pins[i]) {
+		case 0x1d: /* Mic */
+			idx = 2;
+			break;
+				
+		case 0x1e: /* Line In */
+			idx = 3;
+			break;
+
+		case 0x21: /* Front Mic */
+			idx = 4;
+			break;
+
+		case 0x24: /* CD */
+			idx = 1;
+			break;
+		}
+		err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
+					   idx, 0x17);
+		if (err < 0)
+			return err;
+		imux->items[imux->num_items].label = labels[i];
+		imux->items[imux->num_items].index = idx;
+		imux->num_items++;
+	}
+	return 0;
+}
+
+static int vt1708_parse_auto_config(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int err;
+
+	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+	if (err < 0)
+		return err;
+	err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+		return 0; /* can't find valid BIOS pin config */
+
+	err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+	if (err < 0)
+		return err;
+	err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+
+	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+	if (spec->autocfg.dig_out_pin)
+		spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
+	if (spec->autocfg.dig_in_pin)
+		spec->dig_in_nid = VT1708_DIGIN_NID;
+
+	if (spec->kctl_alloc)
+		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+	spec->init_verbs = vt1708_volume_init_verbs;	
+
+	spec->input_mux = &spec->private_imux;
+
+	return 1;
+}
+
+/* init callback for auto-configuration model -- overriding the default init */
+static int via_auto_init(struct hda_codec *codec)
+{
+	via_init(codec);
+	via_auto_init_multi_out(codec);
+	via_auto_init_hp_out(codec);
+	via_auto_init_analog_input(codec);
+	return 0;
+}
+
+static int patch_vt1708(struct hda_codec *codec)
+{
+	struct via_spec *spec;
+	int err;
+
+	/* create a codec specific record */
+	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	/* automatic parse from the BIOS config */
+	err = vt1708_parse_auto_config(codec);
+	if (err < 0) {
+		via_free(codec);
+		return err;
+	} else if (!err) {
+		printk(KERN_INFO "hda_codec: Cannot set up configuration "
+		       "from BIOS.  Using genenic mode...\n");
+	}
+
+	
+	spec->stream_name_analog = "VT1708 Analog";
+	spec->stream_analog_playback = &vt1708_pcm_analog_playback;
+	spec->stream_analog_capture = &vt1708_pcm_analog_capture;
+
+	spec->stream_name_digital = "VT1708 Digital";
+	spec->stream_digital_playback = &vt1708_pcm_digital_playback;
+	spec->stream_digital_capture = &vt1708_pcm_digital_capture;
+
+	
+	if (!spec->adc_nids && spec->input_mux) {
+		spec->adc_nids = vt1708_adc_nids;
+		spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
+		spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
+		spec->num_mixers++;
+	}
+
+	codec->patch_ops = via_patch_ops;
+
+	codec->patch_ops.init = via_auto_init;
+
+	return 0;
+}
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt1709_capture_mixer[] = {
+	HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 * FIXME: the controls appear in the "playback" view!
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 1,
+		.info = via_mux_enum_info,
+		.get = via_mux_enum_get,
+		.put = via_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
+	/*
+	 * Unmute ADC0-2 and set the default input to mic-in
+	 */
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+	 * mixer widget
+	 */
+	/* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+	/*
+	 * Set up output selector (0x1a, 0x1b, 0x29)
+	 */
+	/* set vol=0 to output mixers */
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+	/*
+	 *  Unmute PW3 and PW4
+	 */
+	{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+	/* Set input of PW4 as AOW4 */
+	{0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
+	/* Set mic as default input of sw0 */
+	{0x19, AC_VERB_SET_CONNECT_SEL, 0x2},
+	/* PW9 Output enable */
+	{0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	{ }
+};
+
+static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 10,
+	.nid = 0x10, /* NID to query formats and rates */
+	.ops = {
+		.open = via_playback_pcm_open,
+		.prepare = via_playback_pcm_prepare,
+		.cleanup = via_playback_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 6,
+	.nid = 0x10, /* NID to query formats and rates */
+	.ops = {
+		.open = via_playback_pcm_open,
+		.prepare = via_playback_pcm_prepare,
+		.cleanup = via_playback_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream vt1709_pcm_analog_capture = {
+	.substreams = 2,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0x14, /* NID to query formats and rates */
+	.ops = {
+		.prepare = via_capture_pcm_prepare,
+		.cleanup = via_capture_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream vt1709_pcm_digital_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in via_build_pcms */
+	.ops = {
+		.open = via_dig_playback_pcm_open,
+		.close = via_dig_playback_pcm_close
+	},
+};
+
+static struct hda_pcm_stream vt1709_pcm_digital_capture = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+};
+
+static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
+				     const struct auto_pin_cfg *cfg)
+{
+	int i;
+	hda_nid_t nid;
+
+	if (cfg->line_outs == 4)  /* 10 channels */
+		spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
+	else if (cfg->line_outs == 3) /* 6 channels */
+		spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
+
+	spec->multiout.dac_nids = spec->private_dac_nids;
+
+	if (cfg->line_outs == 4) { /* 10 channels */
+		for (i = 0; i < cfg->line_outs; i++) {
+			nid = cfg->line_out_pins[i];
+			if (nid) {
+				/* config dac list */
+				switch (i) {
+				case AUTO_SEQ_FRONT:
+					/* AOW0 */
+					spec->multiout.dac_nids[i] = 0x10;
+					break;
+				case AUTO_SEQ_CENLFE:
+					/* AOW2 */
+					spec->multiout.dac_nids[i] = 0x12;
+					break;
+				case AUTO_SEQ_SURROUND:
+					/* AOW3 */
+					spec->multiout.dac_nids[i] = 0x27;
+					break;
+				case AUTO_SEQ_SIDE:
+					/* AOW1 */
+					spec->multiout.dac_nids[i] = 0x11;
+					break;
+				default:
+					break;
+				}
+			}
+		}
+		spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
+
+	} else if (cfg->line_outs == 3) { /* 6 channels */
+		for(i = 0; i < cfg->line_outs; i++) {
+			nid = cfg->line_out_pins[i];
+			if (nid) {
+				/* config dac list */
+				switch(i) {
+				case AUTO_SEQ_FRONT:
+					/* AOW0 */
+					spec->multiout.dac_nids[i] = 0x10;
+					break;
+				case AUTO_SEQ_CENLFE:
+					/* AOW2 */
+					spec->multiout.dac_nids[i] = 0x12;
+					break;
+				case AUTO_SEQ_SURROUND:
+					/* AOW1 */
+					spec->multiout.dac_nids[i] = 0x11;
+					break;
+				default:
+					break;
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
+					     const struct auto_pin_cfg *cfg)
+{
+	char name[32];
+	static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+	hda_nid_t nid = 0;
+	int i, err;
+
+	for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
+		nid = cfg->line_out_pins[i];
+
+		if (!nid)	
+			continue;
+
+		if (i == AUTO_SEQ_CENLFE) {
+			/* Center/LFE */
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+					      "Center Playback Volume",
+					      HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+					      "LFE Playback Volume",
+					      HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+					      "Center Playback Switch",
+					      HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+					      "LFE Playback Switch",
+					      HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		} else if (i == AUTO_SEQ_FRONT){
+			/* add control to mixer index 0 */
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+					      "Master Front Playback Volume",
+					      HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT));
+			if (err < 0)
+				return err;
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+					      "Master Front Playback Switch",
+					      HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT));
+			if (err < 0)
+				return err;
+			
+			/* add control to PW3 */
+			sprintf(name, "%s Playback Volume", chname[i]);
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+					      HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			sprintf(name, "%s Playback Switch", chname[i]);
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+					      HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		} else if (i == AUTO_SEQ_SURROUND) {
+			sprintf(name, "%s Playback Volume", chname[i]);
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+					      HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			sprintf(name, "%s Playback Switch", chname[i]);
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+					      HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		} else if (i == AUTO_SEQ_SIDE) {
+			sprintf(name, "%s Playback Volume", chname[i]);
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+					      HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			sprintf(name, "%s Playback Switch", chname[i]);
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+					      HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		}
+	}
+
+	return 0;
+}
+
+static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+	int err;
+
+	if (!pin)
+		return 0;
+
+	if (spec->multiout.num_dacs == 5) /* 10 channels */
+		spec->multiout.hp_nid = VT1709_HP_DAC_NID;
+	else if (spec->multiout.num_dacs == 3) /* 6 channels */
+		spec->multiout.hp_nid = 0;
+
+	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+			      "Headphone Playback Volume",
+			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+	if (err < 0)
+		return err;
+	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+			      "Headphone Playback Switch",
+			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
+						const struct auto_pin_cfg *cfg)
+{
+	static char *labels[] = {
+		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
+	};
+	struct hda_input_mux *imux = &spec->private_imux;
+	int i, err, idx = 0;
+
+	/* for internal loopback recording select */
+	imux->items[imux->num_items].label = "Stereo Mixer";
+	imux->items[imux->num_items].index = idx;
+	imux->num_items++;
+
+	for (i = 0; i < AUTO_PIN_LAST; i++) {
+		if (!cfg->input_pins[i])
+			continue;
+
+		switch (cfg->input_pins[i]) {
+		case 0x1d: /* Mic */
+			idx = 2;
+			break;
+				
+		case 0x1e: /* Line In */
+			idx = 3;
+			break;
+
+		case 0x21: /* Front Mic */
+			idx = 4;
+			break;
+
+		case 0x23: /* CD */
+			idx = 1;
+			break;
+		}
+		err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
+					   idx, 0x18);
+		if (err < 0)
+			return err;
+		imux->items[imux->num_items].label = labels[i];
+		imux->items[imux->num_items].index = idx;
+		imux->num_items++;
+	}
+	return 0;
+}
+
+static int vt1709_parse_auto_config(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int err;
+
+	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+	if (err < 0)
+		return err;
+	err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+		return 0; /* can't find valid BIOS pin config */
+
+	err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+	if (err < 0)
+		return err;
+	err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+
+	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+	if (spec->autocfg.dig_out_pin)
+		spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
+	if (spec->autocfg.dig_in_pin)
+		spec->dig_in_nid = VT1709_DIGIN_NID;
+
+	if (spec->kctl_alloc)
+		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+	spec->input_mux = &spec->private_imux;
+
+	return 1;
+}
+
+static int patch_vt1709_10ch(struct hda_codec *codec)
+{
+	struct via_spec *spec;
+	int err;
+
+	/* create a codec specific record */
+	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	err = vt1709_parse_auto_config(codec);
+	if (err < 0) {
+		via_free(codec);
+		return err;
+	} else if (!err) {
+		printk(KERN_INFO "hda_codec: Cannot set up configuration.  "
+		       "Using genenic mode...\n");
+	}
+
+	spec->init_verbs = vt1709_10ch_volume_init_verbs;	
+
+	spec->stream_name_analog = "VT1709 Analog";
+	spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
+	spec->stream_analog_capture = &vt1709_pcm_analog_capture;
+
+	spec->stream_name_digital = "VT1709 Digital";
+	spec->stream_digital_playback = &vt1709_pcm_digital_playback;
+	spec->stream_digital_capture = &vt1709_pcm_digital_capture;
+
+	
+	if (!spec->adc_nids && spec->input_mux) {
+		spec->adc_nids = vt1709_adc_nids;
+		spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
+		spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
+		spec->num_mixers++;
+	}
+
+	codec->patch_ops = via_patch_ops;
+
+	codec->patch_ops.init = via_auto_init;
+
+	return 0;
+}
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
+	/*
+	 * Unmute ADC0-2 and set the default input to mic-in
+	 */
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+	 * mixer widget
+	 */
+	/* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+	/*
+	 * Set up output selector (0x1a, 0x1b, 0x29)
+	 */
+	/* set vol=0 to output mixers */
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+	/*
+	 *  Unmute PW3 and PW4
+	 */
+	{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+	/* Set input of PW4 as MW0 */
+	{0x20, AC_VERB_SET_CONNECT_SEL, 0},
+	/* Set mic as default input of sw0 */
+	{0x19, AC_VERB_SET_CONNECT_SEL, 0x2},
+	/* PW9 Output enable */
+	{0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	{ }
+};
+
+static int patch_vt1709_6ch(struct hda_codec *codec)
+{
+	struct via_spec *spec;
+	int err;
+
+	/* create a codec specific record */
+	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	err = vt1709_parse_auto_config(codec);
+	if (err < 0) {
+		via_free(codec);
+		return err;
+	} else if (!err) {
+		printk(KERN_INFO "hda_codec: Cannot set up configuration.  "
+		       "Using genenic mode...\n");
+	}
+
+	spec->init_verbs = vt1709_6ch_volume_init_verbs;	
+
+	spec->stream_name_analog = "VT1709 Analog";
+	spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
+	spec->stream_analog_capture = &vt1709_pcm_analog_capture;
+
+	spec->stream_name_digital = "VT1709 Digital";
+	spec->stream_digital_playback = &vt1709_pcm_digital_playback;
+	spec->stream_digital_capture = &vt1709_pcm_digital_capture;
+
+	
+	if (!spec->adc_nids && spec->input_mux) {
+		spec->adc_nids = vt1709_adc_nids;
+		spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
+		spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
+		spec->num_mixers++;
+	}
+
+	codec->patch_ops = via_patch_ops;
+
+	codec->patch_ops.init = via_auto_init;
+
+	return 0;
+}
+
+/*
+ * patch entries
+ */
+struct hda_codec_preset snd_hda_preset_via[] = {
+	{ .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708},
+	{ .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708},
+	{ .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708},
+	{ .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708},
+	{ .id = 0x1106E710, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
+	{ .id = 0x1106E711, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
+	{ .id = 0x1106E712, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
+	{ .id = 0x1106E713, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
+	{ .id = 0x1106E714, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
+	{ .id = 0x1106E715, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
+	{ .id = 0x1106E716, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
+	{ .id = 0x1106E717, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
+	{} /* terminator */
+};
diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile
index 7837cef..6efdd62 100644
--- a/sound/pci/ice1712/Makefile
+++ b/sound/pci/ice1712/Makefile
@@ -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 vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o
+snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o wtm.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o
diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c
index 59c4078..6e22d32 100644
--- a/sound/pci/ice1712/amp.c
+++ b/sound/pci/ice1712/amp.c
@@ -42,7 +42,7 @@
 
 static int __devinit snd_vt1724_amp_init(struct snd_ice1712 *ice)
 {
-	static unsigned short wm_inits[] = {
+	static const unsigned short wm_inits[] = {
 		WM_ATTEN_L,	0x0000,	/* 0 db */
 		WM_ATTEN_R,	0x0000,	/* 0 db */
 		WM_DAC_CTRL,	0x0008,	/* 24bit I2S */
@@ -75,7 +75,7 @@
 
 
 /* entry point */
-struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = {
 	{
 		.subvendor = VT1724_SUBDEVICE_AV710,
 		.name = "Chaintech AV-710",
diff --git a/sound/pci/ice1712/amp.h b/sound/pci/ice1712/amp.h
index a0fc89b..7b667ba 100644
--- a/sound/pci/ice1712/amp.h
+++ b/sound/pci/ice1712/amp.h
@@ -42,7 +42,7 @@
 #define WM_DAC_CTRL	0x02
 #define WM_INT_CTRL	0x03
 
-extern struct snd_ice1712_card_info  snd_vt1724_amp_cards[];
+extern const struct snd_ice1712_card_info  snd_vt1724_amp_cards[];
 
 
 #endif /* __SOUND_AMP_H */
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c
index 9e76ceb..6941d85 100644
--- a/sound/pci/ice1712/aureon.c
+++ b/sound/pci/ice1712/aureon.c
@@ -294,7 +294,7 @@
 static int aureon_ac97_init (struct snd_ice1712 *ice)
 {
 	int i;
-	static unsigned short ac97_defaults[] = {
+	static const unsigned short ac97_defaults[] = {
 		0x00, 0x9640,
 		0x02, 0x8000,
 		0x04, 0x8000,
@@ -474,7 +474,8 @@
 
 	tmp = snd_ice1712_gpio_read(ice);
 
-	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT) {
+	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
+	    ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) {
 		snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS));
 		mosi = PRODIGY_SPI_MOSI;
 		clk = PRODIGY_SPI_CLK;
@@ -601,7 +602,9 @@
 static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
 {
 	aureon_spi_write(ice,
-			(ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ? PRODIGY_WM_CS : AUREON_WM_CS),
+			 ((ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
+			   ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) ?
+			 PRODIGY_WM_CS : AUREON_WM_CS),
 			(reg << 9) | (val & 0x1ff), 16);
 }
 
@@ -661,17 +664,17 @@
 	return change;
 }
 
-static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
-static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
-static DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0);
 
 /*
  * Logarithmic volume values for WM8770
  * Computed as 20 * Log10(255 / x)
  */
-static unsigned char wm_vol[256] = {
+static const unsigned char wm_vol[256] = {
 	127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
 	23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
 	17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
@@ -1064,14 +1067,14 @@
  */
 static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = {
+	static const char * const texts[] = {
 		"CD",		//AIN1
 		"Aux",		//AIN2
 		"Line",		//AIN3
 		"Mic",		//AIN4
 		"AC97"		//AIN5
 	};
-	static char *universe_texts[] = {
+	static const char * const universe_texts[] = {
 		"Aux1",		//AIN1
 		"CD",		//AIN2
 		"Phono",	//AIN3
@@ -1137,11 +1140,11 @@
 static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	static char *aureon_texts[] = {
+	static const char * const aureon_texts[] = {
 		"CD",		//RXP0
 		"Optical"	//RXP1
 	};
-	static char *prodigy_texts[] = {
+	static const char * const prodigy_texts[] = {
 		"CD",
 		"Coax"
 	};
@@ -1288,12 +1291,14 @@
 
 	tmp2 = tmp = snd_ice1712_gpio_read(ice);
 	if (enable)
-		if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT)
+		if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
+		    ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
 			tmp |= AUREON_HP_SEL;
 		else
 			tmp |= PRODIGY_HP_SEL;
 	else
-		if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT)
+		if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
+		    ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
 			tmp &= ~ AUREON_HP_SEL;
 		else
 			tmp &= ~ PRODIGY_HP_SEL;
@@ -1363,7 +1368,7 @@
  */
 static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[2] = { "128x", "64x"	};
+	static const char * const texts[2] = { "128x", "64x"	};
 
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
@@ -1406,7 +1411,7 @@
  * mixers
  */
 
-static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
+static const struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
@@ -1521,7 +1526,7 @@
 	}
 };
 
-static struct snd_kcontrol_new wm_controls[] __devinitdata = {
+static const struct snd_kcontrol_new wm_controls[] __devinitdata = {
  	{
  		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "PCM Playback Switch",
@@ -1587,7 +1592,7 @@
 	}
 };
 
-static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
+static const struct snd_kcontrol_new ac97_controls[] __devinitdata = {
  	{
  		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "AC97 Playback Switch",
@@ -1692,7 +1697,7 @@
  	}
 };
 
-static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
+static const struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
  	{
  		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "AC97 Playback Switch",
@@ -1824,8 +1829,7 @@
 
 };
 
-	
-static struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
+static const struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH),
@@ -1870,7 +1874,6 @@
 	}
 };
 
- 
 static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
 {
 	unsigned int i, counts;
@@ -1898,7 +1901,8 @@
 				return err;
 		}
 	}
-	else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
+	else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
+		 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
 		for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) {
 			err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice));
 			if (err < 0)
@@ -1906,7 +1910,8 @@
 		}
 	}
 
-	if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
+	if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
+	    ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
 		unsigned char id;
 		snd_ice1712_save_gpio_status(ice);
 		id = aureon_cs8415_get(ice, CS8415_ID);
@@ -1936,7 +1941,7 @@
  */
 static int __devinit aureon_init(struct snd_ice1712 *ice)
 {
-	static unsigned short wm_inits_aureon[] = {
+	static const unsigned short wm_inits_aureon[] = {
 		/* These come first to reduce init pop noise */
 		0x1b, 0x044,		/* ADC Mux (AC'97 source) */
 		0x1c, 0x00B,		/* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
@@ -1972,7 +1977,7 @@
 		0x1a, 0x000,		/* -12dB ADC/R */
 		(unsigned short)-1
 	};
-	static unsigned short wm_inits_prodigy[] = {
+	static const unsigned short wm_inits_prodigy[] = {
 
 		/* These come first to reduce init pop noise */
 		0x1b, 0x000,		/* ADC Mux */
@@ -2014,7 +2019,7 @@
 		(unsigned short)-1
 
 	};
-	static unsigned short cs_inits[] = {
+	static const unsigned short cs_inits[] = {
 		0x0441, /* RUN */
 		0x0180, /* no mute, OMCK output on RMCK pin */
 		0x0201, /* S/PDIF source on RXP1 */
@@ -2022,7 +2027,7 @@
 		(unsigned short)-1
 	};
 	unsigned int tmp;
-	unsigned short *p;
+	const unsigned short *p;
 	int err, i;
 
 	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
@@ -2062,7 +2067,8 @@
 
 	/* initialize WM8770 codec */
 	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 ||
-		ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT)
+		ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
+	        ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT)
 		p = wm_inits_prodigy;
 	else
 		p = wm_inits_aureon;
@@ -2070,7 +2076,8 @@
 		wm_put(ice, p[0], p[1]);
 
 	/* initialize CS8415A codec */
-	if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
+	if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
+	    ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
 		for (p = cs_inits; *p != (unsigned short)-1; p++)
 			aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
 		ice->spec.aureon.cs8415_mux = 1;
@@ -2100,73 +2107,58 @@
  * hence the driver needs to sets up it properly.
  */
 
-static unsigned char aureon51_eeprom[] __devinitdata = {
-	0x0a,	/* SYSCONF: clock 512, spdif-in/ADC, 3DACs */
-	0x80,	/* ACLINK: I2S */
-	0xfc,	/* I2S: vol, 96k, 24bit, 192k */
-	0xc3,	/* SPDIF: out-en, out-int, spdif-in */
-	0xff,	/* GPIO_DIR */
-	0xff,	/* GPIO_DIR1 */
-	0x5f,	/* GPIO_DIR2 */
-	0x00,	/* GPIO_MASK */
-	0x00,	/* GPIO_MASK1 */
-	0x00,	/* GPIO_MASK2 */
-	0x00,	/* GPIO_STATE */
-	0x00,	/* GPIO_STATE1 */
-	0x00,	/* GPIO_STATE2 */
+static const unsigned char aureon51_eeprom[] __devinitdata = {
+	[ICE_EEP2_SYSCONF]     = 0x0a,	/* clock 512, spdif-in/ADC, 3DACs */
+	[ICE_EEP2_ACLINK]      = 0x80,	/* I2S */
+	[ICE_EEP2_I2S]         = 0xfc,	/* vol, 96k, 24bit, 192k */
+	[ICE_EEP2_SPDIF]       = 0xc3,	/* out-en, out-int, spdif-in */
+	[ICE_EEP2_GPIO_DIR]    = 0xff,
+	[ICE_EEP2_GPIO_DIR1]   = 0xff,
+	[ICE_EEP2_GPIO_DIR2]   = 0x5f,
+	[ICE_EEP2_GPIO_MASK]   = 0x00,
+	[ICE_EEP2_GPIO_MASK1]  = 0x00,
+	[ICE_EEP2_GPIO_MASK2]  = 0x00,
+	[ICE_EEP2_GPIO_STATE]  = 0x00,
+	[ICE_EEP2_GPIO_STATE1] = 0x00,
+	[ICE_EEP2_GPIO_STATE2] = 0x00,
 };
 
-static unsigned char aureon71_eeprom[] __devinitdata = {
-	0x0b,	/* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
-	0x80,	/* ACLINK: I2S */
-	0xfc,	/* I2S: vol, 96k, 24bit, 192k */
-	0xc3,	/* SPDIF: out-en, out-int, spdif-in */
-	0xff,	/* GPIO_DIR */
-	0xff,	/* GPIO_DIR1 */
-	0x5f,	/* GPIO_DIR2 */
-	0x00,	/* GPIO_MASK */
-	0x00,	/* GPIO_MASK1 */
-	0x00,	/* GPIO_MASK2 */
-	0x00,	/* GPIO_STATE */
-	0x00,	/* GPIO_STATE1 */
-	0x00,	/* GPIO_STATE2 */
+static const unsigned char aureon71_eeprom[] __devinitdata = {
+	[ICE_EEP2_SYSCONF]     = 0x0b,	/* clock 512, spdif-in/ADC, 4DACs */
+	[ICE_EEP2_ACLINK]      = 0x80,	/* I2S */
+	[ICE_EEP2_I2S]         = 0xfc,	/* vol, 96k, 24bit, 192k */
+	[ICE_EEP2_SPDIF]       = 0xc3,	/* out-en, out-int, spdif-in */
+	[ICE_EEP2_GPIO_DIR]    = 0xff,
+	[ICE_EEP2_GPIO_DIR1]   = 0xff,
+	[ICE_EEP2_GPIO_DIR2]   = 0x5f,
+	[ICE_EEP2_GPIO_MASK]   = 0x00,
+	[ICE_EEP2_GPIO_MASK1]  = 0x00,
+	[ICE_EEP2_GPIO_MASK2]  = 0x00,
+	[ICE_EEP2_GPIO_STATE]  = 0x00,
+	[ICE_EEP2_GPIO_STATE1] = 0x00,
+	[ICE_EEP2_GPIO_STATE2] = 0x00,
 };
+#define prodigy71_eeprom aureon71_eeprom
 
-static unsigned char prodigy71_eeprom[] __devinitdata = {
-	0x0b,	/* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
-	0x80,	/* ACLINK: I2S */
-	0xfc,	/* I2S: vol, 96k, 24bit, 192k */
-	0xc3,	/* SPDIF: out-en, out-int, spdif-in */
-	0xff,	/* GPIO_DIR */
-	0xff,	/* GPIO_DIR1 */
-	0x5f,	/* GPIO_DIR2 */
-	0x00,	/* GPIO_MASK */
-	0x00,	/* GPIO_MASK1 */
-	0x00,	/* GPIO_MASK2 */
-	0x00,	/* GPIO_STATE */
-	0x00,	/* GPIO_STATE1 */
-	0x00,	/* GPIO_STATE2 */
+static const unsigned char prodigy71lt_eeprom[] __devinitdata = {
+	[ICE_EEP2_SYSCONF]     = 0x4b,	/* clock 384, spdif-in/ADC, 4DACs */
+	[ICE_EEP2_ACLINK]      = 0x80,	/* I2S */
+	[ICE_EEP2_I2S]         = 0xfc,	/* vol, 96k, 24bit, 192k */
+	[ICE_EEP2_SPDIF]       = 0xc3,	/* out-en, out-int, spdif-in */
+	[ICE_EEP2_GPIO_DIR]    = 0xff,
+	[ICE_EEP2_GPIO_DIR1]   = 0xff,
+	[ICE_EEP2_GPIO_DIR2]   = 0x5f,
+	[ICE_EEP2_GPIO_MASK]   = 0x00,
+	[ICE_EEP2_GPIO_MASK1]  = 0x00,
+	[ICE_EEP2_GPIO_MASK2]  = 0x00,
+	[ICE_EEP2_GPIO_STATE]  = 0x00,
+	[ICE_EEP2_GPIO_STATE1] = 0x00,
+	[ICE_EEP2_GPIO_STATE2] = 0x00,
 };
-
-static unsigned char prodigy71lt_eeprom[] __devinitdata = {
-	0x4b,	/* SYSCINF: clock 512, spdif-in/ADC, 4DACs */
-	0x80,	/* ACLINK: I2S */
-	0xfc,	/* I2S: vol, 96k, 24bit, 192k */
-	0xc3,	/* SPDIF: out-en, out-int, spdif-in */
-	0xff,	/* GPIO_DIR */
-	0xff,	/* GPIO_DIR1 */
-	0x5f,	/* GPIO_DIR2 */
-	0x00,	/* GPIO_MASK */
-	0x00,	/* GPIO_MASK1 */
-	0x00,	/* GPIO_MASK2 */
-	0x00,	/* GPIO_STATE */
-	0x00,	/* GPIO_STATE1 */
-	0x00,	/* GPIO_STATE2 */
-};
-	
+#define prodigy71xt_eeprom prodigy71lt_eeprom
 
 /* entry point */
-struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
 	{
 		.subvendor = VT1724_SUBDEVICE_AUREON51_SKY,
 		.name = "Terratec Aureon 5.1-Sky",
@@ -2217,5 +2209,15 @@
 		.eeprom_data = prodigy71lt_eeprom,
 		.driver = "Prodigy71LT",
 	},
+	{
+		.subvendor = VT1724_SUBDEVICE_PRODIGY71XT,
+		.name = "Audiotrak Prodigy 7.1 XT",
+		.model = "prodigy71xt",
+		.chip_init = aureon_init,
+		.build_controls = aureon_add_controls,
+		.eeprom_size = sizeof(prodigy71xt_eeprom),
+		.eeprom_data = prodigy71xt_eeprom,
+		.driver = "Prodigy71LT",
+	},
 	{ } /* terminator */
 };
diff --git a/sound/pci/ice1712/aureon.h b/sound/pci/ice1712/aureon.h
index 3b7bea6..79e58e8 100644
--- a/sound/pci/ice1712/aureon.h
+++ b/sound/pci/ice1712/aureon.h
@@ -28,15 +28,17 @@
 				       "{Terratec,Aureon 7.1 Space},"\
 				       "{Terratec,Aureon 7.1 Universe}," \
 					"{AudioTrak,Prodigy 7.1}," \
-					"{AudioTrak,Prodigy 7.1 LT},"
+					"{AudioTrak,Prodigy 7.1 LT},"\
+					"{AudioTrak,Prodigy 7.1 XT},"
 
 #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 */
 #define VT1724_SUBDEVICE_PRODIGY71LT	0x32315441	/* PRODIGY 7.1 LT */
+#define VT1724_SUBDEVICE_PRODIGY71XT	0x36315441	/* PRODIGY 7.1 XT*/
 
-extern struct snd_ice1712_card_info  snd_vt1724_aureon_cards[];
+extern const struct snd_ice1712_card_info  snd_vt1724_aureon_cards[];
 
 /* GPIO bits */
 #define AUREON_CS8415_CS	(1 << 22)
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index af65980..3eeb36c 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -416,7 +416,7 @@
 	return 0;
 }
 
-static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devinitdata =
 {
 	.access =	(SNDRV_CTL_ELEM_ACCESS_READ),
 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -429,7 +429,7 @@
  * initialize the chips on M-Audio cards
  */
 
-static struct snd_akm4xxx akm_audiophile __devinitdata = {
+static const struct snd_akm4xxx akm_audiophile __devinitdata = {
 	.type = SND_AK4528,
 	.num_adcs = 2,
 	.num_dacs = 2,
@@ -438,7 +438,7 @@
 	}
 };
 
-static struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = {
 	.caddr = 2,
 	.cif = 0,
 	.data_mask = ICE1712_DELTA_AP_DOUT,
@@ -450,7 +450,7 @@
 	.mask_flags = 0,
 };
 
-static struct snd_akm4xxx akm_delta410 __devinitdata = {
+static const struct snd_akm4xxx akm_delta410 __devinitdata = {
 	.type = SND_AK4529,
 	.num_adcs = 2,
 	.num_dacs = 8,
@@ -459,7 +459,7 @@
 	}
 };
 
-static struct snd_ak4xxx_private akm_delta410_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_delta410_priv __devinitdata = {
 	.caddr = 0,
 	.cif = 0,
 	.data_mask = ICE1712_DELTA_AP_DOUT,
@@ -471,7 +471,7 @@
 	.mask_flags = 0,
 };
 
-static struct snd_akm4xxx akm_delta1010lt __devinitdata = {
+static const struct snd_akm4xxx akm_delta1010lt __devinitdata = {
 	.type = SND_AK4524,
 	.num_adcs = 8,
 	.num_dacs = 8,
@@ -481,7 +481,7 @@
 	}
 };
 
-static struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = {
 	.caddr = 2,
 	.cif = 0, /* the default level of the CIF pin from AK4524 */
 	.data_mask = ICE1712_DELTA_1010LT_DOUT,
@@ -493,7 +493,7 @@
 	.mask_flags = 0,
 };
 
-static struct snd_akm4xxx akm_delta44 __devinitdata = {
+static const struct snd_akm4xxx akm_delta44 __devinitdata = {
 	.type = SND_AK4524,
 	.num_adcs = 4,
 	.num_dacs = 4,
@@ -503,7 +503,7 @@
 	}
 };
 
-static struct snd_ak4xxx_private akm_delta44_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_delta44_priv __devinitdata = {
 	.caddr = 2,
 	.cif = 0, /* the default level of the CIF pin from AK4524 */
 	.data_mask = ICE1712_DELTA_CODEC_SERIAL_DATA,
@@ -515,7 +515,7 @@
 	.mask_flags = 0,
 };
 
-static struct snd_akm4xxx akm_vx442 __devinitdata = {
+static const struct snd_akm4xxx akm_vx442 __devinitdata = {
 	.type = SND_AK4524,
 	.num_adcs = 4,
 	.num_dacs = 4,
@@ -525,7 +525,7 @@
 	}
 };
 
-static struct snd_ak4xxx_private akm_vx442_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_vx442_priv __devinitdata = {
 	.caddr = 2,
 	.cif = 0,
 	.data_mask = ICE1712_VX442_DOUT,
@@ -650,15 +650,15 @@
  * additional controls for M-Audio cards
  */
 
-static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_select __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_select __devinitdata =
 ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0);
-static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_select __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_select __devinitdata =
 ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 0, 0);
-static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_status __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_status __devinitdata =
 ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
-static struct snd_kcontrol_new snd_ice1712_deltadio2496_spdif_in_select __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_deltadio2496_spdif_in_select __devinitdata =
 ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, ICE1712_DELTA_SPDIF_INPUT_SELECT, 0, 0);
-static struct snd_kcontrol_new snd_ice1712_delta_spdif_in_status __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_delta_spdif_in_status __devinitdata =
 ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Delta IEC958 Input Status", 0, ICE1712_DELTA_SPDIF_IN_STAT, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
 
 
@@ -735,7 +735,7 @@
 
 
 /* entry point */
-struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = {
 	{
 		.subvendor = ICE1712_SUBDEVICE_DELTA1010,
 		.name = "M Audio Delta 1010",
diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h
index 746ebde..e65d669 100644
--- a/sound/pci/ice1712/delta.h
+++ b/sound/pci/ice1712/delta.h
@@ -46,7 +46,7 @@
 #define ICE1712_SUBDEVICE_MEDIASTATION	0x694c0100
 
 /* entry point */
-extern struct snd_ice1712_card_info snd_ice1712_delta_cards[];
+extern const struct snd_ice1712_card_info snd_ice1712_delta_cards[];
 
 
 /*
diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c
index b135389..9b7ff30 100644
--- a/sound/pci/ice1712/ews.c
+++ b/sound/pci/ice1712/ews.c
@@ -332,7 +332,7 @@
 
 /*
  */
-static struct snd_akm4xxx akm_ews88mt __devinitdata = {
+static const struct snd_akm4xxx akm_ews88mt __devinitdata = {
 	.num_adcs = 8,
 	.num_dacs = 8,
 	.type = SND_AK4524,
@@ -342,7 +342,7 @@
 	}
 };
 
-static struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = {
 	.caddr = 2,
 	.cif = 1, /* CIF high */
 	.data_mask = ICE1712_EWS88_SERIAL_DATA,
@@ -354,7 +354,7 @@
 	.mask_flags = 0,
 };
 
-static struct snd_akm4xxx akm_ewx2496 __devinitdata = {
+static const struct snd_akm4xxx akm_ewx2496 __devinitdata = {
 	.num_adcs = 2,
 	.num_dacs = 2,
 	.type = SND_AK4524,
@@ -363,7 +363,7 @@
 	}
 };
 
-static struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = {
 	.caddr = 2,
 	.cif = 1, /* CIF high */
 	.data_mask = ICE1712_EWS88_SERIAL_DATA,
@@ -375,7 +375,7 @@
 	.mask_flags = 0,
 };
 
-static struct snd_akm4xxx akm_6fire __devinitdata = {
+static const struct snd_akm4xxx akm_6fire __devinitdata = {
 	.num_adcs = 6,
 	.num_dacs = 6,
 	.type = SND_AK4524,
@@ -384,7 +384,7 @@
 	}
 };
 
-static struct snd_ak4xxx_private akm_6fire_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_6fire_priv __devinitdata = {
 	.caddr = 2,
 	.cif = 1, /* CIF high */
 	.data_mask = ICE1712_6FIRE_SERIAL_DATA,
@@ -578,7 +578,7 @@
 	return val != nval;
 }
 
-static struct snd_kcontrol_new snd_ice1712_ewx2496_controls[] __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_ewx2496_controls[] __devinitdata = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Input Sensitivity Switch",
@@ -678,7 +678,7 @@
 	return ndata != data;
 }
 
-static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Input Sensitivity Switch",
 	.info = snd_ice1712_ewx_io_sense_info,
@@ -687,7 +687,7 @@
 	.count = 8,
 };
 
-static struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Output Sensitivity Switch",
 	.info = snd_ice1712_ewx_io_sense_info,
@@ -769,7 +769,7 @@
   .private_value = xshift | (xinvert << 8),\
 }
 
-static struct snd_kcontrol_new snd_ice1712_ews88d_controls[] __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_ews88d_controls[] __devinitdata = {
 	EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, 1, 0), /* inverted */
 	EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT Output Optical", 1, 0, 0),
 	EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT External Master Clock", 2, 0, 0),
@@ -909,7 +909,7 @@
   .private_value = xshift | (xinvert << 8),\
 }
 
-static struct snd_kcontrol_new snd_ice1712_6fire_controls[] __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_6fire_controls[] __devinitdata = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Analog Input Select",
@@ -989,7 +989,7 @@
 
 
 /* entry point */
-struct snd_ice1712_card_info snd_ice1712_ews_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_ice1712_ews_cards[] __devinitdata = {
 	{
 		.subvendor = ICE1712_SUBDEVICE_EWX2496,
 		.name = "TerraTec EWX24/96",
diff --git a/sound/pci/ice1712/ews.h b/sound/pci/ice1712/ews.h
index a12a0b0..df449b4 100644
--- a/sound/pci/ice1712/ews.h
+++ b/sound/pci/ice1712/ews.h
@@ -40,7 +40,7 @@
 #define ICE1712_SUBDEVICE_PHASE88	0x3b155111
 
 /* entry point */
-extern struct snd_ice1712_card_info snd_ice1712_ews_cards[];
+extern const struct snd_ice1712_card_info snd_ice1712_ews_cards[];
 
 
 /* TerraTec EWX 24/96 configuration definitions */
diff --git a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c
index 3f27d04..df97313 100644
--- a/sound/pci/ice1712/hoontech.c
+++ b/sound/pci/ice1712/hoontech.c
@@ -239,7 +239,7 @@
 static int __devinit snd_ice1712_value_init(struct snd_ice1712 *ice)
 {
 	/* Hoontech STDSP24 with modified hardware */
-	static struct snd_akm4xxx akm_stdsp24_mv __devinitdata = {
+	static const struct snd_akm4xxx akm_stdsp24_mv __devinitdata = {
 		.num_adcs = 2,
 		.num_dacs = 2,
 		.type = SND_AK4524,
@@ -248,7 +248,7 @@
 		}
 	};
 
-	static struct snd_ak4xxx_private akm_stdsp24_mv_priv __devinitdata = {
+	static const struct snd_ak4xxx_private akm_stdsp24_mv_priv __devinitdata = {
 		.caddr = 2,
 		.cif = 1, /* CIF high */
 		.data_mask = ICE1712_STDSP24_SERIAL_DATA,
@@ -298,7 +298,7 @@
 
 
 /* entry point */
-struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = {
 	{
 		.subvendor = ICE1712_SUBDEVICE_STDSP24,
 		.name = "Hoontech SoundTrack Audio DSP24",
@@ -325,4 +325,3 @@
 	},
 	{ } /* terminator */
 };
-
diff --git a/sound/pci/ice1712/hoontech.h b/sound/pci/ice1712/hoontech.h
index 1ee538b..b62d6e4 100644
--- a/sound/pci/ice1712/hoontech.h
+++ b/sound/pci/ice1712/hoontech.h
@@ -35,7 +35,7 @@
 #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[];
+extern const struct snd_ice1712_card_info snd_ice1712_hoontech_cards[];
 
 
 /* Hoontech SoundTrack Audio DSP 24 GPIO definitions */
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 8ba31cf..830a1bb 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -107,7 +107,7 @@
 MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE.");
 
 
-static struct pci_device_id snd_ice1712_ids[] = {
+static const struct pci_device_id snd_ice1712_ids[] = {
 	{ PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_ICE_1712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },   /* ICE1712 */
 	{ 0, }
 };
@@ -287,7 +287,7 @@
 	return val != nval;
 }
 
-static struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Digital Mixer To AC97",
 	.info = snd_ice1712_digmix_route_ac97_info,
@@ -719,7 +719,7 @@
 	return bytes_to_frames(substream->runtime, ptr);
 }
 
-static struct snd_pcm_hardware snd_ice1712_playback =
+static const struct snd_pcm_hardware snd_ice1712_playback =
 {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -739,7 +739,7 @@
 	.fifo_size =		0,
 };
 
-static struct snd_pcm_hardware snd_ice1712_playback_ds =
+static const struct snd_pcm_hardware snd_ice1712_playback_ds =
 {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -759,7 +759,7 @@
 	.fifo_size =		0,
 };
 
-static struct snd_pcm_hardware snd_ice1712_capture =
+static const struct snd_pcm_hardware snd_ice1712_capture =
 {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -1133,7 +1133,7 @@
 	return bytes_to_frames(substream->runtime, ptr);
 }
 
-static struct snd_pcm_hardware snd_ice1712_playback_pro =
+static const struct snd_pcm_hardware snd_ice1712_playback_pro =
 {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -1153,7 +1153,7 @@
 	.fifo_size =		0,
 };
 
-static struct snd_pcm_hardware snd_ice1712_capture_pro =
+static const struct snd_pcm_hardware snd_ice1712_capture_pro =
 {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -1378,9 +1378,9 @@
 	return change;
 }
 
-static DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0);
 
-static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Multi Playback Switch",
@@ -1404,7 +1404,7 @@
 	},
 };
 
-static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "H/W Multi Capture Switch",
 	.info = snd_ice1712_pro_mixer_switch_info,
@@ -1413,7 +1413,7 @@
 	.private_value = 10,
 };
 
-static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,SWITCH),
 	.info = snd_ice1712_pro_mixer_switch_info,
@@ -1423,7 +1423,7 @@
 	.count = 2,
 };
 
-static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
 		   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
@@ -1435,7 +1435,7 @@
 	.tlv = { .p = db_scale_playback }
 };
 
-static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,VOLUME),
 	.info = snd_ice1712_pro_mixer_volume_info,
@@ -1627,7 +1627,7 @@
 	return 0;
 }
 
-static struct snd_kcontrol_new snd_ice1712_eeprom __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_eeprom __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_CARD,
 	.name = "ICE1712 EEPROM",
 	.access = SNDRV_CTL_ELEM_ACCESS_READ,
@@ -1663,7 +1663,7 @@
 	return 0;
 }
 
-static struct snd_kcontrol_new snd_ice1712_spdif_default __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_spdif_default __devinitdata =
 {
 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
@@ -1714,7 +1714,7 @@
 	return 0;
 }
 
-static struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata =
 {
 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1723,7 +1723,7 @@
 	.get =		snd_ice1712_spdif_maskc_get,
 };
 
-static struct snd_kcontrol_new snd_ice1712_spdif_maskp __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_spdif_maskp __devinitdata =
 {
 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1750,7 +1750,7 @@
 	return 0;
 }
 
-static struct snd_kcontrol_new snd_ice1712_spdif_stream __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_spdif_stream __devinitdata =
 {
 	.access =	(SNDRV_CTL_ELEM_ACCESS_READWRITE |
 			 SNDRV_CTL_ELEM_ACCESS_INACTIVE),
@@ -1811,7 +1811,7 @@
 static int snd_ice1712_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
 					       struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = {
+	static const char * const texts[] = {
 		"8000",		/* 0: 6 */
 		"9600",		/* 1: 3 */
 		"11025",	/* 2: 10 */
@@ -1840,7 +1840,7 @@
 					      struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	static unsigned char xlate[16] = {
+	static const unsigned char xlate[16] = {
 		9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 255, 255, 255, 10
 	};
 	unsigned char val;
@@ -1864,7 +1864,7 @@
 					      struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	static unsigned int xrate[13] = {
+	static const unsigned int xrate[13] = {
 		8000, 9600, 11025, 12000, 16000, 22050, 24000,
 		32000, 44100, 48000, 64000, 88200, 96000
 	};
@@ -1891,7 +1891,7 @@
 	return change;
 }
 
-static struct snd_kcontrol_new snd_ice1712_pro_internal_clock __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_pro_internal_clock __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Multi Track Internal Clock",
 	.info = snd_ice1712_pro_internal_clock_info,
@@ -1902,7 +1902,7 @@
 static int snd_ice1712_pro_internal_clock_default_info(struct snd_kcontrol *kcontrol,
 						       struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = {
+	static const char * const texts[] = {
 		"8000",		/* 0: 6 */
 		"9600",		/* 1: 3 */
 		"11025",	/* 2: 10 */
@@ -1931,7 +1931,7 @@
 						      struct snd_ctl_elem_value *ucontrol)
 {
 	int val;
-	static unsigned int xrate[13] = {
+	static const unsigned int xrate[13] = {
 		8000, 9600, 11025, 12000, 16000, 22050, 24000,
 		32000, 44100, 48000, 64000, 88200, 96000
 	};
@@ -1948,7 +1948,7 @@
 static int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcontrol,
 						      struct snd_ctl_elem_value *ucontrol)
 {
-	static unsigned int xrate[13] = {
+	static const unsigned int xrate[13] = {
 		8000, 9600, 11025, 12000, 16000, 22050, 24000,
 		32000, 44100, 48000, 64000, 88200, 96000
 	};
@@ -1962,7 +1962,7 @@
 	return change;
 }
 
-static struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default __devinitdata = {
+static const struct snd_kcontrol_new 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,
@@ -2001,7 +2001,7 @@
 	return change;
 }
 
-static struct snd_kcontrol_new snd_ice1712_pro_rate_locking __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_pro_rate_locking __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Multi Track Rate Locking",
 	.info = snd_ice1712_pro_rate_locking_info,
@@ -2040,7 +2040,7 @@
 	return change;
 }
 
-static struct snd_kcontrol_new snd_ice1712_pro_rate_reset __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_pro_rate_reset __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Multi Track Rate Reset",
 	.info = snd_ice1712_pro_rate_reset_info,
@@ -2054,7 +2054,7 @@
 static int snd_ice1712_pro_route_info(struct snd_kcontrol *kcontrol,
 				      struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = {
+	static const char * const texts[] = {
 		"PCM Out", /* 0 */
 		"H/W In 0", "H/W In 1", "H/W In 2", "H/W In 3", /* 1-4 */
 		"H/W In 4", "H/W In 5", "H/W In 6", "H/W In 7", /* 5-8 */
@@ -2207,7 +2207,7 @@
 	return change;
 }
 
-static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "H/W Playback Route",
 	.info = snd_ice1712_pro_route_info,
@@ -2215,7 +2215,7 @@
 	.put = snd_ice1712_pro_route_analog_put,
 };
 
-static struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
 	.info = snd_ice1712_pro_route_info,
@@ -2257,7 +2257,7 @@
 	return change;
 }
 
-static struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Multi Track Volume Rate",
 	.info = snd_ice1712_pro_volume_rate_info,
@@ -2290,7 +2290,7 @@
 	return 0;
 }
 
-static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Multi Track Peak",
 	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
@@ -2305,7 +2305,7 @@
 /*
  * list of available boards
  */
-static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
+static const struct snd_ice1712_card_info *card_tables[] __devinitdata = {
 	snd_ice1712_hoontech_cards,
 	snd_ice1712_delta_cards,
 	snd_ice1712_ews_cards,
@@ -2329,7 +2329,7 @@
 {
 	int dev = 0xa0;		/* EEPROM device address */
 	unsigned int i, size;
-	struct snd_ice1712_card_info **tbl, *c;
+	const struct snd_ice1712_card_info **tbl, *c;
 
 	if (! modelname || ! *modelname) {
 		ice->eeprom.subvendor = 0;
@@ -2658,7 +2658,7 @@
  *
  */
 
-static struct snd_ice1712_card_info no_matched __devinitdata;
+static const struct snd_ice1712_card_info no_matched __devinitdata;
 
 static int __devinit snd_ice1712_probe(struct pci_dev *pci,
 				       const struct pci_device_id *pci_id)
@@ -2667,7 +2667,7 @@
 	struct snd_card *card;
 	struct snd_ice1712 *ice;
 	int pcm_dev = 0, err;
-	struct snd_ice1712_card_info **tbl, *c;
+	const struct snd_ice1712_card_info **tbl, *c;
 
 	if (dev >= SNDRV_CARDS)
 		return -ENODEV;
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
index ce27eac..c3d9fea 100644
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -28,6 +28,7 @@
 #include <sound/i2c.h>
 #include <sound/ak4xxx-adda.h>
 #include <sound/ak4114.h>
+#include <sound/pt2258.h>
 #include <sound/pcm.h>
 #include <sound/mpu401.h>
 
@@ -381,6 +382,11 @@
 			unsigned short master[2];
 			unsigned short vol[8];
 		} phase28;
+		/* a non-standard I2C device for revo51 */
+		struct revo51_spec {
+			struct snd_i2c_device *dev;
+			struct snd_pt2258 *pt2258;
+		} revo51;
 		/* Hoontech-specific setting */
 		struct hoontech_spec {
 			unsigned char boxbits[4];
@@ -462,6 +468,14 @@
 	snd_ice1712_gpio_write(ice, mask & bits);
 }
 
+static inline int snd_ice1712_gpio_read_bits(struct snd_ice1712 *ice,
+					      unsigned int mask)
+{
+	ice->gpio.direction &= ~mask;
+	snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
+	return  (snd_ice1712_gpio_read(ice) & mask);
+}
+
 int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice);
 
 int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak, const struct snd_akm4xxx *template,
@@ -500,8 +514,8 @@
 	unsigned int mpu401_2_info_flags;
 	const char *mpu401_1_name;
 	const char *mpu401_2_name;
-	unsigned int eeprom_size;
-	unsigned char *eeprom_data;
+	const unsigned int eeprom_size;
+	const unsigned char *eeprom_data;
 };
 
 
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 3e3a102..1127ebd 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -50,7 +50,7 @@
 #include "prodigy192.h"
 #include "juli.h"
 #include "phase.h"
-
+#include "wtm.h"
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
 MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)");
@@ -64,6 +64,7 @@
 	       PRODIGY192_DEVICE_DESC
 	       JULI_DEVICE_DESC
 	       PHASE_DEVICE_DESC
+	       WTM_DEVICE_DESC
 		"{VIA,VT1720},"
 		"{VIA,VT1724},"
 		"{ICEnsemble,Generic ICE1724},"
@@ -86,7 +87,7 @@
 
 
 /* Both VT1720 and VT1724 have the same PCI IDs */
-static struct pci_device_id snd_vt1724_ids[] = {
+static const 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, }
 };
@@ -341,7 +342,7 @@
 
 	what = 0;
 	snd_pcm_group_for_each(pos, substream) {
-		struct vt1724_pcm_reg *reg;
+		const struct vt1724_pcm_reg *reg;
 		s = snd_pcm_group_substream_entry(pos);
 		reg = s->runtime->private_data;
 		what |= reg->start;
@@ -605,7 +606,7 @@
 static int snd_vt1724_pcm_prepare(struct snd_pcm_substream *substream)
 {
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
-	struct vt1724_pcm_reg *reg = substream->runtime->private_data;
+	const struct vt1724_pcm_reg *reg = substream->runtime->private_data;
 
 	spin_lock_irq(&ice->reg_lock);
 	outl(substream->runtime->dma_addr, ice->profi_port + reg->addr);
@@ -620,7 +621,7 @@
 static snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substream)
 {
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
-	struct vt1724_pcm_reg *reg = substream->runtime->private_data;
+	const struct vt1724_pcm_reg *reg = substream->runtime->private_data;
 	size_t ptr;
 
 	if (!(inl(ICEMT1724(ice, DMA_CONTROL)) & reg->start))
@@ -646,21 +647,21 @@
 #endif
 }
 
-static struct vt1724_pcm_reg vt1724_playback_pro_reg = {
+static const struct vt1724_pcm_reg vt1724_playback_pro_reg = {
 	.addr = VT1724_MT_PLAYBACK_ADDR,
 	.size = VT1724_MT_PLAYBACK_SIZE,
 	.count = VT1724_MT_PLAYBACK_COUNT,
 	.start = VT1724_PDMA0_START,
 };
 
-static struct vt1724_pcm_reg vt1724_capture_pro_reg = {
+static const struct vt1724_pcm_reg vt1724_capture_pro_reg = {
 	.addr = VT1724_MT_CAPTURE_ADDR,
 	.size = VT1724_MT_CAPTURE_SIZE,
 	.count = VT1724_MT_CAPTURE_COUNT,
 	.start = VT1724_RDMA0_START,
 };
 
-static struct snd_pcm_hardware snd_vt1724_playback_pro =
+static const struct snd_pcm_hardware snd_vt1724_playback_pro =
 {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -679,7 +680,7 @@
 	.periods_max =		1024,
 };
 
-static struct snd_pcm_hardware snd_vt1724_spdif =
+static const struct snd_pcm_hardware snd_vt1724_spdif =
 {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -701,7 +702,7 @@
 	.periods_max =		1024,
 };
 
-static struct snd_pcm_hardware snd_vt1724_2ch_stereo =
+static const struct snd_pcm_hardware snd_vt1724_2ch_stereo =
 {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -773,7 +774,7 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 	int chs;
 
-	runtime->private_data = &vt1724_playback_pro_reg;
+	runtime->private_data = (void *)&vt1724_playback_pro_reg;
 	ice->playback_pro_substream = substream;
 	runtime->hw = snd_vt1724_playback_pro;
 	snd_pcm_set_sync(substream);
@@ -802,7 +803,7 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
-	runtime->private_data = &vt1724_capture_pro_reg;
+	runtime->private_data = (void *)&vt1724_capture_pro_reg;
 	ice->capture_pro_substream = substream;
 	runtime->hw = snd_vt1724_2ch_stereo;
 	snd_pcm_set_sync(substream);
@@ -888,14 +889,14 @@
  * SPDIF PCM
  */
 
-static struct vt1724_pcm_reg vt1724_playback_spdif_reg = {
+static const struct vt1724_pcm_reg vt1724_playback_spdif_reg = {
 	.addr = VT1724_MT_PDMA4_ADDR,
 	.size = VT1724_MT_PDMA4_SIZE,
 	.count = VT1724_MT_PDMA4_COUNT,
 	.start = VT1724_PDMA4_START,
 };
 
-static struct vt1724_pcm_reg vt1724_capture_spdif_reg = {
+static const struct vt1724_pcm_reg vt1724_capture_spdif_reg = {
 	.addr = VT1724_MT_RDMA1_ADDR,
 	.size = VT1724_MT_RDMA1_SIZE,
 	.count = VT1724_MT_RDMA1_COUNT,
@@ -953,7 +954,7 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
-	runtime->private_data = &vt1724_playback_spdif_reg;
+	runtime->private_data = (void *)&vt1724_playback_spdif_reg;
 	ice->playback_con_substream = substream;
 	if (ice->force_pdma4) {
 		runtime->hw = snd_vt1724_2ch_stereo;
@@ -985,7 +986,7 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
-	runtime->private_data = &vt1724_capture_spdif_reg;
+	runtime->private_data = (void *)&vt1724_capture_spdif_reg;
 	ice->capture_con_substream = substream;
 	if (ice->force_rdma1) {
 		runtime->hw = snd_vt1724_2ch_stereo;
@@ -1090,7 +1091,7 @@
  * independent surround PCMs
  */
 
-static struct vt1724_pcm_reg vt1724_playback_dma_regs[3] = {
+static const struct vt1724_pcm_reg vt1724_playback_dma_regs[3] = {
 	{
 		.addr = VT1724_MT_PDMA1_ADDR,
 		.size = VT1724_MT_PDMA1_SIZE,
@@ -1136,7 +1137,7 @@
 		return -EBUSY; /* FIXME: should handle blocking mode properly */
 	}
 	mutex_unlock(&ice->open_mutex);
-	runtime->private_data = &vt1724_playback_dma_regs[substream->number];
+	runtime->private_data = (void *)&vt1724_playback_dma_regs[substream->number];
 	ice->playback_con_substream_ds[substream->number] = substream;
 	runtime->hw = snd_vt1724_2ch_stereo;
 	snd_pcm_set_sync(substream);
@@ -1317,7 +1318,7 @@
 	return 0;
 }
 
-static struct snd_kcontrol_new snd_vt1724_eeprom __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_eeprom __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_CARD,
 	.name = "ICE1724 EEPROM",
 	.access = SNDRV_CTL_ELEM_ACCESS_READ,
@@ -1430,7 +1431,7 @@
 	return (val != old);
 }
 
-static struct snd_kcontrol_new snd_vt1724_spdif_default __devinitdata =
+static const struct snd_kcontrol_new snd_vt1724_spdif_default __devinitdata =
 {
 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
@@ -1462,7 +1463,7 @@
 	return 0;
 }
 
-static struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata =
+static const struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata =
 {
 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1471,7 +1472,7 @@
 	.get =		snd_vt1724_spdif_maskc_get,
 };
 
-static struct snd_kcontrol_new snd_vt1724_spdif_maskp __devinitdata =
+static const struct snd_kcontrol_new snd_vt1724_spdif_maskp __devinitdata =
 {
 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1516,7 +1517,7 @@
 	return old != val;
 }
 
-static struct snd_kcontrol_new snd_vt1724_spdif_switch __devinitdata =
+static const struct snd_kcontrol_new snd_vt1724_spdif_switch __devinitdata =
 {
 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
 	/* FIXME: the following conflict with IEC958 Playback Route */
@@ -1584,7 +1585,7 @@
 static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
 					      struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts_1724[] = {
+	static const char * const texts_1724[] = {
 		"8000",		/* 0: 6 */
 		"9600",		/* 1: 3 */
 		"11025",	/* 2: 10 */
@@ -1602,7 +1603,7 @@
 		"192000",	/* 14: 14 */
 		"IEC958 Input",	/* 15: -- */
 	};
-	static char *texts_1720[] = {
+	static const char * const texts_1720[] = {
 		"8000",		/* 0: 6 */
 		"9600",		/* 1: 3 */
 		"11025",	/* 2: 10 */
@@ -1635,7 +1636,7 @@
 					     struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	static unsigned char xlate[16] = {
+	static const unsigned char xlate[16] = {
 		9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 13, 255, 14, 10
 	};
 	unsigned char val;
@@ -1694,7 +1695,7 @@
 	return change;
 }
 
-static struct snd_kcontrol_new snd_vt1724_pro_internal_clock __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_pro_internal_clock __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Multi Track Internal Clock",
 	.info = snd_vt1724_pro_internal_clock_info,
@@ -1733,7 +1734,7 @@
 	return change;
 }
 
-static struct snd_kcontrol_new snd_vt1724_pro_rate_locking __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_pro_rate_locking __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Multi Track Rate Locking",
 	.info = snd_vt1724_pro_rate_locking_info,
@@ -1772,7 +1773,7 @@
 	return change;
 }
 
-static struct snd_kcontrol_new snd_vt1724_pro_rate_reset __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_pro_rate_reset __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Multi Track Rate Reset",
 	.info = snd_vt1724_pro_rate_reset_info,
@@ -1816,7 +1817,7 @@
 {
 	unsigned long val;
 	unsigned char eitem;
-	static unsigned char xlate[8] = {
+	static const unsigned char xlate[8] = {
 		0, 255, 1, 2, 255, 255, 3, 4,
 	};
 
@@ -1835,7 +1836,7 @@
 {
 	unsigned int old_val, nval;
 	int change;
-	static unsigned char xroute[8] = {
+	static const unsigned char xroute[8] = {
 		0, /* PCM */
 		2, /* PSDIN0 Left */
 		3, /* PSDIN0 Right */
@@ -1891,7 +1892,7 @@
 			     digital_route_shift(idx));
 }
 
-static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "H/W Playback Route",
 	.info = snd_vt1724_pro_route_info,
@@ -1899,7 +1900,7 @@
 	.put = snd_vt1724_pro_route_analog_put,
 };
 
-static struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
 	.info = snd_vt1724_pro_route_info,
@@ -1935,7 +1936,7 @@
 	return 0;
 }
 
-static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Multi Track Peak",
 	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
@@ -1947,9 +1948,9 @@
  *
  */
 
-static struct snd_ice1712_card_info no_matched __devinitdata;
+static const struct snd_ice1712_card_info no_matched __devinitdata;
 
-static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
+static const struct snd_ice1712_card_info *card_tables[] __devinitdata = {
 	snd_vt1724_revo_cards,
 	snd_vt1724_amp_cards, 
 	snd_vt1724_aureon_cards,
@@ -1958,6 +1959,7 @@
 	snd_vt1724_prodigy192_cards,
 	snd_vt1724_juli_cards,
 	snd_vt1724_phase_cards,
+	snd_vt1724_wtm_cards,
 	NULL,
 };
 
@@ -2007,7 +2009,7 @@
 {
 	const int dev = 0xa0;		/* EEPROM device address */
 	unsigned int i, size;
-	struct snd_ice1712_card_info **tbl, *c;
+	const struct snd_ice1712_card_info **tbl, *c;
 
 	if (! modelname || ! *modelname) {
 		ice->eeprom.subvendor = 0;
@@ -2306,7 +2308,7 @@
 	struct snd_card *card;
 	struct snd_ice1712 *ice;
 	int pcm_dev = 0, err;
-	struct snd_ice1712_card_info **tbl, *c;
+	const struct snd_ice1712_card_info **tbl, *c;
 
 	if (dev >= SNDRV_CARDS)
 		return -ENODEV;
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c
index 5176b41..d88172f 100644
--- a/sound/pci/ice1712/juli.c
+++ b/sound/pci/ice1712/juli.c
@@ -125,7 +125,7 @@
 	snd_akm4xxx_reset(ak, 0);
 }
 
-static struct snd_akm4xxx akm_juli_dac __devinitdata = {
+static const struct snd_akm4xxx akm_juli_dac __devinitdata = {
 	.type = SND_AK4358,
 	.num_dacs = 2,
 	.ops = {
@@ -146,7 +146,7 @@
  */
 static int __devinit juli_init(struct snd_ice1712 *ice)
 {
-	static unsigned char ak4114_init_vals[] = {
+	static const unsigned char ak4114_init_vals[] = {
 		/* AK4117_REG_PWRDN */	AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1,
 		/* AK4114_REQ_FORMAT */	AK4114_DIF_I24I2S,
 		/* AK4114_REG_IO0 */	AK4114_TX1E,
@@ -154,7 +154,7 @@
 		/* AK4114_REG_INT0_MASK */ 0,
 		/* AK4114_REG_INT1_MASK */ 0
 	};
-	static unsigned char ak4114_init_txcsb[] = {
+	static const unsigned char ak4114_init_txcsb[] = {
 		0x41, 0x02, 0x2c, 0x00, 0x00
 	};
 	int err;
@@ -206,24 +206,24 @@
  * hence the driver needs to sets up it properly.
  */
 
-static unsigned char juli_eeprom[] __devinitdata = {
-	0x20,	/* SYSCONF: clock 512, mpu401, 1xADC, 1xDACs */
-	0x80,	/* ACLINK: I2S */
-	0xf8,	/* I2S: vol, 96k, 24bit, 192k */
-	0xc3,	/* SPDIF: out-en, out-int, spdif-in */
-	0x9f,	/* GPIO_DIR */
-	0xff,	/* GPIO_DIR1 */
-	0x7f,	/* GPIO_DIR2 */
-	0x9f,	/* GPIO_MASK */
-	0xff,	/* GPIO_MASK1 */
-	0x7f,	/* GPIO_MASK2 */
-	0x16,	/* GPIO_STATE: internal clock, multiple 1x, 48kHz */
-	0x80,	/* GPIO_STATE1: mute */
-	0x00,	/* GPIO_STATE2 */
+static const unsigned char juli_eeprom[] __devinitdata = {
+	[ICE_EEP2_SYSCONF]     = 0x20,	/* clock 512, mpu401, 1xADC, 1xDACs */
+	[ICE_EEP2_ACLINK]      = 0x80,	/* I2S */
+	[ICE_EEP2_I2S]         = 0xf8,	/* vol, 96k, 24bit, 192k */
+	[ICE_EEP2_SPDIF]       = 0xc3,	/* out-en, out-int, spdif-in */
+	[ICE_EEP2_GPIO_DIR]    = 0x9f,
+	[ICE_EEP2_GPIO_DIR1]   = 0xff,
+	[ICE_EEP2_GPIO_DIR2]   = 0x7f,
+	[ICE_EEP2_GPIO_MASK]   = 0x9f,
+	[ICE_EEP2_GPIO_MASK1]  = 0xff,
+	[ICE_EEP2_GPIO_MASK2]  = 0x7f,
+	[ICE_EEP2_GPIO_STATE]  = 0x16,	/* internal clock, multiple 1x, 48kHz */
+	[ICE_EEP2_GPIO_STATE1] = 0x80,	/* mute */
+	[ICE_EEP2_GPIO_STATE2] = 0x00,
 };
 
 /* entry point */
-struct snd_ice1712_card_info snd_vt1724_juli_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1724_juli_cards[] __devinitdata = {
 	{
 		.subvendor = VT1724_SUBDEVICE_JULI,
 		.name = "ESI Juli@",
diff --git a/sound/pci/ice1712/juli.h b/sound/pci/ice1712/juli.h
index d9f8534..1b9294f 100644
--- a/sound/pci/ice1712/juli.h
+++ b/sound/pci/ice1712/juli.h
@@ -5,6 +5,6 @@
 
 #define VT1724_SUBDEVICE_JULI		0x31305345	/* Juli@ */
 
-extern struct snd_ice1712_card_info  snd_vt1724_juli_cards[];
+extern const struct snd_ice1712_card_info  snd_vt1724_juli_cards[];
 
 #endif	/* __SOUND_JULI_H */
diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c
index e08d73f..0751718 100644
--- a/sound/pci/ice1712/phase.c
+++ b/sound/pci/ice1712/phase.c
@@ -71,7 +71,7 @@
  * Logarithmic volume values for WM8770
  * Computed as 20 * Log10(255 / x)
  */
-static unsigned char wm_vol[256] = {
+static const unsigned char wm_vol[256] = {
 	127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
 	23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
 	17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
@@ -89,13 +89,13 @@
 #define WM_VOL_MAX	(sizeof(wm_vol) - 1)
 #define WM_VOL_MUTE	0x8000
 
-static struct snd_akm4xxx akm_phase22 __devinitdata = {
+static const struct snd_akm4xxx akm_phase22 __devinitdata = {
 	.type = SND_AK4524,
 	.num_dacs = 2,
 	.num_adcs = 2,
 };
 
-static struct snd_ak4xxx_private akm_phase22_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_phase22_priv __devinitdata = {
 	.caddr =	2,
 	.cif =		1,
 	.data_mask =	1 << 4,
@@ -152,36 +152,36 @@
 	return 0;
 }
 
-static unsigned char phase22_eeprom[] __devinitdata = {
-	0x00,	/* SYSCONF: 1xADC, 1xDACs */
-	0x80,	/* ACLINK: I2S */
-	0xf8,	/* I2S: vol, 96k, 24bit*/
-	0xc3,	/* SPDIF: out-en, out-int, spdif-in */
-	0xFF,	/* GPIO_DIR */
-	0xFF,	/* GPIO_DIR1 */
-	0xFF,	/* GPIO_DIR2 */
-	0x00,	/* GPIO_MASK */
-	0x00,	/* GPIO_MASK1 */
-	0x00,	/* GPIO_MASK2 */
-	0x00,	/* GPIO_STATE: */
-	0x00,	/* GPIO_STATE1: */
-	0x00,	/* GPIO_STATE2 */
+static const unsigned char phase22_eeprom[] __devinitdata = {
+	[ICE_EEP2_SYSCONF]     = 0x00,	/* 1xADC, 1xDACs */
+	[ICE_EEP2_ACLINK]      = 0x80,	/* I2S */
+	[ICE_EEP2_I2S]         = 0xf8,	/* vol, 96k, 24bit */
+	[ICE_EEP2_SPDIF]       = 0xc3,	/* out-en, out-int, spdif-in */
+	[ICE_EEP2_GPIO_DIR]    = 0xff,
+	[ICE_EEP2_GPIO_DIR1]   = 0xff,
+	[ICE_EEP2_GPIO_DIR2]   = 0xff,
+	[ICE_EEP2_GPIO_MASK]   = 0x00,
+	[ICE_EEP2_GPIO_MASK1]  = 0x00,
+	[ICE_EEP2_GPIO_MASK2]  = 0x00,
+	[ICE_EEP2_GPIO_STATE]  = 0x00,
+	[ICE_EEP2_GPIO_STATE1] = 0x00,
+	[ICE_EEP2_GPIO_STATE2] = 0x00,
 };
 
-static unsigned char phase28_eeprom[] __devinitdata = {
-	0x0b,	/* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
-	0x80,	/* ACLINK: I2S */
-	0xfc,	/* I2S: vol, 96k, 24bit, 192k */
-	0xc3,	/* SPDIF: out-en, out-int, spdif-in */
-	0xff,	/* GPIO_DIR */
-	0xff,	/* GPIO_DIR1 */
-	0x5f,	/* GPIO_DIR2 */
-	0x00,	/* GPIO_MASK */
-	0x00,	/* GPIO_MASK1 */
-	0x00,	/* GPIO_MASK2 */
-	0x00,	/* GPIO_STATE */
-	0x00,	/* GPIO_STATE1 */
-	0x00,	/* GPIO_STATE2 */
+static const unsigned char phase28_eeprom[] __devinitdata = {
+	[ICE_EEP2_SYSCONF]     = 0x0b,	/* clock 512, spdif-in/ADC, 4DACs */
+	[ICE_EEP2_ACLINK]      = 0x80,	/* I2S */
+	[ICE_EEP2_I2S]         = 0xfc,	/* vol, 96k, 24bit, 192k */
+	[ICE_EEP2_SPDIF]       = 0xc3,	/* out-en, out-int, spdif-in */
+	[ICE_EEP2_GPIO_DIR]    = 0xff,
+	[ICE_EEP2_GPIO_DIR1]   = 0xff,
+	[ICE_EEP2_GPIO_DIR2]   = 0x5f,
+	[ICE_EEP2_GPIO_MASK]   = 0x00,
+	[ICE_EEP2_GPIO_MASK1]  = 0x00,
+	[ICE_EEP2_GPIO_MASK2]  = 0x00,
+	[ICE_EEP2_GPIO_STATE]  = 0x00,
+	[ICE_EEP2_GPIO_STATE1] = 0x00,
+	[ICE_EEP2_GPIO_STATE2] = 0x00,
 };
 
 /*
@@ -343,7 +343,7 @@
 
 static int __devinit phase28_init(struct snd_ice1712 *ice)
 {
-	static unsigned short wm_inits_phase28[] = {
+	static const unsigned short wm_inits_phase28[] = {
 		/* These come first to reduce init pop noise */
 		0x1b, 0x044,		/* ADC Mux (AC'97 source) */
 		0x1c, 0x00B,		/* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
@@ -382,7 +382,7 @@
 
 	unsigned int tmp;
 	struct snd_akm4xxx *ak;
-	unsigned short *p;
+	const unsigned short *p;
 	int i;
 
 	ice->num_total_dacs = 8;
@@ -697,10 +697,10 @@
 	return 0;
 }
 
-static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
-static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
 
-static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
+static const struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
@@ -815,7 +815,7 @@
 	}
 };
 
-static struct snd_kcontrol_new wm_controls[] __devinitdata = {
+static const struct snd_kcontrol_new wm_controls[] __devinitdata = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "PCM Playback Switch",
@@ -870,7 +870,7 @@
 	return 0;
 }
 
-struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = {
 	{
 		.subvendor = VT1724_SUBDEVICE_PHASE22,
 		.name = "Terratec PHASE 22",
diff --git a/sound/pci/ice1712/phase.h b/sound/pci/ice1712/phase.h
index 13e841b..ad379a9 100644
--- a/sound/pci/ice1712/phase.h
+++ b/sound/pci/ice1712/phase.h
@@ -31,7 +31,7 @@
 #define VT1724_SUBDEVICE_PHASE28	0x3b154911
 
 /* entry point */
-extern struct snd_ice1712_card_info snd_vt1724_phase_cards[];
+extern const struct snd_ice1712_card_info snd_vt1724_phase_cards[];
 
 /* PHASE28 GPIO bits */
 #define PHASE28_SPI_MISO	(1 << 21)
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c
index 6c74c2d..9552497 100644
--- a/sound/pci/ice1712/pontis.c
+++ b/sound/pci/ice1712/pontis.c
@@ -434,7 +434,7 @@
  */
 static int cs_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = {
+	static const char * const texts[] = {
 		"Coax",		/* RXP0 */
 		"Optical",	/* RXP1 */
 		"CD",		/* RXP2 */
@@ -565,13 +565,13 @@
 	return changed;
 }
 
-static DECLARE_TLV_DB_SCALE(db_scale_volume, -6400, 50, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_volume, -6400, 50, 1);
 
 /*
  * mixers
  */
 
-static struct snd_kcontrol_new pontis_controls[] __devinitdata = {
+static const struct snd_kcontrol_new pontis_controls[] __devinitdata = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
@@ -741,7 +741,7 @@
  */
 static int __devinit pontis_init(struct snd_ice1712 *ice)
 {
-	static unsigned short wm_inits[] = {
+	static const unsigned short wm_inits[] = {
 		/* These come first to reduce init pop noise */
 		WM_ADC_MUX,	0x00c0,	/* ADC mute */
 		WM_DAC_MUTE,	0x0001,	/* DAC softmute */
@@ -750,7 +750,7 @@
 		WM_POWERDOWN,	0x0008,	/* All power-up except HP */
 		WM_RESET,	0x0000,	/* reset */
 	};
-	static unsigned short wm_inits2[] = {
+	static const unsigned short wm_inits2[] = {
 		WM_MASTER_CTRL,	0x0022,	/* 256fs, slave mode */
 		WM_DAC_INT,	0x0022,	/* I2S, normal polarity, 24bit */
 		WM_ADC_INT,	0x0022,	/* I2S, normal polarity, 24bit */
@@ -776,7 +776,7 @@
 		WM_DAC_MUTE,	0x0000,	/* DAC unmute */
 		WM_ADC_MUX,	0x0003,	/* ADC unmute, both CD/Line On */
 	};
-	static unsigned char cs_inits[] = {
+	static const unsigned char cs_inits[] = {
 		0x04,	0x80,	/* RUN, RXP0 */
 		0x05,	0x05,	/* slave, 24bit */
 		0x01,	0x00,
@@ -826,24 +826,24 @@
  * hence the driver needs to sets up it properly.
  */
 
-static unsigned char pontis_eeprom[] __devinitdata = {
-	0x08,	/* SYSCONF: clock 256, mpu401, spdif-in/ADC, 1DAC */
-	0x80,	/* ACLINK: I2S */
-	0xf8,	/* I2S: vol, 96k, 24bit, 192k */
-	0xc3,	/* SPDIF: out-en, out-int, spdif-in */
-	0x07,	/* GPIO_DIR */
-	0x00,	/* GPIO_DIR1 */
-	0x00,	/* GPIO_DIR2 (ignored) */
-	0x0f,	/* GPIO_MASK (4-7 reserved for CS8416) */
-	0xff,	/* GPIO_MASK1 */
-	0x00,	/* GPIO_MASK2 (ignored) */
-	0x06,	/* GPIO_STATE (0-low, 1-high, 2-high) */
-	0x00,	/* GPIO_STATE1 */
-	0x00,	/* GPIO_STATE2 (ignored) */
+static const unsigned char pontis_eeprom[] __devinitdata = {
+	[ICE_EEP2_SYSCONF]     = 0x08,	/* clock 256, mpu401, spdif-in/ADC, 1DAC */
+	[ICE_EEP2_ACLINK]      = 0x80,	/* I2S */
+	[ICE_EEP2_I2S]         = 0xf8,	/* vol, 96k, 24bit, 192k */
+	[ICE_EEP2_SPDIF]       = 0xc3,	/* out-en, out-int, spdif-in */
+	[ICE_EEP2_GPIO_DIR]    = 0x07,
+	[ICE_EEP2_GPIO_DIR1]   = 0x00,
+	[ICE_EEP2_GPIO_DIR2]   = 0x00,	/* ignored */
+	[ICE_EEP2_GPIO_MASK]   = 0x0f,	/* 4-7 reserved for CS8416 */
+	[ICE_EEP2_GPIO_MASK1]  = 0xff,
+	[ICE_EEP2_GPIO_MASK2]  = 0x00,	/* ignored */
+	[ICE_EEP2_GPIO_STATE]  = 0x06,	/* 0-low, 1-high, 2-high */
+	[ICE_EEP2_GPIO_STATE1] = 0x00,
+	[ICE_EEP2_GPIO_STATE2] = 0x00,	/* ignored */
 };
 
 /* entry point */
-struct snd_ice1712_card_info snd_vt1720_pontis_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1720_pontis_cards[] __devinitdata = {
 	{
 		.subvendor = VT1720_SUBDEVICE_PONTIS_MS300,
 		.name = "Pontis MS300",
diff --git a/sound/pci/ice1712/pontis.h b/sound/pci/ice1712/pontis.h
index d0d1378..1a41825 100644
--- a/sound/pci/ice1712/pontis.h
+++ b/sound/pci/ice1712/pontis.h
@@ -28,6 +28,6 @@
 
 #define VT1720_SUBDEVICE_PONTIS_MS300	0x00020002	/* a dummy id for MS300 */
 
-extern struct snd_ice1712_card_info  snd_vt1720_pontis_cards[];
+extern const struct snd_ice1712_card_info  snd_vt1720_pontis_cards[];
 
 #endif /* __SOUND_PONTIS_H */
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c
index 41b2605..31cc66e 100644
--- a/sound/pci/ice1712/prodigy192.c
+++ b/sound/pci/ice1712/prodigy192.c
@@ -357,14 +357,14 @@
 }
 #endif
 
-static DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0);
 
 /*
  * mixers
  */
 
-static struct snd_kcontrol_new stac_controls[] __devinitdata = {
+static const struct snd_kcontrol_new stac_controls[] __devinitdata = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
@@ -475,7 +475,7 @@
  */
 static int __devinit prodigy192_init(struct snd_ice1712 *ice)
 {
-	static unsigned short stac_inits_prodigy[] = {
+	static const unsigned short stac_inits_prodigy[] = {
 		STAC946X_RESET, 0,
 /*		STAC946X_MASTER_VOLUME, 0,
 		STAC946X_LF_VOLUME, 0,
@@ -486,7 +486,7 @@
 		STAC946X_LFE_VOLUME, 0,*/
 		(unsigned short)-1
 	};
-	unsigned short *p;
+	const unsigned short *p;
 
 	/* prodigy 192 */
 	ice->num_total_dacs = 6;
@@ -506,25 +506,25 @@
  * 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 */
+static const unsigned char prodigy71_eeprom[] __devinitdata = {
+	[ICE_EEP2_SYSCONF]     = 0x2b,	/* clock 512, mpu401, spdif-in/ADC, 4DACs */
+	[ICE_EEP2_ACLINK]      = 0x80,	/* I2S */
+	[ICE_EEP2_I2S]         = 0xf8,	/* vol, 96k, 24bit, 192k */
+	[ICE_EEP2_SPDIF]       = 0xc3,	/* out-en, out-int, spdif-in */
+	[ICE_EEP2_GPIO_DIR]    = 0xff,
+	[ICE_EEP2_GPIO_DIR1]   = 0xff,
+	[ICE_EEP2_GPIO_DIR2]   = 0xbf,
+	[ICE_EEP2_GPIO_MASK]   = 0x00,
+	[ICE_EEP2_GPIO_MASK1]  = 0x00,
+	[ICE_EEP2_GPIO_MASK2]  = 0x00,
+	[ICE_EEP2_GPIO_STATE]  = 0x00,
+	[ICE_EEP2_GPIO_STATE1] = 0x00,
+	[ICE_EEP2_GPIO_STATE2] = 0x00,
 };
 
 
 /* entry point */
-struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = {
 	{
 		.subvendor = VT1724_SUBDEVICE_PRODIGY192VE,
 		.name = "Audiotrak Prodigy 192",
diff --git a/sound/pci/ice1712/prodigy192.h b/sound/pci/ice1712/prodigy192.h
index 94c824e..2fa2e62 100644
--- a/sound/pci/ice1712/prodigy192.h
+++ b/sound/pci/ice1712/prodigy192.h
@@ -6,6 +6,6 @@
 
 #define VT1724_SUBDEVICE_PRODIGY192VE	 0x34495345	/* PRODIGY 192 VE */
 
-extern struct snd_ice1712_card_info  snd_vt1724_prodigy192_cards[];
+extern const struct snd_ice1712_card_info  snd_vt1724_prodigy192_cards[];
 
 #endif	/* __SOUND_PRODIGY192_H */
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c
index bf98ea3..025a7e8 100644
--- a/sound/pci/ice1712/revo.c
+++ b/sound/pci/ice1712/revo.c
@@ -84,38 +84,142 @@
 }
 
 /*
+ * I2C access to the PT2258 volume controller on GPIO 6/7 (Revolution 5.1)
+ */
+
+static void revo_i2c_start(struct snd_i2c_bus *bus)
+{
+	struct snd_ice1712 *ice = bus->private_data;
+	snd_ice1712_save_gpio_status(ice);
+}
+
+static void revo_i2c_stop(struct snd_i2c_bus *bus)
+{
+	struct snd_ice1712 *ice = bus->private_data;
+	snd_ice1712_restore_gpio_status(ice);
+}
+
+static void revo_i2c_direction(struct snd_i2c_bus *bus, int clock, int data)
+{
+	struct snd_ice1712 *ice = bus->private_data;
+	unsigned int mask, val;
+
+	val = 0;
+	if (clock)
+		val |= VT1724_REVO_I2C_CLOCK;	/* write SCL */
+	if (data)
+		val |= VT1724_REVO_I2C_DATA;	/* write SDA */
+	mask = VT1724_REVO_I2C_CLOCK | VT1724_REVO_I2C_DATA;
+	ice->gpio.direction &= ~mask;
+	ice->gpio.direction |= val;
+	snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
+	snd_ice1712_gpio_set_mask(ice, ~mask);
+}
+
+static void revo_i2c_setlines(struct snd_i2c_bus *bus, int clk, int data)
+{
+	struct snd_ice1712 *ice = bus->private_data;
+	unsigned int val = 0;
+
+	if (clk)
+		val |= VT1724_REVO_I2C_CLOCK;
+	if (data)
+		val |= VT1724_REVO_I2C_DATA;
+	snd_ice1712_gpio_write_bits(ice,
+				    VT1724_REVO_I2C_DATA |
+				    VT1724_REVO_I2C_CLOCK, val);
+	udelay(5);
+}
+
+static int revo_i2c_getdata(struct snd_i2c_bus *bus, int ack)
+{
+	struct snd_ice1712 *ice = bus->private_data;
+	int bit;
+
+	if (ack)
+		udelay(5);
+	bit = snd_ice1712_gpio_read_bits(ice, VT1724_REVO_I2C_DATA) ? 1 : 0;
+	return bit;
+}
+
+static struct snd_i2c_bit_ops revo51_bit_ops = {
+	.start = revo_i2c_start,
+	.stop = revo_i2c_stop,
+	.direction = revo_i2c_direction,
+	.setlines = revo_i2c_setlines,
+	.getdata = revo_i2c_getdata,
+};
+
+static int revo51_i2c_init(struct snd_ice1712 *ice,
+			   struct snd_pt2258 *pt)
+{
+	int err;
+
+	/* create the I2C bus */
+	err = snd_i2c_bus_create(ice->card, "ICE1724 GPIO6", NULL, &ice->i2c);
+	if (err < 0)
+		return err;
+
+	ice->i2c->private_data = ice;
+	ice->i2c->hw_ops.bit = &revo51_bit_ops;
+
+	/* create the I2C device */
+	err = snd_i2c_device_create(ice->i2c, "PT2258", 0x40,
+				    &ice->spec.revo51.dev);
+	if (err < 0)
+		return err;
+
+	pt->card = ice->card;
+	pt->i2c_bus = ice->i2c;
+	pt->i2c_dev = ice->spec.revo51.dev;
+	ice->spec.revo51.pt2258 = pt;
+
+	snd_pt2258_reset(pt);
+
+	return 0;
+}
+
+/*
  * initialize the chips on M-Audio Revolution cards
  */
 
 #define AK_DAC(xname,xch) { .name = xname, .num_channels = xch }
 
-static struct snd_akm4xxx_dac_channel revo71_front[] = {
+static const struct snd_akm4xxx_dac_channel revo71_front[] = {
 	AK_DAC("PCM Playback Volume", 2)
 };
 
-static struct snd_akm4xxx_dac_channel revo71_surround[] = {
+static const struct snd_akm4xxx_dac_channel revo71_surround[] = {
 	AK_DAC("PCM Center Playback Volume", 1),
 	AK_DAC("PCM LFE Playback Volume", 1),
 	AK_DAC("PCM Side Playback Volume", 2),
 	AK_DAC("PCM Rear Playback Volume", 2),
 };
 
-static struct snd_akm4xxx_dac_channel revo51_dac[] = {
+static const struct snd_akm4xxx_dac_channel revo51_dac[] = {
 	AK_DAC("PCM Playback Volume", 2),
 	AK_DAC("PCM Center Playback Volume", 1),
 	AK_DAC("PCM LFE Playback Volume", 1),
 	AK_DAC("PCM Rear Playback Volume", 2),
 };
 
-static struct snd_akm4xxx_adc_channel revo51_adc[] = {
+static const char *revo51_adc_input_names[] = {
+	"Mic",
+	"Line",
+	"CD",
+	NULL
+};
+
+static const struct snd_akm4xxx_adc_channel revo51_adc[] = {
 	{
 		.name = "PCM Capture Volume",
 		.switch_name = "PCM Capture Switch",
-		.num_channels = 2
+		.num_channels = 2,
+		.input_names = revo51_adc_input_names
 	},
 };
 
-static struct snd_akm4xxx akm_revo_front __devinitdata = {
+static const struct snd_akm4xxx akm_revo_front __devinitdata = {
 	.type = SND_AK4381,
 	.num_dacs = 2,
 	.ops = {
@@ -124,7 +228,7 @@
 	.dac_info = revo71_front,
 };
 
-static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = {
 	.caddr = 1,
 	.cif = 0,
 	.data_mask = VT1724_REVO_CDOUT,
@@ -136,7 +240,7 @@
 	.mask_flags = 0,
 };
 
-static struct snd_akm4xxx akm_revo_surround __devinitdata = {
+static const struct snd_akm4xxx akm_revo_surround __devinitdata = {
 	.type = SND_AK4355,
 	.idx_offset = 1,
 	.num_dacs = 6,
@@ -146,7 +250,7 @@
 	.dac_info = revo71_surround,
 };
 
-static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = {
 	.caddr = 3,
 	.cif = 0,
 	.data_mask = VT1724_REVO_CDOUT,
@@ -158,7 +262,7 @@
 	.mask_flags = 0,
 };
 
-static struct snd_akm4xxx akm_revo51 __devinitdata = {
+static const struct snd_akm4xxx akm_revo51 __devinitdata = {
 	.type = SND_AK4358,
 	.num_dacs = 6,
 	.ops = {
@@ -167,36 +271,213 @@
 	.dac_info = revo51_dac,
 };
 
-static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_revo51_priv __devinitdata = {
 	.caddr = 2,
 	.cif = 0,
 	.data_mask = VT1724_REVO_CDOUT,
 	.clk_mask = VT1724_REVO_CCLK,
-	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
-	.cs_addr = VT1724_REVO_CS1 | VT1724_REVO_CS2,
-	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
+	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1,
+	.cs_addr = VT1724_REVO_CS1,
+	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1,
 	.add_flags = VT1724_REVO_CCLK, /* high at init */
 	.mask_flags = 0,
 };
 
-static struct snd_akm4xxx akm_revo51_adc __devinitdata = {
+static const struct snd_akm4xxx akm_revo51_adc __devinitdata = {
 	.type = SND_AK5365,
 	.num_adcs = 2,
 	.adc_info = revo51_adc,
 };
 
-static struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = {
 	.caddr = 2,
 	.cif = 0,
 	.data_mask = VT1724_REVO_CDOUT,
 	.clk_mask = VT1724_REVO_CCLK,
-	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
-	.cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS2,
-	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
+	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1,
+	.cs_addr = VT1724_REVO_CS0,
+	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1,
 	.add_flags = VT1724_REVO_CCLK, /* high at init */
 	.mask_flags = 0,
 };
 
+static struct snd_pt2258 ptc_revo51_volume;
+
+/* AK4358 for AP192 DAC, AK5385A for ADC */
+static void ap192_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
+{
+	struct snd_ice1712 *ice = ak->private_data[0];
+
+	revo_set_rate_val(ak, rate);
+
+#if 1 /* FIXME: do we need this procedure? */
+	/* reset DFS pin of AK5385A for ADC, too */
+	/* DFS0 (pin 18) -- GPIO10 pin 77 */
+	snd_ice1712_save_gpio_status(ice);
+	snd_ice1712_gpio_write_bits(ice, 1 << 10,
+				    rate > 48000 ? (1 << 10) : 0);
+	snd_ice1712_restore_gpio_status(ice);
+#endif
+}
+
+static const struct snd_akm4xxx_dac_channel ap192_dac[] = {
+	AK_DAC("PCM Playback Volume", 2)
+};
+
+static const struct snd_akm4xxx akm_ap192 __devinitdata = {
+	.type = SND_AK4358,
+	.num_dacs = 2,
+	.ops = {
+		.set_rate_val = ap192_set_rate_val
+	},
+	.dac_info = ap192_dac,
+};
+
+static const struct snd_ak4xxx_private akm_ap192_priv __devinitdata = {
+	.caddr = 2,
+	.cif = 0,
+	.data_mask = VT1724_REVO_CDOUT,
+	.clk_mask = VT1724_REVO_CCLK,
+	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS3,
+	.cs_addr = VT1724_REVO_CS3,
+	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS3,
+	.add_flags = VT1724_REVO_CCLK, /* high at init */
+	.mask_flags = 0,
+};
+
+#if 0
+/* FIXME: ak4114 makes the sound much lower due to some confliction,
+ *        so let's disable it right now...
+ */
+#define BUILD_AK4114_AP192
+#endif
+
+#ifdef BUILD_AK4114_AP192
+/* AK4114 support on Audiophile 192 */
+/* CDTO (pin 32) -- GPIO2 pin 52
+ * CDTI (pin 33) -- GPIO3 pin 53 (shared with AK4358)
+ * CCLK (pin 34) -- GPIO1 pin 51 (shared with AK4358)
+ * CSN  (pin 35) -- GPIO7 pin 59
+ */
+#define AK4114_ADDR	0x00
+
+static void write_data(struct snd_ice1712 *ice, unsigned int gpio,
+		       unsigned int data, int idx)
+{
+	for (; idx >= 0; idx--) {
+		/* drop clock */
+		gpio &= ~VT1724_REVO_CCLK;
+		snd_ice1712_gpio_write(ice, gpio);
+		udelay(1);
+		/* set data */
+		if (data & (1 << idx))
+			gpio |= VT1724_REVO_CDOUT;
+		else
+			gpio &= ~VT1724_REVO_CDOUT;
+		snd_ice1712_gpio_write(ice, gpio);
+		udelay(1);
+		/* raise clock */
+		gpio |= VT1724_REVO_CCLK;
+		snd_ice1712_gpio_write(ice, gpio);
+		udelay(1);
+	}
+}
+
+static unsigned char read_data(struct snd_ice1712 *ice, unsigned int gpio,
+			       int idx)
+{
+	unsigned char data = 0;
+
+	for (; idx >= 0; idx--) {
+		/* drop clock */
+		gpio &= ~VT1724_REVO_CCLK;
+		snd_ice1712_gpio_write(ice, gpio);
+		udelay(1);
+		/* read data */
+		if (snd_ice1712_gpio_read(ice) & VT1724_REVO_CDIN)
+			data |= (1 << idx);
+		udelay(1);
+		/* raise clock */
+		gpio |= VT1724_REVO_CCLK;
+		snd_ice1712_gpio_write(ice, gpio);
+		udelay(1);
+	}
+	return data;
+}
+
+static unsigned char ap192_4wire_start(struct snd_ice1712 *ice)
+{
+	unsigned int tmp;
+
+	snd_ice1712_save_gpio_status(ice);
+	tmp = snd_ice1712_gpio_read(ice);
+	tmp |= VT1724_REVO_CCLK; /* high at init */
+	tmp |= VT1724_REVO_CS0;
+	tmp &= ~VT1724_REVO_CS3;
+	snd_ice1712_gpio_write(ice, tmp);
+	udelay(1);
+	return tmp;
+}
+
+static void ap192_4wire_finish(struct snd_ice1712 *ice, unsigned int tmp)
+{
+	tmp |= VT1724_REVO_CS3;
+	tmp |= VT1724_REVO_CS0;
+	snd_ice1712_gpio_write(ice, tmp);
+	udelay(1);
+	snd_ice1712_restore_gpio_status(ice);
+}
+
+static void ap192_ak4114_write(void *private_data, unsigned char addr,
+			       unsigned char data)
+{
+	struct snd_ice1712 *ice = private_data;
+	unsigned int tmp, addrdata;
+
+	tmp = ap192_4wire_start(ice);
+	addrdata = (AK4114_ADDR << 6) | 0x20 | (addr & 0x1f);
+	addrdata = (addrdata << 8) | data;
+	write_data(ice, tmp, addrdata, 15);
+	ap192_4wire_finish(ice, tmp);
+}
+
+static unsigned char ap192_ak4114_read(void *private_data, unsigned char addr)
+{
+	struct snd_ice1712 *ice = private_data;
+	unsigned int tmp;
+	unsigned char data;
+
+	tmp = ap192_4wire_start(ice);
+	write_data(ice, tmp, (AK4114_ADDR << 6) | (addr & 0x1f), 7);
+	data = read_data(ice, tmp, 7);
+	ap192_4wire_finish(ice, tmp);
+	return data;
+}
+
+static int ap192_ak4114_init(struct snd_ice1712 *ice)
+{
+	static const unsigned char ak4114_init_vals[] = {
+		AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1,
+		AK4114_DIF_I24I2S,
+		AK4114_TX1E,
+		AK4114_EFH_1024 | AK4114_DIT | AK4114_IPS(1),
+		0,
+		0
+	};
+	static const unsigned char ak4114_init_txcsb[] = {
+		0x41, 0x02, 0x2c, 0x00, 0x00
+	};
+	struct ak4114 *ak;
+	int err;
+
+	return snd_ak4114_create(ice->card,
+				 ap192_ak4114_read,
+				 ap192_ak4114_write,
+				 ak4114_init_vals, ak4114_init_txcsb,
+				 ice, &ak);
+}
+#endif /* BUILD_AK4114_AP192 */
+
 static int __devinit revo_init(struct snd_ice1712 *ice)
 {
 	struct snd_akm4xxx *ak;
@@ -213,6 +494,10 @@
 		ice->num_total_dacs = 6;
 		ice->num_total_adcs = 2;
 		break;
+	case VT1724_SUBDEVICE_AUDIOPHILE192:
+		ice->num_total_dacs = 2;
+		ice->num_total_adcs = 2;
+		break;
 	default:
 		snd_BUG();
 		return -EINVAL;
@@ -235,14 +520,28 @@
 		break;
 	case VT1724_SUBDEVICE_REVOLUTION51:
 		ice->akm_codecs = 2;
-		if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo51, &akm_revo51_priv, ice)) < 0)
+		err = snd_ice1712_akm4xxx_init(ak, &akm_revo51,
+					       &akm_revo51_priv, ice);
+		if (err < 0)
 			return err;
-		err = snd_ice1712_akm4xxx_init(ak + 1, &akm_revo51_adc,
+		err = snd_ice1712_akm4xxx_init(ak+1, &akm_revo51_adc,
 					       &akm_revo51_adc_priv, ice);
 		if (err < 0)
 			return err;
-		/* unmute all codecs - needed! */
-		snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE);
+		err = revo51_i2c_init(ice, &ptc_revo51_volume);
+		if (err < 0)
+			return err;
+		/* unmute all codecs */
+		snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE,
+					    VT1724_REVO_MUTE);
+		break;
+	case VT1724_SUBDEVICE_AUDIOPHILE192:
+		ice->akm_codecs = 1;
+		err = snd_ice1712_akm4xxx_init(ak, &akm_ap192, &akm_ap192_priv,
+					       ice);
+		if (err < 0)
+			return err;
+		
 		break;
 	}
 
@@ -256,16 +555,34 @@
 
 	switch (ice->eeprom.subvendor) {
 	case VT1724_SUBDEVICE_REVOLUTION71:
+		err = snd_ice1712_akm4xxx_build_controls(ice);
+		if (err < 0)
+			return err;
+		break;
 	case VT1724_SUBDEVICE_REVOLUTION51:
 		err = snd_ice1712_akm4xxx_build_controls(ice);
 		if (err < 0)
 			return err;
+		err = snd_pt2258_build_controls(ice->spec.revo51.pt2258);
+		if (err < 0)
+			return err;
+		break;
+	case VT1724_SUBDEVICE_AUDIOPHILE192:
+		err = snd_ice1712_akm4xxx_build_controls(ice);
+		if (err < 0)
+			return err;
+#ifdef BUILD_AK4114_AP192
+		err = ap192_ak4114_init(ice);
+		if (err < 0)
+			return err;
+#endif
+		break;
 	}
 	return 0;
 }
 
 /* entry point */
-struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = {
 	{
 		.subvendor = VT1724_SUBDEVICE_REVOLUTION71,
 		.name = "M Audio Revolution-7.1",
@@ -280,5 +597,12 @@
 		.chip_init = revo_init,
 		.build_controls = revo_add_controls,
 	},
+	{
+		.subvendor = VT1724_SUBDEVICE_AUDIOPHILE192,
+		.name = "M Audio Audiophile192",
+		.model = "ap192",
+		.chip_init = revo_init,
+		.build_controls = revo_add_controls,
+	},
 	{ } /* terminator */
 };
diff --git a/sound/pci/ice1712/revo.h b/sound/pci/ice1712/revo.h
index efbb86e..2a24488 100644
--- a/sound/pci/ice1712/revo.h
+++ b/sound/pci/ice1712/revo.h
@@ -26,13 +26,15 @@
 
 #define REVO_DEVICE_DESC \
 		"{MidiMan M Audio,Revolution 7.1},"\
-		"{MidiMan M Audio,Revolution 5.1},"
+		"{MidiMan M Audio,Revolution 5.1},"\
+		"{MidiMan M Audio,Audiophile 192},"
 
 #define VT1724_SUBDEVICE_REVOLUTION71	0x12143036
 #define VT1724_SUBDEVICE_REVOLUTION51	0x12143136
+#define VT1724_SUBDEVICE_AUDIOPHILE192	0x12143236
 
 /* entry point */
-extern struct snd_ice1712_card_info snd_vt1724_revo_cards[];
+extern const struct snd_ice1712_card_info snd_vt1724_revo_cards[];
 
 
 /*
@@ -42,9 +44,12 @@
 #define VT1724_REVO_CCLK	0x02
 #define VT1724_REVO_CDIN	0x04	/* not used */
 #define VT1724_REVO_CDOUT	0x08
-#define VT1724_REVO_CS0		0x10	/* AK5365 chipselect for Rev. 5.1 */
+#define VT1724_REVO_CS0		0x10	/* AK5365 chipselect for (revo51) */
 #define VT1724_REVO_CS1		0x20	/* front AKM4381 chipselect */
-#define VT1724_REVO_CS2		0x40	/* surround AKM4355 chipselect */
+#define VT1724_REVO_CS2		0x40	/* surround AKM4355 CS (revo71) */
+#define VT1724_REVO_I2C_DATA    0x40    /* I2C: PT 2258 SDA (on revo51) */
+#define VT1724_REVO_I2C_CLOCK   0x80    /* I2C: PT 2258 SCL (on revo51) */
+#define VT1724_REVO_CS3		0x80	/* AK4114 for AP192 */
 #define VT1724_REVO_MUTE	(1<<22)	/* 0 = all mute, 1 = normal operation */
 
 #endif /* __SOUND_REVO_H */
diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c
index 7ca263c1..72b060d 100644
--- a/sound/pci/ice1712/vt1720_mobo.c
+++ b/sound/pci/ice1712/vt1720_mobo.c
@@ -30,6 +30,7 @@
 #include <sound/core.h>
 
 #include "ice1712.h"
+#include "envy24ht.h"
 #include "vt1720_mobo.h"
 
 
@@ -55,41 +56,41 @@
 
 /* EEPROM image */
 
-static unsigned char k8x800_eeprom[] __devinitdata = {
-	0x01,	/* SYSCONF: clock 256, 1ADC, 2DACs */
-	0x02,	/* ACLINK: ACLINK, packed */
-	0x00,	/* I2S: - */
-	0x00,	/* SPDIF: - */
-	0xff,	/* GPIO_DIR */
-	0xff,	/* GPIO_DIR1 */
-	0x00,	/* - */
-	0xff,	/* GPIO_MASK */
-	0xff,	/* GPIO_MASK1 */
-	0x00,	/* - */
-	0x00,	/* GPIO_STATE */
-	0x00,	/* GPIO_STATE1 */
-	0x00,	/* - */
+static const unsigned char k8x800_eeprom[] __devinitdata = {
+	[ICE_EEP2_SYSCONF]     = 0x01,	/* clock 256, 1ADC, 2DACs */
+	[ICE_EEP2_ACLINK]      = 0x02,	/* ACLINK, packed */
+	[ICE_EEP2_I2S]         = 0x00,	/* - */
+	[ICE_EEP2_SPDIF]       = 0x00,	/* - */
+	[ICE_EEP2_GPIO_DIR]    = 0xff,
+	[ICE_EEP2_GPIO_DIR1]   = 0xff,
+	[ICE_EEP2_GPIO_DIR2]   = 0x00,	/* - */
+	[ICE_EEP2_GPIO_MASK]   = 0xff,
+	[ICE_EEP2_GPIO_MASK1]  = 0xff,
+	[ICE_EEP2_GPIO_MASK2]  = 0x00,	/* - */
+	[ICE_EEP2_GPIO_STATE]  = 0x00,
+	[ICE_EEP2_GPIO_STATE1] = 0x00,
+	[ICE_EEP2_GPIO_STATE2] = 0x00,	/* - */
 };
 
-static unsigned char sn25p_eeprom[] __devinitdata = {
-	0x01,	/* SYSCONF: clock 256, 1ADC, 2DACs */
-	0x02,	/* ACLINK: ACLINK, packed */
-	0x00,	/* I2S: - */
-	0x41,	/* SPDIF: - */
-	0xff,	/* GPIO_DIR */
-	0xff,	/* GPIO_DIR1 */
-	0x00,	/* - */
-	0xff,	/* GPIO_MASK */
-	0xff,	/* GPIO_MASK1 */
-	0x00,	/* - */
-	0x00,	/* GPIO_STATE */
-	0x00,	/* GPIO_STATE1 */
-	0x00,	/* - */
+static const unsigned char sn25p_eeprom[] __devinitdata = {
+	[ICE_EEP2_SYSCONF]     = 0x01,	/* clock 256, 1ADC, 2DACs */
+	[ICE_EEP2_ACLINK]      = 0x02,	/* ACLINK, packed */
+	[ICE_EEP2_I2S]         = 0x00,	/* - */
+	[ICE_EEP2_SPDIF]       = 0x41,	/* - */
+	[ICE_EEP2_GPIO_DIR]    = 0xff,
+	[ICE_EEP2_GPIO_DIR1]   = 0xff,
+	[ICE_EEP2_GPIO_DIR2]   = 0x00,	/* - */
+	[ICE_EEP2_GPIO_MASK]   = 0xff,
+	[ICE_EEP2_GPIO_MASK1]  = 0xff,
+	[ICE_EEP2_GPIO_MASK2]  = 0x00,	/* - */
+	[ICE_EEP2_GPIO_STATE]  = 0x00,
+	[ICE_EEP2_GPIO_STATE1] = 0x00,
+	[ICE_EEP2_GPIO_STATE2] = 0x00,	/* - */
 };
 
 
 /* entry point */
-struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = {
 	{
 		.subvendor = VT1720_SUBDEVICE_K8X800,
 		.name = "Albatron K8X800 Pro II",
diff --git a/sound/pci/ice1712/vt1720_mobo.h b/sound/pci/ice1712/vt1720_mobo.h
index 0b1b0ee..70af3ad 100644
--- a/sound/pci/ice1712/vt1720_mobo.h
+++ b/sound/pci/ice1712/vt1720_mobo.h
@@ -36,6 +36,6 @@
 #define VT1720_SUBDEVICE_9CJS		0x0f272327
 #define VT1720_SUBDEVICE_SN25P		0x97123650
 
-extern struct snd_ice1712_card_info  snd_vt1720_mobo_cards[];
+extern const struct snd_ice1712_card_info  snd_vt1720_mobo_cards[];
 
 #endif /* __SOUND_VT1720_MOBO_H */
diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c
new file mode 100644
index 0000000..4a706b1
--- /dev/null
+++ b/sound/pci/ice1712/wtm.c
@@ -0,0 +1,542 @@
+/*
+ *	ALSA driver for ICEnsemble VT1724 (Envy24HT)
+ *	
+ *	Lowlevel functions for Ego Sys Waveterminal 192M
+ *
+ *		Copyright (c) 2006 Guedez Clement <klem.dev@gmail.com>
+ *		Some functions are taken from the Prodigy192 driver
+ *		source
+ *		
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *	
+ */	
+
+
+
+#include <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+
+#include "ice1712.h"
+#include "envy24ht.h"
+#include "wtm.h"
+#include "stac946x.h"
+
+
+/*
+ *	2*ADC 6*DAC no1 ringbuffer r/w on i2c bus 
+ */
+static inline void stac9460_put(struct snd_ice1712 *ice, int reg, 
+						unsigned char val)
+{
+	snd_vt1724_write_i2c(ice, STAC9460_I2C_ADDR, reg, val);
+}
+
+static inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg)
+{
+	return snd_vt1724_read_i2c(ice, STAC9460_I2C_ADDR, reg);
+}
+
+/*
+ *	2*ADC 2*DAC no2 ringbuffer r/w on i2c bus
+ */
+static inline void stac9460_2_put(struct snd_ice1712 *ice, int reg,
+						unsigned char val)
+{
+	snd_vt1724_write_i2c(ice, STAC9460_2_I2C_ADDR, reg, val);
+}
+
+static inline unsigned char stac9460_2_get(struct snd_ice1712 *ice, int reg)
+{
+	return snd_vt1724_read_i2c(ice, STAC9460_2_I2C_ADDR, reg);
+}
+
+
+/*
+ *	DAC mute control
+ */
+static int stac9460_dac_mute_info(struct snd_kcontrol *kcontrol,
+	       			struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	return 0;
+}
+
+static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol,
+	       			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+	unsigned char val;
+	int idx, id;
+
+	if (kcontrol->private_value) {
+		idx = STAC946X_MASTER_VOLUME;
+		id = 0;
+	} else {
+		id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+		idx = id + STAC946X_LF_VOLUME;
+	}
+	if (id < 6)
+		val = stac9460_get(ice, idx);
+	else 
+		val = stac9460_2_get(ice,idx - 6);
+	ucontrol->value.integer.value[0] = (~val >> 7) & 0x1;
+	return 0;
+}
+
+static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol,
+	       			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+	unsigned char new, old;
+	int id, idx;
+	int change;
+
+	if (kcontrol->private_value) {
+		idx = STAC946X_MASTER_VOLUME;
+		old = stac9460_get(ice, idx);
+		new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) |
+		       					(old & ~0x80);
+		change = (new != old);
+		if (change) {
+			stac9460_put(ice, idx, new);
+			stac9460_2_put(ice, idx, new);
+		}
+	} else {
+		id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+		idx = id + STAC946X_LF_VOLUME;
+		if (id < 6)
+			old = stac9460_get(ice, idx);
+		else 
+			old = stac9460_2_get(ice, idx - 6);
+		new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) |
+							(old & ~0x80);
+		change = (new != old);
+		if (change) {
+			if (id < 6)
+			       	stac9460_put(ice, idx, new);
+			else
+			       	stac9460_2_put(ice, idx - 6, new);
+		}
+	}
+	return change;
+}
+
+/*
+ * 	DAC volume attenuation mixer control
+ */
+static int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol,
+	       			struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;			/* mute */
+	uinfo->value.integer.max = 0x7f;		/* 0dB */
+	return 0;
+}
+
+static int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol,
+	       			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+	int idx, id;
+	unsigned char vol;
+
+	if (kcontrol->private_value) {
+		idx = STAC946X_MASTER_VOLUME;
+		id = 0;
+	} else {
+		id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+		idx = id + STAC946X_LF_VOLUME;
+	}
+	if (id < 6)
+		vol = stac9460_get(ice, idx) & 0x7f;
+	else 
+		vol = stac9460_2_get(ice, idx - 6) & 0x7f;
+	ucontrol->value.integer.value[0] = 0x7f - vol;
+	return 0;
+}
+
+static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol,
+	       			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+	int idx, id;
+	unsigned char tmp, ovol, nvol;
+	int change;
+
+	if (kcontrol->private_value) {
+		idx = STAC946X_MASTER_VOLUME;
+		nvol = ucontrol->value.integer.value[0];
+		tmp = stac9460_get(ice, idx);
+		ovol = 0x7f - (tmp & 0x7f);
+		change = (ovol != nvol);
+		if (change) {
+			 stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
+			 stac9460_2_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
+		}
+	} else {
+		id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+		idx = id + STAC946X_LF_VOLUME;
+		nvol = ucontrol->value.integer.value[0];
+		if (id < 6)
+			tmp = stac9460_get(ice, idx);
+		else 
+			tmp = stac9460_2_get(ice, idx - 6);
+		ovol = 0x7f - (tmp & 0x7f);
+		change = (ovol != nvol);
+		if (change) {
+			if (id < 6)
+				stac9460_put(ice, idx, (0x7f - nvol) |
+					       		(tmp & 0x80));
+			else 
+				stac9460_2_put(ice, idx-6, (0x7f - nvol) |
+					       			(tmp & 0x80));
+		}
+	}
+	return change;
+}
+
+/*
+ * ADC mute control
+ */
+static int stac9460_adc_mute_info(struct snd_kcontrol *kcontrol,
+	       			struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol,
+	       			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+	unsigned char val;
+	int i, id;
+	
+	id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	if (id == 0) {
+		for (i = 0; i < 2; ++i) {
+			val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i);
+			ucontrol->value.integer.value[i] = ~val>>7 & 0x1;
+		}
+	} else {
+		for (i = 0; i < 2; ++i) {
+			val = stac9460_2_get(ice, STAC946X_MIC_L_VOLUME + i);
+			ucontrol->value.integer.value[i] = ~val>>7 & 0x1;
+		}
+	}
+	return 0;
+}
+
+static int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol,
+	       			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+	unsigned char new, old;
+	int i, reg, id;
+	int change;
+	
+	id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	if (id == 0) {
+		for (i = 0; i < 2; ++i) {
+			reg = STAC946X_MIC_L_VOLUME + i;
+			old = stac9460_get(ice, reg);
+			new = (~ucontrol->value.integer.value[i]<<7&0x80) |
+			       					(old&~0x80);
+			change = (new != old);
+			if (change)
+				stac9460_put(ice, reg, new);
+		}
+	} else {
+		for (i = 0; i < 2; ++i) {
+			reg = STAC946X_MIC_L_VOLUME + i;
+			old = stac9460_2_get(ice, reg);
+			new = (~ucontrol->value.integer.value[i]<<7&0x80) |
+			       					(old&~0x80);
+			change = (new != old);
+			if (change)
+				stac9460_2_put(ice, reg, new);
+		}
+	}
+	return change;
+}
+
+/*
+ *ADC gain mixer control
+ */
+static int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol,
+	       			struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;		/* 0dB */
+	uinfo->value.integer.max = 0x0f;	/* 22.5dB */
+	return 0;
+}
+
+static int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol,
+	       			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+	int i, reg, id;
+	unsigned char vol;
+	
+	id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	if (id == 0) {
+		for (i = 0; i < 2; ++i) {
+			reg = STAC946X_MIC_L_VOLUME + i;
+			vol = stac9460_get(ice, reg) & 0x0f;
+			ucontrol->value.integer.value[i] = 0x0f - vol;
+		}
+	} else {
+		for (i = 0; i < 2; ++i) {
+			reg = STAC946X_MIC_L_VOLUME + i;
+			vol = stac9460_2_get(ice, reg) & 0x0f;
+			ucontrol->value.integer.value[i] = 0x0f - vol;
+		}
+	}
+	return 0;
+}
+
+static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol,
+	       		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+	int i, reg, id;
+	unsigned char ovol, nvol;
+	int change;
+	
+	id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	if (id == 0) {
+		for (i = 0; i < 2; ++i) {
+			reg = STAC946X_MIC_L_VOLUME + i;
+			nvol = ucontrol->value.integer.value[i];
+			ovol = 0x0f - stac9460_get(ice, reg);
+			change = ((ovol & 0x0f) != nvol);
+			if (change)
+				stac9460_put(ice, reg, (0x0f - nvol) |
+					       		(ovol & ~0x0f));
+		}
+	} else {
+		for (i = 0; i < 2; ++i) {
+			reg = STAC946X_MIC_L_VOLUME + i;
+			nvol = ucontrol->value.integer.value[i];
+			ovol = 0x0f - stac9460_2_get(ice, reg);
+			change = ((ovol & 0x0f) != nvol);
+			if (change)
+				stac9460_2_put(ice, reg, (0x0f - nvol) |
+					       		(ovol & ~0x0f));
+		}
+	}
+	return change;
+}
+
+/*
+ * MIC / LINE switch fonction
+ */
+
+static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol,
+	       			struct snd_ctl_elem_info *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 stac9460_mic_sw_get(struct snd_kcontrol *kcontrol,
+	       		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+	unsigned char val;
+	int id;
+		
+	id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	if (id == 0)
+	       	val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
+	else
+	       	val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
+	ucontrol->value.integer.value[0] = ~val>>7 & 0x1;
+	return 0;
+}
+
+static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol,
+	       		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+	unsigned char new, old;
+	int change, id;
+
+	id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	if (id == 0)
+	       	old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
+	else
+	       	old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
+	new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | (old & ~0x80);
+	change = (new != old);
+	if (change) {
+		if (id == 0)
+		       	stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new);
+		else
+		       	stac9460_2_put(ice, STAC946X_GENERAL_PURPOSE, new);
+	}
+	return change;
+}
+
+/*
+ * Control tabs
+ */
+static const struct snd_kcontrol_new stac9640_controls[] __devinitdata = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = stac9460_dac_mute_info,
+		.get = stac9460_dac_mute_get,
+		.put = stac9460_dac_mute_put,
+		.private_value = 1
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Volume",
+		.info = stac9460_dac_vol_info,
+		.get = stac9460_dac_vol_get,
+		.put = stac9460_dac_vol_put,
+		.private_value = 1,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "MIC/Line switch",
+		.count = 2,
+		.info = stac9460_mic_sw_info,
+		.get = stac9460_mic_sw_get,
+		.put = stac9460_mic_sw_put,
+
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "DAC Switch",
+		.count = 8,
+		.info = stac9460_dac_mute_info,
+		.get = stac9460_dac_mute_get,
+		.put = stac9460_dac_mute_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "DAC Volume",
+		.count = 8,
+		.info = stac9460_dac_vol_info,
+		.get = stac9460_dac_vol_get,
+		.put = stac9460_dac_vol_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "ADC Switch",
+		.count = 2,
+		.info = stac9460_adc_mute_info,
+		.get = stac9460_adc_mute_get,
+		.put = stac9460_adc_mute_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "ADC Volume",
+		.count = 2,
+		.info = stac9460_adc_vol_info,
+		.get = stac9460_adc_vol_get,
+		.put = stac9460_adc_vol_put,
+
+	}	
+};
+
+
+
+/*INIT*/
+static int __devinit wtm_add_controls(struct snd_ice1712 *ice)
+{
+	unsigned int i;
+	int err;
+
+	for (i = 0; i < ARRAY_SIZE(stac9640_controls); i++) {
+		err = snd_ctl_add(ice->card,
+				snd_ctl_new1(&stac9640_controls[i], ice));
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static int __devinit wtm_init(struct snd_ice1712 *ice)
+{
+	static unsigned short stac_inits_prodigy[] = {
+		STAC946X_RESET, 0,
+		(unsigned short)-1
+	};
+	unsigned short *p;
+		
+	/*WTM 192M*/
+	ice->num_total_dacs = 8;
+	ice->num_total_adcs = 4;
+	ice->force_rdma1 = 1;
+
+	/*initialize codec*/
+	p = stac_inits_prodigy;
+	for (; *p != (unsigned short)-1; p += 2) {
+		stac9460_put(ice, p[0], p[1]);
+		stac9460_2_put(ice, p[0], p[1]);
+	}
+	return 0;
+}
+
+
+static unsigned char wtm_eeprom[] __devinitdata = {
+	0x47,	/*SYSCONF: clock 192KHz, 4ADC, 8DAC */
+	0x80,	/* ACLINK : I2S */
+	0xf8,	/* I2S: vol; 96k, 24bit, 192k */
+	0xc1	/*SPDIF: out-en, spidf ext out*/,
+	0x9f,	/* GPIO_DIR */
+	0xff,	/* GPIO_DIR1 */
+	0x7f,	/* GPIO_DIR2 */
+	0x9f,	/* GPIO_MASK */
+	0xff,	/* GPIO_MASK1 */
+	0x7f,	/* GPIO_MASK2 */
+	0x16,	/* GPIO_STATE */
+	0x80,	/* GPIO_STATE1 */
+	0x00,	/* GPIO_STATE2 */
+};
+
+
+/*entry point*/
+struct snd_ice1712_card_info snd_vt1724_wtm_cards[] __devinitdata = {
+	{
+		.subvendor = VT1724_SUBDEVICE_WTM,
+		.name = "ESI Waveterminal 192M",
+		.model = "WT192M",
+		.chip_init = wtm_init,
+		.build_controls = wtm_add_controls,
+		.eeprom_size = sizeof(wtm_eeprom),
+		.eeprom_data = wtm_eeprom,
+	},
+	{} /*terminator*/
+};
diff --git a/sound/pci/ice1712/wtm.h b/sound/pci/ice1712/wtm.h
new file mode 100644
index 0000000..03a394e
--- /dev/null
+++ b/sound/pci/ice1712/wtm.h
@@ -0,0 +1,20 @@
+#ifndef __SOUND_WTM_H
+#define __SOUND_WTM_H
+
+/* ID */
+#define WTM_DEVICE_DESC		"{EGO SYS INC,WaveTerminal 192M},"
+#define VT1724_SUBDEVICE_WTM	0x36495345	/* WT192M ver1.0 */
+
+/*
+ *chip addresses on I2C bus
+ */
+
+#define	AK4114_ADDR		0x20	/*S/PDIF receiver*/
+#define STAC9460_I2C_ADDR	0x54	/* ADC*2 | DAC*6 */	
+#define STAC9460_2_I2C_ADDR	0x56	/* ADC|DAC *2 */	
+
+
+extern struct snd_ice1712_card_info snd_vt1724_wtm_cards[];
+
+#endif /* __SOUND_WTM_H */
+
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 30aaa60..a289abf 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -71,6 +71,7 @@
 static int buggy_semaphore;
 static int buggy_irq = -1; /* auto-check */
 static int xbox;
+static int spdif_aclink = -1;
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for Intel i8x0 soundcard.");
@@ -86,6 +87,8 @@
 MODULE_PARM_DESC(buggy_irq, "Enable workaround for buggy interrupts on some motherboards.");
 module_param(xbox, bool, 0444);
 MODULE_PARM_DESC(xbox, "Set to 1 for Xbox, if you have problems with the AC'97 codec detection.");
+module_param(spdif_aclink, int, 0444);
+MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link.");
 
 /* just for backward compatibility */
 static int enable;
@@ -368,12 +371,8 @@
 
 	int irq;
 
-	unsigned int mmio;
-	unsigned long addr;
-	void __iomem *remap_addr;
-	unsigned int bm_mmio;
-	unsigned long bmaddr;
-	void __iomem *remap_bmaddr;
+	void __iomem *addr;
+	void __iomem *bmaddr;
 
 	struct pci_dev *pci;
 	struct snd_card *card;
@@ -446,72 +445,48 @@
  *  Lowlevel I/O - busmaster
  */
 
-static u8 igetbyte(struct intel8x0 *chip, u32 offset)
+static inline u8 igetbyte(struct intel8x0 *chip, u32 offset)
 {
-	if (chip->bm_mmio)
-		return readb(chip->remap_bmaddr + offset);
-	else
-		return inb(chip->bmaddr + offset);
+	return ioread8(chip->bmaddr + offset);
 }
 
-static u16 igetword(struct intel8x0 *chip, u32 offset)
+static inline u16 igetword(struct intel8x0 *chip, u32 offset)
 {
-	if (chip->bm_mmio)
-		return readw(chip->remap_bmaddr + offset);
-	else
-		return inw(chip->bmaddr + offset);
+	return ioread16(chip->bmaddr + offset);
 }
 
-static u32 igetdword(struct intel8x0 *chip, u32 offset)
+static inline u32 igetdword(struct intel8x0 *chip, u32 offset)
 {
-	if (chip->bm_mmio)
-		return readl(chip->remap_bmaddr + offset);
-	else
-		return inl(chip->bmaddr + offset);
+	return ioread32(chip->bmaddr + offset);
 }
 
-static void iputbyte(struct intel8x0 *chip, u32 offset, u8 val)
+static inline void iputbyte(struct intel8x0 *chip, u32 offset, u8 val)
 {
-	if (chip->bm_mmio)
-		writeb(val, chip->remap_bmaddr + offset);
-	else
-		outb(val, chip->bmaddr + offset);
+	iowrite8(val, chip->bmaddr + offset);
 }
 
-static void iputword(struct intel8x0 *chip, u32 offset, u16 val)
+static inline void iputword(struct intel8x0 *chip, u32 offset, u16 val)
 {
-	if (chip->bm_mmio)
-		writew(val, chip->remap_bmaddr + offset);
-	else
-		outw(val, chip->bmaddr + offset);
+	iowrite16(val, chip->bmaddr + offset);
 }
 
-static void iputdword(struct intel8x0 *chip, u32 offset, u32 val)
+static inline void iputdword(struct intel8x0 *chip, u32 offset, u32 val)
 {
-	if (chip->bm_mmio)
-		writel(val, chip->remap_bmaddr + offset);
-	else
-		outl(val, chip->bmaddr + offset);
+	iowrite32(val, chip->bmaddr + offset);
 }
 
 /*
  *  Lowlevel I/O - AC'97 registers
  */
 
-static u16 iagetword(struct intel8x0 *chip, u32 offset)
+static inline u16 iagetword(struct intel8x0 *chip, u32 offset)
 {
-	if (chip->mmio)
-		return readw(chip->remap_addr + offset);
-	else
-		return inw(chip->addr + offset);
+	return ioread16(chip->addr + offset);
 }
 
-static void iaputword(struct intel8x0 *chip, u32 offset, u16 val)
+static inline void iaputword(struct intel8x0 *chip, u32 offset, u16 val)
 {
-	if (chip->mmio)
-		writew(val, chip->remap_addr + offset);
-	else
-		outw(val, chip->addr + offset);
+	iowrite16(val, chip->addr + offset);
 }
 
 /*
@@ -1606,10 +1581,14 @@
 	case DEVICE_INTEL_ICH4:
 		tbl = intel_pcms;
 		tblsize = ARRAY_SIZE(intel_pcms);
+		if (spdif_aclink)
+			tblsize--;
 		break;
 	case DEVICE_NFORCE:
 		tbl = nforce_pcms;
 		tblsize = ARRAY_SIZE(nforce_pcms);
+		if (spdif_aclink)
+			tblsize--;
 		break;
 	case DEVICE_ALI:
 		tbl = ali_pcms;
@@ -2068,24 +2047,26 @@
 	};
 
 	chip->spdif_idx = -1; /* use PCMOUT (or disabled) */
-	switch (chip->device_type) {
-	case DEVICE_NFORCE:
-		chip->spdif_idx = NVD_SPBAR;
-		break;
-	case DEVICE_ALI:
-		chip->spdif_idx = ALID_AC97SPDIFOUT;
-		break;
-	case DEVICE_INTEL_ICH4:
-		chip->spdif_idx = ICHD_SPBAR;
-		break;
-	};
+	if (!spdif_aclink) {
+		switch (chip->device_type) {
+		case DEVICE_NFORCE:
+			chip->spdif_idx = NVD_SPBAR;
+			break;
+		case DEVICE_ALI:
+			chip->spdif_idx = ALID_AC97SPDIFOUT;
+			break;
+		case DEVICE_INTEL_ICH4:
+			chip->spdif_idx = ICHD_SPBAR;
+			break;
+		};
+	}
 
 	chip->in_ac97_init = 1;
 	
 	memset(&ac97, 0, sizeof(ac97));
 	ac97.private_data = chip;
 	ac97.private_free = snd_intel8x0_mixer_free_ac97;
-	ac97.scaps = AC97_SCAP_SKIP_MODEM;
+	ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE;
 	if (chip->xbox)
 		ac97.scaps |= AC97_SCAP_DETECT_BY_VENDOR;
 	if (chip->device_type != DEVICE_ALI) {
@@ -2201,11 +2182,11 @@
 		if ((igetdword(chip, ICHREG(GLOB_STA)) & ICH_SAMPLE_CAP) == ICH_SAMPLE_16_20)
 			chip->smp20bit = 1;
 	}
-	if (chip->device_type == DEVICE_NFORCE) {
+	if (chip->device_type == DEVICE_NFORCE && !spdif_aclink) {
 		/* 48kHz only */
 		chip->ichd[chip->spdif_idx].pcm->rates = SNDRV_PCM_RATE_48000;
 	}
-	if (chip->device_type == DEVICE_INTEL_ICH4) {
+	if (chip->device_type == DEVICE_INTEL_ICH4 && !spdif_aclink) {
 		/* use slot 10/11 for SPDIF */
 		u32 val;
 		val = igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_PCM_SPDIF_MASK;
@@ -2333,7 +2314,7 @@
 		/* unmute the output on SIS7012 */
 		iputword(chip, 0x4c, igetword(chip, 0x4c) | 1);
 	}
-	if (chip->device_type == DEVICE_NFORCE) {
+	if (chip->device_type == DEVICE_NFORCE && !spdif_aclink) {
 		/* enable SPDIF interrupt */
 		unsigned int val;
 		pci_read_config_dword(chip->pci, 0x4c, &val);
@@ -2426,7 +2407,7 @@
 	/* reset channels */
 	for (i = 0; i < chip->bdbars_count; i++)
 		iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS);
-	if (chip->device_type == DEVICE_NFORCE) {
+	if (chip->device_type == DEVICE_NFORCE && !spdif_aclink) {
 		/* stop the spdif interrupt */
 		unsigned int val;
 		pci_read_config_dword(chip->pci, 0x4c, &val);
@@ -2443,10 +2424,10 @@
 			fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 0);
 		snd_dma_free_pages(&chip->bdbars);
 	}
-	if (chip->remap_addr)
-		iounmap(chip->remap_addr);
-	if (chip->remap_bmaddr)
-		iounmap(chip->remap_bmaddr);
+	if (chip->addr)
+		pci_iounmap(chip->pci, chip->addr);
+	if (chip->bmaddr)
+		pci_iounmap(chip->pci, chip->bmaddr);
 	pci_release_regions(chip->pci);
 	pci_disable_device(chip->pci);
 	kfree(chip);
@@ -2520,7 +2501,7 @@
 	snd_intel8x0_chip_init(chip, 0);
 
 	/* re-initialize mixer stuff */
-	if (chip->device_type == DEVICE_INTEL_ICH4) {
+	if (chip->device_type == DEVICE_INTEL_ICH4 && !spdif_aclink) {
 		/* enable separate SDINs for ICH4 */
 		iputbyte(chip, ICHREG(SDM), chip->sdm_saved);
 		/* use slot 10/11 for SPDIF */
@@ -2793,35 +2774,27 @@
 
 	if (device_type == DEVICE_ALI) {
 		/* ALI5455 has no ac97 region */
-		chip->bmaddr = pci_resource_start(pci, 0);
+		chip->bmaddr = pci_iomap(pci, 0, 0);
 		goto port_inited;
 	}
 
-	if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) {	/* ICH4 and Nforce */
-		chip->mmio = 1;
-		chip->addr = pci_resource_start(pci, 2);
-		chip->remap_addr = ioremap_nocache(chip->addr,
-						   pci_resource_len(pci, 2));
-		if (chip->remap_addr == NULL) {
-			snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
-			snd_intel8x0_free(chip);
-			return -EIO;
-		}
-	} else {
-		chip->addr = pci_resource_start(pci, 0);
+	if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) /* ICH4 and Nforce */
+		chip->addr = pci_iomap(pci, 2, 0);
+	else
+		chip->addr = pci_iomap(pci, 0, 0);
+	if (!chip->addr) {
+		snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
+		snd_intel8x0_free(chip);
+		return -EIO;
 	}
-	if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) {	/* ICH4 */
-		chip->bm_mmio = 1;
-		chip->bmaddr = pci_resource_start(pci, 3);
-		chip->remap_bmaddr = ioremap_nocache(chip->bmaddr,
-						     pci_resource_len(pci, 3));
-		if (chip->remap_bmaddr == NULL) {
-			snd_printk(KERN_ERR "Controller space ioremap problem\n");
-			snd_intel8x0_free(chip);
-			return -EIO;
-		}
-	} else {
-		chip->bmaddr = pci_resource_start(pci, 1);
+	if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) /* ICH4 */
+		chip->bmaddr = pci_iomap(pci, 3, 0);
+	else
+		chip->bmaddr = pci_iomap(pci, 1, 0);
+	if (!chip->bmaddr) {
+		snd_printk(KERN_ERR "Controller space ioremap problem\n");
+		snd_intel8x0_free(chip);
+		return -EIO;
 	}
 
  port_inited:
@@ -2964,6 +2937,29 @@
 	{ 0, NULL },
 };
 
+static struct snd_pci_quirk spdif_aclink_defaults[] __devinitdata = {
+	SND_PCI_QUIRK(0x147b, 0x1c1a, "ASUS KN8", 1),
+	{ } /* end */
+};
+
+/* look up white/black list for SPDIF over ac-link */
+static int __devinit check_default_spdif_aclink(struct pci_dev *pci)
+{
+	const struct snd_pci_quirk *w;
+
+	w = snd_pci_quirk_lookup(pci, spdif_aclink_defaults);
+	if (w) {
+		if (w->value)
+			snd_printdd(KERN_INFO "intel8x0: Using SPDIF over "
+				    "AC-Link for %s\n", w->name);
+		else
+			snd_printdd(KERN_INFO "intel8x0: Using integrated "
+				    "SPDIF DMA for %s\n", w->name);
+		return w->value;
+	}
+	return 0;
+}
+
 static int __devinit snd_intel8x0_probe(struct pci_dev *pci,
 					const struct pci_device_id *pci_id)
 {
@@ -2976,16 +2972,18 @@
 	if (card == NULL)
 		return -ENOMEM;
 
-	switch (pci_id->driver_data) {
-	case DEVICE_NFORCE:
-		strcpy(card->driver, "NFORCE");
-		break;
-	case DEVICE_INTEL_ICH4:
-		strcpy(card->driver, "ICH4");
-		break;
-	default:
-		strcpy(card->driver, "ICH");
-		break;
+	if (spdif_aclink < 0)
+		spdif_aclink = check_default_spdif_aclink(pci);
+
+	strcpy(card->driver, "ICH");
+	if (!spdif_aclink) {
+		switch (pci_id->driver_data) {
+		case DEVICE_NFORCE:
+			strcpy(card->driver, "NFORCE");
+			break;
+		case DEVICE_INTEL_ICH4:
+			strcpy(card->driver, "ICH4");
+		}
 	}
 
 	strcpy(card->shortname, "Intel ICH");
@@ -3025,8 +3023,8 @@
 	snd_intel8x0_proc_init(chip);
 
 	snprintf(card->longname, sizeof(card->longname),
-		 "%s with %s at %#lx, irq %i", card->shortname,
-		 snd_ac97_get_short_name(chip->ac97[0]), chip->addr, chip->irq);
+		 "%s with %s at irq %i", card->shortname,
+		 snd_ac97_get_short_name(chip->ac97[0]), chip->irq);
 
 	if (! ac97_clock)
 		intel8x0_measure_ac97_clock(chip);
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index 09dcf92..c155e1f 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -196,12 +196,8 @@
 
 	int irq;
 
-	unsigned int mmio;
-	unsigned long addr;
-	void __iomem *remap_addr;
-	unsigned int bm_mmio;
-	unsigned long bmaddr;
-	void __iomem *remap_bmaddr;
+	void __iomem *addr;
+	void __iomem *bmaddr;
 
 	struct pci_dev *pci;
 	struct snd_card *card;
@@ -253,72 +249,48 @@
  *  Lowlevel I/O - busmaster
  */
 
-static u8 igetbyte(struct intel8x0m *chip, u32 offset)
+static inline u8 igetbyte(struct intel8x0m *chip, u32 offset)
 {
-	if (chip->bm_mmio)
-		return readb(chip->remap_bmaddr + offset);
-	else
-		return inb(chip->bmaddr + offset);
+	return ioread8(chip->bmaddr + offset);
 }
 
-static u16 igetword(struct intel8x0m *chip, u32 offset)
+static inline u16 igetword(struct intel8x0m *chip, u32 offset)
 {
-	if (chip->bm_mmio)
-		return readw(chip->remap_bmaddr + offset);
-	else
-		return inw(chip->bmaddr + offset);
+	return ioread16(chip->bmaddr + offset);
 }
 
-static u32 igetdword(struct intel8x0m *chip, u32 offset)
+static inline u32 igetdword(struct intel8x0m *chip, u32 offset)
 {
-	if (chip->bm_mmio)
-		return readl(chip->remap_bmaddr + offset);
-	else
-		return inl(chip->bmaddr + offset);
+	return ioread32(chip->bmaddr + offset);
 }
 
-static void iputbyte(struct intel8x0m *chip, u32 offset, u8 val)
+static inline void iputbyte(struct intel8x0m *chip, u32 offset, u8 val)
 {
-	if (chip->bm_mmio)
-		writeb(val, chip->remap_bmaddr + offset);
-	else
-		outb(val, chip->bmaddr + offset);
+	iowrite8(val, chip->bmaddr + offset);
 }
 
-static void iputword(struct intel8x0m *chip, u32 offset, u16 val)
+static inline void iputword(struct intel8x0m *chip, u32 offset, u16 val)
 {
-	if (chip->bm_mmio)
-		writew(val, chip->remap_bmaddr + offset);
-	else
-		outw(val, chip->bmaddr + offset);
+	iowrite16(val, chip->bmaddr + offset);
 }
 
-static void iputdword(struct intel8x0m *chip, u32 offset, u32 val)
+static inline void iputdword(struct intel8x0m *chip, u32 offset, u32 val)
 {
-	if (chip->bm_mmio)
-		writel(val, chip->remap_bmaddr + offset);
-	else
-		outl(val, chip->bmaddr + offset);
+	iowrite32(val, chip->bmaddr + offset);
 }
 
 /*
  *  Lowlevel I/O - AC'97 registers
  */
 
-static u16 iagetword(struct intel8x0m *chip, u32 offset)
+static inline u16 iagetword(struct intel8x0m *chip, u32 offset)
 {
-	if (chip->mmio)
-		return readw(chip->remap_addr + offset);
-	else
-		return inw(chip->addr + offset);
+	return ioread16(chip->addr + offset);
 }
 
-static void iaputword(struct intel8x0m *chip, u32 offset, u16 val)
+static inline void iaputword(struct intel8x0m *chip, u32 offset, u16 val)
 {
-	if (chip->mmio)
-		writew(val, chip->remap_addr + offset);
-	else
-		outw(val, chip->addr + offset);
+	iowrite16(val, chip->addr + offset);
 }
 
 /*
@@ -858,7 +830,7 @@
 	memset(&ac97, 0, sizeof(ac97));
 	ac97.private_data = chip;
 	ac97.private_free = snd_intel8x0_mixer_free_ac97;
-	ac97.scaps = AC97_SCAP_SKIP_AUDIO;
+	ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE;
 
 	glob_sta = igetdword(chip, ICHREG(GLOB_STA));
 
@@ -1019,10 +991,10 @@
       __hw_end:
 	if (chip->bdbars.area)
 		snd_dma_free_pages(&chip->bdbars);
-	if (chip->remap_addr)
-		iounmap(chip->remap_addr);
-	if (chip->remap_bmaddr)
-		iounmap(chip->remap_bmaddr);
+	if (chip->addr)
+		pci_iounmap(chip->pci, chip->addr);
+	if (chip->bmaddr)
+		pci_iounmap(chip->pci, chip->bmaddr);
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
 	pci_release_regions(chip->pci);
@@ -1173,35 +1145,27 @@
 
 	if (device_type == DEVICE_ALI) {
 		/* ALI5455 has no ac97 region */
-		chip->bmaddr = pci_resource_start(pci, 0);
+		chip->bmaddr = pci_iomap(pci, 0, 0);
 		goto port_inited;
 	}
 
-	if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) {	/* ICH4 and Nforce */
-		chip->mmio = 1;
-		chip->addr = pci_resource_start(pci, 2);
-		chip->remap_addr = ioremap_nocache(chip->addr,
-						   pci_resource_len(pci, 2));
-		if (chip->remap_addr == NULL) {
-			snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
-			snd_intel8x0_free(chip);
-			return -EIO;
-		}
-	} else {
-		chip->addr = pci_resource_start(pci, 0);
+	if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) /* ICH4 and Nforce */
+		chip->addr = pci_iomap(pci, 2, 0);
+	else
+		chip->addr = pci_iomap(pci, 0, 0);
+	if (!chip->addr) {
+		snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
+		snd_intel8x0_free(chip);
+		return -EIO;
 	}
-	if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) {	/* ICH4 */
-		chip->bm_mmio = 1;
-		chip->bmaddr = pci_resource_start(pci, 3);
-		chip->remap_bmaddr = ioremap_nocache(chip->bmaddr,
-						     pci_resource_len(pci, 3));
-		if (chip->remap_bmaddr == NULL) {
-			snd_printk(KERN_ERR "Controller space ioremap problem\n");
-			snd_intel8x0_free(chip);
-			return -EIO;
-		}
-	} else {
-		chip->bmaddr = pci_resource_start(pci, 1);
+	if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) /* ICH4 */
+		chip->bmaddr = pci_iomap(pci, 3, 0);
+	else
+		chip->bmaddr = pci_iomap(pci, 1, 0);
+	if (!chip->bmaddr) {
+		snd_printk(KERN_ERR "Controller space ioremap problem\n");
+		snd_intel8x0_free(chip);
+		return -EIO;
 	}
 
  port_inited:
@@ -1339,8 +1303,8 @@
 	
 	snd_intel8x0m_proc_init(chip);
 
-	sprintf(card->longname, "%s at 0x%lx, irq %i",
-		card->shortname, chip->addr, chip->irq);
+	sprintf(card->longname, "%s at irq %i",
+		card->shortname, chip->irq);
 
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 345eefe..21d0899a 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -28,6 +28,7 @@
 #include <linux/wait.h>
 #include <linux/moduleparam.h>
 #include <linux/mutex.h>
+#include <linux/firmware.h>
 
 #include <sound/core.h>
 #include <sound/info.h>
@@ -263,7 +264,15 @@
 #define COMMAND_ACK_DELAY   13         // number of RTC ticks to wait for an acknowledgement
                                        //    from the card after sending a command.
 
+#define FIRMWARE_IN_THE_KERNEL
+
+#ifdef FIRMWARE_IN_THE_KERNEL
 #include "korg1212-firmware.h"
+static const struct firmware static_dsp_code = {
+	.data = (u8 *)dspCode,
+	.size = sizeof dspCode
+};
+#endif
 
 enum ClockSourceIndex {
    K1212_CLKIDX_AdatAt44_1K = 0,    // selects source as ADAT at 44.1 kHz
@@ -345,8 +354,6 @@
         struct snd_dma_buffer dma_rec;
 	struct snd_dma_buffer dma_shared;
 
-        u32 dspCodeSize;
-
 	u32 DataBufsSize;
 
         struct KorgAudioBuffer  * playDataBufsPtr;
@@ -1223,8 +1230,6 @@
 
         snd_korg1212_setCardState(korg1212, K1212_STATE_DSP_IN_PROCESS);
 
-        memcpy(korg1212->dma_dsp.area, dspCode, korg1212->dspCodeSize);
-
         rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_StartDSPDownload,
                                      UpperWordSwap(korg1212->dma_dsp.addr),
                                      0, 0, 0);
@@ -2156,6 +2161,7 @@
         unsigned int i;
 	unsigned ioport_size, iomem_size, iomem2_size;
         struct snd_korg1212 * korg1212;
+	const struct firmware *dsp_code;
 
         static struct snd_device_ops ops = {
                 .dev_free = snd_korg1212_dev_free,
@@ -2329,8 +2335,6 @@
 
 #endif // K1212_LARGEALLOC
 
-        korg1212->dspCodeSize = sizeof (dspCode);
-
         korg1212->VolumeTablePhy = korg1212->sharedBufferPhy +
 		offsetof(struct KorgSharedBuffer, volumeData);
         korg1212->RoutingTablePhy = korg1212->sharedBufferPhy +
@@ -2338,17 +2342,40 @@
         korg1212->AdatTimeCodePhy = korg1212->sharedBufferPhy +
 		offsetof(struct KorgSharedBuffer, AdatTimeCode);
 
+	err = request_firmware(&dsp_code, "korg/k1212.dsp", &pci->dev);
+	if (err < 0) {
+		release_firmware(dsp_code);
+#ifdef FIRMWARE_IN_THE_KERNEL
+		dsp_code = &static_dsp_code;
+#else
+		snd_printk(KERN_ERR "firmware not available\n");
+		snd_korg1212_free(korg1212);
+		return err;
+#endif
+	}
+
 	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
-				korg1212->dspCodeSize, &korg1212->dma_dsp) < 0) {
-		snd_printk(KERN_ERR "korg1212: can not allocate dsp code memory (%d bytes)\n", korg1212->dspCodeSize);
+				dsp_code->size, &korg1212->dma_dsp) < 0) {
+		snd_printk(KERN_ERR "korg1212: cannot allocate dsp code memory (%zd bytes)\n", dsp_code->size);
                 snd_korg1212_free(korg1212);
+#ifdef FIRMWARE_IN_THE_KERNEL
+		if (dsp_code != &static_dsp_code)
+#endif
+			release_firmware(dsp_code);
                 return -ENOMEM;
         }
 
         K1212_DEBUG_PRINTK("K1212_DEBUG: DSP Code area = 0x%p (0x%08x) %d bytes [%s]\n",
-		   korg1212->dma_dsp.area, korg1212->dma_dsp.addr, korg1212->dspCodeSize,
+		   korg1212->dma_dsp.area, korg1212->dma_dsp.addr, dsp_code->size,
 		   stateName[korg1212->cardState]);
 
+	memcpy(korg1212->dma_dsp.area, dsp_code->data, dsp_code->size);
+
+#ifdef FIRMWARE_IN_THE_KERNEL
+	if (dsp_code != &static_dsp_code)
+#endif
+		release_firmware(dsp_code);
+
 	rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_RebootCard, 0, 0, 0, 0);
 
 	if (rc)
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 6efe6d5..4526904 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -41,6 +41,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/moduleparam.h>
+#include <linux/firmware.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -48,6 +49,7 @@
 #include <sound/mpu401.h>
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
+#include <asm/byteorder.h>
 
 MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("ESS Maestro3 PCI");
@@ -768,21 +770,6 @@
 /*
  */
 
-/* quirk lists */
-struct m3_quirk {
-	const char *name;	/* device name */
-	u16 vendor, device;	/* subsystem ids */
-	int amp_gpio;		/* gpio pin #  for external amp, -1 = default */
-	int irda_workaround;	/* non-zero if avoid to touch 0x10 on GPIO_DIRECTION
-				   (e.g. for IrDA on Dell Inspirons) */
-};
-
-struct m3_hv_quirk {
-	u16 vendor, device, subsystem_vendor, subsystem_device;
-	u32 config;		/* ALLEGRO_CONFIG hardware volume bits */
-	int is_omnibook;	/* Do HP OmniBook GPIO magic? */
-};
-
 struct m3_list {
 	int curlen;
 	int mem_addr;
@@ -830,8 +817,6 @@
 	struct snd_pcm *pcm;
 
 	struct pci_dev *pci;
-	const struct m3_quirk *quirk;
-	const struct m3_hv_quirk *hv_quirk;
 
 	int dacs_active;
 	int timer_users;
@@ -845,7 +830,11 @@
 	u8 reset_state;
 
 	int external_amp;
-	int amp_gpio;
+	int amp_gpio;	/* gpio pin #  for external amp, -1 = default */
+	unsigned int hv_config;		/* hardware-volume config bits */
+	unsigned irda_workaround :1;	/* avoid to touch 0x10 on GPIO_DIRECTION
+					   (e.g. for IrDA on Dell Inspirons) */
+	unsigned is_omnibook :1;	/* Do HP OmniBook GPIO magic? */
 
 	/* midi */
 	struct snd_rawmidi *rmidi;
@@ -864,6 +853,9 @@
 #ifdef CONFIG_PM
 	u16 *suspend_mem;
 #endif
+
+	const struct firmware *assp_kernel_image;
+	const struct firmware *assp_minisrc_image;
 };
 
 /*
@@ -891,127 +883,104 @@
 
 MODULE_DEVICE_TABLE(pci, snd_m3_ids);
 
-static const struct m3_quirk m3_quirk_list[] = {
-	/* panasonic CF-28 "toughbook" */
-	{
-		.name = "Panasonic CF-28",
-		.vendor = 0x10f7,
-		.device = 0x833e,
-		.amp_gpio = 0x0d,
-	},
-	/* panasonic CF-72 "toughbook" */
-	{
-		.name = "Panasonic CF-72",
-		.vendor = 0x10f7,
-		.device = 0x833d,
-		.amp_gpio = 0x0d,
-	},
-	/* Dell Inspiron 4000 */
-	{
-		.name = "Dell Inspiron 4000",
-		.vendor = 0x1028,
-		.device = 0x00b0,
-		.amp_gpio = -1,
-		.irda_workaround = 1,
-	},
-	/* Dell Inspiron 8000 */
-	{
-		.name = "Dell Inspiron 8000",
-		.vendor = 0x1028,
-		.device = 0x00a4,
-		.amp_gpio = -1,
-		.irda_workaround = 1,
-	},
-	/* Dell Inspiron 8100 */
-	{
-		.name = "Dell Inspiron 8100",
-		.vendor = 0x1028,
-		.device = 0x00e6,
-		.amp_gpio = -1,
-		.irda_workaround = 1,
-	},
-	/* NEC LM800J/7 */
-	{
-		.name = "NEC LM800J/7",
-		.vendor = 0x1033,
-		.device = 0x80f1,
-		.amp_gpio = 0x03,
-	},
-	/* LEGEND ZhaoYang 3100CF */
-	{
-		.name = "LEGEND ZhaoYang 3100CF",
-		.vendor = 0x1509,
-		.device = 0x1740,
-		.amp_gpio = 0x03,
-	},
-	/* END */
-	{ NULL }
+static struct snd_pci_quirk m3_amp_quirk_list[] __devinitdata = {
+	SND_PCI_QUIRK(0x10f7, 0x833e, "Panasonic CF-28", 0x0d),
+	SND_PCI_QUIRK(0x10f7, 0x833d, "Panasonic CF-72", 0x0d),
+	SND_PCI_QUIRK(0x1033, 0x80f1, "NEC LM800J/7", 0x03),
+	SND_PCI_QUIRK(0x1509, 0x1740, "LEGEND ZhaoYang 3100CF", 0x03),
+	{ } /* END */
 };
 
-/* These values came from the Windows driver. */
-static const struct m3_hv_quirk m3_hv_quirk_list[] = {
+static struct snd_pci_quirk m3_irda_quirk_list[] __devinitdata = {
+	SND_PCI_QUIRK(0x1028, 0x00b0, "Dell Inspiron 4000", 1),
+	SND_PCI_QUIRK(0x1028, 0x00a4, "Dell Inspiron 8000", 1),
+	SND_PCI_QUIRK(0x1028, 0x00e6, "Dell Inspiron 8100", 1),
+	{ } /* END */
+};
+
+/* hardware volume quirks */
+static struct snd_pci_quirk m3_hv_quirk_list[] __devinitdata = {
 	/* Allegro chips */
-	{ 0x125D, 0x1988, 0x0E11, 0x002E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x0E11, 0x0094, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x0E11, 0xB112, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x0E11, 0xB114, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x103C, 0x0012, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x103C, 0x0018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x103C, 0x001C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x103C, 0x001D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x103C, 0x001E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x107B, 0x3350, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x10F7, 0x8338, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x10F7, 0x833C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x10F7, 0x833D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x10F7, 0x833E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x10F7, 0x833F, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x13BD, 0x1018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x13BD, 0x1019, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x13BD, 0x101A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x14FF, 0x0F03, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x14FF, 0x0F04, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x14FF, 0x0F05, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x156D, 0xB400, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x156D, 0xB795, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x156D, 0xB797, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x156D, 0xC700, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
-	{ 0x125D, 0x1988, 0x1033, 0x80F1, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
-	{ 0x125D, 0x1988, 0x103C, 0x001A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, /* HP OmniBook 6100 */
-	{ 0x125D, 0x1988, 0x107B, 0x340A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
-	{ 0x125D, 0x1988, 0x107B, 0x3450, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
-	{ 0x125D, 0x1988, 0x109F, 0x3134, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
-	{ 0x125D, 0x1988, 0x109F, 0x3161, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
-	{ 0x125D, 0x1988, 0x144D, 0x3280, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
-	{ 0x125D, 0x1988, 0x144D, 0x3281, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
-	{ 0x125D, 0x1988, 0x144D, 0xC002, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
-	{ 0x125D, 0x1988, 0x144D, 0xC003, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
-	{ 0x125D, 0x1988, 0x1509, 0x1740, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
-	{ 0x125D, 0x1988, 0x1610, 0x0010, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
-	{ 0x125D, 0x1988, 0x1042, 0x1042, HV_CTRL_ENABLE, 0 },
-	{ 0x125D, 0x1988, 0x107B, 0x9500, HV_CTRL_ENABLE, 0 },
-	{ 0x125D, 0x1988, 0x14FF, 0x0F06, HV_CTRL_ENABLE, 0 },
-	{ 0x125D, 0x1988, 0x1558, 0x8586, HV_CTRL_ENABLE, 0 },
-	{ 0x125D, 0x1988, 0x161F, 0x2011, HV_CTRL_ENABLE, 0 },
+	SND_PCI_QUIRK(0x0E11, 0x002E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x0E11, 0x0094, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x0E11, 0xB112, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x0E11, 0xB114, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x103C, 0x0012, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x103C, 0x0018, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x103C, 0x001C, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x103C, 0x001D, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x103C, 0x001E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x107B, 0x3350, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x10F7, 0x8338, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x10F7, 0x833C, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x10F7, 0x833D, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x10F7, 0x833E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x10F7, 0x833F, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x13BD, 0x1018, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x13BD, 0x1019, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x13BD, 0x101A, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x14FF, 0x0F03, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x14FF, 0x0F04, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x14FF, 0x0F05, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x156D, 0xB400, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x156D, 0xB795, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x156D, 0xB797, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x156D, 0xC700, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+	SND_PCI_QUIRK(0x1033, 0x80F1, NULL,
+		      HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+	SND_PCI_QUIRK(0x103C, 0x001A, NULL, /* HP OmniBook 6100 */
+		      HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+	SND_PCI_QUIRK(0x107B, 0x340A, NULL,
+		      HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+	SND_PCI_QUIRK(0x107B, 0x3450, NULL,
+		      HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+	SND_PCI_QUIRK(0x109F, 0x3134, NULL,
+		      HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+	SND_PCI_QUIRK(0x109F, 0x3161, NULL,
+		      HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+	SND_PCI_QUIRK(0x144D, 0x3280, NULL,
+		      HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+	SND_PCI_QUIRK(0x144D, 0x3281, NULL,
+		      HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+	SND_PCI_QUIRK(0x144D, 0xC002, NULL,
+		      HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+	SND_PCI_QUIRK(0x144D, 0xC003, NULL,
+		      HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+	SND_PCI_QUIRK(0x1509, 0x1740, NULL,
+		      HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+	SND_PCI_QUIRK(0x1610, 0x0010, NULL,
+		      HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+	SND_PCI_QUIRK(0x1042, 0x1042, NULL, HV_CTRL_ENABLE),
+	SND_PCI_QUIRK(0x107B, 0x9500, NULL, HV_CTRL_ENABLE),
+	SND_PCI_QUIRK(0x14FF, 0x0F06, NULL, HV_CTRL_ENABLE),
+	SND_PCI_QUIRK(0x1558, 0x8586, NULL, HV_CTRL_ENABLE),
+	SND_PCI_QUIRK(0x161F, 0x2011, NULL, HV_CTRL_ENABLE),
 	/* Maestro3 chips */
-	{ 0x125D, 0x1998, 0x103C, 0x000E, HV_CTRL_ENABLE, 0 },
-	{ 0x125D, 0x1998, 0x103C, 0x0010, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 6000 */
-	{ 0x125D, 0x1998, 0x103C, 0x0011, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 500 */
-	{ 0x125D, 0x1998, 0x103C, 0x001B, HV_CTRL_ENABLE, 0 },
-	{ 0x125D, 0x1998, 0x104D, 0x80A6, HV_CTRL_ENABLE, 0 },
-	{ 0x125D, 0x1998, 0x104D, 0x80AA, HV_CTRL_ENABLE, 0 },
-	{ 0x125D, 0x1998, 0x107B, 0x5300, HV_CTRL_ENABLE, 0 },
-	{ 0x125D, 0x1998, 0x110A, 0x1998, HV_CTRL_ENABLE, 0 },
-	{ 0x125D, 0x1998, 0x13BD, 0x1015, HV_CTRL_ENABLE, 0 },
-	{ 0x125D, 0x1998, 0x13BD, 0x101C, HV_CTRL_ENABLE, 0 },
-	{ 0x125D, 0x1998, 0x13BD, 0x1802, HV_CTRL_ENABLE, 0 },
-	{ 0x125D, 0x1998, 0x1599, 0x0715, HV_CTRL_ENABLE, 0 },
-	{ 0x125D, 0x1998, 0x5643, 0x5643, HV_CTRL_ENABLE, 0 },
-	{ 0x125D, 0x199A, 0x144D, 0x3260, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
-	{ 0x125D, 0x199A, 0x144D, 0x3261, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
-	{ 0x125D, 0x199A, 0x144D, 0xC000, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
-	{ 0x125D, 0x199A, 0x144D, 0xC001, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
-	{ 0 }
+	SND_PCI_QUIRK(0x103C, 0x000E, NULL, HV_CTRL_ENABLE),
+	SND_PCI_QUIRK(0x103C, 0x0010, NULL, HV_CTRL_ENABLE),
+	SND_PCI_QUIRK(0x103C, 0x0011, NULL, HV_CTRL_ENABLE),
+	SND_PCI_QUIRK(0x103C, 0x001B, NULL, HV_CTRL_ENABLE),
+	SND_PCI_QUIRK(0x104D, 0x80A6, NULL, HV_CTRL_ENABLE),
+	SND_PCI_QUIRK(0x104D, 0x80AA, NULL, HV_CTRL_ENABLE),
+	SND_PCI_QUIRK(0x107B, 0x5300, NULL, HV_CTRL_ENABLE),
+	SND_PCI_QUIRK(0x110A, 0x1998, NULL, HV_CTRL_ENABLE),
+	SND_PCI_QUIRK(0x13BD, 0x1015, NULL, HV_CTRL_ENABLE),
+	SND_PCI_QUIRK(0x13BD, 0x101C, NULL, HV_CTRL_ENABLE),
+	SND_PCI_QUIRK(0x13BD, 0x1802, NULL, HV_CTRL_ENABLE),
+	SND_PCI_QUIRK(0x1599, 0x0715, NULL, HV_CTRL_ENABLE),
+	SND_PCI_QUIRK(0x5643, 0x5643, NULL, HV_CTRL_ENABLE),
+	SND_PCI_QUIRK(0x144D, 0x3260, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
+	SND_PCI_QUIRK(0x144D, 0x3261, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
+	SND_PCI_QUIRK(0x144D, 0xC000, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
+	SND_PCI_QUIRK(0x144D, 0xC001, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
+	{ } /* END */
+};
+
+/* HP Omnibook quirks */
+static struct snd_pci_quirk m3_omnibook_quirk_list[] __devinitdata = {
+	SND_PCI_QUIRK_ID(0x103c, 0x0010), /* HP OmniBook 6000 */
+	SND_PCI_QUIRK_ID(0x103c, 0x0011), /* HP OmniBook 500 */
+	{ } /* END */
 };
 
 /*
@@ -2050,7 +2019,7 @@
 
 	for (i = 0; i < 5; i++) {
 		dir = inw(io + GPIO_DIRECTION);
-		if (! chip->quirk || ! chip->quirk->irda_workaround)
+		if (!chip->irda_workaround)
 			dir |= 0x10; /* assuming pci bus master? */
 
 		snd_m3_remote_codec_config(io, 0);
@@ -2132,6 +2101,10 @@
 }
 
 
+#define FIRMWARE_IN_THE_KERNEL
+
+#ifdef FIRMWARE_IN_THE_KERNEL
+
 /*
  * DSP Code images
  */
@@ -2260,6 +2233,30 @@
     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
 };
 
+static const struct firmware assp_kernel = {
+	.data = (u8 *)assp_kernel_image,
+	.size = sizeof assp_kernel_image
+};
+static const struct firmware assp_minisrc = {
+	.data = (u8 *)assp_minisrc_image,
+	.size = sizeof assp_minisrc_image
+};
+
+#endif /* FIRMWARE_IN_THE_KERNEL */
+
+#ifdef __LITTLE_ENDIAN
+static inline void snd_m3_convert_from_le(const struct firmware *fw) { }
+#else
+static void snd_m3_convert_from_le(const struct firmware *fw)
+{
+	int i;
+	u16 *data = (u16 *)fw->data;
+
+	for (i = 0; i < fw->size / 2; ++i)
+		le16_to_cpus(&data[i]);
+}
+#endif
+
 
 /*
  * initialize ASSP
@@ -2274,6 +2271,7 @@
 static void snd_m3_assp_init(struct snd_m3 *chip)
 {
 	unsigned int i;
+	u16 *data;
 
 	/* zero kernel data */
 	for (i = 0; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
@@ -2291,10 +2289,10 @@
 			  KDATA_DMA_XFER0);
 
 	/* write kernel into code memory.. */
-	for (i = 0 ; i < ARRAY_SIZE(assp_kernel_image); i++) {
+	data = (u16 *)chip->assp_kernel_image->data;
+	for (i = 0 ; i * 2 < chip->assp_kernel_image->size; i++) {
 		snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, 
-				  REV_B_CODE_MEMORY_BEGIN + i, 
-				  assp_kernel_image[i]);
+				  REV_B_CODE_MEMORY_BEGIN + i, data[i]);
 	}
 
 	/*
@@ -2303,10 +2301,10 @@
 	 * drop it there.  It seems that the minisrc doesn't
 	 * need vectors, so we won't bother with them..
 	 */
-	for (i = 0; i < ARRAY_SIZE(assp_minisrc_image); i++) {
+	data = (u16 *)chip->assp_minisrc_image->data;
+	for (i = 0; i * 2 < chip->assp_minisrc_image->size; i++) {
 		snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, 
-				  0x400 + i, 
-				  assp_minisrc_image[i]);
+				  0x400 + i, data[i]);
 	}
 
 	/*
@@ -2444,7 +2442,7 @@
 	       DISABLE_LEGACY);
 	pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w);
 
-	if (chip->hv_quirk && chip->hv_quirk->is_omnibook) {
+	if (chip->is_omnibook) {
 		/*
 		 * Volume buttons on some HP OmniBook laptops don't work
 		 * correctly. This makes them work for the most part.
@@ -2461,8 +2459,7 @@
 	}
 	pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
 	n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD);
-	if (chip->hv_quirk)
-		n |= chip->hv_quirk->config;
+	n |= chip->hv_config;
 	/* For some reason we must always use reduced debounce. */
 	n |= REDUCED_DEBOUNCE;
 	n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING;
@@ -2510,7 +2507,7 @@
 
 	/* TODO: MPU401 not supported yet */
 	val = ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/;
-	if (chip->hv_quirk && (chip->hv_quirk->config & HV_CTRL_ENABLE))
+	if (chip->hv_config & HV_CTRL_ENABLE)
 		val |= HV_INT_ENABLE;
 	outw(val, io + HOST_INT_CTRL);
 	outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
@@ -2553,6 +2550,15 @@
 	if (chip->iobase)
 		pci_release_regions(chip->pci);
 
+#ifdef FIRMWARE_IN_THE_KERNEL
+	if (chip->assp_kernel_image != &assp_kernel)
+#endif
+		release_firmware(chip->assp_kernel_image);
+#ifdef FIRMWARE_IN_THE_KERNEL
+	if (chip->assp_minisrc_image != &assp_minisrc)
+#endif
+		release_firmware(chip->assp_minisrc_image);
+
 	pci_disable_device(chip->pci);
 	kfree(chip);
 	return 0;
@@ -2665,8 +2671,7 @@
 {
 	struct snd_m3 *chip;
 	int i, err;
-	const struct m3_quirk *quirk;
-	const struct m3_hv_quirk *hv_quirk;
+	const struct snd_pci_quirk *quirk;
 	static struct snd_device_ops ops = {
 		.dev_free =	snd_m3_dev_free,
 	};
@@ -2706,34 +2711,32 @@
 	chip->pci = pci;
 	chip->irq = -1;
 
-	for (quirk = m3_quirk_list; quirk->vendor; quirk++) {
-		if (pci->subsystem_vendor == quirk->vendor &&
-		    pci->subsystem_device == quirk->device) {
-			printk(KERN_INFO "maestro3: enabled hack for '%s'\n", quirk->name);
-			chip->quirk = quirk;
-			break;
-		}
-	}
-
-	for (hv_quirk = m3_hv_quirk_list; hv_quirk->vendor; hv_quirk++) {
-		if (pci->vendor == hv_quirk->vendor &&
-		    pci->device == hv_quirk->device &&
-		    pci->subsystem_vendor == hv_quirk->subsystem_vendor &&
-		    pci->subsystem_device == hv_quirk->subsystem_device) {
-			chip->hv_quirk = hv_quirk;
-			break;
-		}
-	}
-
 	chip->external_amp = enable_amp;
 	if (amp_gpio >= 0 && amp_gpio <= 0x0f)
 		chip->amp_gpio = amp_gpio;
-	else if (chip->quirk && chip->quirk->amp_gpio >= 0)
-		chip->amp_gpio = chip->quirk->amp_gpio;
-	else if (chip->allegro_flag)
-		chip->amp_gpio = GPO_EXT_AMP_ALLEGRO;
-	else /* presumably this is for all 'maestro3's.. */
-		chip->amp_gpio = GPO_EXT_AMP_M3;
+	else {
+		quirk = snd_pci_quirk_lookup(pci, m3_amp_quirk_list);
+		if (quirk) {
+			snd_printdd(KERN_INFO "maestro3: set amp-gpio "
+				    "for '%s'\n", quirk->name);
+			chip->amp_gpio = quirk->value;
+		} else if (chip->allegro_flag)
+			chip->amp_gpio = GPO_EXT_AMP_ALLEGRO;
+		else /* presumably this is for all 'maestro3's.. */
+			chip->amp_gpio = GPO_EXT_AMP_M3;
+	}
+
+	quirk = snd_pci_quirk_lookup(pci, m3_irda_quirk_list);
+	if (quirk) {
+		snd_printdd(KERN_INFO "maestro3: enabled irda workaround "
+			    "for '%s'\n", quirk->name);
+		chip->irda_workaround = 1;
+	}
+	quirk = snd_pci_quirk_lookup(pci, m3_hv_quirk_list);
+	if (quirk)
+		chip->hv_config = quirk->value;
+	if (snd_pci_quirk_lookup(pci, m3_omnibook_quirk_list))
+		chip->is_omnibook = 1;
 
 	chip->num_substreams = NR_DSPS;
 	chip->substreams = kcalloc(chip->num_substreams, sizeof(struct m3_dma),
@@ -2744,6 +2747,30 @@
 		return -ENOMEM;
 	}
 
+	err = request_firmware(&chip->assp_kernel_image,
+			       "ess/maestro3_assp_kernel.fw", &pci->dev);
+	if (err < 0) {
+#ifdef FIRMWARE_IN_THE_KERNEL
+		chip->assp_kernel_image = &assp_kernel;
+#else
+		snd_m3_free(chip);
+		return err;
+#endif
+	} else
+		snd_m3_convert_from_le(chip->assp_kernel_image);
+
+	err = request_firmware(&chip->assp_minisrc_image,
+			       "ess/maestro3_assp_minisrc.fw", &pci->dev);
+	if (err < 0) {
+#ifdef FIRMWARE_IN_THE_KERNEL
+		chip->assp_minisrc_image = &assp_minisrc;
+#else
+		snd_m3_free(chip);
+		return err;
+#endif
+	} else
+		snd_m3_convert_from_le(chip->assp_minisrc_image);
+
 	if ((err = pci_request_regions(pci, card->driver)) < 0) {
 		snd_m3_free(chip);
 		return err;
diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c
index 13de0f7..d7d15c0 100644
--- a/sound/pci/mixart/mixart_mixer.c
+++ b/sound/pci/mixart/mixart_mixer.c
@@ -389,7 +389,7 @@
 	return changed;
 }
 
-static DECLARE_TLV_DB_SCALE(db_scale_analog, -9600, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_analog, -9600, 50, 0);
 
 static struct snd_kcontrol_new mixart_control_analog_level = {
 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -872,7 +872,7 @@
 	return changed;
 }
 
-static DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0);
 
 static struct snd_kcontrol_new snd_mixart_pcm_vol =
 {
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 879e31a..03b3a47 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -1628,23 +1628,15 @@
 }
 
 
-struct nm256_quirk {
-	unsigned short vendor;
-	unsigned short device;
-	int type;
-};
-
 enum { NM_BLACKLISTED, NM_RESET_WORKAROUND, NM_RESET_WORKAROUND_2 };
 
-static struct nm256_quirk nm256_quirks[] __devinitdata = {
+static struct snd_pci_quirk nm256_quirks[] __devinitdata = {
 	/* HP omnibook 4150 has cs4232 codec internally */
-	{ .vendor = 0x103c, .device = 0x0007, .type = NM_BLACKLISTED },
-	/* Sony PCG-F305 */
-	{ .vendor = 0x104d, .device = 0x8041, .type = NM_RESET_WORKAROUND },
-	/* Dell Latitude LS */
-	{ .vendor = 0x1028, .device = 0x0080, .type = NM_RESET_WORKAROUND },
-	/* Dell Latitude CSx */
-	{ .vendor = 0x1028, .device = 0x0091, .type = NM_RESET_WORKAROUND_2 },
+	SND_PCI_QUIRK(0x103c, 0x0007, "HP omnibook 4150", NM_BLACKLISTED),
+	/* Reset workarounds to avoid lock-ups */
+	SND_PCI_QUIRK(0x104d, 0x8041, "Sony PCG-F305", NM_RESET_WORKAROUND),
+	SND_PCI_QUIRK(0x1028, 0x0080, "Dell Latitude LS", NM_RESET_WORKAROUND),
+	SND_PCI_QUIRK(0x1028, 0x0091, "Dell Latitude CSx", NM_RESET_WORKAROUND_2),
 	{ } /* terminator */
 };
 
@@ -1655,26 +1647,22 @@
 	struct snd_card *card;
 	struct nm256 *chip;
 	int err;
-	struct nm256_quirk *q;
-	u16 subsystem_vendor, subsystem_device;
+	const struct snd_pci_quirk *q;
 
-	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) {
-			switch (q->type) {
-			case NM_BLACKLISTED:
-				printk(KERN_INFO "nm256: The device is blacklisted. "
-				       "Loading stopped\n");
-				return -ENODEV;
-			case NM_RESET_WORKAROUND_2:
-				reset_workaround_2 = 1;
-				/* Fall-through */
-			case NM_RESET_WORKAROUND:
-				reset_workaround = 1;
-				break;
-			}
+	q = snd_pci_quirk_lookup(pci, nm256_quirks);
+	if (q) {
+		snd_printdd(KERN_INFO "nm256: Enabled quirk for %s.\n", q->name);
+		switch (q->value) {
+		case NM_BLACKLISTED:
+			printk(KERN_INFO "nm256: The device is blacklisted. "
+			       "Loading stopped\n");
+			return -ENODEV;
+		case NM_RESET_WORKAROUND_2:
+			reset_workaround_2 = 1;
+			/* Fall-through */
+		case NM_RESET_WORKAROUND:
+			reset_workaround = 1;
+			break;
 		}
 	}
 
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c
index b133ad9..d9cc8d2 100644
--- a/sound/pci/pcxhr/pcxhr_mixer.c
+++ b/sound/pci/pcxhr/pcxhr_mixer.c
@@ -44,8 +44,8 @@
 #define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX  128	/*    0.0 dB */
 #define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104	/*  -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */
 
-static DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -12800, 100, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -12800, 100, 0);
 
 static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel)
 {
@@ -195,7 +195,7 @@
 #define PCXHR_DIGITAL_LEVEL_MAX		0x1ff	/* +18 dB */
 #define PCXHR_DIGITAL_ZERO_LEVEL	0x1b7	/*  0 dB */
 
-static DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0);
 
 #define MORE_THAN_ONE_STREAM_LEVEL	0x000001
 #define VALID_STREAM_PAN_LEVEL_MASK	0x800000
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 6383987..89b3c7f 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -80,6 +80,7 @@
 /* Write registers. These are defined as byte-offsets from the iobase value.
  */
 #define HDSP_resetPointer               0
+#define HDSP_freqReg			0
 #define HDSP_outputBufferAddress	32
 #define HDSP_inputBufferAddress		36
 #define HDSP_controlRegister		64
@@ -469,6 +470,7 @@
 	struct pci_dev       *pci;
 	struct snd_kcontrol *spdif_ctl;
         unsigned short        mixer_matrix[HDSP_MATRIX_MIXER_SIZE];
+	unsigned int          dds_value; /* last value written to freq register */
 };
 
 /* These tables map the ALSA channels 1..N to the channels that we
@@ -598,6 +600,7 @@
 		return (64 * out) + (32 + (in));
 	case 0x96:
 	case 0x97:
+	case 0x98:
 		return (32 * out) + (16 + (in));
 	default:
 		return (52 * out) + (26 + (in));
@@ -611,6 +614,7 @@
 		return (64 * out) + in;
 	case 0x96:
 	case 0x97:
+	case 0x98:
 		return (32 * out) + in;
 	default:
 		return (52 * out) + in;
@@ -938,6 +942,11 @@
 static void hdsp_reset_hw_pointer(struct hdsp *hdsp)
 {
 	hdsp_write (hdsp, HDSP_resetPointer, 0);
+	if (hdsp->io_type == H9632 && hdsp->firmware_rev >= 152)
+		/* HDSP_resetPointer = HDSP_freqReg, which is strange and
+		 * requires (?) to write again DDS value after a reset pointer
+		 * (at least, it works like this) */
+		hdsp_write (hdsp, HDSP_freqReg, hdsp->dds_value);
 }
 
 static void hdsp_start_audio(struct hdsp *s)
@@ -982,6 +991,30 @@
 	return 0;
 }
 
+static void hdsp_set_dds_value(struct hdsp *hdsp, int rate)
+{
+	u64 n;
+	u32 r;
+	
+	if (rate >= 112000)
+		rate /= 4;
+	else if (rate >= 56000)
+		rate /= 2;
+
+	/* RME says n = 104857600000000, but in the windows MADI driver, I see:
+//	return 104857600000000 / rate; // 100 MHz
+	return 110100480000000 / rate; // 105 MHz
+        */	   
+	n = 104857600000000ULL;  /*  =  2^20 * 10^8 */
+	div64_32(&n, rate, &r);
+	/* n should be less than 2^32 for being written to FREQ register */
+	snd_assert((n >> 32) == 0);
+	/* HDSP_freqReg and HDSP_resetPointer are the same, so keep the DDS
+	   value to write it after a reset */
+	hdsp->dds_value = n;
+	hdsp_write(hdsp, HDSP_freqReg, hdsp->dds_value);
+}
+
 static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
 {
 	int reject_if_open = 0;
@@ -1090,6 +1123,10 @@
 	hdsp->control_register |= rate_bits;
 	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
 
+	/* For HDSP9632 rev 152, need to set DDS value in FREQ register */
+	if (hdsp->io_type == H9632 && hdsp->firmware_rev >= 152)
+		hdsp_set_dds_value(hdsp, rate);
+
 	if (rate >= 128000) {
 		hdsp->channel_map = channel_map_H9632_qs;
 	} else if (rate > 48000) {
@@ -4943,6 +4980,7 @@
 	hdsp->irq = pci->irq;
 	hdsp->precise_ptr = 0;
 	hdsp->use_midi_tasklet = 1;
+	hdsp->dds_value = 0;
 
 	if ((err = snd_hdsp_initialize_memory(hdsp)) < 0)
 		return err;
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 0547f6f..e0215ac 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -6,6 +6,8 @@
  *      code based on hdsp.c   Paul Davis
  *                             Marcus Andersson
  *                             Thomas Charbonnel
+ *      Modified 2006-06-01 for AES32 support by Remy Bruno
+ *                                               <remy.bruno@trinnov.com>
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -77,7 +79,8 @@
 
 MODULE_AUTHOR
       ("Winfried Ritsch <ritsch_AT_iem.at>, Paul Davis <paul@linuxaudiosystems.com>, "
-       "Marcus Andersson, Thomas Charbonnel <thomas@undata.org>");
+       "Marcus Andersson, Thomas Charbonnel <thomas@undata.org>, "
+       "Remy Bruno <remy.bruno@trinnov.com>");
 MODULE_DESCRIPTION("RME HDSPM");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
@@ -107,7 +110,12 @@
 /* --- Read registers. ---
    These are defined as byte-offsets from the iobase value */
 #define HDSPM_statusRegister    0
-#define HDSPM_statusRegister2  96
+/*#define HDSPM_statusRegister2  96 */
+/* after RME Windows driver sources, status2 is 4-byte word # 48 = word at
+ * offset 192, for AES32 *and* MADI
+ * => need to check that offset 192 is working on MADI */
+#define HDSPM_statusRegister2  192
+#define HDSPM_timecodeRegister 128
 
 #define HDSPM_midiDataIn0     360
 #define HDSPM_midiDataIn1     364
@@ -140,37 +148,50 @@
 #define HDSPM_Frequency0  (1<<6)  /* 0=44.1kHz/88.2kHz 1=48kHz/96kHz */
 #define HDSPM_Frequency1  (1<<7)  /* 0=32kHz/64kHz */
 #define HDSPM_DoubleSpeed (1<<8)  /* 0=normal speed, 1=double speed */
-#define HDSPM_QuadSpeed   (1<<31) /* quad speed bit, not implemented now */
+#define HDSPM_QuadSpeed   (1<<31) /* quad speed bit */
 
+#define HDSPM_Professional (1<<9) /* Professional */ /* AES32 ONLY */
 #define HDSPM_TX_64ch     (1<<10) /* Output 64channel MODE=1,
-				     56channelMODE=0 */
+				     56channelMODE=0 */ /* MADI ONLY*/
+#define HDSPM_Emphasis    (1<<10) /* Emphasis */ /* AES32 ONLY */
 
 #define HDSPM_AutoInp     (1<<11) /* Auto Input (takeover) == Safe Mode, 
-                                     0=off, 1=on  */
+                                     0=off, 1=on  */ /* MADI ONLY */
+#define HDSPM_Dolby       (1<<11) /* Dolby = "NonAudio" ?? */ /* AES32 ONLY */
 
-#define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax */
+#define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax */ /* MADI ONLY*/
 #define HDSPM_InputSelect1 (1<<15) /* should be 0 */
 
 #define HDSPM_SyncRef0     (1<<16) /* 0=WOrd, 1=MADI */
-#define HDSPM_SyncRef1     (1<<17) /* should be 0 */
+#define HDSPM_SyncRef1     (1<<17) /* for AES32: SyncRefN codes the AES # */
+#define HDSPM_SyncRef2     (1<<13)
+#define HDSPM_SyncRef3     (1<<25)
 
+#define HDSPM_SMUX         (1<<18) /* Frame ??? */ /* MADI ONY */
 #define HDSPM_clr_tms      (1<<19) /* clear track marker, do not use 
                                       AES additional bits in
 				      lower 5 Audiodatabits ??? */
+#define HDSPM_taxi_reset   (1<<20) /* ??? */ /* MADI ONLY ? */
+#define HDSPM_WCK48        (1<<20) /* Frame ??? = HDSPM_SMUX */ /* AES32 ONLY */
 
 #define HDSPM_Midi0InterruptEnable (1<<22)
 #define HDSPM_Midi1InterruptEnable (1<<23)
 
 #define HDSPM_LineOut (1<<24) /* Analog Out on channel 63/64 on=1, mute=0 */
 
+#define HDSPM_DS_DoubleWire (1<<26) /* AES32 ONLY */
+#define HDSPM_QS_DoubleWire (1<<27) /* AES32 ONLY */
+#define HDSPM_QS_QuadWire   (1<<28) /* AES32 ONLY */
+
+#define HDSPM_wclk_sel (1<<30)
 
 /* --- bit helper defines */
 #define HDSPM_LatencyMask    (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2)
-#define HDSPM_FrequencyMask  (HDSPM_Frequency0|HDSPM_Frequency1)
+#define HDSPM_FrequencyMask  (HDSPM_Frequency0|HDSPM_Frequency1|HDSPM_DoubleSpeed|HDSPM_QuadSpeed)
 #define HDSPM_InputMask      (HDSPM_InputSelect0|HDSPM_InputSelect1)
 #define HDSPM_InputOptical   0
 #define HDSPM_InputCoaxial   (HDSPM_InputSelect0)
-#define HDSPM_SyncRefMask    (HDSPM_SyncRef0|HDSPM_SyncRef1)
+#define HDSPM_SyncRefMask    (HDSPM_SyncRef0|HDSPM_SyncRef1|HDSPM_SyncRef2|HDSPM_SyncRef3)
 #define HDSPM_SyncRef_Word   0
 #define HDSPM_SyncRef_MADI   (HDSPM_SyncRef0)
 
@@ -183,6 +204,9 @@
 #define HDSPM_Frequency64KHz   (HDSPM_DoubleSpeed|HDSPM_Frequency0)
 #define HDSPM_Frequency88_2KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1)
 #define HDSPM_Frequency96KHz   (HDSPM_DoubleSpeed|HDSPM_Frequency1|HDSPM_Frequency0)
+#define HDSPM_Frequency128KHz   (HDSPM_QuadSpeed|HDSPM_Frequency0)
+#define HDSPM_Frequency176_4KHz   (HDSPM_QuadSpeed|HDSPM_Frequency1)
+#define HDSPM_Frequency192KHz   (HDSPM_QuadSpeed|HDSPM_Frequency1|HDSPM_Frequency0)
 
 /* --- for internal discrimination */
 #define HDSPM_CLOCK_SOURCE_AUTOSYNC          0	/* Sample Clock Sources */
@@ -229,7 +253,8 @@
 #define HDSPM_BIGENDIAN_MODE  (1<<9)
 #define HDSPM_RD_MULTIPLE     (1<<10)
 
-/* --- Status Register bits --- */
+/* --- Status Register bits --- */ /* MADI ONLY */ /* Bits defined here and
+     that do not conflict with specific bits for AES32 seem to be valid also for the AES32 */
 #define HDSPM_audioIRQPending    (1<<0)	/* IRQ is high and pending */
 #define HDSPM_RX_64ch            (1<<1)	/* Input 64chan. MODE=1, 56chn. MODE=0 */
 #define HDSPM_AB_int             (1<<2)	/* InputChannel Opt=0, Coax=1 (like inp0) */
@@ -263,7 +288,7 @@
 #define HDSPM_madiFreq176_4 (HDSPM_madiFreq3)
 #define HDSPM_madiFreq192   (HDSPM_madiFreq3|HDSPM_madiFreq0)
 
-/* Status2 Register bits */
+/* Status2 Register bits */ /* MADI ONLY */
 
 #define HDSPM_version0 (1<<0)	/* not realy defined but I guess */
 #define HDSPM_version1 (1<<1)	/* in former cards it was ??? */
@@ -297,6 +322,56 @@
 #define HDSPM_SelSyncRef_MADI      (HDSPM_SelSyncRef0)
 #define HDSPM_SelSyncRef_NVALID    (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|HDSPM_SelSyncRef2)
 
+/*
+   For AES32, bits for status, status2 and timecode are different
+*/
+/* status */
+#define HDSPM_AES32_wcLock	0x0200000
+#define HDSPM_AES32_wcFreq_bit  22
+/* (status >> HDSPM_AES32_wcFreq_bit) & 0xF gives WC frequency (cf function 
+  HDSPM_bit2freq */
+#define HDSPM_AES32_syncref_bit  16
+/* (status >> HDSPM_AES32_syncref_bit) & 0xF gives sync source */
+
+#define HDSPM_AES32_AUTOSYNC_FROM_WORD 0
+#define HDSPM_AES32_AUTOSYNC_FROM_AES1 1
+#define HDSPM_AES32_AUTOSYNC_FROM_AES2 2
+#define HDSPM_AES32_AUTOSYNC_FROM_AES3 3
+#define HDSPM_AES32_AUTOSYNC_FROM_AES4 4
+#define HDSPM_AES32_AUTOSYNC_FROM_AES5 5
+#define HDSPM_AES32_AUTOSYNC_FROM_AES6 6
+#define HDSPM_AES32_AUTOSYNC_FROM_AES7 7
+#define HDSPM_AES32_AUTOSYNC_FROM_AES8 8
+#define HDSPM_AES32_AUTOSYNC_FROM_NONE -1
+
+/*  status2 */
+/* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */
+#define HDSPM_LockAES   0x80
+#define HDSPM_LockAES1  0x80
+#define HDSPM_LockAES2  0x40
+#define HDSPM_LockAES3  0x20
+#define HDSPM_LockAES4  0x10
+#define HDSPM_LockAES5  0x8
+#define HDSPM_LockAES6  0x4
+#define HDSPM_LockAES7  0x2
+#define HDSPM_LockAES8  0x1
+/*
+   Timecode
+   After windows driver sources, bits 4*i to 4*i+3 give the input frequency on
+   AES i+1
+ bits 3210
+      0001  32kHz
+      0010  44.1kHz
+      0011  48kHz
+      0100  64kHz
+      0101  88.2kHz
+      0110  96kHz
+      0111  128kHz
+      1000  176.4kHz
+      1001  192kHz
+  NB: Timecode register doesn't seem to work on AES32 card revision 230
+*/
+
 /* Mixer Values */
 #define UNITY_GAIN          32768	/* = 65536/2 */
 #define MINUS_INFINITY_GAIN 0
@@ -314,10 +389,14 @@
    size is the same regardless of the number of channels, and
    also the latency to use. 
    for one direction !!!
+   => need to mupltiply by 2!!
 */
-#define HDSPM_DMA_AREA_BYTES (HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES)
+#define HDSPM_DMA_AREA_BYTES (2 * HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES)
 #define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024)
 
+/* revisions >= 230 indicate AES32 card */
+#define HDSPM_AESREVISION 230
+
 struct hdspm_midi {
 	struct hdspm *hdspm;
 	int id;
@@ -336,7 +415,9 @@
         struct snd_pcm_substream *playback_substream; /* and/or capture stream */
 
 	char *card_name;	     /* for procinfo */
-	unsigned short firmware_rev; /* dont know if relevant */
+	unsigned short firmware_rev; /* dont know if relevant (yes if AES32)*/
+
+	unsigned char is_aes32;    /* indicates if card is AES32 */
 
 	int precise_ptr;	/* use precise pointers, to be tested */
 	int monitor_outs;	/* set up monitoring outs init flag */
@@ -453,6 +534,15 @@
 static void hdspm_set_sgbuf(struct hdspm * hdspm, struct snd_sg_buf *sgbuf,
 			     unsigned int reg, int channels);
 
+static inline int HDSPM_bit2freq(int n)
+{
+	static int bit2freq_tab[] = { 0, 32000, 44100, 48000, 64000, 88200,
+		96000, 128000, 176400, 192000 };
+	if (n < 1 || n > 9)
+		return 0;
+	return bit2freq_tab[n];
+}
+
 /* Write/read to/from HDSPM with Adresses in Bytes
    not words but only 32Bit writes are allowed */
 
@@ -544,86 +634,105 @@
 /* check for external sample rate */
 static inline int hdspm_external_sample_rate(struct hdspm * hdspm)
 {
-	unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
-	unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
-	unsigned int rate_bits;
-	int rate = 0;
+	if (hdspm->is_aes32) {
+		unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+		unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
+		unsigned int timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
 
-	/* if wordclock has synced freq and wordclock is valid */
-	if ((status2 & HDSPM_wcLock) != 0 &&
-	    (status & HDSPM_SelSyncRef0) == 0) {
+		int syncref = hdspm_autosync_ref(hdspm);
 
-		rate_bits = status2 & HDSPM_wcFreqMask;
+		if (syncref == HDSPM_AES32_AUTOSYNC_FROM_WORD &&
+				status & HDSPM_AES32_wcLock)
+			return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF);
+		if (syncref >= HDSPM_AES32_AUTOSYNC_FROM_AES1 &&
+			syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 &&
+			status2 & (HDSPM_LockAES >>
+			          (syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)))
+			return HDSPM_bit2freq((timecode >>
+			  (4*(syncref-HDSPM_AES32_AUTOSYNC_FROM_AES1))) & 0xF);
+		return 0;
+	} else {
+		unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+		unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
+		unsigned int rate_bits;
+		int rate = 0;
 
-		switch (rate_bits) {
-		case HDSPM_wcFreq32:
-			rate = 32000;
-			break;
-		case HDSPM_wcFreq44_1:
-			rate = 44100;
-			break;
-		case HDSPM_wcFreq48:
-			rate = 48000;
-			break;
-		case HDSPM_wcFreq64:
-			rate = 64000;
-			break;
-		case HDSPM_wcFreq88_2:
-			rate = 88200;
-			break;
-		case HDSPM_wcFreq96:
-			rate = 96000;
-			break;
-			/* Quadspeed Bit missing ???? */
-		default:
-			rate = 0;
-			break;
+		/* if wordclock has synced freq and wordclock is valid */
+		if ((status2 & HDSPM_wcLock) != 0 &&
+				(status & HDSPM_SelSyncRef0) == 0) {
+
+			rate_bits = status2 & HDSPM_wcFreqMask;
+
+			switch (rate_bits) {
+			case HDSPM_wcFreq32:
+				rate = 32000;
+				break;
+			case HDSPM_wcFreq44_1:
+				rate = 44100;
+				break;
+			case HDSPM_wcFreq48:
+				rate = 48000;
+				break;
+			case HDSPM_wcFreq64:
+				rate = 64000;
+				break;
+			case HDSPM_wcFreq88_2:
+				rate = 88200;
+				break;
+			case HDSPM_wcFreq96:
+				rate = 96000;
+				break;
+				/* Quadspeed Bit missing ???? */
+			default:
+				rate = 0;
+				break;
+			}
 		}
-	}
 
-	/* if rate detected and Syncref is Word than have it, word has priority to MADI */
-	if (rate != 0
-	    && (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD)
+		/* if rate detected and Syncref is Word than have it, word has priority to MADI */
+		if (rate != 0 &&
+	            (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD)
+			return rate;
+
+		/* maby a madi input (which is taken if sel sync is madi) */
+		if (status & HDSPM_madiLock) {
+			rate_bits = status & HDSPM_madiFreqMask;
+
+			switch (rate_bits) {
+			case HDSPM_madiFreq32:
+				rate = 32000;
+				break;
+			case HDSPM_madiFreq44_1:
+				rate = 44100;
+				break;
+			case HDSPM_madiFreq48:
+				rate = 48000;
+				break;
+			case HDSPM_madiFreq64:
+				rate = 64000;
+				break;
+			case HDSPM_madiFreq88_2:
+				rate = 88200;
+				break;
+			case HDSPM_madiFreq96:
+				rate = 96000;
+				break;
+			case HDSPM_madiFreq128:
+				rate = 128000;
+				break;
+			case HDSPM_madiFreq176_4:
+				rate = 176400;
+				break;
+			case HDSPM_madiFreq192:
+				rate = 192000;
+				break;
+			default:
+				rate = 0;
+				break;
+			}
+		}
 		return rate;
-
-	/* maby a madi input (which is taken if sel sync is madi) */
-	if (status & HDSPM_madiLock) {
-		rate_bits = status & HDSPM_madiFreqMask;
-
-		switch (rate_bits) {
-		case HDSPM_madiFreq32:
-			rate = 32000;
-			break;
-		case HDSPM_madiFreq44_1:
-			rate = 44100;
-			break;
-		case HDSPM_madiFreq48:
-			rate = 48000;
-			break;
-		case HDSPM_madiFreq64:
-			rate = 64000;
-			break;
-		case HDSPM_madiFreq88_2:
-			rate = 88200;
-			break;
-		case HDSPM_madiFreq96:
-			rate = 96000;
-			break;
-		case HDSPM_madiFreq128:
-			rate = 128000;
-			break;
-		case HDSPM_madiFreq176_4:
-			rate = 176400;
-			break;
-		case HDSPM_madiFreq192:
-			rate = 192000;
-			break;
-		default:
-			rate = 0;
-			break;
-		}
 	}
-	return rate;
 }
 
 /* Latency function */
@@ -676,7 +785,8 @@
 	int n = hdspm->period_bytes;
 	void *buf = hdspm->playback_buffer;
 
-	snd_assert(buf != NULL, return);
+	if (buf == NULL)
+		return;
 
 	for (i = 0; i < HDSPM_MAX_CHANNELS; i++) {
 		memset(buf, 0, n);
@@ -716,6 +826,7 @@
 	int current_rate;
 	int rate_bits;
 	int not_set = 0;
+	int is_single, is_double, is_quad;
 
 	/* ASSUMPTION: hdspm->lock is either set, or there is no need for
 	   it (e.g. during module initialization).
@@ -766,43 +877,56 @@
 	   changes in the read/write routines.  
 	 */
 
+	is_single = (current_rate <= 48000);
+	is_double = (current_rate > 48000 && current_rate <= 96000);
+	is_quad = (current_rate > 96000);
+
 	switch (rate) {
 	case 32000:
-		if (current_rate > 48000) {
+		if (!is_single)
 			reject_if_open = 1;
-		}
 		rate_bits = HDSPM_Frequency32KHz;
 		break;
 	case 44100:
-		if (current_rate > 48000) {
+		if (!is_single)
 			reject_if_open = 1;
-		}
 		rate_bits = HDSPM_Frequency44_1KHz;
 		break;
 	case 48000:
-		if (current_rate > 48000) {
+		if (!is_single)
 			reject_if_open = 1;
-		}
 		rate_bits = HDSPM_Frequency48KHz;
 		break;
 	case 64000:
-		if (current_rate <= 48000) {
+		if (!is_double)
 			reject_if_open = 1;
-		}
 		rate_bits = HDSPM_Frequency64KHz;
 		break;
 	case 88200:
-		if (current_rate <= 48000) {
+		if (!is_double)
 			reject_if_open = 1;
-		}
 		rate_bits = HDSPM_Frequency88_2KHz;
 		break;
 	case 96000:
-		if (current_rate <= 48000) {
+		if (!is_double)
 			reject_if_open = 1;
-		}
 		rate_bits = HDSPM_Frequency96KHz;
 		break;
+	case 128000:
+		if (!is_quad)
+			reject_if_open = 1;
+		rate_bits = HDSPM_Frequency128KHz;
+		break;
+	case 176400:
+		if (!is_quad)
+			reject_if_open = 1;
+		rate_bits = HDSPM_Frequency176_4KHz;
+		break;
+	case 192000:
+		if (!is_quad)
+			reject_if_open = 1;
+		rate_bits = HDSPM_Frequency192KHz;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -819,7 +943,7 @@
 	hdspm->control_register |= rate_bits;
 	hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
 
-	if (rate > 64000)
+	if (rate > 96000 /* 64000*/)
 		hdspm->channel_map = channel_map_madi_qs;
 	else if (rate > 48000)
 		hdspm->channel_map = channel_map_madi_ds;
@@ -1455,11 +1579,27 @@
 	/* Notice that this looks at the requested sync source,
 	   not the one actually in use.
 	 */
-	switch (hdspm->control_register & HDSPM_SyncRefMask) {
-	case HDSPM_SyncRef_Word:
-		return HDSPM_SYNC_FROM_WORD;
-	case HDSPM_SyncRef_MADI:
-		return HDSPM_SYNC_FROM_MADI;
+	if (hdspm->is_aes32) {
+		switch (hdspm->control_register & HDSPM_SyncRefMask) {
+		/* number gives AES index, except for 0 which
+		   corresponds to WordClock */
+		case 0: return 0;
+		case HDSPM_SyncRef0: return 1;
+		case HDSPM_SyncRef1: return 2;
+		case HDSPM_SyncRef1+HDSPM_SyncRef0: return 3;
+		case HDSPM_SyncRef2: return 4;
+		case HDSPM_SyncRef2+HDSPM_SyncRef0: return 5;
+		case HDSPM_SyncRef2+HDSPM_SyncRef1: return 6;
+		case HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0: return 7;
+		case HDSPM_SyncRef3: return 8;
+		}
+	} else {
+		switch (hdspm->control_register & HDSPM_SyncRefMask) {
+		case HDSPM_SyncRef_Word:
+			return HDSPM_SYNC_FROM_WORD;
+		case HDSPM_SyncRef_MADI:
+			return HDSPM_SYNC_FROM_MADI;
+		}
 	}
 
 	return HDSPM_SYNC_FROM_WORD;
@@ -1469,15 +1609,49 @@
 {
 	hdspm->control_register &= ~HDSPM_SyncRefMask;
 
-	switch (pref) {
-	case HDSPM_SYNC_FROM_MADI:
-		hdspm->control_register |= HDSPM_SyncRef_MADI;
-		break;
-	case HDSPM_SYNC_FROM_WORD:
-		hdspm->control_register |= HDSPM_SyncRef_Word;
-		break;
-	default:
-		return -1;
+	if (hdspm->is_aes32) {
+		switch (pref) {
+		case 0:
+		       hdspm->control_register |= 0;
+		       break;
+		case 1:
+		       hdspm->control_register |= HDSPM_SyncRef0;
+		       break;
+		case 2:
+		       hdspm->control_register |= HDSPM_SyncRef1;
+		       break;
+		case 3:
+		       hdspm->control_register |= HDSPM_SyncRef1+HDSPM_SyncRef0;
+		       break;
+		case 4:
+		       hdspm->control_register |= HDSPM_SyncRef2;
+		       break;
+		case 5:
+		       hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef0;
+		       break;
+		case 6:
+		       hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef1;
+		       break;
+		case 7:
+		       hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0;
+		       break;
+		case 8:
+		       hdspm->control_register |= HDSPM_SyncRef3;
+		       break;
+		default:
+		       return -1;
+		}
+	} else {
+		switch (pref) {
+		case HDSPM_SYNC_FROM_MADI:
+			hdspm->control_register |= HDSPM_SyncRef_MADI;
+			break;
+		case HDSPM_SYNC_FROM_WORD:
+			hdspm->control_register |= HDSPM_SyncRef_Word;
+			break;
+		default:
+			return -1;
+		}
 	}
 	hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
 	return 0;
@@ -1486,18 +1660,36 @@
 static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = { "Word", "MADI" };
+	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
 
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
+	if (hdspm->is_aes32) {
+		static char *texts[] = { "Word", "AES1", "AES2", "AES3",
+			"AES4", "AES5",	"AES6", "AES7", "AES8" };
 
-	uinfo->value.enumerated.items = 2;
+		uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+		uinfo->count = 1;
 
-	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]);
+		uinfo->value.enumerated.items = 9;
+
+		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]);
+	} else {
+		static char *texts[] = { "Word", "MADI" };
+
+		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;
 }
 
@@ -1517,7 +1709,7 @@
 	int change, max;
 	unsigned int val;
 
-	max = 2;
+	max = hdspm->is_aes32 ? 9 : 2;
 
 	if (!snd_hdspm_use_is_exclusive(hdspm))
 		return -EBUSY;
@@ -1542,40 +1734,64 @@
 
 static int hdspm_autosync_ref(struct hdspm * hdspm)
 {
-	/* This looks at the autosync selected sync reference */
-	unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+	if (hdspm->is_aes32) {
+		unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
+		unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF;
+		if (syncref == 0)
+			return HDSPM_AES32_AUTOSYNC_FROM_WORD;
+		if (syncref <= 8)
+			return syncref;
+		return HDSPM_AES32_AUTOSYNC_FROM_NONE;
+	} else {
+		/* This looks at the autosync selected sync reference */
+		unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
 
-	switch (status2 & HDSPM_SelSyncRefMask) {
+		switch (status2 & HDSPM_SelSyncRefMask) {
+		case HDSPM_SelSyncRef_WORD:
+			return HDSPM_AUTOSYNC_FROM_WORD;
+		case HDSPM_SelSyncRef_MADI:
+			return HDSPM_AUTOSYNC_FROM_MADI;
+		case HDSPM_SelSyncRef_NVALID:
+			return HDSPM_AUTOSYNC_FROM_NONE;
+		default:
+			return 0;
+		}
 
-	case HDSPM_SelSyncRef_WORD:
-		return HDSPM_AUTOSYNC_FROM_WORD;
-
-	case HDSPM_SelSyncRef_MADI:
-		return HDSPM_AUTOSYNC_FROM_MADI;
-
-	case HDSPM_SelSyncRef_NVALID:
-		return HDSPM_AUTOSYNC_FROM_NONE;
-
-	default:
 		return 0;
 	}
-
-	return 0;
 }
 
 static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol,
 				       struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = { "WordClock", "MADI", "None" };
+	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
 
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 3;
-	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]);
+	if (hdspm->is_aes32) {
+		static char *texts[] = { "WordClock", "AES1", "AES2", "AES3",
+			"AES4",	"AES5", "AES6", "AES7", "AES8", "None"};
+
+		uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+		uinfo->count = 1;
+		uinfo->value.enumerated.items = 10;
+		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]);
+	}
+	else
+	{
+		static char *texts[] = { "WordClock", "MADI", "None" };
+
+		uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+		uinfo->count = 1;
+		uinfo->value.enumerated.items = 3;
+		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;
 }
 
@@ -1841,6 +2057,195 @@
 	return change;
 }
 
+#define HDSPM_EMPHASIS(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .name = xname, \
+  .index = xindex, \
+  .info = snd_hdspm_info_emphasis, \
+  .get = snd_hdspm_get_emphasis, \
+  .put = snd_hdspm_put_emphasis \
+}
+
+static int hdspm_emphasis(struct hdspm * hdspm)
+{
+	return (hdspm->control_register & HDSPM_Emphasis) ? 1 : 0;
+}
+
+static int hdspm_set_emphasis(struct hdspm * hdspm, int emp)
+{
+	if (emp)
+		hdspm->control_register |= HDSPM_Emphasis;
+	else
+		hdspm->control_register &= ~HDSPM_Emphasis;
+	hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+	return 0;
+}
+
+static int snd_hdspm_info_emphasis(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_hdspm_get_emphasis(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+	spin_lock_irq(&hdspm->lock);
+	ucontrol->value.enumerated.item[0] = hdspm_emphasis(hdspm);
+	spin_unlock_irq(&hdspm->lock);
+	return 0;
+}
+
+static int snd_hdspm_put_emphasis(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+	int change;
+	unsigned int val;
+
+	if (!snd_hdspm_use_is_exclusive(hdspm))
+		return -EBUSY;
+	val = ucontrol->value.integer.value[0] & 1;
+	spin_lock_irq(&hdspm->lock);
+	change = (int) val != hdspm_emphasis(hdspm);
+	hdspm_set_emphasis(hdspm, val);
+	spin_unlock_irq(&hdspm->lock);
+	return change;
+}
+
+#define HDSPM_DOLBY(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .name = xname, \
+  .index = xindex, \
+  .info = snd_hdspm_info_dolby, \
+  .get = snd_hdspm_get_dolby, \
+  .put = snd_hdspm_put_dolby \
+}
+
+static int hdspm_dolby(struct hdspm * hdspm)
+{
+	return (hdspm->control_register & HDSPM_Dolby) ? 1 : 0;
+}
+
+static int hdspm_set_dolby(struct hdspm * hdspm, int dol)
+{
+	if (dol)
+		hdspm->control_register |= HDSPM_Dolby;
+	else
+		hdspm->control_register &= ~HDSPM_Dolby;
+	hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+	return 0;
+}
+
+static int snd_hdspm_info_dolby(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_hdspm_get_dolby(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+	spin_lock_irq(&hdspm->lock);
+	ucontrol->value.enumerated.item[0] = hdspm_dolby(hdspm);
+	spin_unlock_irq(&hdspm->lock);
+	return 0;
+}
+
+static int snd_hdspm_put_dolby(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+	int change;
+	unsigned int val;
+
+	if (!snd_hdspm_use_is_exclusive(hdspm))
+		return -EBUSY;
+	val = ucontrol->value.integer.value[0] & 1;
+	spin_lock_irq(&hdspm->lock);
+	change = (int) val != hdspm_dolby(hdspm);
+	hdspm_set_dolby(hdspm, val);
+	spin_unlock_irq(&hdspm->lock);
+	return change;
+}
+
+#define HDSPM_PROFESSIONAL(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .name = xname, \
+  .index = xindex, \
+  .info = snd_hdspm_info_professional, \
+  .get = snd_hdspm_get_professional, \
+  .put = snd_hdspm_put_professional \
+}
+
+static int hdspm_professional(struct hdspm * hdspm)
+{
+	return (hdspm->control_register & HDSPM_Professional) ? 1 : 0;
+}
+
+static int hdspm_set_professional(struct hdspm * hdspm, int dol)
+{
+	if (dol)
+		hdspm->control_register |= HDSPM_Professional;
+	else
+		hdspm->control_register &= ~HDSPM_Professional;
+	hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+	return 0;
+}
+
+static int snd_hdspm_info_professional(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_hdspm_get_professional(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+	spin_lock_irq(&hdspm->lock);
+	ucontrol->value.enumerated.item[0] = hdspm_professional(hdspm);
+	spin_unlock_irq(&hdspm->lock);
+	return 0;
+}
+
+static int snd_hdspm_put_professional(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+	int change;
+	unsigned int val;
+
+	if (!snd_hdspm_use_is_exclusive(hdspm))
+		return -EBUSY;
+	val = ucontrol->value.integer.value[0] & 1;
+	spin_lock_irq(&hdspm->lock);
+	change = (int) val != hdspm_professional(hdspm);
+	hdspm_set_professional(hdspm, val);
+	spin_unlock_irq(&hdspm->lock);
+	return change;
+}
+
 #define HDSPM_INPUT_SELECT(xname, xindex) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
   .name = xname, \
@@ -1912,6 +2317,163 @@
 	return change;
 }
 
+#define HDSPM_DS_WIRE(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .name = xname, \
+  .index = xindex, \
+  .info = snd_hdspm_info_ds_wire, \
+  .get = snd_hdspm_get_ds_wire, \
+  .put = snd_hdspm_put_ds_wire \
+}
+
+static int hdspm_ds_wire(struct hdspm * hdspm)
+{
+	return (hdspm->control_register & HDSPM_DS_DoubleWire) ? 1 : 0;
+}
+
+static int hdspm_set_ds_wire(struct hdspm * hdspm, int ds)
+{
+	if (ds)
+		hdspm->control_register |= HDSPM_DS_DoubleWire;
+	else
+		hdspm->control_register &= ~HDSPM_DS_DoubleWire;
+	hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+	return 0;
+}
+
+static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_info *uinfo)
+{
+	static char *texts[] = { "Single", "Double" };
+
+	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 snd_hdspm_get_ds_wire(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+	spin_lock_irq(&hdspm->lock);
+	ucontrol->value.enumerated.item[0] = hdspm_ds_wire(hdspm);
+	spin_unlock_irq(&hdspm->lock);
+	return 0;
+}
+
+static int snd_hdspm_put_ds_wire(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+	int change;
+	unsigned int val;
+
+	if (!snd_hdspm_use_is_exclusive(hdspm))
+		return -EBUSY;
+	val = ucontrol->value.integer.value[0] & 1;
+	spin_lock_irq(&hdspm->lock);
+	change = (int) val != hdspm_ds_wire(hdspm);
+	hdspm_set_ds_wire(hdspm, val);
+	spin_unlock_irq(&hdspm->lock);
+	return change;
+}
+
+#define HDSPM_QS_WIRE(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .name = xname, \
+  .index = xindex, \
+  .info = snd_hdspm_info_qs_wire, \
+  .get = snd_hdspm_get_qs_wire, \
+  .put = snd_hdspm_put_qs_wire \
+}
+
+static int hdspm_qs_wire(struct hdspm * hdspm)
+{
+	if (hdspm->control_register & HDSPM_QS_DoubleWire)
+		return 1;
+	if (hdspm->control_register & HDSPM_QS_QuadWire)
+		return 2;
+	return 0;
+}
+
+static int hdspm_set_qs_wire(struct hdspm * hdspm, int mode)
+{
+	hdspm->control_register &= ~(HDSPM_QS_DoubleWire | HDSPM_QS_QuadWire);
+	switch (mode) {
+	case 0:
+		break;
+	case 1:
+		hdspm->control_register |= HDSPM_QS_DoubleWire;
+		break;
+	case 2:
+		hdspm->control_register |= HDSPM_QS_QuadWire;
+		break;
+	}
+	hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+	return 0;
+}
+
+static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	static char *texts[] = { "Single", "Double", "Quad" };
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 3;
+
+	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_hdspm_get_qs_wire(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+	spin_lock_irq(&hdspm->lock);
+	ucontrol->value.enumerated.item[0] = hdspm_qs_wire(hdspm);
+	spin_unlock_irq(&hdspm->lock);
+	return 0;
+}
+
+static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+	int change;
+	int val;
+
+	if (!snd_hdspm_use_is_exclusive(hdspm))
+		return -EBUSY;
+	val = ucontrol->value.integer.value[0];
+	if (val < 0)
+		val = 0;
+	if (val > 2)
+		val = 2;
+	spin_lock_irq(&hdspm->lock);
+	change = (int) val != hdspm_qs_wire(hdspm);
+	hdspm_set_qs_wire(hdspm, val);
+	spin_unlock_irq(&hdspm->lock);
+	return change;
+}
+
 /*           Simple Mixer
   deprecated since to much faders ???
   MIXER interface says output (source, destination, value)
@@ -2135,14 +2697,24 @@
 
 static int hdspm_wc_sync_check(struct hdspm * hdspm)
 {
-	int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
-	if (status2 & HDSPM_wcLock) {
-		if (status2 & HDSPM_wcSync)
+	if (hdspm->is_aes32) {
+		int status = hdspm_read(hdspm, HDSPM_statusRegister);
+		if (status & HDSPM_AES32_wcLock) {
+			/* I don't know how to differenciate sync from lock.
+			   Doing as if sync for now */
 			return 2;
-		else
-			return 1;
+		}
+		return 0;
+	} else {
+		int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+		if (status2 & HDSPM_wcLock) {
+			if (status2 & HDSPM_wcSync)
+				return 2;
+			else
+				return 1;
+		}
+		return 0;
 	}
-	return 0;
 }
 
 static int snd_hdspm_get_wc_sync_check(struct snd_kcontrol *kcontrol,
@@ -2188,9 +2760,43 @@
 }
 
 
+#define HDSPM_AES_SYNC_CHECK(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .name = xname, \
+  .index = xindex, \
+  .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+  .info = snd_hdspm_info_sync_check, \
+  .get = snd_hdspm_get_aes_sync_check \
+}
+
+static int hdspm_aes_sync_check(struct hdspm * hdspm, int idx)
+{
+	int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+	if (status2 & (HDSPM_LockAES >> idx)) {
+		/* I don't know how to differenciate sync from lock.
+		   Doing as if sync for now */
+		return 2;
+	}
+	return 0;
+}
+
+static int snd_hdspm_get_aes_sync_check(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	int offset;
+	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+	offset = ucontrol->id.index - 1;
+	if (offset < 0 || offset >= 8)
+		return -EINVAL;
+
+	ucontrol->value.enumerated.item[0] =
+		hdspm_aes_sync_check(hdspm, offset);
+	return 0;
+}
 
 
-static struct snd_kcontrol_new snd_hdspm_controls[] = {
+static struct snd_kcontrol_new snd_hdspm_controls_madi[] = {
 
 	HDSPM_MIXER("Mixer", 0),
 /* 'Sample Clock Source' complies with the alsa control naming scheme */
@@ -2211,6 +2817,29 @@
 	HDSPM_INPUT_SELECT("Input Select", 0),
 };
 
+static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = {
+
+	HDSPM_MIXER("Mixer", 0),
+/* 'Sample Clock Source' complies with the alsa control naming scheme */
+	HDSPM_CLOCK_SOURCE("Sample Clock Source", 0),
+
+	HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
+	HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
+	HDSPM_AUTOSYNC_REF("AutoSync Reference", 0),
+	HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
+/* 'External Rate' complies with the alsa control naming scheme */
+	HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
+	HDSPM_WC_SYNC_CHECK("Word Clock Lock Status", 0),
+/*	HDSPM_AES_SYNC_CHECK("AES Lock Status", 0),*/ /* created in snd_hdspm_create_controls() */
+	HDSPM_LINE_OUT("Line Out", 0),
+	HDSPM_EMPHASIS("Emphasis", 0),
+	HDSPM_DOLBY("Non Audio", 0),
+	HDSPM_PROFESSIONAL("Professional", 0),
+	HDSPM_C_TMS("Clear Track Marker", 0),
+	HDSPM_DS_WIRE("Double Speed Wire Mode", 0),
+	HDSPM_QS_WIRE("Quad Speed Wire Mode", 0),
+};
+
 static struct snd_kcontrol_new snd_hdspm_playback_mixer = HDSPM_PLAYBACK_MIXER;
 
 
@@ -2245,20 +2874,40 @@
 	struct snd_kcontrol *kctl;
 
 	/* add control list first */
+	if (hdspm->is_aes32) {
+		struct snd_kcontrol_new aes_sync_ctl =
+			HDSPM_AES_SYNC_CHECK("AES Lock Status", 0);
 
-	for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls); idx++) {
-		if ((err =
-		     snd_ctl_add(card, kctl =
-				 snd_ctl_new1(&snd_hdspm_controls[idx],
-					      hdspm))) < 0) {
-			return err;
+		for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls_aes32);
+		     idx++) {
+			err = snd_ctl_add(card,
+					  snd_ctl_new1(&snd_hdspm_controls_aes32[idx],
+						       hdspm));
+			if (err < 0)
+				return err;
+		}
+		for (idx = 1; idx <= 8; idx++) {
+			aes_sync_ctl.index = idx;
+			err = snd_ctl_add(card,
+					  snd_ctl_new1(&aes_sync_ctl, hdspm));
+			if (err < 0)
+				return err;
+		}
+	} else {
+		for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls_madi);
+		     idx++) {
+			err = snd_ctl_add(card,
+					  snd_ctl_new1(&snd_hdspm_controls_madi[idx],
+						       hdspm));
+			if (err < 0)
+				return err;
 		}
 	}
 
 	/* Channel playback mixer as default control 
-	   Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats too big for any alsamixer
-	   they are accesible via special IOCTL on hwdep
-	   and the mixer 2dimensional mixer control */
+Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats too big for any alsamixer
+they are accesible via special IOCTL on hwdep
+and the mixer 2dimensional mixer control */
 
 	snd_hdspm_playback_mixer.name = "Chn";
 	limit = HDSPM_MAX_CHANNELS;
@@ -2289,7 +2938,8 @@
  ------------------------------------------------------------*/
 
 static void
-snd_hdspm_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffer)
+snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
+			 struct snd_info_buffer *buffer)
 {
 	struct hdspm *hdspm = (struct hdspm *) entry->private_data;
 	unsigned int status;
@@ -2420,11 +3070,10 @@
 		clock_source = "Error";
 	}
 	snd_iprintf(buffer, "Sample Clock Source: %s\n", clock_source);
-	if (!(hdspm->control_register & HDSPM_ClockModeMaster)) {
+	if (!(hdspm->control_register & HDSPM_ClockModeMaster))
 		system_clock_mode = "Slave";
-	} else {
+	else
 		system_clock_mode = "Master";
-	}
 	snd_iprintf(buffer, "System Clock Mode: %s\n", system_clock_mode);
 
 	switch (hdspm_pref_sync_ref(hdspm)) {
@@ -2484,13 +3133,213 @@
 	snd_iprintf(buffer, "\n");
 }
 
+static void
+snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,
+			  struct snd_info_buffer *buffer)
+{
+	struct hdspm *hdspm = (struct hdspm *) entry->private_data;
+	unsigned int status;
+	unsigned int status2;
+	unsigned int timecode;
+	int pref_syncref;
+	char *autosync_ref;
+	char *system_clock_mode;
+	char *clock_source;
+	int x;
+
+	status = hdspm_read(hdspm, HDSPM_statusRegister);
+	status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+	timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
+
+	snd_iprintf(buffer, "%s (Card #%d) Rev.%x\n",
+		    hdspm->card_name, hdspm->card->number + 1,
+		    hdspm->firmware_rev);
+
+	snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
+		    hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase);
+
+	snd_iprintf(buffer, "--- System ---\n");
+
+	snd_iprintf(buffer,
+		    "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n",
+		    status & HDSPM_audioIRQPending,
+		    (status & HDSPM_midi0IRQPending) ? 1 : 0,
+		    (status & HDSPM_midi1IRQPending) ? 1 : 0,
+		    hdspm->irq_count);
+	snd_iprintf(buffer,
+		    "HW pointer: id = %d, rawptr = %d (%d->%d) estimated= %ld (bytes)\n",
+		    ((status & HDSPM_BufferID) ? 1 : 0),
+		    (status & HDSPM_BufferPositionMask),
+		    (status & HDSPM_BufferPositionMask) % (2 *
+							   (int)hdspm->
+							   period_bytes),
+		    ((status & HDSPM_BufferPositionMask) -
+		     64) % (2 * (int)hdspm->period_bytes),
+		    (long) hdspm_hw_pointer(hdspm) * 4);
+
+	snd_iprintf(buffer,
+		    "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n",
+		    hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF,
+		    hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF,
+		    hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF,
+		    hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF);
+	snd_iprintf(buffer,
+		    "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, status2=0x%x, timecode=0x%x\n",
+		    hdspm->control_register, hdspm->control2_register,
+		    status, status2, timecode);
+
+	snd_iprintf(buffer, "--- Settings ---\n");
+
+	x = 1 << (6 +
+		  hdspm_decode_latency(hdspm->
+				       control_register &
+				       HDSPM_LatencyMask));
+
+	snd_iprintf(buffer,
+		    "Size (Latency): %d samples (2 periods of %lu bytes)\n",
+		    x, (unsigned long) hdspm->period_bytes);
+
+	snd_iprintf(buffer, "Line out: %s,   Precise Pointer: %s\n",
+		    (hdspm->
+		     control_register & HDSPM_LineOut) ? "on " : "off",
+		    (hdspm->precise_ptr) ? "on" : "off");
+
+	snd_iprintf(buffer,
+		    "ClearTrackMarker %s, Emphasis %s, Dolby %s\n",
+		    (hdspm->
+		     control_register & HDSPM_clr_tms) ? "on" : "off",
+		    (hdspm->
+		     control_register & HDSPM_Emphasis) ? "on" : "off",
+		    (hdspm->
+		     control_register & HDSPM_Dolby) ? "on" : "off");
+
+	switch (hdspm_clock_source(hdspm)) {
+	case HDSPM_CLOCK_SOURCE_AUTOSYNC:
+		clock_source = "AutoSync";
+		break;
+	case HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ:
+		clock_source = "Internal 32 kHz";
+		break;
+	case HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ:
+		clock_source = "Internal 44.1 kHz";
+		break;
+	case HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ:
+		clock_source = "Internal 48 kHz";
+		break;
+	case HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ:
+		clock_source = "Internal 64 kHz";
+		break;
+	case HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ:
+		clock_source = "Internal 88.2 kHz";
+		break;
+	case HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ:
+		clock_source = "Internal 96 kHz";
+		break;
+	case HDSPM_CLOCK_SOURCE_INTERNAL_128KHZ:
+		clock_source = "Internal 128 kHz";
+		break;
+	case HDSPM_CLOCK_SOURCE_INTERNAL_176_4KHZ:
+		clock_source = "Internal 176.4 kHz";
+		break;
+	case HDSPM_CLOCK_SOURCE_INTERNAL_192KHZ:
+		clock_source = "Internal 192 kHz";
+		break;
+	default:
+		clock_source = "Error";
+	}
+	snd_iprintf(buffer, "Sample Clock Source: %s\n", clock_source);
+	if (!(hdspm->control_register & HDSPM_ClockModeMaster))
+		system_clock_mode = "Slave";
+	else
+		system_clock_mode = "Master";
+	snd_iprintf(buffer, "System Clock Mode: %s\n", system_clock_mode);
+
+	pref_syncref = hdspm_pref_sync_ref(hdspm);
+	if (pref_syncref == 0)
+		snd_iprintf(buffer, "Preferred Sync Reference: Word Clock\n");
+	else
+		snd_iprintf(buffer, "Preferred Sync Reference: AES%d\n",
+				pref_syncref);
+
+	snd_iprintf(buffer, "System Clock Frequency: %d\n",
+		    hdspm->system_sample_rate);
+
+	snd_iprintf(buffer, "Double speed: %s\n",
+			hdspm->control_register & HDSPM_DS_DoubleWire?
+			"Double wire" : "Single wire");
+	snd_iprintf(buffer, "Quad speed: %s\n",
+			hdspm->control_register & HDSPM_QS_DoubleWire?
+			"Double wire" :
+			hdspm->control_register & HDSPM_QS_QuadWire?
+			"Quad wire" : "Single wire");
+
+	snd_iprintf(buffer, "--- Status:\n");
+
+	snd_iprintf(buffer, "Word: %s  Frequency: %d\n",
+			(status & HDSPM_AES32_wcLock)? "Sync   " : "No Lock",
+			HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF));
+
+	for (x = 0; x < 8; x++) {
+		snd_iprintf(buffer, "AES%d: %s  Frequency: %d\n",
+				x+1,
+				(status2 & (HDSPM_LockAES >> x))? "Sync   ": "No Lock",
+				HDSPM_bit2freq((timecode >> (4*x)) & 0xF));
+	}
+
+	switch (hdspm_autosync_ref(hdspm)) {
+	case HDSPM_AES32_AUTOSYNC_FROM_NONE: autosync_ref="None"; break;
+	case HDSPM_AES32_AUTOSYNC_FROM_WORD: autosync_ref="Word Clock"; break;
+	case HDSPM_AES32_AUTOSYNC_FROM_AES1: autosync_ref="AES1"; break;
+	case HDSPM_AES32_AUTOSYNC_FROM_AES2: autosync_ref="AES2"; break;
+	case HDSPM_AES32_AUTOSYNC_FROM_AES3: autosync_ref="AES3"; break;
+	case HDSPM_AES32_AUTOSYNC_FROM_AES4: autosync_ref="AES4"; break;
+	case HDSPM_AES32_AUTOSYNC_FROM_AES5: autosync_ref="AES5"; break;
+	case HDSPM_AES32_AUTOSYNC_FROM_AES6: autosync_ref="AES6"; break;
+	case HDSPM_AES32_AUTOSYNC_FROM_AES7: autosync_ref="AES7"; break;
+	case HDSPM_AES32_AUTOSYNC_FROM_AES8: autosync_ref="AES8"; break;
+	default: autosync_ref = "---"; break;
+	}
+	snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref);
+
+	snd_iprintf(buffer, "\n");
+}
+
+#ifdef CONFIG_SND_DEBUG
+static void
+snd_hdspm_proc_read_debug(struct snd_info_entry * entry,
+			  struct snd_info_buffer *buffer)
+{
+	struct hdspm *hdspm = (struct hdspm *)entry->private_data;
+
+	int j,i;
+
+	for (i = 0; i < 256 /* 1024*64 */; i += j)
+	{
+		snd_iprintf(buffer, "0x%08X: ", i);
+		for (j = 0; j < 16; j += 4)
+			snd_iprintf(buffer, "%08X ", hdspm_read(hdspm, i + j));
+		snd_iprintf(buffer, "\n");
+	}
+}
+#endif
+
+
+
 static void __devinit snd_hdspm_proc_init(struct hdspm * hdspm)
 {
 	struct snd_info_entry *entry;
 
 	if (!snd_card_proc_new(hdspm->card, "hdspm", &entry))
 		snd_info_set_text_ops(entry, hdspm,
-				      snd_hdspm_proc_read);
+				      hdspm->is_aes32 ?
+				      snd_hdspm_proc_read_aes32 :
+				      snd_hdspm_proc_read_madi);
+#ifdef CONFIG_SND_DEBUG
+	/* debug file to read all hdspm registers */
+	if (!snd_card_proc_new(hdspm->card, "debug", &entry))
+		snd_info_set_text_ops(entry, hdspm,
+				snd_hdspm_proc_read_debug);
+#endif
 }
 
 /*------------------------------------------------------------
@@ -2507,13 +3356,20 @@
 
 	/* set defaults:       */
 
-	hdspm->control_register = HDSPM_ClockModeMaster |	/* Master Cloack Mode on */
-	    hdspm_encode_latency(7) |	/* latency maximum = 8192 samples */
-	    HDSPM_InputCoaxial |	/* Input Coax not Optical */
-	    HDSPM_SyncRef_MADI |	/* Madi is syncclock */
-	    HDSPM_LineOut |	/* Analog output in */
-	    HDSPM_TX_64ch |	/* transmit in 64ch mode */
-	    HDSPM_AutoInp;	/* AutoInput chossing (takeover) */
+	if (hdspm->is_aes32)
+		hdspm->control_register = HDSPM_ClockModeMaster |	/* Master Cloack Mode on */
+			hdspm_encode_latency(7) |	/* latency maximum = 8192 samples */
+			HDSPM_SyncRef0 |	/* AES1 is syncclock */
+			HDSPM_LineOut |	/* Analog output in */
+			HDSPM_Professional;  /* Professional mode */
+	else
+		hdspm->control_register = HDSPM_ClockModeMaster |	/* Master Cloack Mode on */
+			hdspm_encode_latency(7) |	/* latency maximum = 8192 samples */
+			HDSPM_InputCoaxial |	/* Input Coax not Optical */
+			HDSPM_SyncRef_MADI |	/* Madi is syncclock */
+			HDSPM_LineOut |	/* Analog output in */
+			HDSPM_TX_64ch |	/* transmit in 64ch mode */
+			HDSPM_AutoInp;	/* AutoInput chossing (takeover) */
 
 	/* ! HDSPM_Frequency0|HDSPM_Frequency1 = 44.1khz */
 	/* !  HDSPM_DoubleSpeed HDSPM_QuadSpeed = normal speed */
@@ -2822,6 +3678,8 @@
 
 		hdspm->playback_buffer =
 		    (unsigned char *) substream->runtime->dma_area;
+		snd_printdd("Allocated sample buffer for playback at %p\n",
+				hdspm->playback_buffer);
 	} else {
 		hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferIn,
 				params_channels(params));
@@ -2831,7 +3689,15 @@
 
 		hdspm->capture_buffer =
 		    (unsigned char *) substream->runtime->dma_area;
+		snd_printdd("Allocated sample buffer for capture at %p\n",
+				hdspm->capture_buffer);
 	}
+	/*
+	   snd_printdd("Allocated sample buffer for %s at 0x%08X\n",
+	   substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+	   "playback" : "capture",
+	   snd_pcm_sgbuf_get_addr(sgbuf, 0));
+	 */
 	return 0;
 }
 
@@ -2982,9 +3848,10 @@
 		  SNDRV_PCM_RATE_44100 |
 		  SNDRV_PCM_RATE_48000 |
 		  SNDRV_PCM_RATE_64000 |
-		  SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000),
+		  SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+		  SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 ),
 	.rate_min = 32000,
-	.rate_max = 96000,
+	.rate_max = 192000,
 	.channels_min = 1,
 	.channels_max = HDSPM_MAX_CHANNELS,
 	.buffer_bytes_max =
@@ -3006,9 +3873,10 @@
 		  SNDRV_PCM_RATE_44100 |
 		  SNDRV_PCM_RATE_48000 |
 		  SNDRV_PCM_RATE_64000 |
-		  SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000),
+		  SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+		  SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000),
 	.rate_min = 32000,
-	.rate_max = 96000,
+	.rate_max = 192000,
 	.channels_min = 1,
 	.channels_max = HDSPM_MAX_CHANNELS,
 	.buffer_bytes_max =
@@ -3315,7 +4183,8 @@
 
 	pcm = hdspm->pcm;
 
-	wanted = HDSPM_DMA_AREA_BYTES + 4096;	/* dont know why, but it works */
+/*	wanted = HDSPM_DMA_AREA_BYTES + 4096;*/	/* dont know why, but it works */
+	wanted = HDSPM_DMA_AREA_BYTES;
 
 	if ((err =
 	     snd_pcm_lib_preallocate_pages_for_all(pcm,
@@ -3467,9 +4336,16 @@
 	pci_read_config_word(hdspm->pci,
 			     PCI_CLASS_REVISION, &hdspm->firmware_rev);
 
-	strcpy(card->driver, "HDSPM");
+	hdspm->is_aes32 = (hdspm->firmware_rev >= HDSPM_AESREVISION);
+
 	strcpy(card->mixername, "Xilinx FPGA");
-	hdspm->card_name = "RME HDSPM MADI";
+	if (hdspm->is_aes32) {
+		strcpy(card->driver, "HDSPAES32");
+		hdspm->card_name = "RME HDSPM AES32";
+	} else {
+		strcpy(card->driver, "HDSPM");
+		hdspm->card_name = "RME HDSPM MADI";
+	}
 
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index 474f2d4..3bff321 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -2627,7 +2627,7 @@
 	return 0;
 }
 
-static DECLARE_TLV_DB_SCALE(db_scale_gvol, -6375, 25, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_gvol, -6375, 25, 0);
 
 static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol,
 				       struct snd_ctl_elem_value *ucontrol)
@@ -2844,7 +2844,7 @@
 	return change;
 }
 
-static DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1);
 
 static struct snd_kcontrol_new snd_trident_pcm_rvol_control __devinitdata =
 {
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index a572b01..a289922 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -1699,7 +1699,7 @@
 	return change;
 }
 
-static DECLARE_TLV_DB_SCALE(db_scale_dxs, -9450, 150, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_dxs, -9450, 150, 1);
 
 static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = {
 	.name = "PCM Playback Volume",
@@ -1823,7 +1823,7 @@
 	ac97.private_data = chip;
 	ac97.private_free = snd_via82xx_mixer_free_ac97;
 	ac97.pci = chip->pci;
-	ac97.scaps = AC97_SCAP_SKIP_MODEM;
+	ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE;
 	if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0)
 		return err;
 
@@ -2357,93 +2357,59 @@
 /*
  * auto detection of DXS channel supports.
  */
-struct dxs_whitelist {
-	unsigned short subvendor;
-	unsigned short subdevice; 
-	unsigned short mask; 
-	short action;	/* new dxs_support value */
+
+static struct snd_pci_quirk dxs_whitelist[] __devinitdata = {
+	SND_PCI_QUIRK(0x1005, 0x4710, "Avance Logic Mobo", VIA_DXS_ENABLE),
+	SND_PCI_QUIRK(0x1019, 0x0996, "ESC Mobo", VIA_DXS_48K),
+	SND_PCI_QUIRK(0x1019, 0x0a81, "ECS K7VTA3 v8.0", VIA_DXS_NO_VRA),
+	SND_PCI_QUIRK(0x1019, 0x0a85, "ECS L7VMM2", VIA_DXS_NO_VRA),
+	SND_PCI_QUIRK(0x1019, 0, "ESC K8", VIA_DXS_SRC),
+	SND_PCI_QUIRK(0x1019, 0xaa01, "ESC K8T890-A", VIA_DXS_SRC),
+	SND_PCI_QUIRK(0x1025, 0x0033, "Acer Inspire 1353LM", VIA_DXS_NO_VRA),
+	SND_PCI_QUIRK(0x1025, 0x0046, "Acer Aspire 1524 WLMi", VIA_DXS_SRC),
+	SND_PCI_QUIRK(0x1043, 0, "ASUS A7/A8", VIA_DXS_NO_VRA),
+	SND_PCI_QUIRK(0x1071, 0, "Diverse Notebook", VIA_DXS_NO_VRA),
+	SND_PCI_QUIRK(0x10cf, 0x118e, "FSC Laptop", VIA_DXS_ENABLE),
+	SND_PCI_QUIRK(0x1106, 0, "ASRock", VIA_DXS_SRC),
+	SND_PCI_QUIRK(0x1297, 0xa232, "Shuttle", VIA_DXS_ENABLE),
+	SND_PCI_QUIRK(0x1297, 0xc160, "Shuttle Sk41G", VIA_DXS_ENABLE),
+	SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte GA-7VAXP", VIA_DXS_ENABLE),
+	SND_PCI_QUIRK(0x1462, 0x3800, "MSI KT266", VIA_DXS_ENABLE),
+	SND_PCI_QUIRK(0x1462, 0x7120, "MSI KT4V", VIA_DXS_ENABLE),
+	SND_PCI_QUIRK(0x1462, 0x7142, "MSI K8MM-V", VIA_DXS_ENABLE),
+	SND_PCI_QUIRK(0x1462, 0, "MSI Mobo", VIA_DXS_SRC),
+	SND_PCI_QUIRK(0x147b, 0x1401, "ABIT KD7(-RAID)", VIA_DXS_ENABLE),
+	SND_PCI_QUIRK(0x147b, 0x1411, "ABIT VA-20", VIA_DXS_ENABLE),
+	SND_PCI_QUIRK(0x147b, 0x1413, "ABIT KV8 Pro", VIA_DXS_ENABLE),
+	SND_PCI_QUIRK(0x147b, 0x1415, "ABIT AV8", VIA_DXS_NO_VRA),
+	SND_PCI_QUIRK(0x14ff, 0x0403, "Twinhead mobo", VIA_DXS_ENABLE),
+	SND_PCI_QUIRK(0x14ff, 0x0408, "Twinhead laptop", VIA_DXS_SRC),
+	SND_PCI_QUIRK(0x1558, 0x4701, "Clevo D470", VIA_DXS_SRC),
+	SND_PCI_QUIRK(0x1584, 0x8120, "Diverse Laptop", VIA_DXS_ENABLE),
+	SND_PCI_QUIRK(0x1584, 0x8123, "Targa/Uniwill", VIA_DXS_NO_VRA),
+	SND_PCI_QUIRK(0x161f, 0x202b, "Amira Notebook", VIA_DXS_NO_VRA),
+	SND_PCI_QUIRK(0x161f, 0x2032, "m680x machines", VIA_DXS_48K),
+	SND_PCI_QUIRK(0x1631, 0xe004, "PB EasyNote 3174", VIA_DXS_ENABLE),
+	SND_PCI_QUIRK(0x1695, 0x3005, "EPoX EP-8K9A", VIA_DXS_ENABLE),
+	SND_PCI_QUIRK(0x1695, 0, "EPoX mobo", VIA_DXS_SRC),
+	SND_PCI_QUIRK(0x16f3, 0, "Jetway K8", VIA_DXS_SRC),
+	SND_PCI_QUIRK(0x1734, 0, "FSC Laptop", VIA_DXS_SRC),
+	SND_PCI_QUIRK(0x1849, 0x3059, "ASRock K7VM2", VIA_DXS_NO_VRA),
+	SND_PCI_QUIRK(0x1849, 0, "ASRock mobo", VIA_DXS_SRC),
+	SND_PCI_QUIRK(0x1919, 0x200a, "Soltek SL-K8",  VIA_DXS_NO_VRA),
+	SND_PCI_QUIRK(0x4005, 0x4710, "MSI K7T266", VIA_DXS_SRC),
+	{ } /* terminator */
 };
 
 static int __devinit check_dxs_list(struct pci_dev *pci, int revision)
 {
-	static struct dxs_whitelist whitelist[] __devinitdata = {
-		{ .subvendor = 0x1005, .subdevice = 0x4710, .action = VIA_DXS_ENABLE }, /* Avance Logic Mobo */
-		{ .subvendor = 0x1019, .subdevice = 0x0996, .action = VIA_DXS_48K },
-		{ .subvendor = 0x1019, .subdevice = 0x0a81, .action = VIA_DXS_NO_VRA }, /* ECS K7VTA3 v8.0 */
-		{ .subvendor = 0x1019, .subdevice = 0x0a85, .action = VIA_DXS_NO_VRA }, /* ECS L7VMM2 */
-		{ .subvendor = 0x1019, .subdevice = 0xa101, .action = VIA_DXS_SRC },
-		{ .subvendor = 0x1019, .subdevice = 0xaa01, .action = VIA_DXS_SRC }, /* ECS K8T890-A */
-		{ .subvendor = 0x1025, .subdevice = 0x0033, .action = VIA_DXS_NO_VRA }, /* Acer Inspire 1353LM */
-		{ .subvendor = 0x1025, .subdevice = 0x0046, .action = VIA_DXS_SRC }, /* Acer Aspire 1524 WLMi */
-		{ .subvendor = 0x1043, .subdevice = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/
-		{ .subvendor = 0x1043, .subdevice = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */
-		{ .subvendor = 0x1043, .subdevice = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ 
-		{ .subvendor = 0x1043, .subdevice = 0x810d, .action = VIA_DXS_SRC }, /* ASUS */
-		{ .subvendor = 0x1043, .subdevice = 0x812a, .action = VIA_DXS_SRC    }, /* ASUS A8V Deluxe */ 
-		{ .subvendor = 0x1043, .subdevice = 0x8174, .action = VIA_DXS_SRC    }, /* ASUS */
-		{ .subvendor = 0x1043, .subdevice = 0x81b9, .action = VIA_DXS_SRC    }, /* ASUS A8V-MX */
-		{ .subvendor = 0x1071, .subdevice = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */
-		{ .subvendor = 0x1071, .subdevice = 0x8399, .action = VIA_DXS_NO_VRA }, /* Umax AB 595T (VIA K8N800A - VT8237) */
-		{ .subvendor = 0x10cf, .subdevice = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */
-		{ .subvendor = 0x1106, .subdevice = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */
-		{ .subvendor = 0x1106, .subdevice = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */
-		{ .subvendor = 0x1106, .subdevice = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */
-		{ .subvendor = 0x1106, .subdevice = 0xc001, .action = VIA_DXS_SRC }, /* Insight P4-ITX */
-		{ .subvendor = 0x1297, .subdevice = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */
-		{ .subvendor = 0x1297, .subdevice = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */
-		{ .subvendor = 0x1458, .subdevice = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */
-		{ .subvendor = 0x1462, .subdevice = 0x0080, .action = VIA_DXS_SRC }, /* MSI K8T Neo-FIS2R */
-		{ .subvendor = 0x1462, .subdevice = 0x0430, .action = VIA_DXS_SRC }, /* MSI 7142 (K8MM-V) */
-		{ .subvendor = 0x1462, .subdevice = 0x0470, .action = VIA_DXS_SRC }, /* MSI KT880 Delta-FSR */
-		{ .subvendor = 0x1462, .subdevice = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */
-		{ .subvendor = 0x1462, .subdevice = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */
-		{ .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_SRC }, /* MSI K8T Neo2-FI */
-		{ .subvendor = 0x1462, .subdevice = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */
-		{ .subvendor = 0x1462, .subdevice = 0x7142, .action = VIA_DXS_ENABLE }, /* MSI K8MM-V */
-		{ .subvendor = 0x1462, .subdevice = 0xb012, .action = VIA_DXS_SRC }, /* P4M800/VIA8237R */
-		{ .subvendor = 0x147b, .subdevice = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */
-		{ .subvendor = 0x147b, .subdevice = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */
-		{ .subvendor = 0x147b, .subdevice = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */
-		{ .subvendor = 0x147b, .subdevice = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */
-		{ .subvendor = 0x14ff, .subdevice = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */
-		{ .subvendor = 0x14ff, .subdevice = 0x0408, .action = VIA_DXS_SRC }, /* Twinhead laptop */
-		{ .subvendor = 0x1558, .subdevice = 0x4701, .action = VIA_DXS_SRC }, /* Clevo D470 */
-		{ .subvendor = 0x1584, .subdevice = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */
-		{ .subvendor = 0x1584, .subdevice = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */
-		{ .subvendor = 0x161f, .subdevice = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */
-		{ .subvendor = 0x161f, .subdevice = 0x2032, .action = VIA_DXS_48K }, /* m680x machines */
-		{ .subvendor = 0x1631, .subdevice = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */
-		{ .subvendor = 0x1695, .subdevice = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */
-		{ .subvendor = 0x1695, .subdevice = 0x300c, .action = VIA_DXS_SRC }, /* EPoX EP-8KRAI */
-		{ .subvendor = 0x1695, .subdevice = 0x300e, .action = VIA_DXS_SRC }, /* EPoX 9HEAI */
-		{ .subvendor = 0x16f3, .subdevice = 0x6405, .action = VIA_DXS_SRC }, /* Jetway K8M8MS */
-		{ .subvendor = 0x1734, .subdevice = 0x1078, .action = VIA_DXS_SRC }, /* FSC Amilo L7300 */
-		{ .subvendor = 0x1734, .subdevice = 0x1093, .action = VIA_DXS_SRC }, /* FSC */
-		{ .subvendor = 0x1734, .subdevice = 0x10ab, .action = VIA_DXS_SRC }, /* FSC */
-		{ .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */
-		{ .subvendor = 0x1849, .subdevice = 0x9739, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */
-		{ .subvendor = 0x1849, .subdevice = 0x9761, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */
-		{ .subvendor = 0x1919, .subdevice = 0x200a, .action = VIA_DXS_NO_VRA }, /* Soltek SL-K8Tpro-939 */
-		{ .subvendor = 0x4005, .subdevice = 0x4710, .action = VIA_DXS_SRC },	/* MSI K7T266 Pro2 (MS-6380 V2.0) BIOS 3.7 */
-		{ } /* terminator */
-	};
-	const struct dxs_whitelist *w;
-	unsigned short subsystem_vendor;
-	unsigned short subsystem_device;
+	const struct snd_pci_quirk *w;
 
-	pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
-	pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device);
-
-	for (w = whitelist; w->subvendor; w++) {
-		if (w->subvendor != subsystem_vendor)
-			continue;
-		if (w->mask) {
-			if ((w->mask & subsystem_device) == w->subdevice)
-				return w->action;
-		} else {
-			if (subsystem_device == w->subdevice)
-				return w->action;
-		}
+	w = snd_pci_quirk_lookup(pci, dxs_whitelist);
+	if (w) {
+		snd_printdd(KERN_INFO "via82xx: DXS white list for %s found\n",
+			    w->name);
+		return w->value;
 	}
 
 	/* for newer revision, default to DXS_SRC */
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index 17d6b84..b338e15 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -900,7 +900,7 @@
 	ac97.private_data = chip;
 	ac97.private_free = snd_via82xx_mixer_free_ac97;
 	ac97.pci = chip->pci;
-	ac97.scaps = AC97_SCAP_SKIP_AUDIO;
+	ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE;
 	ac97.num = chip->ac97_secondary;
 
 	if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0)
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c
index 89f58ea..474eac9 100644
--- a/sound/pci/vx222/vx222.c
+++ b/sound/pci/vx222/vx222.c
@@ -73,8 +73,8 @@
 /*
  */
 
-static DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_akm, -7350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_akm, -7350, 50, 0);
 
 static struct snd_vx_hardware vx222_old_hw = {
 
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
index 5e51950..55558be 100644
--- a/sound/pci/vx222/vx222_ops.c
+++ b/sound/pci/vx222/vx222_ops.c
@@ -846,7 +846,7 @@
 
 #define MIC_LEVEL_MAX	0xff
 
-static DECLARE_TLV_DB_SCALE(db_scale_mic, -6450, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_mic, -6450, 50, 0);
 
 /*
  * controls API for input levels
diff --git a/sound/pci/ymfpci/ymfpci_image.h b/sound/pci/ymfpci/ymfpci_image.h
index 1b07469..112f2ff 100644
--- a/sound/pci/ymfpci/ymfpci_image.h
+++ b/sound/pci/ymfpci/ymfpci_image.h
@@ -1,7 +1,7 @@
 #ifndef _HWMCODE_
 #define _HWMCODE_
 
-static unsigned long DspInst[YDSXG_DSPLENGTH / 4] = {
+static u32 DspInst[YDSXG_DSPLENGTH / 4] = {
 	0x00000081, 0x000001a4, 0x0000000a, 0x0000002f,
 	0x00080253, 0x01800317, 0x0000407b, 0x0000843f,
 	0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c,
@@ -12,7 +12,7 @@
 	0x00000000, 0x00000000, 0x00000000, 0x00000000
 };
 
-static unsigned long CntrlInst[YDSXG_CTRLLENGTH / 4] = {
+static u32 CntrlInst[YDSXG_CTRLLENGTH / 4] = {
 	0x000007, 0x240007, 0x0C0007, 0x1C0007,
 	0x060007, 0x700002, 0x000020, 0x030040,
 	0x007104, 0x004286, 0x030040, 0x000F0D,
@@ -791,7 +791,7 @@
 // 04/09  creat
 // 04/12  stop nise fix
 // 06/21  WorkingOff timming
-static unsigned long CntrlInst1E[YDSXG_CTRLLENGTH / 4] = {
+static u32 CntrlInst1E[YDSXG_CTRLLENGTH / 4] = {
 	0x000007, 0x240007, 0x0C0007, 0x1C0007,
 	0x060007, 0x700002, 0x000020, 0x030040,
 	0x007104, 0x004286, 0x030040, 0x000F0D,
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 7881944..fd12674 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -2,12 +2,6 @@
  *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
  *  Routines for control of YMF724/740/744/754 chips
  *
- *  BUGS:
- *    --
- *
- *  TODO:
- *    --
- *
  *   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
@@ -26,6 +20,7 @@
 
 #include <sound/driver.h>
 #include <linux/delay.h>
+#include <linux/firmware.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
@@ -42,10 +37,7 @@
 #include <sound/mpu401.h>
 
 #include <asm/io.h>
-
-/*
- *  constants
- */
+#include <asm/byteorder.h>
 
 /*
  *  common I/O routines
@@ -179,6 +171,17 @@
 	return val[0];
 }
 
+static void snd_ymfpci_pcm_441_volume_set(struct snd_ymfpci_pcm *ypcm)
+{
+	unsigned int value;
+	struct snd_ymfpci_pcm_mixer *mixer;
+	
+	mixer = &ypcm->chip->pcm_mixer[ypcm->substream->number];
+	value = min_t(unsigned int, mixer->left, 0x7fff) >> 1;
+	value |= (min_t(unsigned int, mixer->right, 0x7fff) >> 1) << 16;
+	snd_ymfpci_writel(ypcm->chip, YDSXGR_BUF441OUTVOL, value);
+}
+
 /*
  *  Hardware start management
  */
@@ -290,6 +293,10 @@
 	snd_assert(pvoice != NULL, return -EINVAL);
 	snd_ymfpci_hw_stop(chip);
 	spin_lock_irqsave(&chip->voice_lock, flags);
+	if (pvoice->number == chip->src441_used) {
+		chip->src441_used = -1;
+		pvoice->ypcm->use_441_slot = 0;
+	}
 	pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0;
 	pvoice->ypcm = NULL;
 	pvoice->interrupt = NULL;
@@ -394,7 +401,7 @@
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 	case SNDRV_PCM_TRIGGER_RESUME:
 		chip->ctrl_playback[ypcm->voices[0]->number + 1] = cpu_to_le32(ypcm->voices[0]->bank_addr);
-		if (ypcm->voices[1] != NULL)
+		if (ypcm->voices[1] != NULL && !ypcm->use_441_slot)
 			chip->ctrl_playback[ypcm->voices[1]->number + 1] = cpu_to_le32(ypcm->voices[1]->bank_addr);
 		ypcm->running = 1;
 		break;
@@ -402,7 +409,7 @@
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 		chip->ctrl_playback[ypcm->voices[0]->number + 1] = 0;
-		if (ypcm->voices[1] != NULL)
+		if (ypcm->voices[1] != NULL && !ypcm->use_441_slot)
 			chip->ctrl_playback[ypcm->voices[1]->number + 1] = 0;
 		ypcm->running = 0;
 		break;
@@ -489,6 +496,7 @@
 	unsigned int nbank;
 	u32 vol_left, vol_right;
 	u8 use_left, use_right;
+	unsigned long flags;
 
 	snd_assert(voice != NULL, return);
 	if (runtime->channels == 1) {
@@ -507,11 +515,27 @@
 		vol_left = cpu_to_le32(0x40000000);
 		vol_right = cpu_to_le32(0x40000000);
 	}
+	spin_lock_irqsave(&ypcm->chip->voice_lock, flags);
 	format = runtime->channels == 2 ? 0x00010000 : 0;
 	if (snd_pcm_format_width(runtime->format) == 8)
 		format |= 0x80000000;
+	else if (ypcm->chip->device_id == PCI_DEVICE_ID_YAMAHA_754 &&
+		 runtime->rate == 44100 && runtime->channels == 2 &&
+		 voiceidx == 0 && (ypcm->chip->src441_used == -1 ||
+				   ypcm->chip->src441_used == voice->number)) {
+		ypcm->chip->src441_used = voice->number;
+		ypcm->use_441_slot = 1;
+		format |= 0x10000000;
+		snd_ymfpci_pcm_441_volume_set(ypcm);
+	}
+	if (ypcm->chip->src441_used == voice->number &&
+	    (format & 0x10000000) == 0) {
+		ypcm->chip->src441_used = -1;
+		ypcm->use_441_slot = 0;
+	}
 	if (runtime->channels == 2 && (voiceidx & 1) != 0)
 		format |= 1;
+	spin_unlock_irqrestore(&ypcm->chip->voice_lock, flags);
 	for (nbank = 0; nbank < 2; nbank++) {
 		bank = &voice->bank[nbank];
 		memset(bank, 0, sizeof(*bank));
@@ -1480,7 +1504,7 @@
 	return change;
 }
 
-static DECLARE_TLV_DB_LINEAR(db_scale_native, TLV_DB_GAIN_MUTE, 0);
+static const DECLARE_TLV_DB_LINEAR(db_scale_native, TLV_DB_GAIN_MUTE, 0);
 
 #define YMFPCI_DOUBLE(xname, xindex, reg) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
@@ -1722,7 +1746,10 @@
 		spin_lock_irqsave(&chip->voice_lock, flags);
 		if (substream->runtime && substream->runtime->private_data) {
 			struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data;
-			ypcm->update_pcm_vol = 2;
+			if (!ypcm->use_441_slot)
+				ypcm->update_pcm_vol = 2;
+			else
+				snd_ymfpci_pcm_441_volume_set(ypcm);
 		}
 		spin_unlock_irqrestore(&chip->voice_lock, flags);
 		return 1;
@@ -1971,13 +1998,94 @@
 	}
 }
 
+#define FIRMWARE_IN_THE_KERNEL
+
+#ifdef FIRMWARE_IN_THE_KERNEL
+
 #include "ymfpci_image.h"
 
+static struct firmware snd_ymfpci_dsp_microcode = {
+	.size = YDSXG_DSPLENGTH,
+	.data = (u8 *)DspInst,
+};
+static struct firmware snd_ymfpci_controller_microcode = {
+	.size = YDSXG_CTRLLENGTH,
+	.data = (u8 *)CntrlInst,
+};
+static struct firmware snd_ymfpci_controller_1e_microcode = {
+	.size = YDSXG_CTRLLENGTH,
+	.data = (u8 *)CntrlInst1E,
+};
+#endif
+
+#ifdef __LITTLE_ENDIAN
+static inline void snd_ymfpci_convert_from_le(const struct firmware *fw) { }
+#else
+static void snd_ymfpci_convert_from_le(const struct firmware *fw)
+{
+	int i;
+	u32 *data = (u32 *)fw->data;
+
+	for (i = 0; i < fw->size / 4; ++i)
+		le32_to_cpus(&data[i]);
+}
+#endif
+
+static int snd_ymfpci_request_firmware(struct snd_ymfpci *chip)
+{
+	int err, is_1e;
+	const char *name;
+
+	err = request_firmware(&chip->dsp_microcode, "yamaha/ds1_dsp.fw",
+			       &chip->pci->dev);
+	if (err >= 0) {
+		if (chip->dsp_microcode->size == YDSXG_DSPLENGTH)
+			snd_ymfpci_convert_from_le(chip->dsp_microcode);
+		else {
+			snd_printk(KERN_ERR "DSP microcode has wrong size\n");
+			err = -EINVAL;
+		}
+	}
+	if (err < 0) {
+#ifdef FIRMWARE_IN_THE_KERNEL
+		chip->dsp_microcode = &snd_ymfpci_dsp_microcode;
+#else
+		return err;
+#endif
+	}
+	is_1e = chip->device_id == PCI_DEVICE_ID_YAMAHA_724F ||
+		chip->device_id == PCI_DEVICE_ID_YAMAHA_740C ||
+		chip->device_id == PCI_DEVICE_ID_YAMAHA_744 ||
+		chip->device_id == PCI_DEVICE_ID_YAMAHA_754;
+	name = is_1e ? "yamaha/ds1e_ctrl.fw" : "yamaha/ds1_ctrl.fw";
+	err = request_firmware(&chip->controller_microcode, name,
+			       &chip->pci->dev);
+	if (err >= 0) {
+		if (chip->controller_microcode->size == YDSXG_CTRLLENGTH)
+			snd_ymfpci_convert_from_le(chip->controller_microcode);
+		else {
+			snd_printk(KERN_ERR "controller microcode"
+				   " has wrong size\n");
+			err = -EINVAL;
+		}
+	}
+	if (err < 0) {
+#ifdef FIRMWARE_IN_THE_KERNEL
+		chip->controller_microcode =
+			is_1e ? &snd_ymfpci_controller_1e_microcode
+			      : &snd_ymfpci_controller_microcode;
+#else
+		return err;
+#endif
+	}
+	return 0;
+}
+
 static void snd_ymfpci_download_image(struct snd_ymfpci *chip)
 {
 	int i;
 	u16 ctrl;
-	unsigned long *inst;
+	u32 *inst;
 
 	snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x00000000);
 	snd_ymfpci_disable_dsp(chip);
@@ -1992,21 +2100,12 @@
 	snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
 
 	/* setup DSP instruction code */
+	inst = (u32 *)chip->dsp_microcode->data;
 	for (i = 0; i < YDSXG_DSPLENGTH / 4; i++)
-		snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2), DspInst[i]);
+		snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2), inst[i]);
 
 	/* setup control instruction code */
-	switch (chip->device_id) {
-	case PCI_DEVICE_ID_YAMAHA_724F:
-	case PCI_DEVICE_ID_YAMAHA_740C:
-	case PCI_DEVICE_ID_YAMAHA_744:
-	case PCI_DEVICE_ID_YAMAHA_754:
-		inst = CntrlInst1E;
-		break;
-	default:
-		inst = CntrlInst;
-		break;
-	}
+	inst = (u32 *)chip->controller_microcode->data;
 	for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++)
 		snd_ymfpci_writel(chip, YDSXGR_CTRLINSTRAM + (i << 2), inst[i]);
 
@@ -2160,6 +2259,15 @@
 	pci_write_config_word(chip->pci, 0x40, chip->old_legacy_ctrl);
 	
 	pci_disable_device(chip->pci);
+#ifdef FIRMWARE_IN_THE_KERNEL
+	if (chip->dsp_microcode != &snd_ymfpci_dsp_microcode)
+#endif
+		release_firmware(chip->dsp_microcode);
+#ifdef FIRMWARE_IN_THE_KERNEL
+	if (chip->controller_microcode != &snd_ymfpci_controller_microcode &&
+	    chip->controller_microcode != &snd_ymfpci_controller_1e_microcode)
+#endif
+		release_firmware(chip->controller_microcode);
 	kfree(chip);
 	return 0;
 }
@@ -2180,7 +2288,7 @@
 	YDSXGR_PRIADCLOOPVOL,
 	YDSXGR_NATIVEDACINVOL,
 	YDSXGR_NATIVEDACOUTVOL,
-	// YDSXGR_BUF441OUTVOL,
+	YDSXGR_BUF441OUTVOL,
 	YDSXGR_NATIVEADCINVOL,
 	YDSXGR_SPDIFLOOPVOL,
 	YDSXGR_SPDIFOUTVOL,
@@ -2295,6 +2403,7 @@
 	chip->reg_area_phys = pci_resource_start(pci, 0);
 	chip->reg_area_virt = ioremap_nocache(chip->reg_area_phys, 0x8000);
 	pci_set_master(pci);
+	chip->src441_used = -1;
 
 	if ((chip->res_reg_area = request_mem_region(chip->reg_area_phys, 0x8000, "YMFPCI")) == NULL) {
 		snd_printk(KERN_ERR "unable to grab memory region 0x%lx-0x%lx\n", chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1);
@@ -2315,6 +2424,12 @@
 		return -EIO;
 	}
 
+	err = snd_ymfpci_request_firmware(chip);
+	if (err < 0) {
+		snd_printk(KERN_ERR "firmware request failed: %d\n", err);
+		snd_ymfpci_free(chip);
+		return err;
+	}
 	snd_ymfpci_download_image(chip);
 
 	udelay(100); /* seems we need a delay after downloading image.. */
diff --git a/sound/pcmcia/vx/vxp_mixer.c b/sound/pcmcia/vx/vxp_mixer.c
index bced7b6..2b1f996 100644
--- a/sound/pcmcia/vx/vxp_mixer.c
+++ b/sound/pcmcia/vx/vxp_mixer.c
@@ -64,7 +64,7 @@
 	return 0;
 }
 
-static DECLARE_TLV_DB_SCALE(db_scale_mic, -21, 3, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_mic, -21, 3, 0);
 
 static struct snd_kcontrol_new vx_control_mic_level = {
 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index d7df59e..363bcb5 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -91,7 +91,7 @@
  * Only output levels can be modified
  */
 
-static DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0);
 
 static struct snd_vx_hardware vxpocket_hw = {
 	.name = "VXPocket",
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
new file mode 100644
index 0000000..ec821a5
--- /dev/null
+++ b/sound/soc/Kconfig
@@ -0,0 +1,32 @@
+#
+# SoC audio configuration
+#
+
+menu "SoC audio support"
+	depends on SND!=n
+
+config SND_SOC_AC97_BUS
+	bool
+
+config SND_SOC
+	tristate "SoC audio support"
+	---help---
+
+	  If you want SoC support, you should say Y here and also to the
+	  specific driver for your SoC below. You will also need to select the
+	  specific codec(s) attached to the SoC
+
+	  This SoC audio support can also be built as a module.  If so, the module
+	  will be called snd-soc-core.
+
+# All the supported Soc's
+menu "SoC Platforms"
+depends on SND_SOC
+source "sound/soc/at91/Kconfig"
+source "sound/soc/pxa/Kconfig"
+endmenu
+
+# Supported codecs
+source "sound/soc/codecs/Kconfig"
+
+endmenu
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
new file mode 100644
index 0000000..98e6f49
--- /dev/null
+++ b/sound/soc/Makefile
@@ -0,0 +1,4 @@
+snd-soc-core-objs := soc-core.o soc-dapm.o
+
+obj-$(CONFIG_SND_SOC)	+= snd-soc-core.o
+obj-$(CONFIG_SND_SOC)	+= codecs/ at91/ pxa/
diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig
new file mode 100644
index 0000000..5bcf08b
--- /dev/null
+++ b/sound/soc/at91/Kconfig
@@ -0,0 +1,32 @@
+menu "SoC Audio for the Atmel AT91"
+
+config SND_AT91_SOC
+	tristate "SoC Audio for the Atmel AT91 System-on-Chip"
+	depends on ARCH_AT91 && SND
+	select SND_PCM
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the AT91 SSC interface. You will also need
+	  to select the audio interfaces to support below.
+
+config SND_AT91_SOC_I2S
+	tristate
+
+config SND_AT91_SOC_ETI_B1_WM8731
+	tristate "SoC I2S Audio support for WM8731-based Endrelia ETI-B1 boards"
+	depends on SND_AT91_SOC && (MACH_ETI_B1 || MACH_ETI_C1)
+	select SND_AT91_SOC_I2S
+	select SND_SOC_WM8731
+	help
+	  Say Y if you want to add support for SoC audio on WM8731-based
+	  Endrelia Technologies Inc ETI-B1 or ETI-C1 boards.
+
+config SND_AT91_SOC_ETI_SLAVE
+	bool "Run codec in slave Mode on Endrelia boards"
+	depends on SND_AT91_SOC_ETI_B1_WM8731
+	default n
+	help
+	  Say Y if you want to run with the AT91 SSC generating the BCLK
+	  and LRC signals on Endrelia boards.
+
+endmenu
diff --git a/sound/soc/at91/Makefile b/sound/soc/at91/Makefile
new file mode 100644
index 0000000..b77b01a
--- /dev/null
+++ b/sound/soc/at91/Makefile
@@ -0,0 +1,11 @@
+# AT91 Platform Support
+snd-soc-at91-objs := at91-pcm.o
+snd-soc-at91-i2s-objs := at91-i2s.o
+
+obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o
+obj-$(CONFIG_SND_AT91_SOC_I2S) += snd-soc-at91-i2s.o
+
+# AT91 Machine Support
+snd-soc-eti-b1-wm8731-objs := eti_b1_wm8731.o
+
+obj-$(CONFIG_SND_AT91_SOC_ETI_B1_WM8731) += snd-soc-eti-b1-wm8731.o
diff --git a/sound/soc/at91/at91-i2s.c b/sound/soc/at91/at91-i2s.c
new file mode 100644
index 0000000..fcc544a
--- /dev/null
+++ b/sound/soc/at91/at91-i2s.c
@@ -0,0 +1,720 @@
+/*
+ * at91-i2s.c  --  ALSA SoC I2S Audio Layer Platform driver
+ *
+ * Author: Frank Mandarino <fmandarino@endrelia.com>
+ *         Endrelia Technologies Inc.
+ *
+ * Based on pxa2xx Platform drivers by
+ * Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/at91_pmc.h>
+#include <asm/arch/at91_ssc.h>
+#include <asm/arch/at91_pdc.h>
+
+#include "at91-pcm.h"
+#include "at91-i2s.h"
+
+#if 0
+#define	DBG(x...)	printk(KERN_DEBUG "at91-i2s:" x)
+#else
+#define	DBG(x...)
+#endif
+
+#if defined(CONFIG_ARCH_AT91SAM9260)
+#define NUM_SSC_DEVICES		1
+#else
+#define NUM_SSC_DEVICES		3
+#endif
+
+
+/*
+ * SSC PDC registers required by the PCM DMA engine.
+ */
+static struct at91_pdc_regs pdc_tx_reg = {
+	.xpr		= AT91_PDC_TPR,
+	.xcr		= AT91_PDC_TCR,
+	.xnpr		= AT91_PDC_TNPR,
+	.xncr		= AT91_PDC_TNCR,
+};
+
+static struct at91_pdc_regs pdc_rx_reg = {
+	.xpr		= AT91_PDC_RPR,
+	.xcr		= AT91_PDC_RCR,
+	.xnpr		= AT91_PDC_RNPR,
+	.xncr		= AT91_PDC_RNCR,
+};
+
+/*
+ * SSC & PDC status bits for transmit and receive.
+ */
+static struct at91_ssc_mask ssc_tx_mask = {
+	.ssc_enable	= AT91_SSC_TXEN,
+	.ssc_disable	= AT91_SSC_TXDIS,
+	.ssc_endx	= AT91_SSC_ENDTX,
+	.ssc_endbuf	= AT91_SSC_TXBUFE,
+	.pdc_enable	= AT91_PDC_TXTEN,
+	.pdc_disable	= AT91_PDC_TXTDIS,
+};
+
+static struct at91_ssc_mask ssc_rx_mask = {
+	.ssc_enable	= AT91_SSC_RXEN,
+	.ssc_disable	= AT91_SSC_RXDIS,
+	.ssc_endx	= AT91_SSC_ENDRX,
+	.ssc_endbuf	= AT91_SSC_RXBUFF,
+	.pdc_enable	= AT91_PDC_RXTEN,
+	.pdc_disable	= AT91_PDC_RXTDIS,
+};
+
+
+/*
+ * DMA parameters.
+ */
+static struct at91_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
+	{{
+	.name		= "SSC0/I2S PCM Stereo out",
+	.pdc		= &pdc_tx_reg,
+	.mask		= &ssc_tx_mask,
+	},
+	{
+	.name		= "SSC0/I2S PCM Stereo in",
+	.pdc		= &pdc_rx_reg,
+	.mask		= &ssc_rx_mask,
+	}},
+#if NUM_SSC_DEVICES == 3
+	{{
+	.name		= "SSC1/I2S PCM Stereo out",
+	.pdc		= &pdc_tx_reg,
+	.mask		= &ssc_tx_mask,
+	},
+	{
+	.name		= "SSC1/I2S PCM Stereo in",
+	.pdc		= &pdc_rx_reg,
+	.mask		= &ssc_rx_mask,
+	}},
+	{{
+	.name		= "SSC2/I2S PCM Stereo out",
+	.pdc		= &pdc_tx_reg,
+	.mask		= &ssc_tx_mask,
+	},
+	{
+	.name		= "SSC1/I2S PCM Stereo in",
+	.pdc		= &pdc_rx_reg,
+	.mask		= &ssc_rx_mask,
+	}},
+#endif
+};
+
+struct at91_ssc_state {
+	u32	ssc_cmr;
+	u32	ssc_rcmr;
+	u32	ssc_rfmr;
+	u32	ssc_tcmr;
+	u32	ssc_tfmr;
+	u32	ssc_sr;
+	u32	ssc_imr;
+};
+
+static struct at91_ssc_info {
+	char		*name;
+	struct at91_ssc_periph ssc;
+	spinlock_t 	lock;		/* lock for dir_mask */
+	unsigned short	dir_mask;	/* 0=unused, 1=playback, 2=capture */
+	unsigned short	initialized;	/* 1=SSC has been initialized */
+	unsigned short	daifmt;
+	unsigned short	cmr_div;
+	unsigned short	tcmr_period;
+	unsigned short	rcmr_period;
+	struct at91_pcm_dma_params *dma_params[2];
+	struct at91_ssc_state ssc_state;
+
+} ssc_info[NUM_SSC_DEVICES] = {
+	{
+	.name		= "ssc0",
+	.lock		= SPIN_LOCK_UNLOCKED,
+	.dir_mask	= 0,
+	.initialized	= 0,
+	},
+#if NUM_SSC_DEVICES == 3
+	{
+	.name		= "ssc1",
+	.lock		= SPIN_LOCK_UNLOCKED,
+	.dir_mask	= 0,
+	.initialized	= 0,
+	},
+	{
+	.name		= "ssc2",
+	.lock		= SPIN_LOCK_UNLOCKED,
+	.dir_mask	= 0,
+	.initialized	= 0,
+	},
+#endif
+};
+
+static unsigned int at91_i2s_sysclk;
+
+/*
+ * SSC interrupt handler.  Passes PDC interrupts to the DMA
+ * interrupt handler in the PCM driver.
+ */
+static irqreturn_t at91_i2s_interrupt(int irq, void *dev_id)
+{
+	struct at91_ssc_info *ssc_p = dev_id;
+	struct at91_pcm_dma_params *dma_params;
+	u32 ssc_sr;
+	int i;
+
+	ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)
+			& at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR);
+
+	/*
+	 * Loop through the substreams attached to this SSC.  If
+	 * a DMA-related interrupt occurred on that substream, call
+	 * the DMA interrupt handler function, if one has been
+	 * registered in the dma_params structure by the PCM driver.
+	 */
+	for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) {
+		dma_params = ssc_p->dma_params[i];
+
+		if (dma_params != NULL && dma_params->dma_intr_handler != NULL &&
+			(ssc_sr &
+			(dma_params->mask->ssc_endx | dma_params->mask->ssc_endbuf)))
+
+			dma_params->dma_intr_handler(ssc_sr, dma_params->substream);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Startup.  Only that one substream allowed in each direction.
+ */
+static int at91_i2s_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+	int dir_mask;
+
+	DBG("i2s_startup: SSC_SR=0x%08lx\n",
+			at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR));
+	dir_mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0x1 : 0x2;
+
+	spin_lock_irq(&ssc_p->lock);
+	if (ssc_p->dir_mask & dir_mask) {
+		spin_unlock_irq(&ssc_p->lock);
+		return -EBUSY;
+	}
+	ssc_p->dir_mask |= dir_mask;
+	spin_unlock_irq(&ssc_p->lock);
+
+	return 0;
+}
+
+/*
+ * Shutdown.  Clear DMA parameters and shutdown the SSC if there
+ * are no other substreams open.
+ */
+static void at91_i2s_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+	struct at91_pcm_dma_params *dma_params;
+	int dir, dir_mask;
+
+	dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+	dma_params = ssc_p->dma_params[dir];
+
+	if (dma_params != NULL) {
+		at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR,
+				dma_params->mask->ssc_disable);
+		DBG("%s disabled SSC_SR=0x%08lx\n", (dir ? "receive" : "transmit"),
+			at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR));
+
+		dma_params->ssc_base = NULL;
+		dma_params->substream = NULL;
+		ssc_p->dma_params[dir] = NULL;
+	}
+
+	dir_mask = 1 << dir;
+
+	spin_lock_irq(&ssc_p->lock);
+	ssc_p->dir_mask &= ~dir_mask;
+	if (!ssc_p->dir_mask) {
+		/* Shutdown the SSC clock. */
+		DBG("Stopping pid %d clock\n", ssc_p->ssc.pid);
+		at91_sys_write(AT91_PMC_PCDR, 1<<ssc_p->ssc.pid);
+
+		if (ssc_p->initialized) {
+			free_irq(ssc_p->ssc.pid, ssc_p);
+			ssc_p->initialized = 0;
+		}
+
+		/* Reset the SSC */
+		at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST);
+
+		/* Clear the SSC dividers */
+		ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0;
+	}
+	spin_unlock_irq(&ssc_p->lock);
+}
+
+/*
+ * Record the SSC system clock rate.
+ */
+static int at91_i2s_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	/*
+	 * The only clock supplied to the SSC is the AT91 master clock,
+	 * which is only used if the SSC is generating BCLK and/or
+	 * LRC clocks.
+	 */
+	switch (clk_id) {
+	case AT91_SYSCLK_MCK:
+		at91_i2s_sysclk = freq;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Record the DAI format for use in hw_params().
+ */
+static int at91_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai,
+		unsigned int fmt)
+{
+	struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
+
+	if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)
+		return -EINVAL;
+
+	ssc_p->daifmt = fmt;
+	return 0;
+}
+
+/*
+ * Record SSC clock dividers for use in hw_params().
+ */
+static int at91_i2s_set_dai_clkdiv(struct snd_soc_cpu_dai *cpu_dai,
+	int div_id, int div)
+{
+	struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
+
+	switch (div_id) {
+	case AT91SSC_CMR_DIV:
+		/*
+		 * The same master clock divider is used for both
+		 * transmit and receive, so if a value has already
+		 * been set, it must match this value.
+		 */
+		if (ssc_p->cmr_div == 0)
+			ssc_p->cmr_div = div;
+		else
+			if (div != ssc_p->cmr_div)
+				return -EBUSY;
+		break;
+
+	case AT91SSC_TCMR_PERIOD:
+		ssc_p->tcmr_period = div;
+		break;
+
+	case AT91SSC_RCMR_PERIOD:
+		ssc_p->rcmr_period = div;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Configure the SSC.
+ */
+static int at91_i2s_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	int id = rtd->dai->cpu_dai->id;
+	struct at91_ssc_info *ssc_p = &ssc_info[id];
+	struct at91_pcm_dma_params *dma_params;
+	int dir, channels, bits;
+	u32 tfmr, rfmr, tcmr, rcmr;
+	int start_event;
+	int ret;
+
+	/*
+	 * Currently, there is only one set of dma params for
+	 * each direction.  If more are added, this code will
+	 * have to be changed to select the proper set.
+	 */
+	dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+
+	dma_params = &ssc_dma_params[id][dir];
+	dma_params->ssc_base = ssc_p->ssc.base;
+	dma_params->substream = substream;
+
+	ssc_p->dma_params[dir] = dma_params;
+
+	/*
+	 * The cpu_dai->dma_data field is only used to communicate the
+	 * appropriate DMA parameters to the pcm driver hw_params()
+	 * function.  It should not be used for other purposes
+	 * as it is common to all substreams.
+	 */
+	rtd->dai->cpu_dai->dma_data = dma_params;
+
+	channels = params_channels(params);
+
+	/*
+	 * The SSC only supports up to 16-bit samples in I2S format, due
+	 * to the size of the Frame Mode Register FSLEN field.  Also, I2S
+	 * implies signed data.
+	 */
+	bits = 16;
+	dma_params->pdc_xfer_size = 2;
+
+	/*
+	 * Compute SSC register settings.
+	 */
+	switch (ssc_p->daifmt) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		/*
+		 * SSC provides BCLK and LRC clocks.
+		 *
+		 * The SSC transmit and receive clocks are generated from the
+		 * MCK divider, and the BCLK signal is output on the SSC TK line.
+		 */
+		rcmr =	  (( ssc_p->rcmr_period		<< 24) & AT91_SSC_PERIOD)
+			| (( 1				<< 16) & AT91_SSC_STTDLY)
+			| (( AT91_SSC_START_FALLING_RF	     ) & AT91_SSC_START)
+			| (( AT91_SSC_CK_RISING		     ) & AT91_SSC_CKI)
+			| (( AT91_SSC_CKO_NONE		     ) & AT91_SSC_CKO)
+			| (( AT91_SSC_CKS_DIV		     ) & AT91_SSC_CKS);
+
+		rfmr =	  (( AT91_SSC_FSEDGE_POSITIVE	     ) & AT91_SSC_FSEDGE)
+			| (( AT91_SSC_FSOS_NEGATIVE	     ) & AT91_SSC_FSOS)
+			| (((bits - 1)			<< 16) & AT91_SSC_FSLEN)
+			| (((channels - 1)		<<  8) & AT91_SSC_DATNB)
+			| (( 1				<<  7) & AT91_SSC_MSBF)
+			| (( 0				<<  5) & AT91_SSC_LOOP)
+			| (((bits - 1)			<<  0) & AT91_SSC_DATALEN);
+
+		tcmr =	  (( ssc_p->tcmr_period		<< 24) & AT91_SSC_PERIOD)
+			| (( 1				<< 16) & AT91_SSC_STTDLY)
+			| (( AT91_SSC_START_FALLING_RF       ) & AT91_SSC_START)
+			| (( AT91_SSC_CKI_FALLING	     ) & AT91_SSC_CKI)
+			| (( AT91_SSC_CKO_CONTINUOUS	     ) & AT91_SSC_CKO)
+			| (( AT91_SSC_CKS_DIV		     ) & AT91_SSC_CKS);
+
+		tfmr =	  (( AT91_SSC_FSEDGE_POSITIVE	     ) & AT91_SSC_FSEDGE)
+			| (( 0				<< 23) & AT91_SSC_FSDEN)
+			| (( AT91_SSC_FSOS_NEGATIVE	     ) & AT91_SSC_FSOS)
+			| (((bits - 1)			<< 16) & AT91_SSC_FSLEN)
+			| (((channels - 1)		<<  8) & AT91_SSC_DATNB)
+			| (( 1				<<  7) & AT91_SSC_MSBF)
+			| (( 0				<<  5) & AT91_SSC_DATDEF)
+			| (((bits - 1)			<<  0) & AT91_SSC_DATALEN);
+		break;
+
+	case SND_SOC_DAIFMT_CBM_CFM:
+
+		/*
+		 * CODEC supplies BCLK and LRC clocks.
+		 *
+		 * The SSC transmit clock is obtained from the BCLK signal on
+		 * on the TK line, and the SSC receive clock is generated from the
+		 * transmit clock.
+		 *
+		 * For single channel data, one sample is transferred on the falling
+		 * edge of the LRC clock.  For two channel data, one sample is
+		 * transferred on both edges of the LRC clock.
+		 */
+		start_event = channels == 1
+				? AT91_SSC_START_FALLING_RF
+				: AT91_SSC_START_EDGE_RF;
+
+		rcmr =	  (( 0				<< 24) & AT91_SSC_PERIOD)
+			| (( 1				<< 16) & AT91_SSC_STTDLY)
+			| (( start_event		     ) & AT91_SSC_START)
+			| (( AT91_SSC_CK_RISING		     ) & AT91_SSC_CKI)
+			| (( AT91_SSC_CKO_NONE		     ) & AT91_SSC_CKO)
+			| (( AT91_SSC_CKS_CLOCK		     ) & AT91_SSC_CKS);
+
+		rfmr =	  (( AT91_SSC_FSEDGE_POSITIVE	     ) & AT91_SSC_FSEDGE)
+			| (( AT91_SSC_FSOS_NONE		     ) & AT91_SSC_FSOS)
+			| (( 0				<< 16) & AT91_SSC_FSLEN)
+			| (( 0				<<  8) & AT91_SSC_DATNB)
+			| (( 1				<<  7) & AT91_SSC_MSBF)
+			| (( 0				<<  5) & AT91_SSC_LOOP)
+			| (((bits - 1)			<<  0) & AT91_SSC_DATALEN);
+
+		tcmr =	  (( 0				<< 24) & AT91_SSC_PERIOD)
+			| (( 1				<< 16) & AT91_SSC_STTDLY)
+			| (( start_event		     ) & AT91_SSC_START)
+			| (( AT91_SSC_CKI_FALLING	     ) & AT91_SSC_CKI)
+			| (( AT91_SSC_CKO_NONE		     ) & AT91_SSC_CKO)
+			| (( AT91_SSC_CKS_PIN		     ) & AT91_SSC_CKS);
+
+		tfmr =	  (( AT91_SSC_FSEDGE_POSITIVE	     ) & AT91_SSC_FSEDGE)
+			| (( 0				<< 23) & AT91_SSC_FSDEN)
+			| (( AT91_SSC_FSOS_NONE		     ) & AT91_SSC_FSOS)
+			| (( 0				<< 16) & AT91_SSC_FSLEN)
+			| (( 0				<<  8) & AT91_SSC_DATNB)
+			| (( 1				<<  7) & AT91_SSC_MSBF)
+			| (( 0				<<  5) & AT91_SSC_DATDEF)
+			| (((bits - 1)			<<  0) & AT91_SSC_DATALEN);
+		break;
+
+	case SND_SOC_DAIFMT_CBS_CFM:
+	case SND_SOC_DAIFMT_CBM_CFS:
+	default:
+		printk(KERN_WARNING "at91-i2s: unsupported DAI format 0x%x.\n",
+			ssc_p->daifmt);
+		return -EINVAL;
+		break;
+	}
+	DBG("RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", rcmr, rfmr, tcmr, tfmr);
+
+	if (!ssc_p->initialized) {
+
+		/* Enable PMC peripheral clock for this SSC */
+		DBG("Starting pid %d clock\n", ssc_p->ssc.pid);
+		at91_sys_write(AT91_PMC_PCER, 1<<ssc_p->ssc.pid);
+
+		/* Reset the SSC and its PDC registers */
+		at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST);
+
+		at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RPR, 0);
+		at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RCR, 0);
+		at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RNPR, 0);
+		at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RNCR, 0);
+		at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TPR, 0);
+		at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TCR, 0);
+		at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TNPR, 0);
+		at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TNCR, 0);
+
+		if ((ret = request_irq(ssc_p->ssc.pid, at91_i2s_interrupt,
+					0, ssc_p->name, ssc_p)) < 0) {
+			printk(KERN_WARNING "at91-i2s: request_irq failure\n");
+
+			DBG("Stopping pid %d clock\n", ssc_p->ssc.pid);
+			at91_sys_write(AT91_PMC_PCER, 1<<ssc_p->ssc.pid);
+			return ret;
+		}
+
+		ssc_p->initialized = 1;
+	}
+
+	/* set SSC clock mode register */
+	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->cmr_div);
+
+	/* set receive clock mode and format */
+	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, rcmr);
+	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, rfmr);
+
+	/* set transmit clock mode and format */
+	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, tcmr);
+	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, tfmr);
+
+	DBG("hw_params: SSC initialized\n");
+	return 0;
+}
+
+
+static int at91_i2s_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+	struct at91_pcm_dma_params *dma_params;
+	int dir;
+
+	dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+	dma_params = ssc_p->dma_params[dir];
+
+	at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR,
+			dma_params->mask->ssc_enable);
+
+	DBG("%s enabled SSC_SR=0x%08lx\n", dir ? "receive" : "transmit",
+		at91_ssc_read(dma_params->ssc_base + AT91_SSC_SR));
+	return 0;
+}
+
+
+#ifdef CONFIG_PM
+static int at91_i2s_suspend(struct platform_device *pdev,
+	struct snd_soc_cpu_dai *cpu_dai)
+{
+	struct at91_ssc_info *ssc_p;
+
+	if(!cpu_dai->active)
+		return 0;
+
+	ssc_p = &ssc_info[cpu_dai->id];
+
+	/* Save the status register before disabling transmit and receive. */
+	ssc_p->ssc_state.ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR);
+	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR,
+			AT91_SSC_TXDIS | AT91_SSC_RXDIS);
+
+	/* Save the current interrupt mask, then disable unmasked interrupts. */
+	ssc_p->ssc_state.ssc_imr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR);
+	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IDR, ssc_p->ssc_state.ssc_imr);
+
+	ssc_p->ssc_state.ssc_cmr  = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_CMR);
+	ssc_p->ssc_state.ssc_rcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR);
+	ssc_p->ssc_state.ssc_rfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RFMR);
+	ssc_p->ssc_state.ssc_tcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TCMR);
+	ssc_p->ssc_state.ssc_tfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TFMR);
+
+	return 0;
+}
+
+static int at91_i2s_resume(struct platform_device *pdev,
+	struct snd_soc_cpu_dai *cpu_dai)
+{
+	struct at91_ssc_info *ssc_p;
+
+	if(!cpu_dai->active)
+		return 0;
+
+	ssc_p = &ssc_info[cpu_dai->id];
+
+	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, ssc_p->ssc_state.ssc_tfmr);
+	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, ssc_p->ssc_state.ssc_tcmr);
+	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, ssc_p->ssc_state.ssc_rfmr);
+	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_rcmr);
+	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR,  ssc_p->ssc_state.ssc_cmr);
+
+	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IER,  ssc_p->ssc_state.ssc_imr);
+
+	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR,
+		((ssc_p->ssc_state.ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) |
+		((ssc_p->ssc_state.ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0));
+
+	return 0;
+}
+
+#else
+#define at91_i2s_suspend	NULL
+#define at91_i2s_resume		NULL
+#endif
+
+#define AT91_I2S_RATES (SNDRV_PCM_RATE_8000  | SNDRV_PCM_RATE_11025 |\
+			SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+			SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
+			SNDRV_PCM_RATE_96000)
+
+struct snd_soc_cpu_dai at91_i2s_dai[NUM_SSC_DEVICES] = {
+	{	.name = "at91_ssc0/i2s",
+		.id = 0,
+		.type = SND_SOC_DAI_I2S,
+		.suspend = at91_i2s_suspend,
+		.resume = at91_i2s_resume,
+		.playback = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = AT91_I2S_RATES,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+		.capture = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = AT91_I2S_RATES,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+		.ops = {
+			.startup = at91_i2s_startup,
+			.shutdown = at91_i2s_shutdown,
+			.prepare = at91_i2s_prepare,
+			.hw_params = at91_i2s_hw_params,},
+		.dai_ops = {
+			.set_sysclk = at91_i2s_set_dai_sysclk,
+			.set_fmt = at91_i2s_set_dai_fmt,
+			.set_clkdiv = at91_i2s_set_dai_clkdiv,},
+		.private_data = &ssc_info[0].ssc,
+	},
+#if NUM_SSC_DEVICES == 3
+	{	.name = "at91_ssc1/i2s",
+		.id = 1,
+		.type = SND_SOC_DAI_I2S,
+		.suspend = at91_i2s_suspend,
+		.resume = at91_i2s_resume,
+		.playback = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = AT91_I2S_RATES,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+		.capture = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = AT91_I2S_RATES,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+		.ops = {
+			.startup = at91_i2s_startup,
+			.shutdown = at91_i2s_shutdown,
+			.prepare = at91_i2s_prepare,
+			.hw_params = at91_i2s_hw_params,},
+		.dai_ops = {
+			.set_sysclk = at91_i2s_set_dai_sysclk,
+			.set_fmt = at91_i2s_set_dai_fmt,
+			.set_clkdiv = at91_i2s_set_dai_clkdiv,},
+		.private_data = &ssc_info[1].ssc,
+	},
+	{	.name = "at91_ssc2/i2s",
+		.id = 2,
+		.type = SND_SOC_DAI_I2S,
+		.suspend = at91_i2s_suspend,
+		.resume = at91_i2s_resume,
+		.playback = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = AT91_I2S_RATES,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+		.capture = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = AT91_I2S_RATES,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+		.ops = {
+			.startup = at91_i2s_startup,
+			.shutdown = at91_i2s_shutdown,
+			.prepare = at91_i2s_prepare,
+			.hw_params = at91_i2s_hw_params,},
+		.dai_ops = {
+			.set_sysclk = at91_i2s_set_dai_sysclk,
+			.set_fmt = at91_i2s_set_dai_fmt,
+			.set_clkdiv = at91_i2s_set_dai_clkdiv,},
+		.private_data = &ssc_info[2].ssc,
+	},
+#endif
+};
+
+EXPORT_SYMBOL_GPL(at91_i2s_dai);
+
+/* Module information */
+MODULE_AUTHOR("Frank Mandarino, fmandarino@endrelia.com, www.endrelia.com");
+MODULE_DESCRIPTION("AT91 I2S ASoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/at91/at91-i2s.h b/sound/soc/at91/at91-i2s.h
new file mode 100644
index 0000000..f8a875b
--- /dev/null
+++ b/sound/soc/at91/at91-i2s.h
@@ -0,0 +1,27 @@
+/*
+ * at91-i2s.h - ALSA I2S interface for the Atmel AT91 SoC
+ *
+ * Author:	Frank Mandarino <fmandarino@endrelia.com>
+ *		Endrelia Technologies Inc.
+ * Created:	Jan 9, 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _AT91_I2S_H
+#define _AT91_I2S_H
+
+/* I2S system clock ids */
+#define AT91_SYSCLK_MCK		0 /* SSC uses AT91 MCK as system clock */
+
+/* I2S divider ids */
+#define AT91SSC_CMR_DIV		0 /* MCK divider for BCLK */
+#define AT91SSC_TCMR_PERIOD	1 /* BCLK divider for transmit FS */
+#define AT91SSC_RCMR_PERIOD	2 /* BCLK divider for receive FS */
+
+extern struct snd_soc_cpu_dai at91_i2s_dai[];
+
+#endif /* _AT91_I2S_H */
+
diff --git a/sound/soc/at91/at91-pcm.c b/sound/soc/at91/at91-pcm.c
new file mode 100644
index 0000000..e88b12e
--- /dev/null
+++ b/sound/soc/at91/at91-pcm.c
@@ -0,0 +1,432 @@
+/*
+ * at91-pcm.c -- ALSA PCM interface for the Atmel AT91 SoC
+ *
+ * Author:	Frank Mandarino <fmandarino@endrelia.com>
+ *		Endrelia Technologies Inc.
+ * Created:	Mar 3, 2006
+ *
+ * Based on pxa2xx-pcm.c by:
+ *
+ * Author:	Nicolas Pitre
+ * Created:	Nov 30, 2004
+ * Copyright:	(C) 2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/at91_ssc.h>
+#include <asm/arch/at91_pdc.h>
+
+#include "at91-pcm.h"
+
+#if 0
+#define	DBG(x...)	printk(KERN_INFO "at91-pcm: " x)
+#else
+#define	DBG(x...)
+#endif
+
+static const struct snd_pcm_hardware at91_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_PAUSE,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 8192,
+	.periods_min		= 2,
+	.periods_max		= 1024,
+	.buffer_bytes_max	= 32 * 1024,
+};
+
+struct at91_runtime_data {
+	struct at91_pcm_dma_params *params;
+	dma_addr_t dma_buffer;			/* physical address of dma buffer */
+	dma_addr_t dma_buffer_end;		/* first address beyond DMA buffer */
+	size_t period_size;
+	dma_addr_t period_ptr;			/* physical address of next period */
+	u32 pdc_xpr_save;			/* PDC register save */
+	u32 pdc_xcr_save;
+	u32 pdc_xnpr_save;
+	u32 pdc_xncr_save;
+};
+
+static void at91_pcm_dma_irq(u32 ssc_sr,
+	struct snd_pcm_substream *substream)
+{
+	struct at91_runtime_data *prtd = substream->runtime->private_data;
+	struct at91_pcm_dma_params *params = prtd->params;
+	static int count = 0;
+
+	count++;
+
+	if (ssc_sr & params->mask->ssc_endbuf) {
+
+		printk(KERN_WARNING
+			"at91-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n",
+			substream->stream == SNDRV_PCM_STREAM_PLAYBACK
+				? "underrun" : "overrun",
+			params->name, ssc_sr, count);
+
+		/* re-start the PDC */
+		at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable);
+
+		prtd->period_ptr += prtd->period_size;
+		if (prtd->period_ptr >= prtd->dma_buffer_end) {
+			prtd->period_ptr = prtd->dma_buffer;
+		}
+
+		at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr);
+		at91_ssc_write(params->ssc_base + params->pdc->xcr,
+				prtd->period_size / params->pdc_xfer_size);
+
+		at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable);
+	}
+
+	if (ssc_sr & params->mask->ssc_endx) {
+
+		/* Load the PDC next pointer and counter registers */
+		prtd->period_ptr += prtd->period_size;
+		if (prtd->period_ptr >= prtd->dma_buffer_end) {
+			prtd->period_ptr = prtd->dma_buffer;
+		}
+		at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr);
+		at91_ssc_write(params->ssc_base + params->pdc->xncr,
+				prtd->period_size / params->pdc_xfer_size);
+	}
+
+	snd_pcm_period_elapsed(substream);
+}
+
+static int at91_pcm_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct at91_runtime_data *prtd = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	/* this may get called several times by oss emulation
+	 * with different params */
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	runtime->dma_bytes = params_buffer_bytes(params);
+
+	prtd->params = rtd->dai->cpu_dai->dma_data;
+	prtd->params->dma_intr_handler = at91_pcm_dma_irq;
+
+	prtd->dma_buffer = runtime->dma_addr;
+	prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
+	prtd->period_size = params_period_bytes(params);
+
+	DBG("hw_params: DMA for %s initialized (dma_bytes=%d, period_size=%d)\n",
+		prtd->params->name, runtime->dma_bytes, prtd->period_size);
+	return 0;
+}
+
+static int at91_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct at91_runtime_data *prtd = substream->runtime->private_data;
+	struct at91_pcm_dma_params *params = prtd->params;
+
+	if (params != NULL) {
+		at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable);
+		prtd->params->dma_intr_handler = NULL;
+	}
+
+	return 0;
+}
+
+static int at91_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct at91_runtime_data *prtd = substream->runtime->private_data;
+	struct at91_pcm_dma_params *params = prtd->params;
+
+	at91_ssc_write(params->ssc_base + AT91_SSC_IDR,
+			params->mask->ssc_endx | params->mask->ssc_endbuf);
+
+	at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable);
+	return 0;
+}
+
+static int at91_pcm_trigger(struct snd_pcm_substream *substream,
+	int cmd)
+{
+	struct at91_runtime_data *prtd = substream->runtime->private_data;
+	struct at91_pcm_dma_params *params = prtd->params;
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		prtd->period_ptr = prtd->dma_buffer;
+
+		at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr);
+		at91_ssc_write(params->ssc_base + params->pdc->xcr,
+				prtd->period_size / params->pdc_xfer_size);
+
+		prtd->period_ptr += prtd->period_size;
+		at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr);
+		at91_ssc_write(params->ssc_base + params->pdc->xncr,
+				prtd->period_size / params->pdc_xfer_size);
+
+		DBG("trigger: period_ptr=%lx, xpr=%lx, xcr=%ld, xnpr=%lx, xncr=%ld\n",
+			(unsigned long) prtd->period_ptr,
+			at91_ssc_read(params->ssc_base + params->pdc->xpr),
+			at91_ssc_read(params->ssc_base + params->pdc->xcr),
+			at91_ssc_read(params->ssc_base + params->pdc->xnpr),
+			at91_ssc_read(params->ssc_base + params->pdc->xncr));
+
+		at91_ssc_write(params->ssc_base + AT91_SSC_IER,
+			params->mask->ssc_endx | params->mask->ssc_endbuf);
+
+		at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable);
+
+		DBG("sr=%lx imr=%lx\n", at91_ssc_read(params->ssc_base + AT91_SSC_SR),
+					at91_ssc_read(params->ssc_base + AT91_SSC_IER));
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable);
+		break;
+
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static snd_pcm_uframes_t at91_pcm_pointer(
+	struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct at91_runtime_data *prtd = runtime->private_data;
+	struct at91_pcm_dma_params *params = prtd->params;
+	dma_addr_t ptr;
+	snd_pcm_uframes_t x;
+
+	ptr = (dma_addr_t) at91_ssc_read(params->ssc_base + params->pdc->xpr);
+	x = bytes_to_frames(runtime, ptr - prtd->dma_buffer);
+
+	if (x == runtime->buffer_size)
+		x = 0;
+	return x;
+}
+
+static int at91_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct at91_runtime_data *prtd;
+	int ret = 0;
+
+	snd_soc_set_runtime_hwparams(substream, &at91_pcm_hardware);
+
+	/* ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		goto out;
+
+	prtd = kzalloc(sizeof(struct at91_runtime_data), GFP_KERNEL);
+	if (prtd == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	runtime->private_data = prtd;
+
+ out:
+	return ret;
+}
+
+static int at91_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct at91_runtime_data *prtd = substream->runtime->private_data;
+
+	kfree(prtd);
+	return 0;
+}
+
+static int at91_pcm_mmap(struct snd_pcm_substream *substream,
+	struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+				     runtime->dma_area,
+				     runtime->dma_addr,
+				     runtime->dma_bytes);
+}
+
+struct snd_pcm_ops at91_pcm_ops = {
+	.open		= at91_pcm_open,
+	.close		= at91_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= at91_pcm_hw_params,
+	.hw_free	= at91_pcm_hw_free,
+	.prepare	= at91_pcm_prepare,
+	.trigger	= at91_pcm_trigger,
+	.pointer	= at91_pcm_pointer,
+	.mmap		= at91_pcm_mmap,
+};
+
+static int at91_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
+	int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = at91_pcm_hardware.buffer_bytes_max;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+					   &buf->addr, GFP_KERNEL);
+
+	DBG("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
+		(void *) buf->area,
+		(void *) buf->addr,
+		size);
+
+	if (!buf->area)
+		return -ENOMEM;
+
+	buf->bytes = size;
+	return 0;
+}
+
+static u64 at91_pcm_dmamask = 0xffffffff;
+
+static int at91_pcm_new(struct snd_card *card,
+	struct snd_soc_codec_dai *dai, struct snd_pcm *pcm)
+{
+	int ret = 0;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &at91_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = 0xffffffff;
+
+	if (dai->playback.channels_min) {
+		ret = at91_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			goto out;
+	}
+
+	if (dai->capture.channels_min) {
+		ret = at91_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			goto out;
+	}
+ out:
+	return ret;
+}
+
+static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+
+		dma_free_writecombine(pcm->card->dev, buf->bytes,
+				      buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+
+#ifdef CONFIG_PM
+static int at91_pcm_suspend(struct platform_device *pdev,
+	struct snd_soc_cpu_dai *dai)
+{
+	struct snd_pcm_runtime *runtime = dai->runtime;
+	struct at91_runtime_data *prtd;
+	struct at91_pcm_dma_params *params;
+
+	if (!runtime)
+		return 0;
+
+	prtd = runtime->private_data;
+	params = prtd->params;
+
+	/* disable the PDC and save the PDC registers */
+
+	at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable);
+
+	prtd->pdc_xpr_save  = at91_ssc_read(params->ssc_base + params->pdc->xpr);
+	prtd->pdc_xcr_save  = at91_ssc_read(params->ssc_base + params->pdc->xcr);
+	prtd->pdc_xnpr_save = at91_ssc_read(params->ssc_base + params->pdc->xnpr);
+	prtd->pdc_xncr_save = at91_ssc_read(params->ssc_base + params->pdc->xncr);
+
+	return 0;
+}
+
+static int at91_pcm_resume(struct platform_device *pdev,
+	struct snd_soc_cpu_dai *dai)
+{
+	struct snd_pcm_runtime *runtime = dai->runtime;
+	struct at91_runtime_data *prtd;
+	struct at91_pcm_dma_params *params;
+
+	if (!runtime)
+		return 0;
+
+	prtd = runtime->private_data;
+	params = prtd->params;
+
+	/* restore the PDC registers and enable the PDC */
+	at91_ssc_write(params->ssc_base + params->pdc->xpr,  prtd->pdc_xpr_save);
+	at91_ssc_write(params->ssc_base + params->pdc->xcr,  prtd->pdc_xcr_save);
+	at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->pdc_xnpr_save);
+	at91_ssc_write(params->ssc_base + params->pdc->xncr, prtd->pdc_xncr_save);
+
+	at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable);
+	return 0;
+}
+#else
+#define at91_pcm_suspend	NULL
+#define at91_pcm_resume		NULL
+#endif
+
+struct snd_soc_platform at91_soc_platform = {
+	.name		= "at91-audio",
+	.pcm_ops 	= &at91_pcm_ops,
+	.pcm_new	= at91_pcm_new,
+	.pcm_free	= at91_pcm_free_dma_buffers,
+	.suspend	= at91_pcm_suspend,
+	.resume		= at91_pcm_resume,
+};
+
+EXPORT_SYMBOL_GPL(at91_soc_platform);
+
+MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>");
+MODULE_DESCRIPTION("Atmel AT91 PCM module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/at91/at91-pcm.h b/sound/soc/at91/at91-pcm.h
new file mode 100644
index 0000000..58d0f00
--- /dev/null
+++ b/sound/soc/at91/at91-pcm.h
@@ -0,0 +1,72 @@
+/*
+ * at91-pcm.h - ALSA PCM interface for the Atmel AT91 SoC
+ *
+ * Author:	Frank Mandarino <fmandarino@endrelia.com>
+ *		Endrelia Technologies Inc.
+ * Created:	Mar 3, 2006
+ *
+ * Based on pxa2xx-pcm.h by:
+ *
+ * Author:	Nicolas Pitre
+ * Created:	Nov 30, 2004
+ * Copyright:	MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _AT91_PCM_H
+#define _AT91_PCM_H
+
+#include <asm/arch/hardware.h>
+
+struct at91_ssc_periph {
+	void __iomem	*base;
+	u32		pid;
+};
+
+/*
+ * Registers and status bits that are required by the PCM driver.
+ */
+struct at91_pdc_regs {
+	unsigned int	xpr;		/* PDC recv/trans pointer */
+	unsigned int	xcr;		/* PDC recv/trans counter */
+	unsigned int	xnpr;		/* PDC next recv/trans pointer */
+	unsigned int	xncr;		/* PDC next recv/trans counter */
+	unsigned int	ptcr;		/* PDC transfer control */
+};
+
+struct at91_ssc_mask {
+	u32	ssc_enable;		/* SSC recv/trans enable */
+	u32	ssc_disable;		/* SSC recv/trans disable */
+	u32	ssc_endx;		/* SSC ENDTX or ENDRX */
+	u32	ssc_endbuf;		/* SSC TXBUFE or RXBUFF */
+	u32	pdc_enable;		/* PDC recv/trans enable */
+	u32	pdc_disable;		/* PDC recv/trans disable */
+};
+
+/*
+ * This structure, shared between the PCM driver and the interface,
+ * contains all information required by the PCM driver to perform the
+ * PDC DMA operation.  All fields except dma_intr_handler() are initialized
+ * by the interface.  The dms_intr_handler() pointer is set by the PCM
+ * driver and called by the interface SSC interrupt handler if it is
+ * non-NULL.
+ */
+struct at91_pcm_dma_params {
+	char *name;			/* stream identifier */
+	int pdc_xfer_size;		/* PDC counter increment in bytes */
+	void __iomem *ssc_base;		/* SSC base address */
+	struct at91_pdc_regs *pdc; /* PDC receive or transmit registers */
+	struct at91_ssc_mask *mask;/* SSC & PDC status bits */
+	struct snd_pcm_substream *substream;
+	void (*dma_intr_handler)(u32, struct snd_pcm_substream *);
+};
+
+extern struct snd_soc_platform at91_soc_platform;
+
+#define at91_ssc_read(a)	((unsigned long) __raw_readl(a))
+#define at91_ssc_write(a,v)	__raw_writel((v),(a))
+
+#endif /* _AT91_PCM_H */
diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c
new file mode 100644
index 0000000..8179df3
--- /dev/null
+++ b/sound/soc/at91/eti_b1_wm8731.c
@@ -0,0 +1,375 @@
+/*
+ * eti_b1_wm8731  --  SoC audio for AT91RM9200-based Endrelia ETI_B1 board.
+ *
+ * Author:	Frank Mandarino <fmandarino@endrelia.com>
+ *		Endrelia Technologies Inc.
+ * Created:	Mar 29, 2006
+ *
+ * Based on corgi.c by:
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *          Richard Purdie <richard@openedhand.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/at91_pio.h>
+#include <asm/arch/gpio.h>
+
+#include "../codecs/wm8731.h"
+#include "at91-pcm.h"
+#include "at91-i2s.h"
+
+#if 0
+#define	DBG(x...)	printk(KERN_INFO "eti_b1_wm8731: " x)
+#else
+#define	DBG(x...)
+#endif
+
+#define AT91_PIO_TF1	(1 << (AT91_PIN_PB6 - PIN_BASE) % 32)
+#define AT91_PIO_TK1	(1 << (AT91_PIN_PB7 - PIN_BASE) % 32)
+#define AT91_PIO_TD1	(1 << (AT91_PIN_PB8 - PIN_BASE) % 32)
+#define AT91_PIO_RD1	(1 << (AT91_PIN_PB9 - PIN_BASE) % 32)
+#define AT91_PIO_RK1	(1 << (AT91_PIN_PB10 - PIN_BASE) % 32)
+#define AT91_PIO_RF1	(1 << (AT91_PIN_PB11 - PIN_BASE) % 32)
+
+static struct clk *pck1_clk;
+static struct clk *pllb_clk;
+
+
+static int eti_b1_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	int ret;
+
+	/* cpu clock is the AT91 master clock sent to the SSC */
+	ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, AT91_SYSCLK_MCK,
+		60000000, SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* codec system clock is supplied by PCK1, set to 12MHz */
+	ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK,
+		12000000, SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* Start PCK1 clock. */
+	clk_enable(pck1_clk);
+	DBG("pck1 started\n");
+
+	return 0;
+}
+
+static void eti_b1_shutdown(struct snd_pcm_substream *substream)
+{
+	/* Stop PCK1 clock. */
+	clk_disable(pck1_clk);
+	DBG("pck1 stopped\n");
+}
+
+static int eti_b1_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	int ret;
+
+#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
+	unsigned int rate;
+	int cmr_div, period;
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * The SSC clock dividers depend on the sample rate.  The CMR.DIV
+	 * field divides the system master clock MCK to drive the SSC TK
+	 * signal which provides the codec BCLK.  The TCMR.PERIOD and
+	 * RCMR.PERIOD fields further divide the BCLK signal to drive
+	 * the SSC TF and RF signals which provide the codec DACLRC and
+	 * ADCLRC clocks.
+	 *
+	 * The dividers were determined through trial and error, where a
+	 * CMR.DIV value is chosen such that the resulting BCLK value is
+	 * divisible, or almost divisible, by (2 * sample rate), and then
+	 * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1.
+	 */
+	rate = params_rate(params);
+
+	switch (rate) {
+	case 8000:
+		cmr_div = 25;	/* BCLK = 60MHz/(2*25) = 1.2MHz */
+		period = 74;	/* LRC = BCLK/(2*(74+1)) = 8000Hz */
+		break;
+	case 32000:
+		cmr_div = 7;	/* BCLK = 60MHz/(2*7) ~= 4.28571428MHz */
+		period = 66;	/* LRC = BCLK/(2*(66+1)) = 31982.942Hz */
+		break;
+	case 48000:
+		cmr_div = 13;	/* BCLK = 60MHz/(2*13) ~= 2.3076923MHz */
+		period = 23;	/* LRC = BCLK/(2*(23+1)) = 48076.923Hz */
+		break;
+	default:
+		printk(KERN_WARNING "unsupported rate %d on ETI-B1 board\n", rate);
+		return -EINVAL;
+	}
+
+	/* set the MCK divider for BCLK */
+	ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div);
+	if (ret < 0)
+		return ret;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		/* set the BCLK divider for DACLRC */
+		ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai,
+						AT91SSC_TCMR_PERIOD, period);
+	} else {
+		/* set the BCLK divider for ADCLRC */
+		ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai,
+						AT91SSC_RCMR_PERIOD, period);
+	}
+	if (ret < 0)
+		return ret;
+
+#else /* CONFIG_SND_AT91_SOC_ETI_SLAVE */
+	/*
+	 * Codec in Master Mode.
+	 */
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+#endif /* CONFIG_SND_AT91_SOC_ETI_SLAVE */
+
+	return 0;
+}
+
+static struct snd_soc_ops eti_b1_ops = {
+	.startup = eti_b1_startup,
+	.hw_params = eti_b1_hw_params,
+	.shutdown = eti_b1_shutdown,
+};
+
+
+static const struct snd_soc_dapm_widget eti_b1_dapm_widgets[] = {
+	SND_SOC_DAPM_MIC("Int Mic", NULL),
+	SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static const char *intercon[][3] = {
+
+	/* speaker connected to LHPOUT */
+	{"Ext Spk", NULL, "LHPOUT"},
+
+	/* mic is connected to Mic Jack, with WM8731 Mic Bias */
+	{"MICIN", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Int Mic"},
+
+	/* terminator */
+	{NULL, NULL, NULL},
+};
+
+/*
+ * Logic for a wm8731 as connected on a Endrelia ETI-B1 board.
+ */
+static int eti_b1_wm8731_init(struct snd_soc_codec *codec)
+{
+	int i;
+
+	DBG("eti_b1_wm8731_init() called\n");
+
+	/* Add specific widgets */
+	for(i = 0; i < ARRAY_SIZE(eti_b1_dapm_widgets); i++) {
+		snd_soc_dapm_new_control(codec, &eti_b1_dapm_widgets[i]);
+	}
+
+	/* Set up specific audio path interconnects */
+	for(i = 0; intercon[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, intercon[i][0],
+			intercon[i][1], intercon[i][2]);
+	}
+
+	/* not connected */
+	snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0);
+	snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0);
+
+	/* always connected */
+	snd_soc_dapm_set_endpoint(codec, "Int Mic", 1);
+	snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1);
+
+	snd_soc_dapm_sync_endpoints(codec);
+
+	return 0;
+}
+
+static struct snd_soc_dai_link eti_b1_dai = {
+	.name = "WM8731",
+	.stream_name = "WM8731",
+	.cpu_dai = &at91_i2s_dai[1],
+	.codec_dai = &wm8731_dai,
+	.init = eti_b1_wm8731_init,
+	.ops = &eti_b1_ops,
+};
+
+static struct snd_soc_machine snd_soc_machine_eti_b1 = {
+	.name = "ETI_B1",
+	.dai_link = &eti_b1_dai,
+	.num_links = 1,
+};
+
+static struct wm8731_setup_data eti_b1_wm8731_setup = {
+	.i2c_address = 0x1a,
+};
+
+static struct snd_soc_device eti_b1_snd_devdata = {
+	.machine = &snd_soc_machine_eti_b1,
+	.platform = &at91_soc_platform,
+	.codec_dev = &soc_codec_dev_wm8731,
+	.codec_data = &eti_b1_wm8731_setup,
+};
+
+static struct platform_device *eti_b1_snd_device;
+
+static int __init eti_b1_init(void)
+{
+	int ret;
+	u32 ssc_pio_lines;
+	struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
+
+	if (!request_mem_region(AT91RM9200_BASE_SSC1, SZ_16K, "soc-audio")) {
+		DBG("SSC1 memory region is busy\n");
+		return -EBUSY;
+	}
+
+	ssc->base = ioremap(AT91RM9200_BASE_SSC1, SZ_16K);
+	if (!ssc->base) {
+		DBG("SSC1 memory ioremap failed\n");
+		ret = -ENOMEM;
+		goto fail_release_mem;
+	}
+
+	ssc->pid = AT91RM9200_ID_SSC1;
+
+	eti_b1_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!eti_b1_snd_device) {
+		DBG("platform device allocation failed\n");
+		ret = -ENOMEM;
+		goto fail_io_unmap;
+	}
+
+	platform_set_drvdata(eti_b1_snd_device, &eti_b1_snd_devdata);
+	eti_b1_snd_devdata.dev = &eti_b1_snd_device->dev;
+
+	ret = platform_device_add(eti_b1_snd_device);
+	if (ret) {
+		DBG("platform device add failed\n");
+		platform_device_put(eti_b1_snd_device);
+		goto fail_io_unmap;
+	}
+
+ 	ssc_pio_lines = AT91_PIO_TF1 | AT91_PIO_TK1 | AT91_PIO_TD1
+			| AT91_PIO_RD1 /* | AT91_PIO_RK1 */ | AT91_PIO_RF1;
+
+	/* Reset all PIO registers and assign lines to peripheral A */
+ 	at91_sys_write(AT91_PIOB + PIO_PDR,  ssc_pio_lines);
+ 	at91_sys_write(AT91_PIOB + PIO_ODR,  ssc_pio_lines);
+ 	at91_sys_write(AT91_PIOB + PIO_IFDR, ssc_pio_lines);
+ 	at91_sys_write(AT91_PIOB + PIO_CODR, ssc_pio_lines);
+ 	at91_sys_write(AT91_PIOB + PIO_IDR,  ssc_pio_lines);
+ 	at91_sys_write(AT91_PIOB + PIO_MDDR, ssc_pio_lines);
+ 	at91_sys_write(AT91_PIOB + PIO_PUDR, ssc_pio_lines);
+ 	at91_sys_write(AT91_PIOB + PIO_ASR,  ssc_pio_lines);
+ 	at91_sys_write(AT91_PIOB + PIO_OWDR, ssc_pio_lines);
+
+	/*
+	 * Set PCK1 parent to PLLB and its rate to 12 Mhz.
+	 */
+	pllb_clk = clk_get(NULL, "pllb");
+	pck1_clk = clk_get(NULL, "pck1");
+
+	clk_set_parent(pck1_clk, pllb_clk);
+	clk_set_rate(pck1_clk, 12000000);
+
+	DBG("MCLK rate %luHz\n", clk_get_rate(pck1_clk));
+
+	/* assign the GPIO pin to PCK1 */
+	at91_set_B_periph(AT91_PIN_PA24, 0);
+
+#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
+	printk(KERN_INFO "eti_b1_wm8731: Codec in Slave Mode\n");
+#else
+	printk(KERN_INFO "eti_b1_wm8731: Codec in Master Mode\n");
+#endif
+	return ret;
+
+fail_io_unmap:
+	iounmap(ssc->base);
+fail_release_mem:
+	release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
+	return ret;
+}
+
+static void __exit eti_b1_exit(void)
+{
+	struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
+
+	clk_put(pck1_clk);
+	clk_put(pllb_clk);
+
+	platform_device_unregister(eti_b1_snd_device);
+
+	iounmap(ssc->base);
+	release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
+}
+
+module_init(eti_b1_init);
+module_exit(eti_b1_exit);
+
+/* Module information */
+MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>");
+MODULE_DESCRIPTION("ALSA SoC ETI-B1-WM8731");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
new file mode 100644
index 0000000..78ac268
--- /dev/null
+++ b/sound/soc/codecs/Kconfig
@@ -0,0 +1,15 @@
+config SND_SOC_AC97_CODEC
+	tristate
+	depends SND_SOC
+
+config SND_SOC_WM8731
+	tristate
+	depends SND_SOC
+
+config SND_SOC_WM8750
+	tristate
+	depends SND_SOC
+
+config SND_SOC_WM9712
+	tristate
+	depends SND_SOC
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
new file mode 100644
index 0000000..3249a6e
--- /dev/null
+++ b/sound/soc/codecs/Makefile
@@ -0,0 +1,9 @@
+snd-soc-ac97-objs := ac97.o
+snd-soc-wm8731-objs := wm8731.o
+snd-soc-wm8750-objs := wm8750.o
+snd-soc-wm9712-objs := wm9712.o
+
+obj-$(CONFIG_SND_SOC_AC97_CODEC)	+= snd-soc-ac97.o
+obj-$(CONFIG_SND_SOC_WM8731)	+= snd-soc-wm8731.o
+obj-$(CONFIG_SND_SOC_WM8750)	+= snd-soc-wm8750.o
+obj-$(CONFIG_SND_SOC_WM9712)	+= snd-soc-wm9712.o
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
new file mode 100644
index 0000000..55bc55e
--- /dev/null
+++ b/sound/soc/codecs/ac97.c
@@ -0,0 +1,156 @@
+/*
+ * ac97.c  --  ALSA Soc AC97 codec support
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    17th Oct 2005   Initial version.
+ *
+ * Generic AC97 support.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#define AC97_VERSION "0.6"
+
+static int ac97_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+
+	int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+		  AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
+	return snd_ac97_set_rate(codec->ac97, reg, runtime->rate);
+}
+
+#define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+static struct snd_soc_codec_dai ac97_dai = {
+	.name = "AC97 HiFi",
+	.playback = {
+		.stream_name = "AC97 Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = STD_AC97_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.capture = {
+		.stream_name = "AC97 Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = STD_AC97_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = {
+		.prepare = ac97_prepare,},
+};
+
+static unsigned int ac97_read(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	return soc_ac97_ops.read(codec->ac97, reg);
+}
+
+static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int val)
+{
+	soc_ac97_ops.write(codec->ac97, reg, val);
+	return 0;
+}
+
+static int ac97_soc_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	struct snd_ac97_bus *ac97_bus;
+	struct snd_ac97_template ac97_template;
+	int ret = 0;
+
+	printk(KERN_INFO "AC97 SoC Audio Codec %s\n", AC97_VERSION);
+
+	socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (socdev->codec == NULL)
+		return -ENOMEM;
+	codec = socdev->codec;
+	mutex_init(&codec->mutex);
+
+	codec->name = "AC97";
+	codec->owner = THIS_MODULE;
+	codec->dai = &ac97_dai;
+	codec->num_dai = 1;
+	codec->write = ac97_write;
+	codec->read = ac97_read;
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if(ret < 0)
+		goto err;
+
+	/* add codec as bus device for standard ac97 */
+	ret = snd_ac97_bus(codec->card, 0, &soc_ac97_ops, NULL, &ac97_bus);
+	if(ret < 0)
+		goto bus_err;
+
+	memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
+	ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97);
+	if(ret < 0)
+		goto bus_err;
+
+	ret = snd_soc_register_card(socdev);
+	if (ret < 0)
+		goto bus_err;
+	return 0;
+
+bus_err:
+	snd_soc_free_pcms(socdev);
+
+err:
+	kfree(socdev->codec->reg_cache);
+	kfree(socdev->codec);
+	socdev->codec = NULL;
+	return ret;
+}
+
+static int ac97_soc_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	if(codec == NULL)
+		return 0;
+
+	snd_soc_free_pcms(socdev);
+	kfree(socdev->codec->reg_cache);
+	kfree(socdev->codec);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_ac97= {
+	.probe = 	ac97_soc_probe,
+	.remove = 	ac97_soc_remove,
+};
+
+EXPORT_SYMBOL_GPL(soc_codec_dev_ac97);
+
+MODULE_DESCRIPTION("Soc Generic AC97 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ac97.h b/sound/soc/codecs/ac97.h
new file mode 100644
index 0000000..930ddfc
--- /dev/null
+++ b/sound/soc/codecs/ac97.h
@@ -0,0 +1,18 @@
+/*
+ * linux/sound/codecs/ac97.h -- ALSA SoC Layer
+ *
+ * Author:		Liam Girdwood
+ * Created:		Dec 1st 2005
+ * Copyright:	Wolfson Microelectronics. PLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_SOC_AC97_H
+#define __LINUX_SND_SOC_AC97_H
+
+extern struct snd_soc_codec_device soc_codec_dev_ac97;
+
+#endif
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
new file mode 100644
index 0000000..7ca0b52
--- /dev/null
+++ b/sound/soc/codecs/wm8731.c
@@ -0,0 +1,758 @@
+/*
+ * wm8731.c  --  WM8731 ALSA SoC Audio driver
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on wm8753.c by Liam Girdwood
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wm8731.h"
+
+#define AUDIO_NAME "wm8731"
+#define WM8731_VERSION "0.13"
+
+/*
+ * Debug
+ */
+
+#define WM8731_DEBUG 0
+
+#ifdef WM8731_DEBUG
+#define dbg(format, arg...) \
+	printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+#define err(format, arg...) \
+	printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg)
+#define info(format, arg...) \
+	printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg)
+#define warn(format, arg...) \
+	printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg)
+
+struct snd_soc_codec_device soc_codec_dev_wm8731;
+
+/* codec private data */
+struct wm8731_priv {
+	unsigned int sysclk;
+};
+
+/*
+ * wm8731 register cache
+ * We can't read the WM8731 register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ * There is no point in caching the reset register
+ */
+static const u16 wm8731_reg[WM8731_CACHEREGNUM] = {
+    0x0097, 0x0097, 0x0079, 0x0079,
+    0x000a, 0x0008, 0x009f, 0x000a,
+    0x0000, 0x0000
+};
+
+/*
+ * read wm8731 register cache
+ */
+static inline unsigned int wm8731_read_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg == WM8731_RESET)
+		return 0;
+	if (reg >= WM8731_CACHEREGNUM)
+		return -1;
+	return cache[reg];
+}
+
+/*
+ * write wm8731 register cache
+ */
+static inline void wm8731_write_reg_cache(struct snd_soc_codec *codec,
+	u16 reg, unsigned int value)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg >= WM8731_CACHEREGNUM)
+		return;
+	cache[reg] = value;
+}
+
+/*
+ * write to the WM8731 register space
+ */
+static int wm8731_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int value)
+{
+	u8 data[2];
+
+	/* data is
+	 *   D15..D9 WM8731 register offset
+	 *   D8...D0 register data
+	 */
+	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+	data[1] = value & 0x00ff;
+
+	wm8731_write_reg_cache (codec, reg, value);
+	if (codec->hw_write(codec->control_data, data, 2) == 2)
+		return 0;
+	else
+		return -EIO;
+}
+
+#define wm8731_reset(c)	wm8731_write(c, WM8731_RESET, 0)
+
+static const char *wm8731_input_select[] = {"Line In", "Mic"};
+static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+
+static const struct soc_enum wm8731_enum[] = {
+	SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select),
+	SOC_ENUM_SINGLE(WM8731_APDIGI, 1, 4, wm8731_deemph),
+};
+
+static const struct snd_kcontrol_new wm8731_snd_controls[] = {
+
+SOC_DOUBLE_R("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V,
+	0, 127, 0),
+SOC_DOUBLE_R("Master Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V,
+	7, 1, 0),
+
+SOC_DOUBLE_R("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0),
+SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1),
+
+SOC_SINGLE("Mic Boost (+20dB)", WM8731_APANA, 0, 1, 0),
+SOC_SINGLE("Capture Mic Switch", WM8731_APANA, 1, 1, 1),
+
+SOC_SINGLE("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1),
+
+SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1),
+SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0),
+
+SOC_ENUM("Playback De-emphasis", wm8731_enum[1]),
+};
+
+/* add non dapm controls */
+static int wm8731_add_controls(struct snd_soc_codec *codec)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8731_snd_controls); i++) {
+		if ((err = snd_ctl_add(codec->card,
+				snd_soc_cnew(&wm8731_snd_controls[i],codec, NULL))) < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+/* Output Mixer */
+static const struct snd_kcontrol_new wm8731_output_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0),
+SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0),
+SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0),
+};
+
+/* Input mux */
+static const struct snd_kcontrol_new wm8731_input_mux_controls =
+SOC_DAPM_ENUM("Input Select", wm8731_enum[0]);
+
+static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1,
+	&wm8731_output_mixer_controls[0],
+	ARRAY_SIZE(wm8731_output_mixer_controls)),
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8731_PWR, 3, 1),
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("LHPOUT"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_OUTPUT("RHPOUT"),
+SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8731_PWR, 2, 1),
+SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &wm8731_input_mux_controls),
+SND_SOC_DAPM_PGA("Line Input", WM8731_PWR, 0, 1, NULL, 0),
+SND_SOC_DAPM_MICBIAS("Mic Bias", WM8731_PWR, 1, 1),
+SND_SOC_DAPM_INPUT("MICIN"),
+SND_SOC_DAPM_INPUT("RLINEIN"),
+SND_SOC_DAPM_INPUT("LLINEIN"),
+};
+
+static const char *intercon[][3] = {
+	/* output mixer */
+	{"Output Mixer", "Line Bypass Switch", "Line Input"},
+	{"Output Mixer", "HiFi Playback Switch", "DAC"},
+	{"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
+
+	/* outputs */
+	{"RHPOUT", NULL, "Output Mixer"},
+	{"ROUT", NULL, "Output Mixer"},
+	{"LHPOUT", NULL, "Output Mixer"},
+	{"LOUT", NULL, "Output Mixer"},
+
+	/* input mux */
+	{"Input Mux", "Line In", "Line Input"},
+	{"Input Mux", "Mic", "Mic Bias"},
+	{"ADC", NULL, "Input Mux"},
+
+	/* inputs */
+	{"Line Input", NULL, "LLINEIN"},
+	{"Line Input", NULL, "RLINEIN"},
+	{"Mic Bias", NULL, "MICIN"},
+
+	/* terminator */
+	{NULL, NULL, NULL},
+};
+
+static int wm8731_add_widgets(struct snd_soc_codec *codec)
+{
+	int i;
+
+	for(i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) {
+		snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]);
+	}
+
+	/* set up audio path interconnects */
+	for(i = 0; intercon[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, intercon[i][0],
+			intercon[i][1], intercon[i][2]);
+	}
+
+	snd_soc_dapm_new_widgets(codec);
+	return 0;
+}
+
+struct _coeff_div {
+	u32 mclk;
+	u32 rate;
+	u16 fs;
+	u8 sr:4;
+	u8 bosr:1;
+	u8 usb:1;
+};
+
+/* codec mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+	/* 48k */
+	{12288000, 48000, 256, 0x0, 0x0, 0x0},
+	{18432000, 48000, 384, 0x0, 0x1, 0x0},
+	{12000000, 48000, 250, 0x0, 0x0, 0x1},
+
+	/* 32k */
+	{12288000, 32000, 384, 0x6, 0x0, 0x0},
+	{18432000, 32000, 576, 0x6, 0x1, 0x0},
+	{12000000, 32000, 375, 0x6, 0x0, 0x1},
+
+	/* 8k */
+	{12288000, 8000, 1536, 0x3, 0x0, 0x0},
+	{18432000, 8000, 2304, 0x3, 0x1, 0x0},
+	{11289600, 8000, 1408, 0xb, 0x0, 0x0},
+	{16934400, 8000, 2112, 0xb, 0x1, 0x0},
+	{12000000, 8000, 1500, 0x3, 0x0, 0x1},
+
+	/* 96k */
+	{12288000, 96000, 128, 0x7, 0x0, 0x0},
+	{18432000, 96000, 192, 0x7, 0x1, 0x0},
+	{12000000, 96000, 125, 0x7, 0x0, 0x1},
+
+	/* 44.1k */
+	{11289600, 44100, 256, 0x8, 0x0, 0x0},
+	{16934400, 44100, 384, 0x8, 0x1, 0x0},
+	{12000000, 44100, 272, 0x8, 0x1, 0x1},
+
+	/* 88.2k */
+	{11289600, 88200, 128, 0xf, 0x0, 0x0},
+	{16934400, 88200, 192, 0xf, 0x1, 0x0},
+	{12000000, 88200, 136, 0xf, 0x1, 0x1},
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+	return 0;
+}
+
+static int wm8731_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	struct wm8731_priv *wm8731 = codec->private_data;
+	u16 iface = wm8731_read_reg_cache(codec, WM8731_IFACE) & 0xfff3;
+	int i = get_coeff(wm8731->sysclk, params_rate(params));
+	u16 srate = (coeff_div[i].sr << 2) |
+		(coeff_div[i].bosr << 1) | coeff_div[i].usb;
+
+	wm8731_write(codec, WM8731_SRATE, srate);
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		iface |= 0x0004;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		iface |= 0x0008;
+		break;
+	}
+
+	wm8731_write(codec, WM8731_IFACE, iface);
+	return 0;
+}
+
+static int wm8731_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+
+	/* set active */
+	wm8731_write(codec, WM8731_ACTIVE, 0x0001);
+
+	return 0;
+}
+
+static void wm8731_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+
+	/* deactivate */
+	if (!codec->active) {
+		udelay(50);
+		wm8731_write(codec, WM8731_ACTIVE, 0x0);
+	}
+}
+
+static int wm8731_mute(struct snd_soc_codec_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7;
+
+	if (mute)
+		wm8731_write(codec, WM8731_APDIGI, mute_reg | 0x8);
+	else
+		wm8731_write(codec, WM8731_APDIGI, mute_reg);
+	return 0;
+}
+
+static int wm8731_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct wm8731_priv *wm8731 = codec->private_data;
+
+	switch (freq) {
+	case 11289600:
+	case 12000000:
+	case 12288000:
+	case 16934400:
+	case 18432000:
+		wm8731->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+
+static int wm8731_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface |= 0x0040;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x0013;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0090;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0010;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set iface */
+	wm8731_write(codec, WM8731_IFACE, iface);
+	return 0;
+}
+
+static int wm8731_dapm_event(struct snd_soc_codec *codec, int event)
+{
+	u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f;
+
+	switch (event) {
+	case SNDRV_CTL_POWER_D0: /* full On */
+		/* vref/mid, osc on, dac unmute */
+		wm8731_write(codec, WM8731_PWR, reg);
+		break;
+	case SNDRV_CTL_POWER_D1: /* partial On */
+	case SNDRV_CTL_POWER_D2: /* partial On */
+		break;
+	case SNDRV_CTL_POWER_D3hot: /* Off, with power */
+		/* everything off except vref/vmid, */
+		wm8731_write(codec, WM8731_PWR, reg | 0x0040);
+		break;
+	case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+		/* everything off, dac mute, inactive */
+		wm8731_write(codec, WM8731_ACTIVE, 0x0);
+		wm8731_write(codec, WM8731_PWR, 0xffff);
+		break;
+	}
+	codec->dapm_state = event;
+	return 0;
+}
+
+#define WM8731_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
+		SNDRV_PCM_RATE_96000)
+
+#define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+struct snd_soc_codec_dai wm8731_dai = {
+	.name = "WM8731",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8731_RATES,
+		.formats = WM8731_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8731_RATES,
+		.formats = WM8731_FORMATS,},
+	.ops = {
+		.prepare = wm8731_pcm_prepare,
+		.hw_params = wm8731_hw_params,
+		.shutdown = wm8731_shutdown,
+	},
+	.dai_ops = {
+		.digital_mute = wm8731_mute,
+		.set_sysclk = wm8731_set_dai_sysclk,
+		.set_fmt = wm8731_set_dai_fmt,
+	}
+};
+EXPORT_SYMBOL_GPL(wm8731_dai);
+
+static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	wm8731_write(codec, WM8731_ACTIVE, 0x0);
+	wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+	return 0;
+}
+
+static int wm8731_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+	int i;
+	u8 data[2];
+	u16 *cache = codec->reg_cache;
+
+	/* Sync reg_cache with the hardware */
+	for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) {
+		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+		data[1] = cache[i] & 0x00ff;
+		codec->hw_write(codec->control_data, data, 2);
+	}
+	wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+	wm8731_dapm_event(codec, codec->suspend_dapm_state);
+	return 0;
+}
+
+/*
+ * initialise the WM8731 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int wm8731_init(struct snd_soc_device *socdev)
+{
+	struct snd_soc_codec *codec = socdev->codec;
+	int reg, ret = 0;
+
+	codec->name = "WM8731";
+	codec->owner = THIS_MODULE;
+	codec->read = wm8731_read_reg_cache;
+	codec->write = wm8731_write;
+	codec->dapm_event = wm8731_dapm_event;
+	codec->dai = &wm8731_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = sizeof(wm8731_reg);
+	codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL);
+	if (codec->reg_cache == NULL)
+		return -ENOMEM;
+
+	wm8731_reset(codec);
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8731: failed to create pcms\n");
+		goto pcm_err;
+	}
+
+	/* power on device */
+	wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+
+	/* set the update bits */
+	reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V);
+	wm8731_write(codec, WM8731_LOUT1V, reg | 0x0100);
+	reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V);
+	wm8731_write(codec, WM8731_ROUT1V, reg | 0x0100);
+	reg = wm8731_read_reg_cache(codec, WM8731_LINVOL);
+	wm8731_write(codec, WM8731_LINVOL, reg | 0x0100);
+	reg = wm8731_read_reg_cache(codec, WM8731_RINVOL);
+	wm8731_write(codec, WM8731_RINVOL, reg | 0x0100);
+
+	wm8731_add_controls(codec);
+	wm8731_add_widgets(codec);
+	ret = snd_soc_register_card(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8731: failed to register card\n");
+		goto card_err;
+	}
+
+	return ret;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+pcm_err:
+	kfree(codec->reg_cache);
+	return ret;
+}
+
+static struct snd_soc_device *wm8731_socdev;
+
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+
+/*
+ * WM8731 2 wire address is determined by GPIO5
+ * state during powerup.
+ *    low  = 0x1a
+ *    high = 0x1b
+ */
+static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver wm8731_i2c_driver;
+static struct i2c_client client_template;
+
+/* If the i2c layer weren't so broken, we could pass this kind of data
+   around */
+
+static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+	struct snd_soc_device *socdev = wm8731_socdev;
+	struct wm8731_setup_data *setup = socdev->codec_data;
+	struct snd_soc_codec *codec = socdev->codec;
+	struct i2c_client *i2c;
+	int ret;
+
+	if (addr != setup->i2c_address)
+		return -ENODEV;
+
+	client_template.adapter = adap;
+	client_template.addr = addr;
+
+	i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+	if (i2c == NULL) {
+		kfree(codec);
+		return -ENOMEM;
+	}
+	i2c_set_clientdata(i2c, codec);
+	codec->control_data = i2c;
+
+	ret = i2c_attach_client(i2c);
+	if (ret < 0) {
+		err("failed to attach codec at addr %x\n", addr);
+		goto err;
+	}
+
+	ret = wm8731_init(socdev);
+	if (ret < 0) {
+		err("failed to initialise WM8731\n");
+		goto err;
+	}
+	return ret;
+
+err:
+	kfree(codec);
+	kfree(i2c);
+	return ret;
+}
+
+static int wm8731_i2c_detach(struct i2c_client *client)
+{
+	struct snd_soc_codec* codec = i2c_get_clientdata(client);
+	i2c_detach_client(client);
+	kfree(codec->reg_cache);
+	kfree(client);
+	return 0;
+}
+
+static int wm8731_i2c_attach(struct i2c_adapter *adap)
+{
+	return i2c_probe(adap, &addr_data, wm8731_codec_probe);
+}
+
+/* corgi i2c codec control layer */
+static struct i2c_driver wm8731_i2c_driver = {
+	.driver = {
+		.name = "WM8731 I2C Codec",
+		.owner = THIS_MODULE,
+	},
+	.id =             I2C_DRIVERID_WM8731,
+	.attach_adapter = wm8731_i2c_attach,
+	.detach_client =  wm8731_i2c_detach,
+	.command =        NULL,
+};
+
+static struct i2c_client client_template = {
+	.name =   "WM8731",
+	.driver = &wm8731_i2c_driver,
+};
+#endif
+
+static int wm8731_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct wm8731_setup_data *setup;
+	struct snd_soc_codec *codec;
+	struct wm8731_priv *wm8731;
+	int ret = 0;
+
+	info("WM8731 Audio Codec %s", WM8731_VERSION);
+
+	setup = socdev->codec_data;
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		return -ENOMEM;
+
+	wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
+	if (wm8731 == NULL) {
+		kfree(codec);
+		return -ENOMEM;
+	}
+
+	codec->private_data = wm8731;
+	socdev->codec = codec;
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	wm8731_socdev = socdev;
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+	if (setup->i2c_address) {
+		normal_i2c[0] = setup->i2c_address;
+		codec->hw_write = (hw_write_t)i2c_master_send;
+		ret = i2c_add_driver(&wm8731_i2c_driver);
+		if (ret != 0)
+			printk(KERN_ERR "can't add i2c driver");
+	}
+#else
+	/* Add other interfaces here */
+#endif
+	return ret;
+}
+
+/* power down chip */
+static int wm8731_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	if (codec->control_data)
+		wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+	i2c_del_driver(&wm8731_i2c_driver);
+#endif
+	kfree(codec->private_data);
+	kfree(codec);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8731 = {
+	.probe = 	wm8731_probe,
+	.remove = 	wm8731_remove,
+	.suspend = 	wm8731_suspend,
+	.resume =	wm8731_resume,
+};
+
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
+
+MODULE_DESCRIPTION("ASoC WM8731 driver");
+MODULE_AUTHOR("Richard Purdie");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h
new file mode 100644
index 0000000..5bcab6a
--- /dev/null
+++ b/sound/soc/codecs/wm8731.h
@@ -0,0 +1,44 @@
+/*
+ * wm8731.h  --  WM8731 Soc Audio driver
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on wm8753.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8731_H
+#define _WM8731_H
+
+/* WM8731 register space */
+
+#define WM8731_LINVOL   0x00
+#define WM8731_RINVOL   0x01
+#define WM8731_LOUT1V   0x02
+#define WM8731_ROUT1V   0x03
+#define WM8731_APANA    0x04
+#define WM8731_APDIGI   0x05
+#define WM8731_PWR      0x06
+#define WM8731_IFACE    0x07
+#define WM8731_SRATE    0x08
+#define WM8731_ACTIVE   0x09
+#define WM8731_RESET	0x0f
+
+#define WM8731_CACHEREGNUM 	10
+
+#define WM8731_SYSCLK	0
+#define WM8731_DAI		0
+
+struct wm8731_setup_data {
+	unsigned short i2c_address;
+};
+
+extern struct snd_soc_codec_dai wm8731_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8731;
+
+#endif
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
new file mode 100644
index 0000000..7073e8e
--- /dev/null
+++ b/sound/soc/codecs/wm8750.c
@@ -0,0 +1,1049 @@
+/*
+ * wm8750.c -- WM8750 ALSA SoC audio driver
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on WM8753.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wm8750.h"
+
+#define AUDIO_NAME "WM8750"
+#define WM8750_VERSION "0.12"
+
+/*
+ * Debug
+ */
+
+#define WM8750_DEBUG 0
+
+#ifdef WM8750_DEBUG
+#define dbg(format, arg...) \
+	printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+#define err(format, arg...) \
+	printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg)
+#define info(format, arg...) \
+	printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg)
+#define warn(format, arg...) \
+	printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg)
+
+/* codec private data */
+struct wm8750_priv {
+	unsigned int sysclk;
+};
+
+/*
+ * wm8750 register cache
+ * We can't read the WM8750 register space when we
+ * are using 2 wire for device control, so we cache them instead.
+ */
+static const u16 wm8750_reg[] = {
+	0x0097, 0x0097, 0x0079, 0x0079,  /*  0 */
+	0x0000, 0x0008, 0x0000, 0x000a,  /*  4 */
+	0x0000, 0x0000, 0x00ff, 0x00ff,  /*  8 */
+	0x000f, 0x000f, 0x0000, 0x0000,  /* 12 */
+	0x0000, 0x007b, 0x0000, 0x0032,  /* 16 */
+	0x0000, 0x00c3, 0x00c3, 0x00c0,  /* 20 */
+	0x0000, 0x0000, 0x0000, 0x0000,  /* 24 */
+	0x0000, 0x0000, 0x0000, 0x0000,  /* 28 */
+	0x0000, 0x0000, 0x0050, 0x0050,  /* 32 */
+	0x0050, 0x0050, 0x0050, 0x0050,  /* 36 */
+	0x0079, 0x0079, 0x0079,          /* 40 */
+};
+
+/*
+ * read wm8750 register cache
+ */
+static inline unsigned int wm8750_read_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg > WM8750_CACHE_REGNUM)
+		return -1;
+	return cache[reg];
+}
+
+/*
+ * write wm8750 register cache
+ */
+static inline void wm8750_write_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg, unsigned int value)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg > WM8750_CACHE_REGNUM)
+		return;
+	cache[reg] = value;
+}
+
+static int wm8750_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int value)
+{
+	u8 data[2];
+
+	/* data is
+	 *   D15..D9 WM8753 register offset
+	 *   D8...D0 register data
+	 */
+	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+	data[1] = value & 0x00ff;
+
+	wm8750_write_reg_cache (codec, reg, value);
+	if (codec->hw_write(codec->control_data, data, 2) == 2)
+		return 0;
+	else
+		return -EIO;
+}
+
+#define wm8750_reset(c)	wm8750_write(c, WM8750_RESET, 0)
+
+/*
+ * WM8750 Controls
+ */
+static const char *wm8750_bass[] = {"Linear Control", "Adaptive Boost"};
+static const char *wm8750_bass_filter[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" };
+static const char *wm8750_treble[] = {"8kHz", "4kHz"};
+static const char *wm8750_3d_lc[] = {"200Hz", "500Hz"};
+static const char *wm8750_3d_uc[] = {"2.2kHz", "1.5kHz"};
+static const char *wm8750_3d_func[] = {"Capture", "Playback"};
+static const char *wm8750_alc_func[] = {"Off", "Right", "Left", "Stereo"};
+static const char *wm8750_ng_type[] = {"Constant PGA Gain",
+	"Mute ADC Output"};
+static const char *wm8750_line_mux[] = {"Line 1", "Line 2", "Line 3", "PGA",
+	"Differential"};
+static const char *wm8750_pga_sel[] = {"Line 1", "Line 2", "Line 3",
+	"Differential"};
+static const char *wm8750_out3[] = {"VREF", "ROUT1 + Vol", "MonoOut",
+	"ROUT1"};
+static const char *wm8750_diff_sel[] = {"Line 1", "Line 2"};
+static const char *wm8750_adcpol[] = {"Normal", "L Invert", "R Invert",
+	"L + R Invert"};
+static const char *wm8750_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+static const char *wm8750_mono_mux[] = {"Stereo", "Mono (Left)",
+	"Mono (Right)", "Digital Mono"};
+
+static const struct soc_enum wm8750_enum[] = {
+SOC_ENUM_SINGLE(WM8750_BASS, 7, 2, wm8750_bass),
+SOC_ENUM_SINGLE(WM8750_BASS, 6, 2, wm8750_bass_filter),
+SOC_ENUM_SINGLE(WM8750_TREBLE, 6, 2, wm8750_treble),
+SOC_ENUM_SINGLE(WM8750_3D, 5, 2, wm8750_3d_lc),
+SOC_ENUM_SINGLE(WM8750_3D, 6, 2, wm8750_3d_uc),
+SOC_ENUM_SINGLE(WM8750_3D, 7, 2, wm8750_3d_func),
+SOC_ENUM_SINGLE(WM8750_ALC1, 7, 4, wm8750_alc_func),
+SOC_ENUM_SINGLE(WM8750_NGATE, 1, 2, wm8750_ng_type),
+SOC_ENUM_SINGLE(WM8750_LOUTM1, 0, 5, wm8750_line_mux),
+SOC_ENUM_SINGLE(WM8750_ROUTM1, 0, 5, wm8750_line_mux),
+SOC_ENUM_SINGLE(WM8750_LADCIN, 6, 4, wm8750_pga_sel), /* 10 */
+SOC_ENUM_SINGLE(WM8750_RADCIN, 6, 4, wm8750_pga_sel),
+SOC_ENUM_SINGLE(WM8750_ADCTL2, 7, 4, wm8750_out3),
+SOC_ENUM_SINGLE(WM8750_ADCIN, 8, 2, wm8750_diff_sel),
+SOC_ENUM_SINGLE(WM8750_ADCDAC, 5, 4, wm8750_adcpol),
+SOC_ENUM_SINGLE(WM8750_ADCDAC, 1, 4, wm8750_deemph),
+SOC_ENUM_SINGLE(WM8750_ADCIN, 6, 4, wm8750_mono_mux), /* 16 */
+
+};
+
+static const struct snd_kcontrol_new wm8750_snd_controls[] = {
+
+SOC_DOUBLE_R("Capture Volume", WM8750_LINVOL, WM8750_RINVOL, 0, 63, 0),
+SOC_DOUBLE_R("Capture ZC Switch", WM8750_LINVOL, WM8750_RINVOL, 6, 1, 0),
+SOC_DOUBLE_R("Capture Switch", WM8750_LINVOL, WM8750_RINVOL, 7, 1, 1),
+
+SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8750_LOUT1V,
+	WM8750_ROUT1V, 7, 1, 0),
+SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8750_LOUT2V,
+	WM8750_ROUT2V, 7, 1, 0),
+
+SOC_ENUM("Playback De-emphasis", wm8750_enum[15]),
+
+SOC_ENUM("Capture Polarity", wm8750_enum[14]),
+SOC_SINGLE("Playback 6dB Attenuate", WM8750_ADCDAC, 7, 1, 0),
+SOC_SINGLE("Capture 6dB Attenuate", WM8750_ADCDAC, 8, 1, 0),
+
+SOC_DOUBLE_R("PCM Volume", WM8750_LDAC, WM8750_RDAC, 0, 255, 0),
+
+SOC_ENUM("Bass Boost", wm8750_enum[0]),
+SOC_ENUM("Bass Filter", wm8750_enum[1]),
+SOC_SINGLE("Bass Volume", WM8750_BASS, 0, 15, 1),
+
+SOC_SINGLE("Treble Volume", WM8750_TREBLE, 0, 15, 0),
+SOC_ENUM("Treble Cut-off", wm8750_enum[2]),
+
+SOC_SINGLE("3D Switch", WM8750_3D, 0, 1, 0),
+SOC_SINGLE("3D Volume", WM8750_3D, 1, 15, 0),
+SOC_ENUM("3D Lower Cut-off", wm8750_enum[3]),
+SOC_ENUM("3D Upper Cut-off", wm8750_enum[4]),
+SOC_ENUM("3D Mode", wm8750_enum[5]),
+
+SOC_SINGLE("ALC Capture Target Volume", WM8750_ALC1, 0, 7, 0),
+SOC_SINGLE("ALC Capture Max Volume", WM8750_ALC1, 4, 7, 0),
+SOC_ENUM("ALC Capture Function", wm8750_enum[6]),
+SOC_SINGLE("ALC Capture ZC Switch", WM8750_ALC2, 7, 1, 0),
+SOC_SINGLE("ALC Capture Hold Time", WM8750_ALC2, 0, 15, 0),
+SOC_SINGLE("ALC Capture Decay Time", WM8750_ALC3, 4, 15, 0),
+SOC_SINGLE("ALC Capture Attack Time", WM8750_ALC3, 0, 15, 0),
+SOC_SINGLE("ALC Capture NG Threshold", WM8750_NGATE, 3, 31, 0),
+SOC_ENUM("ALC Capture NG Type", wm8750_enum[4]),
+SOC_SINGLE("ALC Capture NG Switch", WM8750_NGATE, 0, 1, 0),
+
+SOC_SINGLE("Left ADC Capture Volume", WM8750_LADC, 0, 255, 0),
+SOC_SINGLE("Right ADC Capture Volume", WM8750_RADC, 0, 255, 0),
+
+SOC_SINGLE("ZC Timeout Switch", WM8750_ADCTL1, 0, 1, 0),
+SOC_SINGLE("Playback Invert Switch", WM8750_ADCTL1, 1, 1, 0),
+
+SOC_SINGLE("Right Speaker Playback Invert Switch", WM8750_ADCTL2, 4, 1, 0),
+
+/* Unimplemented */
+/* ADCDAC Bit 0 - ADCHPD */
+/* ADCDAC Bit 4 - HPOR */
+/* ADCTL1 Bit 2,3 - DATSEL */
+/* ADCTL1 Bit 4,5 - DMONOMIX */
+/* ADCTL1 Bit 6,7 - VSEL */
+/* ADCTL2 Bit 2 - LRCM */
+/* ADCTL2 Bit 3 - TRI */
+/* ADCTL3 Bit 5 - HPFLREN */
+/* ADCTL3 Bit 6 - VROI */
+/* ADCTL3 Bit 7,8 - ADCLRM */
+/* ADCIN Bit 4 - LDCM */
+/* ADCIN Bit 5 - RDCM */
+
+SOC_DOUBLE_R("Mic Boost", WM8750_LADCIN, WM8750_RADCIN, 4, 3, 0),
+
+SOC_DOUBLE_R("Bypass Left Playback Volume", WM8750_LOUTM1,
+	WM8750_LOUTM2, 4, 7, 1),
+SOC_DOUBLE_R("Bypass Right Playback Volume", WM8750_ROUTM1,
+	WM8750_ROUTM2, 4, 7, 1),
+SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8750_MOUTM1,
+	WM8750_MOUTM2, 4, 7, 1),
+
+SOC_SINGLE("Mono Playback ZC Switch", WM8750_MOUTV, 7, 1, 0),
+
+SOC_DOUBLE_R("Headphone Playback Volume", WM8750_LOUT1V, WM8750_ROUT1V,
+	0, 127, 0),
+SOC_DOUBLE_R("Speaker Playback Volume", WM8750_LOUT2V, WM8750_ROUT2V,
+	0, 127, 0),
+
+SOC_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0),
+
+};
+
+/* add non dapm controls */
+static int wm8750_add_controls(struct snd_soc_codec *codec)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8750_snd_controls); i++) {
+		err = snd_ctl_add(codec->card,
+				snd_soc_cnew(&wm8750_snd_controls[i],codec, NULL));
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+/*
+ * DAPM Controls
+ */
+
+/* Left Mixer */
+static const struct snd_kcontrol_new wm8750_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("Playback Switch", WM8750_LOUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_LOUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8750_LOUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_LOUTM2, 7, 1, 0),
+};
+
+/* Right Mixer */
+static const struct snd_kcontrol_new wm8750_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8750_ROUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_ROUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Playback Switch", WM8750_ROUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_ROUTM2, 7, 1, 0),
+};
+
+/* Mono Mixer */
+static const struct snd_kcontrol_new wm8750_mono_mixer_controls[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8750_MOUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_MOUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8750_MOUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_MOUTM2, 7, 1, 0),
+};
+
+/* Left Line Mux */
+static const struct snd_kcontrol_new wm8750_left_line_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[8]);
+
+/* Right Line Mux */
+static const struct snd_kcontrol_new wm8750_right_line_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[9]);
+
+/* Left PGA Mux */
+static const struct snd_kcontrol_new wm8750_left_pga_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[10]);
+
+/* Right PGA Mux */
+static const struct snd_kcontrol_new wm8750_right_pga_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[11]);
+
+/* Out 3 Mux */
+static const struct snd_kcontrol_new wm8750_out3_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[12]);
+
+/* Differential Mux */
+static const struct snd_kcontrol_new wm8750_diffmux_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[13]);
+
+/* Mono ADC Mux */
+static const struct snd_kcontrol_new wm8750_monomux_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[16]);
+
+static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
+	SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+		&wm8750_left_mixer_controls[0],
+		ARRAY_SIZE(wm8750_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+		&wm8750_right_mixer_controls[0],
+		ARRAY_SIZE(wm8750_right_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Mono Mixer", WM8750_PWR2, 2, 0,
+		&wm8750_mono_mixer_controls[0],
+		ARRAY_SIZE(wm8750_mono_mixer_controls)),
+
+	SND_SOC_DAPM_PGA("Right Out 2", WM8750_PWR2, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Left Out 2", WM8750_PWR2, 4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Out 1", WM8750_PWR2, 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Left Out 1", WM8750_PWR2, 6, 0, NULL, 0),
+	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8750_PWR2, 7, 0),
+	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8750_PWR2, 8, 0),
+
+	SND_SOC_DAPM_MICBIAS("Mic Bias", WM8750_PWR1, 1, 0),
+	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8750_PWR1, 2, 0),
+	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8750_PWR1, 3, 0),
+
+	SND_SOC_DAPM_MUX("Left PGA Mux", WM8750_PWR1, 5, 0,
+		&wm8750_left_pga_controls),
+	SND_SOC_DAPM_MUX("Right PGA Mux", WM8750_PWR1, 4, 0,
+		&wm8750_right_pga_controls),
+	SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
+		&wm8750_left_line_controls),
+	SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
+		&wm8750_right_line_controls),
+
+	SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8750_out3_controls),
+	SND_SOC_DAPM_PGA("Out 3", WM8750_PWR2, 1, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mono Out 1", WM8750_PWR2, 2, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
+		&wm8750_diffmux_controls),
+	SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
+		&wm8750_monomux_controls),
+	SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
+		&wm8750_monomux_controls),
+
+	SND_SOC_DAPM_OUTPUT("LOUT1"),
+	SND_SOC_DAPM_OUTPUT("ROUT1"),
+	SND_SOC_DAPM_OUTPUT("LOUT2"),
+	SND_SOC_DAPM_OUTPUT("ROUT2"),
+	SND_SOC_DAPM_OUTPUT("MONO"),
+	SND_SOC_DAPM_OUTPUT("OUT3"),
+
+	SND_SOC_DAPM_INPUT("LINPUT1"),
+	SND_SOC_DAPM_INPUT("LINPUT2"),
+	SND_SOC_DAPM_INPUT("LINPUT3"),
+	SND_SOC_DAPM_INPUT("RINPUT1"),
+	SND_SOC_DAPM_INPUT("RINPUT2"),
+	SND_SOC_DAPM_INPUT("RINPUT3"),
+};
+
+static const char *audio_map[][3] = {
+	/* left mixer */
+	{"Left Mixer", "Playback Switch", "Left DAC"},
+	{"Left Mixer", "Left Bypass Switch", "Left Line Mux"},
+	{"Left Mixer", "Right Playback Switch", "Right DAC"},
+	{"Left Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+	/* right mixer */
+	{"Right Mixer", "Left Playback Switch", "Left DAC"},
+	{"Right Mixer", "Left Bypass Switch", "Left Line Mux"},
+	{"Right Mixer", "Playback Switch", "Right DAC"},
+	{"Right Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+	/* left out 1 */
+	{"Left Out 1", NULL, "Left Mixer"},
+	{"LOUT1", NULL, "Left Out 1"},
+
+	/* left out 2 */
+	{"Left Out 2", NULL, "Left Mixer"},
+	{"LOUT2", NULL, "Left Out 2"},
+
+	/* right out 1 */
+	{"Right Out 1", NULL, "Right Mixer"},
+	{"ROUT1", NULL, "Right Out 1"},
+
+	/* right out 2 */
+	{"Right Out 2", NULL, "Right Mixer"},
+	{"ROUT2", NULL, "Right Out 2"},
+
+	/* mono mixer */
+	{"Mono Mixer", "Left Playback Switch", "Left DAC"},
+	{"Mono Mixer", "Left Bypass Switch", "Left Line Mux"},
+	{"Mono Mixer", "Right Playback Switch", "Right DAC"},
+	{"Mono Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+	/* mono out */
+	{"Mono Out 1", NULL, "Mono Mixer"},
+	{"MONO1", NULL, "Mono Out 1"},
+
+	/* out 3 */
+	{"Out3 Mux", "VREF", "VREF"},
+	{"Out3 Mux", "ROUT1 + Vol", "ROUT1"},
+	{"Out3 Mux", "ROUT1", "Right Mixer"},
+	{"Out3 Mux", "MonoOut", "MONO1"},
+	{"Out 3", NULL, "Out3 Mux"},
+	{"OUT3", NULL, "Out 3"},
+
+	/* Left Line Mux */
+	{"Left Line Mux", "Line 1", "LINPUT1"},
+	{"Left Line Mux", "Line 2", "LINPUT2"},
+	{"Left Line Mux", "Line 3", "LINPUT3"},
+	{"Left Line Mux", "PGA", "Left PGA Mux"},
+	{"Left Line Mux", "Differential", "Differential Mux"},
+
+	/* Right Line Mux */
+	{"Right Line Mux", "Line 1", "RINPUT1"},
+	{"Right Line Mux", "Line 2", "RINPUT2"},
+	{"Right Line Mux", "Line 3", "RINPUT3"},
+	{"Right Line Mux", "PGA", "Right PGA Mux"},
+	{"Right Line Mux", "Differential", "Differential Mux"},
+
+	/* Left PGA Mux */
+	{"Left PGA Mux", "Line 1", "LINPUT1"},
+	{"Left PGA Mux", "Line 2", "LINPUT2"},
+	{"Left PGA Mux", "Line 3", "LINPUT3"},
+	{"Left PGA Mux", "Differential", "Differential Mux"},
+
+	/* Right PGA Mux */
+	{"Right PGA Mux", "Line 1", "RINPUT1"},
+	{"Right PGA Mux", "Line 2", "RINPUT2"},
+	{"Right PGA Mux", "Line 3", "RINPUT3"},
+	{"Right PGA Mux", "Differential", "Differential Mux"},
+
+	/* Differential Mux */
+	{"Differential Mux", "Line 1", "LINPUT1"},
+	{"Differential Mux", "Line 1", "RINPUT1"},
+	{"Differential Mux", "Line 2", "LINPUT2"},
+	{"Differential Mux", "Line 2", "RINPUT2"},
+
+	/* Left ADC Mux */
+	{"Left ADC Mux", "Stereo", "Left PGA Mux"},
+	{"Left ADC Mux", "Mono (Left)", "Left PGA Mux"},
+	{"Left ADC Mux", "Digital Mono", "Left PGA Mux"},
+
+	/* Right ADC Mux */
+	{"Right ADC Mux", "Stereo", "Right PGA Mux"},
+	{"Right ADC Mux", "Mono (Right)", "Right PGA Mux"},
+	{"Right ADC Mux", "Digital Mono", "Right PGA Mux"},
+
+	/* ADC */
+	{"Left ADC", NULL, "Left ADC Mux"},
+	{"Right ADC", NULL, "Right ADC Mux"},
+
+	/* terminator */
+	{NULL, NULL, NULL},
+};
+
+static int wm8750_add_widgets(struct snd_soc_codec *codec)
+{
+	int i;
+
+	for(i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) {
+		snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]);
+	}
+
+	/* set up audio path audio_mapnects */
+	for(i = 0; audio_map[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, audio_map[i][0],
+			audio_map[i][1], audio_map[i][2]);
+	}
+
+	snd_soc_dapm_new_widgets(codec);
+	return 0;
+}
+
+struct _coeff_div {
+	u32 mclk;
+	u32 rate;
+	u16 fs;
+	u8 sr:5;
+	u8 usb:1;
+};
+
+/* codec hifi mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+	/* 8k */
+	{12288000, 8000, 1536, 0x6, 0x0},
+	{11289600, 8000, 1408, 0x16, 0x0},
+	{18432000, 8000, 2304, 0x7, 0x0},
+	{16934400, 8000, 2112, 0x17, 0x0},
+	{12000000, 8000, 1500, 0x6, 0x1},
+
+	/* 11.025k */
+	{11289600, 11025, 1024, 0x18, 0x0},
+	{16934400, 11025, 1536, 0x19, 0x0},
+	{12000000, 11025, 1088, 0x19, 0x1},
+
+	/* 16k */
+	{12288000, 16000, 768, 0xa, 0x0},
+	{18432000, 16000, 1152, 0xb, 0x0},
+	{12000000, 16000, 750, 0xa, 0x1},
+
+	/* 22.05k */
+	{11289600, 22050, 512, 0x1a, 0x0},
+	{16934400, 22050, 768, 0x1b, 0x0},
+	{12000000, 22050, 544, 0x1b, 0x1},
+
+	/* 32k */
+	{12288000, 32000, 384, 0xc, 0x0},
+	{18432000, 32000, 576, 0xd, 0x0},
+	{12000000, 32000, 375, 0xa, 0x1},
+
+	/* 44.1k */
+	{11289600, 44100, 256, 0x10, 0x0},
+	{16934400, 44100, 384, 0x11, 0x0},
+	{12000000, 44100, 272, 0x11, 0x1},
+
+	/* 48k */
+	{12288000, 48000, 256, 0x0, 0x0},
+	{18432000, 48000, 384, 0x1, 0x0},
+	{12000000, 48000, 250, 0x0, 0x1},
+
+	/* 88.2k */
+	{11289600, 88200, 128, 0x1e, 0x0},
+	{16934400, 88200, 192, 0x1f, 0x0},
+	{12000000, 88200, 136, 0x1f, 0x1},
+
+	/* 96k */
+	{12288000, 96000, 128, 0xe, 0x0},
+	{18432000, 96000, 192, 0xf, 0x0},
+	{12000000, 96000, 125, 0xe, 0x1},
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+
+	printk(KERN_ERR "wm8750: could not get coeff for mclk %d @ rate %d\n",
+		mclk, rate);
+	return -EINVAL;
+}
+
+static int wm8750_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct wm8750_priv *wm8750 = codec->private_data;
+
+	switch (freq) {
+	case 11289600:
+	case 12000000:
+	case 12288000:
+	case 16934400:
+	case 18432000:
+		wm8750->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int wm8750_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface = 0x0040;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x0013;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0090;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0010;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wm8750_write(codec, WM8750_IFACE, iface);
+	return 0;
+}
+
+static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	struct wm8750_priv *wm8750 = codec->private_data;
+	u16 iface = wm8750_read_reg_cache(codec, WM8750_IFACE) & 0x1f3;
+	u16 srate = wm8750_read_reg_cache(codec, WM8750_SRATE) & 0x1c0;
+	int coeff = get_coeff(wm8750->sysclk, params_rate(params));
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		iface |= 0x0004;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		iface |= 0x0008;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		iface |= 0x000c;
+		break;
+	}
+
+	/* set iface & srate */
+	wm8750_write(codec, WM8750_IFACE, iface);
+	if (coeff >= 0)
+		wm8750_write(codec, WM8750_SRATE, srate |
+			(coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
+
+	return 0;
+}
+
+static int wm8750_mute(struct snd_soc_codec_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7;
+
+	if (mute)
+		wm8750_write(codec, WM8750_ADCDAC, mute_reg | 0x8);
+	else
+		wm8750_write(codec, WM8750_ADCDAC, mute_reg);
+	return 0;
+}
+
+static int wm8750_dapm_event(struct snd_soc_codec *codec, int event)
+{
+	u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e;
+
+	switch (event) {
+	case SNDRV_CTL_POWER_D0: /* full On */
+		/* set vmid to 50k and unmute dac */
+		wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0);
+		break;
+	case SNDRV_CTL_POWER_D1: /* partial On */
+	case SNDRV_CTL_POWER_D2: /* partial On */
+		/* set vmid to 5k for quick power up */
+		wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1);
+		break;
+	case SNDRV_CTL_POWER_D3hot: /* Off, with power */
+		/* mute dac and set vmid to 500k, enable VREF */
+		wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141);
+		break;
+	case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+		wm8750_write(codec, WM8750_PWR1, 0x0001);
+		break;
+	}
+	codec->dapm_state = event;
+	return 0;
+}
+
+#define WM8750_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
+		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+struct snd_soc_codec_dai wm8750_dai = {
+	.name = "WM8750",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8750_RATES,
+		.formats = WM8750_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8750_RATES,
+		.formats = WM8750_FORMATS,},
+	.ops = {
+		.hw_params = wm8750_pcm_hw_params,
+	},
+	.dai_ops = {
+		.digital_mute = wm8750_mute,
+		.set_fmt = wm8750_set_dai_fmt,
+		.set_sysclk = wm8750_set_dai_sysclk,
+	},
+};
+EXPORT_SYMBOL_GPL(wm8750_dai);
+
+static void wm8750_work(struct work_struct *work)
+{
+	struct snd_soc_codec *codec =
+		container_of(work, struct snd_soc_codec, delayed_work.work);
+	wm8750_dapm_event(codec, codec->dapm_state);
+}
+
+static int wm8750_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+	return 0;
+}
+
+static int wm8750_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+	int i;
+	u8 data[2];
+	u16 *cache = codec->reg_cache;
+
+	/* Sync reg_cache with the hardware */
+	for (i = 0; i < ARRAY_SIZE(wm8750_reg); i++) {
+		if (i == WM8750_RESET)
+			continue;
+		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+		data[1] = cache[i] & 0x00ff;
+		codec->hw_write(codec->control_data, data, 2);
+	}
+
+	wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+
+	/* charge wm8750 caps */
+	if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) {
+		wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2);
+		codec->dapm_state = SNDRV_CTL_POWER_D0;
+		schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000));
+	}
+
+	return 0;
+}
+
+/*
+ * initialise the WM8750 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int wm8750_init(struct snd_soc_device *socdev)
+{
+	struct snd_soc_codec *codec = socdev->codec;
+	int reg, ret = 0;
+
+	codec->name = "WM8750";
+	codec->owner = THIS_MODULE;
+	codec->read = wm8750_read_reg_cache;
+	codec->write = wm8750_write;
+	codec->dapm_event = wm8750_dapm_event;
+	codec->dai = &wm8750_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = sizeof(wm8750_reg);
+	codec->reg_cache = kmemdup(wm8750_reg, sizeof(wm8750_reg), GFP_KRENEL);
+	if (codec->reg_cache == NULL)
+		return -ENOMEM;
+
+	wm8750_reset(codec);
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8750: failed to create pcms\n");
+		goto pcm_err;
+	}
+
+	/* charge output caps */
+	wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2);
+	codec->dapm_state = SNDRV_CTL_POWER_D3hot;
+	schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000));
+
+	/* set the update bits */
+	reg = wm8750_read_reg_cache(codec, WM8750_LDAC);
+	wm8750_write(codec, WM8750_LDAC, reg | 0x0100);
+	reg = wm8750_read_reg_cache(codec, WM8750_RDAC);
+	wm8750_write(codec, WM8750_RDAC, reg | 0x0100);
+	reg = wm8750_read_reg_cache(codec, WM8750_LOUT1V);
+	wm8750_write(codec, WM8750_LOUT1V, reg | 0x0100);
+	reg = wm8750_read_reg_cache(codec, WM8750_ROUT1V);
+	wm8750_write(codec, WM8750_ROUT1V, reg | 0x0100);
+	reg = wm8750_read_reg_cache(codec, WM8750_LOUT2V);
+	wm8750_write(codec, WM8750_LOUT2V, reg | 0x0100);
+	reg = wm8750_read_reg_cache(codec, WM8750_ROUT2V);
+	wm8750_write(codec, WM8750_ROUT2V, reg | 0x0100);
+	reg = wm8750_read_reg_cache(codec, WM8750_LINVOL);
+	wm8750_write(codec, WM8750_LINVOL, reg | 0x0100);
+	reg = wm8750_read_reg_cache(codec, WM8750_RINVOL);
+	wm8750_write(codec, WM8750_RINVOL, reg | 0x0100);
+
+	wm8750_add_controls(codec);
+	wm8750_add_widgets(codec);
+	ret = snd_soc_register_card(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8750: failed to register card\n");
+		goto card_err;
+	}
+	return ret;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+pcm_err:
+	kfree(codec->reg_cache);
+	return ret;
+}
+
+/* If the i2c layer weren't so broken, we could pass this kind of data
+   around */
+static struct snd_soc_device *wm8750_socdev;
+
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+
+/*
+ * WM8731 2 wire address is determined by GPIO5
+ * state during powerup.
+ *    low  = 0x1a
+ *    high = 0x1b
+ */
+static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver wm8750_i2c_driver;
+static struct i2c_client client_template;
+
+static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+	struct snd_soc_device *socdev = wm8750_socdev;
+	struct wm8750_setup_data *setup = socdev->codec_data;
+	struct snd_soc_codec *codec = socdev->codec;
+	struct i2c_client *i2c;
+	int ret;
+
+	if (addr != setup->i2c_address)
+		return -ENODEV;
+
+	client_template.adapter = adap;
+	client_template.addr = addr;
+
+	i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+	if (i2c == NULL) {
+		kfree(codec);
+		return -ENOMEM;
+	}
+	i2c_set_clientdata(i2c, codec);
+	codec->control_data = i2c;
+
+	ret = i2c_attach_client(i2c);
+	if (ret < 0) {
+		err("failed to attach codec at addr %x\n", addr);
+		goto err;
+	}
+
+	ret = wm8750_init(socdev);
+	if (ret < 0) {
+	err("failed to initialise WM8750\n");
+		goto err;
+	}
+	return ret;
+
+err:
+	kfree(codec);
+	kfree(i2c);
+	return ret;
+}
+
+static int wm8750_i2c_detach(struct i2c_client *client)
+{
+	struct snd_soc_codec *codec = i2c_get_clientdata(client);
+	i2c_detach_client(client);
+	kfree(codec->reg_cache);
+	kfree(client);
+	return 0;
+}
+
+static int wm8750_i2c_attach(struct i2c_adapter *adap)
+{
+	return i2c_probe(adap, &addr_data, wm8750_codec_probe);
+}
+
+/* corgi i2c codec control layer */
+static struct i2c_driver wm8750_i2c_driver = {
+	.driver = {
+		.name = "WM8750 I2C Codec",
+		.owner = THIS_MODULE,
+	},
+	.id =             I2C_DRIVERID_WM8750,
+	.attach_adapter = wm8750_i2c_attach,
+	.detach_client =  wm8750_i2c_detach,
+	.command =        NULL,
+};
+
+static struct i2c_client client_template = {
+	.name =   "WM8750",
+	.driver = &wm8750_i2c_driver,
+};
+#endif
+
+static int wm8750_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct wm8750_setup_data *setup = socdev->codec_data;
+	struct snd_soc_codec *codec;
+	struct wm8750_priv *wm8750;
+	int ret = 0;
+
+	info("WM8750 Audio Codec %s", WM8750_VERSION);
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		return -ENOMEM;
+
+	wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL);
+	if (wm8750 == NULL) {
+		kfree(codec);
+		return -ENOMEM;
+	}
+
+	codec->private_data = wm8750;
+	socdev->codec = codec;
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+	wm8750_socdev = socdev;
+	INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work);
+	
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+	if (setup->i2c_address) {
+		normal_i2c[0] = setup->i2c_address;
+		codec->hw_write = (hw_write_t)i2c_master_send;
+		ret = i2c_add_driver(&wm8750_i2c_driver);
+		if (ret != 0)
+			printk(KERN_ERR "can't add i2c driver");
+	}
+#else
+		/* Add other interfaces here */
+#endif
+
+	return ret;
+}
+
+/*
+ * This function forces any delayed work to be queued and run.
+ */
+static int run_delayed_work(struct delayed_work *dwork)
+{
+	int ret;
+
+	/* cancel any work waiting to be queued. */
+	ret = cancel_delayed_work(dwork);
+
+	/* if there was any work waiting then we run it now and
+	 * wait for it's completion */
+	if (ret) {
+		schedule_delayed_work(dwork, 0);
+		flush_scheduled_work();
+	}
+	return ret;
+}
+
+/* power down chip */
+static int wm8750_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	if (codec->control_data)
+		wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+	run_delayed_work(&codec->delayed_work);
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+	i2c_del_driver(&wm8750_i2c_driver);
+#endif
+	kfree(codec->private_data);
+	kfree(codec);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8750 = {
+	.probe = 	wm8750_probe,
+	.remove = 	wm8750_remove,
+	.suspend = 	wm8750_suspend,
+	.resume =	wm8750_resume,
+};
+
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750);
+
+MODULE_DESCRIPTION("ASoC WM8750 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8750.h b/sound/soc/codecs/wm8750.h
new file mode 100644
index 0000000..a97a54a
--- /dev/null
+++ b/sound/soc/codecs/wm8750.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on WM8753.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _WM8750_H
+#define _WM8750_H
+
+/* WM8750 register space */
+
+#define WM8750_LINVOL    0x00
+#define WM8750_RINVOL    0x01
+#define WM8750_LOUT1V    0x02
+#define WM8750_ROUT1V    0x03
+#define WM8750_ADCDAC    0x05
+#define WM8750_IFACE     0x07
+#define WM8750_SRATE     0x08
+#define WM8750_LDAC      0x0a
+#define WM8750_RDAC      0x0b
+#define WM8750_BASS      0x0c
+#define WM8750_TREBLE    0x0d
+#define WM8750_RESET     0x0f
+#define WM8750_3D        0x10
+#define WM8750_ALC1      0x11
+#define WM8750_ALC2      0x12
+#define WM8750_ALC3      0x13
+#define WM8750_NGATE     0x14
+#define WM8750_LADC      0x15
+#define WM8750_RADC      0x16
+#define WM8750_ADCTL1    0x17
+#define WM8750_ADCTL2    0x18
+#define WM8750_PWR1      0x19
+#define WM8750_PWR2      0x1a
+#define WM8750_ADCTL3    0x1b
+#define WM8750_ADCIN     0x1f
+#define WM8750_LADCIN    0x20
+#define WM8750_RADCIN    0x21
+#define WM8750_LOUTM1    0x22
+#define WM8750_LOUTM2    0x23
+#define WM8750_ROUTM1    0x24
+#define WM8750_ROUTM2    0x25
+#define WM8750_MOUTM1    0x26
+#define WM8750_MOUTM2    0x27
+#define WM8750_LOUT2V    0x28
+#define WM8750_ROUT2V    0x29
+#define WM8750_MOUTV     0x2a
+
+#define WM8750_CACHE_REGNUM 0x2a
+
+#define WM8750_SYSCLK	0
+
+struct wm8750_setup_data {
+	unsigned short i2c_address;
+};
+
+extern struct snd_soc_codec_dai wm8750_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8750;
+
+#endif
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
new file mode 100644
index 0000000..92a6487
--- /dev/null
+++ b/sound/soc/codecs/wm9712.c
@@ -0,0 +1,771 @@
+/*
+ * wm9712.c  --  ALSA Soc WM9712 codec support
+ *
+ * Copyright 2006 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    4th Feb 2006   Initial version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#define WM9712_VERSION "0.4"
+
+static unsigned int ac97_read(struct snd_soc_codec *codec,
+	unsigned int reg);
+static int ac97_write(struct snd_soc_codec *codec,
+	unsigned int reg, unsigned int val);
+
+/*
+ * WM9712 register cache
+ */
+static const u16 wm9712_reg[] = {
+	0x6174, 0x8000, 0x8000, 0x8000, // 6
+	0xf0f0, 0xaaa0, 0xc008, 0x6808, // e
+	0xe808, 0xaaa0, 0xad00, 0x8000, // 16
+	0xe808, 0x3000, 0x8000, 0x0000, // 1e
+	0x0000, 0x0000, 0x0000, 0x000f, // 26
+	0x0405, 0x0410, 0xbb80, 0xbb80, // 2e
+	0x0000, 0xbb80, 0x0000, 0x0000, // 36
+	0x0000, 0x2000, 0x0000, 0x0000, // 3e
+	0x0000, 0x0000, 0x0000, 0x0000, // 46
+	0x0000, 0x0000, 0xf83e, 0xffff, // 4e
+	0x0000, 0x0000, 0x0000, 0xf83e, // 56
+	0x0008, 0x0000, 0x0000, 0x0000, // 5e
+	0xb032, 0x3e00, 0x0000, 0x0000, // 66
+	0x0000, 0x0000, 0x0000, 0x0000, // 6e
+	0x0000, 0x0000, 0x0000, 0x0006, // 76
+	0x0001, 0x0000, 0x574d, 0x4c12, // 7e
+	0x0000, 0x0000 // virtual hp mixers
+};
+
+/* virtual HP mixers regs */
+#define HPL_MIXER	0x80
+#define HPR_MIXER	0x82
+
+static const char *wm9712_alc_select[] = {"None", "Left", "Right", "Stereo"};
+static const char *wm9712_alc_mux[] = {"Stereo", "Left", "Right", "None"};
+static const char *wm9712_out3_src[] = {"Left", "VREF", "Left + Right",
+	"Mono"};
+static const char *wm9712_spk_src[] = {"Speaker Mix", "Headphone Mix"};
+static const char *wm9712_rec_adc[] = {"Stereo", "Left", "Right", "Mute"};
+static const char *wm9712_base[] = {"Linear Control", "Adaptive Boost"};
+static const char *wm9712_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"};
+static const char *wm9712_mic[] = {"Mic 1", "Differential", "Mic 2",
+	"Stereo"};
+static const char *wm9712_rec_sel[] = {"Mic", "NC", "NC", "Speaker Mixer",
+	"Line", "Headphone Mixer", "Phone Mixer", "Phone"};
+static const char *wm9712_ng_type[] = {"Constant Gain", "Mute"};
+static const char *wm9712_diff_sel[] = {"Mic", "Line"};
+
+static const struct soc_enum wm9712_enum[] = {
+SOC_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9712_alc_select),
+SOC_ENUM_SINGLE(AC97_VIDEO, 12, 4, wm9712_alc_mux),
+SOC_ENUM_SINGLE(AC97_AUX, 9, 4, wm9712_out3_src),
+SOC_ENUM_SINGLE(AC97_AUX, 8, 2, wm9712_spk_src),
+SOC_ENUM_SINGLE(AC97_REC_SEL, 12, 4, wm9712_rec_adc),
+SOC_ENUM_SINGLE(AC97_MASTER_TONE, 15, 2, wm9712_base),
+SOC_ENUM_DOUBLE(AC97_REC_GAIN, 14, 6, 2, wm9712_rec_gain),
+SOC_ENUM_SINGLE(AC97_MIC, 5, 4, wm9712_mic),
+SOC_ENUM_SINGLE(AC97_REC_SEL, 8, 8, wm9712_rec_sel),
+SOC_ENUM_SINGLE(AC97_REC_SEL, 0, 8, wm9712_rec_sel),
+SOC_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9712_ng_type),
+SOC_ENUM_SINGLE(0x5c, 8, 2, wm9712_diff_sel),
+};
+
+static const struct snd_kcontrol_new wm9712_snd_ac97_controls[] = {
+SOC_DOUBLE("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1),
+SOC_SINGLE("Speaker Playback Switch", AC97_MASTER, 15, 1, 1),
+SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1),
+SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE,15, 1, 1),
+
+SOC_SINGLE("Speaker Playback ZC Switch", AC97_MASTER, 7, 1, 0),
+SOC_SINGLE("Speaker Playback Invert Switch", AC97_MASTER, 6, 1, 0),
+SOC_SINGLE("Headphone Playback ZC Switch", AC97_HEADPHONE, 7, 1, 0),
+SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_MONO, 7, 1, 0),
+SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 0),
+
+SOC_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0),
+SOC_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0),
+SOC_SINGLE("ALC Decay Time", AC97_CODEC_CLASS_REV, 4, 15, 0),
+SOC_SINGLE("ALC Attack Time", AC97_CODEC_CLASS_REV, 0, 15, 0),
+SOC_ENUM("ALC Function", wm9712_enum[0]),
+SOC_SINGLE("ALC Max Volume", AC97_PCI_SVID, 11, 7, 0),
+SOC_SINGLE("ALC ZC Timeout", AC97_PCI_SVID, 9, 3, 1),
+SOC_SINGLE("ALC ZC Switch", AC97_PCI_SVID, 8, 1, 0),
+SOC_SINGLE("ALC NG Switch", AC97_PCI_SVID, 7, 1, 0),
+SOC_ENUM("ALC NG Type", wm9712_enum[10]),
+SOC_SINGLE("ALC NG Threshold", AC97_PCI_SVID, 0, 31, 1),
+
+SOC_SINGLE("Mic Headphone  Volume", AC97_VIDEO, 12, 7, 1),
+SOC_SINGLE("ALC Headphone Volume", AC97_VIDEO, 7, 7, 1),
+
+SOC_SINGLE("Out3 Switch", AC97_AUX, 15, 1, 1),
+SOC_SINGLE("Out3 ZC Switch", AC97_AUX, 7, 1, 1),
+SOC_SINGLE("Out3 Volume", AC97_AUX, 0, 31, 1),
+
+SOC_SINGLE("PCBeep Bypass Headphone Volume", AC97_PC_BEEP, 12, 7, 1),
+SOC_SINGLE("PCBeep Bypass Speaker Volume", AC97_PC_BEEP, 8, 7, 1),
+SOC_SINGLE("PCBeep Bypass Phone Volume", AC97_PC_BEEP, 4, 7, 1),
+
+SOC_SINGLE("Aux Playback Headphone Volume", AC97_CD, 12, 7, 1),
+SOC_SINGLE("Aux Playback Speaker Volume", AC97_CD, 8, 7, 1),
+SOC_SINGLE("Aux Playback Phone Volume", AC97_CD, 4, 7, 1),
+
+SOC_SINGLE("Phone Volume", AC97_PHONE, 0, 15, 0),
+SOC_DOUBLE("Line Capture Volume", AC97_LINE, 8, 0, 31, 1),
+
+SOC_SINGLE("Capture 20dB Boost Switch", AC97_REC_SEL, 14, 1, 0),
+SOC_SINGLE("Capture to Phone 20dB Boost Switch", AC97_REC_SEL, 11, 1, 1),
+
+SOC_SINGLE("3D Upper Cut-off Switch", AC97_3D_CONTROL, 5, 1, 1),
+SOC_SINGLE("3D Lower Cut-off Switch", AC97_3D_CONTROL, 4, 1, 1),
+SOC_SINGLE("3D Playback Volume", AC97_3D_CONTROL, 0, 15, 0),
+
+SOC_ENUM("Bass Control", wm9712_enum[5]),
+SOC_SINGLE("Bass Cut-off Switch", AC97_MASTER_TONE, 12, 1, 1),
+SOC_SINGLE("Tone Cut-off Switch", AC97_MASTER_TONE, 4, 1, 1),
+SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0),
+SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 0),
+SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 0),
+
+SOC_SINGLE("Capture ADC Switch", AC97_REC_GAIN, 15, 1, 1),
+SOC_ENUM("Capture Volume Steps", wm9712_enum[6]),
+SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 1),
+SOC_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0),
+
+SOC_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1),
+SOC_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1),
+SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0),
+};
+
+/* add non dapm controls */
+static int wm9712_add_controls(struct snd_soc_codec *codec)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(wm9712_snd_ac97_controls); i++) {
+		err = snd_ctl_add(codec->card,
+				snd_soc_cnew(&wm9712_snd_ac97_controls[i],codec, NULL));
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+/* We have to create a fake left and right HP mixers because
+ * the codec only has a single control that is shared by both channels.
+ * This makes it impossible to determine the audio path.
+ */
+static int mixer_event (struct snd_soc_dapm_widget *w, int event)
+{
+	u16 l, r, beep, line, phone, mic, pcm, aux;
+
+	l = ac97_read(w->codec, HPL_MIXER);
+	r = ac97_read(w->codec, HPR_MIXER);
+	beep = ac97_read(w->codec, AC97_PC_BEEP);
+	mic = ac97_read(w->codec, AC97_VIDEO);
+	phone = ac97_read(w->codec, AC97_PHONE);
+	line = ac97_read(w->codec, AC97_LINE);
+	pcm = ac97_read(w->codec, AC97_PCM);
+	aux = ac97_read(w->codec, AC97_CD);
+
+	if (l & 0x1 || r & 0x1)
+		ac97_write(w->codec, AC97_VIDEO, mic & 0x7fff);
+	else
+		ac97_write(w->codec, AC97_VIDEO, mic | 0x8000);
+
+	if (l & 0x2 || r & 0x2)
+		ac97_write(w->codec, AC97_PCM, pcm & 0x7fff);
+	else
+		ac97_write(w->codec, AC97_PCM, pcm | 0x8000);
+
+	if (l & 0x4 || r & 0x4)
+		ac97_write(w->codec, AC97_LINE, line & 0x7fff);
+	else
+		ac97_write(w->codec, AC97_LINE, line | 0x8000);
+
+	if (l & 0x8 || r & 0x8)
+		ac97_write(w->codec, AC97_PHONE, phone & 0x7fff);
+	else
+		ac97_write(w->codec, AC97_PHONE, phone | 0x8000);
+
+	if (l & 0x10 || r & 0x10)
+		ac97_write(w->codec, AC97_CD, aux & 0x7fff);
+	else
+		ac97_write(w->codec, AC97_CD, aux | 0x8000);
+
+	if (l & 0x20 || r & 0x20)
+		ac97_write(w->codec, AC97_PC_BEEP, beep & 0x7fff);
+	else
+		ac97_write(w->codec, AC97_PC_BEEP, beep | 0x8000);
+
+	return 0;
+}
+
+/* Left Headphone Mixers */
+static const struct snd_kcontrol_new wm9712_hpl_mixer_controls[] = {
+	SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPL_MIXER, 5, 1, 0),
+	SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 4, 1, 0),
+	SOC_DAPM_SINGLE("Phone Bypass Switch", HPL_MIXER, 3, 1, 0),
+	SOC_DAPM_SINGLE("Line Bypass Switch", HPL_MIXER, 2, 1, 0),
+	SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 1, 1, 0),
+	SOC_DAPM_SINGLE("Mic Sidetone Switch", HPL_MIXER, 0, 1, 0),
+};
+
+/* Right Headphone Mixers */
+static const struct snd_kcontrol_new wm9712_hpr_mixer_controls[] = {
+	SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPR_MIXER, 5, 1, 0),
+	SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 4, 1, 0),
+	SOC_DAPM_SINGLE("Phone Bypass Switch", HPR_MIXER, 3, 1, 0),
+	SOC_DAPM_SINGLE("Line Bypass Switch", HPR_MIXER, 2, 1, 0),
+	SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 1, 1, 0),
+	SOC_DAPM_SINGLE("Mic Sidetone Switch", HPR_MIXER, 0, 1, 0),
+};
+
+/* Speaker Mixer */
+static const struct snd_kcontrol_new wm9712_speaker_mixer_controls[] = {
+	SOC_DAPM_SINGLE("PCBeep Bypass Switch", AC97_PC_BEEP, 11, 1, 1),
+	SOC_DAPM_SINGLE("Aux Playback Switch", AC97_CD, 11, 1, 1),
+	SOC_DAPM_SINGLE("Phone Bypass Switch", AC97_PHONE, 14, 1, 1),
+	SOC_DAPM_SINGLE("Line Bypass Switch", AC97_LINE, 14, 1, 1),
+	SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PCM, 14, 1, 1),
+};
+
+/* Phone Mixer */
+static const struct snd_kcontrol_new wm9712_phone_mixer_controls[] = {
+	SOC_DAPM_SINGLE("PCBeep Bypass Switch", AC97_PC_BEEP, 7, 1, 1),
+	SOC_DAPM_SINGLE("Aux Playback Switch", AC97_CD, 7, 1, 1),
+	SOC_DAPM_SINGLE("Line Bypass Switch", AC97_LINE, 13, 1, 1),
+	SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PCM, 13, 1, 1),
+	SOC_DAPM_SINGLE("Mic 1 Sidetone Switch", AC97_MIC, 14, 1, 1),
+	SOC_DAPM_SINGLE("Mic 2 Sidetone Switch", AC97_MIC, 13, 1, 1),
+};
+
+/* ALC headphone mux */
+static const struct snd_kcontrol_new wm9712_alc_mux_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[1]);
+
+/* out 3 mux */
+static const struct snd_kcontrol_new wm9712_out3_mux_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[2]);
+
+/* spk mux */
+static const struct snd_kcontrol_new wm9712_spk_mux_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[3]);
+
+/* Capture to Phone mux */
+static const struct snd_kcontrol_new wm9712_capture_phone_mux_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[4]);
+
+/* Capture left select */
+static const struct snd_kcontrol_new wm9712_capture_selectl_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[8]);
+
+/* Capture right select */
+static const struct snd_kcontrol_new wm9712_capture_selectr_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[9]);
+
+/* Mic select */
+static const struct snd_kcontrol_new wm9712_mic_src_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[7]);
+
+/* diff select */
+static const struct snd_kcontrol_new wm9712_diff_sel_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[11]);
+
+static const struct snd_soc_dapm_widget wm9712_dapm_widgets[] = {
+SND_SOC_DAPM_MUX("ALC Sidetone Mux", SND_SOC_NOPM, 0, 0,
+	&wm9712_alc_mux_controls),
+SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0,
+	&wm9712_out3_mux_controls),
+SND_SOC_DAPM_MUX("Speaker Mux", SND_SOC_NOPM, 0, 0,
+	&wm9712_spk_mux_controls),
+SND_SOC_DAPM_MUX("Capture Phone Mux", SND_SOC_NOPM, 0, 0,
+	&wm9712_capture_phone_mux_controls),
+SND_SOC_DAPM_MUX("Left Capture Select", SND_SOC_NOPM, 0, 0,
+	&wm9712_capture_selectl_controls),
+SND_SOC_DAPM_MUX("Right Capture Select", SND_SOC_NOPM, 0, 0,
+	&wm9712_capture_selectr_controls),
+SND_SOC_DAPM_MUX("Mic Select Source", SND_SOC_NOPM, 0, 0,
+	&wm9712_mic_src_controls),
+SND_SOC_DAPM_MUX("Differential Source", SND_SOC_NOPM, 0, 0,
+	&wm9712_diff_sel_controls),
+SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER_E("Left HP Mixer", AC97_INT_PAGING, 9, 1,
+	&wm9712_hpl_mixer_controls[0], ARRAY_SIZE(wm9712_hpl_mixer_controls),
+	mixer_event, SND_SOC_DAPM_POST_REG),
+SND_SOC_DAPM_MIXER_E("Right HP Mixer", AC97_INT_PAGING, 8, 1,
+	&wm9712_hpr_mixer_controls[0], ARRAY_SIZE(wm9712_hpr_mixer_controls),
+	 mixer_event, SND_SOC_DAPM_POST_REG),
+SND_SOC_DAPM_MIXER("Phone Mixer", AC97_INT_PAGING, 6, 1,
+	&wm9712_phone_mixer_controls[0], ARRAY_SIZE(wm9712_phone_mixer_controls)),
+SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_INT_PAGING, 7, 1,
+	&wm9712_speaker_mixer_controls[0],
+	ARRAY_SIZE(wm9712_speaker_mixer_controls)),
+SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", AC97_INT_PAGING, 14, 1),
+SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", AC97_INT_PAGING, 13, 1),
+SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", AC97_INT_PAGING, 12, 1),
+SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", AC97_INT_PAGING, 11, 1),
+SND_SOC_DAPM_PGA("Headphone PGA", AC97_INT_PAGING, 4, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Speaker PGA", AC97_INT_PAGING, 3, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Out 3 PGA", AC97_INT_PAGING, 5, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Line PGA", AC97_INT_PAGING, 2, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Phone PGA", AC97_INT_PAGING, 1, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Mic PGA", AC97_INT_PAGING, 0, 1, NULL, 0),
+SND_SOC_DAPM_MICBIAS("Mic Bias", AC97_INT_PAGING, 10, 1),
+SND_SOC_DAPM_OUTPUT("MONOOUT"),
+SND_SOC_DAPM_OUTPUT("HPOUTL"),
+SND_SOC_DAPM_OUTPUT("HPOUTR"),
+SND_SOC_DAPM_OUTPUT("LOUT2"),
+SND_SOC_DAPM_OUTPUT("ROUT2"),
+SND_SOC_DAPM_OUTPUT("OUT3"),
+SND_SOC_DAPM_INPUT("LINEINL"),
+SND_SOC_DAPM_INPUT("LINEINR"),
+SND_SOC_DAPM_INPUT("PHONE"),
+SND_SOC_DAPM_INPUT("PCBEEP"),
+SND_SOC_DAPM_INPUT("MIC1"),
+SND_SOC_DAPM_INPUT("MIC2"),
+};
+
+static const char *audio_map[][3] = {
+	/* virtual mixer - mixes left & right channels for spk and mono */
+	{"AC97 Mixer", NULL, "Left DAC"},
+	{"AC97 Mixer", NULL, "Right DAC"},
+
+	/* Left HP mixer */
+	{"Left HP Mixer", "PCBeep Bypass Switch", "PCBEEP"},
+	{"Left HP Mixer", "Aux Playback Switch",  "Aux DAC"},
+	{"Left HP Mixer", "Phone Bypass Switch",  "Phone PGA"},
+	{"Left HP Mixer", "Line Bypass Switch",   "Line PGA"},
+	{"Left HP Mixer", "PCM Playback Switch",  "Left DAC"},
+	{"Left HP Mixer", "Mic Sidetone Switch",  "Mic PGA"},
+	{"Left HP Mixer", NULL,  "ALC Sidetone Mux"},
+	//{"Right HP Mixer", NULL, "HP Mixer"},
+
+	/* Right HP mixer */
+	{"Right HP Mixer", "PCBeep Bypass Switch", "PCBEEP"},
+	{"Right HP Mixer", "Aux Playback Switch",  "Aux DAC"},
+	{"Right HP Mixer", "Phone Bypass Switch",  "Phone PGA"},
+	{"Right HP Mixer", "Line Bypass Switch",   "Line PGA"},
+	{"Right HP Mixer", "PCM Playback Switch",  "Right DAC"},
+	{"Right HP Mixer", "Mic Sidetone Switch",  "Mic PGA"},
+	{"Right HP Mixer", NULL,  "ALC Sidetone Mux"},
+
+	/* speaker mixer */
+	{"Speaker Mixer", "PCBeep Bypass Switch", "PCBEEP"},
+	{"Speaker Mixer", "Line Bypass Switch",   "Line PGA"},
+	{"Speaker Mixer", "PCM Playback Switch",  "AC97 Mixer"},
+	{"Speaker Mixer", "Phone Bypass Switch",  "Phone PGA"},
+	{"Speaker Mixer", "Aux Playback Switch",  "Aux DAC"},
+
+	/* Phone mixer */
+	{"Phone Mixer", "PCBeep Bypass Switch",  "PCBEEP"},
+	{"Phone Mixer", "Line Bypass Switch",    "Line PGA"},
+	{"Phone Mixer", "Aux Playback Switch",   "Aux DAC"},
+	{"Phone Mixer", "PCM Playback Switch",   "AC97 Mixer"},
+	{"Phone Mixer", "Mic 1 Sidetone Switch", "Mic PGA"},
+	{"Phone Mixer", "Mic 2 Sidetone Switch", "Mic PGA"},
+
+	/* inputs */
+	{"Line PGA", NULL, "LINEINL"},
+	{"Line PGA", NULL, "LINEINR"},
+	{"Phone PGA", NULL, "PHONE"},
+	{"Mic PGA", NULL, "MIC1"},
+	{"Mic PGA", NULL, "MIC2"},
+
+	/* left capture selector */
+	{"Left Capture Select", "Mic", "MIC1"},
+	{"Left Capture Select", "Speaker Mixer", "Speaker Mixer"},
+	{"Left Capture Select", "Line", "LINEINL"},
+	{"Left Capture Select", "Headphone Mixer", "Left HP Mixer"},
+	{"Left Capture Select", "Phone Mixer", "Phone Mixer"},
+	{"Left Capture Select", "Phone", "PHONE"},
+
+	/* right capture selector */
+	{"Right Capture Select", "Mic", "MIC2"},
+	{"Right Capture Select", "Speaker Mixer", "Speaker Mixer"},
+	{"Right Capture Select", "Line", "LINEINR"},
+	{"Right Capture Select", "Headphone Mixer", "Right HP Mixer"},
+	{"Right Capture Select", "Phone Mixer", "Phone Mixer"},
+	{"Right Capture Select", "Phone", "PHONE"},
+
+	/* ALC Sidetone */
+	{"ALC Sidetone Mux", "Stereo", "Left Capture Select"},
+	{"ALC Sidetone Mux", "Stereo", "Right Capture Select"},
+	{"ALC Sidetone Mux", "Left", "Left Capture Select"},
+	{"ALC Sidetone Mux", "Right", "Right Capture Select"},
+
+	/* ADC's */
+	{"Left ADC", NULL, "Left Capture Select"},
+	{"Right ADC", NULL, "Right Capture Select"},
+
+	/* outputs */
+	{"MONOOUT", NULL, "Phone Mixer"},
+	{"HPOUTL", NULL, "Headphone PGA"},
+	{"Headphone PGA", NULL, "Left HP Mixer"},
+	{"HPOUTR", NULL, "Headphone PGA"},
+	{"Headphone PGA", NULL, "Right HP Mixer"},
+
+	/* mono hp mixer */
+	{"Mono HP Mixer", NULL, "Left HP Mixer"},
+	{"Mono HP Mixer", NULL, "Right HP Mixer"},
+
+	/* Out3 Mux */
+	{"Out3 Mux", "Left", "Left HP Mixer"},
+	{"Out3 Mux", "Mono", "Phone Mixer"},
+	{"Out3 Mux", "Left + Right", "Mono HP Mixer"},
+	{"Out 3 PGA", NULL, "Out3 Mux"},
+	{"OUT3", NULL, "Out 3 PGA"},
+
+	/* speaker Mux */
+	{"Speaker Mux", "Speaker Mix", "Speaker Mixer"},
+	{"Speaker Mux", "Headphone Mix", "Mono HP Mixer"},
+	{"Speaker PGA", NULL, "Speaker Mux"},
+	{"LOUT2", NULL, "Speaker PGA"},
+	{"ROUT2", NULL, "Speaker PGA"},
+
+	{NULL, NULL, NULL},
+};
+
+static int wm9712_add_widgets(struct snd_soc_codec *codec)
+{
+	int i;
+
+	for(i = 0; i < ARRAY_SIZE(wm9712_dapm_widgets); i++) {
+		snd_soc_dapm_new_control(codec, &wm9712_dapm_widgets[i]);
+	}
+
+	/* set up audio path audio_mapnects */
+	for(i = 0; audio_map[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, audio_map[i][0],
+			audio_map[i][1], audio_map[i][2]);
+	}
+
+	snd_soc_dapm_new_widgets(codec);
+	return 0;
+}
+
+static unsigned int ac97_read(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+
+	if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
+		reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 ||
+		reg == AC97_REC_GAIN)
+		return soc_ac97_ops.read(codec->ac97, reg);
+	else {
+		reg = reg >> 1;
+
+		if (reg > (ARRAY_SIZE(wm9712_reg)))
+			return -EIO;
+
+		return cache[reg];
+	}
+}
+
+static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int val)
+{
+	u16 *cache = codec->reg_cache;
+
+	soc_ac97_ops.write(codec->ac97, reg, val);
+	reg = reg >> 1;
+	if (reg <= (ARRAY_SIZE(wm9712_reg)))
+		cache[reg] = val;
+
+	return 0;
+}
+
+static int ac97_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	int reg;
+	u16 vra;
+
+	vra = ac97_read(codec, AC97_EXTENDED_STATUS);
+	ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		reg = AC97_PCM_FRONT_DAC_RATE;
+	else
+		reg = AC97_PCM_LR_ADC_RATE;
+
+	return ac97_write(codec, reg, runtime->rate);
+}
+
+static int ac97_aux_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	u16 vra, xsle;
+
+	vra = ac97_read(codec, AC97_EXTENDED_STATUS);
+	ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
+	xsle = ac97_read(codec, AC97_PCI_SID);
+	ac97_write(codec, AC97_PCI_SID, xsle | 0x8000);
+
+	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+		return -ENODEV;
+
+	return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate);
+}
+
+#define WM9712_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+struct snd_soc_codec_dai wm9712_dai[] = {
+{
+	.name = "AC97 HiFi",
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM9712_AC97_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM9712_AC97_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = {
+		.prepare = ac97_prepare,},
+},
+{
+	.name = "AC97 Aux",
+	.playback = {
+		.stream_name = "Aux Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = WM9712_AC97_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = {
+		.prepare = ac97_aux_prepare,},
+}
+};
+EXPORT_SYMBOL_GPL(wm9712_dai);
+
+static int wm9712_dapm_event(struct snd_soc_codec *codec, int event)
+{
+	u16 reg;
+
+	switch (event) {
+	case SNDRV_CTL_POWER_D0: /* full On */
+		/* liam - maybe enable thermal shutdown */
+		reg = ac97_read(codec, AC97_EXTENDED_MID) & 0xdfff;
+		ac97_write(codec, AC97_EXTENDED_MID, reg);
+		break;
+	case SNDRV_CTL_POWER_D1: /* partial On */
+	case SNDRV_CTL_POWER_D2: /* partial On */
+		break;
+	case SNDRV_CTL_POWER_D3hot: /* Off, with power */
+		/* enable master bias and vmid */
+		reg = ac97_read(codec, AC97_EXTENDED_MID) & 0xbbff;
+		ac97_write(codec, AC97_EXTENDED_MID, reg);
+		ac97_write(codec, AC97_POWERDOWN, 0x0000);
+		break;
+	case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+		/* disable everything including AC link */
+		ac97_write(codec, AC97_EXTENDED_MID, 0xffff);
+		ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
+		ac97_write(codec, AC97_POWERDOWN, 0xffff);
+		break;
+	}
+	codec->dapm_state = event;
+	return 0;
+}
+
+static int wm9712_reset(struct snd_soc_codec *codec, int try_warm)
+{
+	if (try_warm && soc_ac97_ops.warm_reset) {
+		soc_ac97_ops.warm_reset(codec->ac97);
+		if (!(ac97_read(codec, 0) & 0x8000))
+			return 1;
+	}
+
+	soc_ac97_ops.reset(codec->ac97);
+	if (ac97_read(codec, 0) & 0x8000)
+		goto err;
+	return 0;
+
+err:
+	printk(KERN_ERR "WM9712 AC97 reset failed\n");
+	return -EIO;
+}
+
+static int wm9712_soc_suspend(struct platform_device *pdev,
+	pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+	return 0;
+}
+
+static int wm9712_soc_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+	int i, ret;
+	u16 *cache = codec->reg_cache;
+
+	ret = wm9712_reset(codec, 1);
+	if (ret < 0){
+		printk(KERN_ERR "could not reset AC97 codec\n");
+		return ret;
+	}
+
+	wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+
+	if (ret == 0) {
+		/* Sync reg_cache with the hardware after cold reset */
+		for (i = 2; i < ARRAY_SIZE(wm9712_reg) << 1; i+=2) {
+			if (i == AC97_INT_PAGING || i == AC97_POWERDOWN ||
+				(i > 0x58 && i != 0x5c))
+				continue;
+			soc_ac97_ops.write(codec->ac97, i, cache[i>>1]);
+		}
+	}
+
+	if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0)
+		wm9712_dapm_event(codec, SNDRV_CTL_POWER_D0);
+
+	return ret;
+}
+
+static int wm9712_soc_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	int ret = 0;
+
+	printk(KERN_INFO "WM9711/WM9712 SoC Audio Codec %s\n", WM9712_VERSION);
+
+	socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (socdev->codec == NULL)
+		return -ENOMEM;
+	codec = socdev->codec;
+	mutex_init(&codec->mutex);
+
+	codec->reg_cache =
+		kzalloc(sizeof(u16) * ARRAY_SIZE(wm9712_reg), GFP_KERNEL);
+	if (codec->reg_cache == NULL) {
+		ret = -ENOMEM;
+		goto cache_err;
+	}
+	memcpy(codec->reg_cache, wm9712_reg, sizeof(u16) * ARRAY_SIZE(wm9712_reg));
+	codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(wm9712_reg);
+	codec->reg_cache_step = 2;
+
+	codec->name = "WM9712";
+	codec->owner = THIS_MODULE;
+	codec->dai = wm9712_dai;
+	codec->num_dai = ARRAY_SIZE(wm9712_dai);
+	codec->write = ac97_write;
+	codec->read = ac97_read;
+	codec->dapm_event = wm9712_dapm_event;
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+	if (ret < 0) {
+		printk(KERN_ERR "wm9712: failed to register AC97 codec\n");
+		goto codec_err;
+	}
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0)
+		goto pcm_err;
+
+	ret = wm9712_reset(codec, 0);
+	if (ret < 0) {
+		printk(KERN_ERR "AC97 link error\n");
+		goto reset_err;
+	}
+
+	/* set alc mux to none */
+	ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000);
+
+	wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+	wm9712_add_controls(codec);
+	wm9712_add_widgets(codec);
+	ret = snd_soc_register_card(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "wm9712: failed to register card\n");
+		goto reset_err;
+	}
+
+	return 0;
+
+reset_err:
+	snd_soc_free_pcms(socdev);
+
+pcm_err:
+	snd_soc_free_ac97_codec(codec);
+
+codec_err:
+	kfree(codec->reg_cache);
+
+cache_err:
+	kfree(socdev->codec);
+	socdev->codec = NULL;
+	return ret;
+}
+
+static int wm9712_soc_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	if (codec == NULL)
+		return 0;
+
+	snd_soc_dapm_free(socdev);
+	snd_soc_free_pcms(socdev);
+	snd_soc_free_ac97_codec(codec);
+	kfree(codec->reg_cache);
+	kfree(codec);
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm9712 = {
+	.probe = 	wm9712_soc_probe,
+	.remove = 	wm9712_soc_remove,
+	.suspend =	wm9712_soc_suspend,
+	.resume =	wm9712_soc_resume,
+};
+
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm9712);
+
+MODULE_DESCRIPTION("ASoC WM9711/WM9712 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm9712.h b/sound/soc/codecs/wm9712.h
new file mode 100644
index 0000000..719105d
--- /dev/null
+++ b/sound/soc/codecs/wm9712.h
@@ -0,0 +1,14 @@
+/*
+ * wm9712.h  --  WM9712 Soc Audio driver
+ */
+
+#ifndef _WM9712_H
+#define _WM9712_H
+
+#define WM9712_DAI_AC97_HIFI	0
+#define WM9712_DAI_AC97_AUX		1
+
+extern struct snd_soc_codec_dai wm9712_dai[2];
+extern struct snd_soc_codec_device soc_codec_dev_wm9712;
+
+#endif
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
new file mode 100644
index 0000000..579e1c8
--- /dev/null
+++ b/sound/soc/pxa/Kconfig
@@ -0,0 +1,60 @@
+menu "SoC Audio for the Intel PXA2xx"
+
+config SND_PXA2XX_SOC
+	tristate "SoC Audio for the Intel PXA2xx chip"
+	depends on ARCH_PXA && SND
+	select SND_PCM
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the PXA2xx AC97, I2S or SSP interface. You will also need
+	  to select the audio interfaces to support below.
+
+config SND_PXA2XX_AC97
+	tristate
+	select SND_AC97_CODEC
+
+config SND_PXA2XX_SOC_AC97
+	tristate
+	select AC97_BUS
+	select SND_SOC_AC97_BUS
+
+config SND_PXA2XX_SOC_I2S
+	tristate
+
+config SND_PXA2XX_SOC_CORGI
+	tristate "SoC Audio support for Sharp Zaurus SL-C7x0"
+	depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx
+	select SND_PXA2XX_SOC_I2S
+	select SND_SOC_WM8731
+	help
+	  Say Y if you want to add support for SoC audio on Sharp
+	  Zaurus SL-C7x0 models (Corgi, Shepherd, Husky).
+
+config SND_PXA2XX_SOC_SPITZ
+	tristate "SoC Audio support for Sharp Zaurus SL-Cxx00"
+	depends on SND_PXA2XX_SOC && PXA_SHARP_Cxx00
+	select SND_PXA2XX_SOC_I2S
+	select SND_SOC_WM8750
+	help
+	  Say Y if you want to add support for SoC audio on Sharp
+	  Zaurus SL-Cxx00 models (Spitz, Borzoi and Akita).
+
+config SND_PXA2XX_SOC_POODLE
+	tristate "SoC Audio support for Poodle"
+	depends on SND_PXA2XX_SOC && MACH_POODLE
+	select SND_PXA2XX_SOC_I2S
+	select SND_SOC_WM8731
+	help
+	  Say Y if you want to add support for SoC audio on Sharp
+	  Zaurus SL-5600 model (Poodle).
+
+config SND_PXA2XX_SOC_TOSA
+	tristate "SoC AC97 Audio support for Tosa"
+	depends on SND_PXA2XX_SOC && MACH_TOSA
+	select SND_PXA2XX_SOC_AC97
+	select SND_SOC_WM9712
+	help
+	  Say Y if you want to add support for SoC audio on Sharp
+	  Zaurus SL-C6000x models (Tosa).
+
+endmenu
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
new file mode 100644
index 0000000..78e0d6b
--- /dev/null
+++ b/sound/soc/pxa/Makefile
@@ -0,0 +1,20 @@
+# PXA Platform Support
+snd-soc-pxa2xx-objs := pxa2xx-pcm.o
+snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o
+snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o
+
+obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o
+obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o
+obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o
+
+# PXA Machine Support
+snd-soc-corgi-objs := corgi.o
+snd-soc-poodle-objs := poodle.o
+snd-soc-tosa-objs := tosa.o
+snd-soc-spitz-objs := spitz.o
+
+obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o
+obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o
+obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o
+obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o
+
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
new file mode 100644
index 0000000..5ee51a9
--- /dev/null
+++ b/sound/soc/pxa/corgi.c
@@ -0,0 +1,383 @@
+/*
+ * corgi.c  --  SoC audio for Corgi
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *          Richard Purdie <richard@openedhand.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    30th Nov 2005   Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware/scoop.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/corgi.h>
+#include <asm/arch/audio.h>
+
+#include "../codecs/wm8731.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-i2s.h"
+
+#define CORGI_HP        0
+#define CORGI_MIC       1
+#define CORGI_LINE      2
+#define CORGI_HEADSET   3
+#define CORGI_HP_OFF    4
+#define CORGI_SPK_ON    0
+#define CORGI_SPK_OFF   1
+
+ /* audio clock in Hz - rounded from 12.235MHz */
+#define CORGI_AUDIO_CLOCK 12288000
+
+static int corgi_jack_func;
+static int corgi_spk_func;
+
+static void corgi_ext_control(struct snd_soc_codec *codec)
+{
+	int spk = 0, mic = 0, line = 0, hp = 0, hs = 0;
+
+	/* set up jack connection */
+	switch (corgi_jack_func) {
+	case CORGI_HP:
+		hp = 1;
+		/* set = unmute headphone */
+		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
+		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+		break;
+	case CORGI_MIC:
+		mic = 1;
+		/* reset = mute headphone */
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+		break;
+	case CORGI_LINE:
+		line = 1;
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+		break;
+	case CORGI_HEADSET:
+		hs = 1;
+		mic = 1;
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
+		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+		break;
+	}
+
+	if (corgi_spk_func == CORGI_SPK_ON)
+		spk = 1;
+
+	/* set the enpoints to their new connetion states */
+	snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk);
+	snd_soc_dapm_set_endpoint(codec, "Mic Jack", mic);
+	snd_soc_dapm_set_endpoint(codec, "Line Jack", line);
+	snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp);
+	snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs);
+
+	/* signal a DAPM event */
+	snd_soc_dapm_sync_endpoints(codec);
+}
+
+static int corgi_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->socdev->codec;
+
+	/* check the jack status at stream startup */
+	corgi_ext_control(codec);
+	return 0;
+}
+
+/* we need to unmute the HP at shutdown as the mute burns power on corgi */
+static int corgi_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->socdev->codec;
+
+	/* set = unmute headphone */
+	set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
+	set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+	return 0;
+}
+
+static int corgi_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	unsigned int clk = 0;
+	int ret = 0;
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+		clk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+		clk = 11289600;
+		break;
+	}
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set the codec system clock for DAC and ADC */
+	ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set the I2S system clock as input (unused) */
+	ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops corgi_ops = {
+	.startup = corgi_startup,
+	.hw_params = corgi_hw_params,
+	.shutdown = corgi_shutdown,
+};
+
+static int corgi_get_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = corgi_jack_func;
+	return 0;
+}
+
+static int corgi_set_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	if (corgi_jack_func == ucontrol->value.integer.value[0])
+		return 0;
+
+	corgi_jack_func = ucontrol->value.integer.value[0];
+	corgi_ext_control(codec);
+	return 1;
+}
+
+static int corgi_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = corgi_spk_func;
+	return 0;
+}
+
+static int corgi_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+
+	if (corgi_spk_func == ucontrol->value.integer.value[0])
+		return 0;
+
+	corgi_spk_func = ucontrol->value.integer.value[0];
+	corgi_ext_control(codec);
+	return 1;
+}
+
+static int corgi_amp_event(struct snd_soc_dapm_widget *w, int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
+	else
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
+
+	return 0;
+}
+
+static int corgi_mic_event(struct snd_soc_dapm_widget *w, int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
+	else
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
+
+	return 0;
+}
+
+/* corgi machine dapm widgets */
+static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
+SND_SOC_DAPM_HP("Headphone Jack", NULL),
+SND_SOC_DAPM_MIC("Mic Jack", corgi_mic_event),
+SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event),
+SND_SOC_DAPM_LINE("Line Jack", NULL),
+SND_SOC_DAPM_HP("Headset Jack", NULL),
+};
+
+/* Corgi machine audio map (connections to the codec pins) */
+static const char *audio_map[][3] = {
+
+	/* headset Jack  - in = micin, out = LHPOUT*/
+	{"Headset Jack", NULL, "LHPOUT"},
+
+	/* headphone connected to LHPOUT1, RHPOUT1 */
+	{"Headphone Jack", NULL, "LHPOUT"},
+	{"Headphone Jack", NULL, "RHPOUT"},
+
+	/* speaker connected to LOUT, ROUT */
+	{"Ext Spk", NULL, "ROUT"},
+	{"Ext Spk", NULL, "LOUT"},
+
+	/* mic is connected to MICIN (via right channel of headphone jack) */
+	{"MICIN", NULL, "Mic Jack"},
+
+	/* Same as the above but no mic bias for line signals */
+	{"MICIN", NULL, "Line Jack"},
+
+	{NULL, NULL, NULL},
+};
+
+static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
+	"Off"};
+static const char *spk_function[] = {"On", "Off"};
+static const struct soc_enum corgi_enum[] = {
+	SOC_ENUM_SINGLE_EXT(5, jack_function),
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+};
+
+static const struct snd_kcontrol_new wm8731_corgi_controls[] = {
+	SOC_ENUM_EXT("Jack Function", corgi_enum[0], corgi_get_jack,
+		corgi_set_jack),
+	SOC_ENUM_EXT("Speaker Function", corgi_enum[1], corgi_get_spk,
+		corgi_set_spk),
+};
+
+/*
+ * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device
+ */
+static int corgi_wm8731_init(struct snd_soc_codec *codec)
+{
+	int i, err;
+
+	snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0);
+	snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0);
+
+	/* Add corgi specific controls */
+	for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) {
+		err = snd_ctl_add(codec->card,
+			snd_soc_cnew(&wm8731_corgi_controls[i],codec, NULL));
+		if (err < 0)
+			return err;
+	}
+
+	/* Add corgi specific widgets */
+	for(i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) {
+		snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]);
+	}
+
+	/* Set up corgi specific audio path audio_map */
+	for(i = 0; audio_map[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, audio_map[i][0],
+			audio_map[i][1], audio_map[i][2]);
+	}
+
+	snd_soc_dapm_sync_endpoints(codec);
+	return 0;
+}
+
+/* corgi digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link corgi_dai = {
+	.name = "WM8731",
+	.stream_name = "WM8731",
+	.cpu_dai = &pxa_i2s_dai,
+	.codec_dai = &wm8731_dai,
+	.init = corgi_wm8731_init,
+	.ops = &corgi_ops,
+};
+
+/* corgi audio machine driver */
+static struct snd_soc_machine snd_soc_machine_corgi = {
+	.name = "Corgi",
+	.dai_link = &corgi_dai,
+	.num_links = 1,
+};
+
+/* corgi audio private data */
+static struct wm8731_setup_data corgi_wm8731_setup = {
+	.i2c_address = 0x1b,
+};
+
+/* corgi audio subsystem */
+static struct snd_soc_device corgi_snd_devdata = {
+	.machine = &snd_soc_machine_corgi,
+	.platform = &pxa2xx_soc_platform,
+	.codec_dev = &soc_codec_dev_wm8731,
+	.codec_data = &corgi_wm8731_setup,
+};
+
+static struct platform_device *corgi_snd_device;
+
+static int __init corgi_init(void)
+{
+	int ret;
+
+	if (!(machine_is_corgi() || machine_is_shepherd() || machine_is_husky()))
+		return -ENODEV;
+
+	corgi_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!corgi_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(corgi_snd_device, &corgi_snd_devdata);
+	corgi_snd_devdata.dev = &corgi_snd_device->dev;
+	ret = platform_device_add(corgi_snd_device);
+
+	if (ret)
+		platform_device_put(corgi_snd_device);
+
+	return ret;
+}
+
+static void __exit corgi_exit(void)
+{
+	platform_device_unregister(corgi_snd_device);
+}
+
+module_init(corgi_init);
+module_exit(corgi_exit);
+
+/* Module information */
+MODULE_AUTHOR("Richard Purdie");
+MODULE_DESCRIPTION("ALSA SoC Corgi");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
new file mode 100644
index 0000000..0915cf7
--- /dev/null
+++ b/sound/soc/pxa/poodle.c
@@ -0,0 +1,352 @@
+/*
+ * poodle.c  --  SoC audio for Poodle
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *          Richard Purdie <richard@openedhand.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware/locomo.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/poodle.h>
+#include <asm/arch/audio.h>
+
+#include "../codecs/wm8731.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-i2s.h"
+
+#define POODLE_HP        1
+#define POODLE_HP_OFF    0
+#define POODLE_SPK_ON    1
+#define POODLE_SPK_OFF   0
+
+ /* audio clock in Hz - rounded from 12.235MHz */
+#define POODLE_AUDIO_CLOCK 12288000
+
+static int poodle_jack_func;
+static int poodle_spk_func;
+
+static void poodle_ext_control(struct snd_soc_codec *codec)
+{
+	int spk = 0;
+
+	/* set up jack connection */
+	if (poodle_jack_func == POODLE_HP) {
+		/* set = unmute headphone */
+		locomo_gpio_write(&poodle_locomo_device.dev,
+			POODLE_LOCOMO_GPIO_MUTE_L, 1);
+		locomo_gpio_write(&poodle_locomo_device.dev,
+			POODLE_LOCOMO_GPIO_MUTE_R, 1);
+		snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1);
+	} else {
+		locomo_gpio_write(&poodle_locomo_device.dev,
+			POODLE_LOCOMO_GPIO_MUTE_L, 0);
+		locomo_gpio_write(&poodle_locomo_device.dev,
+			POODLE_LOCOMO_GPIO_MUTE_R, 0);
+		snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0);
+	}
+
+	if (poodle_spk_func == POODLE_SPK_ON)
+		spk = 1;
+
+	/* set the enpoints to their new connetion states */
+	snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk);
+
+	/* signal a DAPM event */
+	snd_soc_dapm_sync_endpoints(codec);
+}
+
+static int poodle_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->socdev->codec;
+
+	/* check the jack status at stream startup */
+	poodle_ext_control(codec);
+	return 0;
+}
+
+/* we need to unmute the HP at shutdown as the mute burns power on poodle */
+static int poodle_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->socdev->codec;
+
+	/* set = unmute headphone */
+	locomo_gpio_write(&poodle_locomo_device.dev,
+		POODLE_LOCOMO_GPIO_MUTE_L, 1);
+	locomo_gpio_write(&poodle_locomo_device.dev,
+		POODLE_LOCOMO_GPIO_MUTE_R, 1);
+	return 0;
+}
+
+static int poodle_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	unsigned int clk = 0;
+	int ret = 0;
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+		clk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+		clk = 11289600;
+		break;
+	}
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set the codec system clock for DAC and ADC */
+	ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set the I2S system clock as input (unused) */
+	ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops poodle_ops = {
+	.startup = poodle_startup,
+	.hw_params = poodle_hw_params,
+	.shutdown = poodle_shutdown,
+};
+
+static int poodle_get_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = poodle_jack_func;
+	return 0;
+}
+
+static int poodle_set_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+
+	if (poodle_jack_func == ucontrol->value.integer.value[0])
+		return 0;
+
+	poodle_jack_func = ucontrol->value.integer.value[0];
+	poodle_ext_control(codec);
+	return 1;
+}
+
+static int poodle_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = poodle_spk_func;
+	return 0;
+}
+
+static int poodle_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+
+	if (poodle_spk_func == ucontrol->value.integer.value[0])
+		return 0;
+
+	poodle_spk_func = ucontrol->value.integer.value[0];
+	poodle_ext_control(codec);
+	return 1;
+}
+
+static int poodle_amp_event(struct snd_soc_dapm_widget *w, int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		locomo_gpio_write(&poodle_locomo_device.dev,
+			POODLE_LOCOMO_GPIO_AMP_ON, 0);
+	else
+		locomo_gpio_write(&poodle_locomo_device.dev,
+			POODLE_LOCOMO_GPIO_AMP_ON, 1);
+
+	return 0;
+}
+
+/* poodle machine dapm widgets */
+static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
+SND_SOC_DAPM_HP("Headphone Jack", NULL),
+SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event),
+};
+
+/* Corgi machine audio_mapnections to the codec pins */
+static const char *audio_map[][3] = {
+
+	/* headphone connected to LHPOUT1, RHPOUT1 */
+	{"Headphone Jack", NULL, "LHPOUT"},
+	{"Headphone Jack", NULL, "RHPOUT"},
+
+	/* speaker connected to LOUT, ROUT */
+	{"Ext Spk", NULL, "ROUT"},
+	{"Ext Spk", NULL, "LOUT"},
+
+	{NULL, NULL, NULL},
+};
+
+static const char *jack_function[] = {"Off", "Headphone"};
+static const char *spk_function[] = {"Off", "On"};
+static const struct soc_enum poodle_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, jack_function),
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+};
+
+static const snd_kcontrol_new_t wm8731_poodle_controls[] = {
+	SOC_ENUM_EXT("Jack Function", poodle_enum[0], poodle_get_jack,
+		poodle_set_jack),
+	SOC_ENUM_EXT("Speaker Function", poodle_enum[1], poodle_get_spk,
+		poodle_set_spk),
+};
+
+/*
+ * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device
+ */
+static int poodle_wm8731_init(struct snd_soc_codec *codec)
+{
+	int i, err;
+
+	snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0);
+	snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0);
+	snd_soc_dapm_set_endpoint(codec, "MICIN", 1);
+
+	/* Add poodle specific controls */
+	for (i = 0; i < ARRAY_SIZE(wm8731_poodle_controls); i++) {
+		err = snd_ctl_add(codec->card,
+			snd_soc_cnew(&wm8731_poodle_controls[i],codec, NULL));
+		if (err < 0)
+			return err;
+	}
+
+	/* Add poodle specific widgets */
+	for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) {
+		snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]);
+	}
+
+	/* Set up poodle specific audio path audio_map */
+	for (i = 0; audio_map[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, audio_map[i][0],
+			audio_map[i][1], audio_map[i][2]);
+	}
+
+	snd_soc_dapm_sync_endpoints(codec);
+	return 0;
+}
+
+/* poodle digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link poodle_dai = {
+	.name = "WM8731",
+	.stream_name = "WM8731",
+	.cpu_dai = &pxa_i2s_dai,
+	.codec_dai = &wm8731_dai,
+	.init = poodle_wm8731_init,
+	.ops = &poodle_ops,
+};
+
+/* poodle audio machine driver */
+static struct snd_soc_machine snd_soc_machine_poodle = {
+	.name = "Poodle",
+	.dai_link = &poodle_dai,
+	.num_links = 1,
+};
+
+/* poodle audio private data */
+static struct wm8731_setup_data poodle_wm8731_setup = {
+	.i2c_address = 0x1b,
+};
+
+/* poodle audio subsystem */
+static struct snd_soc_device poodle_snd_devdata = {
+	.machine = &snd_soc_machine_poodle,
+	.platform = &pxa2xx_soc_platform,
+	.codec_dev = &soc_codec_dev_wm8731,
+	.codec_data = &poodle_wm8731_setup,
+};
+
+static struct platform_device *poodle_snd_device;
+
+static int __init poodle_init(void)
+{
+	int ret;
+
+	if (!machine_is_poodle())
+		return -ENODEV;
+
+	locomo_gpio_set_dir(&poodle_locomo_device.dev,
+		POODLE_LOCOMO_GPIO_AMP_ON, 0);
+	/* should we mute HP at startup - burning power ?*/
+	locomo_gpio_set_dir(&poodle_locomo_device.dev,
+		POODLE_LOCOMO_GPIO_MUTE_L, 0);
+	locomo_gpio_set_dir(&poodle_locomo_device.dev,
+		POODLE_LOCOMO_GPIO_MUTE_R, 0);
+
+	poodle_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!poodle_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(poodle_snd_device, &poodle_snd_devdata);
+	poodle_snd_devdata.dev = &poodle_snd_device->dev;
+	ret = platform_device_add(poodle_snd_device);
+
+	if (ret)
+		platform_device_put(poodle_snd_device);
+
+	return ret;
+}
+
+static void __exit poodle_exit(void)
+{
+	platform_device_unregister(poodle_snd_device);
+}
+
+module_init(poodle_init);
+module_exit(poodle_exit);
+
+/* Module information */
+MODULE_AUTHOR("Richard Purdie");
+MODULE_DESCRIPTION("ALSA SoC Poodle");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
new file mode 100644
index 0000000..1bbbeff
--- /dev/null
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -0,0 +1,431 @@
+/*
+ * linux/sound/pxa2xx-ac97.c -- AC97 support for the Intel PXA2xx chip.
+ *
+ * Author:	Nicolas Pitre
+ * Created:	Dec 02, 2004
+ * Copyright:	MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/irq.h>
+#include <linux/mutex.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/audio.h>
+
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+
+static DEFINE_MUTEX(car_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
+static volatile long gsr_bits;
+
+/*
+ * Beware PXA27x bugs:
+ *
+ *   o Slot 12 read from modem space will hang controller.
+ *   o CDONE, SDONE interrupt fails after any slot 12 IO.
+ *
+ * We therefore have an hybrid approach for waiting on SDONE (interrupt or
+ * 1 jiffy timeout if interrupt never comes).
+ */
+
+static unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97,
+	unsigned short reg)
+{
+	unsigned short val = -1;
+	volatile u32 *reg_addr;
+
+	mutex_lock(&car_mutex);
+
+	/* set up primary or secondary codec/modem space */
+#ifdef CONFIG_PXA27x
+	reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
+#else
+	if (reg == AC97_GPIO_STATUS)
+		reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE;
+	else
+		reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
+#endif
+	reg_addr += (reg >> 1);
+
+#ifndef CONFIG_PXA27x
+	if (reg == AC97_GPIO_STATUS) {
+		/* read from controller cache */
+		val = *reg_addr;
+		goto out;
+	}
+#endif
+
+	/* start read access across the ac97 link */
+	GSR = GSR_CDONE | GSR_SDONE;
+	gsr_bits = 0;
+	val = *reg_addr;
+
+	wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
+	if (!((GSR | gsr_bits) & GSR_SDONE)) {
+		printk(KERN_ERR "%s: read error (ac97_reg=%x GSR=%#lx)\n",
+				__FUNCTION__, reg, GSR | gsr_bits);
+		val = -1;
+		goto out;
+	}
+
+	/* valid data now */
+	GSR = GSR_CDONE | GSR_SDONE;
+	gsr_bits = 0;
+	val = *reg_addr;
+	/* but we've just started another cycle... */
+	wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
+
+out:	mutex_unlock(&car_mutex);
+	return val;
+}
+
+static void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+	unsigned short val)
+{
+	volatile u32 *reg_addr;
+
+	mutex_lock(&car_mutex);
+
+	/* set up primary or secondary codec/modem space */
+#ifdef CONFIG_PXA27x
+	reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
+#else
+	if (reg == AC97_GPIO_STATUS)
+		reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE;
+	else
+		reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
+#endif
+	reg_addr += (reg >> 1);
+
+	GSR = GSR_CDONE | GSR_SDONE;
+	gsr_bits = 0;
+	*reg_addr = val;
+	wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1);
+	if (!((GSR | gsr_bits) & GSR_CDONE))
+		printk(KERN_ERR "%s: write error (ac97_reg=%x GSR=%#lx)\n",
+				__FUNCTION__, reg, GSR | gsr_bits);
+
+	mutex_unlock(&car_mutex);
+}
+
+static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+	gsr_bits = 0;
+
+#ifdef CONFIG_PXA27x
+	/* warm reset broken on Bulverde,
+	   so manually keep AC97 reset high */
+	pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH);
+	udelay(10);
+	GCR |= GCR_WARM_RST;
+	pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+	udelay(500);
+#else
+	GCR |= GCR_WARM_RST | GCR_PRIRDY_IEN | GCR_SECRDY_IEN;
+	wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
+#endif
+
+	if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)))
+		printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n",
+				 __FUNCTION__, gsr_bits);
+
+	GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
+	GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
+}
+
+static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+	GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
+	GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
+
+	gsr_bits = 0;
+#ifdef CONFIG_PXA27x
+	/* PXA27x Developers Manual section 13.5.2.2.1 */
+	pxa_set_cken(1 << 31, 1);
+	udelay(5);
+	pxa_set_cken(1 << 31, 0);
+	GCR = GCR_COLD_RST;
+	udelay(50);
+#else
+	GCR = GCR_COLD_RST;
+	GCR |= GCR_CDONE_IE|GCR_SDONE_IE;
+	wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
+#endif
+
+	if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)))
+		printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n",
+				 __FUNCTION__, gsr_bits);
+
+	GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
+	GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
+}
+
+static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id)
+{
+	long status;
+
+	status = GSR;
+	if (status) {
+		GSR = status;
+		gsr_bits |= status;
+		wake_up(&gsr_wq);
+
+#ifdef CONFIG_PXA27x
+		/* Although we don't use those we still need to clear them
+		   since they tend to spuriously trigger when MMC is used
+		   (hardware bug? go figure)... */
+		MISR = MISR_EOC;
+		PISR = PISR_EOC;
+		MCSR = MCSR_EOC;
+#endif
+
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+	.read	= pxa2xx_ac97_read,
+	.write	= pxa2xx_ac97_write,
+	.warm_reset	= pxa2xx_ac97_warm_reset,
+	.reset	= pxa2xx_ac97_cold_reset,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = {
+	.name			= "AC97 PCM Stereo out",
+	.dev_addr		= __PREG(PCDR),
+	.drcmr			= &DRCMRTXPCDR,
+	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
+				  DCMD_BURST32 | DCMD_WIDTH4,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_in = {
+	.name			= "AC97 PCM Stereo in",
+	.dev_addr		= __PREG(PCDR),
+	.drcmr			= &DRCMRRXPCDR,
+	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
+				  DCMD_BURST32 | DCMD_WIDTH4,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_out = {
+	.name			= "AC97 Aux PCM (Slot 5) Mono out",
+	.dev_addr		= __PREG(MODR),
+	.drcmr			= &DRCMRTXMODR,
+	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
+				  DCMD_BURST16 | DCMD_WIDTH2,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_in = {
+	.name			= "AC97 Aux PCM (Slot 5) Mono in",
+	.dev_addr		= __PREG(MODR),
+	.drcmr			= &DRCMRRXMODR,
+	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
+				  DCMD_BURST16 | DCMD_WIDTH2,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = {
+	.name			= "AC97 Mic PCM (Slot 6) Mono in",
+	.dev_addr		= __PREG(MCDR),
+	.drcmr			= &DRCMRRXMCDR,
+	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
+				  DCMD_BURST16 | DCMD_WIDTH2,
+};
+
+#ifdef CONFIG_PM
+static int pxa2xx_ac97_suspend(struct platform_device *pdev,
+	struct snd_soc_cpu_dai *dai)
+{
+	GCR |= GCR_ACLINK_OFF;
+	pxa_set_cken(CKEN2_AC97, 0);
+	return 0;
+}
+
+static int pxa2xx_ac97_resume(struct platform_device *pdev,
+	struct snd_soc_cpu_dai *dai)
+{
+	pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
+	pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
+	pxa_gpio_mode(GPIO28_BITCLK_AC97_MD);
+	pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
+#ifdef CONFIG_PXA27x
+	/* Use GPIO 113 as AC97 Reset on Bulverde */
+	pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+#endif
+	pxa_set_cken(CKEN2_AC97, 1);
+	return 0;
+}
+
+#else
+#define pxa2xx_ac97_suspend	NULL
+#define pxa2xx_ac97_resume	NULL
+#endif
+
+static int pxa2xx_ac97_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, IRQF_DISABLED, "AC97", NULL);
+	if (ret < 0)
+		goto err;
+
+	pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
+	pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
+	pxa_gpio_mode(GPIO28_BITCLK_AC97_MD);
+	pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
+#ifdef CONFIG_PXA27x
+	/* Use GPIO 113 as AC97 Reset on Bulverde */
+	pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+#endif
+	pxa_set_cken(CKEN2_AC97, 1);
+	return 0;
+
+ err:
+	if (CKEN & CKEN2_AC97) {
+		GCR |= GCR_ACLINK_OFF;
+		free_irq(IRQ_AC97, NULL);
+		pxa_set_cken(CKEN2_AC97, 0);
+	}
+	return ret;
+}
+
+static void pxa2xx_ac97_remove(struct platform_device *pdev)
+{
+	GCR |= GCR_ACLINK_OFF;
+	free_irq(IRQ_AC97, NULL);
+	pxa_set_cken(CKEN2_AC97, 0);
+}
+
+static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out;
+	else
+		cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_in;
+
+	return 0;
+}
+
+static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out;
+	else
+		cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_in;
+
+	return 0;
+}
+
+static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return -ENODEV;
+	else
+		cpu_dai->dma_data = &pxa2xx_ac97_pcm_mic_mono_in;
+
+	return 0;
+}
+
+#define PXA2XX_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
+		SNDRV_PCM_RATE_48000)
+
+/*
+ * There is only 1 physical AC97 interface for pxa2xx, but it
+ * has extra fifo's that can be used for aux DACs and ADCs.
+ */
+struct snd_soc_cpu_dai pxa_ac97_dai[] = {
+{
+	.name = "pxa2xx-ac97",
+	.id = 0,
+	.type = SND_SOC_DAI_AC97,
+	.probe = pxa2xx_ac97_probe,
+	.remove = pxa2xx_ac97_remove,
+	.suspend = pxa2xx_ac97_suspend,
+	.resume = pxa2xx_ac97_resume,
+	.playback = {
+		.stream_name = "AC97 Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = PXA2XX_AC97_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.capture = {
+		.stream_name = "AC97 Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = PXA2XX_AC97_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = {
+		.hw_params = pxa2xx_ac97_hw_params,},
+},
+{
+	.name = "pxa2xx-ac97-aux",
+	.id = 1,
+	.type = SND_SOC_DAI_AC97,
+	.playback = {
+		.stream_name = "AC97 Aux Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = PXA2XX_AC97_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.capture = {
+		.stream_name = "AC97 Aux Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = PXA2XX_AC97_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = {
+		.hw_params = pxa2xx_ac97_hw_aux_params,},
+},
+{
+	.name = "pxa2xx-ac97-mic",
+	.id = 2,
+	.type = SND_SOC_DAI_AC97,
+	.capture = {
+		.stream_name = "AC97 Mic Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = PXA2XX_AC97_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = {
+		.hw_params = pxa2xx_ac97_hw_mic_params,},
+},
+};
+
+EXPORT_SYMBOL_GPL(pxa_ac97_dai);
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+MODULE_AUTHOR("Nicolas Pitre");
+MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/pxa2xx-ac97.h b/sound/soc/pxa/pxa2xx-ac97.h
new file mode 100644
index 0000000..4c4b882
--- /dev/null
+++ b/sound/soc/pxa/pxa2xx-ac97.h
@@ -0,0 +1,22 @@
+/*
+ * linux/sound/arm/pxa2xx-ac97.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _PXA2XX_AC97_H
+#define _PXA2XX_AC97_H
+
+/* pxa2xx DAI ID's */
+#define PXA2XX_DAI_AC97_HIFI	0
+#define PXA2XX_DAI_AC97_AUX		1
+#define PXA2XX_DAI_AC97_MIC		2
+
+extern struct snd_soc_cpu_dai pxa_ac97_dai[3];
+
+/* platform data */
+extern struct snd_ac97_bus_ops pxa2xx_ac97_ops;
+
+#endif
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
new file mode 100644
index 0000000..575a613
--- /dev/null
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -0,0 +1,318 @@
+/*
+ * pxa2xx-i2s.c  --  ALSA Soc Audio Layer
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    12th Aug 2005   Initial version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/audio.h>
+
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-i2s.h"
+
+struct pxa_i2s_port {
+	u32 sadiv;
+	u32 sacr0;
+	u32 sacr1;
+	u32 saimr;
+	int master;
+	u32 fmt;
+};
+static struct pxa_i2s_port pxa_i2s;
+
+static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = {
+	.name			= "I2S PCM Stereo out",
+	.dev_addr		= __PREG(SADR),
+	.drcmr			= &DRCMRTXSADR,
+	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
+				  DCMD_BURST32 | DCMD_WIDTH4,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = {
+	.name			= "I2S PCM Stereo in",
+	.dev_addr		= __PREG(SADR),
+	.drcmr			= &DRCMRRXSADR,
+	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
+				  DCMD_BURST32 | DCMD_WIDTH4,
+};
+
+static struct pxa2xx_gpio gpio_bus[] = {
+	{ /* I2S SoC Slave */
+		.rx = GPIO29_SDATA_IN_I2S_MD,
+		.tx = GPIO30_SDATA_OUT_I2S_MD,
+		.clk = GPIO28_BITCLK_IN_I2S_MD,
+		.frm = GPIO31_SYNC_I2S_MD,
+	},
+	{ /* I2S SoC Master */
+#ifdef CONFIG_PXA27x
+		.sys = GPIO113_I2S_SYSCLK_MD,
+#else
+		.sys = GPIO32_SYSCLK_I2S_MD,
+#endif
+		.rx = GPIO29_SDATA_IN_I2S_MD,
+		.tx = GPIO30_SDATA_OUT_I2S_MD,
+		.clk = GPIO28_BITCLK_OUT_I2S_MD,
+		.frm = GPIO31_SYNC_I2S_MD,
+	},
+};
+
+static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+	if (!cpu_dai->active) {
+		SACR0 |= SACR0_RST;
+		SACR0 = 0;
+	}
+
+	return 0;
+}
+
+/* wait for I2S controller to be ready */
+static int pxa_i2s_wait(void)
+{
+	int i;
+
+	/* flush the Rx FIFO */
+	for(i = 0; i < 16; i++)
+		SADR;
+	return 0;
+}
+
+static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai,
+		unsigned int fmt)
+{
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		pxa_i2s.fmt = 0;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		pxa_i2s.fmt = SACR1_AMSL;
+		break;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		pxa_i2s.master = 1;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		pxa_i2s.master = 0;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	if (clk_id != PXA2XX_I2S_SYSCLK)
+		return -ENODEV;
+
+	if (pxa_i2s.master && dir == SND_SOC_CLOCK_OUT)
+		pxa_gpio_mode(gpio_bus[pxa_i2s.master].sys);
+
+	return 0;
+}
+
+static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+	pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx);
+	pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx);
+	pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm);
+	pxa_gpio_mode(gpio_bus[pxa_i2s.master].clk);
+	pxa_set_cken(CKEN8_I2S, 1);
+	pxa_i2s_wait();
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out;
+	else
+		cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in;
+
+	/* is port used by another stream */
+	if (!(SACR0 & SACR0_ENB)) {
+
+		SACR0 = 0;
+		SACR1 = 0;
+		if (pxa_i2s.master)
+			SACR0 |= SACR0_BCKD;
+
+		SACR0 |= SACR0_RFTH(14) | SACR0_TFTH(1);
+		SACR1 |= pxa_i2s.fmt;
+	}
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		SAIMR |= SAIMR_TFS;
+	else
+		SAIMR |= SAIMR_RFS;
+
+	switch (params_rate(params)) {
+	case 8000:
+		SADIV = 0x48;
+		break;
+	case 11025:
+		SADIV = 0x34;
+		break;
+	case 16000:
+		SADIV = 0x24;
+		break;
+	case 22050:
+		SADIV = 0x1a;
+		break;
+	case 44100:
+		SADIV = 0xd;
+		break;
+	case 48000:
+		SADIV = 0xc;
+		break;
+	case 96000: /* not in manual and possibly slightly inaccurate */
+		SADIV = 0x6;
+		break;
+	}
+
+	return 0;
+}
+
+static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		SACR0 |= SACR0_ENB;
+		break;
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream)
+{
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		SACR1 |= SACR1_DRPL;
+		SAIMR &= ~SAIMR_TFS;
+	} else {
+		SACR1 |= SACR1_DREC;
+		SAIMR &= ~SAIMR_RFS;
+	}
+
+	if (SACR1 & (SACR1_DREC | SACR1_DRPL)) {
+		SACR0 &= ~SACR0_ENB;
+		pxa_i2s_wait();
+		pxa_set_cken(CKEN8_I2S, 0);
+	}
+}
+
+#ifdef CONFIG_PM
+static int pxa2xx_i2s_suspend(struct platform_device *dev,
+	struct snd_soc_cpu_dai *dai)
+{
+	if (!dai->active)
+		return 0;
+
+	/* store registers */
+	pxa_i2s.sacr0 = SACR0;
+	pxa_i2s.sacr1 = SACR1;
+	pxa_i2s.saimr = SAIMR;
+	pxa_i2s.sadiv = SADIV;
+
+	/* deactivate link */
+	SACR0 &= ~SACR0_ENB;
+	pxa_i2s_wait();
+	return 0;
+}
+
+static int pxa2xx_i2s_resume(struct platform_device *pdev,
+	struct snd_soc_cpu_dai *dai)
+{
+	if (!dai->active)
+		return 0;
+
+	pxa_i2s_wait();
+
+	SACR0 = pxa_i2s.sacr0 &= ~SACR0_ENB;
+	SACR1 = pxa_i2s.sacr1;
+	SAIMR = pxa_i2s.saimr;
+	SADIV = pxa_i2s.sadiv;
+	SACR0 |= SACR0_ENB;
+
+	return 0;
+}
+
+#else
+#define pxa2xx_i2s_suspend	NULL
+#define pxa2xx_i2s_resume	NULL
+#endif
+
+#define PXA2XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
+		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+
+struct snd_soc_cpu_dai pxa_i2s_dai = {
+	.name = "pxa2xx-i2s",
+	.id = 0,
+	.type = SND_SOC_DAI_I2S,
+	.suspend = pxa2xx_i2s_suspend,
+	.resume = pxa2xx_i2s_resume,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = PXA2XX_I2S_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.capture = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = PXA2XX_I2S_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = {
+		.startup = pxa2xx_i2s_startup,
+		.shutdown = pxa2xx_i2s_shutdown,
+		.trigger = pxa2xx_i2s_trigger,
+		.hw_params = pxa2xx_i2s_hw_params,},
+	.dai_ops = {
+		.set_fmt = pxa2xx_i2s_set_dai_fmt,
+		.set_sysclk = pxa2xx_i2s_set_dai_sysclk,
+	},
+};
+
+EXPORT_SYMBOL_GPL(pxa_i2s_dai);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/pxa2xx-i2s.h b/sound/soc/pxa/pxa2xx-i2s.h
new file mode 100644
index 0000000..a2484f0
--- /dev/null
+++ b/sound/soc/pxa/pxa2xx-i2s.h
@@ -0,0 +1,20 @@
+/*
+ * linux/sound/arm/pxa2xx-i2s.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _PXA2XX_I2S_H
+#define _PXA2XX_I2S_H
+
+/* pxa2xx DAI ID's */
+#define PXA2XX_DAI_I2S			0
+
+/* I2S clock */
+#define PXA2XX_I2S_SYSCLK		0
+
+extern struct snd_soc_cpu_dai pxa_i2s_dai;
+
+#endif
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
new file mode 100644
index 0000000..35e8fa3
--- /dev/null
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -0,0 +1,372 @@
+/*
+ * linux/sound/arm/pxa2xx-pcm.c -- ALSA PCM interface for the Intel PXA2xx chip
+ *
+ * Author:	Nicolas Pitre
+ * Created:	Nov 30, 2004
+ * Copyright:	(C) 2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/dma.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/audio.h>
+
+#include "pxa2xx-pcm.h"
+
+static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_PAUSE |
+				  SNDRV_PCM_INFO_RESUME,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
+					SNDRV_PCM_FMTBIT_S24_LE |
+					SNDRV_PCM_FMTBIT_S32_LE,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 8192 - 32,
+	.periods_min		= 1,
+	.periods_max		= PAGE_SIZE/sizeof(pxa_dma_desc),
+	.buffer_bytes_max	= 128 * 1024,
+	.fifo_size		= 32,
+};
+
+struct pxa2xx_runtime_data {
+	int dma_ch;
+	struct pxa2xx_pcm_dma_params *params;
+	pxa_dma_desc *dma_desc_array;
+	dma_addr_t dma_desc_array_phys;
+};
+
+static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
+{
+	struct snd_pcm_substream *substream = dev_id;
+	struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
+	int dcsr;
+
+	dcsr = DCSR(dma_ch);
+	DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN;
+
+	if (dcsr & DCSR_ENDINTR) {
+		snd_pcm_period_elapsed(substream);
+	} else {
+		printk( KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
+			prtd->params->name, dma_ch, dcsr );
+	}
+}
+
+static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct pxa2xx_runtime_data *prtd = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data;
+	size_t totsize = params_buffer_bytes(params);
+	size_t period = params_period_bytes(params);
+	pxa_dma_desc *dma_desc;
+	dma_addr_t dma_buff_phys, next_desc_phys;
+	int ret;
+
+	/* return if this is a bufferless transfer e.g.
+	 * codec <--> BT codec or GSM modem -- lg FIXME */
+	 if (!dma)
+	 	return 0;
+
+	/* this may get called several times by oss emulation
+	 * with different params */
+	if (prtd->params == NULL) {
+		prtd->params = dma;
+		ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW,
+			      pxa2xx_pcm_dma_irq, substream);
+		if (ret < 0)
+			return ret;
+		prtd->dma_ch = ret;
+	} else if (prtd->params != dma) {
+		pxa_free_dma(prtd->dma_ch);
+		prtd->params = dma;
+		ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW,
+			      pxa2xx_pcm_dma_irq, substream);
+		if (ret < 0)
+			return ret;
+		prtd->dma_ch = ret;
+	}
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	runtime->dma_bytes = totsize;
+
+	dma_desc = prtd->dma_desc_array;
+	next_desc_phys = prtd->dma_desc_array_phys;
+	dma_buff_phys = runtime->dma_addr;
+	do {
+		next_desc_phys += sizeof(pxa_dma_desc);
+		dma_desc->ddadr = next_desc_phys;
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			dma_desc->dsadr = dma_buff_phys;
+			dma_desc->dtadr = prtd->params->dev_addr;
+		} else {
+			dma_desc->dsadr = prtd->params->dev_addr;
+			dma_desc->dtadr = dma_buff_phys;
+		}
+		if (period > totsize)
+			period = totsize;
+		dma_desc->dcmd = prtd->params->dcmd | period | DCMD_ENDIRQEN;
+		dma_desc++;
+		dma_buff_phys += period;
+	} while (totsize -= period);
+	dma_desc[-1].ddadr = prtd->dma_desc_array_phys;
+
+	return 0;
+}
+
+static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
+
+	if (prtd && prtd->params)
+		*prtd->params->drcmr = 0;
+
+	if (prtd->dma_ch) {
+		snd_pcm_set_runtime_buffer(substream, NULL);
+		pxa_free_dma(prtd->dma_ch);
+		prtd->dma_ch = 0;
+	}
+
+	return 0;
+}
+
+static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
+
+	DCSR(prtd->dma_ch) &= ~DCSR_RUN;
+	DCSR(prtd->dma_ch) = 0;
+	DCMD(prtd->dma_ch) = 0;
+	*prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD;
+
+	return 0;
+}
+
+static int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
+		DCSR(prtd->dma_ch) = DCSR_RUN;
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		DCSR(prtd->dma_ch) &= ~DCSR_RUN;
+		break;
+
+	case SNDRV_PCM_TRIGGER_RESUME:
+		DCSR(prtd->dma_ch) |= DCSR_RUN;
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
+		DCSR(prtd->dma_ch) |= DCSR_RUN;
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static snd_pcm_uframes_t
+pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct pxa2xx_runtime_data *prtd = runtime->private_data;
+
+	dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+			 DSADR(prtd->dma_ch) : DTADR(prtd->dma_ch);
+	snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr);
+
+	if (x == runtime->buffer_size)
+		x = 0;
+	return x;
+}
+
+static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct pxa2xx_runtime_data *prtd;
+	int ret;
+
+	snd_soc_set_runtime_hwparams(substream, &pxa2xx_pcm_hardware);
+
+	/*
+	 * For mysterious reasons (and despite what the manual says)
+	 * playback samples are lost if the DMA count is not a multiple
+	 * of the DMA burst size.  Let's add a rule to enforce that.
+	 */
+	ret = snd_pcm_hw_constraint_step(runtime, 0,
+		SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
+	if (ret)
+		goto out;
+
+	ret = snd_pcm_hw_constraint_step(runtime, 0,
+		SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
+	if (ret)
+		goto out;
+
+	ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		goto out;
+
+	prtd = kzalloc(sizeof(struct pxa2xx_runtime_data), GFP_KERNEL);
+	if (prtd == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	prtd->dma_desc_array =
+		dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE,
+				       &prtd->dma_desc_array_phys, GFP_KERNEL);
+	if (!prtd->dma_desc_array) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	runtime->private_data = prtd;
+	return 0;
+
+ err1:
+	kfree(prtd);
+ out:
+	return ret;
+}
+
+static int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct pxa2xx_runtime_data *prtd = runtime->private_data;
+
+	dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
+			      prtd->dma_desc_array, prtd->dma_desc_array_phys);
+	kfree(prtd);
+	return 0;
+}
+
+static int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
+	struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+				     runtime->dma_area,
+				     runtime->dma_addr,
+				     runtime->dma_bytes);
+}
+
+struct snd_pcm_ops pxa2xx_pcm_ops = {
+	.open		= pxa2xx_pcm_open,
+	.close		= pxa2xx_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= pxa2xx_pcm_hw_params,
+	.hw_free	= pxa2xx_pcm_hw_free,
+	.prepare	= pxa2xx_pcm_prepare,
+	.trigger	= pxa2xx_pcm_trigger,
+	.pointer	= pxa2xx_pcm_pointer,
+	.mmap		= pxa2xx_pcm_mmap,
+};
+
+static int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = pxa2xx_pcm_hardware.buffer_bytes_max;
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+					   &buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+	buf->bytes = size;
+	return 0;
+}
+
+static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+
+		dma_free_writecombine(pcm->card->dev, buf->bytes,
+				      buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+
+static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK;
+
+int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai,
+	struct snd_pcm *pcm)
+{
+	int ret = 0;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &pxa2xx_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_32BIT_MASK;
+
+	if (dai->playback.channels_min) {
+		ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			goto out;
+	}
+
+	if (dai->capture.channels_min) {
+		ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			goto out;
+	}
+ out:
+	return ret;
+}
+
+struct snd_soc_platform pxa2xx_soc_platform = {
+	.name		= "pxa2xx-audio",
+	.pcm_ops 	= &pxa2xx_pcm_ops,
+	.pcm_new	= pxa2xx_pcm_new,
+	.pcm_free	= pxa2xx_pcm_free_dma_buffers,
+};
+
+EXPORT_SYMBOL_GPL(pxa2xx_soc_platform);
+
+MODULE_AUTHOR("Nicolas Pitre");
+MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/pxa2xx-pcm.h b/sound/soc/pxa/pxa2xx-pcm.h
new file mode 100644
index 0000000..54c9c75
--- /dev/null
+++ b/sound/soc/pxa/pxa2xx-pcm.h
@@ -0,0 +1,34 @@
+/*
+ * linux/sound/arm/pxa2xx-pcm.h -- ALSA PCM interface for the Intel PXA2xx chip
+ *
+ * Author:	Nicolas Pitre
+ * Created:	Nov 30, 2004
+ * Copyright:	MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _PXA2XX_PCM_H
+#define _PXA2XX_PCM_H
+
+struct pxa2xx_pcm_dma_params {
+	char *name;			/* stream identifier */
+	u32 dcmd;			/* DMA descriptor dcmd field */
+	volatile u32 *drcmr;		/* the DMA request channel to use */
+	u32 dev_addr;			/* device physical address for DMA */
+};
+
+struct pxa2xx_gpio {
+	u32 sys;
+	u32	rx;
+	u32 tx;
+	u32 clk;
+	u32 frm;
+};
+
+/* platform data */
+extern struct snd_soc_platform pxa2xx_soc_platform;
+
+#endif
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
new file mode 100644
index 0000000..80e8210
--- /dev/null
+++ b/sound/soc/pxa/spitz.c
@@ -0,0 +1,394 @@
+/*
+ * spitz.c  --  SoC audio for Sharp SL-Cxx00 models Spitz, Borzoi and Akita
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *          Richard Purdie <richard@openedhand.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    30th Nov 2005   Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware/scoop.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/akita.h>
+#include <asm/arch/spitz.h>
+#include <asm/mach-types.h>
+#include "../codecs/wm8750.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-i2s.h"
+
+#define SPITZ_HP        0
+#define SPITZ_MIC       1
+#define SPITZ_LINE      2
+#define SPITZ_HEADSET   3
+#define SPITZ_HP_OFF    4
+#define SPITZ_SPK_ON    0
+#define SPITZ_SPK_OFF   1
+
+ /* audio clock in Hz - rounded from 12.235MHz */
+#define SPITZ_AUDIO_CLOCK 12288000
+
+static int spitz_jack_func;
+static int spitz_spk_func;
+
+static void spitz_ext_control(struct snd_soc_codec *codec)
+{
+	if (spitz_spk_func == SPITZ_SPK_ON)
+		snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1);
+	else
+		snd_soc_dapm_set_endpoint(codec, "Ext Spk", 0);
+
+	/* set up jack connection */
+	switch (spitz_jack_func) {
+	case SPITZ_HP:
+		/* enable and unmute hp jack, disable mic bias */
+		snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0);
+		snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0);
+		snd_soc_dapm_set_endpoint(codec, "Line Jack", 0);
+		snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1);
+		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
+		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+		break;
+	case SPITZ_MIC:
+		/* enable mic jack and bias, mute hp */
+		snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0);
+		snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0);
+		snd_soc_dapm_set_endpoint(codec, "Line Jack", 0);
+		snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1);
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+		break;
+	case SPITZ_LINE:
+		/* enable line jack, disable mic bias and mute hp */
+		snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0);
+		snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0);
+		snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0);
+		snd_soc_dapm_set_endpoint(codec, "Line Jack", 1);
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+		break;
+	case SPITZ_HEADSET:
+		/* enable and unmute headset jack enable mic bias, mute L hp */
+		snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0);
+		snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1);
+		snd_soc_dapm_set_endpoint(codec, "Line Jack", 0);
+		snd_soc_dapm_set_endpoint(codec, "Headset Jack", 1);
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
+		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+		break;
+	case SPITZ_HP_OFF:
+
+		/* jack removed, everything off */
+		snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0);
+		snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0);
+		snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0);
+		snd_soc_dapm_set_endpoint(codec, "Line Jack", 0);
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+		break;
+	}
+	snd_soc_dapm_sync_endpoints(codec);
+}
+
+static int spitz_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->socdev->codec;
+
+	/* check the jack status at stream startup */
+	spitz_ext_control(codec);
+	return 0;
+}
+
+static int spitz_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	unsigned int clk = 0;
+	int ret = 0;
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+		clk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+		clk = 11289600;
+		break;
+	}
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set the codec system clock for DAC and ADC */
+	ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8750_SYSCLK, clk,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set the I2S system clock as input (unused) */
+	ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops spitz_ops = {
+	.startup = spitz_startup,
+	.hw_params = spitz_hw_params,
+};
+
+static int spitz_get_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = spitz_jack_func;
+	return 0;
+}
+
+static int spitz_set_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	if (spitz_jack_func == ucontrol->value.integer.value[0])
+		return 0;
+
+	spitz_jack_func = ucontrol->value.integer.value[0];
+	spitz_ext_control(codec);
+	return 1;
+}
+
+static int spitz_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = spitz_spk_func;
+	return 0;
+}
+
+static int spitz_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+
+	if (spitz_spk_func == ucontrol->value.integer.value[0])
+		return 0;
+
+	spitz_spk_func = ucontrol->value.integer.value[0];
+	spitz_ext_control(codec);
+	return 1;
+}
+
+static int spitz_mic_bias(struct snd_soc_dapm_widget *w, int event)
+{
+	if (machine_is_borzoi() || machine_is_spitz()) {
+		if (SND_SOC_DAPM_EVENT_ON(event))
+			set_scoop_gpio(&spitzscoop2_device.dev,
+				SPITZ_SCP2_MIC_BIAS);
+		else
+			reset_scoop_gpio(&spitzscoop2_device.dev,
+				SPITZ_SCP2_MIC_BIAS);
+	}
+
+	if (machine_is_akita()) {
+		if (SND_SOC_DAPM_EVENT_ON(event))
+			akita_set_ioexp(&akitaioexp_device.dev,
+				AKITA_IOEXP_MIC_BIAS);
+		else
+			akita_reset_ioexp(&akitaioexp_device.dev,
+				AKITA_IOEXP_MIC_BIAS);
+	}
+	return 0;
+}
+
+/* spitz machine dapm widgets */
+static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias),
+	SND_SOC_DAPM_SPK("Ext Spk", NULL),
+	SND_SOC_DAPM_LINE("Line Jack", NULL),
+
+	/* headset is a mic and mono headphone */
+	SND_SOC_DAPM_HP("Headset Jack", NULL),
+};
+
+/* Spitz machine audio_map */
+static const char *audio_map[][3] = {
+
+	/* headphone connected to LOUT1, ROUT1 */
+	{"Headphone Jack", NULL, "LOUT1"},
+	{"Headphone Jack", NULL, "ROUT1"},
+
+	/* headset connected to ROUT1 and LINPUT1 with bias (def below) */
+	{"Headset Jack", NULL, "ROUT1"},
+
+	/* ext speaker connected to LOUT2, ROUT2  */
+	{"Ext Spk", NULL , "ROUT2"},
+	{"Ext Spk", NULL , "LOUT2"},
+
+	/* mic is connected to input 1 - with bias */
+	{"LINPUT1", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Mic Jack"},
+
+	/* line is connected to input 1 - no bias */
+	{"LINPUT1", NULL, "Line Jack"},
+
+	{NULL, NULL, NULL},
+};
+
+static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
+	"Off"};
+static const char *spk_function[] = {"On", "Off"};
+static const struct soc_enum spitz_enum[] = {
+	SOC_ENUM_SINGLE_EXT(5, jack_function),
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+};
+
+static const struct snd_kcontrol_new wm8750_spitz_controls[] = {
+	SOC_ENUM_EXT("Jack Function", spitz_enum[0], spitz_get_jack,
+		spitz_set_jack),
+	SOC_ENUM_EXT("Speaker Function", spitz_enum[1], spitz_get_spk,
+		spitz_set_spk),
+};
+
+/*
+ * Logic for a wm8750 as connected on a Sharp SL-Cxx00 Device
+ */
+static int spitz_wm8750_init(struct snd_soc_codec *codec)
+{
+	int i, err;
+
+	/* NC codec pins */
+	snd_soc_dapm_set_endpoint(codec, "RINPUT1", 0);
+	snd_soc_dapm_set_endpoint(codec, "LINPUT2", 0);
+	snd_soc_dapm_set_endpoint(codec, "RINPUT2", 0);
+	snd_soc_dapm_set_endpoint(codec, "LINPUT3", 0);
+	snd_soc_dapm_set_endpoint(codec, "RINPUT3", 0);
+	snd_soc_dapm_set_endpoint(codec, "OUT3", 0);
+	snd_soc_dapm_set_endpoint(codec, "MONO", 0);
+
+	/* Add spitz specific controls */
+	for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) {
+		err = snd_ctl_add(codec->card,
+			snd_soc_cnew(&wm8750_spitz_controls[i], codec, NULL));
+		if (err < 0)
+			return err;
+	}
+
+	/* Add spitz specific widgets */
+	for (i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) {
+		snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]);
+	}
+
+	/* Set up spitz specific audio path audio_map */
+	for (i = 0; audio_map[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, audio_map[i][0],
+			audio_map[i][1], audio_map[i][2]);
+	}
+
+	snd_soc_dapm_sync_endpoints(codec);
+	return 0;
+}
+
+/* spitz digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link spitz_dai = {
+	.name = "wm8750",
+	.stream_name = "WM8750",
+	.cpu_dai = &pxa_i2s_dai,
+	.codec_dai = &wm8750_dai,
+	.init = spitz_wm8750_init,
+	.ops = &spitz_ops,
+};
+
+/* spitz audio machine driver */
+static struct snd_soc_machine snd_soc_machine_spitz = {
+	.name = "Spitz",
+	.dai_link = &spitz_dai,
+	.num_links = 1,
+};
+
+/* spitz audio private data */
+static struct wm8750_setup_data spitz_wm8750_setup = {
+	.i2c_address = 0x1b,
+};
+
+/* spitz audio subsystem */
+static struct snd_soc_device spitz_snd_devdata = {
+	.machine = &snd_soc_machine_spitz,
+	.platform = &pxa2xx_soc_platform,
+	.codec_dev = &soc_codec_dev_wm8750,
+	.codec_data = &spitz_wm8750_setup,
+};
+
+static struct platform_device *spitz_snd_device;
+
+static int __init spitz_init(void)
+{
+	int ret;
+
+	if (!(machine_is_spitz() || machine_is_borzoi() || machine_is_akita()))
+		return -ENODEV;
+
+	spitz_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!spitz_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(spitz_snd_device, &spitz_snd_devdata);
+	spitz_snd_devdata.dev = &spitz_snd_device->dev;
+	ret = platform_device_add(spitz_snd_device);
+
+	if (ret)
+		platform_device_put(spitz_snd_device);
+
+	return ret;
+}
+
+static void __exit spitz_exit(void)
+{
+	platform_device_unregister(spitz_snd_device);
+}
+
+module_init(spitz_init);
+module_exit(spitz_exit);
+
+MODULE_AUTHOR("Richard Purdie");
+MODULE_DESCRIPTION("ALSA SoC Spitz");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
new file mode 100644
index 0000000..5504e30
--- /dev/null
+++ b/sound/soc/pxa/tosa.c
@@ -0,0 +1,289 @@
+/*
+ * tosa.c  --  SoC audio for Tosa
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *          Richard Purdie <richard@openedhand.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    30th Nov 2005   Initial version.
+ *
+ * GPIO's
+ *  1 - Jack Insertion
+ *  5 - Hookswitch (headset answer/hang up switch)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware/tmio.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/audio.h>
+#include <asm/arch/tosa.h>
+
+#include "../codecs/wm9712.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+
+static struct snd_soc_machine tosa;
+
+#define TOSA_HP        0
+#define TOSA_MIC_INT   1
+#define TOSA_HEADSET   2
+#define TOSA_HP_OFF    3
+#define TOSA_SPK_ON    0
+#define TOSA_SPK_OFF   1
+
+static int tosa_jack_func;
+static int tosa_spk_func;
+
+static void tosa_ext_control(struct snd_soc_codec *codec)
+{
+	int spk = 0, mic_int = 0, hp = 0, hs = 0;
+
+	/* set up jack connection */
+	switch (tosa_jack_func) {
+	case TOSA_HP:
+		hp = 1;
+		break;
+	case TOSA_MIC_INT:
+		mic_int = 1;
+		break;
+	case TOSA_HEADSET:
+		hs = 1;
+		break;
+	}
+
+	if (tosa_spk_func == TOSA_SPK_ON)
+		spk = 1;
+
+	snd_soc_dapm_set_endpoint(codec, "Speaker", spk);
+	snd_soc_dapm_set_endpoint(codec, "Mic (Internal)", mic_int);
+	snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp);
+	snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs);
+	snd_soc_dapm_sync_endpoints(codec);
+}
+
+static int tosa_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->socdev->codec;
+
+	/* check the jack status at stream startup */
+	tosa_ext_control(codec);
+	return 0;
+}
+
+static struct snd_soc_ops tosa_ops = {
+	.startup = tosa_startup,
+};
+
+static int tosa_get_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = tosa_jack_func;
+	return 0;
+}
+
+static int tosa_set_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+
+	if (tosa_jack_func == ucontrol->value.integer.value[0])
+		return 0;
+
+	tosa_jack_func = ucontrol->value.integer.value[0];
+	tosa_ext_control(codec);
+	return 1;
+}
+
+static int tosa_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = tosa_spk_func;
+	return 0;
+}
+
+static int tosa_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+
+	if (tosa_spk_func == ucontrol->value.integer.value[0])
+		return 0;
+
+	tosa_spk_func = ucontrol->value.integer.value[0];
+	tosa_ext_control(codec);
+	return 1;
+}
+
+/* tosa dapm event handlers */
+static int tosa_hp_event(struct snd_soc_dapm_widget *w, int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		set_tc6393_gpio(&tc6393_device.dev,TOSA_TC6393_L_MUTE);
+	else
+		reset_tc6393_gpio(&tc6393_device.dev,TOSA_TC6393_L_MUTE);
+	return 0;
+}
+
+/* tosa machine dapm widgets */
+static const struct snd_soc_dapm_widget tosa_dapm_widgets[] = {
+SND_SOC_DAPM_HP("Headphone Jack", tosa_hp_event),
+SND_SOC_DAPM_HP("Headset Jack", NULL),
+SND_SOC_DAPM_MIC("Mic (Internal)", NULL),
+SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+/* tosa audio map */
+static const char *audio_map[][3] = {
+
+	/* headphone connected to HPOUTL, HPOUTR */
+	{"Headphone Jack", NULL, "HPOUTL"},
+	{"Headphone Jack", NULL, "HPOUTR"},
+
+	/* ext speaker connected to LOUT2, ROUT2 */
+	{"Speaker", NULL, "LOUT2"},
+	{"Speaker", NULL, "ROUT2"},
+
+	/* internal mic is connected to mic1, mic2 differential - with bias */
+	{"MIC1", NULL, "Mic Bias"},
+	{"MIC2", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Mic (Internal)"},
+
+	/* headset is connected to HPOUTR, and LINEINR with bias */
+	{"Headset Jack", NULL, "HPOUTR"},
+	{"LINEINR", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Headset Jack"},
+
+	{NULL, NULL, NULL},
+};
+
+static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
+	"Off"};
+static const char *spk_function[] = {"On", "Off"};
+static const struct soc_enum tosa_enum[] = {
+	SOC_ENUM_SINGLE_EXT(5, jack_function),
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+};
+
+static const struct snd_kcontrol_new tosa_controls[] = {
+	SOC_ENUM_EXT("Jack Function", tosa_enum[0], tosa_get_jack,
+		tosa_set_jack),
+	SOC_ENUM_EXT("Speaker Function", tosa_enum[1], tosa_get_spk,
+		tosa_set_spk),
+};
+
+static int tosa_ac97_init(struct snd_soc_codec *codec)
+{
+	int i, err;
+
+	snd_soc_dapm_set_endpoint(codec, "OUT3", 0);
+	snd_soc_dapm_set_endpoint(codec, "MONOOUT", 0);
+
+	/* add tosa specific controls */
+	for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) {
+		err = snd_ctl_add(codec->card,
+				snd_soc_cnew(&tosa_controls[i],codec, NULL));
+		if (err < 0)
+			return err;
+	}
+
+	/* add tosa specific widgets */
+	for (i = 0; i < ARRAY_SIZE(tosa_dapm_widgets); i++) {
+		snd_soc_dapm_new_control(codec, &tosa_dapm_widgets[i]);
+	}
+
+	/* set up tosa specific audio path audio_map */
+	for (i = 0; audio_map[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, audio_map[i][0],
+			audio_map[i][1], audio_map[i][2]);
+	}
+
+	snd_soc_dapm_sync_endpoints(codec);
+	return 0;
+}
+
+static struct snd_soc_dai_link tosa_dai[] = {
+{
+	.name = "AC97",
+	.stream_name = "AC97 HiFi",
+	.cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
+	.codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+	.init = tosa_ac97_init,
+	.ops = &tosa_ops,
+},
+{
+	.name = "AC97 Aux",
+	.stream_name = "AC97 Aux",
+	.cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
+	.codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+	.ops = &tosa_ops,
+},
+};
+
+static struct snd_soc_machine tosa = {
+	.name = "Tosa",
+	.dai_link = tosa_dai,
+	.num_links = ARRAY_SIZE(tosa_dai),
+};
+
+static struct snd_soc_device tosa_snd_devdata = {
+	.machine = &tosa,
+	.platform = &pxa2xx_soc_platform,
+	.codec_dev = &soc_codec_dev_wm9712,
+};
+
+static struct platform_device *tosa_snd_device;
+
+static int __init tosa_init(void)
+{
+	int ret;
+
+	if (!machine_is_tosa())
+		return -ENODEV;
+
+	tosa_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!tosa_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(tosa_snd_device, &tosa_snd_devdata);
+	tosa_snd_devdata.dev = &tosa_snd_device->dev;
+	ret = platform_device_add(tosa_snd_device);
+
+	if (ret)
+		platform_device_put(tosa_snd_device);
+
+	return ret;
+}
+
+static void __exit tosa_exit(void)
+{
+	platform_device_unregister(tosa_snd_device);
+}
+
+module_init(tosa_init);
+module_exit(tosa_exit);
+
+/* Module information */
+MODULE_AUTHOR("Richard Purdie");
+MODULE_DESCRIPTION("ALSA SoC Tosa");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
new file mode 100644
index 0000000..36519ae
--- /dev/null
+++ b/sound/soc/soc-core.c
@@ -0,0 +1,1587 @@
+/*
+ * soc-core.c  --  ALSA SoC Audio Layer
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *         with code, comments and ideas from :-
+ *         Richard Purdie <richard@openedhand.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    12th Aug 2005   Initial version.
+ *    25th Oct 2005   Working Codec, Interface and Platform registration.
+ *
+ *  TODO:
+ *   o Add hw rules to enforce rates, etc.
+ *   o More testing with other codecs/machines.
+ *   o Add more codecs and platforms to ensure good API coverage.
+ *   o Support TDM on PCM and I2S
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+/* debug */
+#define SOC_DEBUG 0
+#if SOC_DEBUG
+#define dbg(format, arg...) printk(format, ## arg)
+#else
+#define dbg(format, arg...)
+#endif
+
+static DEFINE_MUTEX(pcm_mutex);
+static DEFINE_MUTEX(io_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq);
+
+/*
+ * This is a timeout to do a DAPM powerdown after a stream is closed().
+ * It can be used to eliminate pops between different playback streams, e.g.
+ * between two audio tracks.
+ */
+static int pmdown_time = 5000;
+module_param(pmdown_time, int, 0);
+MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)");
+
+/*
+ * This function forces any delayed work to be queued and run.
+ */
+static int run_delayed_work(struct delayed_work *dwork)
+{
+	int ret;
+
+	/* cancel any work waiting to be queued. */
+	ret = cancel_delayed_work(dwork);
+
+	/* if there was any work waiting then we run it now and
+	 * wait for it's completion */
+	if (ret) {
+		schedule_delayed_work(dwork, 0);
+		flush_scheduled_work();
+	}
+	return ret;
+}
+
+#ifdef CONFIG_SND_SOC_AC97_BUS
+/* unregister ac97 codec */
+static int soc_ac97_dev_unregister(struct snd_soc_codec *codec)
+{
+	if (codec->ac97->dev.bus)
+		device_unregister(&codec->ac97->dev);
+	return 0;
+}
+
+/* stop no dev release warning */
+static void soc_ac97_device_release(struct device *dev){}
+
+/* register ac97 codec to bus */
+static int soc_ac97_dev_register(struct snd_soc_codec *codec)
+{
+	int err;
+
+	codec->ac97->dev.bus = &ac97_bus_type;
+	codec->ac97->dev.parent = NULL;
+	codec->ac97->dev.release = soc_ac97_device_release;
+
+	snprintf(codec->ac97->dev.bus_id, BUS_ID_SIZE, "%d-%d:%s",
+		 codec->card->number, 0, codec->name);
+	err = device_register(&codec->ac97->dev);
+	if (err < 0) {
+		snd_printk(KERN_ERR "Can't register ac97 bus\n");
+		codec->ac97->dev.bus = NULL;
+		return err;
+	}
+	return 0;
+}
+#endif
+
+static inline const char* get_dai_name(int type)
+{
+	switch(type) {
+	case SND_SOC_DAI_AC97:
+		return "AC97";
+	case SND_SOC_DAI_I2S:
+		return "I2S";
+	case SND_SOC_DAI_PCM:
+		return "PCM";
+	}
+	return NULL;
+}
+
+/*
+ * Called by ALSA when a PCM substream is opened, the runtime->hw record is
+ * then initialized and any private data can be allocated. This also calls
+ * startup for the cpu DAI, platform, machine and codec DAI.
+ */
+static int soc_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_dai_link *machine = rtd->dai;
+	struct snd_soc_platform *platform = socdev->platform;
+	struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;
+	struct snd_soc_codec_dai *codec_dai = machine->codec_dai;
+	int ret = 0;
+
+	mutex_lock(&pcm_mutex);
+
+	/* startup the audio subsystem */
+	if (cpu_dai->ops.startup) {
+		ret = cpu_dai->ops.startup(substream);
+		if (ret < 0) {
+			printk(KERN_ERR "asoc: can't open interface %s\n",
+				cpu_dai->name);
+			goto out;
+		}
+	}
+
+	if (platform->pcm_ops->open) {
+		ret = platform->pcm_ops->open(substream);
+		if (ret < 0) {
+			printk(KERN_ERR "asoc: can't open platform %s\n", platform->name);
+			goto platform_err;
+		}
+	}
+
+	if (codec_dai->ops.startup) {
+		ret = codec_dai->ops.startup(substream);
+		if (ret < 0) {
+			printk(KERN_ERR "asoc: can't open codec %s\n",
+				codec_dai->name);
+			goto codec_dai_err;
+		}
+	}
+
+	if (machine->ops && machine->ops->startup) {
+		ret = machine->ops->startup(substream);
+		if (ret < 0) {
+			printk(KERN_ERR "asoc: %s startup failed\n", machine->name);
+			goto machine_err;
+		}
+	}
+
+	/* Check that the codec and cpu DAI's are compatible */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		runtime->hw.rate_min =
+			max(codec_dai->playback.rate_min, cpu_dai->playback.rate_min);
+		runtime->hw.rate_max =
+			min(codec_dai->playback.rate_max, cpu_dai->playback.rate_max);
+		runtime->hw.channels_min =
+			max(codec_dai->playback.channels_min,
+				cpu_dai->playback.channels_min);
+		runtime->hw.channels_max =
+			min(codec_dai->playback.channels_max,
+				cpu_dai->playback.channels_max);
+		runtime->hw.formats =
+			codec_dai->playback.formats & cpu_dai->playback.formats;
+		runtime->hw.rates =
+			codec_dai->playback.rates & cpu_dai->playback.rates;
+	} else {
+		runtime->hw.rate_min =
+			max(codec_dai->capture.rate_min, cpu_dai->capture.rate_min);
+		runtime->hw.rate_max =
+			min(codec_dai->capture.rate_max, cpu_dai->capture.rate_max);
+		runtime->hw.channels_min =
+			max(codec_dai->capture.channels_min,
+				cpu_dai->capture.channels_min);
+		runtime->hw.channels_max =
+			min(codec_dai->capture.channels_max,
+				cpu_dai->capture.channels_max);
+		runtime->hw.formats =
+			codec_dai->capture.formats & cpu_dai->capture.formats;
+		runtime->hw.rates =
+			codec_dai->capture.rates & cpu_dai->capture.rates;
+	}
+
+	snd_pcm_limit_hw_rates(runtime);
+	if (!runtime->hw.rates) {
+		printk(KERN_ERR "asoc: %s <-> %s No matching rates\n",
+			codec_dai->name, cpu_dai->name);
+		goto machine_err;
+	}
+	if (!runtime->hw.formats) {
+		printk(KERN_ERR "asoc: %s <-> %s No matching formats\n",
+			codec_dai->name, cpu_dai->name);
+		goto machine_err;
+	}
+	if (!runtime->hw.channels_min || !runtime->hw.channels_max) {
+		printk(KERN_ERR "asoc: %s <-> %s No matching channels\n",
+			codec_dai->name, cpu_dai->name);
+		goto machine_err;
+	}
+
+	dbg("asoc: %s <-> %s info:\n",codec_dai->name, cpu_dai->name);
+	dbg("asoc: rate mask 0x%x\n", runtime->hw.rates);
+	dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min,
+		runtime->hw.channels_max);
+	dbg("asoc: min rate %d max rate %d\n", runtime->hw.rate_min,
+		runtime->hw.rate_max);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		cpu_dai->playback.active = codec_dai->playback.active = 1;
+	else
+		cpu_dai->capture.active = codec_dai->capture.active = 1;
+	cpu_dai->active = codec_dai->active = 1;
+	cpu_dai->runtime = runtime;
+	socdev->codec->active++;
+	mutex_unlock(&pcm_mutex);
+	return 0;
+
+machine_err:
+	if (machine->ops && machine->ops->shutdown)
+		machine->ops->shutdown(substream);
+
+codec_dai_err:
+	if (platform->pcm_ops->close)
+		platform->pcm_ops->close(substream);
+
+platform_err:
+	if (cpu_dai->ops.shutdown)
+		cpu_dai->ops.shutdown(substream);
+out:
+	mutex_unlock(&pcm_mutex);
+	return ret;
+}
+
+/*
+ * Power down the audio subsytem pmdown_time msecs after close is called.
+ * This is to ensure there are no pops or clicks in between any music tracks
+ * due to DAPM power cycling.
+ */
+static void close_delayed_work(struct work_struct *work)
+{
+	struct snd_soc_device *socdev =
+		container_of(work, struct snd_soc_device, delayed_work.work);
+	struct snd_soc_codec *codec = socdev->codec;
+	struct snd_soc_codec_dai *codec_dai;
+	int i;
+
+	mutex_lock(&pcm_mutex);
+	for(i = 0; i < codec->num_dai; i++) {
+		codec_dai = &codec->dai[i];
+
+		dbg("pop wq checking: %s status: %s waiting: %s\n",
+			codec_dai->playback.stream_name,
+			codec_dai->playback.active ? "active" : "inactive",
+			codec_dai->pop_wait ? "yes" : "no");
+
+		/* are we waiting on this codec DAI stream */
+		if (codec_dai->pop_wait == 1) {
+
+			codec_dai->pop_wait = 0;
+			snd_soc_dapm_stream_event(codec, codec_dai->playback.stream_name,
+				SND_SOC_DAPM_STREAM_STOP);
+
+			/* power down the codec power domain if no longer active */
+			if (codec->active == 0) {
+				dbg("pop wq D3 %s %s\n", codec->name,
+					codec_dai->playback.stream_name);
+		 		if (codec->dapm_event)
+					codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+			}
+		}
+	}
+	mutex_unlock(&pcm_mutex);
+}
+
+/*
+ * Called by ALSA when a PCM substream is closed. Private data can be
+ * freed here. The cpu DAI, codec DAI, machine and platform are also
+ * shutdown.
+ */
+static int soc_codec_close(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_dai_link *machine = rtd->dai;
+	struct snd_soc_platform *platform = socdev->platform;
+	struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;
+	struct snd_soc_codec_dai *codec_dai = machine->codec_dai;
+	struct snd_soc_codec *codec = socdev->codec;
+
+	mutex_lock(&pcm_mutex);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		cpu_dai->playback.active = codec_dai->playback.active = 0;
+	else
+		cpu_dai->capture.active = codec_dai->capture.active = 0;
+
+	if (codec_dai->playback.active == 0 &&
+		codec_dai->capture.active == 0) {
+		cpu_dai->active = codec_dai->active = 0;
+	}
+	codec->active--;
+
+	if (cpu_dai->ops.shutdown)
+		cpu_dai->ops.shutdown(substream);
+
+	if (codec_dai->ops.shutdown)
+		codec_dai->ops.shutdown(substream);
+
+	if (machine->ops && machine->ops->shutdown)
+		machine->ops->shutdown(substream);
+
+	if (platform->pcm_ops->close)
+		platform->pcm_ops->close(substream);
+	cpu_dai->runtime = NULL;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		/* start delayed pop wq here for playback streams */
+		codec_dai->pop_wait = 1;
+		schedule_delayed_work(&socdev->delayed_work,
+			msecs_to_jiffies(pmdown_time));
+	} else {
+		/* capture streams can be powered down now */
+		snd_soc_dapm_stream_event(codec,
+			codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_STOP);
+
+		if (codec->active == 0 && codec_dai->pop_wait == 0){
+			if (codec->dapm_event)
+				codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+		}
+	}
+
+	mutex_unlock(&pcm_mutex);
+	return 0;
+}
+
+/*
+ * Called by ALSA when the PCM substream is prepared, can set format, sample
+ * rate, etc.  This function is non atomic and can be called multiple times,
+ * it can refer to the runtime info.
+ */
+static int soc_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_dai_link *machine = rtd->dai;
+	struct snd_soc_platform *platform = socdev->platform;
+	struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;
+	struct snd_soc_codec_dai *codec_dai = machine->codec_dai;
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret = 0;
+
+	mutex_lock(&pcm_mutex);
+
+	if (machine->ops && machine->ops->prepare) {
+		ret = machine->ops->prepare(substream);
+		if (ret < 0) {
+			printk(KERN_ERR "asoc: machine prepare error\n");
+			goto out;
+		}
+	}
+
+	if (platform->pcm_ops->prepare) {
+		ret = platform->pcm_ops->prepare(substream);
+		if (ret < 0) {
+			printk(KERN_ERR "asoc: platform prepare error\n");
+			goto out;
+		}
+	}
+
+	if (codec_dai->ops.prepare) {
+		ret = codec_dai->ops.prepare(substream);
+		if (ret < 0) {
+			printk(KERN_ERR "asoc: codec DAI prepare error\n");
+			goto out;
+		}
+	}
+
+	if (cpu_dai->ops.prepare) {
+		ret = cpu_dai->ops.prepare(substream);
+		if (ret < 0) {
+			printk(KERN_ERR "asoc: cpu DAI prepare error\n");
+			goto out;
+		}
+	}
+
+	/* we only want to start a DAPM playback stream if we are not waiting
+	 * on an existing one stopping */
+	if (codec_dai->pop_wait) {
+		/* we are waiting for the delayed work to start */
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+				snd_soc_dapm_stream_event(socdev->codec,
+					codec_dai->capture.stream_name,
+					SND_SOC_DAPM_STREAM_START);
+		else {
+			codec_dai->pop_wait = 0;
+			cancel_delayed_work(&socdev->delayed_work);
+			if (codec_dai->dai_ops.digital_mute)
+				codec_dai->dai_ops.digital_mute(codec_dai, 0);
+		}
+	} else {
+		/* no delayed work - do we need to power up codec */
+		if (codec->dapm_state != SNDRV_CTL_POWER_D0) {
+
+			if (codec->dapm_event)
+				codec->dapm_event(codec, SNDRV_CTL_POWER_D1);
+
+			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+				snd_soc_dapm_stream_event(codec,
+					codec_dai->playback.stream_name,
+					SND_SOC_DAPM_STREAM_START);
+			else
+				snd_soc_dapm_stream_event(codec,
+					codec_dai->capture.stream_name,
+					SND_SOC_DAPM_STREAM_START);
+
+			if (codec->dapm_event)
+				codec->dapm_event(codec, SNDRV_CTL_POWER_D0);
+			if (codec_dai->dai_ops.digital_mute)
+				codec_dai->dai_ops.digital_mute(codec_dai, 0);
+
+		} else {
+			/* codec already powered - power on widgets */
+			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+				snd_soc_dapm_stream_event(codec,
+					codec_dai->playback.stream_name,
+					SND_SOC_DAPM_STREAM_START);
+			else
+				snd_soc_dapm_stream_event(codec,
+					codec_dai->capture.stream_name,
+					SND_SOC_DAPM_STREAM_START);
+			if (codec_dai->dai_ops.digital_mute)
+				codec_dai->dai_ops.digital_mute(codec_dai, 0);
+		}
+	}
+
+out:
+	mutex_unlock(&pcm_mutex);
+	return ret;
+}
+
+/*
+ * Called by ALSA when the hardware params are set by application. This
+ * function can also be called multiple times and can allocate buffers
+ * (using snd_pcm_lib_* ). It's non-atomic.
+ */
+static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_dai_link *machine = rtd->dai;
+	struct snd_soc_platform *platform = socdev->platform;
+	struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;
+	struct snd_soc_codec_dai *codec_dai = machine->codec_dai;
+	int ret = 0;
+
+	mutex_lock(&pcm_mutex);
+
+	if (machine->ops && machine->ops->hw_params) {
+		ret = machine->ops->hw_params(substream, params);
+		if (ret < 0) {
+			printk(KERN_ERR "asoc: machine hw_params failed\n");
+			goto out;
+		}
+	}
+
+	if (codec_dai->ops.hw_params) {
+		ret = codec_dai->ops.hw_params(substream, params);
+		if (ret < 0) {
+			printk(KERN_ERR "asoc: can't set codec %s hw params\n",
+				codec_dai->name);
+			goto codec_err;
+		}
+	}
+
+	if (cpu_dai->ops.hw_params) {
+		ret = cpu_dai->ops.hw_params(substream, params);
+		if (ret < 0) {
+			printk(KERN_ERR "asoc: can't set interface %s hw params\n",
+				cpu_dai->name);
+			goto interface_err;
+		}
+	}
+
+	if (platform->pcm_ops->hw_params) {
+		ret = platform->pcm_ops->hw_params(substream, params);
+		if (ret < 0) {
+			printk(KERN_ERR "asoc: can't set platform %s hw params\n",
+				platform->name);
+			goto platform_err;
+		}
+	}
+
+out:
+	mutex_unlock(&pcm_mutex);
+	return ret;
+
+platform_err:
+	if (cpu_dai->ops.hw_free)
+		cpu_dai->ops.hw_free(substream);
+
+interface_err:
+	if (codec_dai->ops.hw_free)
+		codec_dai->ops.hw_free(substream);
+
+codec_err:
+	if(machine->ops && machine->ops->hw_free)
+		machine->ops->hw_free(substream);
+
+	mutex_unlock(&pcm_mutex);
+	return ret;
+}
+
+/*
+ * Free's resources allocated by hw_params, can be called multiple times
+ */
+static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_dai_link *machine = rtd->dai;
+	struct snd_soc_platform *platform = socdev->platform;
+	struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;
+	struct snd_soc_codec_dai *codec_dai = machine->codec_dai;
+	struct snd_soc_codec *codec = socdev->codec;
+
+	mutex_lock(&pcm_mutex);
+
+	/* apply codec digital mute */
+	if (!codec->active && codec_dai->dai_ops.digital_mute)
+		codec_dai->dai_ops.digital_mute(codec_dai, 1);
+
+	/* free any machine hw params */
+	if (machine->ops && machine->ops->hw_free)
+		machine->ops->hw_free(substream);
+
+	/* free any DMA resources */
+	if (platform->pcm_ops->hw_free)
+		platform->pcm_ops->hw_free(substream);
+
+	/* now free hw params for the DAI's  */
+	if (codec_dai->ops.hw_free)
+		codec_dai->ops.hw_free(substream);
+
+	if (cpu_dai->ops.hw_free)
+		cpu_dai->ops.hw_free(substream);
+
+	mutex_unlock(&pcm_mutex);
+	return 0;
+}
+
+static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_dai_link *machine = rtd->dai;
+	struct snd_soc_platform *platform = socdev->platform;
+	struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;
+	struct snd_soc_codec_dai *codec_dai = machine->codec_dai;
+	int ret;
+
+	if (codec_dai->ops.trigger) {
+		ret = codec_dai->ops.trigger(substream, cmd);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (platform->pcm_ops->trigger) {
+		ret = platform->pcm_ops->trigger(substream, cmd);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (cpu_dai->ops.trigger) {
+		ret = cpu_dai->ops.trigger(substream, cmd);
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+/* ASoC PCM operations */
+static struct snd_pcm_ops soc_pcm_ops = {
+	.open		= soc_pcm_open,
+	.close		= soc_codec_close,
+	.hw_params	= soc_pcm_hw_params,
+	.hw_free	= soc_pcm_hw_free,
+	.prepare	= soc_pcm_prepare,
+	.trigger	= soc_pcm_trigger,
+};
+
+#ifdef CONFIG_PM
+/* powers down audio subsystem for suspend */
+static int soc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ 	struct snd_soc_machine *machine = socdev->machine;
+ 	struct snd_soc_platform *platform = socdev->platform;
+ 	struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
+	struct snd_soc_codec *codec = socdev->codec;
+	int i;
+
+	/* mute any active DAC's */
+	for(i = 0; i < machine->num_links; i++) {
+		struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai;
+		if (dai->dai_ops.digital_mute && dai->playback.active)
+			dai->dai_ops.digital_mute(dai, 1);
+	}
+
+	if (machine->suspend_pre)
+		machine->suspend_pre(pdev, state);
+
+	for(i = 0; i < machine->num_links; i++) {
+		struct snd_soc_cpu_dai  *cpu_dai = machine->dai_link[i].cpu_dai;
+		if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97)
+			cpu_dai->suspend(pdev, cpu_dai);
+		if (platform->suspend)
+			platform->suspend(pdev, cpu_dai);
+	}
+
+	/* close any waiting streams and save state */
+	run_delayed_work(&socdev->delayed_work);
+	codec->suspend_dapm_state = codec->dapm_state;
+
+	for(i = 0; i < codec->num_dai; i++) {
+		char *stream = codec->dai[i].playback.stream_name;
+		if (stream != NULL)
+			snd_soc_dapm_stream_event(codec, stream,
+				SND_SOC_DAPM_STREAM_SUSPEND);
+		stream = codec->dai[i].capture.stream_name;
+		if (stream != NULL)
+			snd_soc_dapm_stream_event(codec, stream,
+				SND_SOC_DAPM_STREAM_SUSPEND);
+	}
+
+	if (codec_dev->suspend)
+		codec_dev->suspend(pdev, state);
+
+	for(i = 0; i < machine->num_links; i++) {
+		struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+		if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97)
+			cpu_dai->suspend(pdev, cpu_dai);
+	}
+
+	if (machine->suspend_post)
+		machine->suspend_post(pdev, state);
+
+	return 0;
+}
+
+/* powers up audio subsystem after a suspend */
+static int soc_resume(struct platform_device *pdev)
+{
+ 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ 	struct snd_soc_machine *machine = socdev->machine;
+ 	struct snd_soc_platform *platform = socdev->platform;
+ 	struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
+	struct snd_soc_codec *codec = socdev->codec;
+	int i;
+
+	if (machine->resume_pre)
+		machine->resume_pre(pdev);
+
+	for(i = 0; i < machine->num_links; i++) {
+		struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+		if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97)
+			cpu_dai->resume(pdev, cpu_dai);
+	}
+
+	if (codec_dev->resume)
+		codec_dev->resume(pdev);
+
+	for(i = 0; i < codec->num_dai; i++) {
+		char* stream = codec->dai[i].playback.stream_name;
+		if (stream != NULL)
+			snd_soc_dapm_stream_event(codec, stream,
+				SND_SOC_DAPM_STREAM_RESUME);
+		stream = codec->dai[i].capture.stream_name;
+		if (stream != NULL)
+			snd_soc_dapm_stream_event(codec, stream,
+				SND_SOC_DAPM_STREAM_RESUME);
+	}
+
+	/* unmute any active DAC's */
+	for(i = 0; i < machine->num_links; i++) {
+		struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai;
+		if (dai->dai_ops.digital_mute && dai->playback.active)
+			dai->dai_ops.digital_mute(dai, 0);
+	}
+
+	for(i = 0; i < machine->num_links; i++) {
+		struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+		if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97)
+			cpu_dai->resume(pdev, cpu_dai);
+		if (platform->resume)
+			platform->resume(pdev, cpu_dai);
+	}
+
+	if (machine->resume_post)
+		machine->resume_post(pdev);
+
+	return 0;
+}
+
+#else
+#define soc_suspend	NULL
+#define soc_resume	NULL
+#endif
+
+/* probes a new socdev */
+static int soc_probe(struct platform_device *pdev)
+{
+	int ret = 0, i;
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_machine *machine = socdev->machine;
+	struct snd_soc_platform *platform = socdev->platform;
+	struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
+
+	if (machine->probe) {
+		ret = machine->probe(pdev);
+		if(ret < 0)
+			return ret;
+	}
+
+	for (i = 0; i < machine->num_links; i++) {
+		struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+		if (cpu_dai->probe) {
+			ret = cpu_dai->probe(pdev);
+			if(ret < 0)
+				goto cpu_dai_err;
+		}
+	}
+
+	if (codec_dev->probe) {
+		ret = codec_dev->probe(pdev);
+		if(ret < 0)
+			goto cpu_dai_err;
+	}
+
+	if (platform->probe) {
+		ret = platform->probe(pdev);
+		if(ret < 0)
+			goto platform_err;
+	}
+
+	/* DAPM stream work */
+	INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work);
+	return 0;
+
+platform_err:
+	if (codec_dev->remove)
+		codec_dev->remove(pdev);
+
+cpu_dai_err:
+	for (i--; i >= 0; i--) {
+		struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+		if (cpu_dai->remove)
+			cpu_dai->remove(pdev);
+	}
+
+	if (machine->remove)
+		machine->remove(pdev);
+
+	return ret;
+}
+
+/* removes a socdev */
+static int soc_remove(struct platform_device *pdev)
+{
+	int i;
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_machine *machine = socdev->machine;
+	struct snd_soc_platform *platform = socdev->platform;
+	struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
+
+	run_delayed_work(&socdev->delayed_work);
+
+	if (platform->remove)
+		platform->remove(pdev);
+
+	if (codec_dev->remove)
+		codec_dev->remove(pdev);
+
+	for (i = 0; i < machine->num_links; i++) {
+		struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+		if (cpu_dai->remove)
+			cpu_dai->remove(pdev);
+	}
+
+	if (machine->remove)
+		machine->remove(pdev);
+
+	return 0;
+}
+
+/* ASoC platform driver */
+static struct platform_driver soc_driver = {
+	.driver		= {
+		.name		= "soc-audio",
+	},
+	.probe		= soc_probe,
+	.remove		= soc_remove,
+	.suspend	= soc_suspend,
+	.resume		= soc_resume,
+};
+
+/* create a new pcm */
+static int soc_new_pcm(struct snd_soc_device *socdev,
+	struct snd_soc_dai_link *dai_link, int num)
+{
+	struct snd_soc_codec *codec = socdev->codec;
+	struct snd_soc_codec_dai *codec_dai = dai_link->codec_dai;
+	struct snd_soc_cpu_dai *cpu_dai = dai_link->cpu_dai;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_pcm *pcm;
+	char new_name[64];
+	int ret = 0, playback = 0, capture = 0;
+
+	rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL);
+	if (rtd == NULL)
+		return -ENOMEM;
+
+	rtd->dai = dai_link;
+	rtd->socdev = socdev;
+	codec_dai->codec = socdev->codec;
+
+	/* check client and interface hw capabilities */
+	sprintf(new_name, "%s %s-%s-%d",dai_link->stream_name, codec_dai->name,
+		get_dai_name(cpu_dai->type), num);
+
+	if (codec_dai->playback.channels_min)
+		playback = 1;
+	if (codec_dai->capture.channels_min)
+		capture = 1;
+
+	ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback,
+		capture, &pcm);
+	if (ret < 0) {
+		printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name);
+		kfree(rtd);
+		return ret;
+	}
+
+	pcm->private_data = rtd;
+	soc_pcm_ops.mmap = socdev->platform->pcm_ops->mmap;
+	soc_pcm_ops.pointer = socdev->platform->pcm_ops->pointer;
+	soc_pcm_ops.ioctl = socdev->platform->pcm_ops->ioctl;
+	soc_pcm_ops.copy = socdev->platform->pcm_ops->copy;
+	soc_pcm_ops.silence = socdev->platform->pcm_ops->silence;
+	soc_pcm_ops.ack = socdev->platform->pcm_ops->ack;
+	soc_pcm_ops.page = socdev->platform->pcm_ops->page;
+
+	if (playback)
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
+
+	if (capture)
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
+
+	ret = socdev->platform->pcm_new(codec->card, codec_dai, pcm);
+	if (ret < 0) {
+		printk(KERN_ERR "asoc: platform pcm constructor failed\n");
+		kfree(rtd);
+		return ret;
+	}
+
+	pcm->private_free = socdev->platform->pcm_free;
+	printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,
+		cpu_dai->name);
+	return ret;
+}
+
+/* codec register dump */
+static ssize_t codec_reg_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct snd_soc_device *devdata = dev_get_drvdata(dev);
+	struct snd_soc_codec *codec = devdata->codec;
+	int i, step = 1, count = 0;
+
+	if (!codec->reg_cache_size)
+		return 0;
+
+	if (codec->reg_cache_step)
+		step = codec->reg_cache_step;
+
+	count += sprintf(buf, "%s registers\n", codec->name);
+	for(i = 0; i < codec->reg_cache_size; i += step)
+		count += sprintf(buf + count, "%2x: %4x\n", i, codec->read(codec, i));
+
+	return count;
+}
+static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
+
+/**
+ * snd_soc_new_ac97_codec - initailise AC97 device
+ * @codec: audio codec
+ * @ops: AC97 bus operations
+ * @num: AC97 codec number
+ *
+ * Initialises AC97 codec resources for use by ad-hoc devices only.
+ */
+int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
+	struct snd_ac97_bus_ops *ops, int num)
+{
+	mutex_lock(&codec->mutex);
+
+	codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL);
+	if (codec->ac97 == NULL) {
+		mutex_unlock(&codec->mutex);
+		return -ENOMEM;
+	}
+
+	codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL);
+	if (codec->ac97->bus == NULL) {
+		kfree(codec->ac97);
+		codec->ac97 = NULL;
+		mutex_unlock(&codec->mutex);
+		return -ENOMEM;
+	}
+
+	codec->ac97->bus->ops = ops;
+	codec->ac97->num = num;
+	mutex_unlock(&codec->mutex);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
+
+/**
+ * snd_soc_free_ac97_codec - free AC97 codec device
+ * @codec: audio codec
+ *
+ * Frees AC97 codec device resources.
+ */
+void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
+{
+	mutex_lock(&codec->mutex);
+	kfree(codec->ac97->bus);
+	kfree(codec->ac97);
+	codec->ac97 = NULL;
+	mutex_unlock(&codec->mutex);
+}
+EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
+
+/**
+ * snd_soc_update_bits - update codec register bits
+ * @codec: audio codec
+ * @reg: codec register
+ * @mask: register mask
+ * @value: new value
+ *
+ * Writes new register value.
+ *
+ * Returns 1 for change else 0.
+ */
+int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
+				unsigned short mask, unsigned short value)
+{
+	int change;
+	unsigned short old, new;
+
+	mutex_lock(&io_mutex);
+	old = snd_soc_read(codec, reg);
+	new = (old & ~mask) | value;
+	change = old != new;
+	if (change)
+		snd_soc_write(codec, reg, new);
+
+	mutex_unlock(&io_mutex);
+	return change;
+}
+EXPORT_SYMBOL_GPL(snd_soc_update_bits);
+
+/**
+ * snd_soc_test_bits - test register for change
+ * @codec: audio codec
+ * @reg: codec register
+ * @mask: register mask
+ * @value: new value
+ *
+ * Tests a register with a new value and checks if the new value is
+ * different from the old value.
+ *
+ * Returns 1 for change else 0.
+ */
+int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
+				unsigned short mask, unsigned short value)
+{
+	int change;
+	unsigned short old, new;
+
+	mutex_lock(&io_mutex);
+	old = snd_soc_read(codec, reg);
+	new = (old & ~mask) | value;
+	change = old != new;
+	mutex_unlock(&io_mutex);
+
+	return change;
+}
+EXPORT_SYMBOL_GPL(snd_soc_test_bits);
+
+/**
+ * snd_soc_new_pcms - create new sound card and pcms
+ * @socdev: the SoC audio device
+ *
+ * Create a new sound card based upon the codec and interface pcms.
+ *
+ * Returns 0 for success, else error.
+ */
+int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid)
+{
+	struct snd_soc_codec *codec = socdev->codec;
+	struct snd_soc_machine *machine = socdev->machine;
+	int ret = 0, i;
+
+	mutex_lock(&codec->mutex);
+
+	/* register a sound card */
+	codec->card = snd_card_new(idx, xid, codec->owner, 0);
+	if (!codec->card) {
+		printk(KERN_ERR "asoc: can't create sound card for codec %s\n",
+			codec->name);
+		mutex_unlock(&codec->mutex);
+		return -ENODEV;
+	}
+
+	codec->card->dev = socdev->dev;
+	codec->card->private_data = codec;
+	strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver));
+
+	/* create the pcms */
+	for(i = 0; i < machine->num_links; i++) {
+		ret = soc_new_pcm(socdev, &machine->dai_link[i], i);
+		if (ret < 0) {
+			printk(KERN_ERR "asoc: can't create pcm %s\n",
+				machine->dai_link[i].stream_name);
+			mutex_unlock(&codec->mutex);
+			return ret;
+		}
+	}
+
+	mutex_unlock(&codec->mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_new_pcms);
+
+/**
+ * snd_soc_register_card - register sound card
+ * @socdev: the SoC audio device
+ *
+ * Register a SoC sound card. Also registers an AC97 device if the
+ * codec is AC97 for ad hoc devices.
+ *
+ * Returns 0 for success, else error.
+ */
+int snd_soc_register_card(struct snd_soc_device *socdev)
+{
+	struct snd_soc_codec *codec = socdev->codec;
+	struct snd_soc_machine *machine = socdev->machine;
+	int ret = 0, i, ac97 = 0, err = 0;
+
+	mutex_lock(&codec->mutex);
+	for(i = 0; i < machine->num_links; i++) {
+		if (socdev->machine->dai_link[i].init) {
+			err = socdev->machine->dai_link[i].init(codec);
+			if (err < 0) {
+				printk(KERN_ERR "asoc: failed to init %s\n",
+					socdev->machine->dai_link[i].stream_name);
+				continue;
+			}
+		}
+		if (socdev->machine->dai_link[i].cpu_dai->type == SND_SOC_DAI_AC97)
+			ac97 = 1;
+	}
+	snprintf(codec->card->shortname, sizeof(codec->card->shortname),
+		 "%s", machine->name);
+	snprintf(codec->card->longname, sizeof(codec->card->longname),
+		 "%s (%s)", machine->name, codec->name);
+
+	ret = snd_card_register(codec->card);
+	if (ret < 0) {
+		printk(KERN_ERR "asoc: failed to register soundcard for codec %s\n",
+				codec->name);
+		goto out;
+	}
+
+#ifdef CONFIG_SND_SOC_AC97_BUS
+	if (ac97) {
+		ret = soc_ac97_dev_register(codec);
+		if (ret < 0) {
+			printk(KERN_ERR "asoc: AC97 device register failed\n");
+			snd_card_free(codec->card);
+			goto out;
+		}
+	}
+#endif
+
+	err = snd_soc_dapm_sys_add(socdev->dev);
+	if (err < 0)
+		printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n");
+
+	err = device_create_file(socdev->dev, &dev_attr_codec_reg);
+	if (err < 0)
+		printk(KERN_WARNING "asoc: failed to add codec sysfs entries\n");
+out:
+	mutex_unlock(&codec->mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_register_card);
+
+/**
+ * snd_soc_free_pcms - free sound card and pcms
+ * @socdev: the SoC audio device
+ *
+ * Frees sound card and pcms associated with the socdev.
+ * Also unregister the codec if it is an AC97 device.
+ */
+void snd_soc_free_pcms(struct snd_soc_device *socdev)
+{
+	struct snd_soc_codec *codec = socdev->codec;
+
+	mutex_lock(&codec->mutex);
+#ifdef CONFIG_SND_SOC_AC97_BUS
+	if (codec->ac97)
+		soc_ac97_dev_unregister(codec);
+#endif
+
+	if (codec->card)
+		snd_card_free(codec->card);
+	device_remove_file(socdev->dev, &dev_attr_codec_reg);
+	mutex_unlock(&codec->mutex);
+}
+EXPORT_SYMBOL_GPL(snd_soc_free_pcms);
+
+/**
+ * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
+ * @substream: the pcm substream
+ * @hw: the hardware parameters
+ *
+ * Sets the substream runtime hardware parameters.
+ */
+int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
+	const struct snd_pcm_hardware *hw)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	runtime->hw.info = hw->info;
+	runtime->hw.formats = hw->formats;
+	runtime->hw.period_bytes_min = hw->period_bytes_min;
+	runtime->hw.period_bytes_max = hw->period_bytes_max;
+	runtime->hw.periods_min = hw->periods_min;
+	runtime->hw.periods_max = hw->periods_max;
+	runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
+	runtime->hw.fifo_size = hw->fifo_size;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
+
+/**
+ * snd_soc_cnew - create new control
+ * @_template: control template
+ * @data: control private data
+ * @lnng_name: control long name
+ *
+ * Create a new mixer control from a template control.
+ *
+ * Returns 0 for success, else error.
+ */
+struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
+	void *data, char *long_name)
+{
+	struct snd_kcontrol_new template;
+
+	memcpy(&template, _template, sizeof(template));
+	if (long_name)
+		template.name = long_name;
+	template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+	template.index = 0;
+
+	return snd_ctl_new1(&template, data);
+}
+EXPORT_SYMBOL_GPL(snd_soc_cnew);
+
+/**
+ * snd_soc_info_enum_double - enumerated double mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about a double enumerated
+ * mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = e->shift_l == e->shift_r ? 1 : 2;
+	uinfo->value.enumerated.items = e->mask;
+
+	if (uinfo->value.enumerated.item > e->mask - 1)
+		uinfo->value.enumerated.item = e->mask - 1;
+	strcpy(uinfo->value.enumerated.name,
+		e->texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_enum_double);
+
+/**
+ * snd_soc_get_enum_double - enumerated double mixer get callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to get the value of a double enumerated mixer.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned short val, bitmask;
+
+	for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+		;
+	val = snd_soc_read(codec, e->reg);
+	ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
+	if (e->shift_l != e->shift_r)
+		ucontrol->value.enumerated.item[1] =
+			(val >> e->shift_r) & (bitmask - 1);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_enum_double);
+
+/**
+ * snd_soc_put_enum_double - enumerated double mixer put callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to set the value of a double enumerated mixer.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned short val;
+	unsigned short mask, bitmask;
+
+	for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+		;
+	if (ucontrol->value.enumerated.item[0] > e->mask - 1)
+		return -EINVAL;
+	val = ucontrol->value.enumerated.item[0] << e->shift_l;
+	mask = (bitmask - 1) << e->shift_l;
+	if (e->shift_l != e->shift_r) {
+		if (ucontrol->value.enumerated.item[1] > e->mask - 1)
+			return -EINVAL;
+		val |= ucontrol->value.enumerated.item[1] << e->shift_r;
+		mask |= (bitmask - 1) << e->shift_r;
+	}
+
+	return snd_soc_update_bits(codec, e->reg, mask, val);
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
+
+/**
+ * snd_soc_info_enum_ext - external enumerated single mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about an external enumerated
+ * single mixer.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = e->mask;
+
+	if (uinfo->value.enumerated.item > e->mask - 1)
+		uinfo->value.enumerated.item = e->mask - 1;
+	strcpy(uinfo->value.enumerated.name,
+		e->texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_enum_ext);
+
+/**
+ * snd_soc_info_volsw_ext - external single mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about a single external mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	int mask = kcontrol->private_value;
+
+	uinfo->type =
+		mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = mask;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext);
+
+/**
+ * snd_soc_info_bool_ext - external single boolean mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about a single boolean external mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_bool_ext(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_bool_ext);
+
+/**
+ * snd_soc_info_volsw - single mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about a single mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	int mask = (kcontrol->private_value >> 16) & 0xff;
+	int shift = (kcontrol->private_value >> 8) & 0x0f;
+	int rshift = (kcontrol->private_value >> 12) & 0x0f;
+
+	uinfo->type =
+		mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = shift == rshift ? 1 : 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = mask;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
+
+/**
+ * snd_soc_get_volsw - single mixer get callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to get the value of a single mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int reg = kcontrol->private_value & 0xff;
+	int shift = (kcontrol->private_value >> 8) & 0x0f;
+	int rshift = (kcontrol->private_value >> 12) & 0x0f;
+	int mask = (kcontrol->private_value >> 16) & 0xff;
+	int invert = (kcontrol->private_value >> 24) & 0x01;
+
+	ucontrol->value.integer.value[0] =
+		(snd_soc_read(codec, reg) >> shift) & mask;
+	if (shift != rshift)
+		ucontrol->value.integer.value[1] =
+			(snd_soc_read(codec, reg) >> rshift) & mask;
+	if (invert) {
+		ucontrol->value.integer.value[0] =
+			mask - ucontrol->value.integer.value[0];
+		if (shift != rshift)
+			ucontrol->value.integer.value[1] =
+				mask - ucontrol->value.integer.value[1];
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_volsw);
+
+/**
+ * snd_soc_put_volsw - single mixer put callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to set the value of a single mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int reg = kcontrol->private_value & 0xff;
+	int shift = (kcontrol->private_value >> 8) & 0x0f;
+	int rshift = (kcontrol->private_value >> 12) & 0x0f;
+	int mask = (kcontrol->private_value >> 16) & 0xff;
+	int invert = (kcontrol->private_value >> 24) & 0x01;
+	int err;
+	unsigned short val, val2, val_mask;
+
+	val = (ucontrol->value.integer.value[0] & mask);
+	if (invert)
+		val = mask - val;
+	val_mask = mask << shift;
+	val = val << shift;
+	if (shift != rshift) {
+		val2 = (ucontrol->value.integer.value[1] & mask);
+		if (invert)
+			val2 = mask - val2;
+		val_mask |= mask << rshift;
+		val |= val2 << rshift;
+	}
+	err = snd_soc_update_bits(codec, reg, val_mask, val);
+	return err;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
+
+/**
+ * snd_soc_info_volsw_2r - double mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about a double mixer control that
+ * spans 2 codec registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	int mask = (kcontrol->private_value >> 12) & 0xff;
+
+	uinfo->type =
+		mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = mask;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r);
+
+/**
+ * snd_soc_get_volsw_2r - double mixer get callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to get the value of a double mixer control that spans 2 registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int reg = kcontrol->private_value & 0xff;
+	int reg2 = (kcontrol->private_value >> 24) & 0xff;
+	int shift = (kcontrol->private_value >> 8) & 0x0f;
+	int mask = (kcontrol->private_value >> 12) & 0xff;
+	int invert = (kcontrol->private_value >> 20) & 0x01;
+
+	ucontrol->value.integer.value[0] =
+		(snd_soc_read(codec, reg) >> shift) & mask;
+	ucontrol->value.integer.value[1] =
+		(snd_soc_read(codec, reg2) >> shift) & mask;
+	if (invert) {
+		ucontrol->value.integer.value[0] =
+			mask - ucontrol->value.integer.value[0];
+		ucontrol->value.integer.value[1] =
+			mask - ucontrol->value.integer.value[1];
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r);
+
+/**
+ * snd_soc_put_volsw_2r - double mixer set callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to set the value of a double mixer control that spans 2 registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int reg = kcontrol->private_value & 0xff;
+	int reg2 = (kcontrol->private_value >> 24) & 0xff;
+	int shift = (kcontrol->private_value >> 8) & 0x0f;
+	int mask = (kcontrol->private_value >> 12) & 0xff;
+	int invert = (kcontrol->private_value >> 20) & 0x01;
+	int err;
+	unsigned short val, val2, val_mask;
+
+	val_mask = mask << shift;
+	val = (ucontrol->value.integer.value[0] & mask);
+	val2 = (ucontrol->value.integer.value[1] & mask);
+
+	if (invert) {
+		val = mask - val;
+		val2 = mask - val2;
+	}
+
+	val = val << shift;
+	val2 = val2 << shift;
+
+	if ((err = snd_soc_update_bits(codec, reg, val_mask, val)) < 0)
+		return err;
+
+	err = snd_soc_update_bits(codec, reg2, val_mask, val2);
+	return err;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r);
+
+static int __devinit snd_soc_init(void)
+{
+	printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION);
+	return platform_driver_register(&soc_driver);
+}
+
+static void snd_soc_exit(void)
+{
+ 	platform_driver_unregister(&soc_driver);
+}
+
+module_init(snd_soc_init);
+module_exit(snd_soc_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC Core");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
new file mode 100644
index 0000000..7caf8c7
--- /dev/null
+++ b/sound/soc/soc-dapm.c
@@ -0,0 +1,1323 @@
+/*
+ * soc-dapm.c  --  ALSA SoC Dynamic Audio Power Management
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    12th Aug 2005   Initial version.
+ *    25th Oct 2005   Implemented path power domain.
+ *    18th Dec 2005   Implemented machine and stream level power domain.
+ *
+ *  Features:
+ *    o Changes power status of internal codec blocks depending on the
+ *      dynamic configuration of codec internal audio paths and active
+ *      DAC's/ADC's.
+ *    o Platform power domain - can support external components i.e. amps and
+ *      mic/meadphone insertion events.
+ *    o Automatic Mic Bias support
+ *    o Jack insertion power event initiation - e.g. hp insertion will enable
+ *      sinks, dacs, etc
+ *    o Delayed powerdown of audio susbsytem to reduce pops between a quick
+ *      device reopen.
+ *
+ *  Todo:
+ *    o DAPM power change sequencing - allow for configurable per
+ *      codec sequences.
+ *    o Support for analogue bias optimisation.
+ *    o Support for reduced codec oversampling rates.
+ *    o Support for reduced codec bias currents.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/jiffies.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+/* debug */
+#define DAPM_DEBUG 0
+#if DAPM_DEBUG
+#define dump_dapm(codec, action) dbg_dump_dapm(codec, action)
+#define dbg(format, arg...) printk(format, ## arg)
+#else
+#define dump_dapm(codec, action)
+#define dbg(format, arg...)
+#endif
+
+#define POP_DEBUG 0
+#if POP_DEBUG
+#define POP_TIME 500 /* 500 msecs - change if pop debug is too fast */
+#define pop_wait(time) schedule_timeout_interruptible(msecs_to_jiffies(time))
+#define pop_dbg(format, arg...) printk(format, ## arg); pop_wait(POP_TIME)
+#else
+#define pop_dbg(format, arg...)
+#define pop_wait(time)
+#endif
+
+/* dapm power sequences - make this per codec in the future */
+static int dapm_up_seq[] = {
+	snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic,
+	snd_soc_dapm_mux, snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_pga,
+	snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post
+};
+static int dapm_down_seq[] = {
+	snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
+	snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic,
+	snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_post
+};
+
+static int dapm_status = 1;
+module_param(dapm_status, int, 0);
+MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries");
+
+/* create a new dapm widget */
+static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
+	const struct snd_soc_dapm_widget *_widget)
+{
+	return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
+}
+
+/* set up initial codec paths */
+static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
+	struct snd_soc_dapm_path *p, int i)
+{
+	switch (w->id) {
+	case snd_soc_dapm_switch:
+	case snd_soc_dapm_mixer: {
+		int val;
+		int reg = w->kcontrols[i].private_value & 0xff;
+		int shift = (w->kcontrols[i].private_value >> 8) & 0x0f;
+		int mask = (w->kcontrols[i].private_value >> 16) & 0xff;
+		int invert = (w->kcontrols[i].private_value >> 24) & 0x01;
+
+		val = snd_soc_read(w->codec, reg);
+		val = (val >> shift) & mask;
+
+		if ((invert && !val) || (!invert && val))
+			p->connect = 1;
+		else
+			p->connect = 0;
+	}
+	break;
+	case snd_soc_dapm_mux: {
+		struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;
+		int val, item, bitmask;
+
+		for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+		;
+		val = snd_soc_read(w->codec, e->reg);
+		item = (val >> e->shift_l) & (bitmask - 1);
+
+		p->connect = 0;
+		for (i = 0; i < e->mask; i++) {
+			if (!(strcmp(p->name, e->texts[i])) && item == i)
+				p->connect = 1;
+		}
+	}
+	break;
+	/* does not effect routing - always connected */
+	case snd_soc_dapm_pga:
+	case snd_soc_dapm_output:
+	case snd_soc_dapm_adc:
+	case snd_soc_dapm_input:
+	case snd_soc_dapm_dac:
+	case snd_soc_dapm_micbias:
+	case snd_soc_dapm_vmid:
+		p->connect = 1;
+	break;
+	/* does effect routing - dynamically connected */
+	case snd_soc_dapm_hp:
+	case snd_soc_dapm_mic:
+	case snd_soc_dapm_spk:
+	case snd_soc_dapm_line:
+	case snd_soc_dapm_pre:
+	case snd_soc_dapm_post:
+		p->connect = 0;
+	break;
+	}
+}
+
+/* connect mux widget to it's interconnecting audio paths */
+static int dapm_connect_mux(struct snd_soc_codec *codec,
+	struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
+	struct snd_soc_dapm_path *path, const char *control_name,
+	const struct snd_kcontrol_new *kcontrol)
+{
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	int i;
+
+	for (i = 0; i < e->mask; i++) {
+		if (!(strcmp(control_name, e->texts[i]))) {
+			list_add(&path->list, &codec->dapm_paths);
+			list_add(&path->list_sink, &dest->sources);
+			list_add(&path->list_source, &src->sinks);
+			path->name = (char*)e->texts[i];
+			dapm_set_path_status(dest, path, 0);
+			return 0;
+		}
+	}
+
+	return -ENODEV;
+}
+
+/* connect mixer widget to it's interconnecting audio paths */
+static int dapm_connect_mixer(struct snd_soc_codec *codec,
+	struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
+	struct snd_soc_dapm_path *path, const char *control_name)
+{
+	int i;
+
+	/* search for mixer kcontrol */
+	for (i = 0; i < dest->num_kcontrols; i++) {
+		if (!strcmp(control_name, dest->kcontrols[i].name)) {
+			list_add(&path->list, &codec->dapm_paths);
+			list_add(&path->list_sink, &dest->sources);
+			list_add(&path->list_source, &src->sinks);
+			path->name = dest->kcontrols[i].name;
+			dapm_set_path_status(dest, path, i);
+			return 0;
+		}
+	}
+	return -ENODEV;
+}
+
+/* update dapm codec register bits */
+static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
+{
+	int change, power;
+	unsigned short old, new;
+	struct snd_soc_codec *codec = widget->codec;
+
+	/* check for valid widgets */
+	if (widget->reg < 0 || widget->id == snd_soc_dapm_input ||
+		widget->id == snd_soc_dapm_output ||
+		widget->id == snd_soc_dapm_hp ||
+		widget->id == snd_soc_dapm_mic ||
+		widget->id == snd_soc_dapm_line ||
+		widget->id == snd_soc_dapm_spk)
+		return 0;
+
+	power = widget->power;
+	if (widget->invert)
+		power = (power ? 0:1);
+
+	old = snd_soc_read(codec, widget->reg);
+	new = (old & ~(0x1 << widget->shift)) | (power << widget->shift);
+
+	change = old != new;
+	if (change) {
+		pop_dbg("pop test %s : %s in %d ms\n", widget->name,
+			widget->power ? "on" : "off", POP_TIME);
+		snd_soc_write(codec, widget->reg, new);
+		pop_wait(POP_TIME);
+	}
+	dbg("reg old %x new %x change %d\n", old, new, change);
+	return change;
+}
+
+/* ramps the volume up or down to minimise pops before or after a
+ * DAPM power event */
+static int dapm_set_pga(struct snd_soc_dapm_widget *widget, int power)
+{
+	const struct snd_kcontrol_new *k = widget->kcontrols;
+
+	if (widget->muted && !power)
+		return 0;
+	if (!widget->muted && power)
+		return 0;
+
+	if (widget->num_kcontrols && k) {
+		int reg = k->private_value & 0xff;
+		int shift = (k->private_value >> 8) & 0x0f;
+		int mask = (k->private_value >> 16) & 0xff;
+		int invert = (k->private_value >> 24) & 0x01;
+
+		if (power) {
+			int i;
+			/* power up has happended, increase volume to last level */
+			if (invert) {
+				for (i = mask; i > widget->saved_value; i--)
+					snd_soc_update_bits(widget->codec, reg, mask, i);
+			} else {
+				for (i = 0; i < widget->saved_value; i++)
+					snd_soc_update_bits(widget->codec, reg, mask, i);
+			}
+			widget->muted = 0;
+		} else {
+			/* power down is about to occur, decrease volume to mute */
+			int val = snd_soc_read(widget->codec, reg);
+			int i = widget->saved_value = (val >> shift) & mask;
+			if (invert) {
+				for (; i < mask; i++)
+					snd_soc_update_bits(widget->codec, reg, mask, i);
+			} else {
+				for (; i > 0; i--)
+					snd_soc_update_bits(widget->codec, reg, mask, i);
+			}
+			widget->muted = 1;
+		}
+	}
+	return 0;
+}
+
+/* create new dapm mixer control */
+static int dapm_new_mixer(struct snd_soc_codec *codec,
+	struct snd_soc_dapm_widget *w)
+{
+	int i, ret = 0;
+	char name[32];
+	struct snd_soc_dapm_path *path;
+
+	/* add kcontrol */
+	for (i = 0; i < w->num_kcontrols; i++) {
+
+		/* match name */
+		list_for_each_entry(path, &w->sources, list_sink) {
+
+			/* mixer/mux paths name must match control name */
+			if (path->name != (char*)w->kcontrols[i].name)
+				continue;
+
+			/* add dapm control with long name */
+			snprintf(name, 32, "%s %s", w->name, w->kcontrols[i].name);
+			path->long_name = kstrdup (name, GFP_KERNEL);
+			if (path->long_name == NULL)
+				return -ENOMEM;
+
+			path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
+				path->long_name);
+			ret = snd_ctl_add(codec->card, path->kcontrol);
+			if (ret < 0) {
+				printk(KERN_ERR "asoc: failed to add dapm kcontrol %s\n",
+						path->long_name);
+				kfree(path->long_name);
+				path->long_name = NULL;
+				return ret;
+			}
+		}
+	}
+	return ret;
+}
+
+/* create new dapm mux control */
+static int dapm_new_mux(struct snd_soc_codec *codec,
+	struct snd_soc_dapm_widget *w)
+{
+	struct snd_soc_dapm_path *path = NULL;
+	struct snd_kcontrol *kcontrol;
+	int ret = 0;
+
+	if (!w->num_kcontrols) {
+		printk(KERN_ERR "asoc: mux %s has no controls\n", w->name);
+		return -EINVAL;
+	}
+
+	kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
+	ret = snd_ctl_add(codec->card, kcontrol);
+	if (ret < 0)
+		goto err;
+
+	list_for_each_entry(path, &w->sources, list_sink)
+		path->kcontrol = kcontrol;
+
+	return ret;
+
+err:
+	printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name);
+	return ret;
+}
+
+/* create new dapm volume control */
+static int dapm_new_pga(struct snd_soc_codec *codec,
+	struct snd_soc_dapm_widget *w)
+{
+	struct snd_kcontrol *kcontrol;
+	int ret = 0;
+
+	if (!w->num_kcontrols)
+		return -EINVAL;
+
+	kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
+	ret = snd_ctl_add(codec->card, kcontrol);
+	if (ret < 0) {
+		printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name);
+		return ret;
+	}
+
+	return ret;
+}
+
+/* reset 'walked' bit for each dapm path */
+static inline void dapm_clear_walk(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_path *p;
+
+	list_for_each_entry(p, &codec->dapm_paths, list)
+		p->walked = 0;
+}
+
+/*
+ * Recursively check for a completed path to an active or physically connected
+ * output widget. Returns number of complete paths.
+ */
+static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
+{
+	struct snd_soc_dapm_path *path;
+	int con = 0;
+
+	if (widget->id == snd_soc_dapm_adc && widget->active)
+		return 1;
+
+	if (widget->connected) {
+		/* connected pin ? */
+		if (widget->id == snd_soc_dapm_output && !widget->ext)
+			return 1;
+
+		/* connected jack or spk ? */
+		if (widget->id == snd_soc_dapm_hp || widget->id == snd_soc_dapm_spk ||
+			widget->id == snd_soc_dapm_line)
+			return 1;
+	}
+
+	list_for_each_entry(path, &widget->sinks, list_source) {
+		if (path->walked)
+			continue;
+
+		if (path->sink && path->connect) {
+			path->walked = 1;
+			con += is_connected_output_ep(path->sink);
+		}
+	}
+
+	return con;
+}
+
+/*
+ * Recursively check for a completed path to an active or physically connected
+ * input widget. Returns number of complete paths.
+ */
+static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
+{
+	struct snd_soc_dapm_path *path;
+	int con = 0;
+
+	/* active stream ? */
+	if (widget->id == snd_soc_dapm_dac && widget->active)
+		return 1;
+
+	if (widget->connected) {
+		/* connected pin ? */
+		if (widget->id == snd_soc_dapm_input && !widget->ext)
+			return 1;
+
+		/* connected VMID/Bias for lower pops */
+		if (widget->id == snd_soc_dapm_vmid)
+			return 1;
+
+		/* connected jack ? */
+		if (widget->id == snd_soc_dapm_mic || widget->id == snd_soc_dapm_line)
+			return 1;
+	}
+
+	list_for_each_entry(path, &widget->sources, list_sink) {
+		if (path->walked)
+			continue;
+
+		if (path->source && path->connect) {
+			path->walked = 1;
+			con += is_connected_input_ep(path->source);
+		}
+	}
+
+	return con;
+}
+
+/*
+ * Scan each dapm widget for complete audio path.
+ * A complete path is a route that has valid endpoints i.e.:-
+ *
+ *  o DAC to output pin.
+ *  o Input Pin to ADC.
+ *  o Input pin to Output pin (bypass, sidetone)
+ *  o DAC to ADC (loopback).
+ */
+static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
+{
+	struct snd_soc_dapm_widget *w;
+	int in, out, i, c = 1, *seq = NULL, ret = 0, power_change, power;
+
+	/* do we have a sequenced stream event */
+	if (event == SND_SOC_DAPM_STREAM_START) {
+		c = ARRAY_SIZE(dapm_up_seq);
+		seq = dapm_up_seq;
+	} else if (event == SND_SOC_DAPM_STREAM_STOP) {
+		c = ARRAY_SIZE(dapm_down_seq);
+		seq = dapm_down_seq;
+	}
+
+	for(i = 0; i < c; i++) {
+		list_for_each_entry(w, &codec->dapm_widgets, list) {
+
+			/* is widget in stream order */
+			if (seq && seq[i] && w->id != seq[i])
+				continue;
+
+			/* vmid - no action */
+			if (w->id == snd_soc_dapm_vmid)
+				continue;
+
+			/* active ADC */
+			if (w->id == snd_soc_dapm_adc && w->active) {
+				in = is_connected_input_ep(w);
+				dapm_clear_walk(w->codec);
+				w->power = (in != 0) ? 1 : 0;
+				dapm_update_bits(w);
+				continue;
+			}
+
+			/* active DAC */
+			if (w->id == snd_soc_dapm_dac && w->active) {
+				out = is_connected_output_ep(w);
+				dapm_clear_walk(w->codec);
+				w->power = (out != 0) ? 1 : 0;
+				dapm_update_bits(w);
+				continue;
+			}
+
+			/* programmable gain/attenuation */
+			if (w->id == snd_soc_dapm_pga) {
+				int on;
+				in = is_connected_input_ep(w);
+				dapm_clear_walk(w->codec);
+				out = is_connected_output_ep(w);
+				dapm_clear_walk(w->codec);
+				w->power = on = (out != 0 && in != 0) ? 1 : 0;
+
+				if (!on)
+					dapm_set_pga(w, on); /* lower volume to reduce pops */
+				dapm_update_bits(w);
+				if (on)
+					dapm_set_pga(w, on); /* restore volume from zero */
+
+				continue;
+			}
+
+			/* pre and post event widgets */
+			if (w->id == snd_soc_dapm_pre) {
+				if (!w->event)
+					continue;
+
+				if (event == SND_SOC_DAPM_STREAM_START) {
+					ret = w->event(w, SND_SOC_DAPM_PRE_PMU);
+					if (ret < 0)
+						return ret;
+				} else if (event == SND_SOC_DAPM_STREAM_STOP) {
+					ret = w->event(w, SND_SOC_DAPM_PRE_PMD);
+					if (ret < 0)
+						return ret;
+				}
+				continue;
+			}
+			if (w->id == snd_soc_dapm_post) {
+				if (!w->event)
+					continue;
+
+				if (event == SND_SOC_DAPM_STREAM_START) {
+					ret = w->event(w, SND_SOC_DAPM_POST_PMU);
+					if (ret < 0)
+						return ret;
+				} else if (event == SND_SOC_DAPM_STREAM_STOP) {
+					ret = w->event(w, SND_SOC_DAPM_POST_PMD);
+					if (ret < 0)
+						return ret;
+				}
+				continue;
+			}
+
+			/* all other widgets */
+			in = is_connected_input_ep(w);
+			dapm_clear_walk(w->codec);
+			out = is_connected_output_ep(w);
+			dapm_clear_walk(w->codec);
+			power = (out != 0 && in != 0) ? 1 : 0;
+			power_change = (w->power == power) ? 0: 1;
+			w->power = power;
+
+			/* call any power change event handlers */
+			if (power_change) {
+				if (w->event) {
+					dbg("power %s event for %s flags %x\n",
+						w->power ? "on" : "off", w->name, w->event_flags);
+					if (power) {
+						/* power up event */
+						if (w->event_flags & SND_SOC_DAPM_PRE_PMU) {
+							ret = w->event(w, SND_SOC_DAPM_PRE_PMU);
+							if (ret < 0)
+								return ret;
+						}
+						dapm_update_bits(w);
+						if (w->event_flags & SND_SOC_DAPM_POST_PMU){
+							ret = w->event(w, SND_SOC_DAPM_POST_PMU);
+							if (ret < 0)
+								return ret;
+						}
+					} else {
+						/* power down event */
+						if (w->event_flags & SND_SOC_DAPM_PRE_PMD) {
+							ret = w->event(w, SND_SOC_DAPM_PRE_PMD);
+							if (ret < 0)
+								return ret;
+						}
+						dapm_update_bits(w);
+						if (w->event_flags & SND_SOC_DAPM_POST_PMD) {
+							ret = w->event(w, SND_SOC_DAPM_POST_PMD);
+							if (ret < 0)
+								return ret;
+						}
+					}
+				} else
+					/* no event handler */
+					dapm_update_bits(w);
+			}
+		}
+	}
+
+	return ret;
+}
+
+#if DAPM_DEBUG
+static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
+{
+	struct snd_soc_dapm_widget *w;
+	struct snd_soc_dapm_path *p = NULL;
+	int in, out;
+
+	printk("DAPM %s %s\n", codec->name, action);
+
+	list_for_each_entry(w, &codec->dapm_widgets, list) {
+
+		/* only display widgets that effect routing */
+		switch (w->id) {
+		case snd_soc_dapm_pre:
+		case snd_soc_dapm_post:
+		case snd_soc_dapm_vmid:
+			continue;
+		case snd_soc_dapm_mux:
+		case snd_soc_dapm_output:
+		case snd_soc_dapm_input:
+		case snd_soc_dapm_switch:
+		case snd_soc_dapm_hp:
+		case snd_soc_dapm_mic:
+		case snd_soc_dapm_spk:
+		case snd_soc_dapm_line:
+		case snd_soc_dapm_micbias:
+		case snd_soc_dapm_dac:
+		case snd_soc_dapm_adc:
+		case snd_soc_dapm_pga:
+		case snd_soc_dapm_mixer:
+			if (w->name) {
+				in = is_connected_input_ep(w);
+				dapm_clear_walk(w->codec);
+				out = is_connected_output_ep(w);
+				dapm_clear_walk(w->codec);
+				printk("%s: %s  in %d out %d\n", w->name,
+					w->power ? "On":"Off",in, out);
+
+				list_for_each_entry(p, &w->sources, list_sink) {
+					if (p->connect)
+						printk(" in  %s %s\n", p->name ? p->name : "static",
+							p->source->name);
+				}
+				list_for_each_entry(p, &w->sinks, list_source) {
+					if (p->connect)
+						printk(" out %s %s\n", p->name ? p->name : "static",
+							p->sink->name);
+				}
+			}
+		break;
+		}
+	}
+}
+#endif
+
+/* test and update the power status of a mux widget */
+static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+				 struct snd_kcontrol *kcontrol, int mask,
+				 int val, struct soc_enum* e)
+{
+	struct snd_soc_dapm_path *path;
+	int found = 0;
+
+	if (widget->id != snd_soc_dapm_mux)
+		return -ENODEV;
+
+	if (!snd_soc_test_bits(widget->codec, e->reg, mask, val))
+		return 0;
+
+	/* find dapm widget path assoc with kcontrol */
+	list_for_each_entry(path, &widget->codec->dapm_paths, list) {
+		if (path->kcontrol != kcontrol)
+			continue;
+
+		if (!path->name || ! e->texts[val])
+			continue;
+
+		found = 1;
+		/* we now need to match the string in the enum to the path */
+		if (!(strcmp(path->name, e->texts[val])))
+			path->connect = 1; /* new connection */
+		else
+			path->connect = 0; /* old connection must be powered down */
+	}
+
+	if (found)
+		dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
+
+	return 0;
+}
+
+/* test and update the power status of a mixer widget */
+static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+				   struct snd_kcontrol *kcontrol, int reg,
+				   int val_mask, int val, int invert)
+{
+	struct snd_soc_dapm_path *path;
+	int found = 0;
+
+	if (widget->id != snd_soc_dapm_mixer)
+		return -ENODEV;
+
+	if (!snd_soc_test_bits(widget->codec, reg, val_mask, val))
+		return 0;
+
+	/* find dapm widget path assoc with kcontrol */
+	list_for_each_entry(path, &widget->codec->dapm_paths, list) {
+		if (path->kcontrol != kcontrol)
+			continue;
+
+		/* found, now check type */
+		found = 1;
+		if (val)
+			/* new connection */
+			path->connect = invert ? 0:1;
+		else
+			/* old connection must be powered down */
+			path->connect = invert ? 1:0;
+		break;
+	}
+
+	if (found)
+		dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
+
+	return 0;
+}
+
+/* show dapm widget status in sys fs */
+static ssize_t dapm_widget_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct snd_soc_device *devdata = dev_get_drvdata(dev);
+	struct snd_soc_codec *codec = devdata->codec;
+	struct snd_soc_dapm_widget *w;
+	int count = 0;
+	char *state = "not set";
+
+	list_for_each_entry(w, &codec->dapm_widgets, list) {
+
+		/* only display widgets that burnm power */
+		switch (w->id) {
+		case snd_soc_dapm_hp:
+		case snd_soc_dapm_mic:
+		case snd_soc_dapm_spk:
+		case snd_soc_dapm_line:
+		case snd_soc_dapm_micbias:
+		case snd_soc_dapm_dac:
+		case snd_soc_dapm_adc:
+		case snd_soc_dapm_pga:
+		case snd_soc_dapm_mixer:
+			if (w->name)
+				count += sprintf(buf + count, "%s: %s\n",
+					w->name, w->power ? "On":"Off");
+		break;
+		default:
+		break;
+		}
+	}
+
+	switch(codec->dapm_state){
+	case SNDRV_CTL_POWER_D0:
+		state = "D0";
+		break;
+	case SNDRV_CTL_POWER_D1:
+		state = "D1";
+		break;
+	case SNDRV_CTL_POWER_D2:
+		state = "D2";
+		break;
+	case SNDRV_CTL_POWER_D3hot:
+		state = "D3hot";
+		break;
+	case SNDRV_CTL_POWER_D3cold:
+		state = "D3cold";
+		break;
+	}
+	count += sprintf(buf + count, "PM State: %s\n", state);
+
+	return count;
+}
+
+static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
+
+int snd_soc_dapm_sys_add(struct device *dev)
+{
+	int ret = 0;
+
+	if (dapm_status)
+		ret = device_create_file(dev, &dev_attr_dapm_widget);
+
+	return ret;
+}
+
+static void snd_soc_dapm_sys_remove(struct device *dev)
+{
+	if (dapm_status)
+		device_remove_file(dev, &dev_attr_dapm_widget);
+}
+
+/* free all dapm widgets and resources */
+static void dapm_free_widgets(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_widget *w, *next_w;
+	struct snd_soc_dapm_path *p, *next_p;
+
+	list_for_each_entry_safe(w, next_w, &codec->dapm_widgets, list) {
+		list_del(&w->list);
+		kfree(w);
+	}
+
+	list_for_each_entry_safe(p, next_p, &codec->dapm_paths, list) {
+		list_del(&p->list);
+		kfree(p->long_name);
+		kfree(p);
+	}
+}
+
+/**
+ * snd_soc_dapm_sync_endpoints - scan and power dapm paths
+ * @codec: audio codec
+ *
+ * Walks all dapm audio paths and powers widgets according to their
+ * stream or path usage.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec)
+{
+	return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_endpoints);
+
+/**
+ * snd_soc_dapm_connect_input - connect dapm widgets
+ * @codec: audio codec
+ * @sink: name of target widget
+ * @control: mixer control name
+ * @source: name of source name
+ *
+ * Connects 2 dapm widgets together via a named audio path. The sink is
+ * the widget receiving the audio signal, whilst the source is the sender
+ * of the audio signal.
+ *
+ * Returns 0 for success else error.
+ */
+int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink,
+	const char * control, const char *source)
+{
+	struct snd_soc_dapm_path *path;
+	struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
+	int ret = 0;
+
+	/* find src and dest widgets */
+	list_for_each_entry(w, &codec->dapm_widgets, list) {
+
+		if (!wsink && !(strcmp(w->name, sink))) {
+			wsink = w;
+			continue;
+		}
+		if (!wsource && !(strcmp(w->name, source))) {
+			wsource = w;
+		}
+	}
+
+	if (wsource == NULL || wsink == NULL)
+		return -ENODEV;
+
+	path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
+	if (!path)
+		return -ENOMEM;
+
+	path->source = wsource;
+	path->sink = wsink;
+	INIT_LIST_HEAD(&path->list);
+	INIT_LIST_HEAD(&path->list_source);
+	INIT_LIST_HEAD(&path->list_sink);
+
+	/* check for external widgets */
+	if (wsink->id == snd_soc_dapm_input) {
+		if (wsource->id == snd_soc_dapm_micbias ||
+			wsource->id == snd_soc_dapm_mic ||
+			wsink->id == snd_soc_dapm_line)
+			wsink->ext = 1;
+	}
+	if (wsource->id == snd_soc_dapm_output) {
+		if (wsink->id == snd_soc_dapm_spk ||
+			wsink->id == snd_soc_dapm_hp ||
+			wsink->id == snd_soc_dapm_line)
+			wsource->ext = 1;
+	}
+
+	/* connect static paths */
+	if (control == NULL) {
+		list_add(&path->list, &codec->dapm_paths);
+		list_add(&path->list_sink, &wsink->sources);
+		list_add(&path->list_source, &wsource->sinks);
+		path->connect = 1;
+		return 0;
+	}
+
+	/* connect dynamic paths */
+	switch(wsink->id) {
+	case snd_soc_dapm_adc:
+	case snd_soc_dapm_dac:
+	case snd_soc_dapm_pga:
+	case snd_soc_dapm_input:
+	case snd_soc_dapm_output:
+	case snd_soc_dapm_micbias:
+	case snd_soc_dapm_vmid:
+	case snd_soc_dapm_pre:
+	case snd_soc_dapm_post:
+		list_add(&path->list, &codec->dapm_paths);
+		list_add(&path->list_sink, &wsink->sources);
+		list_add(&path->list_source, &wsource->sinks);
+		path->connect = 1;
+		return 0;
+	case snd_soc_dapm_mux:
+		ret = dapm_connect_mux(codec, wsource, wsink, path, control,
+			&wsink->kcontrols[0]);
+		if (ret != 0)
+			goto err;
+		break;
+	case snd_soc_dapm_switch:
+	case snd_soc_dapm_mixer:
+		ret = dapm_connect_mixer(codec, wsource, wsink, path, control);
+		if (ret != 0)
+			goto err;
+		break;
+	case snd_soc_dapm_hp:
+	case snd_soc_dapm_mic:
+	case snd_soc_dapm_line:
+	case snd_soc_dapm_spk:
+		list_add(&path->list, &codec->dapm_paths);
+		list_add(&path->list_sink, &wsink->sources);
+		list_add(&path->list_source, &wsource->sinks);
+		path->connect = 0;
+		return 0;
+	}
+	return 0;
+
+err:
+	printk(KERN_WARNING "asoc: no dapm match for %s --> %s --> %s\n", source,
+		control, sink);
+	kfree(path);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input);
+
+/**
+ * snd_soc_dapm_new_widgets - add new dapm widgets
+ * @codec: audio codec
+ *
+ * Checks the codec for any new dapm widgets and creates them if found.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_widget *w;
+
+	mutex_lock(&codec->mutex);
+	list_for_each_entry(w, &codec->dapm_widgets, list)
+	{
+		if (w->new)
+			continue;
+
+		switch(w->id) {
+		case snd_soc_dapm_switch:
+		case snd_soc_dapm_mixer:
+			dapm_new_mixer(codec, w);
+			break;
+		case snd_soc_dapm_mux:
+			dapm_new_mux(codec, w);
+			break;
+		case snd_soc_dapm_adc:
+		case snd_soc_dapm_dac:
+		case snd_soc_dapm_pga:
+			dapm_new_pga(codec, w);
+			break;
+		case snd_soc_dapm_input:
+		case snd_soc_dapm_output:
+		case snd_soc_dapm_micbias:
+		case snd_soc_dapm_spk:
+		case snd_soc_dapm_hp:
+		case snd_soc_dapm_mic:
+		case snd_soc_dapm_line:
+		case snd_soc_dapm_vmid:
+		case snd_soc_dapm_pre:
+		case snd_soc_dapm_post:
+			break;
+		}
+		w->new = 1;
+	}
+
+	dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
+	mutex_unlock(&codec->mutex);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
+
+/**
+ * snd_soc_dapm_get_volsw - dapm mixer get callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to get the value of a dapm mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	int reg = kcontrol->private_value & 0xff;
+	int shift = (kcontrol->private_value >> 8) & 0x0f;
+	int rshift = (kcontrol->private_value >> 12) & 0x0f;
+	int mask = (kcontrol->private_value >> 16) & 0xff;
+	int invert = (kcontrol->private_value >> 24) & 0x01;
+
+	/* return the saved value if we are powered down */
+	if (widget->id == snd_soc_dapm_pga && !widget->power) {
+		ucontrol->value.integer.value[0] = widget->saved_value;
+		return 0;
+	}
+
+	ucontrol->value.integer.value[0] =
+		(snd_soc_read(widget->codec, reg) >> shift) & mask;
+	if (shift != rshift)
+		ucontrol->value.integer.value[1] =
+			(snd_soc_read(widget->codec, reg) >> rshift) & mask;
+	if (invert) {
+		ucontrol->value.integer.value[0] =
+			mask - ucontrol->value.integer.value[0];
+		if (shift != rshift)
+			ucontrol->value.integer.value[1] =
+				mask - ucontrol->value.integer.value[1];
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
+
+/**
+ * snd_soc_dapm_put_volsw - dapm mixer set callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to set the value of a dapm mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	int reg = kcontrol->private_value & 0xff;
+	int shift = (kcontrol->private_value >> 8) & 0x0f;
+	int rshift = (kcontrol->private_value >> 12) & 0x0f;
+	int mask = (kcontrol->private_value >> 16) & 0xff;
+	int invert = (kcontrol->private_value >> 24) & 0x01;
+	unsigned short val, val2, val_mask;
+	int ret;
+
+	val = (ucontrol->value.integer.value[0] & mask);
+
+	if (invert)
+		val = mask - val;
+	val_mask = mask << shift;
+	val = val << shift;
+	if (shift != rshift) {
+		val2 = (ucontrol->value.integer.value[1] & mask);
+		if (invert)
+			val2 = mask - val2;
+		val_mask |= mask << rshift;
+		val |= val2 << rshift;
+	}
+
+	mutex_lock(&widget->codec->mutex);
+	widget->value = val;
+
+	/* save volume value if the widget is powered down */
+	if (widget->id == snd_soc_dapm_pga && !widget->power) {
+		widget->saved_value = val;
+		mutex_unlock(&widget->codec->mutex);
+		return 1;
+	}
+
+	dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert);
+	if (widget->event) {
+		if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
+			ret = widget->event(widget, SND_SOC_DAPM_PRE_REG);
+			if (ret < 0)
+				goto out;
+		}
+		ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
+		if (widget->event_flags & SND_SOC_DAPM_POST_REG)
+			ret = widget->event(widget, SND_SOC_DAPM_POST_REG);
+	} else
+		ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
+
+out:
+	mutex_unlock(&widget->codec->mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
+
+/**
+ * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to get the value of a dapm enumerated double mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned short val, bitmask;
+
+	for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+		;
+	val = snd_soc_read(widget->codec, e->reg);
+	ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
+	if (e->shift_l != e->shift_r)
+		ucontrol->value.enumerated.item[1] =
+			(val >> e->shift_r) & (bitmask - 1);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
+
+/**
+ * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to set the value of a dapm enumerated double mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned short val, mux;
+	unsigned short mask, bitmask;
+	int ret = 0;
+
+	for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+		;
+	if (ucontrol->value.enumerated.item[0] > e->mask - 1)
+		return -EINVAL;
+	mux = ucontrol->value.enumerated.item[0];
+	val = mux << e->shift_l;
+	mask = (bitmask - 1) << e->shift_l;
+	if (e->shift_l != e->shift_r) {
+		if (ucontrol->value.enumerated.item[1] > e->mask - 1)
+			return -EINVAL;
+		val |= ucontrol->value.enumerated.item[1] << e->shift_r;
+		mask |= (bitmask - 1) << e->shift_r;
+	}
+
+	mutex_lock(&widget->codec->mutex);
+	widget->value = val;
+	dapm_mux_update_power(widget, kcontrol, mask, mux, e);
+	if (widget->event) {
+		if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
+			ret = widget->event(widget, SND_SOC_DAPM_PRE_REG);
+			if (ret < 0)
+				goto out;
+		}
+		ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
+		if (widget->event_flags & SND_SOC_DAPM_POST_REG)
+			ret = widget->event(widget, SND_SOC_DAPM_POST_REG);
+	} else
+		ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
+
+out:
+	mutex_unlock(&widget->codec->mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
+
+/**
+ * snd_soc_dapm_new_control - create new dapm control
+ * @codec: audio codec
+ * @widget: widget template
+ *
+ * Creates a new dapm control based upon the template.
+ *
+ * Returns 0 for success else error.
+ */
+int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
+	const struct snd_soc_dapm_widget *widget)
+{
+	struct snd_soc_dapm_widget *w;
+
+	if ((w = dapm_cnew_widget(widget)) == NULL)
+		return -ENOMEM;
+
+	w->codec = codec;
+	INIT_LIST_HEAD(&w->sources);
+	INIT_LIST_HEAD(&w->sinks);
+	INIT_LIST_HEAD(&w->list);
+	list_add(&w->list, &codec->dapm_widgets);
+
+	/* machine layer set ups unconnected pins and insertions */
+	w->connected = 1;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
+
+/**
+ * snd_soc_dapm_stream_event - send a stream event to the dapm core
+ * @codec: audio codec
+ * @stream: stream name
+ * @event: stream event
+ *
+ * Sends a stream event to the dapm core. The core then makes any
+ * necessary widget power changes.
+ *
+ * Returns 0 for success else error.
+ */
+int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
+	char *stream, int event)
+{
+	struct snd_soc_dapm_widget *w;
+
+	if (stream == NULL)
+		return 0;
+
+	mutex_lock(&codec->mutex);
+	list_for_each_entry(w, &codec->dapm_widgets, list)
+	{
+		if (!w->sname)
+			continue;
+		dbg("widget %s\n %s stream %s event %d\n", w->name, w->sname,
+			stream, event);
+		if (strstr(w->sname, stream)) {
+			switch(event) {
+			case SND_SOC_DAPM_STREAM_START:
+				w->active = 1;
+				break;
+			case SND_SOC_DAPM_STREAM_STOP:
+				w->active = 0;
+				break;
+			case SND_SOC_DAPM_STREAM_SUSPEND:
+				if (w->active)
+					w->suspend = 1;
+				w->active = 0;
+				break;
+			case SND_SOC_DAPM_STREAM_RESUME:
+				if (w->suspend) {
+					w->active = 1;
+					w->suspend = 0;
+				}
+				break;
+			case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
+				break;
+			case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
+				break;
+			}
+		}
+	}
+	mutex_unlock(&codec->mutex);
+
+	dapm_power_widgets(codec, event);
+	dump_dapm(codec, __FUNCTION__);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
+
+/**
+ * snd_soc_dapm_set_endpoint - set audio endpoint status
+ * @codec: audio codec
+ * @endpoint: audio signal endpoint (or start point)
+ * @status: point status
+ *
+ * Set audio endpoint status - connected or disconnected.
+ *
+ * Returns 0 for success else error.
+ */
+int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec,
+	char *endpoint, int status)
+{
+	struct snd_soc_dapm_widget *w;
+
+	list_for_each_entry(w, &codec->dapm_widgets, list) {
+		if (!strcmp(w->name, endpoint)) {
+			w->connected = status;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_set_endpoint);
+
+/**
+ * snd_soc_dapm_free - free dapm resources
+ * @socdev: SoC device
+ *
+ * Free all dapm widgets and resources.
+ */
+void snd_soc_dapm_free(struct snd_soc_device *socdev)
+{
+	struct snd_soc_codec *codec = socdev->codec;
+
+	snd_soc_dapm_sys_remove(socdev->dev);
+	dapm_free_widgets(codec);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
+MODULE_LICENSE("GPL");
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
index 4ceb09d..25a2a73 100644
--- a/sound/sparc/dbri.c
+++ b/sound/sparc/dbri.c
@@ -678,7 +678,7 @@
  * The JUMP cmd points to the new cmd string.
  * It also releases the cmdlock spinlock.
  *
- * Lock must not be held before calling this.
+ * Lock must be held before calling this.
  */
 static void dbri_cmdsend(struct snd_dbri * dbri, s32 * cmd,int len)
 {
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 19bdcc7..4dfb91d 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -186,6 +186,7 @@
 	u64 formats;			/* format bitmasks (all or'ed) */
 	unsigned int num_formats;		/* number of supported audio formats (list) */
 	struct list_head fmt_list;	/* format list */
+	struct snd_pcm_hw_constraint_list rate_list;	/* limited rates */
 	spinlock_t lock;
 
 	struct snd_urb_ops ops;		/* callbacks (must be filled at init) */
@@ -253,7 +254,7 @@
 				    struct urb *urb)
 {
 	unsigned char *cp = urb->transfer_buffer;
-	struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
+	struct snd_urb_ctx *ctx = urb->context;
 
 	urb->dev = ctx->subs->dev; /* we need to set this at each time */
 	urb->iso_frame_desc[0].length = 3;
@@ -275,7 +276,7 @@
 				       struct urb *urb)
 {
 	unsigned char *cp = urb->transfer_buffer;
-	struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
+	struct snd_urb_ctx *ctx = urb->context;
 
 	urb->dev = ctx->subs->dev; /* we need to set this at each time */
 	urb->iso_frame_desc[0].length = 4;
@@ -313,7 +314,7 @@
 			       struct urb *urb)
 {
 	int i, offs;
-	struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
+	struct snd_urb_ctx *ctx = urb->context;
 
 	offs = 0;
 	urb->dev = ctx->subs->dev; /* we need to set this at each time */
@@ -391,6 +392,16 @@
 	return 0;
 }
 
+/*
+ * Process after capture complete when paused.  Nothing to do.
+ */
+static int retire_paused_capture_urb(struct snd_usb_substream *subs,
+				     struct snd_pcm_runtime *runtime,
+				     struct urb *urb)
+{
+	return 0;
+}
+
 
 /*
  * prepare urb for full speed playback sync pipe
@@ -402,7 +413,7 @@
 				     struct snd_pcm_runtime *runtime,
 				     struct urb *urb)
 {
-	struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
+	struct snd_urb_ctx *ctx = urb->context;
 
 	urb->dev = ctx->subs->dev; /* we need to set this at each time */
 	urb->iso_frame_desc[0].length = 3;
@@ -420,7 +431,7 @@
 					struct snd_pcm_runtime *runtime,
 					struct urb *urb)
 {
-	struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
+	struct snd_urb_ctx *ctx = urb->context;
 
 	urb->dev = ctx->subs->dev; /* we need to set this at each time */
 	urb->iso_frame_desc[0].length = 4;
@@ -493,13 +504,13 @@
 }
 
 /*
- * Prepare urb for streaming before playback starts.
+ * Prepare urb for streaming before playback starts or when paused.
  *
- * We don't yet have data, so we send a frame of silence.
+ * We don't have any data, so we send a frame of silence.
  */
-static int prepare_startup_playback_urb(struct snd_usb_substream *subs,
-					struct snd_pcm_runtime *runtime,
-					struct urb *urb)
+static int prepare_nodata_playback_urb(struct snd_usb_substream *subs,
+				       struct snd_pcm_runtime *runtime,
+				       struct urb *urb)
 {
 	unsigned int i, offs, counts;
 	struct snd_urb_ctx *ctx = urb->context;
@@ -537,7 +548,7 @@
 	unsigned int counts;
 	unsigned long flags;
 	int period_elapsed = 0;
-	struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
+	struct snd_urb_ctx *ctx = urb->context;
 
 	stride = runtime->frame_bits >> 3;
 
@@ -622,7 +633,7 @@
  */
 static struct snd_urb_ops audio_urb_ops[2] = {
 	{
-		.prepare =	prepare_startup_playback_urb,
+		.prepare =	prepare_nodata_playback_urb,
 		.retire =	retire_playback_urb,
 		.prepare_sync =	prepare_playback_sync_urb,
 		.retire_sync =	retire_playback_sync_urb,
@@ -637,7 +648,7 @@
 
 static struct snd_urb_ops audio_urb_ops_high_speed[2] = {
 	{
-		.prepare =	prepare_startup_playback_urb,
+		.prepare =	prepare_nodata_playback_urb,
 		.retire =	retire_playback_urb,
 		.prepare_sync =	prepare_playback_sync_urb_hs,
 		.retire_sync =	retire_playback_sync_urb_hs,
@@ -655,7 +666,7 @@
  */
 static void snd_complete_urb(struct urb *urb)
 {
-	struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
+	struct snd_urb_ctx *ctx = urb->context;
 	struct snd_usb_substream *subs = ctx->subs;
 	struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
 	int err = 0;
@@ -678,7 +689,7 @@
  */
 static void snd_complete_sync_urb(struct urb *urb)
 {
-	struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
+	struct snd_urb_ctx *ctx = urb->context;
 	struct snd_usb_substream *subs = ctx->subs;
 	struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
 	int err = 0;
@@ -925,10 +936,14 @@
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		subs->ops.prepare = prepare_playback_urb;
 		return 0;
 	case SNDRV_PCM_TRIGGER_STOP:
 		return deactivate_urbs(subs, 0, 0);
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		subs->ops.prepare = prepare_nodata_playback_urb;
+		return 0;
 	default:
 		return -EINVAL;
 	}
@@ -944,9 +959,16 @@
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
+		subs->ops.retire = retire_capture_urb;
 		return start_urbs(subs, substream->runtime);
 	case SNDRV_PCM_TRIGGER_STOP:
 		return deactivate_urbs(subs, 0, 0);
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		subs->ops.retire = retire_paused_capture_urb;
+		return 0;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		subs->ops.retire = retire_capture_urb;
+		return 0;
 	default:
 		return -EINVAL;
 	}
@@ -1408,7 +1430,7 @@
 static int snd_usb_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *hw_params)
 {
-	struct snd_usb_substream *subs = (struct snd_usb_substream *)substream->runtime->private_data;
+	struct snd_usb_substream *subs = substream->runtime->private_data;
 	struct audioformat *fmt;
 	unsigned int channels, rate, format;
 	int ret, changed;
@@ -1464,7 +1486,7 @@
  */
 static int snd_usb_hw_free(struct snd_pcm_substream *substream)
 {
-	struct snd_usb_substream *subs = (struct snd_usb_substream *)substream->runtime->private_data;
+	struct snd_usb_substream *subs = substream->runtime->private_data;
 
 	subs->cur_audiofmt = NULL;
 	subs->cur_rate = 0;
@@ -1505,33 +1527,20 @@
 	/* for playback, submit the URBs now; otherwise, the first hwptr_done
 	 * updates for all URBs would happen at the same time when starting */
 	if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
-		subs->ops.prepare = prepare_startup_playback_urb;
+		subs->ops.prepare = prepare_nodata_playback_urb;
 		return start_urbs(subs, runtime);
 	} else
 		return 0;
 }
 
-static struct snd_pcm_hardware snd_usb_playback =
+static struct snd_pcm_hardware snd_usb_hardware =
 {
 	.info =			SNDRV_PCM_INFO_MMAP |
 				SNDRV_PCM_INFO_MMAP_VALID |
 				SNDRV_PCM_INFO_BATCH |
 				SNDRV_PCM_INFO_INTERLEAVED |
-				SNDRV_PCM_INFO_BLOCK_TRANSFER,
-	.buffer_bytes_max =	1024 * 1024,
-	.period_bytes_min =	64,
-	.period_bytes_max =	512 * 1024,
-	.periods_min =		2,
-	.periods_max =		1024,
-};
-
-static struct snd_pcm_hardware snd_usb_capture =
-{
-	.info =			SNDRV_PCM_INFO_MMAP |
-				SNDRV_PCM_INFO_MMAP_VALID |
-				SNDRV_PCM_INFO_BATCH |
-				SNDRV_PCM_INFO_INTERLEAVED |
-				SNDRV_PCM_INFO_BLOCK_TRANSFER,
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_PAUSE,
 	.buffer_bytes_max =	1024 * 1024,
 	.period_bytes_min =	64,
 	.period_bytes_max =	512 * 1024,
@@ -1810,28 +1819,33 @@
 static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
 				  struct snd_usb_substream *subs)
 {
-	struct list_head *p;
-	struct snd_pcm_hw_constraint_list constraints_rates;
+	struct audioformat *fp;
+	int count = 0, needs_knot = 0;
 	int err;
 
-	list_for_each(p, &subs->fmt_list) {
-		struct audioformat *fp;
-		fp = list_entry(p, struct audioformat, list);
-
-		if (!fp->needs_knot)
-			continue;
-
-		constraints_rates.count = fp->nr_rates;
-		constraints_rates.list = fp->rate_table;
-		constraints_rates.mask = 0;
-
-		err = snd_pcm_hw_constraint_list(runtime, 0,
-			SNDRV_PCM_HW_PARAM_RATE,
-			&constraints_rates);
-
-		if (err < 0)
-			return err;
+	list_for_each_entry(fp, &subs->fmt_list, list) {
+		if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)
+			return 0;
+		count += fp->nr_rates;
+		if (fp->needs_knot)
+			needs_knot = 1;
 	}
+	if (!needs_knot)
+		return 0;
+
+	subs->rate_list.count = count;
+	subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL);
+	subs->rate_list.mask = 0;
+	count = 0;
+	list_for_each_entry(fp, &subs->fmt_list, list) {
+		int i;
+		for (i = 0; i < fp->nr_rates; i++)
+			subs->rate_list.list[count++] = fp->rate_table[i];
+	}
+	err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+					 &subs->rate_list);
+	if (err < 0)
+		return err;
 
 	return 0;
 }
@@ -1904,8 +1918,7 @@
 	return 0;
 }
 
-static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction,
-			    struct snd_pcm_hardware *hw)
+static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction)
 {
 	struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
@@ -1913,7 +1926,7 @@
 
 	subs->interface = -1;
 	subs->format = 0;
-	runtime->hw = *hw;
+	runtime->hw = snd_usb_hardware;
 	runtime->private_data = subs;
 	subs->pcm_substream = substream;
 	return setup_hw_info(runtime, subs);
@@ -1934,7 +1947,7 @@
 
 static int snd_usb_playback_open(struct snd_pcm_substream *substream)
 {
-	return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK, &snd_usb_playback);
+	return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK);
 }
 
 static int snd_usb_playback_close(struct snd_pcm_substream *substream)
@@ -1944,7 +1957,7 @@
 
 static int snd_usb_capture_open(struct snd_pcm_substream *substream)
 {
-	return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_CAPTURE, &snd_usb_capture);
+	return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_CAPTURE);
 }
 
 static int snd_usb_capture_close(struct snd_pcm_substream *substream)
@@ -2231,6 +2244,7 @@
 		kfree(fp->rate_table);
 		kfree(fp);
 	}
+	kfree(subs->rate_list.list);
 }
 
 
@@ -2456,6 +2470,7 @@
 		 * build the rate table and bitmap flags
 		 */
 		int r, idx, c;
+		unsigned int nonzero_rates = 0;
 		/* this table corresponds to the SNDRV_PCM_RATE_XXX bit */
 		static unsigned int conv_rates[] = {
 			5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
@@ -2478,6 +2493,7 @@
 			    fp->altsetting == 5 && fp->maxpacksize == 392)
 				rate = 96000;
 			fp->rate_table[r] = rate;
+			nonzero_rates |= rate;
 			if (rate < fp->rate_min)
 				fp->rate_min = rate;
 			else if (rate > fp->rate_max)
@@ -2493,6 +2509,10 @@
 			if (!found)
 				fp->needs_knot = 1;
 		}
+		if (!nonzero_rates) {
+			hwc_debug("All rates were zero. Skipping format!\n");
+			return -1;
+		}
 		if (fp->needs_knot)
 			fp->rates |= SNDRV_PCM_RATE_KNOT;
 	} else {
@@ -3057,6 +3077,58 @@
 	return 0;
 }
 
+/*
+ * Create a stream for an Edirol UA-101 interface.
+ * Copy, paste and modify from Edirol UA-1000
+ */
+static int create_ua101_quirk(struct snd_usb_audio *chip,
+			       struct usb_interface *iface,
+			       const struct snd_usb_audio_quirk *quirk)
+{
+	static const struct audioformat ua101_format = {
+		.format = SNDRV_PCM_FORMAT_S32_LE,
+		.fmt_type = USB_FORMAT_TYPE_I,
+		.altsetting = 1,
+		.altset_idx = 1,
+		.attributes = 0,
+		.rates = SNDRV_PCM_RATE_CONTINUOUS,
+	};
+	struct usb_host_interface *alts;
+	struct usb_interface_descriptor *altsd;
+	struct audioformat *fp;
+	int stream, err;
+
+	if (iface->num_altsetting != 2)
+		return -ENXIO;
+	alts = &iface->altsetting[1];
+	altsd = get_iface_desc(alts);
+	if (alts->extralen != 18 || alts->extra[1] != USB_DT_CS_INTERFACE ||
+	    altsd->bNumEndpoints != 1)
+		return -ENXIO;
+
+	fp = kmemdup(&ua101_format, sizeof(*fp), GFP_KERNEL);
+	if (!fp)
+		return -ENOMEM;
+
+	fp->channels = alts->extra[11];
+	fp->iface = altsd->bInterfaceNumber;
+	fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
+	fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
+	fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
+	fp->rate_max = fp->rate_min = combine_triple(&alts->extra[15]);
+
+	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;
+	}
+	/* FIXME: playback must be synchronized to capture */
+	usb_set_interface(chip->dev, fp->iface, 0);
+	return 0;
+}
+
 static int snd_usb_create_quirk(struct snd_usb_audio *chip,
 				struct usb_interface *iface,
 				const struct snd_usb_audio_quirk *quirk);
@@ -3238,6 +3310,7 @@
 		[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
 		[QUIRK_AUDIO_EDIROL_UA700_UA25] = create_ua700_ua25_quirk,
 		[QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk,
+		[QUIRK_AUDIO_EDIROL_UA101] = create_ua101_quirk,
 	};
 
 	if (quirk->type < QUIRK_TYPE_COUNT) {
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 0f4b2b8..2272f45 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -159,6 +159,7 @@
 	QUIRK_AUDIO_FIXED_ENDPOINT,
 	QUIRK_AUDIO_EDIROL_UA700_UA25,
 	QUIRK_AUDIO_EDIROL_UA1000,
+	QUIRK_AUDIO_EDIROL_UA101,
 
 	QUIRK_TYPE_COUNT
 };
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
index a7e9563..25b4ab4 100644
--- a/sound/usb/usbquirks.h
+++ b/sound/usb/usbquirks.h
@@ -1098,7 +1098,37 @@
 		}
 	}
 },
-	/* TODO: add Edirol UA-101 support */
+/* Roland UA-101 in High-Speed Mode only */
+{
+	USB_DEVICE(0x0582, 0x007d),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "Roland",
+		.product_name = "UA-101",
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = (const struct snd_usb_audio_quirk[]) {
+			{
+				.ifnum = 0,
+				.type = QUIRK_AUDIO_EDIROL_UA101
+			},
+			{
+				.ifnum = 1,
+				.type = QUIRK_AUDIO_EDIROL_UA101
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_MIDI_FIXED_ENDPOINT,
+				.data = & (const struct snd_usb_midi_endpoint_info) {
+					.out_cables = 0x0001,
+					.in_cables  = 0x0001
+				}
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
 {
 	/* has ID 0x0081 when not in "Advanced Driver" mode */
 	USB_DEVICE(0x0582, 0x0080),